Skip to content

Commit dcdd6a8

Browse files
committed
Add div_ceil() for unsigned integers.
These were stabilized in Rust 1.73. https://blog.rust-lang.org/2023/10/05/Rust-1.73.0.html Part of #221.
1 parent 51ed5a4 commit dcdd6a8

13 files changed

+186
-0
lines changed

sus/num/__private/unsigned_integer_methods.inc

+30
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,36 @@ sus_pure constexpr _self wrapping_rem(U rhs) const& noexcept {
16291629
}
16301630
#endif
16311631

1632+
/// Calculates the quotient of itself and `rhs`, rounding the result towards
1633+
/// positive infinity.
1634+
///
1635+
/// # Panics
1636+
/// This function will panic if `rhs` is zero.
1637+
///
1638+
/// # Examples
1639+
/// Basic usage:
1640+
/// ```
1641+
/// assert_eq!((7_u8).div_ceil(4u), 2u);
1642+
/// ```
1643+
sus_pure constexpr _self div_ceil(_self rhs) const& noexcept {
1644+
::sus::check_with_message(rhs.primitive_value != _primitive{0},
1645+
"attempt to divide by zero");
1646+
_self d =
1647+
_self(__private::unchecked_div(primitive_value, rhs.primitive_value));
1648+
_self r =
1649+
_self(__private::unchecked_rem(primitive_value, rhs.primitive_value));
1650+
return (r > _primitive{0}) ? d + _primitive{1} : d;
1651+
}
1652+
1653+
#if _pointer
1654+
template <class U>
1655+
requires((UnsignedNumeric<U> || UnsignedPrimitiveInteger<U>) &&
1656+
::sus::mem::size_of<U>() <= ::sus::mem::size_of<_primitive>())
1657+
sus_pure constexpr _self div_ceil(U rhs) const& noexcept {
1658+
return div_ceil(_self(_primitive{rhs}));
1659+
}
1660+
#endif
1661+
16321662
/// Performs Euclidean division.
16331663
///
16341664
/// Since, for the positive integers, all common definitions of division are

sus/num/u16_overflow_unittest.cc

+17
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,21 @@ TEST(u16OverflowDeathTest, WrappingRemEuclidOverflow) {
251251
#endif
252252
}
253253

254+
TEST(u16OverflowDeathTest, DivCeilDivByZero) {
255+
#if GTEST_HAS_DEATH_TEST
256+
EXPECT_DEATH(
257+
{
258+
auto x = (0_u16).div_ceil(0_u16);
259+
ensure_use(&x);
260+
},
261+
"attempt to divide by zero");
262+
EXPECT_DEATH(
263+
{
264+
auto x = u16::MAX.div_ceil(0_u16);
265+
ensure_use(&x);
266+
},
267+
"attempt to divide by zero");
268+
#endif
269+
}
270+
254271
} // namespace

sus/num/u16_unittest.cc

+2
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,8 @@ TEST(u16, InvokeEverything) {
658658
(void)i.overflowing_rem_euclid(j);
659659
(void)i.wrapping_rem_euclid(j);
660660

661+
(void)i.div_ceil(j);
662+
661663
(void)i.checked_shl(1_u32);
662664
(void)i.overflowing_shl(1_u32);
663665
(void)i.wrapping_shl(1_u32);

sus/num/u32_overflow_unittest.cc

+17
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,21 @@ TEST(u32Overlow, NextPowerOfTwoOutOfBounds) {
256256
EXPECT_EQ(u32::MAX.next_power_of_two(), 0_u32);
257257
}
258258

259+
TEST(u32OverflowDeathTest, DivCeilDivByZero) {
260+
#if GTEST_HAS_DEATH_TEST
261+
EXPECT_DEATH(
262+
{
263+
auto x = (0_u32).div_ceil(0_u32);
264+
ensure_use(&x);
265+
},
266+
"attempt to divide by zero");
267+
EXPECT_DEATH(
268+
{
269+
auto x = u32::MAX.div_ceil(0_u32);
270+
ensure_use(&x);
271+
},
272+
"attempt to divide by zero");
273+
#endif
274+
}
275+
259276
} // namespace

