diff options
Diffstat (limited to 'absl/numeric')
-rw-r--r-- | absl/numeric/BUILD.bazel | 8 | ||||
-rw-r--r-- | absl/numeric/CMakeLists.txt | 78 | ||||
-rw-r--r-- | absl/numeric/int128.cc | 30 | ||||
-rw-r--r-- | absl/numeric/int128.h | 42 | ||||
-rw-r--r-- | absl/numeric/int128_benchmark.cc | 2 | ||||
-rw-r--r-- | absl/numeric/int128_have_intrinsic.inc | 4 | ||||
-rw-r--r-- | absl/numeric/int128_no_intrinsic.inc | 4 | ||||
-rw-r--r-- | absl/numeric/int128_stream_test.cc | 2 | ||||
-rw-r--r-- | absl/numeric/int128_test.cc | 45 |
9 files changed, 144 insertions, 71 deletions
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel index 324ce669..d9b561df 100644 --- a/absl/numeric/BUILD.bazel +++ b/absl/numeric/BUILD.bazel @@ -4,7 +4,7 @@ # 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 +# https://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, @@ -13,8 +13,9 @@ # limitations under the License. load( - "//absl:copts.bzl", + "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) @@ -31,6 +32,7 @@ cc_library( ], hdrs = ["int128.h"], copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:config", "//absl/base:core_headers", @@ -45,6 +47,7 @@ cc_test( "int128_test.cc", ], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":int128", "//absl/base", @@ -59,6 +62,7 @@ cc_test( name = "int128_benchmark", srcs = ["int128_benchmark.cc"], copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], deps = [ ":int128", diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt index 3360b2ee..242889f0 100644 --- a/absl/numeric/CMakeLists.txt +++ b/absl/numeric/CMakeLists.txt @@ -5,7 +5,7 @@ # 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 +# https://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, @@ -14,49 +14,47 @@ # limitations under the License. # -list(APPEND NUMERIC_PUBLIC_HEADERS - "int128.h" -) - - -# library 128 -list(APPEND INT128_SRC - "int128.cc" - ${NUMERIC_PUBLIC_HEADERS} -) -absl_library( - TARGET - absl_int128 - SOURCES - ${INT128_SRC} - PUBLIC_LIBRARIES - ${INT128_PUBLIC_LIBRARIES} - EXPORT_NAME +absl_cc_library( + NAME int128 + HDRS + "int128.h" + SRCS + "int128.cc" + "int128_have_intrinsic.inc" + "int128_no_intrinsic.inc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::core_headers + PUBLIC ) - -absl_header_library( - TARGET - absl_numeric - PUBLIC_LIBRARIES +absl_cc_test( + NAME + int128_test + SRCS + "int128_stream_test.cc" + "int128_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS absl::int128 - EXPORT_NAME - numeric + absl::base + absl::core_headers + absl::hash_testing + absl::type_traits + gmock_main ) -# test int128_test -set(INT128_TEST_SRC "int128_test.cc") -set(INT128_TEST_PUBLIC_LIBRARIES absl::numeric absl::base) - -absl_test( - TARGET - int128_test - SOURCES - ${INT128_TEST_SRC} - PUBLIC_LIBRARIES - ${INT128_TEST_PUBLIC_LIBRARIES} +# component target +absl_cc_library( + NAME + numeric + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::int128 + PUBLIC ) - - - diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index 98af84b7..a22f1e3e 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc @@ -4,7 +4,7 @@ // 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 +// https://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, @@ -23,7 +23,7 @@ #include <type_traits> namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { const uint128 kuint128max = MakeUint128(std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max()); @@ -66,7 +66,7 @@ static inline int Fls128(uint128 n) { // Long division/modulo for uint128 implemented using the shift-subtract // division algorithm adapted from: -// http://stackoverflow.com/questions/5386377/division-without-using +// https://stackoverflow.com/questions/5386377/division-without-using void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret, uint128* remainder_ret) { assert(divisor != 0); @@ -124,6 +124,28 @@ uint128 MakeUint128FromFloat(T v) { return MakeUint128(0, static_cast<uint64_t>(v)); } + +#if defined(__clang__) && !defined(__SSE3__) +// Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289 +// Casting from long double to uint64_t is miscompiled and drops bits. +// It is more work, so only use when we need the workaround. +uint128 MakeUint128FromFloat(long double v) { + // Go 50 bits at a time, that fits in a double + static_assert(std::numeric_limits<double>::digits >= 50, ""); + static_assert(std::numeric_limits<long double>::digits <= 150, ""); + // Undefined behavior if v is not finite or cannot fit into uint128. + assert(std::isfinite(v) && v > -1 && v < std::ldexp(1.0L, 128)); + + v = std::ldexp(v, -100); + uint64_t w0 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + v = std::ldexp(v - static_cast<double>(w0), 50); + uint64_t w1 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + v = std::ldexp(v - static_cast<double>(w1), 50); + uint64_t w2 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + return (static_cast<uint128>(w0) << 100) | (static_cast<uint128>(w1) << 50) | + static_cast<uint128>(w2); +} +#endif // __clang__ && !__SSE3__ } // namespace uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {} @@ -223,7 +245,7 @@ std::ostream& operator<<(std::ostream& os, uint128 v) { return os << rep; } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl namespace std { diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index cb4776f1..a9693a27 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h @@ -5,7 +5,7 @@ // 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 +// https://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, @@ -19,8 +19,8 @@ // // This header file defines 128-bit integer types. // -// Currently, this file defines `uint128`, an unsigned 128-bit integer; a signed -// 128-bit integer is forthcoming. +// Currently, this file defines `uint128`, an unsigned 128-bit integer; +// a signed 128-bit integer is forthcoming. #ifndef ABSL_NUMERIC_INT128_H_ #define ABSL_NUMERIC_INT128_H_ @@ -37,14 +37,22 @@ #include "absl/base/macros.h" #include "absl/base/port.h" -#if defined(_MSC_VER) && defined(_WIN64) +#if defined(_MSC_VER) +// In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is +// a typedef for unsigned short. Otherwise wchar_t is mapped to the __wchar_t +// builtin type. We need to make sure not to define operator wchar_t() +// alongside operator unsigned short() in these instances. +#define ABSL_INTERNAL_WCHAR_T __wchar_t +#if defined(_M_X64) #include <intrin.h> #pragma intrinsic(_umul128) -#endif // defined(_MSC_VER) && defined(_WIN64) +#endif // defined(_M_X64) +#else // defined(_MSC_VER) +#define ABSL_INTERNAL_WCHAR_T wchar_t +#endif // defined(_MSC_VER) namespace absl { -inline namespace lts_2018_12_18 { - +inline namespace lts_2019_08_08 { // uint128 // @@ -132,7 +140,7 @@ class constexpr explicit operator unsigned char() const; constexpr explicit operator char16_t() const; constexpr explicit operator char32_t() const; - constexpr explicit operator wchar_t() const; + constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const; constexpr explicit operator short() const; // NOLINT(runtime/int) // NOLINTNEXTLINE(runtime/int) constexpr explicit operator unsigned short() const; @@ -237,7 +245,7 @@ constexpr uint128 Uint128Max() { (std::numeric_limits<uint64_t>::max)()); } -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl // Specialized numeric_limits for uint128. @@ -273,9 +281,9 @@ class numeric_limits<absl::uint128> { #endif // ABSL_HAVE_INTRINSIC_INT128 static constexpr bool tinyness_before = false; - static constexpr absl::uint128 min() { return 0; } + static constexpr absl::uint128 (min)() { return 0; } static constexpr absl::uint128 lowest() { return 0; } - static constexpr absl::uint128 max() { return absl::Uint128Max(); } + static constexpr absl::uint128 (max)() { return absl::Uint128Max(); } static constexpr absl::uint128 epsilon() { return 0; } static constexpr absl::uint128 round_error() { return 0; } static constexpr absl::uint128 infinity() { return 0; } @@ -291,7 +299,7 @@ class numeric_limits<absl::uint128> { // Implementation details follow // -------------------------------------------------------------------------- namespace absl { -inline namespace lts_2018_12_18 { +inline namespace lts_2019_08_08 { constexpr uint128 MakeUint128(uint64_t high, uint64_t low) { return uint128(high, low); @@ -471,8 +479,8 @@ constexpr uint128::operator char32_t() const { return static_cast<char32_t>(lo_); } -constexpr uint128::operator wchar_t() const { - return static_cast<wchar_t>(lo_); +constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const { + return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_); } // NOLINTNEXTLINE(runtime/int) @@ -669,7 +677,7 @@ inline uint128 operator*(uint128 lhs, uint128 rhs) { // can be used for uint128 storage. return static_cast<unsigned __int128>(lhs) * static_cast<unsigned __int128>(rhs); -#elif defined(_MSC_VER) && defined(_WIN64) +#elif defined(_MSC_VER) && defined(_M_X64) uint64_t carry; uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry); return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) + @@ -720,7 +728,9 @@ inline uint128& uint128::operator--() { #include "absl/numeric/int128_no_intrinsic.inc" #endif // ABSL_HAVE_INTRINSIC_INT128 -} // inline namespace lts_2018_12_18 +} // inline namespace lts_2019_08_08 } // namespace absl +#undef ABSL_INTERNAL_WCHAR_T + #endif // ABSL_NUMERIC_INT128_H_ diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc index 1cb7d0ed..a5502d92 100644 --- a/absl/numeric/int128_benchmark.cc +++ b/absl/numeric/int128_benchmark.cc @@ -4,7 +4,7 @@ // 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 +// https://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, diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc index ee2a0930..c7ea6834 100644 --- a/absl/numeric/int128_have_intrinsic.inc +++ b/absl/numeric/int128_have_intrinsic.inc @@ -5,7 +5,7 @@ // 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 +// https://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, @@ -15,4 +15,4 @@ // 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. +// included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined. diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc index 0d0b3cfd..046cb9b3 100644 --- a/absl/numeric/int128_no_intrinsic.inc +++ b/absl/numeric/int128_no_intrinsic.inc @@ -5,7 +5,7 @@ // 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 +// https://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, @@ -15,4 +15,4 @@ // This file contains :int128 implementation details that depend on internal // representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file -// is included by int128.h. +// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined. diff --git a/absl/numeric/int128_stream_test.cc b/absl/numeric/int128_stream_test.cc index 09efaad4..3cfa9dc1 100644 --- a/absl/numeric/int128_stream_test.cc +++ b/absl/numeric/int128_stream_test.cc @@ -4,7 +4,7 @@ // 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 +// https://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, diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc index dfe3475a..5e1b5ec3 100644 --- a/absl/numeric/int128_test.cc +++ b/absl/numeric/int128_test.cc @@ -4,7 +4,7 @@ // 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 +// https://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, @@ -51,7 +51,7 @@ template <typename T> class Uint128FloatTraitsTest : public ::testing::Test {}; typedef ::testing::Types<float, double, long double> FloatingPointTypes; -TYPED_TEST_CASE(Uint128IntegerTraitsTest, IntegerTypes); +TYPED_TEST_SUITE(Uint128IntegerTraitsTest, IntegerTypes); TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) { static_assert(std::is_constructible<absl::uint128, TypeParam>::value, @@ -62,7 +62,7 @@ TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) { "TypeParam must not be assignable from absl::uint128"); } -TYPED_TEST_CASE(Uint128FloatTraitsTest, FloatingPointTypes); +TYPED_TEST_SUITE(Uint128FloatTraitsTest, FloatingPointTypes); TYPED_TEST(Uint128FloatTraitsTest, ConstructAssignTest) { static_assert(std::is_constructible<absl::uint128, TypeParam>::value, @@ -271,6 +271,20 @@ TEST(Uint128, ConversionTests) { EXPECT_EQ(static_cast<absl::uint128>(round_to_zero), 0); EXPECT_EQ(static_cast<absl::uint128>(round_to_five), 5); EXPECT_EQ(static_cast<absl::uint128>(round_to_nine), 9); + + absl::uint128 highest_precision_in_long_double = + ~absl::uint128{} >> (128 - std::numeric_limits<long double>::digits); + EXPECT_EQ(highest_precision_in_long_double, + static_cast<absl::uint128>( + static_cast<long double>(highest_precision_in_long_double))); + // Apply a mask just to make sure all the bits are the right place. + const absl::uint128 arbitrary_mask = + absl::MakeUint128(0xa29f622677ded751, 0xf8ca66add076f468); + EXPECT_EQ(highest_precision_in_long_double & arbitrary_mask, + static_cast<absl::uint128>(static_cast<long double>( + highest_precision_in_long_double & arbitrary_mask))); + + EXPECT_EQ(static_cast<absl::uint128>(-0.1L), 0); } TEST(Uint128, OperatorAssignReturnRef) { @@ -440,4 +454,29 @@ TEST(Uint128, NumericLimitsTest) { EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max()); } +TEST(Uint128, Hash) { + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({ + // Some simple values + absl::uint128{0}, + absl::uint128{1}, + ~absl::uint128{}, + // 64 bit limits + absl::uint128{std::numeric_limits<int64_t>::max()}, + absl::uint128{std::numeric_limits<uint64_t>::max()} + 0, + absl::uint128{std::numeric_limits<uint64_t>::max()} + 1, + absl::uint128{std::numeric_limits<uint64_t>::max()} + 2, + // Keeping high same + absl::uint128{1} << 62, + absl::uint128{1} << 63, + // Keeping low same + absl::uint128{1} << 64, + absl::uint128{1} << 65, + // 128 bit limits + std::numeric_limits<absl::uint128>::max(), + std::numeric_limits<absl::uint128>::max() - 1, + std::numeric_limits<absl::uint128>::min() + 1, + std::numeric_limits<absl::uint128>::min(), + })); +} + } // namespace |