@@ -30,7 +30,6 @@ namespace modm
30
30
* @see https://en.wikipedia.org/wiki/Saturation_arithmetic
31
31
*
32
32
* @author Thomas Sommer
33
- *
34
33
* @ingroup modm_math_saturated
35
34
*/
36
35
@@ -42,7 +41,7 @@ class Saturated
42
41
using TP = std::remove_reference_t <T>;
43
42
using TS = std::conditional_t <std::is_signed_v<T>, T, std::make_signed_t <modm::WideType<TP>>>;
44
43
45
- T value = 0 ;
44
+ T value{ 0 } ;
46
45
private:
47
46
static constexpr TP min = std::numeric_limits<TP>::min();
48
47
static constexpr TP max = std::numeric_limits<TP>::max();
@@ -55,36 +54,35 @@ class Saturated
55
54
56
55
template <typename U>
57
56
requires std::integral<std::remove_reference_t <U>>
58
- constexpr Saturated (const U& v )
59
- { value = std::clamp< modm::fits_any_t <TP, U> >(v , min, max); }
57
+ constexpr Saturated (const U& value )
58
+ { this -> value = std::clamp< modm::fits_any_t <TP, U> >(value , min, max); }
60
59
61
60
template <typename U>
62
61
requires std::floating_point<std::remove_reference_t <U>>
63
- constexpr Saturated (const U& v )
64
- { value = std::clamp<float >(v , min, max); }
62
+ constexpr Saturated (const U& value )
63
+ { this -> value = std::clamp<float >(value , min, max); }
65
64
66
65
template <typename U>
67
66
requires std::integral<std::remove_reference_t <U>>
68
67
constexpr Saturated (const Saturated<U>& other)
69
68
{ value = std::clamp< modm::fits_any_t <TP, U> >(other.value , min, max); }
70
69
71
- TP
72
- getValue () const
70
+ // Cast to underlying type. No need to define getters and comparison operators.
71
+ // @see https://en.cppreference.com/w/cpp/language/cast_operator
72
+ operator T () const
73
73
{ return value; }
74
74
75
- // Implicitely serve underlying type so you can f.e. pass Saturated to std::abs()
76
- operator T&() { return value; }
77
- operator T () const { return value; }
78
-
79
- // comparison operators
80
- constexpr auto
81
- operator <=>(const Saturated<T>&) const = default ;
82
-
83
75
// operator=
84
76
void
85
77
operator =(const Saturated& other)
86
78
{ value = other.value ; }
87
79
80
+ template <typename U>
81
+ requires std::integral<std::remove_reference_t <U>>
82
+ void
83
+ operator =(const U& other)
84
+ { value = std::clamp< modm::fits_any_t <TP, U> >(other, min, max); }
85
+
88
86
template <typename U>
89
87
requires std::integral<std::remove_reference_t <U>>
90
88
void
@@ -110,26 +108,26 @@ class Saturated
110
108
Saturated
111
109
operator ++(int )
112
110
{
113
- Saturated tmp (*this );
111
+ Saturated ret (*this );
114
112
if (value < max) value++;
115
- return tmp ;
113
+ return ret ;
116
114
}
117
115
118
116
Saturated
119
117
operator --(int )
120
118
{
121
- Saturated tmp (*this );
119
+ Saturated ret (*this );
122
120
if (value > min) value--;
123
- return tmp ;
121
+ return ret ;
124
122
}
125
123
126
124
// operator+=, operator-=, operator*=
127
125
template <typename U>
128
126
requires std::unsigned_integral<std::remove_reference_t <U>>
129
127
Saturated&
130
- operator +=(const Saturated<U> & other)
128
+ operator +=(const U & other)
131
129
{
132
- if (__builtin_add_overflow (value, other. value , &value))
130
+ if (__builtin_add_overflow (value, other, &value))
133
131
value = max;
134
132
135
133
return *this ;
@@ -138,25 +136,31 @@ class Saturated
138
136
template <typename U>
139
137
requires std::signed_integral<std::remove_reference_t <U>>
140
138
Saturated&
141
- operator +=(const Saturated<U> & other)
139
+ operator +=(const U & other)
142
140
{
143
- if (other. value < 0 ) {
144
- if (__builtin_sub_overflow (value, -other. value , &value))
141
+ if (other < 0 ) {
142
+ if (__builtin_sub_overflow (value, -other, &value))
145
143
value = min;
146
144
} else {
147
- if (__builtin_add_overflow (value, other. value , &value))
145
+ if (__builtin_add_overflow (value, other, &value))
148
146
value = max;
149
147
}
150
148
151
149
return *this ;
152
150
}
153
151
152
+ template <typename U>
153
+ requires std::integral<std::remove_reference_t <U>>
154
+ Saturated&
155
+ operator +=(const Saturated<U>& other)
156
+ { return this ->operator +=(other.value ); }
157
+
154
158
template <typename U>
155
159
requires std::unsigned_integral<std::remove_reference_t <U>>
156
160
Saturated&
157
- operator -=(const Saturated<U> & other)
161
+ operator -=(const U & other)
158
162
{
159
- if (__builtin_sub_overflow (value, other. value , &value))
163
+ if (__builtin_sub_overflow (value, other, &value))
160
164
value = min;
161
165
162
166
return *this ;
@@ -165,25 +169,31 @@ class Saturated
165
169
template <typename U>
166
170
requires std::signed_integral<std::remove_reference_t <U>>
167
171
Saturated&
168
- operator -=(const Saturated<U> & other)
172
+ operator -=(const U & other)
169
173
{
170
- if (other. value < 0 ) {
171
- if (__builtin_add_overflow (value, -other. value , &value))
174
+ if (other < 0 ) {
175
+ if (__builtin_add_overflow (value, -other, &value))
172
176
value = max;
173
177
} else {
174
- if (__builtin_sub_overflow (value, other. value , &value))
178
+ if (__builtin_sub_overflow (value, other, &value))
175
179
value = min;
176
180
}
177
181
178
182
return *this ;
179
183
}
180
184
185
+ template <typename U>
186
+ requires std::integral<std::remove_reference_t <U>>
187
+ Saturated&
188
+ operator -=(const Saturated<U>& other)
189
+ { return this ->operator -=(other.value ); }
190
+
181
191
template <typename U>
182
192
requires std::unsigned_integral<std::remove_reference_t <U>>
183
193
Saturated&
184
- operator *=(const Saturated<U> & other)
194
+ operator *=(const U & other)
185
195
{
186
- if (__builtin_mul_overflow (value, other. value , &value))
196
+ if (__builtin_mul_overflow (value, other, &value))
187
197
value = max;
188
198
189
199
return *this ;
@@ -192,126 +202,156 @@ class Saturated
192
202
template <typename U>
193
203
requires std::signed_integral<std::remove_reference_t <U>>
194
204
Saturated&
195
- operator *=(const Saturated<U> & other)
205
+ operator *=(const U & other)
196
206
{
197
- if (other. value < 0 ) {
198
- if (__builtin_mul_overflow (value, -other. value , &value))
207
+ if (other < 0 ) {
208
+ if (__builtin_mul_overflow (value, -other, &value))
199
209
value = max;
200
210
value = -value;
201
211
} else {
202
- if (__builtin_mul_overflow (value, other. value , &value))
212
+ if (__builtin_mul_overflow (value, other, &value))
203
213
value = max;
204
214
}
205
215
206
216
return *this ;
207
217
}
208
218
209
- // OPTIMIZE By whatever reason, for operator*= the compiler doesn't implicitly construct Saturated types.
210
- // Overload plain types for now:
211
219
template <typename U>
212
- requires std::unsigned_integral <std::remove_reference_t <U>>
220
+ requires std::integral <std::remove_reference_t <U>>
213
221
Saturated&
214
- operator *=(const U& v)
222
+ operator *=(const Saturated<U>& other)
223
+ { return this ->operator *=(other.value ); }
224
+
225
+ // operator+, operator-, operator*
226
+ template <typename U>
227
+ requires std::unsigned_integral<std::remove_reference_t <U>>
228
+ TP
229
+ operator +(const U& other) const
215
230
{
216
- if (__builtin_mul_overflow (value, v, &value))
217
- value = max;
231
+ Saturated<TP> ret;
218
232
219
- return *this ;
233
+ if (__builtin_add_overflow (value, other, &ret.value ))
234
+ ret.value = max;
235
+
236
+ return ret;
220
237
}
221
238
222
239
template <typename U>
223
240
requires std::signed_integral<std::remove_reference_t <U>>
224
- Saturated&
225
- operator *= (const U& v)
241
+ TP
242
+ operator + (const U& other) const
226
243
{
227
- if (v < 0 ) {
228
- if (__builtin_mul_overflow (value, -v, &value))
229
- value = max;
230
- value = -value;
244
+ Saturated<TP> ret;
245
+
246
+ if (other < 0 ) {
247
+ if (__builtin_sub_overflow (value, -other, &ret.value ))
248
+ ret.value = min;
231
249
} else {
232
- if (__builtin_mul_overflow (value, v , &value))
233
- value = max;
250
+ if (__builtin_add_overflow (value, other , &ret. value ))
251
+ ret. value = max;
234
252
}
235
253
236
- return * this ;
254
+ return ret ;
237
255
}
238
256
239
- // operator+, operator-, operator*
257
+ template <typename U>
258
+ requires std::integral<std::remove_reference_t <U>>
259
+ Saturated<TP>
260
+ operator +(const Saturated<U>& other) const
261
+ { return this ->operator +(other.value ); }
262
+
240
263
template <typename U>
241
264
requires std::unsigned_integral<std::remove_reference_t <U>>
242
- TP
243
- operator + (const Saturated<U> & other)
265
+ Saturated<TP>
266
+ operator - (const U & other) const
244
267
{
245
- Saturated<TP> tmp ;
268
+ Saturated<TP> ret ;
246
269
247
- if (__builtin_add_overflow (value, other. value , &tmp .value ))
248
- tmp .value = max ;
270
+ if (__builtin_sub_overflow (value, other, &ret .value ))
271
+ ret .value = min ;
249
272
250
- return tmp. value ;
273
+ return ret ;
251
274
}
252
275
253
276
template <typename U>
254
277
requires std::signed_integral<std::remove_reference_t <U>>
255
- TP
256
- operator + (const Saturated<U> & other)
278
+ Saturated<TP>
279
+ operator - (const U & other) const
257
280
{
258
- Saturated<TP> tmp ;
281
+ Saturated<TP> ret ;
259
282
260
- if (other. value < 0 ) {
261
- if (__builtin_sub_overflow (value, -other. value , &tmp .value ))
262
- tmp .value = min ;
283
+ if (other < 0 ) {
284
+ if (__builtin_add_overflow (value, -other, &ret .value ))
285
+ ret .value = max ;
263
286
} else {
264
- if (__builtin_add_overflow (value, other. value , &tmp .value ))
265
- tmp .value = max ;
287
+ if (__builtin_sub_overflow (value, other, &ret .value ))
288
+ ret .value = min ;
266
289
}
267
290
268
- return tmp. value ;
291
+ return ret ;
269
292
}
270
293
294
+ template <typename U>
295
+ requires std::integral<std::remove_reference_t <U>>
296
+ Saturated<TP>
297
+ operator -(const Saturated<U>& other) const
298
+ { return this ->operator -(other.value ); }
299
+
271
300
template <typename U>
272
301
requires std::unsigned_integral<std::remove_reference_t <U>>
273
- TP
274
- operator - (const Saturated<U> & other)
302
+ Saturated<TP>
303
+ operator * (const U & other) const
275
304
{
276
- Saturated<TP> tmp ;
305
+ Saturated<TP> ret ;
277
306
278
- if (__builtin_sub_overflow (value, other. value , &tmp .value ))
279
- tmp .value = min ;
307
+ if (__builtin_mul_overflow (value, other, &ret .value ))
308
+ ret .value = max ;
280
309
281
- return tmp. value ;
310
+ return ret ;
282
311
}
283
312
284
313
template <typename U>
285
314
requires std::signed_integral<std::remove_reference_t <U>>
286
- TP
287
- operator - (const Saturated<U> & other)
315
+ Saturated<TP>
316
+ operator * (const U & other) const
288
317
{
289
- Saturated<TP> tmp ;
318
+ Saturated<TP> ret ;
290
319
291
- if (other.value < 0 ) {
292
- if (__builtin_add_overflow (value, -other.value , &tmp.value ))
293
- tmp.value = max;
320
+ if (other < 0 ) {
321
+ if (__builtin_mul_overflow (value, -other, &ret.value ))
322
+ ret.value = max;
323
+ ret.value = -ret.value ;
294
324
} else {
295
- if (__builtin_sub_overflow (value, other. value , &tmp .value ))
296
- tmp .value = min ;
325
+ if (__builtin_mul_overflow (value, other, &ret .value ))
326
+ ret .value = max ;
297
327
}
298
328
299
- return tmp. value ;
329
+ return ret ;
300
330
}
301
331
302
- TP
303
- operator *(const Saturated<T>& other)
332
+ template <typename U>
333
+ requires std::integral<std::remove_reference_t <U>>
334
+ Saturated<TP>
335
+ operator *(const Saturated<U>& other) const
336
+ { return this ->operator *(other.value ); }
337
+
338
+ template <typename U>
339
+ requires std::integral<std::remove_reference_t <U>>
340
+ Saturated<TP>
341
+ operator /(const U& other) const
304
342
{
305
- Saturated<TP> tmp;
343
+ return Saturated<TP>(value / other);
344
+ }
306
345
307
- if (__builtin_mul_overflow (value, other.value , &tmp.value ))
308
- tmp.value = max;
346
+ template <typename U>
347
+ requires std::integral<std::remove_reference_t <U>>
348
+ Saturated<TP>
349
+ operator /(const Saturated<U>& other) const
350
+ { return this ->operator /(other.value ); }
309
351
310
- return tmp.value ;
311
- }
312
352
313
353
TS
314
- operator -()
354
+ operator -() const
315
355
{ return -TS (value); }
316
356
317
357
void
0 commit comments