[libcxx-commits] [libcxx] [libc++] Add __detected_or_t and use it to implement some of the allocator traits aliases (PR #115654)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sat Nov 23 03:49:03 PST 2024


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/115654

>From d75e83a3cdd9239bec28de9641ea112239094e8d Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 10 Nov 2024 13:17:34 +0100
Subject: [PATCH] [libc++] Add __detected_or_t and use it to implement some of
 the allocator traits aliases

---
 libcxx/include/CMakeLists.txt              |  1 +
 libcxx/include/__memory/allocator_traits.h | 95 +++++++++-------------
 libcxx/include/__memory/unique_ptr.h       |  4 +-
 libcxx/include/__type_traits/detected_or.h | 36 ++++++++
 libcxx/include/module.modulemap            |  1 +
 5 files changed, 80 insertions(+), 57 deletions(-)
 create mode 100644 libcxx/include/__type_traits/detected_or.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 0ae031e5365aef..2bb6d263340d30 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -761,6 +761,7 @@ set(files
   __type_traits/decay.h
   __type_traits/dependent_type.h
   __type_traits/desugars_to.h
+  __type_traits/detected_or.h
   __type_traits/disjunction.h
   __type_traits/enable_if.h
   __type_traits/extent.h
diff --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h
index 499b30b85b6c9b..62b454c9227523 100644
--- a/libcxx/include/__memory/allocator_traits.h
+++ b/libcxx/include/__memory/allocator_traits.h
@@ -15,6 +15,7 @@
 #include <__fwd/memory.h>
 #include <__memory/construct_at.h>
 #include <__memory/pointer_traits.h>
+#include <__type_traits/detected_or.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/is_constructible.h>
 #include <__type_traits/is_empty.h>
@@ -42,17 +43,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
   struct NAME<_Tp, __void_t<typename _Tp::PROPERTY > > : true_type {}
 
 // __pointer
-template <class _Tp,
-          class _Alloc,
-          class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
-          bool            = __has_pointer<_RawAlloc>::value>
-struct __pointer {
-  using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer;
-};
-template <class _Tp, class _Alloc, class _RawAlloc>
-struct __pointer<_Tp, _Alloc, _RawAlloc, false> {
-  using type _LIBCPP_NODEBUG = _Tp*;
-};
+template <class _Tp>
+using __pointer_member = typename _Tp::pointer;
+
+template <class _Tp, class _Alloc>
+using __pointer = __detected_or_t<_Tp*, __pointer_member, __libcpp_remove_reference_t<_Alloc> >;
 
 // __const_pointer
 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_pointer, const_pointer);
@@ -100,13 +95,11 @@ struct __const_void_pointer<_Ptr, _Alloc, false> {
 };
 
 // __size_type
-_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_size_type, size_type);
-template <class _Alloc, class _DiffType, bool = __has_size_type<_Alloc>::value>
-struct __size_type : make_unsigned<_DiffType> {};
+template <class _Tp>
+using __size_type_member = typename _Tp::size_type;
+
 template <class _Alloc, class _DiffType>
-struct __size_type<_Alloc, _DiffType, true> {
-  using type _LIBCPP_NODEBUG = typename _Alloc::size_type;
-};
+using __size_type = __detected_or_t<__make_unsigned_t<_DiffType>, __size_type_member, _Alloc>;
 
 // __alloc_traits_difference_type
 _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_alloc_traits_difference_type, difference_type);
@@ -120,40 +113,34 @@ struct __alloc_traits_difference_type<_Alloc, _Ptr, true> {
 };
 
 // __propagate_on_container_copy_assignment
-_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_copy_assignment, propagate_on_container_copy_assignment);
-template <class _Alloc, bool = __has_propagate_on_container_copy_assignment<_Alloc>::value>
-struct __propagate_on_container_copy_assignment : false_type {};
+template <class _Tp>
+using __propagate_on_container_copy_assignment_member = typename _Tp::propagate_on_container_copy_assignment;
+
 template <class _Alloc>
-struct __propagate_on_container_copy_assignment<_Alloc, true> {
-  using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_copy_assignment;
-};
+using __propagate_on_container_copy_assignment =
+    __detected_or_t<false_type, __propagate_on_container_copy_assignment_member, _Alloc>;
 
 // __propagate_on_container_move_assignment
-_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_move_assignment, propagate_on_container_move_assignment);
-template <class _Alloc, bool = __has_propagate_on_container_move_assignment<_Alloc>::value>
-struct __propagate_on_container_move_assignment : false_type {};
+template <class _Tp>
+using __propagate_on_container_move_assignment_member = typename _Tp::propagate_on_container_move_assignment;
+
 template <class _Alloc>
-struct __propagate_on_container_move_assignment<_Alloc, true> {
-  using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_move_assignment;
-};
+using __propagate_on_container_move_assignment =
+    __detected_or_t<false_type, __propagate_on_container_move_assignment_member, _Alloc>;
 
 // __propagate_on_container_swap
-_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_swap, propagate_on_container_swap);
-template <class _Alloc, bool = __has_propagate_on_container_swap<_Alloc>::value>
-struct __propagate_on_container_swap : false_type {};
+template <class _Tp>
+using __propagate_on_container_swap_member = typename _Tp::propagate_on_container_swap;
+
 template <class _Alloc>
-struct __propagate_on_container_swap<_Alloc, true> {
-  using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_swap;
-};
+using __propagate_on_container_swap = __detected_or_t<false_type, __propagate_on_container_swap_member, _Alloc>;
 
 // __is_always_equal
