mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 00:40:06 +00:00 
			
		
		
		
	Settings variable abstract base, additional validation, and reading/writing JSON
This commit is contained in:
		
							parent
							
								
									1ad67de71b
								
							
						
					
					
						commit
						46c4dd3780
					
				
					 7 changed files with 408 additions and 17 deletions
				
			
		|  | @ -11,6 +11,7 @@ namespace settings | |||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::settings::settings_container"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| template<class Container> | ||||
| class SettingsContainer<Container>::Impl | ||||
|  | @ -61,16 +62,29 @@ bool SettingsContainer<Container>::SetValueOrDefault(const Container& c) | |||
|          } | ||||
|          else if (p->elementMinimum_.has_value() && value < p->elementMinimum_) | ||||
|          { | ||||
|             logger_->warn("{0} less than minimum ({1} < {2}), setting to: {2}", | ||||
|                           this->name(), | ||||
|                           value, | ||||
|                           *p->elementMinimum_); | ||||
|             validated = false; | ||||
|             return *p->elementMinimum_; | ||||
|          } | ||||
|          else if (p->elementMaximum_.has_value() && value > p->elementMaximum_) | ||||
|          { | ||||
|             logger_->warn( | ||||
|                "{0} greater than maximum ({1} > {2}), setting to: {2}", | ||||
|                this->name(), | ||||
|                value, | ||||
|                *p->elementMaximum_); | ||||
|             validated = false; | ||||
|             return *p->elementMaximum_; | ||||
|          } | ||||
|          else | ||||
|          { | ||||
|             logger_->warn("{} validation failed ({}), setting to default: {}", | ||||
|                           this->name(), | ||||
|                           value, | ||||
|                           p->elementDefault_); | ||||
|             validated = false; | ||||
|             return p->elementDefault_; | ||||
|          } | ||||
|  | @ -143,6 +157,21 @@ bool SettingsContainer<Container>::ValidateElement(const T& value) const | |||
|       (p->elementValidator_ == nullptr || p->elementValidator_(value))); | ||||
| } | ||||
| 
 | ||||
| template<class Container> | ||||
| bool SettingsContainer<Container>::Equals(const SettingsVariableBase& o) const | ||||
| { | ||||
|    // This is only ever called with SettingsContainer<Container>, so static_cast
 | ||||
|    // is safe
 | ||||
|    const SettingsContainer<Container>& v = | ||||
|       static_cast<const SettingsContainer<Container>&>(o); | ||||
| 
 | ||||
|    // Don't compare validator
 | ||||
|    return SettingsVariable<Container>::Equals(o) && | ||||
|           p->elementDefault_ == v.p->elementDefault_ && | ||||
|           p->elementMinimum_ == v.p->elementMinimum_ && | ||||
|           p->elementMaximum_ == v.p->elementMaximum_; | ||||
| } | ||||
| 
 | ||||
