Skip to content

Commit 0c82bca

Browse files
committed
Add all signed subtraction with unsigned values
1 parent 0108268 commit 0c82bca

File tree

2 files changed

+102
-20
lines changed

2 files changed

+102
-20
lines changed

num/__private/signed_integer_macros.h

+30-1
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,17 @@
805805
return Option<T>::none(); \
806806
} \
807807
\
808+
/** Checked integer subtraction with an unsigned rhs. Computes self - rhs, \
809+
* returning None if overflow occurred. \
810+
*/ \
811+
constexpr Option<T> checked_sub_unsigned(const UnsignedT& rhs) const& { \
812+
auto out = __private::sub_with_overflow_unsigned(primitive_value, rhs); \
813+
if (!out.overflow) [[likely]] \
814+
return Option<T>::some(out.value); \
815+
else \
816+
return Option<T>::none(); \
817+
} \
818+
\
808819
/** Calculates self - rhs \
809820
* \
810821
* Returns a tuple of the subtraction along with a boolean indicating \
@@ -817,7 +828,7 @@
817828
return Tuple<T, bool>::with(r.value, r.overflow); \
818829
} \
819830
\
820-
/** Calculates self - rhs \
831+
/** Calculates self - rhs with an unsigned rhs. \
821832
* \
822833
* Returns a tuple of the subtraction along with a boolean indicating \
823834
* whether an arithmetic overflow would occur. If an overflow would have \
@@ -836,6 +847,17 @@
836847
return __private::saturating_sub(primitive_value, rhs.primitive_value); \
837848
} \
838849
\
850+
/** Saturating integer subtraction with an unsigned rhs. Computes self - \
851+
* rhs, saturating at the numeric bounds instead of overflowing. \
852+
*/ \
853+
constexpr T saturating_sub_unsigned(const UnsignedT& rhs) const& { \
854+
auto r = __private::sub_with_overflow_unsigned(primitive_value, rhs); \
855+
if (!r.overflow) [[likely]] \
856+
return r.value; \
857+
else \
858+
return MIN(); \
859+
} \
860+
\
839861
/** Unchecked integer subtraction. Computes self - rhs, assuming overflow \
840862
* cannot occur. \
841863
*/ \
@@ -849,6 +871,13 @@
849871
*/ \
850872
constexpr T wrapping_sub(const T& rhs) const& { \
851873
return __private::wrapping_sub(primitive_value, rhs.primitive_value); \
874+
} \
875+
\
876+
/** Wrapping (modular) subtraction with an unsigned rhs. Computes self - \
877+
* rhs, wrapping around at the boundary of the type. \
878+
*/ \
879+
constexpr T wrapping_sub_unsigned(const UnsignedT& rhs) const& { \
880+
return __private::sub_with_overflow_unsigned(primitive_value, rhs).value; \
852881
} \
853882
static_assert(true)
854883

num/i32_unittest.cc

+72-19
Original file line numberDiff line numberDiff line change
@@ -1216,25 +1216,6 @@ TEST(i32, OverflowingSub) {
12161216
(Tuple<i32, bool>::with(i32::MIN(), true)));
12171217
}
12181218

