Move kIsMoveSameAsCopy and IsAllocMoveSameAsCopy to absl/meta/type_traits.h and factor out IsDefaultAlloc logic PiperOrigin-RevId: 1008270403
diff --git a/absl/container/internal/raw_hash_map.h b/absl/container/internal/raw_hash_map.h index 3495905..645b447 100644 --- a/absl/container/internal/raw_hash_map.h +++ b/absl/container/internal/raw_hash_map.h
@@ -84,8 +84,8 @@ // separate move-only overloads. template <class K, bool Value, bool ExtraConstraint = true> using LifetimeBoundK = std::bool_constant< - (ExtraConstraint || - !IsAllocMoveSameAsCopy<absl::remove_cvref_t<K>, Alloc>::value) && + (ExtraConstraint || !type_traits_internal::IsAllocMoveSameAsCopy< + absl::remove_cvref_t<K>, Alloc>::value) && HasValue<Value, std::conditional_t< policy_trait_element_is_owner<Policy>::value, std::false_type, @@ -383,16 +383,13 @@ // (example: https://godbolt.org/z/nefW93T6K) if constexpr (type_traits_internal::ShouldPreferPassByValueOverRRef< - 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) { + std::conditional_t<sizeof...(Args) == 0 && + type_traits_internal:: + IsDefaultAlloc<Alloc>::value, + 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 8f07678..7a18275 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -2355,55 +2355,6 @@ TypeList<Policy, Hash, Eq, Alloc>>::type; }; -template <class T> -using HasTrivialCopyAndMove = - std::bool_constant<std::is_trivially_copy_constructible_v<T> && - std::is_trivially_move_constructible_v<T>>; - -// In principle, being trivially copy- and move-constructible is sufficient -// (though not necessary) for proving copy and move equivalence. However, we -// can't even test that for all types, because not all types are complete at the -// point of evaluation of this trait. Therefore, we restrict this trait to a -// subset of common types that we know to be complete at the point of evaluation -// of this trait. -template <class T> -inline constexpr bool kIsMoveSameAsCopy = HasTrivialCopyAndMove< - std::conditional_t<(!std::is_class_v<T> && !std::is_union_v<T>) || - std::is_same_v<T, std::type_index> || - std::is_same_v<T, absl::string_view>, - T, void>>::value; - -template <class T, class Traits> -inline constexpr bool kIsMoveSameAsCopy<std::basic_string_view<T, Traits>> = - std::is_trivially_copy_constructible_v<std::basic_string_view<T, Traits>>; - -template <class T, size_t N> -inline constexpr bool kIsMoveSameAsCopy<std::array<T, N>> = - kIsMoveSameAsCopy<T>; - -template <class T> -inline constexpr bool kIsMoveSameAsCopy<std::optional<T>> = - kIsMoveSameAsCopy<T>; - -template <class T1, class T2> -inline constexpr bool kIsMoveSameAsCopy<std::pair<T1, T2>> = - kIsMoveSameAsCopy<T1> && kIsMoveSameAsCopy<T2>; - -template <class... T> -inline constexpr bool kIsMoveSameAsCopy<std::tuple<T...>> = - (true && ... && kIsMoveSameAsCopy<T>); - -template <class... T> -inline constexpr bool kIsMoveSameAsCopy<std::variant<T...>> = - (true && ... && kIsMoveSameAsCopy<T>); - -template <class T, class Alloc = std::allocator<T>> -using IsAllocMoveSameAsCopy = - std::bool_constant<kIsMoveSameAsCopy<std::conditional_t< - std::is_same_v<std::allocator<T>, typename std::allocator_traits< - Alloc>::template rebind_alloc<T>>, - T, void>>>; - // This is a 'struct' instead of 'using' in order to avoid eager evaluation for // callers that may be passing incomplete types. template <class T> @@ -2416,10 +2367,9 @@ }; template <class T, class Alloc = std::allocator<T>> -using PreferredMoveParamType = - typename std::conditional_t<IsAllocMoveSameAsCopy<T, Alloc>::value, - AddConstRefIfExpensive<T>, - std::add_rvalue_reference<T>>::type; +using PreferredMoveParamType = typename std::conditional_t< + type_traits_internal::IsAllocMoveSameAsCopy<T, Alloc>::value, + AddConstRefIfExpensive<T>, std::add_rvalue_reference<T>>::type; // A SwissTable. // @@ -2587,9 +2537,9 @@ // Bit-fields cannot be moved, and types with trivial copy and move // constructors should also not be moved. template <class T> - using EnableElementMoveFrom = - std::bool_constant<std::is_pointer_v<T*> && - !IsAllocMoveSameAsCopy<T, Alloc>::value>; + using EnableElementMoveFrom = std::bool_constant< + std::is_pointer_v<T*> && + !type_traits_internal::IsAllocMoveSameAsCopy<T, Alloc>::value>; // RequiresNotInit is a workaround for gcc prior to 7.1. // See https://godbolt.org/g/Y4xsUh.
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index 51dfb27..4738693 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h
@@ -35,13 +35,18 @@ #ifndef ABSL_META_TYPE_TRAITS_H_ #define ABSL_META_TYPE_TRAITS_H_ +#include <limits.h> + #include <array> #include <cstddef> #include <functional> +#include <memory> +#include <optional> #include <string> #include <string_view> #include <tuple> #include <type_traits> +#include <typeindex> #include <utility> #include <variant> #include <vector> @@ -66,6 +71,10 @@ namespace absl { ABSL_NAMESPACE_BEGIN +#ifndef ABSL_USES_STD_STRING_VIEW +class string_view; +#endif + namespace type_traits_internal { template <typename... Ts> @@ -636,6 +645,66 @@ IsView<absl::remove_cvref_t<T>>>; template <class T> +using HasTrivialCopyAndMove = + std::bool_constant<std::is_trivially_copy_constructible_v<T> && + std::is_trivially_move_constructible_v<T>>; + +// In principle, being trivially copy- and move-constructible is sufficient +// (though not necessary) for proving copy and move equivalence. However, we +// can't even test that for all types, because not all types are complete at the +// point of evaluation of this trait. Therefore, we restrict this trait to a +// subset of common types that we know to be complete at the point of evaluation +// of this trait. +template <class T> +inline constexpr bool kIsMoveSameAsCopy = + HasTrivialCopyAndMove<std::conditional_t< + std::is_class_v<T> || std::is_union_v<T>, void, T>>::value; + +template <class T, class Traits> +inline constexpr bool kIsMoveSameAsCopy<std::basic_string_view<T, Traits>> = + std::is_trivially_copy_constructible_v<std::basic_string_view<T, Traits>>; + +template <class T, size_t N> +inline constexpr bool kIsMoveSameAsCopy<std::array<T, N>> = + kIsMoveSameAsCopy<T>; + +template <class T> +inline constexpr bool kIsMoveSameAsCopy<std::optional<T>> = + kIsMoveSameAsCopy<T>; + +template <class T1, class T2> +inline constexpr bool kIsMoveSameAsCopy<std::pair<T1, T2>> = + kIsMoveSameAsCopy<T1> && kIsMoveSameAsCopy<T2>; + +template <class... T> +inline constexpr bool kIsMoveSameAsCopy<std::tuple<T...>> = + (true && ... && kIsMoveSameAsCopy<T>); + +template <> +inline constexpr bool kIsMoveSameAsCopy<std::type_index> = true; + +template <class... T> +inline constexpr bool kIsMoveSameAsCopy<std::variant<T...>> = + (true && ... && kIsMoveSameAsCopy<T>); + +#ifndef ABSL_USES_STD_STRING_VIEW +template <> +inline constexpr bool kIsMoveSameAsCopy<absl::string_view> = + kIsMoveSameAsCopy<std::string_view>; +#endif + +template <class Alloc> +using IsDefaultAlloc = std::is_same< + std::allocator<typename std::allocator_traits<Alloc>::value_type>, + typename std::allocator_traits<Alloc>::template rebind_alloc< + typename std::allocator_traits<Alloc>::value_type>>; + +template <class T, class Alloc = std::allocator<T>> +using IsAllocMoveSameAsCopy = + std::bool_constant<type_traits_internal::kIsMoveSameAsCopy< + std::conditional_t<IsDefaultAlloc<Alloc>::value, T, void>>>; + +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 && @@ -645,20 +714,15 @@ 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 ShouldPreferPassByValueOverRRef = - std::bool_constant<ShouldSemanticallyPreferPassByValue<T>::value && - ShouldStructurallyPreferPassByValue<std::conditional_t< - std::is_void_v<T>, char, T>>::value>; +using ShouldPreferPassByValueOverRRef = ShouldStructurallyPreferPassByValue< + std::conditional_t<std::is_trivially_move_constructible_v<T> && + std::is_trivially_destructible_v<T>, + T, char[SHRT_MAX]>>; } // namespace type_traits_internal