[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