diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 1d26eef..875a36c 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc
@@ -1365,12 +1365,12 @@ ctrl_t* old_ctrl = common.control(); void* old_slots = common.slot_array(); - common.set_capacity(kNewCapacity); const size_t slot_size = policy.slot_size; const size_t slot_align = policy.slot_align; void* alloc = policy.get_char_alloc(common); HashtablezInfoHandle infoz = common.infoz(); const bool has_infoz = infoz.IsSampled(); + common.set_capacity(kNewCapacity); const auto [new_ctrl, new_slots] = AllocBackingArray(common, policy, kNewCapacity, has_infoz, alloc);
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 4850e7e..9f62700 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -3188,7 +3188,7 @@ bool inserted; // We use a lambda function to be able to exit from the nested loop without // duplicating generated code for the return statement (e.g. iterator_at). - [&] { + [&]() ABSL_ATTRIBUTE_ALWAYS_INLINE { while (true) { #ifndef ABSL_HAVE_MEMORY_SANITIZER absl::PrefetchToLocalCache(slot_array() + seq.offset());
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel index f9c58d4..b7aa31f 100644 --- a/absl/functional/BUILD.bazel +++ b/absl/functional/BUILD.bazel
@@ -104,8 +104,10 @@ linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":any_invocable", + "//absl/base:config", "//absl/base:core_headers", "//absl/meta:type_traits", + "//absl/utility", ], ) @@ -117,8 +119,10 @@ deps = [ ":any_invocable", ":function_ref", + "//absl/base:config", "//absl/container:test_instance_tracker", "//absl/memory", + "//absl/utility", "@googletest//:gtest", "@googletest//:gtest_main", ],
diff --git a/absl/functional/CMakeLists.txt b/absl/functional/CMakeLists.txt index 34d285d..07f3dc0 100644 --- a/absl/functional/CMakeLists.txt +++ b/absl/functional/CMakeLists.txt
@@ -87,9 +87,11 @@ COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::config absl::core_headers absl::any_invocable absl::meta + absl::utility PUBLIC ) @@ -101,9 +103,11 @@ COPTS ${ABSL_TEST_COPTS} DEPS + absl::config absl::function_ref absl::memory absl::test_instance_tracker + absl::utility GTest::gmock_main )
diff --git a/absl/functional/function_ref.h b/absl/functional/function_ref.h index f1d087a..edf61de 100644 --- a/absl/functional/function_ref.h +++ b/absl/functional/function_ref.h
@@ -47,12 +47,13 @@ #define ABSL_FUNCTIONAL_FUNCTION_REF_H_ #include <cassert> -#include <functional> #include <type_traits> #include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/functional/internal/function_ref.h" #include "absl/meta/type_traits.h" +#include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -89,15 +90,17 @@ // signature of this FunctionRef. template <typename F, typename FR = std::invoke_result_t<F, Args&&...>> using EnableIfCompatible = - typename std::enable_if<std::is_void<R>::value || - std::is_convertible<FR, R>::value>::type; + std::enable_if_t<std::conditional_t<std::is_void_v<R>, std::true_type, + std::is_invocable_r<R, FR()>>::value>; public: // Constructs a FunctionRef from any invocable type. - template <typename F, typename = EnableIfCompatible<const F&>> - // NOLINTNEXTLINE(runtime/explicit) - FunctionRef(const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND) - : invoker_(&absl::functional_internal::InvokeObject<F, R, Args...>) { + template <typename F, + typename = EnableIfCompatible<std::enable_if_t< + !std::is_same_v<FunctionRef, absl::remove_cvref_t<F>>, F&>>> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(F&& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept + : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) { absl::functional_internal::AssertNonNull(f); ptr_.obj = &f; } @@ -111,14 +114,39 @@ template < typename F, typename = EnableIfCompatible<F*>, absl::functional_internal::EnableIf<absl::is_function<F>::value> = 0> - FunctionRef(F* f) // NOLINT(runtime/explicit) + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(F* f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept : invoker_(&absl::functional_internal::InvokeFunction<F*, R, Args...>) { assert(f != nullptr); ptr_.fun = reinterpret_cast<decltype(ptr_.fun)>(f); } - FunctionRef& operator=(const FunctionRef& rhs) = default; - FunctionRef(const FunctionRef& rhs) = default; +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L + // Similar to the other overloads, but passes the address of a known callable + // `F` at compile time. This allows calling arbitrary functions while avoiding + // an indirection. + // Needs C++20 as `nontype_t` needs C++20 for `auto` template parameters. + template <auto F> + FunctionRef(nontype_t<F>) noexcept // NOLINT(google-explicit-constructor) + : invoker_(&absl::functional_internal::InvokeFunction<decltype(F), F, R, + Args...>) {} + + template <auto F, typename Obj> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(nontype_t<F>, Obj&& obj) noexcept + : invoker_(&absl::functional_internal::InvokeObject<Obj&, decltype(F), F, + R, Args...>) { + ptr_.obj = std::addressof(obj); + } + + template <auto F, typename Obj> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(nontype_t<F>, Obj* obj) noexcept + : invoker_(&absl::functional_internal::InvokePtr<Obj, decltype(F), F, R, + Args...>) { + ptr_.obj = obj; + } +#endif // Call the underlying object. R operator()(Args... args) const { @@ -134,8 +162,39 @@ // constness anyway we can just make this a no-op. template <typename R, typename... Args> class FunctionRef<R(Args...) const> : public FunctionRef<R(Args...)> { + using Base = FunctionRef<R(Args...)>; + + template <typename F, typename T = void> + using EnableIfCallable = + std::enable_if_t<!std::is_same_v<FunctionRef, absl::remove_cvref_t<F>> && + std::is_invocable_r_v<R, F, Args...> && + std::is_constructible_v<Base, F>, + T>; + public: - using FunctionRef<R(Args...)>::FunctionRef; + template <typename F, typename = EnableIfCallable<const F&>> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept : Base(f) {} + + template <typename F, + typename = std::enable_if_t<std::is_constructible_v<Base, F*>>> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(F* f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept : Base(f) {} + +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L + template <auto F, typename = EnableIfCallable<decltype(F)>> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(nontype_t<F> arg) noexcept : Base(arg) {} + + template <auto F, typename Obj, typename = EnableIfCallable<decltype(F)>> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(nontype_t<F> arg, Obj&& obj) noexcept + : Base(arg, std::forward<Obj>(obj)) {} + + template <auto F, typename Obj, typename = EnableIfCallable<decltype(F)>> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(nontype_t<F> arg, Obj* obj) noexcept : Base(arg, obj) {} +#endif }; ABSL_NAMESPACE_END
diff --git a/absl/functional/function_ref_test.cc b/absl/functional/function_ref_test.cc index 98d11f7..c8ff080 100644 --- a/absl/functional/function_ref_test.cc +++ b/absl/functional/function_ref_test.cc
@@ -16,26 +16,31 @@ #include <functional> #include <memory> +#include <type_traits> +#include <utility> #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/container/internal/test_instance_tracker.h" #include "absl/functional/any_invocable.h" #include "absl/memory/memory.h" +#include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace { -void RunFun(FunctionRef<void()> f) { f(); } +int Function() { return 1337; } -TEST(FunctionRefTest, Lambda) { - bool ran = false; - RunFun([&] { ran = true; }); - EXPECT_TRUE(ran); +template <typename T> +T Dereference(const T* v) { + return *v; } -int Function() { return 1337; } +template <typename T> +T Copy(const T& v) { + return v; +} TEST(FunctionRefTest, Function1) { FunctionRef<int()> ref(&Function); @@ -251,11 +256,11 @@ std::is_same<Invoker<void, Trivial>, void (*)(VoidPtr, Trivial)>::value, "Small trivial types should be passed by value"); static_assert(std::is_same<Invoker<void, LargeTrivial>, - void (*)(VoidPtr, LargeTrivial &&)>::value, + void (*)(VoidPtr, LargeTrivial&&)>::value, "Large trivial types should be passed by rvalue reference"); static_assert( std::is_same<Invoker<void, CopyableMovableInstance>, - void (*)(VoidPtr, CopyableMovableInstance &&)>::value, + void (*)(VoidPtr, CopyableMovableInstance&&)>::value, "Types with copy/move ctor should be passed by rvalue reference"); // References are passed as references. @@ -268,7 +273,7 @@ "Reference types should be preserved"); static_assert( std::is_same<Invoker<void, CopyableMovableInstance&&>, - void (*)(VoidPtr, CopyableMovableInstance &&)>::value, + void (*)(VoidPtr, CopyableMovableInstance&&)>::value, "Reference types should be preserved"); // Make sure the address of an object received by reference is the same as the @@ -298,6 +303,61 @@ ref(obj); } +TEST(FunctionRefTest, CorrectConstQualifiers) { + struct S { + int operator()() { return 42; } + int operator()() const { return 1337; } + }; + S s; + EXPECT_EQ(42, FunctionRef<int()>(s)()); + EXPECT_EQ(1337, FunctionRef<int() const>(s)()); + EXPECT_EQ(1337, FunctionRef<int()>(std::as_const(s))()); +} + +TEST(FunctionRefTest, Lambdas) { + // Stateless lambdas implicitly convert to function pointers, so their + // mutability is irrelevant. + EXPECT_TRUE(FunctionRef<bool()>([]() /*const*/ { return true; })()); + EXPECT_TRUE(FunctionRef<bool()>([]() mutable { return true; })()); + EXPECT_TRUE(FunctionRef<bool() const>([]() /*const*/ { return true; })()); +#if defined(__clang__) || (ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L && \ + defined(_MSC_VER) && !defined(__EDG__)) + // MSVC has problems compiling the following code pre-C++20: + // const auto f = []() mutable {}; + // f(); + // EDG's MSVC-compatible mode (which Visual C++ uses for Intellisense) + // exhibits the bug in C++20 as well. So we don't support them. + EXPECT_TRUE(FunctionRef<bool() const>([]() mutable { return true; })()); +#endif + + // Stateful lambdas are not implicitly convertible to function pointers, so + // a const stateful lambda is not mutably callable. + EXPECT_TRUE(FunctionRef<bool()>([v = true]() /*const*/ { return v; })()); + EXPECT_TRUE(FunctionRef<bool()>([v = true]() mutable { return v; })()); + EXPECT_TRUE( + FunctionRef<bool() const>([v = true]() /*const*/ { return v; })()); + const auto func = [v = true]() mutable { return v; }; + static_assert( + !std::is_convertible_v<decltype(func), FunctionRef<bool() const>>); +} + +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L +TEST(FunctionRefTest, NonTypeParameter) { + EXPECT_EQ(1337, FunctionRef<int()>(nontype<&Function>)()); + EXPECT_EQ(42, FunctionRef<int()>(nontype<&Copy<int>>, 42)()); + EXPECT_EQ(42, FunctionRef<int()>(nontype<&Dereference<int>>, + &std::integral_constant<int, 42>::value)()); +} +#endif + +TEST(FunctionRefTest, OptionalArguments) { + struct S { + int operator()(int = 0) const { return 1337; } + }; + S s; + EXPECT_EQ(1337, FunctionRef<int()>(s)()); +} + } // namespace ABSL_NAMESPACE_END } // namespace absl
diff --git a/absl/functional/internal/function_ref.h b/absl/functional/internal/function_ref.h index 27d45b8..0796364 100644 --- a/absl/functional/internal/function_ref.h +++ b/absl/functional/internal/function_ref.h
@@ -72,8 +72,25 @@ // static_cast<R> handles the case the return type is void. template <typename Obj, typename R, typename... Args> R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) { - auto o = static_cast<const Obj*>(ptr.obj); - return static_cast<R>(std::invoke(*o, std::forward<Args>(args)...)); + using T = std::remove_reference_t<Obj>; + return static_cast<R>(std::invoke( + std::forward<Obj>(*const_cast<T*>(static_cast<const T*>(ptr.obj))), + std::forward<typename ForwardT<Args>::type>(args)...)); +} + +template <typename Obj, typename Fun, Fun F, typename R, typename... Args> +R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) { + using T = std::remove_reference_t<Obj>; + return static_cast<R>( + F(std::forward<Obj>(*const_cast<T*>(static_cast<const T*>(ptr.obj))), + std::forward<typename ForwardT<Args>::type>(args)...)); +} + +template <typename T, typename Fun, Fun F, typename R, typename... Args> +R InvokePtr(VoidPtr ptr, typename ForwardT<Args>::type... args) { + return static_cast<R>( + F(const_cast<T*>(static_cast<const T*>(ptr.obj)), + std::forward<typename ForwardT<Args>::type>(args)...)); } template <typename Fun, typename R, typename... Args> @@ -82,6 +99,12 @@ return static_cast<R>(std::invoke(f, std::forward<Args>(args)...)); } +template <typename Fun, Fun F, typename R, typename... Args> +R InvokeFunction(VoidPtr, typename ForwardT<Args>::type... args) { + return static_cast<R>( + F(std::forward<typename ForwardT<Args>::type>(args)...)); +} + template <typename Sig> void AssertNonNull(const std::function<Sig>& f) { assert(f != nullptr); @@ -98,7 +121,7 @@ void AssertNonNull(const F&) {} template <typename F, typename C> -void AssertNonNull(F C::*f) { +void AssertNonNull(F C::* f) { assert(f != nullptr); (void)f; }
diff --git a/absl/log/internal/check_op.h b/absl/log/internal/check_op.h index c9dcc05..532b37c 100644 --- a/absl/log/internal/check_op.h +++ b/absl/log/internal/check_op.h
@@ -362,6 +362,18 @@ UnprintableWrapper> Detect(...); +// Equivalent to the updated std::underlying_type from C++20, which is no +// longer undefined behavior for non-enum types. +template <typename T, typename EnableT = void> +struct UnderlyingType {}; + +template <typename T> +struct UnderlyingType<T, std::enable_if_t<std::is_enum_v<T>>> { + using type = std::underlying_type_t<T>; +}; +template <typename T> +using UnderlyingTypeT = typename UnderlyingType<T>::type; + // This overload triggers when T is a scoped enum that has not defined an output // stream operator (operator<<) or AbslStringify. It causes the enum value to be // converted to a type that can be streamed. For consistency with other enums, a @@ -373,14 +385,13 @@ std::negation<std::is_convertible<T, int>>, std::negation<HasOstreamOperator<T>>, std::negation<HasAbslStringify<T>>>, - std::conditional_t< - std::is_same_v<std::underlying_type_t<T>, bool> || - std::is_same_v<std::underlying_type_t<T>, char> || - std::is_same_v<std::underlying_type_t<T>, signed char> || - std::is_same_v<std::underlying_type_t<T>, unsigned char>, - std::underlying_type_t<T>, - std::conditional_t<std::is_signed_v<std::underlying_type_t<T>>, int64_t, - uint64_t>>> + std::conditional_t<std::is_same_v<UnderlyingTypeT<T>, bool> || + std::is_same_v<UnderlyingTypeT<T>, char> || + std::is_same_v<UnderlyingTypeT<T>, signed char> || + std::is_same_v<UnderlyingTypeT<T>, unsigned char>, + UnderlyingTypeT<T>, + std::conditional_t<std::is_signed_v<UnderlyingTypeT<T>>, + int64_t, uint64_t>>> Detect(...); } // namespace detect_specialization
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index 775e132..32603b0 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h
@@ -164,9 +164,9 @@ constexpr explicit operator __int128() const; constexpr explicit operator unsigned __int128() const; #endif // ABSL_HAVE_INTRINSIC_INT128 - explicit operator float() const; - explicit operator double() const; - explicit operator long double() const; + constexpr explicit operator float() const; + constexpr explicit operator double() const; + constexpr explicit operator long double() const; // Trivial copy constructor, assignment operator and destructor. @@ -357,14 +357,18 @@ constexpr int128(unsigned long v); // NOLINT(runtime/int) constexpr int128(long long v); // NOLINT(runtime/int) constexpr int128(unsigned long long v); // NOLINT(runtime/int) + constexpr explicit int128(uint128 v); #ifdef ABSL_HAVE_INTRINSIC_INT128 constexpr int128(__int128 v); // NOLINT(runtime/explicit) constexpr explicit int128(unsigned __int128 v); -#endif // ABSL_HAVE_INTRINSIC_INT128 - constexpr explicit int128(uint128 v); + constexpr explicit int128(float v); + constexpr explicit int128(double v); + constexpr explicit int128(long double v); +#else explicit int128(float v); explicit int128(double v); explicit int128(long double v); +#endif // ABSL_HAVE_INTRINSIC_INT128 // Assignment operators from arithmetic types int128& operator=(int v); @@ -401,9 +405,9 @@ constexpr explicit operator __int128() const; constexpr explicit operator unsigned __int128() const; #endif // ABSL_HAVE_INTRINSIC_INT128 - explicit operator float() const; - explicit operator double() const; - explicit operator long double() const; + constexpr explicit operator float() const; + constexpr explicit operator double() const; + constexpr explicit operator long double() const; // Trivial copy constructor, assignment operator and destructor. @@ -794,18 +798,18 @@ // Conversion operators to floating point types. -inline uint128::operator float() const { +constexpr uint128::operator float() const { // Note: This method might return Inf. constexpr float pow_2_64 = 18446744073709551616.0f; return static_cast<float>(lo_) + static_cast<float>(hi_) * pow_2_64; } -inline uint128::operator double() const { +constexpr uint128::operator double() const { constexpr double pow_2_64 = 18446744073709551616.0; return static_cast<double>(lo_) + static_cast<double>(hi_) * pow_2_64; } -inline uint128::operator long double() const { +constexpr uint128::operator long double() const { constexpr long double pow_2_64 = 18446744073709551616.0L; return static_cast<long double>(lo_) + static_cast<long double>(hi_) * pow_2_64;
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc index 62eb045..dea1d21 100644 --- a/absl/numeric/int128_have_intrinsic.inc +++ b/absl/numeric/int128_have_intrinsic.inc
@@ -73,17 +73,11 @@ constexpr int128::int128(unsigned __int128 v) : v_{static_cast<__int128>(v)} {} -inline int128::int128(float v) { - v_ = static_cast<__int128>(v); -} +constexpr int128::int128(float v) : v_{static_cast<__int128>(v)} {} -inline int128::int128(double v) { - v_ = static_cast<__int128>(v); -} +constexpr int128::int128(double v) : v_{static_cast<__int128>(v)} {} -inline int128::int128(long double v) { - v_ = static_cast<__int128>(v); -} +constexpr int128::int128(long double v) : v_{static_cast<__int128>(v)} {} constexpr int128::int128(uint128 v) : v_{static_cast<__int128>(v)} {} @@ -119,9 +113,7 @@ return static_cast<unsigned short>(v_); // NOLINT(runtime/int) } -constexpr int128::operator int() const { - return static_cast<int>(v_); -} +constexpr int128::operator int() const { return static_cast<int>(v_); } constexpr int128::operator unsigned int() const { return static_cast<unsigned int>(v_); @@ -153,17 +145,17 @@ // conversions. In that case, we do the conversion with a similar implementation // to the conversion operators in int128_no_intrinsic.inc. #if defined(__clang__) && !defined(__ppc64__) -inline int128::operator float() const { return static_cast<float>(v_); } +constexpr int128::operator float() const { return static_cast<float>(v_); } -inline int128::operator double() const { return static_cast<double>(v_); } +constexpr int128::operator double() const { return static_cast<double>(v_); } -inline int128::operator long double() const { +constexpr int128::operator long double() const { return static_cast<long double>(v_); } -#else // Clang on PowerPC +#else // Clang on PowerPC -inline int128::operator float() const { +constexpr int128::operator float() const { // We must convert the absolute value and then negate as needed, because // floating point types are typically sign-magnitude. Otherwise, the // difference between the high and low 64 bits when interpreted as two's @@ -177,7 +169,7 @@ static_cast<float>(Int128High64(*this)) * pow_2_64; } -inline int128::operator double() const { +constexpr int128::operator double() const { // See comment in int128::operator float() above. constexpr double pow_2_64 = 18446744073709551616.0; return v_ < 0 && *this != Int128Min() @@ -186,7 +178,7 @@ static_cast<double>(Int128High64(*this)) * pow_2_64; } -inline int128::operator long double() const { +constexpr int128::operator long double() const { // See comment in int128::operator float() above. constexpr long double pow_2_64 = 18446744073709551616.0L; return v_ < 0 && *this != Int128Min() @@ -266,7 +258,7 @@ constexpr int128 operator%(int128 lhs, int128 rhs) { return static_cast<__int128>(lhs) % static_cast<__int128>(rhs); } -#endif // ABSL_HAVE_INTRINSIC_INT128 +#endif // ABSL_HAVE_INTRINSIC_INT128 inline int128 int128::operator++(int) { int128 tmp(*this);
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc index a7cdcea..48bec2c 100644 --- a/absl/numeric/int128_no_intrinsic.inc +++ b/absl/numeric/int128_no_intrinsic.inc
@@ -132,7 +132,7 @@ return static_cast<unsigned long long>(lo_); // NOLINT(runtime/int) } -inline int128::operator float() const { +constexpr int128::operator float() const { // We must convert the absolute value and then negate as needed, because // floating point types are typically sign-magnitude. Otherwise, the // difference between the high and low 64 bits when interpreted as two's @@ -142,20 +142,18 @@ constexpr float pow_2_64 = 18446744073709551616.0f; return hi_ < 0 && *this != Int128Min() ? -static_cast<float>(-*this) - : static_cast<float>(lo_) + - static_cast<float>(hi_) * pow_2_64; + : static_cast<float>(lo_) + static_cast<float>(hi_) * pow_2_64; } -inline int128::operator double() const { +constexpr int128::operator double() const { // See comment in int128::operator float() above. constexpr double pow_2_64 = 18446744073709551616.0; return hi_ < 0 && *this != Int128Min() ? -static_cast<double>(-*this) - : static_cast<double>(lo_) + - static_cast<double>(hi_) * pow_2_64; + : static_cast<double>(lo_) + static_cast<double>(hi_) * pow_2_64; } -inline int128::operator long double() const { +constexpr int128::operator long double() const { // See comment in int128::operator float() above. constexpr long double pow_2_64 = 18446744073709551616.0L; return hi_ < 0 && *this != Int128Min()
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc index 1712af8..77ee63c 100644 --- a/absl/numeric/int128_test.cc +++ b/absl/numeric/int128_test.cc
@@ -463,6 +463,15 @@ EXPECT_EQ(one, absl::uint128(1)); EXPECT_EQ(minus_two, absl::MakeUint128(-1, -2)); + constexpr double f = static_cast<float>(absl::uint128(123)); + EXPECT_EQ(f, 123.0f); + + constexpr double d = static_cast<double>(absl::uint128(123)); + EXPECT_EQ(d, 123.0); + + constexpr long double ld = static_cast<long double>(absl::uint128(123)); + EXPECT_EQ(ld, 123.0); + #ifdef ABSL_HAVE_INTRINSIC_INT128 constexpr absl::uint128 division = absl::uint128(10) / absl::uint128(2); EXPECT_EQ(division, absl::uint128(5)); @@ -779,7 +788,25 @@ EXPECT_GT(max, one); EXPECT_LT(min, minus_two); + constexpr double f = static_cast<float>(absl::int128(123)); + EXPECT_EQ(f, 123.0f); + + constexpr double d = static_cast<double>(absl::int128(123)); + EXPECT_EQ(d, 123.0); + + constexpr long double ld = static_cast<long double>(absl::int128(123)); + EXPECT_EQ(ld, 123.0); + #ifdef ABSL_HAVE_INTRINSIC_INT128 + constexpr absl::int128 f_int128(static_cast<float>(123.0)); + EXPECT_EQ(f_int128, absl::int128(123)); + + constexpr absl::int128 d_int128(static_cast<double>(123.0)); + EXPECT_EQ(d_int128, absl::int128(123)); + + constexpr absl::int128 ld_int128(static_cast<long double>(123.0)); + EXPECT_EQ(ld_int128, absl::int128(123)); + constexpr absl::int128 division = absl::int128(10) / absl::int128(2); EXPECT_EQ(division, absl::int128(5));
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index dce8b8f..2062486 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h
@@ -61,17 +61,15 @@ #include <atomic> #include <cstdint> #include <cstring> -#include <iterator> -#include <string> #include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/base/const_init.h" #include "absl/base/internal/identity.h" -#include "absl/base/internal/low_level_alloc.h" #include "absl/base/internal/thread_identity.h" #include "absl/base/internal/tsan_mutex_interface.h" +#include "absl/base/macros.h" #include "absl/base/nullability.h" -#include "absl/base/port.h" #include "absl/base/thread_annotations.h" #include "absl/synchronization/internal/kernel_timeout.h" #include "absl/synchronization/internal/per_thread_sem.h" @@ -561,10 +559,10 @@ base_internal::PerThreadSynch* absl_nonnull w); void Dtor(); - friend class CondVar; // for access to Trans()/Fer(). + friend class CondVar; // for access to Trans()/Fer(). void Trans(MuHow absl_nonnull how); // used for CondVar->Mutex transfer void Fer(base_internal::PerThreadSynch* absl_nonnull - w); // used for CondVar->Mutex transfer + w); // used for CondVar->Mutex transfer // Catch the error of writing Mutex when intending MutexLock. explicit Mutex(const volatile Mutex* absl_nullable /*ignored*/) {} @@ -797,7 +795,7 @@ Condition( bool (*absl_nonnull func)(T* absl_nullability_unknown), typename absl::internal::type_identity<T>::type* absl_nullability_unknown - arg); + arg); // Templated version for invoking a method that returns a `bool`. // @@ -1186,7 +1184,7 @@ inline Condition::Condition( bool (*absl_nonnull func)(T* absl_nullability_unknown), typename absl::internal::type_identity<T>::type* absl_nullability_unknown - arg) + arg) // Just delegate to the overload above. : Condition(func, arg) {}
diff --git a/absl/utility/utility.h b/absl/utility/utility.h index 4637b03..4d72c31 100644 --- a/absl/utility/utility.h +++ b/absl/utility/utility.h
@@ -49,6 +49,19 @@ using std::make_integer_sequence; using std::move; +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L +// Backfill for std::nontype_t. An instance of this class can be provided as a +// disambiguation tag to `absl::function_ref` to pass the address of a known +// callable at compile time. +// Requires C++20 due to `auto` template parameter. +template <auto> +struct nontype_t { + explicit nontype_t() = default; +}; +template <auto V> +constexpr nontype_t<V> nontype{}; +#endif + ABSL_NAMESPACE_END } // namespace absl