| } // namespace settings
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  |  | |||
|  | @ -24,25 +24,83 @@ public: | |||
|    SettingsContainer(SettingsContainer&&) noexcept; | ||||
|    SettingsContainer& operator=(SettingsContainer&&) noexcept; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the current value of the settings variable. If the value is out of | ||||
|     * range, the value is set to the minimum or maximum. If the value fails | ||||
|     * validation, the value is set to default. | ||||
|     * | ||||
|     * @param c Container value to set | ||||
|     * | ||||
|     * @return true if the value is valid, false if the value was modified. | ||||
|     */ | ||||
|    bool SetValueOrDefault(const Container& c) override; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Validate the container value against the defined parameters of the | ||||
|     * settings variable. | ||||
|     * | ||||
|     * @param c Container value to validate | ||||
|     * | ||||
|     * @return true if the value is valid, false if the value failed validation. | ||||
|     */ | ||||
|    bool Validate(const Container& c) const override; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Validate the element value against the defined parameters of the settings | ||||
|     * variable. | ||||
|     * | ||||
|     * @param value Element value to validate | ||||
|     * | ||||
|     * @return true if the value is valid, false if the value failed validation. | ||||
|     */ | ||||
|    bool ValidateElement(const T& value) const; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Gets the default element value of the settings variable. | ||||
|     * | ||||
|     * @return Default element value | ||||
|     */ | ||||
|    T GetElementDefault() const; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the default element value of the settings variable. | ||||
|     * | ||||
|     * @param value Default element value | ||||
|     */ | ||||
|    void SetElementDefault(const T& value); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the minimum element value of the settings variable. | ||||
|     * | ||||
|     * @param value Minimum element value | ||||
|     */ | ||||
|    void SetElementMinimum(const T& value); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the maximum element value of the settings variable. | ||||
|     * | ||||
|     * @param value Maximum element value | ||||
|     */ | ||||
|    void SetElementMaximum(const T& value); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets a custom validator function for each element of the settings | ||||
|     * variable. | ||||
|     * | ||||
|     * @param validator Element validator function | ||||
|     */ | ||||
|    void SetElementValidator(std::function<bool(const T&)> validator); | ||||
| 
 | ||||
| protected: | ||||
|    virtual bool Equals(const SettingsVariableBase& o) const override; | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| #ifdef SETTINGS_CONTAINER_IMPLEMENTATION | ||||
| template class SettingsContainer<std::vector<int64_t>>; | ||||
| template class SettingsContainer<std::vector<std::int64_t>>; | ||||
| #endif | ||||
| 
 | ||||
| } // namespace settings
 | ||||
|  |  | |||
|  | @ -3,6 +3,11 @@ | |||
| #include <scwx/qt/settings/settings_variable.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <optional> | ||||
| 
 | ||||
| #include <boost/json.hpp> | ||||
| #include <fmt/ostream.h> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
|  | @ -11,16 +16,16 @@ namespace settings | |||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::settings::settings_variable"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| template<class T> | ||||
| class SettingsVariable<T>::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl(const std::string& name) : name_ {name} {} | ||||
|    explicit Impl() {} | ||||
| 
 | ||||
|    ~Impl() {} | ||||
| 
 | ||||
|    const std::string             name_; | ||||
|    T                             value_ {}; | ||||
|    T                             default_ {}; | ||||
|    std::optional<T>              staged_ {}; | ||||
|  | @ -31,7 +36,7 @@ public: | |||
| 
 | ||||
| template<class T> | ||||
| SettingsVariable<T>::SettingsVariable(const std::string& name) : | ||||
|     p(std::make_unique<Impl>(name)) | ||||
|     SettingsVariableBase(name), p(std::make_unique<Impl>()) | ||||
| { | ||||
| } | ||||
| template<class T> | ||||
|  | @ -44,9 +49,16 @@ SettingsVariable<T>& | |||
| SettingsVariable<T>::operator=(SettingsVariable&&) noexcept = default; | ||||
| 
 | ||||
| template<class T> | ||||
| std::string SettingsVariable<T>::name() const | ||||
| inline auto FormatParameter(const T& value) | ||||
| { | ||||
|    return p->name_; | ||||
|    if constexpr (std::is_integral_v<T> || std::is_same_v<T, std::string>) | ||||
|    { | ||||
|       return value; | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       return fmt::join(value, ", "); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
|  | @ -81,14 +93,26 @@ bool SettingsVariable<T>::SetValueOrDefault(const T& value) | |||
|    } | ||||
|    else if (p->minimum_.has_value() && value < p->minimum_) | ||||
|    { | ||||
|       logger_->warn("{0} less than minimum ({1} < {2}), setting to: {2}", | ||||
|                     name(), | ||||
|                     FormatParameter<T>(value), | ||||
|                     FormatParameter<T>(*p->minimum_)); | ||||
|       p->value_ = *p->minimum_; | ||||
|    } | ||||
|    else if (p->maximum_.has_value() && value > p->maximum_) | ||||
|    { | ||||
|       logger_->warn("{0} greater than maximum ({1} > {2}), setting to: {2}", | ||||
|                     name(), | ||||
|                     FormatParameter<T>(value), | ||||
|                     FormatParameter<T>(*p->maximum_)); | ||||
|       p->value_ = *p->maximum_; | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       logger_->warn("{} validation failed ({}), setting to default: {}", | ||||
|                     name(), | ||||
|                     FormatParameter<T>(value), | ||||
|                     FormatParameter<T>(p->default_)); | ||||
|       p->value_ = p->default_; | ||||
|    } | ||||
| 
 | ||||
|  | @ -164,6 +188,59 @@ bool SettingsVariable<T>::Validate(const T& value) const | |||
|       (p->validator_ == nullptr || p->validator_(value)));  // User-validation
 | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| bool SettingsVariable<T>::ReadValue(const boost::json::object& json) | ||||