-_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_is_always_equal, is_always_equal);
-template <class _Alloc, bool = __has_is_always_equal<_Alloc>::value>
-struct __is_always_equal : is_empty<_Alloc> {};
+template <class _Tp>
+using __is_always_equal_member = typename _Tp::is_always_equal;
+
 template <class _Alloc>
-struct __is_always_equal<_Alloc, true> {
-  using type _LIBCPP_NODEBUG = typename _Alloc::is_always_equal;
-};
+using __is_always_equal = __detected_or_t<typename is_empty<_Alloc>::type, __is_always_equal_member, _Alloc>;
 
 // __allocator_traits_rebind
 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
@@ -245,20 +232,18 @@ _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(allocation_result);
 
 template <class _Alloc>
 struct _LIBCPP_TEMPLATE_VIS allocator_traits {
-  using allocator_type     = _Alloc;
-  using value_type         = typename allocator_type::value_type;
-  using pointer            = typename __pointer<value_type, allocator_type>::type;
-  using const_pointer      = typename __const_pointer<value_type, pointer, allocator_type>::type;
-  using void_pointer       = typename __void_pointer<pointer, allocator_type>::type;
-  using const_void_pointer = typename __const_void_pointer<pointer, allocator_type>::type;
-  using difference_type    = typename __alloc_traits_difference_type<allocator_type, pointer>::type;
-  using size_type          = typename __size_type<allocator_type, difference_type>::type;
-  using propagate_on_container_copy_assignment =
-      typename __propagate_on_container_copy_assignment<allocator_type>::type;
-  using propagate_on_container_move_assignment =
-      typename __propagate_on_container_move_assignment<allocator_type>::type;
-  using propagate_on_container_swap = typename __propagate_on_container_swap<allocator_type>::type;
-  using is_always_equal             = typename __is_always_equal<allocator_type>::type;
+  using allocator_type                         = _Alloc;
+  using value_type                             = typename allocator_type::value_type;
+  using pointer                                = __pointer<value_type, allocator_type>;
+  using const_pointer                          = typename __const_pointer<value_type, pointer, allocator_type>::type;
+  using void_pointer                           = typename __void_pointer<pointer, allocator_type>::type;
+  using const_void_pointer                     = typename __const_void_pointer<pointer, allocator_type>::type;
+  using difference_type                        = typename __alloc_traits_difference_type<allocator_type, pointer>::type;
+  using size_type                              = __size_type<allocator_type, difference_type>;
+  using propagate_on_container_copy_assignment = __propagate_on_container_copy_assignment<allocator_type>;
+  using propagate_on_container_move_assignment = __propagate_on_container_move_assignment<allocator_type>;
+  using propagate_on_container_swap            = __propagate_on_container_swap<allocator_type>;
+  using is_always_equal                        = __is_always_equal<allocator_type>;
 
 #ifndef _LIBCPP_CXX03_LANG
   template <class _Tp>
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 28c62e13566e24..9526255583dd56 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -143,7 +143,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
 public:
   typedef _Tp element_type;
   typedef _Dp deleter_type;
-  typedef _LIBCPP_NODEBUG typename __pointer<_Tp, deleter_type>::type pointer;
+  using pointer _LIBCPP_NODEBUG = __pointer<_Tp, deleter_type>;
 
   static_assert(!is_rvalue_reference<deleter_type>::value, "the specified deleter type cannot be an rvalue reference");
 
@@ -410,7 +410,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
 public:
   typedef _Tp element_type;
   typedef _Dp deleter_type;
-  typedef typename __pointer<_Tp, deleter_type>::type pointer;
+  using pointer = __pointer<_Tp, deleter_type>;
 
   // A unique_ptr contains the following members which may be trivially relocatable:
   // - pointer: this may be trivially relocatable, so it's checked
diff --git a/libcxx/include/__type_traits/detected_or.h b/libcxx/include/__type_traits/detected_or.h
new file mode 100644
index 00000000000000..390f368411471e
--- /dev/null
+++ b/libcxx/include/__type_traits/detected_or.h
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_DETECTED_OR_H
+#define _LIBCPP___TYPE_TRAITS_DETECTED_OR_H
+
+#include <__config>
+#include <__type_traits/void_t.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Default, class _Void, template <class...> class _Op, class... _Args>
+struct __detector {
+  using type = _Default;
+};
+
+template <class _Default, template <class...> class _Op, class... _Args>
+struct __detector<_Default, __void_t<_Op<_Args...> >, _Op, _Args...> {
+  using type = _Op<_Args...>;
+};
+
+template <class _Default, template <class...> class _Op, class... _Args>
+using __detected_or_t = typename __detector<_Default, void, _Op, _Args...>::type;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_DETECTED_OR_H
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 4e06a68c6a6b61..ed2b7fb1921642 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -87,6 +87,7 @@ module std_core [system] {
     module decay                                      { header "__type_traits/decay.h" }
     module dependent_type                             { header "__type_traits/dependent_type.h" }
     module desugars_to                                { header "__type_traits/desugars_to.h" }
+    module detected_or                                { header "__type_traits/detected_or.h" }
     module disjunction                                { header "__type_traits/disjunction.h" }
     module enable_if                                  { header "__type_traits/enable_if.h" }
     module extent                                     { header "__type_traits/extent.h" }



More information about the libcxx-commits mailing list