diff options
-rw-r--r-- | absl/meta/type_traits.h | 101 | ||||
-rw-r--r-- | absl/meta/type_traits_test.cc | 22 |
2 files changed, 123 insertions, 0 deletions
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index a15059de..ded55820 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -37,11 +37,21 @@ #include <cstddef> #include <functional> +#include <string> #include <type_traits> +#include <vector> #include "absl/base/attributes.h" #include "absl/base/config.h" +#ifdef __cpp_lib_span +#include <span> // NOLINT(build/c++20) +#endif + +#ifdef ABSL_HAVE_STD_STRING_VIEW +#include <string_view> +#endif + // Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17 // feature. #if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) @@ -553,6 +563,97 @@ constexpr bool is_constant_evaluated() noexcept { #endif } #endif // ABSL_HAVE_CONSTANT_EVALUATED + +namespace type_traits_internal { + +// Detects if a class's definition has declared itself to be an owner by +// declaring +// using absl_internal_is_view = std::true_type; +// as a member. +// Types that don't want either must either omit this declaration entirely, or +// (if e.g. inheriting from a base class) define the member to something that +// isn't a Boolean trait class, such as `void`. +// Do not specialize or use this directly. It's an implementation detail. +template <typename T, typename = void> +struct IsOwnerImpl : std::false_type { + static_assert(std::is_same<T, absl::remove_cvref_t<T>>::value, + "type must lack qualifiers"); +}; + +template <typename T> +struct IsOwnerImpl< + T, + std::enable_if_t<std::is_class<typename T::absl_internal_is_view>::value>> + : absl::negation<typename T::absl_internal_is_view> {}; + +// A trait to determine whether a type is an owner. +// Do *not* depend on the correctness of this trait for correct code behavior. +// It is only a safety feature and its value may change in the future. +// Do not specialize this; instead, define the member trait inside your type so +// that it can be auto-detected, and to prevent ODR violations. +// If it ever becomes possible to detect [[gsl::Owner]], we should leverage it: +// https://wg21.link/p1179 +template <typename T> +struct IsOwner : IsOwnerImpl<T> {}; + +template <typename T, typename Traits, typename Alloc> +struct IsOwner<std::basic_string<T, Traits, Alloc>> : std::true_type {}; + +template <typename T, typename Alloc> +struct IsOwner<std::vector<T, Alloc>> : std::true_type {}; + +// Detects if a class's definition has declared itself to be a view by declaring +// using absl_internal_is_view = std::true_type; +// as a member. +// Do not specialize or use this directly. +template <typename T, typename = void> +struct IsViewImpl : std::false_type { + static_assert(std::is_same<T, absl::remove_cvref_t<T>>::value, + "type must lack qualifiers"); +}; + +template <typename T> +struct IsViewImpl< + T, + std::enable_if_t<std::is_class<typename T::absl_internal_is_view>::value>> + : T::absl_internal_is_view {}; + +// A trait to determine whether a type is a view. +// Do *not* depend on the correctness of this trait for correct code behavior. +// It is only a safety feature, and its value may change in the future. +// Do not specialize this trait. Instead, define the member +// using absl_internal_is_view = std::true_type; +// in your class to allow its detection while preventing ODR violations. +// If it ever becomes possible to detect [[gsl::Pointer]], we should leverage +// it: https://wg21.link/p1179 +template <typename T> +struct IsView : std::integral_constant<bool, std::is_pointer<T>::value || + IsViewImpl<T>::value> {}; + +#ifdef ABSL_HAVE_STD_STRING_VIEW +template <typename Char, typename Traits> +struct IsView<std::basic_string_view<Char, Traits>> : std::true_type {}; +#endif + +#ifdef __cpp_lib_span +template <typename T> +struct IsView<std::span<T>> : std::true_type {}; +#endif + +// Determines whether the assignment of the given types is lifetime-bound. +// Do *not* depend on the correctness of this trait for correct code behavior. +// It is only a safety feature and its value may change in the future. +// If it ever becomes possible to detect [[clang::lifetimebound]] directly, +// we should change the implementation to leverage that. +// Until then, we consider an assignment from an "owner" (such as std::string) +// to a "view" (such as std::string_view) to be a lifetime-bound assignment. +template <typename T, typename U> +using IsLifetimeBoundAssignment = + std::integral_constant<bool, IsView<absl::remove_cvref_t<T>>::value && + IsOwner<absl::remove_cvref_t<U>>::value>; + +} // namespace type_traits_internal + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index 6080beef..1e056bb2 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc @@ -26,10 +26,32 @@ #include "absl/time/clock.h" #include "absl/time/time.h" +#ifdef ABSL_HAVE_STD_STRING_VIEW +#include <string_view> +#endif + namespace { using ::testing::StaticAssertTypeEq; +template <typename T> +using IsOwnerAndNotView = + absl::conjunction<absl::type_traits_internal::IsOwner<T>, + absl::negation<absl::type_traits_internal::IsView<T>>>; + +static_assert(IsOwnerAndNotView<std::vector<int>>::value, + "vector is an owner, not a view"); +static_assert(IsOwnerAndNotView<std::string>::value, + "string is an owner, not a view"); +static_assert(IsOwnerAndNotView<std::wstring>::value, + "wstring is an owner, not a view"); +#ifdef ABSL_HAVE_STD_STRING_VIEW +static_assert(!IsOwnerAndNotView<std::string_view>::value, + "string_view is a view, not an owner"); +static_assert(!IsOwnerAndNotView<std::wstring_view>::value, + "wstring_view is a view, not an owner"); +#endif + template <class T, class U> struct simple_pair { T first; |