Skip to content

Commit

Permalink
Make remaining simple functions constexpr (#305)
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast authored Aug 4, 2024
1 parent 9196508 commit 6bae23e
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 16 deletions.
35 changes: 19 additions & 16 deletions include/intx/intx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,24 +270,24 @@ inline constexpr uint128 operator-(uint128 x) noexcept
return 0 - x;
}

inline uint128& operator++(uint128& x) noexcept
inline constexpr uint128& operator++(uint128& x) noexcept
{
return x = x + 1;
}

inline uint128& operator--(uint128& x) noexcept
inline constexpr uint128& operator--(uint128& x) noexcept
{
return x = x - 1;
}

inline const uint128 operator++(uint128& x, int) noexcept // NOLINT(readability-const-return-type)
inline constexpr const uint128 operator++(uint128& x, int) noexcept // NOLINT(*-const-return-type)
{
const auto ret = x;
++x;
return ret;
}

inline const uint128 operator--(uint128& x, int) noexcept // NOLINT(readability-const-return-type)
inline constexpr const uint128 operator--(uint128& x, int) noexcept // NOLINT(*-const-return-type)
{
const auto ret = x;
--x;
Expand Down Expand Up @@ -593,6 +593,8 @@ struct div_result
QuotT quot;
RemT rem;

bool operator==(const div_result&) const = default;

/// Conversion to tuple of references, to allow usage with std::tie().
constexpr operator std::tuple<QuotT&, RemT&>() noexcept { return {quot, rem}; }
};
Expand Down Expand Up @@ -627,7 +629,7 @@ constexpr uint16_t reciprocal_table[] = {REPEAT256()};
/// Computes the reciprocal (2^128 - 1) / d - 2^64 for normalized d.
///
/// Based on Algorithm 2 from "Improved division by invariant integers".
inline uint64_t reciprocal_2by1(uint64_t d) noexcept
inline constexpr uint64_t reciprocal_2by1(uint64_t d) noexcept
{
INTX_REQUIRE(d & 0x8000000000000000); // Must be normalized.

Expand All @@ -648,7 +650,7 @@ inline uint64_t reciprocal_2by1(uint64_t d) noexcept
return v4;
}

inline uint64_t reciprocal_3by2(uint128 d) noexcept
inline constexpr uint64_t reciprocal_3by2(uint128 d) noexcept
{
auto v = reciprocal_2by1(d[1]);
auto p = d[1] * v;
Expand Down Expand Up @@ -679,7 +681,7 @@ inline uint64_t reciprocal_3by2(uint128 d) noexcept
return v;
}

inline div_result<uint64_t> udivrem_2by1(uint128 u, uint64_t d, uint64_t v) noexcept
inline constexpr div_result<uint64_t> udivrem_2by1(uint128 u, uint64_t d, uint64_t v) noexcept
{
auto q = umul(v, u[1]);
q = fast_add(q, u);
Expand All @@ -703,7 +705,7 @@ inline div_result<uint64_t> udivrem_2by1(uint128 u, uint64_t d, uint64_t v) noex
return {q[1], r};
}

