File indexing completed on 2025-01-30 09:32:42
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <cstdint>
0011 #include <map>
0012 #include <string>
0013 #include <variant>
0014 #include <vector>
0015
0016 #include <fmt/format.h>
0017 #include <fmt/ranges.h>
0018
0019 #include <algorithms/detail/upcast.h>
0020 #include <algorithms/error.h>
0021 #include <algorithms/name.h>
0022
0023 namespace algorithms {
0024
0025 class PropertyError : public Error {
0026 public:
0027 PropertyError(std::string_view msg) : Error{msg, "algorithms::PropertyError"} {}
0028 };
0029
0030
0031
0032
0033 using PropertyValue = std::variant<bool, uint32_t, int32_t, uint64_t, int64_t, double, std::string,
0034 std::vector<bool>, std::vector<uint32_t>, std::vector<int32_t>,
0035 std::vector<uint64_t>, std::vector<int64_t>, std::vector<double>,
0036 std::vector<std::string>>;
0037
0038
0039 class Configurable {
0040 public:
0041 class PropertyBase;
0042 using PropertyMap = std::map<std::string_view, PropertyBase&>;
0043
0044 template <typename T> void setProperty(std::string_view name, T&& value) {
0045 m_props.at(name).set(static_cast<detail::upcast_type_t<T>>(value));
0046 }
0047 template <typename T> T getProperty(std::string_view name) const {
0048 return std::get<T>(m_props.at(name).get());
0049 }
0050 const PropertyMap& getProperties() const { return m_props; }
0051 bool hasProperty(std::string_view name) const {
0052 return m_props.count(name) && m_props.at(name).hasValue();
0053 }
0054
0055 auto missingProperties() const {
0056 std::vector<std::string_view> missing;
0057 for (const auto& [name, prop] : m_props) {
0058 if (!prop.hasValue()) {
0059 missing.push_back(name);
0060 }
0061 }
0062 return missing;
0063 }
0064
0065 void validate() const {
0066 const auto missing = missingProperties();
0067 if (!missing.empty()) {
0068 throw PropertyError(fmt::format("Missing properties: {}", missing));
0069 }
0070 }
0071
0072 private:
0073 void registerProperty(PropertyBase& prop) {
0074 if (m_props.count(prop.name())) {
0075 throw PropertyError(fmt::format("Duplicate property name: {}", prop.name()));
0076 }
0077 m_props.emplace(prop.name(), prop);
0078 }
0079
0080 PropertyMap m_props;
0081
0082 public:
0083 class PropertyBase : public NameMixin {
0084 public:
0085 PropertyBase(std::string_view name, std::string_view description)
0086 : NameMixin{name, description} {}
0087 virtual void set(const PropertyValue& v) = 0;
0088 virtual PropertyValue get() const = 0;
0089 bool hasValue() const { return m_has_value; }
0090
0091 protected:
0092 bool m_has_value = false;
0093 };
0094
0095
0096
0097 template <class T> class Property : public PropertyBase {
0098 public:
0099 using value_type = T;
0100 using impl_type = detail::upcast_type_t<T>;
0101
0102 Property(Configurable* owner, std::string_view name, std::string_view description)
0103 : PropertyBase{name, description} {
0104 if (owner) {
0105 owner->registerProperty(*this);
0106 } else {
0107 throw PropertyError(
0108 fmt::format("Attempting to create Property '{}' without valid owner", name));
0109 }
0110 }
0111 Property(Configurable* owner, std::string_view name, const value_type& v,
0112 std::string_view description)
0113 : Property(owner, name, description) {
0114 set(static_cast<impl_type>(v));
0115 }
0116
0117 Property() = delete;
0118 Property(const Property&) = default;
0119 Property& operator=(const Property&) = default;
0120
0121
0122
0123 virtual void set(const PropertyValue& v) {
0124 m_value = static_cast<value_type>(std::get<impl_type>(v));
0125 m_has_value = true;
0126 }
0127
0128
0129 virtual PropertyValue get() const { return static_cast<impl_type>(m_value); }
0130
0131
0132
0133 const value_type& value() const { return m_value; }
0134
0135
0136 operator T() const { return m_value; }
0137
0138
0139 template <typename U> bool operator==(const U& rhs) const { return m_value == rhs; }
0140 template <typename U> bool operator!=(const U& rhs) const { return m_value != rhs; }
0141 template <typename U> bool operator>(const U& rhs) const { return m_value > rhs; }
0142 template <typename U> bool operator>=(const U& rhs) const { return m_value >= rhs; }
0143 template <typename U> bool operator<(const U& rhs) const { return m_value < rhs; }
0144 template <typename U> bool operator<=(const U& rhs) const { return m_value <= rhs; }
0145 template <typename U> decltype(auto) operator+(const U& rhs) const { return m_value + rhs; }
0146 template <typename U> decltype(auto) operator-(const U& rhs) const { return m_value - rhs; }
0147 template <typename U> decltype(auto) operator*(const U& rhs) const { return m_value * rhs; }
0148 template <typename U> decltype(auto) operator/(const U& rhs) const { return m_value / rhs; }
0149
0150
0151
0152 template <class U = const value_type> decltype(auto) size() const { return value().size(); }
0153 template <class U = const value_type> decltype(auto) length() const { return value().length(); }
0154 template <class U = const value_type> decltype(auto) empty() const { return value().empty(); }
0155 template <class U = value_type> decltype(auto) clear() { value().clear(); }
0156 template <class U = const value_type> decltype(auto) begin() const { return value().begin(); }
0157 template <class U = const value_type> decltype(auto) end() const { return value().end(); }
0158 template <class U = value_type> decltype(auto) begin() { return value().begin(); }
0159 template <class U = value_type> decltype(auto) end() { return value().end(); }
0160 template <class Arg> decltype(auto) operator[](const Arg& arg) const { return value()[arg]; }
0161 template <class Arg> decltype(auto) operator[](const Arg& arg) { return value()[arg]; }
0162 template <class U = const value_type>
0163 decltype(auto) find(const typename U::key_type& key) const {
0164 return value().find(key);
0165 }
0166 template <class U = value_type> decltype(auto) find(const typename U::key_type& key) {
0167 return value().find(key);
0168 }
0169 template <class Arg> decltype(auto) erase(const Arg& arg) { return value().erase(arg); }
0170
0171
0172 template <class... Args>
0173 decltype(std::declval<value_type>()(std::declval<Args&&>()...))
0174 operator()(Args&&... args) const {
0175 return m_value()(std::forward<Args>(args)...);
0176 }
0177
0178 private:
0179 T m_value;
0180 };
0181 };
0182
0183
0184
0185
0186 using PropertyMixin = Configurable;
0187
0188 }
0189
0190
0191 #if __cpp_impl_three_way_comparison < 201711
0192 template <class T, class U>
0193 bool operator==(const U& rhs, const algorithms::Configurable::Property<T>& p) {
0194 return p == rhs;
0195 }
0196 #endif
0197 template <class T>
0198 std::ostream& operator<<(std::ostream& os, const algorithms::Configurable::Property<T>& p) {
0199 return os << p.value();
0200 }
0201
0202
0203 template <class T>
0204 struct fmt::formatter<algorithms::Configurable::Property<T>> : fmt::formatter<T> {};
0205