Sparkle 0.0.1
Loading...
Searching...
No Matches
spk_safe_comparand.hpp
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5
6#include "structure/math/spk_constants.hpp"
7
8namespace spk
9{
16 template <typename TType, bool IsFloat = std::is_floating_point_v<TType>>
18
33 template <typename TType>
34 struct SafeComparand<TType, false>
35 {
36 static_assert(std::is_arithmetic_v<TType>, "TType must be arithmetic");
40 using value_type = TType;
41
43 TType value{};
44
46 SafeComparand() = default;
47
52 explicit SafeComparand(const TType &p_value) :
53 value(p_value)
54 {
55 }
56 };
57
72 template <typename TType>
73 struct SafeComparand<TType, true>
74 {
75 static_assert(std::is_floating_point_v<TType>, "TType must be floating");
76
78 TType value{};
80 TType epsilon{static_cast<TType>(spk::Math::Constants::pointPrecision)};
81
83 SafeComparand() = default;
84
89 explicit SafeComparand(const TType &p_value) :
90 value(p_value)
91 {
92 }
93
99 SafeComparand(const TType &p_value, const TType &p_epsilon) :
100 value(p_value),
101 epsilon(p_epsilon)
102 {
103 }
104 };
105
106 template <class T>
107 SafeComparand(T) -> SafeComparand<std::remove_cv_t<std::remove_reference_t<T>>, std::is_floating_point_v<std::remove_cv_t<std::remove_reference_t<T>>>>;
108
109 template <class T, class U>
110 SafeComparand(T, U) -> SafeComparand<std::remove_cv_t<std::remove_reference_t<T>>, std::is_floating_point_v<std::remove_cv_t<std::remove_reference_t<T>>>>;
111
112 template <typename TLeftHandType, bool IsLeftHandleFloatingType, typename TRightHandType>
113 requires(std::is_arithmetic_v<TLeftHandType> && std::is_arithmetic_v<TRightHandType>)
114 constexpr bool operator==(const SafeComparand<TLeftHandType, IsLeftHandleFloatingType> &p_lhs, const TRightHandType &p_rhs)
115 {
116 using Common = std::common_type_t<TLeftHandType, TRightHandType>;
117
118 if constexpr (IsLeftHandleFloatingType)
119 {
120 const Common dv = static_cast<Common>(p_lhs.value) - static_cast<Common>(p_rhs);
121 const Common eps = static_cast<Common>(p_lhs.epsilon);
122 return std::abs(dv) <= eps;
123 }
124 else
125 {
126 if constexpr (std::is_floating_point_v<TRightHandType>)
127 {
128 const Common dv = static_cast<Common>(p_lhs.value) - static_cast<Common>(p_rhs);
129 const Common eps = static_cast<Common>(spk::Math::Constants::pointPrecision);
130 return std::abs(dv) <= eps;
131 }
132 else
133 {
134 return p_lhs.value == static_cast<TLeftHandType>(p_rhs);
135 }
136 }
137 }
138
139 template <typename TLeftHandType, typename TRightHandType, bool IsRightHandFloatingType>
140 requires(std::is_arithmetic_v<TLeftHandType> && std::is_arithmetic_v<TRightHandType>)
141 constexpr bool operator==(const TLeftHandType &p_lhs, const SafeComparand<TRightHandType, IsRightHandFloatingType> &p_rhs)
142 {
143 return (p_rhs == p_lhs);
144 }
145
146 template <typename TLeftHandType, bool IsLeftHandFloatingType, typename TRightHandType, bool IsRightHandFloatingType>
147 requires(std::is_arithmetic_v<TLeftHandType> && std::is_arithmetic_v<TRightHandType>)
148 constexpr bool operator==(
150 {
151 using Common = std::common_type_t<TLeftHandType, TRightHandType>;
152 if constexpr (IsLeftHandFloatingType || IsRightHandFloatingType)
153 {
154 const Common dv = static_cast<Common>(p_lhs.value) - static_cast<Common>(p_rhs.value);
155 Common eps{};
156 if constexpr (IsLeftHandFloatingType && IsRightHandFloatingType)
157 {
158 eps = std::min<Common>(static_cast<Common>(p_lhs.epsilon), static_cast<Common>(p_rhs.epsilon));
159 }
160 else if constexpr (IsLeftHandFloatingType)
161 {
162 eps = static_cast<Common>(p_lhs.epsilon);
163 }
164 else
165 {
166 eps = static_cast<Common>(p_rhs.epsilon);
167 }
168 return std::abs(dv) <= eps;
169 }
170 else
171 {
172 return static_cast<Common>(p_lhs.value) == static_cast<Common>(p_rhs.value);
173 }
174 }
175
176 template <typename TLeftHandType, bool IsLeftHandFloatingType, typename TRightHandType>
177 requires(std::is_arithmetic_v<TLeftHandType> && std::is_arithmetic_v<TRightHandType>)
178 constexpr bool operator!=(const SafeComparand<TLeftHandType, IsLeftHandFloatingType> &p_lhs, const TRightHandType &p_rhs)
179 {
180 return !(p_lhs == p_rhs);
181 }
182
183 template <typename TLeftHandType, typename TRightHandType, bool IsRightHandFloatingType>
184 requires(std::is_arithmetic_v<TLeftHandType> && std::is_arithmetic_v<TRightHandType>)
185 constexpr bool operator!=(const TLeftHandType &p_lhs, const SafeComparand<TRightHandType, IsRightHandFloatingType> &p_rhs)
186 {
187 return !(p_lhs == p_rhs);
188 }
189
190 template <typename TLeftHandType, bool IsLeftHandFloatingType, typename TRightHandType, bool IsRightHandFloatingType>
191 requires(std::is_arithmetic_v<TLeftHandType> && std::is_arithmetic_v<TRightHandType>)
192 constexpr bool operator!=(
194 {
195 return !(p_lhs == p_rhs);
196 }
197}
SafeComparand(const TType &p_value)
Wraps a value for tolerant comparisons.
Definition spk_safe_comparand.hpp:52
TType value
Stored numeric value.
Definition spk_safe_comparand.hpp:43
SafeComparand()=default
Default-initializes the stored value.
TType value_type
Exposes the underlying arithmetic type.
Definition spk_safe_comparand.hpp:40
TType epsilon
Comparison tolerance applied when evaluating equality.
Definition spk_safe_comparand.hpp:80
SafeComparand()=default
Default-initializes the value to zero with default epsilon.
SafeComparand(const TType &p_value, const TType &p_epsilon)
Wraps a floating value with a custom tolerance.
Definition spk_safe_comparand.hpp:99
TType value
Stored numeric value.
Definition spk_safe_comparand.hpp:78
SafeComparand(const TType &p_value)
Wraps a floating value using default epsilon.
Definition spk_safe_comparand.hpp:89
Wraps arithmetic values to compare with tolerance for floating-point inputs.
Definition spk_safe_comparand.hpp:17