@@ -42,7 +42,7 @@ class Saturated
42
42
using TP = std::remove_reference_t <T>;
43
43
using TS = std::conditional_t <std::is_signed_v<T>, T, std::make_signed_t <modm::WideType<TP>>>;
44
44
45
- T value = 0 ;
45
+ T value{ 0 } ;
46
46
private:
47
47
static constexpr TP min = std::numeric_limits<TP>::min();
48
48
static constexpr TP max = std::numeric_limits<TP>::max();
@@ -55,36 +55,63 @@ class Saturated
55
55
56
56
template <typename U>
57
57
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); }
58
+ constexpr Saturated (const U& value )
59
+ { this -> value = std::clamp< modm::fits_any_t <TP, U> >(value , min, max); }
60
60
61
61
template <typename U>
62
62
requires std::floating_point<std::remove_reference_t <U>>
63
- constexpr Saturated (const U& v )
64
- { value = std::clamp<float >(v , min, max); }
63
+ constexpr Saturated (const U& value )
64
+ { this -> value = std::clamp<float >(value , min, max); }
65
65
66
66
template <typename U>
67
67
requires std::integral<std::remove_reference_t <U>>
68
68
constexpr Saturated (const Saturated<U>& other)
69
69
{ value = std::clamp< modm::fits_any_t <TP, U> >(other.value , min, max); }
70
70
71
- TP
72
- getValue () const
73
- { return value; }
74
-
75
- // Implicitely serve underlying type so you can f.e. pass Saturated to std::abs()
76
- operator T&() { return value; }
71
+ // Implicit conversion to underlying type
72
+ // @see: https://en.cppreference.com/w/cpp/language/implicit_conversion
77
73
operator T () const { return value; }
78
74
79
75
// comparison operators
80
76
constexpr auto
81
77
operator <=>(const Saturated<T>&) const = default ;
82
78
79
+ template <typename U>
80
+ constexpr bool
81
+ operator ==(const U& other) const
82
+ { return value == other; }
83
+
84
+ template <typename U>
85
+ constexpr bool
86
+ operator >(const U& other) const
87
+ { return value > other; }
88
+
89
+ template <typename U>
90
+ constexpr bool
91
+ operator <(const U& other) const
92
+ { return value < other; }
93
+
94
+ template <typename U>
95
+ constexpr bool
96
+ operator >=(const U& other) const
97
+ { return value >= other; }
98
+
99
+ template <typename U>
100
+ constexpr bool
101
+ operator <=(const U& other) const
102
+ { return value <= other; }
103
+
83
104
// operator=
84
105
void
85
106
operator =(const Saturated& other)
86
107
{ value = other.value ; }
87
108
109
+ template <typename U>
110
+ requires std::integral<std::remove_reference_t <U>>
111
+ void
112
+ operator =(const U& other)
113
+ { value = std::clamp< modm::fits_any_t <TP, U> >(other, min, max); }
114
+
88
115
template <typename U>
89
116
requires std::integral<std::remove_reference_t <U>>
90
117
void
@@ -124,6 +151,17 @@ class Saturated
124
151
}
125
152
126
153
// operator+=, operator-=, operator*=
154
+ template <typename U>
155
+ requires std::unsigned_integral<std::remove_reference_t <U>>
156
+ Saturated&
157
+ operator +=(const U& other)
158
+ {
159
+ if (__builtin_add_overflow (value, other, &value))
160
+ value = max;
161
+
162
+ return *this ;
163
+ }
164
+
127
165
template <typename U>
128
166
requires std::unsigned_integral<std::remove_reference_t <U>>
129
167
Saturated&
@@ -135,6 +173,22 @@ class Saturated
135
173
return *this ;
136
174
}
137
175
176
+ template <typename U>
177
+ requires std::signed_integral<std::remove_reference_t <U>>
178
+ Saturated&
179
+ operator +=(const U& other)
180
+ {
181
+ if (other < 0 ) {
182
+ if (__builtin_sub_overflow (value, -other, &value))
183
+ value = min;
184
+ } else {
185
+ if (__builtin_add_overflow (value, other, &value))
186
+ value = max;
187
+ }
188
+
189
+ return *this ;
190
+ }
191
+
138
192
template <typename U>
139
193
requires std::signed_integral<std::remove_reference_t <U>>
140
194
Saturated&
@@ -151,6 +205,17 @@ class Saturated
151
205
return *this ;
152
206
}
153
207
208
+ template <typename U>
209
+ requires std::unsigned_integral<std::remove_reference_t <U>>
210
+ Saturated&
211
+ operator -=(const U& other)
212
+ {
213
+ if (__builtin_sub_overflow (value, other, &value))
214
+ value = min;
215
+
216
+ return *this ;
217
+ }
218
+
154
219
template <typename U>
155
220
requires std::unsigned_integral<std::remove_reference_t <U>>
156
221
Saturated&
@@ -162,6 +227,22 @@ class Saturated
162
227
return *this ;
163
228
}
164
229
230
+ template <typename U>
231
+ requires std::signed_integral<std::remove_reference_t <U>>
232
+ Saturated&
233
+ operator -=(const U& other)
234
+ {
235
+ if (other < 0 ) {
236
+ if (__builtin_add_overflow (value, -other, &value))
237
+ value = max;
238
+ } else {
239
+ if (__builtin_sub_overflow (value, other, &value))
240
+ value = min;
241
+ }
242
+
243
+ return *this ;
244
+ }
245
+
165
246
template <typename U>
166
247
requires std::signed_integral<std::remove_reference_t <U>>
167
248
Saturated&
@@ -181,62 +262,73 @@ class Saturated
181
262
template <typename U>
182
263
requires std::unsigned_integral<std::remove_reference_t <U>>
183
264
Saturated&
184
- operator *=(const Saturated<U> & other)
265
+ operator *=(const U & other)
185
266
{
186
- if (__builtin_mul_overflow (value, other. value , &value))
267
+ if (__builtin_mul_overflow (value, other, &value))
187
268
value = max;
188
269
189
270
return *this ;
190
271
}
191
272
192
273
template <typename U>
193
- requires std::signed_integral <std::remove_reference_t <U>>
274
+ requires std::unsigned_integral <std::remove_reference_t <U>>
194
275
Saturated&
195
276
operator *=(const Saturated<U>& other)
196
277
{
197
- if (other.value < 0 ) {
198
- if (__builtin_mul_overflow (value, -other.value , &value))
199
- value = max;
200
- value = -value;
201
- } else {
202
- if (__builtin_mul_overflow (value, other.value , &value))
203
- value = max;
204
- }
278
+ if (__builtin_mul_overflow (value, other.value , &value))
279
+ value = max;
205
280
206
281
return *this ;
207
282
}
208
283
209
- // OPTIMIZE By whatever reason, for operator*= the compiler doesn't implicitly construct Saturated types.
210
- // Overload plain types for now:
211
284
template <typename U>
212
- requires std::unsigned_integral <std::remove_reference_t <U>>
285
+ requires std::signed_integral <std::remove_reference_t <U>>
213
286
Saturated&
214
- operator *=(const U& v )
287
+ operator *=(const U& other )
215
288
{
216
- if (__builtin_mul_overflow (value, v, &value))
217
- value = max;
289
+ if (other < 0 ) {
290
+ if (__builtin_mul_overflow (value, -other, &value))
291
+ value = max;
292
+ value = -value;
293
+ } else {
294
+ if (__builtin_mul_overflow (value, other, &value))
295
+ value = max;
296
+ }
218
297
219
298
return *this ;
220
299
}
221
300
222
301
template <typename U>
223
302
requires std::signed_integral<std::remove_reference_t <U>>
224
303
Saturated&
225
- operator *=(const U& v )
304
+ operator *=(const Saturated<U>& other )
226
305
{
227
- if (v < 0 ) {
228
- if (__builtin_mul_overflow (value, -v , &value))
306
+ if (other. value < 0 ) {
307
+ if (__builtin_mul_overflow (value, -other. value , &value))
229
308
value = max;
230
309
value = -value;
231
310
} else {
232
- if (__builtin_mul_overflow (value, v , &value))
311
+ if (__builtin_mul_overflow (value, other. value , &value))
233
312
value = max;
234
313
}
235
314
236
315
return *this ;
237
316
}
238
317
239
318
// operator+, operator-, operator*
319
+ template <typename U>
320
+ requires std::unsigned_integral<std::remove_reference_t <U>>
321
+ TP
322
+ operator +(const U& other)
323
+ {
324
+ Saturated<TP> tmp;
325
+
326
+ if (__builtin_add_overflow (value, other, &tmp.value ))
327
+ tmp.value = max;
328
+
329
+ return tmp.value ;
330
+ }
331
+
240
332
template <typename U>
241
333
requires std::unsigned_integral<std::remove_reference_t <U>>
242
334
TP
@@ -250,6 +342,24 @@ class Saturated
250
342
return tmp.value ;
251
343
}
252
344
345
+ template <typename U>
346
+ requires std::signed_integral<std::remove_reference_t <U>>
347
+ TP
348
+ operator +(const U& other)
349
+ {
350
+ Saturated<TP> tmp;
351
+
352
+ if (other < 0 ) {
353
+ if (__builtin_sub_overflow (value, -other, &tmp.value ))
354
+ tmp.value = min;
355
+ } else {
356
+ if (__builtin_add_overflow (value, other, &tmp.value ))
357
+ tmp.value = max;
358
+ }
359
+
360
+ return tmp.value ;
361
+ }
362
+
253
363
template <typename U>
254
364
requires std::signed_integral<std::remove_reference_t <U>>
255
365
TP
@@ -268,6 +378,19 @@ class Saturated
268
378
return tmp.value ;
269
379
}
270
380
381
+ template <typename U>
382
+ requires std::unsigned_integral<std::remove_reference_t <U>>
383
+ TP
384
+ operator -(const U& other)
385
+ {
386
+ Saturated<TP> tmp;
387
+
388
+ if (__builtin_sub_overflow (value, other, &tmp.value ))
389
+ tmp.value = min;
390
+
391
+ return tmp.value ;
392
+ }
393
+
271
394
template <typename U>
272
395
requires std::unsigned_integral<std::remove_reference_t <U>>
273
396
TP
@@ -281,6 +404,24 @@ class Saturated
281
404
return tmp.value ;
282
405
}
283
406
407
+ template <typename U>
408
+ requires std::signed_integral<std::remove_reference_t <U>>
409
+ TP
410
+ operator -(const U& other)
411
+ {
412
+ Saturated<TP> tmp;
413
+
414
+ if (other < 0 ) {
415
+ if (__builtin_add_overflow (value, -other, &tmp.value ))
416
+ tmp.value = max;
417
+ } else {
418
+ if (__builtin_sub_overflow (value, other, &tmp.value ))
419
+ tmp.value = min;
420
+ }
421
+
422
+ return tmp.value ;
423
+ }
424
+
284
425
template <typename U>
285
426
requires std::signed_integral<std::remove_reference_t <U>>
286
427
TP
0 commit comments