|
36 | 36 | } \
|
37 | 37 | static_assert(true)
|
38 | 38 |
|
39 |
| -#define _sus__unsigned_impl(T, Bytes, LargerT) \ |
40 |
| - _sus__unsigned_from(T); \ |
41 |
| - _sus__unsigned_integer_comparison(T); \ |
42 |
| - _sus__unsigned_unary_ops(T); \ |
43 |
| - _sus__unsigned_binary_logic_ops(T); \ |
44 |
| - _sus__unsigned_binary_bit_ops(T); \ |
45 |
| - _sus__unsigned_mutable_logic_ops(T); \ |
46 |
| - _sus__unsigned_mutable_bit_ops(T); \ |
47 |
| - _sus__unsigned_abs(T); \ |
48 |
| - _sus__unsigned_add(T); \ |
49 |
| - _sus__unsigned_div(T); \ |
50 |
| - _sus__unsigned_mul(T, LargerT); \ |
51 |
| - _sus__unsigned_neg(T); \ |
52 |
| - _sus__unsigned_rem(T); \ |
53 |
| - _sus__unsigned_shift(T); \ |
54 |
| - _sus__unsigned_sub(T); \ |
55 |
| - _sus__unsigned_bits(T); \ |
56 |
| - _sus__unsigned_pow(T); \ |
57 |
| - _sus__unsigned_log(T); \ |
| 39 | +#define _sus__unsigned_impl(T, Bytes, SignedT, LargerT) \ |
| 40 | + _sus__unsigned_from(T); \ |
| 41 | + _sus__unsigned_integer_comparison(T); \ |
| 42 | + _sus__unsigned_unary_ops(T); \ |
| 43 | + _sus__unsigned_binary_logic_ops(T); \ |
| 44 | + _sus__unsigned_binary_bit_ops(T); \ |
| 45 | + _sus__unsigned_mutable_logic_ops(T); \ |
| 46 | + _sus__unsigned_mutable_bit_ops(T); \ |
| 47 | + _sus__unsigned_abs(T); \ |
| 48 | + _sus__unsigned_add(T, SignedT); \ |
| 49 | + _sus__unsigned_div(T); \ |
| 50 | + _sus__unsigned_mul(T, LargerT); \ |
| 51 | + _sus__unsigned_neg(T); \ |
| 52 | + _sus__unsigned_rem(T); \ |
| 53 | + _sus__unsigned_shift(T); \ |
| 54 | + _sus__unsigned_sub(T); \ |
| 55 | + _sus__unsigned_bits(T); \ |
| 56 | + _sus__unsigned_pow(T); \ |
| 57 | + _sus__unsigned_log(T); \ |
58 | 58 | _sus__unsigned_endian(T, Bytes)
|
59 | 59 |
|
60 | 60 | #define _sus__unsigned_from(T) \
|
|
248 | 248 | } \
|
249 | 249 | static_assert(true)
|
250 | 250 |
|
251 |
| -#define _sus__unsigned_add(T) \ |
| 251 | +#define _sus__unsigned_add(T, SignedT) \ |
252 | 252 | /** Checked integer addition. Computes self + rhs, returning None if \
|
253 | 253 | * overflow occurred. \
|
254 | 254 | */ \
|
|
261 | 261 | return Option<T>::none(); \
|
262 | 262 | } \
|
263 | 263 | \
|
| 264 | + /** Checked integer addition with an unsigned rhs. Computes self + rhs, \ |
| 265 | + * returning None if overflow occurred. \ |
| 266 | + */ \ |
| 267 | + template <std::same_as<SignedT> S> \ |
| 268 | + constexpr Option<T> checked_add_signed(const S& rhs) const& noexcept { \ |
| 269 | + const auto out = __private::add_with_overflow_signed(primitive_value, \ |
| 270 | + rhs.primitive_value); \ |
| 271 | + if (!out.overflow) [[likely]] \ |
| 272 | + return Option<T>::some(out.value); \ |
| 273 | + else \ |
| 274 | + return Option<T>::none(); \ |
| 275 | + } \ |
| 276 | + \ |
264 | 277 | /** Calculates self + rhs \
|
265 | 278 | * \
|
266 | 279 | * Returns a tuple of the addition along with a boolean indicating whether \
|
|
273 | 286 | return Tuple<T, bool>::with(out.value, out.overflow); \
|
274 | 287 | } \
|
275 | 288 | \
|
| 289 | + /** Calculates self + rhs with an unsigned rhs \ |
| 290 | + * \ |
| 291 | + * Returns a tuple of the addition along with a boolean indicating whether \ |
| 292 | + * an arithmetic overflow would occur. If an overflow would have occurred \ |
| 293 | + * then the wrapped value is returned. \ |
| 294 | + */ \ |
| 295 | + template <std::same_as<SignedT> S> \ |
| 296 | + constexpr Tuple<T, bool> overflowing_add_signed(const S& rhs) \ |
| 297 | + const& noexcept { \ |
| 298 | + const auto r = __private::add_with_overflow_signed(primitive_value, \ |
| 299 | + rhs.primitive_value); \ |
| 300 | + return Tuple<T, bool>::with(r.value, r.overflow); \ |
| 301 | + } \ |
| 302 | + \ |
276 | 303 | /** Saturating integer addition. Computes self + rhs, saturating at the \
|
277 | 304 | * numeric bounds instead of overflowing. \
|
278 | 305 | */ \
|
279 | 306 | constexpr T saturating_add(const T& rhs) const& noexcept { \
|
280 | 307 | return __private::saturating_add(primitive_value, rhs.primitive_value); \
|
281 | 308 | } \
|
282 | 309 | \
|
| 310 | + /** Saturating integer addition with an unsigned rhs. Computes self + rhs, \ |
| 311 | + * saturating at the numeric bounds instead of overflowing. \ |
| 312 | + */ \ |
| 313 | + template <std::same_as<SignedT> S> \ |
| 314 | + constexpr T saturating_add_signed(const S& rhs) const& noexcept { \ |
| 315 | + const auto r = __private::add_with_overflow_signed(primitive_value, \ |
| 316 | + rhs.primitive_value); \ |
| 317 | + if (!r.overflow) [[likely]] \ |
| 318 | + return r.value; \ |
| 319 | + else { \ |
| 320 | + /* TODO: Can this be done without a branch? If it's complex or uses \ |
| 321 | + * compiler stuff, move into intrinsics. */ \ |
| 322 | + if (rhs.primitive_value >= 0) \ |
| 323 | + return MAX(); \ |
| 324 | + else \ |
| 325 | + return MIN(); \ |
| 326 | + } \ |
| 327 | + } \ |
| 328 | + \ |
283 | 329 | /** Unchecked integer addition. Computes self + rhs, assuming overflow \
|
284 | 330 | * cannot occur. \
|
285 | 331 | * \
|
|
298 | 344 | */ \
|
299 | 345 | constexpr T wrapping_add(const T& rhs) const& noexcept { \
|
300 | 346 | return __private::wrapping_add(primitive_value, rhs.primitive_value); \
|
| 347 | + } \ |
| 348 | + \ |
| 349 | + /** Wrapping (modular) addition with an unsigned rhs. Computes self + rhs, \ |
| 350 | + * wrapping around at the boundary of the type. \ |
| 351 | + */ \ |
| 352 | + template <std::same_as<SignedT> S> \ |
| 353 | + constexpr T wrapping_add_signed(const S& rhs) const& noexcept { \ |
| 354 | + return __private::add_with_overflow_signed(primitive_value, \ |
| 355 | + rhs.primitive_value) \ |
| 356 | + .value; \ |
301 | 357 | } \
|
302 | 358 | static_assert(true)
|
303 | 359 |
|
|
0 commit comments