40 constexpr UInt128()
noexcept =
default;
48 requires std::unsigned_integral<T>
50 constexpr UInt128(T value) noexcept : lo(value) {}
58 requires std::signed_integral<T>
60 constexpr UInt128(T value) noexcept
61 : lo((TESS_ASSERT(value >= 0),
static_cast<std::uint64_t
>(value))) {}
63 [[nodiscard]]
static constexpr auto from_parts(std::uint64_t high,
64 std::uint64_t low)
noexcept
66 auto result = UInt128{};
72 [[nodiscard]]
explicit constexpr operator std::uint64_t()
const noexcept {
76 friend constexpr auto operator==(UInt128 lhs, UInt128 rhs)
noexcept
78 friend constexpr auto operator<=>(UInt128 lhs, UInt128 rhs)
noexcept
79 -> std::strong_ordering =
default;
81 friend constexpr auto operator*(UInt128 lhs, UInt128 rhs)
noexcept
83 const std::uint64_t mask32 = 0xffffffffULL;
84 const std::uint64_t a_lo = lhs.lo & mask32;
85 const std::uint64_t a_hi = lhs.lo >> 32U;
86 const std::uint64_t b_lo = rhs.lo & mask32;
87 const std::uint64_t b_hi = rhs.lo >> 32U;
90 const std::uint64_t p0 = a_lo * b_lo;
91 const std::uint64_t p1 = a_lo * b_hi;
92 const std::uint64_t p2 = a_hi * b_lo;
93 const std::uint64_t p3 = a_hi * b_hi;
95 const std::uint64_t mid = p1 + (p0 >> 32U);
96 const std::uint64_t mid2 = p2 + (mid & mask32);
98 const std::uint64_t low = (mid2 << 32U) | (p0 & mask32);
99 std::uint64_t high = p3 + (mid >> 32U) + (mid2 >> 32U);
102 high += lhs.hi * rhs.lo + lhs.lo * rhs.hi;
103 return from_parts(high, low);
106 friend constexpr auto operator-(UInt128 lhs, UInt128 rhs)
noexcept
108 const std::uint64_t borrow = lhs.lo < rhs.lo ? 1U : 0U;
109 return from_parts(lhs.hi - rhs.hi - borrow, lhs.lo - rhs.lo);
112 friend constexpr auto operator&(UInt128 lhs, UInt128 rhs)
noexcept
114 return from_parts(lhs.hi & rhs.hi, lhs.lo & rhs.lo);
117 friend constexpr auto operator|(UInt128 lhs, UInt128 rhs)
noexcept
119 return from_parts(lhs.hi | rhs.hi, lhs.lo | rhs.lo);
122 friend constexpr auto operator<<(UInt128 value, std::uint32_t count)
noexcept
131 return from_parts(value.lo << (count - 64U), 0U);
133 return from_parts((value.hi << count) | (value.lo >> (64U - count)),
137 friend constexpr auto operator>>(UInt128 value, std::uint32_t count)
noexcept
146 return from_parts(0U, value.hi >> (count - 64U));
148 return from_parts(value.hi >> count,
149 (value.lo >> count) | (value.hi << (64U - count)));
152 constexpr auto operator<<=(std::uint32_t count)
noexcept -> UInt128& {
153 *
this = *
this << count;
157 constexpr auto operator>>=(std::uint32_t count)
noexcept -> UInt128& {
158 *
this = *
this >> count;