Simplify absl::strings_internal::IsStrictlyBaseOfAndConvertibleToSTLContainer PiperOrigin-RevId: 929910722 Change-Id: I24f4d01582bff54232f64bbc2c9b8ce379332806
diff --git a/absl/strings/internal/stl_type_traits.h b/absl/strings/internal/stl_type_traits.h index ae8454d..6298921 100644 --- a/absl/strings/internal/stl_type_traits.h +++ b/absl/strings/internal/stl_type_traits.h
@@ -25,6 +25,8 @@ #ifndef ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ #define ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ +#include <stddef.h> + #include <array> #include <bitset> #include <deque> @@ -43,212 +45,97 @@ ABSL_NAMESPACE_BEGIN namespace strings_internal { -template <typename C, template <typename...> class T> -struct IsSpecializationImpl : std::false_type {}; -template <template <typename...> class T, typename... Args> -struct IsSpecializationImpl<T<Args...>, T> : std::true_type {}; -template <typename C, template <typename...> class T> -using IsSpecialization = IsSpecializationImpl<std::decay_t<C>, T>; +template <typename To, typename From> +using IsCastableToDerivedSTLContainer = + std::enable_if_t<!std::is_same_v<From, To>, std::is_convertible<From, To>>; template <typename C> -struct IsArrayImpl : std::false_type {}; -template <template <typename, size_t> class A, typename T, size_t N> -struct IsArrayImpl<A<T, N>> : std::is_same<A<T, N>, std::array<T, N>> {}; -template <typename C> -using IsArray = IsArrayImpl<std::decay_t<C>>; +std::false_type CastableToDerivedSTLContainer(C*); -template <typename C> -struct IsBitsetImpl : std::false_type {}; -template <template <size_t> class B, size_t N> -struct IsBitsetImpl<B<N>> : std::is_same<B<N>, std::bitset<N>> {}; -template <typename C> -using IsBitset = IsBitsetImpl<std::decay_t<C>>; +template <typename C, typename V, size_t N> +IsCastableToDerivedSTLContainer<C, std::array<typename C::value_type, N>> +CastableToDerivedSTLContainer(std::array<V, N>*); -template <typename C> -struct IsSTLContainer - : std::disjunction< - IsArray<C>, IsBitset<C>, IsSpecialization<C, std::deque>, - IsSpecialization<C, std::forward_list>, - IsSpecialization<C, std::list>, IsSpecialization<C, std::map>, - IsSpecialization<C, std::multimap>, IsSpecialization<C, std::set>, - IsSpecialization<C, std::multiset>, - IsSpecialization<C, std::unordered_map>, - IsSpecialization<C, std::unordered_multimap>, - IsSpecialization<C, std::unordered_set>, - IsSpecialization<C, std::unordered_multiset>, - IsSpecialization<C, std::vector>> {}; +template <typename C, size_t N> +IsCastableToDerivedSTLContainer<C, std::bitset<N>> +CastableToDerivedSTLContainer(std::bitset<N>*); -template <typename C, template <typename...> class T, typename = void> -struct IsBaseOfSpecializationImpl : std::false_type {}; -// IsBaseOfSpecializationImpl needs multiple partial specializations to SFINAE -// on the existence of container dependent types and plug them into the STL -// template. -template <typename C, template <typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, std::void_t<typename C::value_type, typename C::allocator_type>> - : std::is_base_of<C, - T<typename C::value_type, typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, - std::void_t<typename C::key_type, typename C::key_compare, - typename C::allocator_type>> - : std::is_base_of<C, T<typename C::key_type, typename C::key_compare, - typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, - std::void_t<typename C::key_type, typename C::mapped_type, +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::deque<typename C::value_type, typename C::allocator_type>> +CastableToDerivedSTLContainer(std::deque<U...>*); + +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::forward_list<typename C::value_type, typename C::allocator_type>> +CastableToDerivedSTLContainer(std::forward_list<U...>*); + +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::list<typename C::value_type, typename C::allocator_type>> +CastableToDerivedSTLContainer(std::list<U...>*); + +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::map<typename C::key_type, typename C::mapped_type, typename C::key_compare, typename C::allocator_type>> - : std::is_base_of<C, - T<typename C::key_type, typename C::mapped_type, - typename C::key_compare, typename C::allocator_type>> { -}; -template <typename C, template <typename, typename, typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, - // Roundabout equivalent of std::void_t that works around a template - // redefinition error from Clang. - std::conditional_t< - true, void, - std::common_type<typename C::key_type, typename C::hasher, - typename C::key_equal, typename C::allocator_type>>> - : std::is_base_of<C, T<typename C::key_type, typename C::hasher, - typename C::key_equal, typename C::allocator_type>> { -}; -template <typename C, - template <typename, typename, typename, typename, typename> class T> -struct IsBaseOfSpecializationImpl< - C, T, - std::void_t<typename C::key_type, typename C::mapped_type, - typename C::hasher, typename C::key_equal, +CastableToDerivedSTLContainer(std::map<U...>*); + +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::multimap<typename C::key_type, typename C::mapped_type, + typename C::key_compare, typename C::allocator_type>> +CastableToDerivedSTLContainer(std::multimap<U...>*); + +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::set<typename C::value_type, typename C::key_compare, typename C::allocator_type>> - : std::is_base_of<C, T<typename C::key_type, typename C::mapped_type, - typename C::hasher, typename C::key_equal, - typename C::allocator_type>> {}; -template <typename C, template <typename...> class T> -using IsBaseOfSpecialization = IsBaseOfSpecializationImpl<std::decay_t<C>, T>; +CastableToDerivedSTLContainer(std::set<U...>*); -template <typename C> -struct IsBaseOfArrayImpl : std::false_type {}; -template <template <typename, size_t> class A, typename T, size_t N> -struct IsBaseOfArrayImpl<A<T, N>> : std::is_base_of<A<T, N>, std::array<T, N>> { -}; -template <typename C> -using IsBaseOfArray = IsBaseOfArrayImpl<std::decay_t<C>>; +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::multiset<typename C::value_type, typename C::key_compare, + typename C::allocator_type>> +CastableToDerivedSTLContainer(std::multiset<U...>*); -template <typename C> -struct IsBaseOfBitsetImpl : std::false_type {}; -template <template <size_t> class B, size_t N> -struct IsBaseOfBitsetImpl<B<N>> : std::is_base_of<B<N>, std::bitset<N>> {}; -template <typename C> -using IsBaseOfBitset = IsBaseOfBitsetImpl<std::decay_t<C>>; +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::unordered_map<typename C::key_type, typename C::mapped_type, + typename C::hasher, typename C::key_equal, + typename C::allocator_type>> +CastableToDerivedSTLContainer(std::unordered_map<U...>*); -template <typename C> -struct IsBaseOfSTLContainer - : std::disjunction<IsBaseOfArray<C>, IsBaseOfBitset<C>, - IsBaseOfSpecialization<C, std::deque>, - IsBaseOfSpecialization<C, std::forward_list>, - IsBaseOfSpecialization<C, std::list>, - IsBaseOfSpecialization<C, std::map>, - IsBaseOfSpecialization<C, std::multimap>, - IsBaseOfSpecialization<C, std::set>, - IsBaseOfSpecialization<C, std::multiset>, - IsBaseOfSpecialization<C, std::unordered_map>, - IsBaseOfSpecialization<C, std::unordered_multimap>, - IsBaseOfSpecialization<C, std::unordered_set>, - IsBaseOfSpecialization<C, std::unordered_multiset>, - IsBaseOfSpecialization<C, std::vector>> {}; - -template <typename C, template <typename...> class T, typename = void> -struct IsConvertibleToSpecializationImpl : std::false_type {}; -// IsConvertibleToSpecializationImpl needs multiple partial specializations to -// SFINAE on the existence of container dependent types and plug them into the -// STL template. -template <typename C, template <typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, std::void_t<typename C::value_type, typename C::allocator_type>> - : std::is_convertible< - C, T<typename C::value_type, typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, - std::void_t<typename C::key_type, typename C::key_compare, - typename C::allocator_type>> - : std::is_convertible<C, T<typename C::key_type, typename C::key_compare, - typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, - std::void_t<typename C::key_type, typename C::mapped_type, - typename C::key_compare, typename C::allocator_type>> - : std::is_convertible< - C, T<typename C::key_type, typename C::mapped_type, - typename C::key_compare, typename C::allocator_type>> {}; -template <typename C, template <typename, typename, typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, - // Roundabout equivalent of std::void_t that works around a template - // redefinition error from Clang. - std::conditional_t< - true, void, - std::common_type<typename C::key_type, typename C::hasher, - typename C::key_equal, typename C::allocator_type>>> - : std::is_convertible< - C, T<typename C::key_type, typename C::hasher, typename C::key_equal, - typename C::allocator_type>> {}; -template <typename C, - template <typename, typename, typename, typename, typename> class T> -struct IsConvertibleToSpecializationImpl< - C, T, - std::void_t<typename C::key_type, typename C::mapped_type, - typename C::hasher, typename C::key_equal, - typename C::allocator_type>> - : std::is_convertible<C, T<typename C::key_type, typename C::mapped_type, +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::unordered_multimap<typename C::key_type, typename C::mapped_type, typename C::hasher, typename C::key_equal, - typename C::allocator_type>> {}; -template <typename C, template <typename...> class T> -using IsConvertibleToSpecialization = - IsConvertibleToSpecializationImpl<std::decay_t<C>, T>; + typename C::allocator_type>> +CastableToDerivedSTLContainer(std::unordered_multimap<U...>*); -template <typename C> -struct IsConvertibleToArrayImpl : std::false_type {}; -template <template <typename, size_t> class A, typename T, size_t N> -struct IsConvertibleToArrayImpl<A<T, N>> - : std::is_convertible<A<T, N>, std::array<T, N>> {}; -template <typename C> -using IsConvertibleToArray = IsConvertibleToArrayImpl<std::decay_t<C>>; +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::unordered_set<typename C::key_type, typename C::hasher, + typename C::key_equal, typename C::allocator_type>> +CastableToDerivedSTLContainer(std::unordered_set<U...>*); -template <typename C> -struct IsConvertibleToBitsetImpl : std::false_type {}; -template <template <size_t> class B, size_t N> -struct IsConvertibleToBitsetImpl<B<N>> - : std::is_convertible<B<N>, std::bitset<N>> {}; -template <typename C> -using IsConvertibleToBitset = IsConvertibleToBitsetImpl<std::decay_t<C>>; +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, + std::unordered_multiset<typename C::key_type, typename C::hasher, + typename C::key_equal, typename C::allocator_type>> +CastableToDerivedSTLContainer(std::unordered_multiset<U...>*); -template <typename C> -struct IsConvertibleToSTLContainer - : std::disjunction< - IsConvertibleToArray<C>, IsConvertibleToBitset<C>, - IsConvertibleToSpecialization<C, std::deque>, - IsConvertibleToSpecialization<C, std::forward_list>, - IsConvertibleToSpecialization<C, std::list>, - IsConvertibleToSpecialization<C, std::map>, - IsConvertibleToSpecialization<C, std::multimap>, - IsConvertibleToSpecialization<C, std::set>, - IsConvertibleToSpecialization<C, std::multiset>, - IsConvertibleToSpecialization<C, std::unordered_map>, - IsConvertibleToSpecialization<C, std::unordered_multimap>, - IsConvertibleToSpecialization<C, std::unordered_set>, - IsConvertibleToSpecialization<C, std::unordered_multiset>, - IsConvertibleToSpecialization<C, std::vector>> {}; +template <typename C, typename... U> +IsCastableToDerivedSTLContainer< + C, std::vector<typename C::value_type, typename C::allocator_type>> +CastableToDerivedSTLContainer(std::vector<U...>*); template <typename C> struct IsStrictlyBaseOfAndConvertibleToSTLContainer - : std::conjunction<std::negation<IsSTLContainer<C>>, - IsBaseOfSTLContainer<C>, - IsConvertibleToSTLContainer<C>> {}; + : decltype(strings_internal::CastableToDerivedSTLContainer< + absl::remove_cvref_t<C>>( + std::declval<absl::remove_cvref_t<C>*>())) {}; } // namespace strings_internal ABSL_NAMESPACE_END