#pragma once #include "Common/enumFlags.h" #include #include template class ConfigValueAtomic { public: constexpr ConfigValueAtomic() : m_value(TType()), m_init_value(TType()) {} constexpr ConfigValueAtomic(const TType& init_value) : m_value(init_value), m_init_value(init_value) {} constexpr ConfigValueAtomic(TType&& init_value) : m_value(init_value), m_init_value(init_value) {} ConfigValueAtomic(const ConfigValueAtomic& v) : m_value(v.GetValue()), m_init_value(v.m_init_value) {} ConfigValueAtomic& operator=(const ConfigValueAtomic& v) { SetValue(v.GetValue()); return *this; } ConfigValueAtomic& operator=(const TType& v) { SetValue(v); return *this; } ConfigValueAtomic& operator=(TType&& v) { SetValue(v); return *this; } [[nodiscard]] inline TType GetValue() const { return m_value.load(); } void SetValue(const TType& v) { m_value = v; } [[nodiscard]] const TType& GetInitValue() const { return m_init_value; } operator TType() const { return m_value.load(); } private: std::atomic m_value; const TType m_init_value; }; template class ConfigValueNoneAtomic { public: constexpr ConfigValueNoneAtomic() : m_value({}), m_init_value({}) {} constexpr ConfigValueNoneAtomic(const TType& init_value) : m_value(init_value), m_init_value(init_value) {} constexpr ConfigValueNoneAtomic(TType&& init_value) : m_value(init_value), m_init_value(init_value) {} ConfigValueNoneAtomic(const ConfigValueNoneAtomic& v) : m_value(v.GetValue()), m_init_value(v.GetInitValue()) {} ConfigValueNoneAtomic& operator=(const ConfigValueNoneAtomic& v) { SetValue(v.GetValue()); return *this; } ConfigValueNoneAtomic& operator=(const TType& v) { SetValue(v); return *this; } ConfigValueNoneAtomic& operator=(TType&& v) { SetValue(v); return *this; } [[nodiscard]] TType GetValue() const { std::shared_lock lock(m_mutex); return m_value; } void SetValue(const TType& v) { std::lock_guard lock(m_mutex); m_value = v; } template >> void SetValue(std::string_view v) { std::lock_guard lock(m_mutex); m_value = v; } template >> void SetValue(std::wstring_view v) { std::lock_guard lock(m_mutex); m_value = v; } [[nodiscard]] const TType& GetInitValue() const { return m_init_value; } [[nodiscard]] operator TType() const { return GetValue(); } protected: mutable std::shared_mutex m_mutex; TType m_value; const TType m_init_value; }; template constexpr bool is_atomic_type_v = std::is_trivially_copyable_v && std::is_copy_constructible_v && std::is_move_constructible_v && std::is_copy_assignable_v && std::is_move_assignable_v; template class ConfigValue : public std::conditional, ConfigValueAtomic, ConfigValueNoneAtomic>::type { public: using base_type = typename std::conditional, ConfigValueAtomic, ConfigValueNoneAtomic>::type; using base_type::base_type; ConfigValue& operator=(const ConfigValue& v) { base_type::operator=(v.GetValue()); return *this; } ConfigValue& operator=(const TType& v) { base_type::operator=(v); return *this; } ConfigValue& operator=(TType&& v) { base_type::operator=(v); return *this; } }; template class ConfigValueBounds : public ConfigValue { public: using base_type = ConfigValue; constexpr ConfigValueBounds(const TType& min, const TType& init_value, const TType& max) :base_type(init_value), m_min_value(min), m_max_value(max) { assert(m_min_value <= init_value && init_value <= m_max_value); } constexpr ConfigValueBounds(TType&& min, TType&& init_value, TType&& max) : base_type(std::forward(init_value)), m_min_value(min), m_max_value(max) { assert(m_min_value <= init_value && init_value <= m_max_value); } // init from enum with iterators template::value && EnableEnumIterators::enable, TType>> constexpr ConfigValueBounds() : base_type(), m_min_value(begin(TEnum{})), m_max_value(rbegin(TEnum{})) { assert(m_min_value <= this->GetInitValue() && this->GetInitValue() <= m_max_value); } template::value && EnableEnumIterators::enable, TType>> constexpr ConfigValueBounds(const TType& init_value) : base_type(std::forward(init_value)), m_min_value(begin(init_value)), m_max_value(rbegin(init_value)) { assert(m_min_value <= init_value && init_value <= m_max_value); } template::value && EnableEnumIterators::enable, TType>> constexpr ConfigValueBounds(TType&& init_value) : base_type(std::forward(init_value)), m_min_value(begin(init_value)), m_max_value(rbegin(init_value)) { assert(m_min_value <= init_value && init_value <= m_max_value); } ConfigValueBounds& operator=(const ConfigValueBounds& v) { base_type::operator=(v.GetValue()); const auto& value = this->GetValue(); if (value < GetMin() || value > GetMax()) base_type::SetValue(this->GetInitValue()); return *this; }; ConfigValueBounds& operator=(const TType& v) { base_type::operator=(v); const auto& value = this->GetValue(); if (value < GetMin() || value > GetMax()) base_type::SetValue(this->GetInitValue()); return *this; }; ConfigValueBounds& operator=(TType&& v) { base_type::operator=(v); const auto& value = this->GetValue(); if (value < GetMin() || value > GetMax()) base_type::SetValue(this->GetInitValue()); return *this; }; [[nodiscard]] const TType& GetMax() const { return m_max_value; } [[nodiscard]] const TType& GetMin() const { return m_min_value; } private: const TType m_min_value; const TType m_max_value; }; template struct fmt::formatter< ConfigValue > : formatter { template auto format(const ConfigValue& v, FormatContext& ctx) { return formatter::format(v.GetValue(), ctx); } }; template struct fmt::formatter< ConfigValueBounds > : formatter { template auto format(const ConfigValueBounds& v, FormatContext& ctx) { return formatter::format(v.GetValue(), ctx); } };