diff --git a/lib/core/include/qx/core/qx-setonce.h b/lib/core/include/qx/core/qx-setonce.h index 45e51b6c..69480256 100644 --- a/lib/core/include/qx/core/qx-setonce.h +++ b/lib/core/include/qx/core/qx-setonce.h @@ -2,7 +2,7 @@ #define QX_SETONCE_H // Standard Library Includes -#include +#include // Extra-component Includes #include @@ -10,20 +10,76 @@ namespace Qx { -template> - requires std::is_assignable_v && Qx::defines_call_for_s -class SetOnce +/* I'd prefer doing this in a way where we don't need to repeat the common implementation + * for each class, but using a base can screw up doxygen, and having optional data members + * is fuggy as of C++20, so for now we just duplicate as needed. + */ + +template +class SetOnce; + +/*! @cond */ + +template + requires std::assignable_from +class SetOnce +{ +//-Instance Members---------------------------------------------------------------------------------------------------- +private: + bool mSet; + T mDefaultValue; + T mValue; + +//-Constructor------------------------------------------------------------------------------------------------------- +public: + SetOnce(T initial = T()) : + mSet(false), + mDefaultValue(initial), + mValue(initial) + {} + +//-Instance Functions-------------------------------------------------------------------------------------------------- +public: + bool isSet() const { return mSet; } + const T& value() const { return mValue; } + + void reset() + { + mSet = false; + mValue = mDefaultValue; + } + + SetOnce& operator=(const T& value) + { + if(!mSet) + { + mValue = value; + mSet = true; + } + + return *this; + } + +//-Operators-------------------------------------------------------------------------------------------------- + const T& operator*() const { return mValue; } + const T* operator->() const { return &mValue; } +}; +/*! @endcond */ + +template + requires std::assignable_from && comparator +class SetOnce { //-Instance Members---------------------------------------------------------------------------------------------------- private: - CompareEq mComparator; + C mComparator; bool mSet; T mDefaultValue; T mValue; //-Constructor------------------------------------------------------------------------------------------------------- public: - SetOnce(T initial, const CompareEq& comp = CompareEq()) : + SetOnce(T initial, C&& comp = C()) : mComparator(comp), mSet(false), mDefaultValue(initial), @@ -41,7 +97,7 @@ class SetOnce mValue = mDefaultValue; } - SetOnce& operator=(const T& value) + SetOnce& operator=(const T& value) { if(!mSet && !mComparator(mDefaultValue, value)) { @@ -51,8 +107,15 @@ class SetOnce return *this; } + +//-Operators-------------------------------------------------------------------------------------------------- + const T& operator*() const { return mValue; } + const T* operator->() const { return &mValue; } + explicit operator bool() const { return mSet; } }; + + } #endif // QX_SETONCE_H diff --git a/lib/core/src/qx-setonce.dox b/lib/core/src/qx-setonce.dox index 45843e40..e8039ee2 100644 --- a/lib/core/src/qx-setonce.dox +++ b/lib/core/src/qx-setonce.dox @@ -5,48 +5,49 @@ namespace Qx //=============================================================================================================== /*! - * @class SetOnce qx/core/qx-setonce.h + * @class SetOnces qx/core/qx-setonce.h * @ingroup qx-core * * @brief The SetOnce template class acts as a container for a value that can only be set once. * - * The optional @a CompareEq template parameter can be used to provide a custom compare-equal function - * object type. + * The optional @a C template parameter (defaults to @c void) can be used to provide a comparator + * (such as std::equal_to), which is then used to reject assignment if the passed value is the same + * as the containers default. + * + * @sa operator=(). */ //-Constructor---------------------------------------------------------------------------------------------- //Public: /*! - * @fn SetOnce::SetOnce(T initial, const CompareEq& comp) + * @fn SetOnce::SetOnce(T initial, C&& comp = C()) * * Creates a SetOnce container that holds the initial value @a initial. * * The container is initially unset and only holds this value until it is set. * - * Optionally, a custom compare-equal function can be provided through @a comp, which - * is used to determine whether or not an assigned value is different from the - * container's initial value. + * When C is not @c void, @a comp is used to compare the input value to the container's + * default value when performing an assignment. * * @sa operator=(const T& value). */ - //-Instance Functions---------------------------------------------------------------------------------------------- //Public: /*! - * @fn SetOnce::isSet() const + * @fn SetOnce::isSet() const * * Returns @c true if the containers value has been set; otherwise returns @c false. */ /*! - * @fn const T& SetOnce::value() const + * @fn const T& SetOnce::value() const * * Returns the current value of the container. */ /*! - * @fn void SetOnce::reset() + * @fn void SetOnce::reset() * * Resets the container to its initial state. * @@ -56,12 +57,41 @@ namespace Qx */ /*! - * @fn SetOnce& SetOnce::operator=(const T& value) + * @fn SetOnce& SetOnce::operator=(const T& value) * - * Sets the value of the container to @a value, if it is different from its initial value. + * Sets the value of the container to @a value. If C is not @c void and @a value is + * the same as the container's default value, the container is not considered to + * be set. + * + * To clarify: + * - C = void: Any assignment causes the container to be considered set. + * - C satisfies @ref Qx::comparator : Only assignment of a value other than the default + * causes the container to be considered set. * * Once the containers value has been set it cannot be changed again until it is reset. * * @sa reset(). */ + +//-Instance Functions---------------------------------------------------------------------------------------------- +//Public: +/*! + * @fn const T& SetOnce::operator*() const + * + * Same as value(). + */ + +/*! + * @fn const T* SetOnce::operator->() const + * + * Allows access to members of T for the value of the container. + */ + +/*! + * @fn SetOnce::operator bool() const + * + * Produces the boolean value @c true if the container is set; otherwise, produces @c false. + */ + + } diff --git a/lib/utility/include/qx/utility/qx-concepts.h b/lib/utility/include/qx/utility/qx-concepts.h index f9cac1f4..8c70864b 100644 --- a/lib/utility/include/qx/utility/qx-concepts.h +++ b/lib/utility/include/qx/utility/qx-concepts.h @@ -504,6 +504,9 @@ concept traverseable = std::bidirectional_iterator & std::is_default_constructible_v && requires(K klass) {{ klass.size() } -> std::integral<>;}; +template +concept comparator = defines_call_for_s; + // Conversion template concept static_castable_to = requires(K klass) {{ static_cast(klass) };}; diff --git a/lib/utility/src/qx-concepts.dox b/lib/utility/src/qx-concepts.dox index 60d9a015..040a351a 100644 --- a/lib/utility/src/qx-concepts.dox +++ b/lib/utility/src/qx-concepts.dox @@ -1101,6 +1101,16 @@ namespace Qx * is default constructable, and defines a member function 'size' that returns an integral type. */ +/*! + * @concept comparator + * @brief Specifies that a type can act as a comparator. + * + * Satisfied if @c F returns a @c bool when called with two values of T. + * + * Generally it is assumed that the comparator will return @c true if the values are equal, and + * @c false otherwise. + */ + // Conversion /*! * @concept static_castable_to