Skip to content

Commit 7ae61a3

Browse files
authored
[libc++] Add __detected_or_t and use it to implement some of the allocator traits aliases (#115654)
This simplifies the implementation a bit, since we don't need a lot of the `__has_x` classes anymore. We just need two template aliases to implement the `allocator_traits` aliases now.
1 parent 09e7477 commit 7ae61a3

File tree

5 files changed

+80
-57
lines changed

5 files changed

+80
-57
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ set(files
761761
__type_traits/decay.h
762762
__type_traits/dependent_type.h
763763
__type_traits/desugars_to.h
764+
__type_traits/detected_or.h
764765
__type_traits/disjunction.h
765766
__type_traits/enable_if.h
766767
__type_traits/extent.h

libcxx/include/__memory/allocator_traits.h

Lines changed: 40 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <__fwd/memory.h>
1616
#include <__memory/construct_at.h>
1717
#include <__memory/pointer_traits.h>
18+
#include <__type_traits/detected_or.h>
1819
#include <__type_traits/enable_if.h>
1920
#include <__type_traits/is_constructible.h>
2021
#include <__type_traits/is_empty.h>
@@ -42,17 +43,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
4243
struct NAME<_Tp, __void_t<typename _Tp::PROPERTY > > : true_type {}
4344

4445
// __pointer
45-
template <class _Tp,
46-
class _Alloc,
47-
class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
48-
bool = __has_pointer<_RawAlloc>::value>
49-
struct __pointer {
50-
using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer;
51-
};
52-
template <class _Tp, class _Alloc, class _RawAlloc>
53-
struct __pointer<_Tp, _Alloc, _RawAlloc, false> {
54-
using type _LIBCPP_NODEBUG = _Tp*;
55-
};
46+
template <class _Tp>
47+
using __pointer_member = typename _Tp::pointer;
48+
49+
template <class _Tp, class _Alloc>
50+
using __pointer = __detected_or_t<_Tp*, __pointer_member, __libcpp_remove_reference_t<_Alloc> >;
5651

5752
// __const_pointer
5853
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_pointer, const_pointer);
@@ -100,13 +95,11 @@ struct __const_void_pointer<_Ptr, _Alloc, false> {
10095
};
10196

10297
// __size_type
103-
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_size_type, size_type);
104-
template <class _Alloc, class _DiffType, bool = __has_size_type<_Alloc>::value>
105-
struct __size_type : make_unsigned<_DiffType> {};
98+
template <class _Tp>
99+
using __size_type_member = typename _Tp::size_type;
100+
106101
template <class _Alloc, class _DiffType>
107-
struct __size_type<_Alloc, _DiffType, true> {
108-
using type _LIBCPP_NODEBUG = typename _Alloc::size_type;
109-
};
102+
using __size_type = __detected_or_t<__make_unsigned_t<_DiffType>, __size_type_member, _Alloc>;
110103

111104
// __alloc_traits_difference_type
112105
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_alloc_traits_difference_type, difference_type);
@@ -120,40 +113,34 @@ struct __alloc_traits_difference_type<_Alloc, _Ptr, true> {
120113
};
121114

122115
// __propagate_on_container_copy_assignment
123-
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_copy_assignment, propagate_on_container_copy_assignment);
124-
template <class _Alloc, bool = __has_propagate_on_container_copy_assignment<_Alloc>::value>
125-
struct __propagate_on_container_copy_assignment : false_type {};
116+
template <class _Tp>
117+
using __propagate_on_container_copy_assignment_member = typename _Tp::propagate_on_container_copy_assignment;
118+
126119
template <class _Alloc>
127-
struct __propagate_on_container_copy_assignment<_Alloc, true> {
128-
using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_copy_assignment;
129-
};
120+
using __propagate_on_container_copy_assignment =
121+
__detected_or_t<false_type, __propagate_on_container_copy_assignment_member, _Alloc>;
130122

131123
// __propagate_on_container_move_assignment
132-
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_move_assignment, propagate_on_container_move_assignment);
133-
template <class _Alloc, bool = __has_propagate_on_container_move_assignment<_Alloc>::value>
134-
struct __propagate_on_container_move_assignment : false_type {};
124+
template <class _Tp>
125+
using __propagate_on_container_move_assignment_member = typename _Tp::propagate_on_container_move_assignment;
126+
135127
template <class _Alloc>
136-
struct __propagate_on_container_move_assignment<_Alloc, true> {
137-
using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_move_assignment;
138-
};
128+
using __propagate_on_container_move_assignment =
129+
__detected_or_t<false_type, __propagate_on_container_move_assignment_member, _Alloc>;
139130

140131
// __propagate_on_container_swap
141-
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_swap, propagate_on_container_swap);
142-
template <class _Alloc, bool = __has_propagate_on_container_swap<_Alloc>::value>
143-
struct __propagate_on_container_swap : false_type {};
132+
template <class _Tp>
133+
using __propagate_on_container_swap_member = typename _Tp::propagate_on_container_swap;
134+
144135
template <class _Alloc>
145-
struct __propagate_on_container_swap<_Alloc, true> {
146-
using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_swap;
147-
};
136+
using __propagate_on_container_swap = __detected_or_t<false_type, __propagate_on_container_swap_member, _Alloc>;
148137