| { | ||||
|    const boost::json::value* jv        = json.if_contains(name()); | ||||
|    bool                      validated = false; | ||||
| 
 | ||||
|    if (jv != nullptr) | ||||
|    { | ||||
|       try | ||||
|       { | ||||
|          validated = SetValueOrDefault(boost::json::value_to<T>(*jv)); | ||||
|       } | ||||
|       catch (const std::exception& ex) | ||||
|       { | ||||
|          logger_->warn("{} is invalid ({}), setting to default: {}", | ||||
|                        name(), | ||||
|                        ex.what(), | ||||
|                        FormatParameter<T>(p->default_)); | ||||
|          p->value_ = p->default_; | ||||
|       } | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       logger_->debug("{} is not present, setting to default: {}", | ||||
|                      name(), | ||||
|                      FormatParameter<T>(p->default_)); | ||||
|       p->value_ = p->default_; | ||||
|    } | ||||
| 
 | ||||
|    return validated; | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| void SettingsVariable<T>::WriteValue(boost::json::object& json) const | ||||
| { | ||||
|    json[name()] = boost::json::value_from<T&>(p->value_); | ||||
| } | ||||
| 
 | ||||
| template<class T> | ||||
| bool SettingsVariable<T>::Equals(const SettingsVariableBase& o) const | ||||
| { | ||||
|    // This is only ever called with SettingsVariable<T>, so static_cast is safe
 | ||||
|    const SettingsVariable<T>& v = static_cast<const SettingsVariable<T>&>(o); | ||||
| 
 | ||||
|    // Don't compare validator
 | ||||
|    return SettingsVariableBase::Equals(o) && //
 | ||||
|           p->value_ == v.p->value_ &&        //
 | ||||
|           p->default_ == v.p->default_ &&    //
 | ||||
|           p->staged_ == v.p->staged_ &&      //
 | ||||
|           p->minimum_ == v.p->minimum_ &&    //
 | ||||
|           p->maximum_ == v.p->maximum_; | ||||
| } | ||||
| 
 | ||||
| } // namespace settings
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/settings/settings_variable_base.hpp> | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
|  | @ -12,7 +12,7 @@ namespace settings | |||
| { | ||||
| 
 | ||||
| template<class T> | ||||
| class SettingsVariable | ||||
| class SettingsVariable : public SettingsVariableBase | ||||
| { | ||||
| public: | ||||
|    explicit SettingsVariable(const std::string& name); | ||||
|  | @ -24,25 +24,120 @@ public: | |||
|    SettingsVariable(SettingsVariable&&) noexcept; | ||||
|    SettingsVariable& operator=(SettingsVariable&&) noexcept; | ||||
| 
 | ||||
|    std::string name() const; | ||||
|    /**
 | ||||
|     * Gets the current value of the settings variable. | ||||
|     * | ||||
|     * @return Current value | ||||
|     */ | ||||
|    T GetValue() const; | ||||
| 
 | ||||
|    T            GetValue() const; | ||||
|    bool         SetValue(const T& value); | ||||
|    /**
 | ||||
|     * Sets the current value of the settings variable. | ||||
|     * | ||||
|     * @param value Value to set | ||||
|     * | ||||
|     * @return true if the current value was set, false if the value failed | ||||
|     * validation. | ||||
|     */ | ||||
|    bool SetValue(const T& value); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the current value of the settings variable. If the value is out of | ||||
|     * range, the value is set to the minimum or maximum. If the value fails | ||||
|     * validation, the value is set to default. | ||||
|     * | ||||
|     * @param value Value to set | ||||
|     * | ||||
|     * @return true if the value is valid, false if the value was modified. | ||||
|     */ | ||||
|    virtual bool SetValueOrDefault(const T& value); | ||||
|    void         SetValueToDefault(); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the current value of the settings variable to default. | ||||
|     */ | ||||
|    void SetValueToDefault() override; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the staged value of the settings variable. | ||||
|     * | ||||
|     * @param value Value to stage | ||||
|     * | ||||
|     * @return true if the staged value was set, false if the value failed | ||||
|     * validation. | ||||
|     */ | ||||
|    bool StageValue(const T& value); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the current value of the settings variable to the staged value. | ||||
|     */ | ||||
|    void Commit(); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Validate the value against the defined parameters of the settings | ||||
|     * variable. | ||||
|     * | ||||
|     * @param value Value to validate | ||||
|     * | ||||
|     * @return true if the value is valid, false if the value failed validation. | ||||
|     */ | ||||
|    virtual bool Validate(const T& value) const; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Gets the default value of the settings variable. | ||||
|     * | ||||
|     * @return Default value | ||||
|     */ | ||||
|    T GetDefault() const; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the default value of the settings variable. | ||||
|     * | ||||
|     * @param value Default value | ||||
|     */ | ||||
|    void SetDefault(const T& value); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the minimum value of the settings variable. | ||||
|     * | ||||
|     * @param value Minimum value | ||||
|     */ | ||||
|    void SetMinimum(const T& value); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the maximum value of the settings variable. | ||||
|     * | ||||
|     * @param value Maximum value | ||||
|     */ | ||||
|    void SetMaximum(const T& value); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets a custom validator function for the settings variable. | ||||
|     * | ||||
|     * @param validator Validator function | ||||
|     */ | ||||
|    void SetValidator(std::function<bool(const T&)> validator); | ||||
| 
 | ||||
|    /**
 | ||||
|     * Reads the value from the JSON object. If the read value is out of range, | ||||
|     * the value is set to the minimum or maximum. If the read value fails | ||||
|     * validation, the value is set to default. | ||||
|     * | ||||
|     * @param json JSON object to read | ||||
|     * | ||||
|     * @return true if the read value is valid, false if the value was modified. | ||||
|     */ | ||||
|    virtual bool ReadValue(const boost::json::object& json) override; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Writes the current value to the JSON object. | ||||
|     * | ||||
|     * @param json JSON object to write | ||||
|     */ | ||||
|    virtual void WriteValue(boost::json::object& json) const override; | ||||
| 
 | ||||
| protected: | ||||
|    virtual bool Equals(const SettingsVariableBase& o) const override; | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::unique_ptr<Impl> p; | ||||
|  | @ -50,11 +145,11 @@ private: | |||
| 
 | ||||
| #ifdef SETTINGS_VARIABLE_IMPLEMENTATION | ||||
| template class SettingsVariable<bool>; | ||||
| template class SettingsVariable<int64_t>; | ||||
| template class SettingsVariable<std::int64_t>; | ||||
| template class SettingsVariable<std::string>; | ||||
| 
 | ||||
| // Containers are not to be used directly
 | ||||
| template class SettingsVariable<std::vector<int64_t>>; | ||||
| template class SettingsVariable<std::vector<std::int64_t>>; | ||||
| #endif | ||||
| 
 | ||||
| } // namespace settings
 | ||||
|  |  | |||
							
								
								
									
										54
									
								
								scwx-qt/source/scwx/qt/settings/settings_variable_base.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								scwx-qt/source/scwx/qt/settings/settings_variable_base.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| #include <scwx/qt/settings/settings_variable_base.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace settings | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = | ||||
|    "scwx::qt::settings::settings_variable_base"; | ||||
| 
 | ||||
| class SettingsVariableBase::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl(const std::string& name) : name_ {name} {} | ||||
| 
 | ||||
|    ~Impl() {} | ||||
| 
 | ||||
|    const std::string name_; | ||||
| }; | ||||
| 
 | ||||
