Skip to content

Commit 6e3806e

Browse files
committed
Add all signed addition with unsigned values
1 parent e89ae4c commit 6e3806e

File tree

2 files changed

+104
-20
lines changed

2 files changed

+104
-20
lines changed

num/__private/signed_integer_macros.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,19 @@
390390
return Option<T>::none(); \
391391
} \
392392
\
393+
/** Checked integer addition with an unsigned rhs. Computes self + rhs, \
394+
* returning None if overflow occurred. \
395+
*/ \
396+
constexpr Option<T> checked_add_unsigned(const UnsignedT& rhs) \
397+
const& noexcept { \
398+
const auto out = \
399+
__private::add_with_overflow_unsigned(primitive_value, rhs); \
400+
if (!out.overflow) [[likely]] \
401+
return Option<T>::some(out.value); \
402+
else \
403+
return Option<T>::none(); \
404+
} \
405+
\
393406
/** Calculates self + rhs \
394407
* \
395408
* Returns a tuple of the addition along with a boolean indicating whether \
@@ -422,6 +435,18 @@
422435
return __private::saturating_add(primitive_value, rhs.primitive_value); \
423436
} \
424437
\
438+
/** Saturating integer addition with an unsigned rhs. Computes self + rhs, \
439+
* saturating at the numeric bounds instead of overflowing. \
440+
*/ \
441+
constexpr T saturating_add_unsigned(const UnsignedT& rhs) const& noexcept { \
442+
const auto r = \
443+
__private::add_with_overflow_unsigned(primitive_value, rhs); \
444+
if (!r.overflow) [[likely]] \
445+
return r.value; \
446+
else \
447+
return MAX(); \
448+
} \
449+
\
425450
/** Unchecked integer addition. Computes self + rhs, assuming overflow \
426451
* cannot occur. \
427452
* \
@@ -439,6 +464,13 @@
439464
*/ \
440465
constexpr T wrapping_add(const T& rhs) const& noexcept { \
441466
return __private::wrapping_add(primitive_value, rhs.primitive_value); \
467+
} \
468+
\
469+
/** Wrapping (modular) addition with an unsigned rhs. Computes self + rhs, \
470+
* wrapping around at the boundary of the type. \
471+
*/ \
472+
constexpr T wrapping_add_unsigned(const UnsignedT& rhs) const& noexcept { \
473+
return __private::add_with_overflow_unsigned(primitive_value, rhs).value; \
442474
} \
443475
static_assert(true)
444476

num/i32_unittest.cc

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -413,26 +413,6 @@ TEST(i32, OverflowingAdd) {
413413
(Tuple<i32, bool>::with(0_i32, true)));
414414
}
415415

416-
// ** Signed only.
417-
TEST(i32, OverflowingAddUnsigned) {
418-
constexpr auto a = (1_i32).overflowing_add_unsigned(3u);
419-
EXPECT_EQ(a, (Tuple<i32, bool>::with(4_i32, false)));
420-
421-
EXPECT_EQ((-1_i32).overflowing_add_unsigned(2u),
422-
(Tuple<i32, bool>::with(1_i32, false)));
423-
EXPECT_EQ(
424-
(i32::MIN()).overflowing_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
425-
(Tuple<i32, bool>::with(i32::MAX(), false)));
426-
EXPECT_EQ((i32::MIN() + 1_i32)
427-
.overflowing_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
428-
(Tuple<i32, bool>::with(i32::MIN(), true)));
429-
EXPECT_EQ((i32::MIN() + 1_i32)
430-
.overflowing_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
431-
(Tuple<i32, bool>::with(i32::MAX(), false)));
432-
EXPECT_EQ((i32::MAX() - 2_i32).overflowing_add_unsigned(3u),
433-
(Tuple<i32, bool>::with(i32::MIN(), true)));
434-
}
435-
436416
TEST(i32, SaturatingAdd) {
437417
constexpr auto a = (1_i32).saturating_add(3_i32);
438418
EXPECT_EQ(a, 4_i32);
@@ -1899,6 +1879,78 @@ TEST(i32, ToNeBytes) {
18991879
}
19001880
}
19011881

