diff options
Diffstat (limited to 'absl/numeric/int128.h')
-rw-r--r-- | absl/numeric/int128.h | 126 |
1 files changed, 78 insertions, 48 deletions
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index bbb76edb4ba9..cfbf74c46689 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h @@ -262,21 +262,50 @@ inline uint128& uint128::operator=(unsigned __int128 v) { } #endif // ABSL_HAVE_INTRINSIC_INT128 -// Shift and arithmetic operators. +// Arithmetic operators. -inline uint128 operator<<(uint128 lhs, int amount) { return lhs <<= amount; } +uint128 operator<<(uint128 lhs, int amount); +uint128 operator>>(uint128 lhs, int amount); +uint128 operator+(uint128 lhs, uint128 rhs); +uint128 operator-(uint128 lhs, uint128 rhs); +uint128 operator*(uint128 lhs, uint128 rhs); +uint128 operator/(uint128 lhs, uint128 rhs); +uint128 operator%(uint128 lhs, uint128 rhs); -inline uint128 operator>>(uint128 lhs, int amount) { return lhs >>= amount; } +inline uint128& uint128::operator<<=(int amount) { + *this = *this << amount; + return *this; +} -inline uint128 operator+(uint128 lhs, uint128 rhs) { return lhs += rhs; } +inline uint128& uint128::operator>>=(int amount) { + *this = *this >> amount; + return *this; +} -inline uint128 operator-(uint128 lhs, uint128 rhs) { return lhs -= rhs; } +inline uint128& uint128::operator+=(uint128 other) { + *this = *this + other; + return *this; +} -inline uint128 operator*(uint128 lhs, uint128 rhs) { return lhs *= rhs; } +inline uint128& uint128::operator-=(uint128 other) { + *this = *this - other; + return *this; +} -inline uint128 operator/(uint128 lhs, uint128 rhs) { return lhs /= rhs; } +inline uint128& uint128::operator*=(uint128 other) { + *this = *this * other; + return *this; +} -inline uint128 operator%(uint128 lhs, uint128 rhs) { return lhs %= rhs; } +inline uint128& uint128::operator/=(uint128 other) { + *this = *this / other; + return *this; +} + +inline uint128& uint128::operator%=(uint128 other) { + *this = *this % other; + return *this; +} constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; } @@ -514,9 +543,9 @@ inline uint128& uint128::operator^=(uint128 other) { return *this; } -// Shift and arithmetic assign operators. +// Arithmetic operators. -inline uint128& uint128::operator<<=(int amount) { +inline uint128 operator<<(uint128 lhs, int amount) { assert(amount >= 0); // Negative shifts are undefined. assert(amount < 128); // Shifts of >= 128 are undefined. @@ -524,17 +553,16 @@ inline uint128& uint128::operator<<=(int amount) { // special-casing. if (amount < 64) { if (amount != 0) { - hi_ = (hi_ << amount) | (lo_ >> (64 - amount)); - lo_ = lo_ << amount; + return MakeUint128( + (Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)), + Uint128Low64(lhs) << amount); } - } else { - hi_ = lo_ << (amount - 64); - lo_ = 0; + return lhs; } - return *this; + return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0); } -inline uint128& uint128::operator>>=(int amount) { +inline uint128 operator>>(uint128 lhs, int amount) { assert(amount >= 0); // Negative shifts are undefined. assert(amount < 128); // Shifts of >= 128 are undefined. @@ -542,49 +570,51 @@ inline uint128& uint128::operator>>=(int amount) { // special-casing. if (amount < 64) { if (amount != 0) { - lo_ = (lo_ >> amount) | (hi_ << (64 - amount)); - hi_ = hi_ >> amount; + return MakeUint128(Uint128High64(lhs) >> amount, + (Uint128Low64(lhs) >> amount) | + (Uint128High64(lhs) << (64 - amount))); } - } else { - lo_ = hi_ >> (amount - 64); - hi_ = 0; + return lhs; } - return *this; + return MakeUint128(0, Uint128High64(lhs) >> (amount - 64)); } -inline uint128& uint128::operator+=(uint128 other) { - hi_ += other.hi_; - uint64_t lolo = lo_ + other.lo_; - if (lolo < lo_) - ++hi_; - lo_ = lolo; - return *this; +inline uint128 operator+(uint128 lhs, uint128 rhs) { + uint128 result = MakeUint128(Uint128High64(lhs) + Uint128High64(rhs), + Uint128Low64(lhs) + Uint128Low64(rhs)); + if (Uint128Low64(result) < Uint128Low64(lhs)) { // check for carry + return MakeUint128(Uint128High64(result) + 1, Uint128Low64(result)); + } + return result; } -inline uint128& uint128::operator-=(uint128 other) { - hi_ -= other.hi_; - if (other.lo_ > lo_) --hi_; - lo_ -= other.lo_; - return *this; +inline uint128 operator-(uint128 lhs, uint128 rhs) { + uint128 result = MakeUint128(Uint128High64(lhs) - Uint128High64(rhs), + Uint128Low64(lhs) - Uint128Low64(rhs)); + if (Uint128Low64(lhs) < Uint128Low64(rhs)) { // check for carry + return MakeUint128(Uint128High64(result) - 1, Uint128Low64(result)); + } + return result; } -inline uint128& uint128::operator*=(uint128 other) { +inline uint128 operator*(uint128 lhs, uint128 rhs) { #if defined(ABSL_HAVE_INTRINSIC_INT128) // TODO(strel) Remove once alignment issues are resolved and unsigned __int128 // can be used for uint128 storage. - *this = static_cast<unsigned __int128>(*this) * - static_cast<unsigned __int128>(other); - return *this; + return static_cast<unsigned __int128>(lhs) * + static_cast<unsigned __int128>(rhs); #else // ABSL_HAVE_INTRINSIC128 - uint64_t a32 = lo_ >> 32; - uint64_t a00 = lo_ & 0xffffffff; - uint64_t b32 = other.lo_ >> 32; - uint64_t b00 = other.lo_ & 0xffffffff; - hi_ = hi_ * other.lo_ + lo_ * other.hi_ + a32 * b32; - lo_ = a00 * b00; - *this += uint128(a32 * b00) << 32; - *this += uint128(a00 * b32) << 32; - return *this; + uint64_t a32 = Uint128Low64(lhs) >> 32; + uint64_t a00 = Uint128Low64(lhs) & 0xffffffff; + uint64_t b32 = Uint128Low64(rhs) >> 32; + uint64_t b00 = Uint128Low64(rhs) & 0xffffffff; + uint128 result = + MakeUint128(Uint128High64(lhs) * Uint128Low64(rhs) + + Uint128Low64(lhs) * Uint128High64(rhs) + a32 * b32, + a00 * b00); + result += uint128(a32 * b00) << 32; + result += uint128(a00 * b32) << 32; + return result; #endif // ABSL_HAVE_INTRINSIC128 } |