1219-
// ** Signed only.
1220-
TEST(i32, OverflowingSubUnsigned) {
1221-
[[maybe_unused]] constexpr auto a = (-1_i32).overflowing_sub_unsigned(3u);
1222-
1223-
EXPECT_EQ((1_i32).overflowing_sub_unsigned(2u),
1224-
(Tuple<i32, bool>::with(-1_i32, false)));
1225-
EXPECT_EQ(
1226-
(i32::MAX()).overflowing_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1227-
(Tuple<i32, bool>::with(i32::MIN(), false)));
1228-
EXPECT_EQ((i32::MAX() - 1_i32)
1229-
.overflowing_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1230-
(Tuple<i32, bool>::with(i32::MAX(), true)));
1231-
EXPECT_EQ((i32::MAX() - 1_i32)
1232-
.overflowing_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
1233-
(Tuple<i32, bool>::with(i32::MIN(), false)));
1234-
EXPECT_EQ((i32::MIN() + 2_i32).overflowing_sub_unsigned(3u),
1235-
(Tuple<i32, bool>::with(i32::MAX(), true)));
1236-
}
1237-
12381219
TEST(i32, SaturatingSub) {
12391220
constexpr auto a = (5_i32).saturating_sub(3_i32);
12401221
EXPECT_EQ(a, 2_i32);
@@ -1951,6 +1932,78 @@ TEST(i32, WrappingAddUnsigned) {
19511932
EXPECT_EQ((i32::MAX() - 2_i32).wrapping_add_unsigned(3u), i32::MIN());
19521933
}
19531934

1935+
// ** Signed only.
1936+
TEST(i32, CheckedSubUnsigned) {
1937+
constexpr auto a = (1_i32).checked_sub_unsigned(3u);
1938+
EXPECT_EQ(a, Option<i32>::some(-2_i32));
1939+
1940+
EXPECT_EQ((-1_i32).checked_sub_unsigned(2u), Option<i32>::some(-3_i32));
1941+
EXPECT_EQ((i32::MAX()).checked_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1942+
Option<i32>::some(i32::MIN()));
1943+
EXPECT_EQ((i32::MAX() - 1_i32)
1944+
.checked_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1945+
None);
1946+
EXPECT_EQ((i32::MAX() - 1_i32)
1947+
.checked_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
1948+
Option<i32>::some(i32::MIN()));
1949+
EXPECT_EQ((i32::MIN() + 2_i32).checked_sub_unsigned(3u), None);
1950+
}
1951+
1952+
// ** Signed only.
1953+
TEST(i32, OverflowingSubUnsigned) {
1954+
constexpr auto a = (1_i32).overflowing_sub_unsigned(3u);
1955+
EXPECT_EQ(a, (Tuple<i32, bool>::with(-2_i32, false)));
1956+
1957+
EXPECT_EQ((-1_i32).overflowing_sub_unsigned(2u),
1958+
(Tuple<i32, bool>::with(-3_i32, false)));
1959+
EXPECT_EQ(
1960+
(i32::MAX()).overflowing_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1961+
(Tuple<i32, bool>::with(i32::MIN(), false)));
1962+
EXPECT_EQ((i32::MAX() - 1_i32)
1963+
.overflowing_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1964+
(Tuple<i32, bool>::with(i32::MAX(), true)));
1965+
EXPECT_EQ((i32::MAX() - 1_i32)
1966+
.overflowing_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
1967+
(Tuple<i32, bool>::with(i32::MIN(), false)));
1968+
EXPECT_EQ((i32::MIN() + 2_i32).overflowing_sub_unsigned(3u),
1969+
(Tuple<i32, bool>::with(i32::MAX(), true)));
1970+
}
1971+
1972+
// ** Signed only.
1973+
TEST(i32, SaturatingSubUnsigned) {
1974+
constexpr auto a = (1_i32).saturating_sub_unsigned(3u);
1975+
EXPECT_EQ(a, -2_i32);
1976+
1977+
EXPECT_EQ((-1_i32).saturating_sub_unsigned(2u), -3_i32);
1978+
EXPECT_EQ(
1979+
(i32::MAX()).saturating_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1980+
i32::MIN());
1981+
EXPECT_EQ((i32::MAX() - 1_i32)
1982+
.saturating_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1983+
i32::MIN());
1984+
EXPECT_EQ((i32::MAX() - 1_i32)
1985+
.saturating_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
1986+
i32::MIN());
1987+
EXPECT_EQ((i32::MIN() + 2_i32).saturating_sub_unsigned(3u), i32::MIN());
1988+
}
1989+
1990+
// ** Signed only.
1991+
TEST(i32, WrappingSubUnsigned) {
1992+
constexpr auto a = (1_i32).wrapping_sub_unsigned(3u);
1993+
EXPECT_EQ(a, -2_i32);
1994+
1995+
EXPECT_EQ((-1_i32).wrapping_sub_unsigned(2u), -3_i32);
1996+
EXPECT_EQ((i32::MAX()).wrapping_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
1997+
i32::MIN());
1998+
EXPECT_EQ((i32::MAX() - 1_i32)
1999+
.wrapping_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX),
2000+
i32::MAX());
2001+
EXPECT_EQ((i32::MAX() - 1_i32)
2002+
.wrapping_sub_unsigned(/* TODO: u32::MAX() */ UINT_MAX - 1),
2003+
i32::MIN());
2004+
EXPECT_EQ((i32::MIN() + 2_i32).wrapping_sub_unsigned(3u), i32::MAX());
2005+
}
2006+
19542007
TEST(i32, From) {
19552008
static_assert(sus::concepts::from::From<i32, u32>);
19562009

0 commit comments

Comments
 (0)