sus/num/u32_unittest.cc

+36
Original file line numberDiff line numberDiff line change
@@ -2168,4 +2168,40 @@ static_assert([] {
21682168
return v.as_mut_ptr() == &v.primitive_value;
21692169
}());
21702170

2171+
TEST(u32, DivCeil) {
2172+
EXPECT_EQ((7_u32).div_ceil(1u), 7u);
2173+
EXPECT_EQ((7_u32).div_ceil(2u), 4u);
2174+
EXPECT_EQ((7_u32).div_ceil(3u), 3u);
2175+
EXPECT_EQ((7_u32).div_ceil(4u), 2u);
2176+
EXPECT_EQ((7_u32).div_ceil(5u), 2u);
2177+
EXPECT_EQ((7_u32).div_ceil(6u), 2u);
2178+
EXPECT_EQ((7_u32).div_ceil(7u), 1u);
2179+
EXPECT_EQ((7_u32).div_ceil(8u), 1u);
2180+
2181+
EXPECT_EQ((6_u32).div_ceil(1u), 6u);
2182+
EXPECT_EQ((6_u32).div_ceil(2u), 3u);
2183+
EXPECT_EQ((6_u32).div_ceil(3u), 2u);
2184+
EXPECT_EQ((6_u32).div_ceil(4u), 2u);
2185+
EXPECT_EQ((6_u32).div_ceil(5u), 2u);
2186+
EXPECT_EQ((6_u32).div_ceil(6u), 1u);
2187+
EXPECT_EQ((6_u32).div_ceil(7u), 1u);
2188+
}
2189+
2190+
TEST(u32DeathTest, DivCeilDivByZero) {
2191+
#if GTEST_HAS_DEATH_TEST
2192+
EXPECT_DEATH(
2193+
{
2194+
auto x = (0_u32).div_ceil(0_u32);
2195+
ensure_use(&x);
2196+
},
2197+
"attempt to divide by zero");
2198+
EXPECT_DEATH(
2199+
{
2200+
auto x = u32::MAX.div_ceil(0_u32);
2201+
ensure_use(&x);
2202+
},
2203+
"attempt to divide by zero");
2204+
#endif
2205+
}
2206+
21712207
} // namespace

sus/num/u64_overflow_unittest.cc

+17
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,21 @@ TEST(u64OverflowDeathTest, WrappingRemEuclidOverflow) {
251251
#endif
252252
}
253253

254+
TEST(u64OverflowDeathTest, DivCeilDivByZero) {
255+
#if GTEST_HAS_DEATH_TEST
256+
EXPECT_DEATH(
257+
{
258+
auto x = (0_u64).div_ceil(0_u64);
259+
ensure_use(&x);
260+
},
261+
"attempt to divide by zero");
262+
EXPECT_DEATH(
263+
{
264+
auto x = u64::MAX.div_ceil(0_u64);
265+
ensure_use(&x);
266+
},
267+
"attempt to divide by zero");
268+
#endif
269+
}
270+
254271
} // namespace

sus/num/u64_unittest.cc

+2
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,8 @@ TEST(u64, InvokeEverything) {
674674
(void)i.overflowing_rem_euclid(j);
675675
(void)i.wrapping_rem_euclid(j);
676676

677+
(void)i.div_ceil(j);
678+
677679
(void)i.checked_shl(1_u32);
678680
(void)i.overflowing_shl(1_u32);
679681
(void)i.wrapping_shl(1_u32);

sus/num/u8_overflow_unittest.cc

+17
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,21 @@ TEST(u8OverflowDeathTest, WrappingRemEuclidOverflow) {
227227
#endif
228228
}
229229

230+
TEST(u8OverflowDeathTest, DivCeilDivByZero) {
231+
#if GTEST_HAS_DEATH_TEST
232+
EXPECT_DEATH(
233+
{
234+
auto x = (0_u8).div_ceil(0_u8);
235+
ensure_use(&x);
236+
},
237+
"attempt to divide by zero");
238+
EXPECT_DEATH(
239+
{
240+
auto x = u8::MAX.div_ceil(0_u8);
241+
ensure_use(&x);
242+
},
243+
"attempt to divide by zero");
244+
#endif
245+
}
246+
230247
} // namespace