149138
// __is_always_equal
150-
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_is_always_equal, is_always_equal);
151-
template <class _Alloc, bool = __has_is_always_equal<_Alloc>::value>
152-
struct __is_always_equal : is_empty<_Alloc> {};
139+
template <class _Tp>
140+
using __is_always_equal_member = typename _Tp::is_always_equal;
141+
153142
template <class _Alloc>
154-
struct __is_always_equal<_Alloc, true> {
155-
using type _LIBCPP_NODEBUG = typename _Alloc::is_always_equal;
156-
};
143+
using __is_always_equal = __detected_or_t<typename is_empty<_Alloc>::type, __is_always_equal_member, _Alloc>;
157144

158145
// __allocator_traits_rebind
159146
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
@@ -245,20 +232,18 @@ _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(allocation_result);
245232

246233
template <class _Alloc>
247234
struct _LIBCPP_TEMPLATE_VIS allocator_traits {
248-
using allocator_type = _Alloc;
249-
using value_type = typename allocator_type::value_type;
250-
using pointer = typename __pointer<value_type, allocator_type>::type;
251-
using const_pointer = typename __const_pointer<value_type, pointer, allocator_type>::type;
252-
using void_pointer = typename __void_pointer<pointer, allocator_type>::type;
253-
using const_void_pointer = typename __const_void_pointer<pointer, allocator_type>::type;
254-
using difference_type = typename __alloc_traits_difference_type<allocator_type, pointer>::type;
255-
using size_type = typename __size_type<allocator_type, difference_type>::type;
256-
using propagate_on_container_copy_assignment =
257-
typename __propagate_on_container_copy_assignment<allocator_type>::type;
258-
using propagate_on_container_move_assignment =
259-
typename __propagate_on_container_move_assignment<allocator_type>::type;
260-
using propagate_on_container_swap = typename __propagate_on_container_swap<allocator_type>::type;
261-
using is_always_equal = typename __is_always_equal<allocator_type>::type;
235+
using allocator_type = _Alloc;
236+
using value_type = typename allocator_type::value_type;
237+
using pointer = __pointer<value_type, allocator_type>;
238+
using const_pointer = typename __const_pointer<value_type, pointer, allocator_type>::type;
239+
using void_pointer = typename __void_pointer<pointer, allocator_type>::type;
240+
using const_void_pointer = typename __const_void_pointer<pointer, allocator_type>::type;
241+
using difference_type = typename __alloc_traits_difference_type<allocator_type, pointer>::type;
242+
using size_type = __size_type<allocator_type, difference_type>;
243+
using propagate_on_container_copy_assignment = __propagate_on_container_copy_assignment<allocator_type>;
244+
using propagate_on_container_move_assignment = __propagate_on_container_move_assignment<allocator_type>;
245+
using propagate_on_container_swap = __propagate_on_container_swap<allocator_type>;
246+
using is_always_equal = __is_always_equal<allocator_type>;
262247

263248
#ifndef _LIBCPP_CXX03_LANG
264249
template <class _Tp>

libcxx/include/__memory/unique_ptr.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
143143
public:
144144
typedef _Tp element_type;
145145
typedef _Dp deleter_type;
146-
typedef _LIBCPP_NODEBUG typename __pointer<_Tp, deleter_type>::type pointer;
146+
using pointer _LIBCPP_NODEBUG = __pointer<_Tp, deleter_type>;
147147

148148
static_assert(!is_rvalue_reference<deleter_type>::value, "the specified deleter type cannot be an rvalue reference");
149149

@@ -410,7 +410,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
410410
public:
411411
typedef _Tp element_type;
412412
typedef _Dp deleter_type;
413-
typedef typename __pointer<_Tp, deleter_type>::type pointer;
413+
using pointer = __pointer<_Tp, deleter_type>;
414414

415415
// A unique_ptr contains the following members which may be trivially relocatable:
416416
// - pointer: this may be trivially relocatable, so it's checked
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___TYPE_TRAITS_DETECTED_OR_H
10+
#define _LIBCPP___TYPE_TRAITS_DETECTED_OR_H
11+
12+
#include <__config>
13+
#include <__type_traits/void_t.h>
14+
15+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
16+
# pragma GCC system_header
17+
#endif
18+
19+
_LIBCPP_BEGIN_NAMESPACE_STD
20+
21+
template <class _Default, class _Void, template <class...> class _Op, class... _Args>
22+
struct __detector {
23+
using type = _Default;
24+
};
25+
26+
template <class _Default, template <class...> class _Op, class... _Args>
27+
struct __detector<_Default, __void_t<_Op<_Args...> >, _Op, _Args...> {
28+
using type = _Op<_Args...>;
29+
};
30+
31+
template <class _Default, template <class...> class _Op, class... _Args>
32+
using __detected_or_t = typename __detector<_Default, void, _Op, _Args...>::type;
33+
34+
_LIBCPP_END_NAMESPACE_STD
35+
36+
#endif // _LIBCPP___TYPE_TRAITS_DETECTED_OR_H

libcxx/include/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ module std_core [system] {
8787
module decay { header "__type_traits/decay.h" }
8888
module dependent_type { header "__type_traits/dependent_type.h" }
8989
module desugars_to { header "__type_traits/desugars_to.h" }
90+
module detected_or { header "__type_traits/detected_or.h" }
9091
module disjunction { header "__type_traits/disjunction.h" }
9192
module enable_if { header "__type_traits/enable_if.h" }
9293
module extent { header "__type_traits/extent.h" }

0 commit comments

Comments
 (0)