| SettingsVariableBase::SettingsVariableBase(const std::string& name) : | ||||
|     p(std::make_unique<Impl>(name)) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| SettingsVariableBase::~SettingsVariableBase() = default; | ||||
| 
 | ||||
| SettingsVariableBase::SettingsVariableBase(SettingsVariableBase&&) noexcept = | ||||
|    default; | ||||
| 
 | ||||
| SettingsVariableBase& | ||||
| SettingsVariableBase::operator=(SettingsVariableBase&&) noexcept = default; | ||||
| 
 | ||||
| std::string SettingsVariableBase::name() const | ||||
| { | ||||
|    return p->name_; | ||||
| } | ||||
| 
 | ||||
| bool SettingsVariableBase::Equals(const SettingsVariableBase& o) const | ||||
| { | ||||
|    return p->name_ == o.p->name_; | ||||
| } | ||||
| 
 | ||||
| bool operator==(const SettingsVariableBase& lhs, | ||||
|                 const SettingsVariableBase& rhs) | ||||
| { | ||||
|    return typeid(lhs) == typeid(rhs) && lhs.Equals(rhs); | ||||
| } | ||||
| 
 | ||||
| } // namespace settings
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										76
									
								
								scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| #include <boost/json/object.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace settings | ||||
| { | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Settings Variable base class | ||||
|  */ | ||||
| class SettingsVariableBase | ||||
| { | ||||
| protected: | ||||
|    explicit SettingsVariableBase(const std::string& name); | ||||
|    ~SettingsVariableBase(); | ||||
| 
 | ||||
| public: | ||||
|    SettingsVariableBase(const SettingsVariableBase&)            = delete; | ||||
|    SettingsVariableBase& operator=(const SettingsVariableBase&) = delete; | ||||
| 
 | ||||
|    SettingsVariableBase(SettingsVariableBase&&) noexcept; | ||||
|    SettingsVariableBase& operator=(SettingsVariableBase&&) noexcept; | ||||
| 
 | ||||
|    std::string name() const; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the current value of the settings variable to default. | ||||
|     */ | ||||
|    virtual void SetValueToDefault() = 0; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Sets the current value of the settings variable to the staged value. | ||||
|     */ | ||||
|    virtual void Commit() = 0; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Reads the value from the JSON object. If the read value is out of range, | ||||
|     * the value is set to the minimum or maximum. If the read value fails | ||||
|     * validation, the value is set to default. | ||||
|     * | ||||
|     * @param json JSON object to read | ||||
|     * | ||||
|     * @return true if the read value is valid, false if the value was modified. | ||||
|     */ | ||||
|    virtual bool ReadValue(const boost::json::object& json) = 0; | ||||
| 
 | ||||
|    /**
 | ||||
|     * Writes the current value to the JSON object. | ||||
|     * | ||||
|     * @param json JSON object to write | ||||
|     */ | ||||
|    virtual void WriteValue(boost::json::object& json) const = 0; | ||||
| 
 | ||||
| protected: | ||||
|    friend bool  operator==(const SettingsVariableBase& lhs, | ||||
|                           const SettingsVariableBase& rhs); | ||||
|    virtual bool Equals(const SettingsVariableBase& o) const; | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| bool operator==(const SettingsVariableBase& lhs, | ||||
|                 const SettingsVariableBase& rhs); | ||||
| 
 | ||||
| } // namespace settings
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat