Initial working version

This commit is contained in:
John Wellbelove 2026-09-14 15:33:54 +01:00
parent d839849841
commit 8e3ad413cf

View File

@ -38,10 +38,60 @@ SOFTWARE.
#include "platform.h"
#include "algorithm.h"
#include "exception.h"
#include "integral_limits.h"
#include "static_assert.h"
#include "type_traits.h"
namespace etl
{
namespace private_cyclic_value
{
//*************************************************************************
/// Advances a value and wraps it at the supplied limits.
///\param value The current value.
///\param min_value The minimum value.
///\param max_value The maximum value.
///\param n The number of steps.
///\return The advanced value.
//*************************************************************************
template <typename T, typename TStep>
ETL_NODISCARD
static ETL_CONSTEXPR14 T advance(T value, T min_value, T max_value, TStep n) ETL_NOEXCEPT
{
typedef typename etl::make_unsigned<T>::type unsigned_type;
if (n == 0)
{
return value;
}
// Check for full range limits.
const bool is_full_range = (min_value == etl::integral_limits<T>::min) && (max_value == etl::integral_limits<T>::max);
if (is_full_range)
{
// This is safe as the type's own overflow behaviour is modulo wrap-around.
return static_cast<T>(etl::to_unsigned(value) + static_cast<unsigned_type>(n));
}
else
{
// Size of the wrap-around range.
const unsigned_type range = (etl::to_unsigned(max_value) - etl::to_unsigned(min_value)) + 1U;
// Value expressed as an offset from min_value (0 .. range - 1).
const unsigned_type current = etl::to_unsigned(value) - etl::to_unsigned(min_value);
// Reduce the step to something within a single lap of the range.
const unsigned_type step = etl::absolute_unsigned(n) % range;
// Direction-corrected offset to add, always in [0, range).
const unsigned_type offset = (n > 0) ? step : (range - step) % range;
return static_cast<T>(etl::to_unsigned(min_value) + (current + offset) % range);
}
}
} // namespace private_cyclic_value
//***************************************************************************
/// Provides a value that cycles between two limits.
//***************************************************************************
@ -65,7 +115,7 @@ namespace etl
/// Default constructor.
/// The initial value is set to the first value.
//*************************************************************************
ETL_CONSTEXPR cyclic_value()
ETL_CONSTEXPR cyclic_value() ETL_NOEXCEPT
: value(First)
{
}
@ -75,15 +125,15 @@ namespace etl
/// Set to an initial value.
/// Clamped to the range.
//*************************************************************************
ETL_CONSTEXPR14 explicit cyclic_value(T initial)
ETL_CONSTEXPR explicit cyclic_value(T initial) ETL_NOEXCEPT
: value(etl::clamp(initial, First, Last))
{
set(initial);
}
//*************************************************************************
/// Copy constructor.
//*************************************************************************
ETL_CONSTEXPR cyclic_value(const cyclic_value<T, First, Last>& other)
ETL_CONSTEXPR cyclic_value(const cyclic_value<T, First, Last>& other) ETL_NOEXCEPT
: value(other.value)
{
}
@ -91,19 +141,45 @@ namespace etl
//*************************************************************************
/// Assignment operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value& operator=(const cyclic_value<T, First, Last>& other)
ETL_CONSTEXPR14 cyclic_value& operator=(const cyclic_value<T, First, Last>& other) ETL_NOEXCEPT
{
value = other.value;
return *this;
}
//*************************************************************************
/// Adds a number of steps and clamps to the range.
/// Floating-point steps may be fractional. NaN is rejected.
///\param n The number of steps.
///\return A reference to this value.
//*************************************************************************
template <typename TStep>
ETL_CONSTEXPR14 cyclic_value& operator+=(TStep n) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
{
advance(n);
return *this;
}
//*************************************************************************
/// Subtracts a number of steps and clamps to the range.
/// Floating-point steps may be fractional. NaN is rejected.
///\param n The number of steps.
///\return A reference to this value.
//*************************************************************************
template <typename TStep>
ETL_CONSTEXPR14 cyclic_value& operator-=(TStep n) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
{
value = private_cyclic_value::advance(value, First, Last, -n);
return *this;
}
//*************************************************************************
/// Sets the value.
/// Truncates to the First/Last range.
///\param value The value.
//*************************************************************************
ETL_CONSTEXPR14 void set(T value_)
ETL_CONSTEXPR14 void set(T value_) ETL_NOEXCEPT
{
value = etl::clamp(value_, First, Last);
}
@ -111,7 +187,7 @@ namespace etl
//*************************************************************************
/// Resets the value to the first in the range.
//*************************************************************************
ETL_CONSTEXPR14 void to_first()
ETL_CONSTEXPR14 void to_first() ETL_NOEXCEPT
{
value = First;
}
@ -119,7 +195,7 @@ namespace etl
//*************************************************************************
/// Resets the value to the last in the range.
//*************************************************************************
ETL_CONSTEXPR14 void to_last()
ETL_CONSTEXPR14 void to_last() ETL_NOEXCEPT
{
value = Last;
}
@ -128,38 +204,17 @@ namespace etl
/// Advances to value by a number of steps.
///\param n The number of steps to advance.
//*************************************************************************
ETL_CONSTEXPR14 void advance(int n)
template <typename TStep>
ETL_CONSTEXPR14 void advance(TStep n) ETL_NOEXCEPT
{
if (n > 0)
{
for (int i = 0; i < n; ++i)
{
operator++();
}
}
else
{
for (int i = 0; i < -n; ++i)
{
operator--();
}
}
}
//*************************************************************************
/// Conversion operator.
/// \return The value of the underlying type.
//*************************************************************************
ETL_CONSTEXPR14 operator T()
{
return value;
value = private_cyclic_value::advance(value, First, Last, n);
}
//*************************************************************************
/// Const conversion operator.
/// \return The value of the underlying type.
//*************************************************************************
ETL_CONSTEXPR operator const T() const
ETL_CONSTEXPR operator T() const ETL_NOEXCEPT
{
return value;
}
@ -167,16 +222,9 @@ namespace etl
//*************************************************************************
/// ++ operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value& operator++()
ETL_CONSTEXPR14 cyclic_value& operator++() ETL_NOEXCEPT
{
if (value >= Last) ETL_UNLIKELY
{
value = First;
}
else
{
++value;
}
value = private_cyclic_value::advance(value, First, Last, 1);
return *this;
}
@ -184,7 +232,7 @@ namespace etl
//*************************************************************************
/// ++ operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value operator++(int)
ETL_CONSTEXPR14 cyclic_value operator++(int) ETL_NOEXCEPT
{
cyclic_value temp(*this);
@ -196,16 +244,9 @@ namespace etl
//*************************************************************************
/// -- operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value& operator--()
ETL_CONSTEXPR14 cyclic_value& operator--() ETL_NOEXCEPT
{
if (value <= First) ETL_UNLIKELY
{
value = Last;
}
else
{
--value;
}
value = private_cyclic_value::advance(value, First, Last, int(-1));
return *this;
}
@ -213,7 +254,7 @@ namespace etl
//*************************************************************************
/// -- operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value operator--(int)
ETL_CONSTEXPR14 cyclic_value operator--(int) ETL_NOEXCEPT
{
cyclic_value temp(*this);
@ -225,7 +266,7 @@ namespace etl
//*************************************************************************
/// = operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value& operator=(T t)
ETL_CONSTEXPR14 cyclic_value& operator=(T t) ETL_NOEXCEPT
{
set(t);
return *this;
@ -234,8 +275,8 @@ namespace etl
//*************************************************************************
/// = operator.
//*************************************************************************
template <const T FIRST2, const T LAST2>
ETL_CONSTEXPR14 cyclic_value& operator=(const cyclic_value<T, FIRST2, LAST2>& other)
template <T FIRST2, T LAST2>
ETL_CONSTEXPR14 cyclic_value& operator=(const cyclic_value<T, FIRST2, LAST2>& other) ETL_NOEXCEPT
{
set(other.get());
return *this;
@ -244,7 +285,7 @@ namespace etl
//*************************************************************************
/// Gets the value.
//*************************************************************************
ETL_CONSTEXPR T get() const
ETL_CONSTEXPR T get() const ETL_NOEXCEPT
{
return value;
}
@ -252,7 +293,7 @@ namespace etl
//*************************************************************************
/// Gets the first value.
//*************************************************************************
static ETL_CONSTEXPR T first()
static ETL_CONSTEXPR T first() ETL_NOEXCEPT
{
return First;
}
@ -260,7 +301,7 @@ namespace etl
//*************************************************************************
/// Gets the last value.
//*************************************************************************
static ETL_CONSTEXPR T last()
static ETL_CONSTEXPR T last() ETL_NOEXCEPT
{
return Last;
}
@ -268,7 +309,7 @@ namespace etl
//*************************************************************************
/// Swaps the values.
//*************************************************************************
void swap(cyclic_value<T, First, Last>& other)
ETL_CONSTEXPR14 void swap(cyclic_value<T, First, Last>& other) ETL_NOEXCEPT
{
using ETL_OR_STD::swap; // Allow ADL
@ -278,7 +319,7 @@ namespace etl
//*************************************************************************
/// Swaps the values.
//*************************************************************************
friend void swap(cyclic_value<T, First, Last>& lhs, cyclic_value<T, First, Last>& rhs)
friend ETL_CONSTEXPR14 void swap(cyclic_value<T, First, Last>& lhs, cyclic_value<T, First, Last>& rhs) ETL_NOEXCEPT
{
lhs.swap(rhs);
}
@ -286,7 +327,7 @@ namespace etl
//*************************************************************************
/// Operator ==.
//*************************************************************************
friend ETL_CONSTEXPR bool operator==(const cyclic_value<T, First, Last>& lhs, const cyclic_value<T, First, Last>& rhs)
friend ETL_CONSTEXPR bool operator==(const cyclic_value<T, First, Last>& lhs, const cyclic_value<T, First, Last>& rhs) ETL_NOEXCEPT
{
return lhs.value == rhs.value;
}
@ -294,7 +335,7 @@ namespace etl
//*************************************************************************
/// Operator !=.
//*************************************************************************
friend ETL_CONSTEXPR bool operator!=(const cyclic_value<T, First, Last>& lhs, const cyclic_value<T, First, Last>& rhs)
friend ETL_CONSTEXPR bool operator!=(const cyclic_value<T, First, Last>& lhs, const cyclic_value<T, First, Last>& rhs) ETL_NOEXCEPT
{
return !(lhs == rhs);
}
@ -322,7 +363,7 @@ namespace etl
/// Sets 'first' and 'last' to the template parameter values.
/// The initial value is set to the first value.
//*************************************************************************
ETL_CONSTEXPR cyclic_value()
ETL_CONSTEXPR cyclic_value() ETL_NOEXCEPT
: value(First)
, first_value(First)
, last_value(Last)
@ -335,7 +376,7 @@ namespace etl
///\param first The first value in the range.
///\param last The last value in the range.
//*************************************************************************
ETL_CONSTEXPR cyclic_value(T first_, T last_)
ETL_CONSTEXPR cyclic_value(T first_, T last_) ETL_NOEXCEPT
: value(first_)
, first_value(first_)
, last_value(last_)
@ -349,17 +390,17 @@ namespace etl
///\param first The first value in the range.
///\param last The last value in the range.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value(T first_, T last_, T initial)
: first_value(first_)
ETL_CONSTEXPR cyclic_value(T first_, T last_, T initial) ETL_NOEXCEPT
: value(etl::clamp(initial, first_, last_))
, first_value(first_)
, last_value(last_)
{
set(initial);
}
//*************************************************************************
/// Copy constructor.
//*************************************************************************
ETL_CONSTEXPR cyclic_value(const cyclic_value& other)
ETL_CONSTEXPR cyclic_value(const cyclic_value& other) ETL_NOEXCEPT
: value(other.value)
, first_value(other.first_value)
, last_value(other.last_value)
@ -372,7 +413,7 @@ namespace etl
///\param first The first value in the range.
///\param last The last value in the range.
//*************************************************************************
ETL_CONSTEXPR14 void set(T first_, T last_)
ETL_CONSTEXPR14 void set(T first_, T last_) ETL_NOEXCEPT
{
first_value = first_;
last_value = last_;
@ -383,7 +424,7 @@ namespace etl
/// Sets the value.
///\param value The value.
//*************************************************************************
ETL_CONSTEXPR14 void set(T value_)
ETL_CONSTEXPR14 void set(T value_) ETL_NOEXCEPT
{
value = etl::clamp(value_, first_value, last_value);
}
@ -391,7 +432,7 @@ namespace etl
//*************************************************************************
/// Resets the value to the first in the range.
//*************************************************************************
ETL_CONSTEXPR14 void to_first()
ETL_CONSTEXPR14 void to_first() ETL_NOEXCEPT
{
value = first_value;
}
@ -399,7 +440,7 @@ namespace etl
//*************************************************************************
/// Resets the value to the last in the range.
//*************************************************************************
ETL_CONSTEXPR14 void to_last()
ETL_CONSTEXPR14 void to_last() ETL_NOEXCEPT
{
value = last_value;
}
@ -408,38 +449,16 @@ namespace etl
/// Advances to value by a number of steps.
///\param n The number of steps to advance.
//*************************************************************************
ETL_CONSTEXPR14 void advance(int n)
ETL_CONSTEXPR14 void advance(int n) ETL_NOEXCEPT
{
if (n > 0)
{
for (int i = 0; i < n; ++i)
{
operator++();
}
}
else
{
for (int i = 0; i < -n; ++i)
{
operator--();
}
}
}
//*************************************************************************
/// Conversion operator.
/// \return The value of the underlying type.
//*************************************************************************
ETL_CONSTEXPR14 operator T()
{
return value;
value = private_cyclic_value::advance(value, first_value, last_value, n);
}
//*************************************************************************
/// Const conversion operator.
/// \return The value of the underlying type.
//*************************************************************************
ETL_CONSTEXPR operator const T() const
ETL_CONSTEXPR operator T() const ETL_NOEXCEPT
{
return value;
}
@ -447,16 +466,9 @@ namespace etl
//*************************************************************************
/// ++ operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value& operator++()
ETL_CONSTEXPR14 cyclic_value& operator++() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
{
if (value >= last_value)
{
value = first_value;
}
else
{
++value;
}
value = private_cyclic_value::advance(value, first_value, last_value, 1);
return *this;
}
@ -464,7 +476,7 @@ namespace etl
//*************************************************************************
/// ++ operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value operator++(int)
ETL_CONSTEXPR14 cyclic_value operator++(int) ETL_NOEXCEPT
{
cyclic_value temp(*this);
@ -476,16 +488,9 @@ namespace etl
//*************************************************************************
/// -- operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value& operator--()
ETL_CONSTEXPR14 cyclic_value& operator--() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
{
if (value <= first_value)
{
value = last_value;
}
else
{
--value;
}
value = private_cyclic_value::advance(value, first_value, last_value, int(-1));
return *this;
}
@ -493,7 +498,7 @@ namespace etl
//*************************************************************************
/// -- operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value operator--(int)
ETL_CONSTEXPR14 cyclic_value operator--(int) ETL_NOEXCEPT
{
cyclic_value temp(*this);
@ -505,7 +510,7 @@ namespace etl
//*************************************************************************
/// = operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value& operator=(T t)
ETL_CONSTEXPR14 cyclic_value& operator=(T t) ETL_NOEXCEPT
{
set(t);
return *this;
@ -514,7 +519,7 @@ namespace etl
//*************************************************************************
/// = operator.
//*************************************************************************
ETL_CONSTEXPR14 cyclic_value& operator=(const cyclic_value& other)
ETL_CONSTEXPR14 cyclic_value& operator=(const cyclic_value& other) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
{
value = other.value;
first_value = other.first_value;
@ -522,10 +527,36 @@ namespace etl
return *this;
}
//*************************************************************************
/// Adds a number of steps and clamps to the range.
/// Floating-point steps may be fractional. NaN is rejected.
///\param n The number of steps.
///\return A reference to this value.
//*************************************************************************
template <typename TStep>
ETL_CONSTEXPR14 cyclic_value& operator+=(TStep n) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
{
advance(n);
return *this;
}
//*************************************************************************
/// Subtracts a number of steps and clamps to the range.
/// Floating-point steps may be fractional. NaN is rejected.
///\param n The number of steps.
///\return A reference to this value.
//*************************************************************************
template <typename TStep>
ETL_CONSTEXPR14 cyclic_value& operator-=(TStep n) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
{
value = private_cyclic_value::advance(value, first_value, last_value, -n);
return *this;
}
//*************************************************************************
/// Gets the value.
//*************************************************************************
ETL_CONSTEXPR T get() const
ETL_CONSTEXPR T get() const ETL_NOEXCEPT
{
return value;
}
@ -533,7 +564,7 @@ namespace etl
//*************************************************************************
/// Gets the first value.
//*************************************************************************
ETL_CONSTEXPR T first() const
ETL_CONSTEXPR T first() const ETL_NOEXCEPT
{
return first_value;
}
@ -541,7 +572,7 @@ namespace etl
//*************************************************************************
/// Gets the last value.
//*************************************************************************
ETL_CONSTEXPR T last() const
ETL_CONSTEXPR T last() const ETL_NOEXCEPT
{
return last_value;
}
@ -549,7 +580,7 @@ namespace etl
//*************************************************************************
/// Swaps the values.
//*************************************************************************
void swap(cyclic_value<T, First, Last>& other)
ETL_CONSTEXPR14 void swap(cyclic_value<T, First, Last>& other) ETL_NOEXCEPT
{
using ETL_OR_STD::swap; // Allow ADL
@ -561,27 +592,71 @@ namespace etl
//*************************************************************************
/// Swaps the values.
//*************************************************************************
friend void swap(cyclic_value<T, First, Last>& lhs, cyclic_value<T, First, Last>& rhs)
friend ETL_CONSTEXPR14 void swap(cyclic_value<T, First, Last>& lhs, cyclic_value<T, First, Last>& rhs) ETL_NOEXCEPT
{
lhs.swap(rhs);
}
//*************************************************************************
/// Operator ==.
/// Operator ==
//*************************************************************************
friend ETL_CONSTEXPR bool operator==(const cyclic_value<T, First, Last>& lhs, const cyclic_value<T, First, Last>& rhs)
friend ETL_CONSTEXPR bool operator==(const cyclic_value<T, First, Last>& lhs, const cyclic_value<T, First, Last>& rhs) ETL_NOEXCEPT
{
return (lhs.value == rhs.value) && (lhs.first_value == rhs.first_value) && (lhs.last_value == rhs.last_value);
return (lhs.value == rhs.value);
}
//*************************************************************************
/// Operator !=.
/// Operator !=
//*************************************************************************
friend ETL_CONSTEXPR bool operator!=(const cyclic_value<T, First, Last>& lhs, const cyclic_value<T, First, Last>& rhs)
friend ETL_CONSTEXPR bool operator!=(const cyclic_value<T, First, Last>& lhs, const cyclic_value<T, First, Last>& rhs) ETL_NOEXCEPT
{
return !(lhs == rhs);
}
//*************************************************************************
/// Operator <
///\param lhs The left-hand operand.
///\param rhs The right-hand operand.
///\return `true` if lhs is less than rhs.
//*************************************************************************
friend ETL_CONSTEXPR bool operator<(const cyclic_value& lhs, const cyclic_value& rhs) ETL_NOEXCEPT
{
return lhs.value < rhs.value;
}
//*************************************************************************
/// Operator <=
///\param lhs The left-hand operand.
///\param rhs The right-hand operand.
///\return `true` if lhs is less than or equal to rhs.
//*************************************************************************
friend ETL_CONSTEXPR bool operator<=(const cyclic_value& lhs, const cyclic_value& rhs) ETL_NOEXCEPT
{
return !(rhs < lhs);
}
//*************************************************************************
/// Operator >
///\param lhs The left-hand operand.
///\param rhs The right-hand operand.
///\return `true` if lhs is greater than rhs.
//*************************************************************************
friend ETL_CONSTEXPR bool operator>(const cyclic_value& lhs, const cyclic_value& rhs) ETL_NOEXCEPT
{
return rhs < lhs;
}
//*************************************************************************
/// Operator >=
///\param lhs The left-hand operand.
///\param rhs The right-hand operand.
///\return `true` if lhs is greater than or equal to rhs.
//*************************************************************************
friend ETL_CONSTEXPR bool operator>=(const cyclic_value& lhs, const cyclic_value& rhs) ETL_NOEXCEPT
{
return !(lhs < rhs);
}
private:
T value; ///< The current value.