3#include <tess/core/assert.h>
9namespace tess::detail {
24 constexpr UInt128() noexcept = default;
32 requires std::unsigned_integral<T>
34 constexpr UInt128(T value) noexcept : lo(value) {}
38 constexpr UInt128(
int value) noexcept
39 : lo((TESS_ASSERT(value >= 0),
static_cast<std::uint64_t
>(value))) {}
41 [[nodiscard]]
static constexpr auto from_parts(std::uint64_t high,
42 std::uint64_t low)
noexcept
44 auto result = UInt128{};
50 [[nodiscard]]
explicit constexpr operator std::uint64_t() const noexcept {
54 friend constexpr auto operator==(UInt128 lhs, UInt128 rhs)
noexcept
56 friend constexpr auto operator<=>(UInt128 lhs, UInt128 rhs)
noexcept
57 -> std::strong_ordering =
default;
59 friend constexpr auto operator*(UInt128 lhs, UInt128 rhs)
noexcept
61 const std::uint64_t mask32 = 0xffffffffULL;
62 const std::uint64_t a_lo = lhs.lo & mask32;
63 const std::uint64_t a_hi = lhs.lo >> 32U;
64 const std::uint64_t b_lo = rhs.lo & mask32;
65 const std::uint64_t b_hi = rhs.lo >> 32U;
68 const std::uint64_t p0 = a_lo * b_lo;
69 const std::uint64_t p1 = a_lo * b_hi;
70 const std::uint64_t p2 = a_hi * b_lo;
71 const std::uint64_t p3 = a_hi * b_hi;
73 const std::uint64_t mid = p1 + (p0 >> 32U);
74 const std::uint64_t mid2 = p2 + (mid & mask32);
76 const std::uint64_t low = (mid2 << 32U) | (p0 & mask32);
77 std::uint64_t high = p3 + (mid >> 32U) + (mid2 >> 32U);
80 high += lhs.hi * rhs.lo + lhs.lo * rhs.hi;
81 return from_parts(high, low);
84 friend constexpr auto operator-(UInt128 lhs, UInt128 rhs)
noexcept
86 const std::uint64_t borrow = lhs.lo < rhs.lo ? 1U : 0U;
87 return from_parts(lhs.hi - rhs.hi - borrow, lhs.lo - rhs.lo);
90 friend constexpr auto operator&(UInt128 lhs, UInt128 rhs)
noexcept
92 return from_parts(lhs.hi & rhs.hi, lhs.lo & rhs.lo);
95 friend constexpr auto operator|(UInt128 lhs, UInt128 rhs)
noexcept
97 return from_parts(lhs.hi | rhs.hi, lhs.lo | rhs.lo);
100 friend constexpr auto operator<<(UInt128 value, std::uint32_t count)
noexcept
109 return from_parts(value.lo << (count - 64U), 0U);
111 return from_parts((value.hi << count) | (value.lo >> (64U - count)),
115 friend constexpr auto operator>>(UInt128 value, std::uint32_t count)
noexcept
124 return from_parts(0U, value.hi >> (count - 64U));
126 return from_parts(value.hi >> count,
127 (value.lo >> count) | (value.hi << (64U - count)));
130 constexpr auto operator<<=(std::uint32_t count)
noexcept -> UInt128& {
131 *
this = *
this << count;
135 constexpr auto operator>>=(std::uint32_t count)
noexcept -> UInt128& {
136 *
this = *
this >> count;