Move pass-by-value type traits to `absl::type_traits_internal`. `ShouldSemanticallyPreferPassByValue` and `ShouldPreferPassByValue` are unchanged. `ShouldStructurallyPreferPassByValue` uses `(sizeof(T) & (sizeof(T) - 1)) == 0` in place of `absl::has_single_bit(sizeof(T))` to avoid a dependency from `type_traits` on `numeric:bits`. PiperOrigin-RevId: 1004944315
diff --git a/absl/container/internal/raw_hash_map.h b/absl/container/internal/raw_hash_map.h index 8984dfa..d4a7564 100644 --- a/absl/container/internal/raw_hash_map.h +++ b/absl/container/internal/raw_hash_map.h
@@ -382,15 +382,17 @@ // Try to avoid using std::tuple since that slows compilation. // (example: https://godbolt.org/z/nefW93T6K) - if constexpr (ShouldPreferPassByValue<std::conditional_t< - sizeof...(Args) == 0 && - std::is_same_v< - typename std::allocator_traits< - Alloc>::template rebind_alloc<char>, - std::allocator<char>>, - mapped_type, - // Trick to avoid unnecessary template instantiations. - void>>::value) { + if constexpr (type_traits_internal::ShouldPreferPassByValue< + std::conditional_t< + sizeof...(Args) == 0 && + std::is_same_v< + typename std::allocator_traits< + Alloc>::template rebind_alloc<char>, + std::allocator<char>>, + mapped_type, + // Trick to avoid unnecessary template + // instantiations. + void>>::value) { // Common case: operator[] // Note: This has a different run-time performance characteristic than // the other branches, due to the usage of a temporary object. In the
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 0b2d03d..caf8219 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -2380,36 +2380,12 @@ Alloc>::template rebind_alloc<T>>, T, void>>>; -template <class T> -using ShouldStructurallyPreferPassByValue = std::bool_constant< - // Check if size is a power of 2, to ensure cheap calls. - absl::has_single_bit(sizeof(T)) && - // Check if copying 1-2 registers is enough. We don't want (for example) 32 - // one-byte values to move around, since that sometimes results in poor - // codegen. - alignof(T) * 2 >= sizeof(T) && - sizeof(T) <= sizeof(std::pair<void*, size_t>)>; - -template <class T> -using ShouldSemanticallyPreferPassByValue = - std::bool_constant<std::is_trivially_move_constructible_v<T> && - std::is_trivially_destructible_v<T>>; - -// Checks the given type to see if it is a good candidate for accepting by value -// instead of by rvalue-reference. This includes both a semantic constraint -// (to ensure correctness), as well as a structural constraint (to ensure -// performance). -template <class T> -using ShouldPreferPassByValue = - std::bool_constant<ShouldSemanticallyPreferPassByValue<T>::value && - ShouldStructurallyPreferPassByValue<std::conditional_t< - std::is_void_v<T>, char, T>>::value>; - // This is a 'struct' instead of 'using' in order to avoid eager evaluation for // callers that may be passing incomplete types. template <class T> struct AddConstRefIfExpensive - : std::conditional<ShouldPreferPassByValue<T>::value, T, const T&> { + : std::conditional<type_traits_internal::ShouldPreferPassByValue<T>::value, + T, const T&> { static_assert(std::is_same_v<remove_cvref_t<T>, T>, "passed types must be unqualified"); };
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index b60579c..143d14e 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h
@@ -635,6 +635,31 @@ IsOwner<absl::remove_cvref_t<U>>, IsView<absl::remove_cvref_t<T>>>; +template <class T> +using ShouldStructurallyPreferPassByValue = std::bool_constant< + // Check if size is a power of 2, to ensure cheap calls. + (sizeof(T) & (sizeof(T) - 1)) == 0 && + // Check if copying 1-2 registers is enough. We don't want (for example) 32 + // one-byte values to move around, since that sometimes results in poor + // codegen. + alignof(T) * 2 >= sizeof(T) && + sizeof(T) <= sizeof(std::pair<void*, size_t>)>; + +template <class T> +using ShouldSemanticallyPreferPassByValue = + std::bool_constant<std::is_trivially_move_constructible_v<T> && + std::is_trivially_destructible_v<T>>; + +// Checks the given type to see if it is a good candidate for accepting by value +// instead of by rvalue-reference. This includes both a semantic constraint +// (to ensure correctness), as well as a structural constraint (to ensure +// performance). +template <class T> +using ShouldPreferPassByValue = + std::bool_constant<ShouldSemanticallyPreferPassByValue<T>::value && + ShouldStructurallyPreferPassByValue<std::conditional_t< + std::is_void_v<T>, char, T>>::value>; + } // namespace type_traits_internal ABSL_NAMESPACE_END
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index a11049c..ff44922 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc
@@ -17,6 +17,7 @@ #include <array> #include <cstdint> #include <functional> +#include <memory> #include <string> #include <string_view> #include <tuple> @@ -31,6 +32,9 @@ #include "absl/time/clock.h" #include "absl/time/time.h" +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace type_traits_internal { namespace { using ::testing::StaticAssertTypeEq; @@ -473,4 +477,40 @@ #endif // ABSL_HAVE_CONSTANT_EVALUATED } +enum UnscopedEnum { kUnscoped }; +enum class ScopedEnum { kScoped }; +union TrivialUnion { + int a; + void* b; +}; +struct TrivialMoveNonTrivialCopy { + TrivialMoveNonTrivialCopy(const TrivialMoveNonTrivialCopy&) {} // NOLINT + TrivialMoveNonTrivialCopy(TrivialMoveNonTrivialCopy&&) = default; +}; +struct TrivialCopyNonTrivialMove { + TrivialCopyNonTrivialMove(const TrivialCopyNonTrivialMove&) = default; + TrivialCopyNonTrivialMove(TrivialCopyNonTrivialMove&&) {} // NOLINT +}; + +TEST(ShouldPreferPassByValue, Basic) { + static_assert(ShouldPreferPassByValue<int>::value); + static_assert(ShouldPreferPassByValue<void*>::value); + static_assert(ShouldPreferPassByValue<UnscopedEnum>::value); + static_assert(ShouldPreferPassByValue<ScopedEnum>::value); + static_assert(ShouldPreferPassByValue<TrivialUnion>::value); + static_assert(ShouldPreferPassByValue<std::string_view>::value); + static_assert(ShouldPreferPassByValue<std::pair<int, int>>::value); + static_assert(ShouldPreferPassByValue<std::pair<char, int>>::value); + static_assert(ShouldPreferPassByValue<TrivialMoveNonTrivialCopy>::value); + static_assert(!ShouldPreferPassByValue<TrivialCopyNonTrivialMove>::value); + static_assert(!ShouldPreferPassByValue<void>::value); + static_assert(!ShouldPreferPassByValue<char[3]>::value); + static_assert(!ShouldPreferPassByValue<char[4]>::value); + static_assert(!ShouldPreferPassByValue<std::string>::value); + static_assert(!ShouldPreferPassByValue<std::shared_ptr<int>>::value); +} + } // namespace +} // namespace type_traits_internal +ABSL_NAMESPACE_END +} // namespace absl