72 #include <type_traits>
111 template <typename T>
112 constexpr
Uint128(T v) noexcept;
120 explicit
Uint128(uint64_t high, uint64_t low) noexcept;
122 #if defined(__SIZEOF_INT128__)
131 explicit operator __uint128_t() const noexcept;
267 Uint128 operator<<(
int shift) const noexcept;
278 Uint128 operator>>(
int shift) const noexcept;
310 Uint128& operator<<=(
int shift) noexcept;
318 Uint128& operator>>=(
int shift) noexcept;
326 [[nodiscard]]
bool operator==(const
Uint128& other) const noexcept;
334 [[nodiscard]]
bool operator!=(const
Uint128& other) const noexcept;
345 [[nodiscard]]
bool operator<(const
Uint128& other) const noexcept;
353 [[nodiscard]]
bool operator>(const
Uint128& other) const noexcept;
361 [[nodiscard]]
bool operator<=(const
Uint128& other) const noexcept;
369 [[nodiscard]]
bool operator>=(const
Uint128& other) const noexcept;
376 Uint128& operator++() noexcept;
383 Uint128 operator++(
int) noexcept;
390 Uint128& operator--() noexcept;
397 Uint128 operator--(
int) noexcept;
404 [[nodiscard]] uint64_t
get_high() const noexcept;
411 [[nodiscard]] uint64_t
get_low() const noexcept;
425 VLINK_EXPORT static
void mul_64_128(uint64_t a, uint64_t b, uint64_t& hi, uint64_t& lo) noexcept;
427 VLINK_EXPORT static uint64_t add64_carry(uint64_t a, uint64_t b, uint64_t& carry_out) noexcept;
429 VLINK_EXPORT static
void add_128_with64(uint64_t& high, uint64_t& low, uint64_t add_low,
430 uint64_t add_high = 0) noexcept;
451 #if defined(__SIZEOF_INT128__)
452 inline Uint128::operator __uint128_t() const noexcept {
return (
static_cast<__uint128_t
>(high_) << 64) | low_; }
481 uint64_t old_low = low_;
485 uint64_t carry = (low_ < old_low) ? 1 : 0;
487 high_ += other.high_ + carry;
493 uint64_t borrow = (low_ < other.low_) ? 1 : 0;
496 high_ = high_ - other.high_ - borrow;
502 #if defined(__SIZEOF_INT128__)
503 __uint128_t lhs = (
static_cast<__uint128_t
>(high_) << 64) | low_;
504 __uint128_t rhs = (
static_cast<__uint128_t
>(other.high_) << 64) | other.low_;
505 __uint128_t res = lhs * rhs;
507 high_ =
static_cast<uint64_t
>(res >> 64);
508 low_ =
static_cast<uint64_t
>(res);
510 Uint128 r = mul_u128_fallback(*
this, other);
519 auto qr = u128_divmod(*
this, other);
521 high_ = qr.first.high_;
522 low_ = qr.first.low_;
528 auto qr = u128_divmod(*
this, other);
530 high_ = qr.second.high_;
531 low_ = qr.second.low_;
537 return Uint128(high_ | other.high_, low_ | other.low_);
541 return Uint128(high_ & other.high_, low_ & other.low_);
545 return Uint128(high_ ^ other.high_, low_ ^ other.low_);
560 return Uint128(low_ << (shift - 64), 0);
563 uint64_t new_high = (high_ << shift) | (low_ >> (64 - shift));
564 uint64_t new_low = low_ << shift;
566 return Uint128(new_high, new_low);
579 return Uint128(0, high_ >> (shift - 64));
582 uint64_t new_low = (low_ >> shift) | (high_ << (64 - shift));
583 uint64_t new_high = high_ >> shift;
585 return Uint128(new_high, new_low);
589 high_ |= other.high_;
596 high_ &= other.high_;
603 high_ ^= other.high_;
622 high_ = (low_ << (shift - 64));
625 uint64_t nh = (high_ << shift) | (low_ >> (64 - shift));
626 uint64_t nl = low_ << shift;
647 low_ = (high_ >> (shift - 64));
650 uint64_t nl = (low_ >> shift) | (high_ << (64 - shift));
651 uint64_t nh = high_ >> shift;
661 return high_ == other.high_ && low_ == other.low_;
667 return (high_ < other.high_) || (high_ == other.high_ && low_ < other.low_);
677 uint64_t old_low = low_;
681 if (low_ < old_low) {
697 uint64_t old_low = low_;
719 template <
typename T>
723 #if defined(__SIZEOF_INT128__)
724 if constexpr (std::is_same_v<__uint128_t, T>) {
725 high_ =
static_cast<uint64_t
>(v >> 64);
726 low_ =
static_cast<uint64_t
>(v);
732 if constexpr (std::is_constructible_v<uint64_t, T>) {
733 if constexpr (std::is_signed_v<T>) {
734 high_ = (v < 0) ? ~uint64_t{0} : uint64_t{0};
735 low_ =
static_cast<uint64_t
>(
static_cast<int64_t
>(v));
128-bit unsigned integer represented as two 64-bit halves with full operator support.
Definition: uint128.h:88
Uint128 operator>>(int shift) const noexcept
Returns *this shifted right by shift bits (logical, zero-fill).
Definition: uint128.h:569
Uint128 & operator*=(const Uint128 &other) noexcept
Multiplies *this by other in-place.
Definition: uint128.h:501
Uint128 operator-(const Uint128 &other) const noexcept
Returns the difference of *this and other.
Definition: uint128.h:462
bool operator<(const Uint128 &other) const noexcept
Returns true when *this is strictly less than other.
Definition: uint128.h:666
Uint128 operator+(const Uint128 &other) const noexcept
Returns the sum of *this and other.
Definition: uint128.h:455
Uint128 & operator--() noexcept
Pre-decrement with borrow across the 64-bit boundary.
Definition: uint128.h:696
Uint128 & operator|=(const Uint128 &other) noexcept
Applies bitwise OR with other in-place.
Definition: uint128.h:588
uint64_t get_low() const noexcept
Returns the lower 64 bits of the stored value.
Definition: uint128.h:717
Uint128 & operator%=(const Uint128 &other)
Computes *this modulo other in-place.
Definition: uint128.h:527
bool operator!=(const Uint128 &other) const noexcept
Returns true when any half differs.
Definition: uint128.h:664
Uint128 operator/(const Uint128 &other) const
Returns the quotient of *this divided by other.
Definition: uint128.h:476
Uint128 & operator-=(const Uint128 &other) noexcept
Subtracts other from *this in-place with borrow propagation.
Definition: uint128.h:492
Uint128 & operator+=(const Uint128 &other) noexcept
Adds other to *this in-place with carry propagation.
Definition: uint128.h:480
bool operator>=(const Uint128 &other) const noexcept
Returns true when *this is greater than or equal to other.
Definition: uint128.h:674
Uint128 operator*(const Uint128 &other) const noexcept
Returns the product of *this and other.
Definition: uint128.h:469
bool operator==(const Uint128 &other) const noexcept
Returns true when both halves of *this and other are equal.
Definition: uint128.h:660
Uint128 & operator>>=(int shift) noexcept
Shifts *this right by shift bits in-place (logical, zero-fill).
Definition: uint128.h:635
Uint128 operator%(const Uint128 &other) const
Returns the remainder of *this divided by other.
Definition: uint128.h:478
uint64_t get_high() const noexcept
Returns the upper 64 bits of the stored value.
Definition: uint128.h:715
Uint128 operator&(const Uint128 &other) const noexcept
Returns the bitwise AND of *this and other.
Definition: uint128.h:540
bool operator<=(const Uint128 &other) const noexcept
Returns true when *this is less than or equal to other.
Definition: uint128.h:672
Uint128 & operator/=(const Uint128 &other)
Divides *this by other in-place.
Definition: uint128.h:518
Uint128 operator~() const noexcept
Returns the bitwise complement of *this.
Definition: uint128.h:548
Uint128 operator<<(int shift) const noexcept
Returns *this shifted left by shift bits.
Definition: uint128.h:550
Uint128 & operator++() noexcept
Pre-increment with carry across the 64-bit boundary.
Definition: uint128.h:676
Uint128 & operator^=(const Uint128 &other) noexcept
Applies bitwise XOR with other in-place.
Definition: uint128.h:602
bool operator>(const Uint128 &other) const noexcept
Returns true when *this is strictly greater than other.
Definition: uint128.h:670
Uint128 operator^(const Uint128 &other) const noexcept
Returns the bitwise XOR of *this and other.
Definition: uint128.h:544
Uint128 & operator&=(const Uint128 &other) noexcept
Applies bitwise AND with other in-place.
Definition: uint128.h:595
Uint128 & operator<<=(int shift) noexcept
Shifts *this left by shift bits in-place.
Definition: uint128.h:609
Uint128() noexcept=default
Default-constructs a zero-valued Uint128.
Uint128 operator|(const Uint128 &other) const noexcept
Returns the bitwise OR of *this and other.
Definition: uint128.h:536
Cross-platform macros for visibility, branch hints, copy prevention, singletons and string helpers.
#define VLINK_EXPORT
Definition: macros.h:81
VLINK_EXPORT size_t operator()(const vlink::Uint128 &value) const noexcept
Hashes value into a size_t.