diff options
Diffstat (limited to 'absl/numeric')
-rw-r--r-- | absl/numeric/int128.cc | 34 | ||||
-rw-r--r-- | absl/numeric/int128.h | 99 | ||||
-rw-r--r-- | absl/numeric/int128_have_intrinsic.inc | 19 | ||||
-rw-r--r-- | absl/numeric/int128_no_intrinsic.inc | 19 | ||||
-rw-r--r-- | absl/numeric/int128_test.cc | 6 |
5 files changed, 100 insertions, 77 deletions
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index 00bf7f47a4a2..de1b997ad159 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc @@ -139,9 +139,9 @@ uint128& uint128::operator%=(uint128 other) { return *this; } -std::ostream& operator<<(std::ostream& o, uint128 b) { - std::ios_base::fmtflags flags = o.flags(); +namespace { +std::string Uint128ToFormattedString(uint128 v, std::ios_base::fmtflags flags) { // Select a divisor which is the largest power of the base < 2^64. uint128 div; int div_base_log; @@ -160,14 +160,14 @@ std::ostream& operator<<(std::ostream& o, uint128 b) { break; } - // Now piece together the uint128 representation from three chunks of - // the original value, each less than "div" and therefore representable - // as a uint64_t. + // Now piece together the uint128 representation from three chunks of the + // original value, each less than "div" and therefore representable as a + // uint64_t. std::ostringstream os; std::ios_base::fmtflags copy_mask = std::ios::basefield | std::ios::showbase | std::ios::uppercase; os.setf(flags & copy_mask, copy_mask); - uint128 high = b; + uint128 high = v; uint128 low; DivModImpl(high, div, &high, &low); uint128 mid; @@ -182,25 +182,31 @@ std::ostream& operator<<(std::ostream& o, uint128 b) { os << std::noshowbase << std::setfill('0') << std::setw(div_base_log); } os << Uint128Low64(low); - std::string rep = os.str(); + return os.str(); +} + +} // namespace + +std::ostream& operator<<(std::ostream& os, uint128 v) { + std::ios_base::fmtflags flags = os.flags(); + std::string rep = Uint128ToFormattedString(v, flags); // Add the requisite padding. - std::streamsize width = o.width(0); + std::streamsize width = os.width(0); if (static_cast<size_t>(width) > rep.size()) { std::ios::fmtflags adjustfield = flags & std::ios::adjustfield; if (adjustfield == std::ios::left) { - rep.append(width - rep.size(), o.fill()); + rep.append(width - rep.size(), os.fill()); } else if (adjustfield == std::ios::internal && (flags & std::ios::showbase) && - (flags & std::ios::basefield) == std::ios::hex && b != 0) { - rep.insert(2, width - rep.size(), o.fill()); + (flags & std::ios::basefield) == std::ios::hex && v != 0) { + rep.insert(2, width - rep.size(), os.fill()); } else { - rep.insert(0, width - rep.size(), o.fill()); + rep.insert(0, width - rep.size(), os.fill()); } } - // Stream the final representation in a single "<<" call. - return o << rep; + return os << rep; } } // namespace absl diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index d87cbbd44752..5e1b3f03c0f2 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h @@ -62,7 +62,7 @@ namespace absl { // However, a `uint128` differs from intrinsic integral types in the following // ways: // -// * Errors on implicit conversions that does not preserve value (such as +// * Errors on implicit conversions that do not preserve value (such as // loss of precision when converting to float values). // * Requires explicit construction from and conversion to floating point // types. @@ -71,8 +71,8 @@ namespace absl { // // Example: // -// float y = absl::kuint128max; // Error. uint128 cannot be implicitly -// // converted to float. +// float y = absl::Uint128Max(); // Error. uint128 cannot be implicitly +// // converted to float. // // absl::uint128 v; // absl::uint64_t i = v; // Error @@ -175,10 +175,15 @@ class alignas(16) uint128 { // Example: // // absl::uint128 big = absl::MakeUint128(1, 0); - friend constexpr uint128 MakeUint128(uint64_t top, uint64_t bottom); + friend constexpr uint128 MakeUint128(uint64_t high, uint64_t low); + + // Uint128Max() + // + // Returns the highest value for a 128-bit unsigned integer. + friend constexpr uint128 Uint128Max(); private: - constexpr uint128(uint64_t top, uint64_t bottom); + constexpr uint128(uint64_t high, uint64_t low); // TODO(strel) Update implementation to use __int128 once all users of // uint128 are fixed to not depend on alignof(uint128) == 8. Also add @@ -195,10 +200,13 @@ class alignas(16) uint128 { #endif // byte order }; +// Prefer to use the constexpr `Uint128Max()`. +// +// TODO(absl-team) deprecate kuint128max once migration tool is released. extern const uint128 kuint128max; // allow uint128 to be logged -extern std::ostream& operator<<(std::ostream& o, uint128 b); +extern std::ostream& operator<<(std::ostream& os, uint128 v); // TODO(strel) add operator>>(std::istream&, uint128) @@ -208,8 +216,13 @@ extern std::ostream& operator<<(std::ostream& o, uint128 b); // Implementation details follow // -------------------------------------------------------------------------- -constexpr uint128 MakeUint128(uint64_t top, uint64_t bottom) { - return uint128(top, bottom); +constexpr uint128 MakeUint128(uint64_t high, uint64_t low) { + return uint128(high, low); +} + +constexpr uint128 Uint128Max() { + return uint128(std::numeric_limits<uint64_t>::max(), + std::numeric_limits<uint64_t>::max()); } // Assignment from integer types. @@ -251,33 +264,19 @@ inline uint128& uint128::operator=(unsigned __int128 v) { // Shift and arithmetic operators. -inline uint128 operator<<(uint128 lhs, int amount) { - return uint128(lhs) <<= amount; -} +inline uint128 operator<<(uint128 lhs, int amount) { return lhs <<= amount; } -inline uint128 operator>>(uint128 lhs, int amount) { - return uint128(lhs) >>= amount; -} +inline uint128 operator>>(uint128 lhs, int amount) { return lhs >>= amount; } -inline uint128 operator+(uint128 lhs, uint128 rhs) { - return uint128(lhs) += rhs; -} +inline uint128 operator+(uint128 lhs, uint128 rhs) { return lhs += rhs; } -inline uint128 operator-(uint128 lhs, uint128 rhs) { - return uint128(lhs) -= rhs; -} +inline uint128 operator-(uint128 lhs, uint128 rhs) { return lhs -= rhs; } -inline uint128 operator*(uint128 lhs, uint128 rhs) { - return uint128(lhs) *= rhs; -} +inline uint128 operator*(uint128 lhs, uint128 rhs) { return lhs *= rhs; } -inline uint128 operator/(uint128 lhs, uint128 rhs) { - return uint128(lhs) /= rhs; -} +inline uint128 operator/(uint128 lhs, uint128 rhs) { return lhs /= rhs; } -inline uint128 operator%(uint128 lhs, uint128 rhs) { - return uint128(lhs) %= rhs; -} +inline uint128 operator%(uint128 lhs, uint128 rhs) { return lhs %= rhs; } constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; } @@ -287,8 +286,8 @@ constexpr uint64_t Uint128High64(uint128 v) { return v.hi_; } #if defined(ABSL_IS_LITTLE_ENDIAN) -constexpr uint128::uint128(uint64_t top, uint64_t bottom) - : lo_(bottom), hi_(top) {} +constexpr uint128::uint128(uint64_t high, uint64_t low) + : lo_(low), hi_(high) {} constexpr uint128::uint128(int v) : lo_(v), hi_(v < 0 ? std::numeric_limits<uint64_t>::max() : 0) {} @@ -314,8 +313,8 @@ constexpr uint128::uint128(unsigned __int128 v) #elif defined(ABSL_IS_BIG_ENDIAN) -constexpr uint128::uint128(uint64_t top, uint64_t bottom) - : hi_(top), lo_(bottom) {} +constexpr uint128::uint128(uint64_t high, uint64_t low) + : hi_(high), lo_(low) {} constexpr uint128::uint128(int v) : hi_(v < 0 ? std::numeric_limits<uint64_t>::max() : 0), lo_(v) {} @@ -460,13 +459,10 @@ inline bool operator>=(uint128 lhs, uint128 rhs) { // Unary operators. inline uint128 operator-(uint128 val) { - const uint64_t hi_flip = ~Uint128High64(val); - const uint64_t lo_flip = ~Uint128Low64(val); - const uint64_t lo_add = lo_flip + 1; - if (lo_add < lo_flip) { - return MakeUint128(hi_flip + 1, lo_add); - } - return MakeUint128(hi_flip, lo_add); + uint64_t hi = ~Uint128High64(val); + uint64_t lo = ~Uint128Low64(val) + 1; + if (lo == 0) ++hi; // carry + return MakeUint128(hi, lo); } inline bool operator!(uint128 val) { @@ -515,8 +511,8 @@ inline uint128& uint128::operator^=(uint128 other) { // Shift and arithmetic assign operators. inline uint128& uint128::operator<<=(int amount) { - // Shifts of >= 128 are undefined. - assert(amount < 128); + assert(amount >= 0); // Negative shifts are undefined. + assert(amount < 128); // Shifts of >= 128 are undefined. // uint64_t shifts of >= 64 are undefined, so we will need some // special-casing. @@ -533,8 +529,8 @@ inline uint128& uint128::operator<<=(int amount) { } inline uint128& uint128::operator>>=(int amount) { - // Shifts of >= 128 are undefined. - assert(amount < 128); + assert(amount >= 0); // Negative shifts are undefined. + assert(amount < 128); // Shifts of >= 128 are undefined. // uint64_t shifts of >= 64 are undefined, so we will need some // special-casing. @@ -574,25 +570,14 @@ inline uint128& uint128::operator*=(uint128 other) { static_cast<unsigned __int128>(other); return *this; #else // ABSL_HAVE_INTRINSIC128 - uint64_t a96 = hi_ >> 32; - uint64_t a64 = hi_ & 0xffffffff; uint64_t a32 = lo_ >> 32; uint64_t a00 = lo_ & 0xffffffff; - uint64_t b96 = other.hi_ >> 32; - uint64_t b64 = other.hi_ & 0xffffffff; uint64_t b32 = other.lo_ >> 32; uint64_t b00 = other.lo_ & 0xffffffff; - // multiply [a96 .. a00] x [b96 .. b00] - // terms higher than c96 disappear off the high side - // terms c96 and c64 are safe to ignore carry bit - uint64_t c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96; - uint64_t c64 = a64 * b00 + a32 * b32 + a00 * b64; - this->hi_ = (c96 << 32) + c64; - this->lo_ = 0; - // add terms after this one at a time to capture carry + hi_ = hi_ * other.lo_ + lo_ * other.hi_ + a32 * b32; + lo_ = a00 * b00; *this += uint128(a32 * b00) << 32; *this += uint128(a00 * b32) << 32; - *this += a00 * b00; return *this; #endif // ABSL_HAVE_INTRINSIC128 } diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc index 49bde0767870..ee2a093018d9 100644 --- a/absl/numeric/int128_have_intrinsic.inc +++ b/absl/numeric/int128_have_intrinsic.inc @@ -1,3 +1,18 @@ -// This file will contain :int128 implementation details that depend on internal -// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file will be +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file contains :int128 implementation details that depend on internal +// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is // included by int128.h. diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc index 2dbff2b31565..0d0b3cfdeb12 100644 --- a/absl/numeric/int128_no_intrinsic.inc +++ b/absl/numeric/int128_no_intrinsic.inc @@ -1,3 +1,18 @@ -// This file will contain :int128 implementation details that depend on internal +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file contains :int128 implementation details that depend on internal // representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file -// will be included by int128.h. +// is included by int128.h. diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc index d674cb125f5e..79bcca907ae9 100644 --- a/absl/numeric/int128_test.cc +++ b/absl/numeric/int128_test.cc @@ -110,7 +110,7 @@ TEST(Uint128, AllTests) { absl::uint128 big = absl::MakeUint128(2000, 2); absl::uint128 big_minus_one = absl::MakeUint128(2000, 1); absl::uint128 bigger = absl::MakeUint128(2001, 1); - absl::uint128 biggest = absl::kuint128max; + absl::uint128 biggest = absl::Uint128Max(); absl::uint128 high_low = absl::MakeUint128(1, 0); absl::uint128 low_high = absl::MakeUint128(0, std::numeric_limits<uint64_t>::max()); @@ -227,8 +227,10 @@ TEST(Uint128, AllTests) { EXPECT_EQ(big, -(-big)); EXPECT_EQ(two, -((-one) - 1)); - EXPECT_EQ(absl::kuint128max, -one); + EXPECT_EQ(absl::Uint128Max(), -one); EXPECT_EQ(zero, -zero); + + EXPECT_EQ(absl::Uint128Max(), absl::kuint128max); } TEST(Uint128, ConversionTests) { |