mirror of
https://github.com/ETLCPP/etl.git
synced 2026-10-28 18:07:10 +08:00
Implement clamped_value utility (#1565)
* feat: add clamped_value utility * style: format clamped_value include list * feat: enhance clamped_value with runtime bounds and comparison operators and DRY up the implementation * refactor: call set in runtime ctor instead of duplicated the clamping logic * Add C++20 floating-point clamped_value support * Document and stress clamped_value edge cases * Change ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS) to ETL_NOEXCEPT * Change ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS) to ETL_NOEXCEPT * Revert changes --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
ee87ea90aa
commit
11623e6862
170
docs/utilities/clamped-value.md
Normal file
170
docs/utilities/clamped-value.md
Normal file
@ -0,0 +1,170 @@
|
||||
---
|
||||
title: "clamped_value"
|
||||
---
|
||||
|
||||
{{< callout type="info">}}
|
||||
Header: `clamped_value.h`
|
||||
Since: `TBC`
|
||||
{{< /callout >}}
|
||||
|
||||
Provides a value constrained between a minimum and maximum value. Values are
|
||||
clamped using `etl::clamp`. The type supports compile-time bounds to minimise
|
||||
storage and runtime bounds when the range must be changed. Integral types are
|
||||
supported in all language modes. Floating-point types are supported in C++20
|
||||
when `ETL_HAS_FLOATING_POINT_CLAMPED_VALUE` is `1`. By default, the macro is
|
||||
enabled when `__cpp_nontype_template_args` is at least `201911L`.
|
||||
|
||||
## Availability
|
||||
|
||||
`ETL_HAS_FLOATING_POINT_CLAMPED_VALUE` is always defined by this header as
|
||||
either `0` or `1`. It defaults to `1` only when C++20 is enabled and the
|
||||
compiler supports floating-point non-type template arguments. A platform
|
||||
profile or build may define the macro before including the header to override
|
||||
automatic detection.
|
||||
|
||||
When the macro is `0`, `T` must be an integral type. When it is `1`, `float`,
|
||||
`double`, and `long double` may also be used.
|
||||
|
||||
```cpp
|
||||
template <typename T,
|
||||
T Min = T(),
|
||||
T Max = T(),
|
||||
bool RuntimeSpecialisation = ((Min == T()) && (Max == T()))>
|
||||
class clamped_value;
|
||||
```
|
||||
|
||||
```cpp
|
||||
etl::clamped_value<int, 2, 7> value_ct; // Fixed range [2, 7].
|
||||
|
||||
etl::clamped_value<int> value_rt(2, 7, 5); // Runtime range and initial value.
|
||||
|
||||
#if ETL_HAS_FLOATING_POINT_CLAMPED_VALUE
|
||||
etl::clamped_value<float, -1.5f, 2.5f> float_ct(0.5f);
|
||||
etl::clamped_value<double> float_rt(-1.5, 2.5, 0.5);
|
||||
#endif
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
`difference_type` is the signed counterpart of `T` for integral values. For
|
||||
floating-point values, `difference_type` is `T`, allowing fractional steps.
|
||||
`limits_type` and `difference_limits_type` provide the corresponding
|
||||
`etl::numeric_limits` specializations.
|
||||
|
||||
## Constructors
|
||||
|
||||
```cpp
|
||||
clamped_value<int, 2, 7> value;
|
||||
```
|
||||
|
||||
Creates a compile-time clamped value initialized to `Min`.
|
||||
|
||||
```cpp
|
||||
clamped_value<int> value(min, max);
|
||||
clamped_value<int> value(min, max, initial);
|
||||
```
|
||||
|
||||
Creates a runtime clamped value. The two-argument form initializes the value
|
||||
to `min`; the three-argument form clamps `initial` to the range.
|
||||
|
||||
`min` must not be greater than `max`. As with `cyclic_value`, zero-initialized
|
||||
`Min` and `Max` select the runtime-bound specialization; use a non-zero
|
||||
compile-time bound when a fixed compile-time range is needed. NaN bounds and
|
||||
initial values are rejected. Infinite bounds and values are permitted.
|
||||
|
||||
Because zero-initialized `Min` and `Max` select runtime bounds, a fixed
|
||||
compile-time range `[0, 0]` cannot be represented by this dispatch scheme.
|
||||
|
||||
## Modifiers
|
||||
|
||||
```cpp
|
||||
void set(T value);
|
||||
void set(T min, T max);
|
||||
void to_min();
|
||||
void to_max();
|
||||
void advance(difference_type n) ETL_NOEXCEPT;
|
||||
```
|
||||
|
||||
`set(T)` clamps the current value. The runtime `set(min, max)` changes the
|
||||
range and resets the value to the new minimum. `to_min()` and `to_max()` move
|
||||
the value directly to a bound. For integral values, `advance` uses the signed
|
||||
counterpart of `T` as its step type. For floating-point values, the step type
|
||||
is `T` and may be fractional. Steps saturate in constant time at the minimum
|
||||
or maximum rather than wrapping. NaN steps are rejected.
|
||||
|
||||
Positive steps move toward `max`; negative steps move toward `min`. Infinite
|
||||
steps saturate at a finite bound. Infinite values and bounds remain valid.
|
||||
|
||||
```cpp
|
||||
etl::clamped_value<float, -1.0f, 1.0f> value(0.25f);
|
||||
value.advance(0.5f); // 0.75f
|
||||
value.advance(10.0f); // 1.0f
|
||||
value.advance(-0.5f); // 0.5f
|
||||
```
|
||||
|
||||
Increment and decrement move by one and also saturate, including when a
|
||||
floating-point bound is less than one unit away:
|
||||
|
||||
```cpp
|
||||
++value; // Remains Max when already at Max.
|
||||
--value; // Remains Min when already at Min.
|
||||
```
|
||||
|
||||
## Access
|
||||
|
||||
```cpp
|
||||
ETL_NODISCARD T get() const noexcept;
|
||||
ETL_NODISCARD T min() const noexcept;
|
||||
ETL_NODISCARD T max() const noexcept;
|
||||
```
|
||||
|
||||
Gets the current value and its bounds. Both compile-time and runtime
|
||||
specializations provide these accessors as const-qualified member functions.
|
||||
|
||||
## Operators
|
||||
|
||||
```cpp
|
||||
ETL_NODISCARD operator T() const noexcept;
|
||||
clamped_value& operator++() & noexcept;
|
||||
clamped_value operator++(int) noexcept;
|
||||
clamped_value& operator--() & noexcept;
|
||||
clamped_value operator--(int) noexcept;
|
||||
clamped_value& operator=(T value) & noexcept;
|
||||
clamped_value& operator+=(difference_type n) & noexcept;
|
||||
clamped_value& operator-=(difference_type n) & noexcept;
|
||||
```
|
||||
|
||||
Conversion and assignment to the underlying type are supported. Assignment is
|
||||
clamped to the configured range. The lvalue reference qualification on
|
||||
assignment prevents assignment through temporary values where supported. For
|
||||
floating-point values, assignment and compound-assignment reject NaN.
|
||||
|
||||
Prefix increment and decrement return a reference to the updated object.
|
||||
Postfix increment and decrement return a copy of the value before it was
|
||||
updated. All four operations move by one and saturate at the applicable bound.
|
||||
|
||||
## Operations
|
||||
|
||||
```cpp
|
||||
ETL_CONSTEXPR14 void swap(clamped_value& other);
|
||||
ETL_CONSTEXPR14 void swap(clamped_value& lhs, clamped_value& rhs);
|
||||
```
|
||||
|
||||
Swaps clamped values. Runtime values also swap their bounds.
|
||||
|
||||
Equality, inequality, and relational comparisons are provided. Comparisons
|
||||
against arithmetic values use the implicit conversion to `T`. Equality
|
||||
compares the current values; runtime bounds do not affect equality. Runtime
|
||||
ranges must satisfy `min <= max`; invalid ranges trigger an ETL assertion. The
|
||||
default runtime specialization uses the full representable range of `T`.
|
||||
|
||||
Floating-point comparisons use the underlying values directly; no approximate
|
||||
or tolerance-based comparison is applied.
|
||||
|
||||
## Error Handling
|
||||
|
||||
Runtime ranges with `min > max` trigger an ETL assertion. NaN values, bounds,
|
||||
assignments, and steps also trigger an ETL assertion. Depending on the ETL
|
||||
error-handler configuration, an assertion may throw `etl::exception`, invoke a
|
||||
configured handler, or terminate. Operations that validate input are only
|
||||
`noexcept` when exceptions are disabled.
|
||||
956
include/etl/clamped_value.h
Normal file
956
include/etl/clamped_value.h
Normal file
@ -0,0 +1,956 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2026 John Wellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ETL_CLAMPED_VALUE_INCLUDED
|
||||
#define ETL_CLAMPED_VALUE_INCLUDED
|
||||
|
||||
#include "platform.h"
|
||||
#include "absolute.h"
|
||||
#include "algorithm.h"
|
||||
#include "error_handler.h"
|
||||
#include "limits.h"
|
||||
#include "math.h"
|
||||
#include "static_assert.h"
|
||||
#include "type_traits.h"
|
||||
#include "utility.h"
|
||||
|
||||
///\def ETL_HAS_FLOATING_POINT_CLAMPED_VALUE
|
||||
/// Set to `1` when clamped_value supports floating-point types.
|
||||
/// Floating-point support requires C++20 non-type template arguments.
|
||||
/// The macro may be defined by the build or platform profile to override
|
||||
/// automatic detection.
|
||||
#if !defined(ETL_HAS_FLOATING_POINT_CLAMPED_VALUE)
|
||||
#if ETL_USING_CPP20 && defined(__cpp_nontype_template_args) && (__cpp_nontype_template_args >= 201911L)
|
||||
#define ETL_HAS_FLOATING_POINT_CLAMPED_VALUE 1
|
||||
#else
|
||||
#define ETL_HAS_FLOATING_POINT_CLAMPED_VALUE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///\defgroup clamped_value clamped_value
|
||||
/// Provides a value that is clamped between two limits.
|
||||
/// Integral types are supported in all language modes. Floating-point types
|
||||
/// are supported when ETL_HAS_FLOATING_POINT_CLAMPED_VALUE is `1`.
|
||||
/// \ingroup utilities
|
||||
|
||||
namespace etl
|
||||
{
|
||||
/// \cond INTERNAL
|
||||
namespace private_clamped_value
|
||||
{
|
||||
//*************************************************************************
|
||||
/// Type policy for clamped_value.
|
||||
/// Integral values use a signed difference type and unsigned saturation
|
||||
/// arithmetic. Floating-point values use `T` as the difference type.
|
||||
//*************************************************************************
|
||||
template <typename T, bool IsIntegral = etl::is_integral<T>::value>
|
||||
struct traits;
|
||||
|
||||
template <typename T>
|
||||
struct traits<T, true>
|
||||
{
|
||||
typedef typename etl::make_signed<T>::type difference_type;
|
||||
typedef typename etl::make_unsigned<T>::type unsigned_type;
|
||||
typedef etl::numeric_limits<T> limits_type;
|
||||
typedef etl::numeric_limits<difference_type> difference_limits_type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct traits<T, false>
|
||||
{
|
||||
ETL_STATIC_ASSERT(ETL_HAS_FLOATING_POINT_CLAMPED_VALUE&& etl::is_floating_point<T>::value,
|
||||
"clamped_value requires an integral type, or a floating-point type when supported");
|
||||
|
||||
typedef T difference_type;
|
||||
typedef etl::numeric_limits<T> limits_type;
|
||||
typedef etl::numeric_limits<T> difference_limits_type;
|
||||
};
|
||||
|
||||
template <typename T, bool IsIntegral = etl::is_integral<T>::value>
|
||||
struct arithmetic;
|
||||
|
||||
//*************************************************************************
|
||||
/// Saturating arithmetic policy for integral values.
|
||||
//*************************************************************************
|
||||
template <typename T>
|
||||
struct arithmetic<T, true>
|
||||
{
|
||||
typedef typename traits<T>::unsigned_type unsigned_type;
|
||||
|
||||
ETL_NODISCARD
|
||||
static ETL_CONSTEXPR14 T advance(T value, T min_value, T max_value, typename traits<T>::difference_type n) ETL_NOEXCEPT
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
const unsigned_type current = static_cast<unsigned_type>(value);
|
||||
const unsigned_type step = etl::absolute_unsigned(n);
|
||||
|
||||
if ((n > 0) && (value < max_value))
|
||||
{
|
||||
const unsigned_type distance = static_cast<unsigned_type>(max_value) - current;
|
||||
|
||||
value = (step >= distance) ? max_value : static_cast<T>(current + step);
|
||||
}
|
||||
else if ((n < 0) && (value > min_value))
|
||||
{
|
||||
const unsigned_type distance = current - static_cast<unsigned_type>(min_value);
|
||||
|
||||
value = (step >= distance) ? min_value : static_cast<T>(current - step);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ETL_NODISCARD
|
||||
static ETL_CONSTEXPR14 T subtract(T value, T min_value, T max_value, typename traits<T>::difference_type n) ETL_NOEXCEPT
|
||||
{
|
||||
if (n == traits<T>::difference_limits_type::lowest()) ETL_UNLIKELY
|
||||
{
|
||||
value = advance(value, min_value, max_value, traits<T>::difference_limits_type::max());
|
||||
return advance(value, min_value, max_value, 1);
|
||||
}
|
||||
|
||||
return advance(value, min_value, max_value, static_cast<typename traits<T>::difference_type>(-n));
|
||||
}
|
||||
};
|
||||
|
||||
#if ETL_HAS_FLOATING_POINT_CLAMPED_VALUE
|
||||
//*************************************************************************
|
||||
/// Saturating arithmetic policy for floating-point values.
|
||||
//*************************************************************************
|
||||
template <typename T>
|
||||
struct arithmetic<T, false>
|
||||
{
|
||||
ETL_NODISCARD
|
||||
static ETL_CONSTEXPR14 T advance(T value, T min_value, T max_value, T n) ETL_NOEXCEPT
|
||||
{
|
||||
if ((n > T(0)) && (value < max_value))
|
||||
{
|
||||
const T distance = max_value - value;
|
||||
value = (n >= distance) ? max_value : static_cast<T>(value + n);
|
||||
}
|
||||
else if ((n < T(0)) && (value > min_value))
|
||||
{
|
||||
const T distance = value - min_value;
|
||||
value = (-n >= distance) ? min_value : static_cast<T>(value + n);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ETL_NODISCARD
|
||||
static ETL_CONSTEXPR14 T subtract(T value, T min_value, T max_value, T n) ETL_NOEXCEPT
|
||||
{
|
||||
return advance(value, min_value, max_value, -n);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Advances a value and saturates it at the supplied bounds.
|
||||
///\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>
|
||||
ETL_NODISCARD ETL_CONSTEXPR14 T advance(T value, T min_value, T max_value, typename traits<T>::difference_type n) ETL_NOEXCEPT
|
||||
{
|
||||
return arithmetic<T>::advance(value, min_value, max_value, n);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Subtracts a value and saturates it at the supplied bounds.
|
||||
/// Handles the lowest integral difference without signed overflow.
|
||||
///\param value The current value.
|
||||
///\param min_value The minimum value.
|
||||
///\param max_value The maximum value.
|
||||
///\param n The number of steps to subtract.
|
||||
///\return The value after subtraction.
|
||||
//*************************************************************************
|
||||
template <typename T>
|
||||
ETL_NODISCARD ETL_CONSTEXPR14 T subtract(T value, T min_value, T max_value, typename traits<T>::difference_type n) ETL_NOEXCEPT
|
||||
{
|
||||
return arithmetic<T>::subtract(value, min_value, max_value, n);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Verifies that a clamped value, bound, or difference is not NaN.
|
||||
/// Integral values always pass validation.
|
||||
///\param value The value to validate.
|
||||
//*************************************************************************
|
||||
template <typename T>
|
||||
ETL_CONSTEXPR14 void validate(T value) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
ETL_ASSERT(!etl::is_nan(value), ETL_ERROR_GENERIC("clamped_value: NaN is not supported"));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Validates a value and its bounds before clamping.
|
||||
///\param value The value to clamp.
|
||||
///\param min_value The minimum permitted value.
|
||||
///\param max_value The maximum permitted value.
|
||||
///\return The value clamped to the supplied range.
|
||||
//*************************************************************************
|
||||
template <typename T>
|
||||
ETL_NODISCARD ETL_CONSTEXPR14 T validated_clamp(T value, T min_value, T max_value) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
validate(value);
|
||||
validate(min_value);
|
||||
validate(max_value);
|
||||
ETL_ASSERT(min_value <= max_value, ETL_ERROR_GENERIC("clamped_value: invalid range"));
|
||||
return etl::clamp(value, min_value, max_value);
|
||||
}
|
||||
} // namespace private_clamped_value
|
||||
/// \endcond
|
||||
|
||||
#include "private/diagnostic_float_equal_push.h"
|
||||
template <typename T, T Min = T(), T Max = T(), bool RuntimeSpecialisation = ((Min == T()) && (Max == T()))>
|
||||
class clamped_value;
|
||||
#include "private/diagnostic_pop.h"
|
||||
|
||||
//***************************************************************************
|
||||
/// Provides a value that is clamped between two compile-time limits.
|
||||
/// Supports incrementing, decrementing and arbitrary advance.
|
||||
///@tparam T An integral type, or a floating-point type when
|
||||
/// ETL_HAS_FLOATING_POINT_CLAMPED_VALUE is `1`.
|
||||
///@tparam Min The minimum value of the range.
|
||||
///@tparam Max The maximum value of the range.
|
||||
///\ingroup clamped_value
|
||||
//***************************************************************************
|
||||
template <typename T, T Min, T Max>
|
||||
class clamped_value<T, Min, Max, false>
|
||||
{
|
||||
public:
|
||||
|
||||
/// The type used to advance or subtract from the stored value.
|
||||
typedef typename private_clamped_value::traits<T>::difference_type difference_type;
|
||||
|
||||
/// Numeric limits for the stored value type.
|
||||
typedef typename private_clamped_value::traits<T>::limits_type limits_type;
|
||||
|
||||
/// Numeric limits for difference_type.
|
||||
typedef typename private_clamped_value::traits<T>::difference_limits_type difference_limits_type;
|
||||
|
||||
/// \cond INTERNAL
|
||||
ETL_STATIC_ASSERT(Min <= Max, "clamped_value minimum must not exceed maximum");
|
||||
/// \endcond
|
||||
|
||||
//*************************************************************************
|
||||
/// Default constructor.
|
||||
/// The initial value is set to the minimum value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR clamped_value() ETL_NOEXCEPT
|
||||
: value(Min)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor.
|
||||
/// Set to an initial value.
|
||||
/// Clamped to the range.
|
||||
/// NaN is rejected for floating-point values.
|
||||
///\param initial The initial value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 explicit clamped_value(T initial) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
: value(private_clamped_value::validated_clamp(initial, Min, Max))
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Copy constructor.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR clamped_value(const clamped_value& other) ETL_NOEXCEPT
|
||||
: value(other.value)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Assignment operator.
|
||||
///\param other The value to copy.
|
||||
///\return A reference to this value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator=(const clamped_value& other) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
|
||||
{
|
||||
if (this == &other)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
set(other.value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Sets the value.
|
||||
/// Clamps to the Min/Max range.
|
||||
/// NaN is rejected for floating-point values.
|
||||
///\param value_ The value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void set(T value_) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
value = private_clamped_value::validated_clamp(value_, Min, Max);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Resets the value to the minimum in the range.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void to_min() ETL_NOEXCEPT
|
||||
{
|
||||
value = Min;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Resets the value to the maximum in the range.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void to_max() ETL_NOEXCEPT
|
||||
{
|
||||
value = Max;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Advances the value by a number of steps.
|
||||
/// Saturates at the Min/Max range.
|
||||
/// Floating-point steps may be fractional. NaN is rejected.
|
||||
///\param n The number of steps.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void advance(difference_type n) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
private_clamped_value::validate(n);
|
||||
value = private_clamped_value::advance(value, Min, Max, n);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Conversion operator.
|
||||
/// \return The value of the underlying type.
|
||||
//*************************************************************************
|
||||
ETL_NODISCARD ETL_CONSTEXPR14 operator T() const ETL_NOEXCEPT
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// ++ operator.
|
||||
/// Advances by one.
|
||||
/// Saturates at Max.
|
||||
///\return A reference to this value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator++() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
|
||||
{
|
||||
value = private_clamped_value::advance(value, Min, Max, difference_type(1));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// ++ operator.
|
||||
/// Saturates at Max.
|
||||
///\return The value before incrementing.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value operator++(int) ETL_NOEXCEPT
|
||||
{
|
||||
clamped_value temp(*this);
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// -- operator.
|
||||
/// Subtracts one.
|
||||
/// Saturates at Min.
|
||||
///\return A reference to this value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator--() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
|
||||
{
|
||||
value = private_clamped_value::advance(value, Min, Max, difference_type(-1));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// -- operator.
|
||||
/// Saturates at Min.
|
||||
///\return The value before decrementing.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value operator--(int) ETL_NOEXCEPT
|
||||
{
|
||||
clamped_value temp(*this);
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// = operator.
|
||||
/// Clamps to the Min/Max range.
|
||||
///\param value_ The value to assign.
|
||||
///\return A reference to this value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator=(T value_) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
set(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.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator+=(difference_type n) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
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.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator-=(difference_type n) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
private_clamped_value::validate(n);
|
||||
value = private_clamped_value::subtract(value, Min, Max, n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets the value.
|
||||
///\return The current value.
|
||||
//*************************************************************************
|
||||
ETL_NODISCARD ETL_CONSTEXPR T get() const ETL_NOEXCEPT
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets the minimum value.
|
||||
///\return The minimum value.
|
||||
//*************************************************************************
|
||||
ETL_NODISCARD ETL_CONSTEXPR T min() const ETL_NOEXCEPT
|
||||
{
|
||||
return Min;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets the maximum value.
|
||||
///\return The maximum value.
|
||||
//*************************************************************************
|
||||
ETL_NODISCARD ETL_CONSTEXPR T max() const ETL_NOEXCEPT
|
||||
{
|
||||
return Max;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Swaps the values.
|
||||
///\param other The value to swap with.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void swap(clamped_value& other) ETL_NOEXCEPT
|
||||
{
|
||||
using ETL_OR_STD::swap;
|
||||
swap(value, other.value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Swaps the values.
|
||||
///\param lhs The first value.
|
||||
///\param rhs The second value.
|
||||
//*************************************************************************
|
||||
friend ETL_CONSTEXPR14 void swap(clamped_value& lhs, clamped_value& rhs) ETL_NOEXCEPT
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Operator ==.
|
||||
///\param lhs The left-hand value.
|
||||
///\param rhs The right-hand value.
|
||||
///\return `true` if the values are equal.
|
||||
//*************************************************************************
|
||||
friend ETL_CONSTEXPR bool operator==(const clamped_value& lhs, const clamped_value& rhs) ETL_NOEXCEPT
|
||||
{
|
||||
#include "private/diagnostic_float_equal_push.h"
|
||||
return lhs.value == rhs.value;
|
||||
#include "private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Operator !=.
|
||||
///\param lhs The left-hand value.
|
||||
///\param rhs The right-hand value.
|
||||
///\return `true` if the values are not equal.
|
||||
//*************************************************************************
|
||||
friend ETL_CONSTEXPR bool operator!=(const clamped_value& lhs, const clamped_value& 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 clamped_value& lhs, const clamped_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 clamped_value& lhs, const clamped_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 clamped_value& lhs, const clamped_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 clamped_value& lhs, const clamped_value& rhs) ETL_NOEXCEPT
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
||||
T value;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Provides a value that is clamped between two runtime limits.
|
||||
/// Supports incrementing, decrementing and arbitrary advance.
|
||||
///@tparam T An integral type, or a floating-point type when
|
||||
/// ETL_HAS_FLOATING_POINT_CLAMPED_VALUE is `1`.
|
||||
///@tparam Min Ignored for this specialisation.
|
||||
///@tparam Max Ignored for this specialisation.
|
||||
///\ingroup clamped_value
|
||||
//***************************************************************************
|
||||
template <typename T, T Min, T Max>
|
||||
class clamped_value<T, Min, Max, true>
|
||||
{
|
||||
public:
|
||||
|
||||
/// The type used to advance or subtract from the stored value.
|
||||
typedef typename private_clamped_value::traits<T>::difference_type difference_type;
|
||||
|
||||
/// Numeric limits for the stored value type.
|
||||
typedef typename private_clamped_value::traits<T>::limits_type limits_type;
|
||||
|
||||
/// Numeric limits for difference_type.
|
||||
typedef typename private_clamped_value::traits<T>::difference_limits_type difference_limits_type;
|
||||
|
||||
//*************************************************************************
|
||||
/// Default constructor.
|
||||
/// Sets the value to the minimum representable value of `T` and the
|
||||
/// bounds to the full range of `T`.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR clamped_value() ETL_NOEXCEPT
|
||||
: value(limits_type::lowest())
|
||||
, min_value(limits_type::lowest())
|
||||
, max_value(limits_type::max())
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor.
|
||||
/// Sets the value to the minimum of the range.
|
||||
/// Reversed bounds and NaN bounds are rejected.
|
||||
///\param min_ The minimum value.
|
||||
///\param max_ The maximum value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value(T min_, T max_) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
: value(min_)
|
||||
, min_value(min_)
|
||||
, max_value(max_)
|
||||
{
|
||||
private_clamped_value::validate(min_);
|
||||
private_clamped_value::validate(max_);
|
||||
ETL_ASSERT(min_ <= max_, ETL_ERROR_GENERIC("clamped_value: invalid range"));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor.
|
||||
/// Set to an initial value.
|
||||
/// Clamped to the range.
|
||||
/// Reversed bounds and NaN values or bounds are rejected.
|
||||
///\param min_ The minimum value.
|
||||
///\param max_ The maximum value.
|
||||
///\param initial The initial value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value(T min_, T max_, T initial) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
: value(private_clamped_value::validated_clamp(initial, min_, max_))
|
||||
, min_value(min_)
|
||||
, max_value(max_)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Copy constructor.
|
||||
///\param other The value to copy.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR clamped_value(const clamped_value& other) ETL_NOEXCEPT
|
||||
: value(other.value)
|
||||
, min_value(other.min_value)
|
||||
, max_value(other.max_value)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Sets the range.
|
||||
/// Sets the value to the minimum of the range.
|
||||
/// Reversed bounds and NaN bounds are rejected.
|
||||
///\param min_ The minimum value.
|
||||
///\param max_ The maximum value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void set(T min_, T max_) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
private_clamped_value::validate(min_);
|
||||
private_clamped_value::validate(max_);
|
||||
ETL_ASSERT(min_ <= max_, ETL_ERROR_GENERIC("clamped_value: invalid range"));
|
||||
min_value = min_;
|
||||
max_value = max_;
|
||||
value = min_;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Sets the value.
|
||||
/// Clamps to the runtime Min/Max range.
|
||||
/// NaN is rejected for floating-point values.
|
||||
///\param value_ The value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void set(T value_) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
value = private_clamped_value::validated_clamp(value_, min_value, max_value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Resets the value to the minimum in the range.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void to_min() ETL_NOEXCEPT
|
||||
{
|
||||
value = min_value;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Resets the value to the maximum in the range.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void to_max() ETL_NOEXCEPT
|
||||
{
|
||||
value = max_value;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Advances the value by a number of steps.
|
||||
/// Saturates at the runtime Min/Max range.
|
||||
/// Floating-point steps may be fractional. NaN is rejected.
|
||||
///\param n The number of steps.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void advance(difference_type n) ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
private_clamped_value::validate(n);
|
||||
value = private_clamped_value::advance(value, min_value, max_value, n);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Conversion operator.
|
||||
/// \return The value of the underlying type.
|
||||
//*************************************************************************
|
||||
ETL_NODISCARD ETL_CONSTEXPR14 operator T() const ETL_NOEXCEPT
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// ++ operator.
|
||||
/// Advances by one.
|
||||
/// Saturates at the maximum.
|
||||
///\return A reference to this value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator++() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
|
||||
{
|
||||
value = private_clamped_value::advance(value, min_value, max_value, difference_type(1));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// ++ operator.
|
||||
/// Saturates at the maximum.
|
||||
///\return The value before incrementing.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value operator++(int) ETL_NOEXCEPT
|
||||
{
|
||||
clamped_value temp(*this);
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// -- operator.
|
||||
/// Subtracts one.
|
||||
/// Saturates at the minimum.
|
||||
///\return A reference to this value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator--() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
|
||||
{
|
||||
value = private_clamped_value::advance(value, min_value, max_value, difference_type(-1));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// -- operator.
|
||||
/// Saturates at the minimum.
|
||||
///\return The value before decrementing.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value operator--(int) ETL_NOEXCEPT
|
||||
{
|
||||
clamped_value temp(*this);
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// = operator.
|
||||
/// Clamps to the runtime Min/Max range.
|
||||
///\param value_ The value to assign.
|
||||
///\return A reference to this value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator=(T value_) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
set(value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// = operator.
|
||||
/// Copies the value and runtime bounds.
|
||||
///\param other The value to copy.
|
||||
///\return A reference to this value.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator=(const clamped_value& other) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
|
||||
{
|
||||
if (this == &other)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
value = other.value;
|
||||
min_value = other.min_value;
|
||||
max_value = other.max_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.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator+=(difference_type n) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
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.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 clamped_value& operator-=(difference_type n) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT_IF(ETL_NOT_USING_EXCEPTIONS)
|
||||
{
|
||||
private_clamped_value::validate(n);
|
||||
value = private_clamped_value::subtract(value, min_value, max_value, n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets the value.
|
||||
///\return The current value.
|
||||
//*************************************************************************
|
||||
ETL_NODISCARD ETL_CONSTEXPR T get() const ETL_NOEXCEPT
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets the minimum value.
|
||||
///\return The minimum value.
|
||||
//*************************************************************************
|
||||
ETL_NODISCARD ETL_CONSTEXPR T min() const ETL_NOEXCEPT
|
||||
{
|
||||
return min_value;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets the maximum value.
|
||||
///\return The maximum value.
|
||||
//*************************************************************************
|
||||
ETL_NODISCARD ETL_CONSTEXPR T max() const ETL_NOEXCEPT
|
||||
{
|
||||
return max_value;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Swaps the values and runtime bounds.
|
||||
///\param other The value to swap with.
|
||||
//*************************************************************************
|
||||
ETL_CONSTEXPR14 void swap(clamped_value& other) ETL_NOEXCEPT
|
||||
{
|
||||
using ETL_OR_STD::swap;
|
||||
swap(value, other.value);
|
||||
swap(min_value, other.min_value);
|
||||
swap(max_value, other.max_value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Swaps the values and runtime bounds.
|
||||
///\param lhs The first value.
|
||||
///\param rhs The second value.
|
||||
//*************************************************************************
|
||||
friend ETL_CONSTEXPR14 void swap(clamped_value& lhs, clamped_value& rhs) ETL_NOEXCEPT
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Operator ==.
|
||||
///\param lhs The left-hand value.
|
||||
///\param rhs The right-hand value.
|
||||
///\return `true` if the values are equal.
|
||||
//*************************************************************************
|
||||
friend ETL_CONSTEXPR bool operator==(const clamped_value& lhs, const clamped_value& rhs) ETL_NOEXCEPT
|
||||
{
|
||||
#include "private/diagnostic_float_equal_push.h"
|
||||
return lhs.value == rhs.value;
|
||||
#include "private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Operator !=.
|
||||
///\param lhs The left-hand value.
|
||||
///\param rhs The right-hand value.
|
||||
///\return `true` if the values differ.
|
||||
//*************************************************************************
|
||||
friend ETL_CONSTEXPR bool operator!=(const clamped_value& lhs, const clamped_value& 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 clamped_value& lhs, const clamped_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 clamped_value& lhs, const clamped_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 clamped_value& lhs, const clamped_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 clamped_value& lhs, const clamped_value& rhs) ETL_NOEXCEPT
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
||||
T value;
|
||||
T min_value;
|
||||
T max_value;
|
||||
};
|
||||
} // namespace etl
|
||||
|
||||
#endif
|
||||
@ -163,6 +163,7 @@ add_executable(etl_tests
|
||||
test_crc8_opensafety.cpp
|
||||
test_crc8_rohc.cpp
|
||||
test_crc8_wcdma.cpp
|
||||
test_clamped_value.cpp
|
||||
test_cyclic_value.cpp
|
||||
test_debounce.cpp
|
||||
test_delegate.cpp
|
||||
|
||||
@ -46,6 +46,7 @@ SOFTWARE.
|
||||
#include "etl/callback_timer.h"
|
||||
#include "etl/char_traits.h"
|
||||
#include "etl/checksum.h"
|
||||
#include "etl/clamped_value.h"
|
||||
#include "etl/combinations.h"
|
||||
#include "etl/compare.h"
|
||||
#include "etl/constant.h"
|
||||
|
||||
@ -151,6 +151,7 @@ etl_test_sources = files(
|
||||
'test_crc8_opensafety.cpp',
|
||||
'test_crc8_rohc.cpp',
|
||||
'test_crc8_wcdma.cpp',
|
||||
'test_clamped_value.cpp',
|
||||
'test_cyclic_value.cpp',
|
||||
'test_debounce.cpp',
|
||||
'test_delegate.cpp',
|
||||
|
||||
@ -202,6 +202,7 @@ target_sources(tests PRIVATE
|
||||
crc8_nrsc5.h.t.cpp
|
||||
crc8_rohc.h.t.cpp
|
||||
crc8_wcdma.h.t.cpp
|
||||
clamped_value.h.t.cpp
|
||||
cyclic_value.h.t.cpp
|
||||
debounce.h.t.cpp
|
||||
debug_count.h.t.cpp
|
||||
|
||||
36
test/syntax_check/clamped_value.h.t.cpp
Normal file
36
test/syntax_check/clamped_value.h.t.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2026 John Wellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <etl/clamped_value.h>
|
||||
|
||||
#if ETL_HAS_FLOATING_POINT_CLAMPED_VALUE
|
||||
etl::clamped_value<float, -1.0f, 1.0f> clamped_float_compile_time;
|
||||
etl::clamped_value<double> clamped_double_run_time;
|
||||
#endif
|
||||
515
test/test_clamped_value.cpp
Normal file
515
test/test_clamped_value.cpp
Normal file
@ -0,0 +1,515 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2026 John Wellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "unit_test_framework.h"
|
||||
|
||||
#include "etl/clamped_value.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_clamped_value)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_compile_time_initialisation)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> value;
|
||||
const etl::clamped_value<int, 2, 7> const_value(value);
|
||||
int converted_value = value;
|
||||
int converted_const_value = const_value;
|
||||
CHECK_EQUAL(2, value.get());
|
||||
CHECK_EQUAL(2, value.min());
|
||||
CHECK_EQUAL(7, value.max());
|
||||
CHECK_EQUAL(2, converted_value);
|
||||
CHECK_EQUAL(2, converted_const_value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_compile_time_bounds_accessors_are_const)
|
||||
{
|
||||
const etl::clamped_value<int, 2, 7> value(4);
|
||||
CHECK_EQUAL(2, value.min());
|
||||
CHECK_EQUAL(7, value.max());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_run_time_initialisation)
|
||||
{
|
||||
etl::clamped_value<int> value(2, 7, 5);
|
||||
etl::clamped_value<int> default_value;
|
||||
etl::clamped_value<int> range_value(2, 7);
|
||||
const etl::clamped_value<int> const_value(value);
|
||||
int converted_value = value;
|
||||
int converted_const_value = const_value;
|
||||
CHECK_EQUAL(5, value.get());
|
||||
CHECK_EQUAL(2, value.min());
|
||||
CHECK_EQUAL(7, value.max());
|
||||
CHECK_EQUAL(etl::numeric_limits<int>::lowest(), default_value.min());
|
||||
CHECK_EQUAL(etl::numeric_limits<int>::max(), default_value.max());
|
||||
CHECK_EQUAL(etl::numeric_limits<int>::lowest(), default_value.get());
|
||||
CHECK_EQUAL(2, range_value.get());
|
||||
CHECK_EQUAL(5, converted_value);
|
||||
CHECK_EQUAL(5, converted_const_value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_set_and_assignment_clamp_values)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> compile_time(1);
|
||||
etl::clamped_value<int> run_time(2, 7, 8);
|
||||
CHECK_EQUAL(2, compile_time.get());
|
||||
CHECK_EQUAL(7, run_time.get());
|
||||
compile_time = 8;
|
||||
run_time.set(1);
|
||||
CHECK_EQUAL(7, compile_time.get());
|
||||
CHECK_EQUAL(2, run_time.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_increment_and_decrement_saturate)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> compile_time(7);
|
||||
etl::clamped_value<int> run_time(2, 7, 2);
|
||||
++compile_time;
|
||||
--run_time;
|
||||
CHECK_EQUAL(7, compile_time.get());
|
||||
CHECK_EQUAL(2, run_time.get());
|
||||
compile_time.to_min();
|
||||
run_time.to_max();
|
||||
--compile_time;
|
||||
++run_time;
|
||||
CHECK_EQUAL(2, compile_time.get());
|
||||
CHECK_EQUAL(7, run_time.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_postfix_operators)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> value(4);
|
||||
etl::clamped_value<int, 2, 7> previous_increment = value++;
|
||||
CHECK_EQUAL(4, previous_increment.get());
|
||||
CHECK_EQUAL(5, value.get());
|
||||
etl::clamped_value<int, 2, 7> previous_decrement = value--;
|
||||
CHECK_EQUAL(5, previous_decrement.get());
|
||||
CHECK_EQUAL(4, value.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_advance_saturates)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> value;
|
||||
value.advance(100);
|
||||
CHECK_EQUAL(7, value.get());
|
||||
value.advance(-100);
|
||||
CHECK_EQUAL(2, value.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_set_run_time_bounds)
|
||||
{
|
||||
etl::clamped_value<int> value(2, 7, 6);
|
||||
value.set(3, 8);
|
||||
CHECK_EQUAL(3, value.get());
|
||||
CHECK_EQUAL(3, value.min());
|
||||
CHECK_EQUAL(8, value.max());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_copy_equality_and_swap_compile_time)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> value1(4);
|
||||
etl::clamped_value<int, 2, 7> value2(value1);
|
||||
CHECK(value1 == value2);
|
||||
value2 = 6;
|
||||
CHECK(value1 != value2);
|
||||
swap(value1, value2);
|
||||
CHECK_EQUAL(6, value1.get());
|
||||
CHECK_EQUAL(4, value2.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_compile_time_instances_with_different_bounds)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> value1(3);
|
||||
etl::clamped_value<int, 2, 8> value2(3);
|
||||
CHECK(value1 == value2);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_runtime_equality_uses_current_value)
|
||||
{
|
||||
etl::clamped_value<int> equal_value1(2, 7, 3);
|
||||
etl::clamped_value<int> equal_value2(2, 8, 3);
|
||||
etl::clamped_value<int> different_value(2, 8, 4);
|
||||
CHECK(equal_value1 == equal_value2);
|
||||
CHECK(!(equal_value1 != equal_value2));
|
||||
CHECK(equal_value1 != different_value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_copy_assignment_and_self_assignment_run_time)
|
||||
{
|
||||
etl::clamped_value<int> value1(2, 7, 5);
|
||||
etl::clamped_value<int> value2(3, 8, 6);
|
||||
value1 = value2;
|
||||
CHECK_EQUAL(6, value1.get());
|
||||
CHECK_EQUAL(3, value1.min());
|
||||
CHECK_EQUAL(8, value1.max());
|
||||
etl::clamped_value<int>* value1_pointer = &value1;
|
||||
value1 = *value1_pointer;
|
||||
CHECK_EQUAL(6, value1.get());
|
||||
CHECK_EQUAL(3, value1.min());
|
||||
CHECK_EQUAL(8, value1.max());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_unsigned_boundary_values)
|
||||
{
|
||||
etl::clamped_value<unsigned, 0U, 2U> value(2U);
|
||||
++value;
|
||||
CHECK_EQUAL(2U, value.get());
|
||||
value.to_min();
|
||||
--value;
|
||||
CHECK_EQUAL(0U, value.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_narrow_signed_range_spanning_lowest_value)
|
||||
{
|
||||
etl::clamped_value<int8_t, INT8_MIN, -10> value(-50);
|
||||
|
||||
value += 10;
|
||||
CHECK_EQUAL(-40, value.get());
|
||||
value -= 10;
|
||||
CHECK_EQUAL(-50, value.get());
|
||||
value.advance(INT8_MIN);
|
||||
CHECK_EQUAL(INT8_MIN, value.get());
|
||||
value.advance(INT8_MAX);
|
||||
CHECK_EQUAL(-10, value.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_runtime_postfix_and_advance)
|
||||
{
|
||||
etl::clamped_value<int> value(2, 7, 4);
|
||||
etl::clamped_value<int> previous_increment = value++;
|
||||
CHECK_EQUAL(4, previous_increment.get());
|
||||
CHECK_EQUAL(5, value.get());
|
||||
etl::clamped_value<int> previous_decrement = value--;
|
||||
CHECK_EQUAL(5, previous_decrement.get());
|
||||
CHECK_EQUAL(4, value.get());
|
||||
value.advance(0);
|
||||
CHECK_EQUAL(4, value.get());
|
||||
value.advance(3);
|
||||
CHECK_EQUAL(7, value.get());
|
||||
value.advance(-3);
|
||||
CHECK_EQUAL(4, value.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_wide_and_negative_ranges)
|
||||
{
|
||||
etl::clamped_value<int, -7, -2> negative(-4);
|
||||
etl::clamped_value<int64_t, -INT64_C(7), INT64_C(7)> wide(0);
|
||||
etl::clamped_value<unsigned> unsigned_value(2U, 7U, 4U);
|
||||
|
||||
negative.advance(100);
|
||||
wide.advance(INT64_MAX);
|
||||
unsigned_value.advance(3);
|
||||
|
||||
CHECK_EQUAL(-2, negative.get());
|
||||
CHECK_EQUAL(INT64_C(7), wide.get());
|
||||
CHECK_EQUAL(7U, unsigned_value.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_compound_and_comparison_operators)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> value(4);
|
||||
etl::clamped_value<int, 2, 7> other(6);
|
||||
|
||||
value += 10;
|
||||
CHECK_EQUAL(7, value.get());
|
||||
value -= 10;
|
||||
CHECK_EQUAL(2, value.get());
|
||||
CHECK(value < other);
|
||||
CHECK(value < 6);
|
||||
CHECK(4 < other);
|
||||
CHECK(value <= other);
|
||||
CHECK(value <= 4);
|
||||
CHECK(4 <= other);
|
||||
CHECK(other > value);
|
||||
CHECK(other > 4);
|
||||
CHECK(6 > value);
|
||||
CHECK(other >= value);
|
||||
CHECK(other >= 6);
|
||||
CHECK(6 >= value);
|
||||
CHECK(value == 2);
|
||||
CHECK(2 == value);
|
||||
CHECK(value != 6);
|
||||
CHECK(6 != value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_mixed_type_comparisons_are_not_ambiguous)
|
||||
{
|
||||
etl::clamped_value<uint8_t, 0, 200> narrow(10);
|
||||
etl::clamped_value<int, 0, 200> value(10);
|
||||
|
||||
CHECK(narrow < 20);
|
||||
CHECK(value < 20L);
|
||||
CHECK(20L > value);
|
||||
CHECK(value <= 20L);
|
||||
CHECK(20L >= value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_runtime_comparison_operator_overloads)
|
||||
{
|
||||
etl::clamped_value<int> value(2, 7, 4);
|
||||
etl::clamped_value<int> other(2, 8, 6);
|
||||
|
||||
CHECK(value < other);
|
||||
CHECK(value < 6);
|
||||
CHECK(4 < other);
|
||||
CHECK(value <= other);
|
||||
CHECK(value <= 4);
|
||||
CHECK(4 <= other);
|
||||
CHECK(other > value);
|
||||
CHECK(other > 4);
|
||||
CHECK(6 > value);
|
||||
CHECK(other >= value);
|
||||
CHECK(other >= 6);
|
||||
CHECK(6 >= value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_advance_extreme_values)
|
||||
{
|
||||
etl::clamped_value<int, 2, 7> compile_time(4);
|
||||
etl::clamped_value<int> run_time(2, 7, 4);
|
||||
compile_time.advance(INT_MAX);
|
||||
run_time.advance(INT_MIN);
|
||||
CHECK_EQUAL(7, compile_time.get());
|
||||
CHECK_EQUAL(2, run_time.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_subtract_lowest_difference_saturates)
|
||||
{
|
||||
etl::clamped_value<int, -10, 10> compile_time(0);
|
||||
etl::clamped_value<int> run_time(-10, 10, 0);
|
||||
|
||||
compile_time -= etl::clamped_value<int, -10, 10>::difference_limits_type::lowest();
|
||||
run_time -= etl::clamped_value<int>::difference_limits_type::lowest();
|
||||
|
||||
CHECK_EQUAL(10, compile_time.get());
|
||||
CHECK_EQUAL(10, run_time.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_runtime_compound_assignment_and_swap)
|
||||
{
|
||||
etl::clamped_value<int> value1(-4, 8, 2);
|
||||
etl::clamped_value<int> value2(10, 20, 15);
|
||||
|
||||
value1 += 20;
|
||||
value2 -= 20;
|
||||
value1.swap(value2);
|
||||
|
||||
CHECK_EQUAL(10, value1.get());
|
||||
CHECK_EQUAL(10, value1.min());
|
||||
CHECK_EQUAL(20, value1.max());
|
||||
CHECK_EQUAL(8, value2.get());
|
||||
CHECK_EQUAL(-4, value2.min());
|
||||
CHECK_EQUAL(8, value2.max());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_runtime_reversed_bounds_are_rejected)
|
||||
{
|
||||
CHECK_THROW((etl::clamped_value<int>(7, 2)), etl::exception);
|
||||
CHECK_THROW((etl::clamped_value<int>(7, 2, 4)), etl::exception);
|
||||
|
||||
etl::clamped_value<int> value;
|
||||
CHECK_THROW(value.set(7, 2), etl::exception);
|
||||
}
|
||||
|
||||
#if ETL_HAS_FLOATING_POINT_CLAMPED_VALUE
|
||||
//*************************************************************************
|
||||
TEST(test_compile_time_floating_clamps_and_advances)
|
||||
{
|
||||
etl::clamped_value<float, -1.5f, 2.5f> value(4.0f);
|
||||
CHECK_CLOSE(2.5f, value.get(), 0.0001f);
|
||||
|
||||
value = -4.0f;
|
||||
CHECK_CLOSE(-1.5f, value.get(), 0.0001f);
|
||||
|
||||
value += 0.75f;
|
||||
CHECK_CLOSE(-0.75f, value.get(), 0.0001f);
|
||||
value -= 0.5f;
|
||||
CHECK_CLOSE(-1.25f, value.get(), 0.0001f);
|
||||
value.advance(10.0f);
|
||||
CHECK_CLOSE(2.5f, value.get(), 0.0001f);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_runtime_floating_clamps_and_advances)
|
||||
{
|
||||
etl::clamped_value<double> value(-1.5, 2.5, 4.0);
|
||||
CHECK_CLOSE(2.5, value.get(), 0.0001);
|
||||
|
||||
value = -4.0;
|
||||
value += 0.75;
|
||||
value -= 0.5;
|
||||
CHECK_CLOSE(-1.25, value.get(), 0.0001);
|
||||
|
||||
value.advance(-10.0);
|
||||
CHECK_CLOSE(-1.5, value.get(), 0.0001);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_floating_increment_and_decrement_saturate_at_fractional_bounds)
|
||||
{
|
||||
etl::clamped_value<float, -0.5f, 0.5f> compile_time(0.25f);
|
||||
etl::clamped_value<float> run_time(-0.5f, 0.5f, -0.25f);
|
||||
|
||||
++compile_time;
|
||||
--run_time;
|
||||
|
||||
CHECK_CLOSE(0.5f, compile_time.get(), 0.0001f);
|
||||
CHECK_CLOSE(-0.5f, run_time.get(), 0.0001f);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_floating_comparison_and_swap)
|
||||
{
|
||||
etl::clamped_value<double, -2.0, 2.0> compile_time1(-0.5);
|
||||
etl::clamped_value<double, -2.0, 2.0> compile_time2(1.5);
|
||||
etl::clamped_value<double> run_time1(-3.0, 3.0, -1.0);
|
||||
etl::clamped_value<double> run_time2(4.0, 8.0, 6.0);
|
||||
|
||||
CHECK(compile_time1 < compile_time2);
|
||||
CHECK(compile_time1 < 1.0);
|
||||
swap(compile_time1, compile_time2);
|
||||
swap(run_time1, run_time2);
|
||||
|
||||
CHECK_CLOSE(1.5, compile_time1.get(), 0.0001);
|
||||
CHECK_CLOSE(6.0, run_time1.get(), 0.0001);
|
||||
CHECK_CLOSE(4.0, run_time1.min(), 0.0001);
|
||||
CHECK_CLOSE(-1.0, run_time2.get(), 0.0001);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_floating_infinity_saturates)
|
||||
{
|
||||
const double infinity = etl::numeric_limits<double>::infinity();
|
||||
etl::clamped_value<double, -2.0, 2.0> value(0.0);
|
||||
etl::clamped_value<double> infinite_range(-infinity, infinity, 0.0);
|
||||
|
||||
value += infinity;
|
||||
CHECK_CLOSE(2.0, value.get(), 0.0001);
|
||||
value -= infinity;
|
||||
CHECK_CLOSE(-2.0, value.get(), 0.0001);
|
||||
|
||||
infinite_range = infinity;
|
||||
CHECK(etl::is_infinity(infinite_range.get()));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_floating_finite_overflow_is_prevented)
|
||||
{
|
||||
const double maximum = etl::numeric_limits<double>::max();
|
||||
etl::clamped_value<double> value(-maximum, maximum, maximum / 2.0);
|
||||
|
||||
value += maximum;
|
||||
CHECK_EQUAL(maximum, value.get());
|
||||
|
||||
value = -maximum / 2.0;
|
||||
value -= maximum;
|
||||
CHECK_EQUAL(-maximum, value.get());
|
||||
|
||||
value = -maximum;
|
||||
value += maximum;
|
||||
CHECK_EQUAL(0.0, value.get());
|
||||
value += maximum;
|
||||
CHECK_EQUAL(maximum, value.get());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_floating_nan_is_rejected)
|
||||
{
|
||||
const double nan = etl::numeric_limits<double>::quiet_NaN();
|
||||
CHECK_THROW((etl::clamped_value<double>(nan, 1.0)), etl::exception);
|
||||
CHECK_THROW((etl::clamped_value<double>(-1.0, nan)), etl::exception);
|
||||
CHECK_THROW((etl::clamped_value<double>(-1.0, 1.0, nan)), etl::exception);
|
||||
|
||||
etl::clamped_value<double> value(-1.0, 1.0, 0.0);
|
||||
CHECK_THROW(value.set(nan, 1.0), etl::exception);
|
||||
CHECK_THROW(value.set(-1.0, nan), etl::exception);
|
||||
CHECK_THROW(value = nan, etl::exception);
|
||||
CHECK_THROW(value.advance(nan), etl::exception);
|
||||
CHECK_THROW(value += nan, etl::exception);
|
||||
CHECK_THROW(value -= nan, etl::exception);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_default_floating_range)
|
||||
{
|
||||
etl::clamped_value<double> value;
|
||||
CHECK_EQUAL(etl::numeric_limits<double>::lowest(), value.min());
|
||||
CHECK_EQUAL(etl::numeric_limits<double>::max(), value.max());
|
||||
CHECK_EQUAL(etl::numeric_limits<double>::lowest(), value.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ETL_USING_CPP14
|
||||
//*************************************************************************
|
||||
TEST(test_clamped_value_constexpr_ctor)
|
||||
{
|
||||
constexpr etl::clamped_value<int, 0, 9> value;
|
||||
static_assert(value.get() == 0, "constexpr clamped_value constructor");
|
||||
CHECK(true);
|
||||
}
|
||||
|
||||
#if ETL_HAS_FLOATING_POINT_CLAMPED_VALUE
|
||||
//*************************************************************************
|
||||
TEST(test_floating_clamped_value_constexpr)
|
||||
{
|
||||
constexpr etl::clamped_value<double, -1.0, 1.0> value(0.5);
|
||||
static_assert((value.get() > 0.49) && (value.get() < 0.51), "constexpr floating clamped_value constructor");
|
||||
CHECK(true);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
@ -3764,6 +3764,7 @@
|
||||
<ClInclude Include="..\..\include\etl\bloom_filter.h" />
|
||||
<ClInclude Include="..\..\include\etl\char_traits.h" />
|
||||
<ClInclude Include="..\..\include\etl\checksum.h" />
|
||||
<ClInclude Include="..\..\include\etl\clamped_value.h" />
|
||||
<ClInclude Include="..\..\include\etl\cyclic_value.h" />
|
||||
<ClInclude Include="..\..\include\etl\debounce.h" />
|
||||
<ClInclude Include="..\..\include\etl\debug_count.h" />
|
||||
@ -6303,6 +6304,7 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - Force C++03|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20 - Force C++03 - No virtual messages|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\syntax_check\clamped_value.h.t.cpp" />
|
||||
<ClCompile Include="..\syntax_check\cyclic_value.h.t.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug MSVC C++20|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Clang C++20|Win32'">true</ExcludedFromBuild>
|
||||
@ -10446,6 +10448,7 @@
|
||||
<ClCompile Include="..\test_compare.cpp" />
|
||||
<ClCompile Include="..\test_constant.cpp" />
|
||||
<ClCompile Include="..\test_container.cpp" />
|
||||
<ClCompile Include="..\test_clamped_value.cpp" />
|
||||
<ClCompile Include="..\test_cyclic_value.cpp" />
|
||||
<ClCompile Include="..\test_debounce.cpp" />
|
||||
<ClCompile Include="..\test_deque.cpp">
|
||||
|
||||
@ -261,6 +261,9 @@
|
||||
<ClInclude Include="..\..\include\etl\numeric.h">
|
||||
<Filter>ETL\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\clamped_value.h">
|
||||
<Filter>ETL\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\cyclic_value.h">
|
||||
<Filter>ETL\Utilities</Filter>
|
||||
</ClInclude>
|
||||
@ -2087,6 +2090,9 @@
|
||||
<ClCompile Include="..\test_pseudo_moving_average.cpp">
|
||||
<Filter>Tests\Algorithms</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_clamped_value.cpp">
|
||||
<Filter>Tests\Algorithms</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_cyclic_value.cpp">
|
||||
<Filter>Tests\Algorithms</Filter>
|
||||
</ClCompile>
|
||||
@ -2909,6 +2915,9 @@
|
||||
<ClCompile Include="..\syntax_check\crc64_ecma.h.t.cpp">
|
||||
<Filter>Tests\Syntax Checks\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\syntax_check\clamped_value.h.t.cpp">
|
||||
<Filter>Tests\Syntax Checks\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\syntax_check\cyclic_value.h.t.cpp">
|
||||
<Filter>Tests\Syntax Checks\Source</Filter>
|
||||
</ClCompile>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user