1882+
// ** Signed only.
1883+
TEST(i32, CheckedAddUnsigned) {
1884+
constexpr auto a = (1_i32).checked_add_unsigned(3u);
1885+
EXPECT_EQ(a, Option<i32>::some(4_i32));
1886+
1887+
EXPECT_EQ((-1_i32).checked_add_unsigned(2u), Option<i32>::some(1_i32));
1888+
EXPECT_EQ((i32::MIN()).checked_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1889+
Option<i32>::some(i32::MAX()));
1890+
EXPECT_EQ((i32::MIN() + 1_i32)
1891+
.checked_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1892+
None);
1893+
EXPECT_EQ((i32::MIN() + 1_i32)
1894+
.checked_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
1895+
Option<i32>::some(i32::MAX()));
1896+
EXPECT_EQ((i32::MAX() - 2_i32).checked_add_unsigned(3u), None);
1897+
}
1898+
1899+
// ** Signed only.
1900+
TEST(i32, OverflowingAddUnsigned) {
1901+
constexpr auto a = (1_i32).overflowing_add_unsigned(3u);
1902+
EXPECT_EQ(a, (Tuple<i32, bool>::with(4_i32, false)));
1903+
1904+
EXPECT_EQ((-1_i32).overflowing_add_unsigned(2u),
1905+
(Tuple<i32, bool>::with(1_i32, false)));
1906+
EXPECT_EQ(
1907+
(i32::MIN()).overflowing_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1908+
(Tuple<i32, bool>::with(i32::MAX(), false)));
1909+
EXPECT_EQ((i32::MIN() + 1_i32)
1910+
.overflowing_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1911+
(Tuple<i32, bool>::with(i32::MIN(), true)));
1912+
EXPECT_EQ((i32::MIN() + 1_i32)
1913+
.overflowing_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
1914+
(Tuple<i32, bool>::with(i32::MAX(), false)));
1915+
EXPECT_EQ((i32::MAX() - 2_i32).overflowing_add_unsigned(3u),
1916+
(Tuple<i32, bool>::with(i32::MIN(), true)));
1917+
}
1918+
1919+
// ** Signed only.
1920+
TEST(i32, SaturatingAddUnsigned) {
1921+
constexpr auto a = (1_i32).saturating_add_unsigned(3u);
1922+
EXPECT_EQ(a, 4_i32);
1923+
1924+
EXPECT_EQ((-1_i32).saturating_add_unsigned(2u), 1_i32);
1925+
EXPECT_EQ(
1926+
(i32::MIN()).saturating_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1927+
i32::MAX());
1928+
EXPECT_EQ((i32::MIN() + 1_i32)
1929+
.saturating_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1930+
i32::MAX());
1931+
EXPECT_EQ((i32::MIN() + 1_i32)
1932+
.saturating_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
1933+
i32::MAX());
1934+
EXPECT_EQ((i32::MAX() - 2_i32).saturating_add_unsigned(3u), i32::MAX());
1935+
}
1936+
1937+
// ** Signed only.
1938+
TEST(i32, WrappingAddUnsigned) {
1939+
constexpr auto a = (1_i32).wrapping_add_unsigned(3u);
1940+
EXPECT_EQ(a, 4_i32);
1941+
1942+
EXPECT_EQ((-1_i32).wrapping_add_unsigned(2u), 1_i32);
1943+
EXPECT_EQ((i32::MIN()).wrapping_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1944+
i32::MAX());
1945+
EXPECT_EQ((i32::MIN() + 1_i32)
1946+
.wrapping_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1947+
i32::MIN());
1948+
EXPECT_EQ((i32::MIN() + 1_i32)
1949+
.wrapping_add_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
1950+
i32::MAX());
1951+
EXPECT_EQ((i32::MAX() - 2_i32).wrapping_add_unsigned(3u), i32::MIN());
1952+
}
1953+
19021954
TEST(i32, From) {
19031955
static_assert(sus::concepts::from::From<i32, u32>);
19041956

0 commit comments

Comments
 (0)