inline div_result<uint64_t, uint128> udivrem_3by2(
inline constexpr div_result<uint64_t, uint128> udivrem_3by2(
uint64_t u2, uint64_t u1, uint64_t u0, uint128 d, uint64_t v) noexcept
{
auto q = umul(v, u2);
Expand Down Expand Up @@ -733,7 +735,7 @@ inline div_result<uint64_t, uint128> udivrem_3by2(
return {q[1], r};
}

inline div_result<uint128> udivrem(uint128 x, uint128 y) noexcept
inline constexpr div_result<uint128> udivrem(uint128 x, uint128 y) noexcept
{
if (y[1] == 0)
{
Expand Down Expand Up @@ -778,7 +780,7 @@ inline div_result<uint128> udivrem(uint128 x, uint128 y) noexcept
return {res.quot, res.rem >> lsh};
}

inline div_result<uint128> sdivrem(uint128 x, uint128 y) noexcept
inline constexpr div_result<uint128> sdivrem(uint128 x, uint128 y) noexcept
{
constexpr auto sign_mask = uint128{1} << 127;
const auto x_is_neg = (x & sign_mask) != 0;
Expand All @@ -794,22 +796,22 @@ inline div_result<uint128> sdivrem(uint128 x, uint128 y) noexcept
return {q_is_neg ? -res.quot : res.quot, x_is_neg ? -res.rem : res.rem};
}

inline uint128 operator/(uint128 x, uint128 y) noexcept
inline constexpr uint128 operator/(uint128 x, uint128 y) noexcept
{
return udivrem(x, y).quot;
}

inline uint128 operator%(uint128 x, uint128 y) noexcept
inline constexpr uint128 operator%(uint128 x, uint128 y) noexcept
{
return udivrem(x, y).rem;
}

inline uint128& operator/=(uint128& x, uint128 y) noexcept
inline constexpr uint128& operator/=(uint128& x, uint128 y) noexcept
{
return x = x / y;
}

inline uint128& operator%=(uint128& x, uint128 y) noexcept
inline constexpr uint128& operator%=(uint128& x, uint128 y) noexcept
{
return x = x % y;
}
Expand Down Expand Up @@ -1001,8 +1003,9 @@ struct uint

constexpr explicit operator bool() const noexcept { return *this != uint{}; }

/// Explicit converting operator to smaller uint types.
template <unsigned M>
explicit operator uint<M>() const noexcept
constexpr explicit operator uint<M>() const noexcept
requires(M < N)
{
uint<M> r;
Expand All @@ -1013,7 +1016,7 @@ struct uint

/// Explicit converting operator for all builtin integral types.
template <typename Int>
explicit operator Int() const noexcept
constexpr explicit operator Int() const noexcept
requires(std::is_integral_v<Int>)
{
static_assert(sizeof(Int) <= sizeof(uint64_t));
Expand Down
3 changes: 3 additions & 0 deletions test/unittests/test_div.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ inline uint64_t reciprocal_naive(uint64_t d) noexcept

TEST(div, reciprocal)
{
static_assert(reciprocal_2by1(0x8000000000000000) == 0xffffffffffffffff);

constexpr auto n = 1000000;

constexpr auto d_start = uint64_t{1} << 63;
Expand All @@ -466,6 +468,7 @@ TEST(div, reciprocal)
TEST(div, reciprocal_3by2)
{
// Basic inputs for reciprocal_3by2() to make porting to other languages easier.
static_assert(reciprocal_3by2(0x80000000000000000000000000000000_u128) == 0xffffffffffffffff);

EXPECT_EQ(reciprocal_3by2({0x0000000000000000, 0x8000000000000000}), 0xffffffffffffffffu);
EXPECT_EQ(reciprocal_3by2({0x0000000000000001, 0x8000000000000000}), 0xffffffffffffffffu);
Expand Down
34 changes: 34 additions & 0 deletions test/unittests/test_int128.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,26 @@ TEST(int128, mul)

TEST(int128, increment)
{
static_assert([] {
uint128 x;
return ++x;
}() == 1);

static_assert([] {
uint128 x;
return x++;
}() == 0);

static_assert([] {
uint128 x = 1;
return --x;
}() == 0);

static_assert([] {
uint128 x = 1;
return x++;
}() == 1);

constexpr auto IO = uint128{0, 1};
constexpr auto Of = uint128{~uint64_t{0}};

Expand Down Expand Up @@ -307,6 +327,16 @@ TEST(int128, shr)

TEST(int128, div)
{
static_assert(7_u128 / 3_u128 == 2_u128);
static_assert(7_u128 % 3_u128 == 1_u128);
static_assert(udivrem(7, 3) == div_result<uint128>{2, 1});
static_assert(udivrem(0x10000000000000000_u128, 0x20000000000000000_u128) ==
div_result<uint128>{0, 0x10000000000000000_u128});
static_assert(udivrem(0x80000000000000000000000000000002_u128,
0x80000000000000000000000000000000_u128) == div_result<uint128>{1, 2});
static_assert(udivrem(0x70000000000000000_u128, 0x20000000000000000_u128) ==
div_result<uint128>{3, 0x10000000000000000_u128});

int index = 0;
for (const auto& t : div_test_cases)
{
Expand All @@ -326,6 +356,10 @@ TEST(int128, div)

TEST(int128, sdivrem)
{
static_assert(
sdivrem(0x33c7c3442a47d644b0d0b4ca50f8bbe1_u128, 0x5d99de82798cc77d06c05e7aa7c1f54_u128) ==
div_result<uint128>{8, 0x4fad402ed8172862d70858cfd17c141_u128});

const auto x = 0x83017fa6deecda0063b1977_u128;
const auto y = 0x1bc83504ea8f7_u128;

Expand Down
22 changes: 22 additions & 0 deletions test/unittests/test_intx_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,30 @@ TYPED_TEST(uint_api, bitwise_op_assignment)
EXPECT_EQ(x >>= x, 0);
}

TYPED_TEST(uint_api, explicit_conversion_to_smaller_uint)
{
if constexpr (TypeParam::num_bits > 128)
{
using SmallerType = intx::uint<TypeParam::num_bits - 64>;
static_assert(static_cast<SmallerType>(TypeParam{1}) == 1);

TypeParam x;
for (size_t i = 0; i < TypeParam::num_words; ++i)
x[i] = i + 1;

const auto smaller = static_cast<SmallerType>(x);
for (size_t i = 0; i < SmallerType::num_words; ++i)
{
EXPECT_EQ(smaller[i], i + 1);
}
}
}

TYPED_TEST(uint_api, explicit_conversion_to_integral_type)
{
static_assert(
static_cast<uint32_t>(TypeParam{0x0102030405060708, 0xffffffffffffffff}) == 0x05060708);

TypeParam x;
x[0] = 3;
x[1] = 0xffffffffffffffff;
Expand Down

0 comments on commit 6bae23e

Please sign in to comment.