Skip to content

Commit

Permalink
Have SetOnce default to be comparatorless
Browse files Browse the repository at this point in the history
In this case any assignment will cause the container to be set. One must
explicitly provide a comparator in order to have values equal to the
default be rejected.
  • Loading branch information
oblivioncth committed Nov 18, 2024
1 parent 44a5b02 commit 34a6dd6
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 20 deletions.
77 changes: 70 additions & 7 deletions lib/core/include/qx/core/qx-setonce.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,84 @@
#define QX_SETONCE_H

// Standard Library Includes
#include <type_traits>
#include <concepts>

// Extra-component Includes
#include <qx/utility/qx-concepts.h>

namespace Qx
{

template<typename T, class CompareEq = std::equal_to<T>>
requires std::is_assignable_v<T&, T> && Qx::defines_call_for_s<CompareEq, bool, T, T>
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<typename T, class C = void>
class SetOnce;

/*! @cond */

template<typename T>
requires std::assignable_from<T&, T>
class SetOnce<T, void>
{
//-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<T, void>& 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<typename T, class C>
requires std::assignable_from<T&, T> && comparator<C, T>
class SetOnce<T, C>
{
//-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),
Expand All @@ -41,7 +97,7 @@ class SetOnce
mValue = mDefaultValue;
}

SetOnce<T, CompareEq>& operator=(const T& value)
SetOnce<T, C>& operator=(const T& value)
{
if(!mSet && !mComparator(mDefaultValue, value))
{
Expand All @@ -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
56 changes: 43 additions & 13 deletions lib/core/src/qx-setonce.dox
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,49 @@ namespace Qx
//===============================================================================================================

/*!
* @class SetOnce qx/core/qx-setonce.h
* @class SetOnce<T, C>s 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<T, CompareEq>::SetOnce(T initial, const CompareEq& comp)
* @fn SetOnce<T, C>::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<T, CompareEq>::isSet() const
* @fn SetOnce<T, C>::isSet() const
*
* Returns @c true if the containers value has been set; otherwise returns @c false.
*/

/*!
* @fn const T& SetOnce<T, CompareEq>::value() const
* @fn const T& SetOnce<T, C>::value() const
*
* Returns the current value of the container.
*/

/*!
* @fn void SetOnce<T, CompareEq>::reset()
* @fn void SetOnce<T, C>::reset()
*
* Resets the container to its initial state.
*
Expand All @@ -56,12 +57,41 @@ namespace Qx
*/

/*!
* @fn SetOnce<T, CompareEq>& SetOnce<T, CompareEq>::operator=(const T& value)
* @fn SetOnce<T, C>& SetOnce<T, C>::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<C, T> : 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<T, C>::operator*() const
*
* Same as value().
*/

/*!
* @fn const T* SetOnce<T, C>::operator->() const
*
* Allows access to members of T for the value of the container.
*/

/*!
* @fn SetOnce<T, C>::operator bool() const
*
* Produces the boolean value @c true if the container is set; otherwise, produces @c false.
*/


}
3 changes: 3 additions & 0 deletions lib/utility/include/qx/utility/qx-concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,9 @@ concept traverseable = std::bidirectional_iterator<typename K::const_iterator> &
std::is_default_constructible_v<K> &&
requires(K klass) {{ klass.size() } -> std::integral<>;};

template<typename F, typename T>
concept comparator = defines_call_for_s<F, bool, T, T>;

// Conversion
template<class K, typename T>
concept static_castable_to = requires(K klass) {{ static_cast<T>(klass) };};
Expand Down
10 changes: 10 additions & 0 deletions lib/utility/src/qx-concepts.dox
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 34a6dd6

Please sign in to comment.