sus/num/u8_unittest.cc

+2
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,8 @@ TEST(u8, InvokeEverything) {
652652
(void)i.overflowing_rem_euclid(j);
653653
(void)i.wrapping_rem_euclid(j);
654654

655+
(void)i.div_ceil(j);
656+
655657
(void)i.checked_shl(1_u32);
656658
(void)i.overflowing_shl(1_u32);
657659
(void)i.wrapping_shl(1_u32);

sus/num/uptr_overflow_unittest.cc

+17
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,21 @@ TEST(uptrOverflowDeathTest, WrappingRemEuclidOverflow) {
253253
#endif
254254
}
255255

256+
TEST(uptrOverflowDeathTest, DivCeilDivByZero) {
257+
#if GTEST_HAS_DEATH_TEST
258+
EXPECT_DEATH(
259+
{
260+
auto x = uptr().with_addr(0_usize).div_ceil(0_u32);
261+
ensure_use(&x);
262+
},
263+
"attempt to divide by zero");
264+
EXPECT_DEATH(
265+
{
266+
auto x = uptr::MAX_BIT_PATTERN.div_ceil(0_u64);
267+
ensure_use(&x);
268+
},
269+
"attempt to divide by zero");
270+
#endif
271+
}
272+
256273
} // namespace

sus/num/uptr_unittest.cc

+10
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,8 @@ TEST(uptr, InvokeEverything) {
653653
(void)i.overflowing_rem_euclid(j);
654654
(void)i.wrapping_rem_euclid(j);
655655

656+
(void)i.div_ceil(j);
657+
656658
(void)i.checked_shl(1_u32);
657659
(void)i.overflowing_shl(1_u32);
658660
(void)i.wrapping_shl(1_u32);
@@ -1061,6 +1063,14 @@ TEST(uptr, ArithemticWithSmallerIntegers) {
10611063
EXPECT_EQ(i.wrapping_rem_euclid(p), i.wrapping_rem_euclid(i));
10621064
EXPECT_EQ(i.wrapping_rem_euclid(u), i.wrapping_rem_euclid(i));
10631065

1066+
// Ceil math.
1067+
1068+
static_assert(std::same_as<uptr, decltype(i.div_ceil(i))>);
1069+
static_assert(std::same_as<uptr, decltype(i.div_ceil(p))>);
1070+
static_assert(std::same_as<uptr, decltype(i.div_ceil(u))>);
1071+
EXPECT_EQ(i.div_ceil(p), i.div_ceil(i));
1072+
EXPECT_EQ(i.div_ceil(u), i.div_ceil(i));
1073+
10641074
// Log math.
10651075
static_assert(std::same_as<u32, decltype(i.log(i))>);
10661076
static_assert(std::same_as<u32, decltype(i.log(p))>);

sus/num/usize_overflow_unittest.cc

+17
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,21 @@ TEST(usizeOverflowDeathTest, WrappingRemEuclidOverflow) {
253253
#endif
254254
}
255255

256+
TEST(usizeOverflowDeathTest, DivCeilDivByZero) {
257+
#if GTEST_HAS_DEATH_TEST
258+
EXPECT_DEATH(
259+
{
260+
auto x = (0_usize).div_ceil(0_usize);
261+
ensure_use(&x);
262+
},
263+
"attempt to divide by zero");
264+
EXPECT_DEATH(
265+
{
266+
auto x = usize::MAX.div_ceil(0_usize);
267+
ensure_use(&x);
268+
},
269+
"attempt to divide by zero");
270+
#endif
271+
}
272+
256273
} // namespace

sus/num/usize_unittest.cc

+2
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,8 @@ TEST(usize, InvokeEverything) {
707707
(void)i.overflowing_rem_euclid(j);
708708
(void)i.wrapping_rem_euclid(j);
709709

710+
(void)i.div_ceil(j);
711+
710712
(void)i.checked_shl(1_u32);
711713
(void)i.overflowing_shl(1_u32);
712714
(void)i.wrapping_shl(1_u32);

0 commit comments

Comments
 (0)