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 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: libcpp-no-concepts
11 
12 // template<class T>
13 // struct indirectly_readable_traits;
14 
15 #include <iterator>
16 
17 #include <concepts>
18 #include <memory>
19 #include <optional>
20 #include <string>
21 #include <vector>
22 
23 template <class T>
24 concept has_no_value_type = !requires {
25   typename std::indirectly_readable_traits<T>::value_type;
26 };
27 
28 template <class T, class Expected>
29 concept value_type_matches =
30   std::same_as<typename std::indirectly_readable_traits<T>::value_type, Expected>;
31 
32 template <class T>
check_pointer()33 constexpr bool check_pointer() {
34   constexpr bool result = value_type_matches<T*, T>;
35   static_assert(value_type_matches<T const*, T> == result);
36   static_assert(value_type_matches<T volatile*, T> == result);
37   static_assert(value_type_matches<T const volatile*, T> == result);
38 
39   static_assert(value_type_matches<T* const, T> == result);
40   static_assert(value_type_matches<T const* const, T> == result);
41   static_assert(value_type_matches<T volatile* const, T> == result);
42   static_assert(value_type_matches<T const volatile* const, T> == result);
43 
44   return result;
45 }
46 
47 template <class T>
check_array()48 constexpr bool check_array() {
49   static_assert(value_type_matches<T[], T>);
50   static_assert(value_type_matches<T const[], T>);
51   static_assert(value_type_matches<T volatile[], T>);
52   static_assert(value_type_matches<T const volatile[], T>);
53   static_assert(value_type_matches<T[10], T>);
54   static_assert(value_type_matches<T const[10], T>);
55   static_assert(value_type_matches<T volatile[10], T>);
56   static_assert(value_type_matches<T const volatile[10], T>);
57   return true;
58 }
59 
60 template <class T, class Expected>
check_member()61 constexpr bool check_member() {
62   static_assert(value_type_matches<T, Expected>);
63   static_assert(value_type_matches<T const, Expected>);
64   static_assert(value_type_matches<T volatile, Expected>);
65   return true;
66 }
67 
68 static_assert(check_pointer<int>());
69 static_assert(check_pointer<int*>());
70 static_assert(check_pointer<int[10]>());
71 static_assert(!check_pointer<void>());
72 static_assert(!check_pointer<int()>());
73 
74 static_assert(check_array<int>());
75 static_assert(check_array<int*>());
76 static_assert(check_array<int[10]>());
77 
78 template<class T>
79 struct ValueOf {
80   using value_type = T;
81 };
82 
83 template<class U>
84 struct ElementOf {
85   using element_type = U;
86 };
87 
88 template<class T, class U>
89 struct TwoTypes {
90   using value_type = T;
91   using element_type = U;
92 };
93 
94 static_assert(check_member<ValueOf<int>, int>());
95 static_assert(check_member<ValueOf<int[10]>, int[10]>());
96 static_assert(check_member<ValueOf<int[]>, int[]>());
97 static_assert(has_no_value_type<ValueOf<void>>);
98 static_assert(has_no_value_type<ValueOf<int()>>);
99 static_assert(has_no_value_type<ValueOf<int&>>);
100 static_assert(has_no_value_type<ValueOf<int&&>>);
101 
102 static_assert(check_member<ElementOf<int>, int>());
103 static_assert(check_member<ElementOf<int[10]>, int[10]>());
104 static_assert(check_member<ElementOf<int[]>, int[]>());
105 static_assert(has_no_value_type<ElementOf<void>>);
106 static_assert(has_no_value_type<ElementOf<int()>>);
107 static_assert(has_no_value_type<ElementOf<int&>>);
108 static_assert(has_no_value_type<ElementOf<int&&>>);
109 
110 static_assert(check_member<TwoTypes<int, int>, int>());
111 static_assert(check_member<TwoTypes<int, int const>, int>());
112 static_assert(check_member<TwoTypes<int, int volatile>, int>());
113 static_assert(check_member<TwoTypes<int, int const volatile>, int>());
114 static_assert(check_member<TwoTypes<int const, int>, int>());
115 static_assert(check_member<TwoTypes<int const, int const>, int>());
116 static_assert(check_member<TwoTypes<int const, int volatile>, int>());
117 static_assert(check_member<TwoTypes<int const, int const volatile>, int>());
118 static_assert(check_member<TwoTypes<int volatile, int>, int>());
119 static_assert(check_member<TwoTypes<int volatile, int const>, int>());
120 static_assert(check_member<TwoTypes<int volatile, int volatile>, int>());
121 static_assert(check_member<TwoTypes<int volatile, int const volatile>, int>());
122 static_assert(check_member<TwoTypes<int const volatile, int>, int>());
123 static_assert(check_member<TwoTypes<int const volatile, int const>, int>());
124 static_assert(check_member<TwoTypes<int const volatile, int volatile>, int>());
125 static_assert(check_member<TwoTypes<int const volatile, int const volatile>, int>());
126 static_assert(has_no_value_type<TwoTypes<int, long>>);
127 static_assert(has_no_value_type<TwoTypes<int, int&>>);
128 static_assert(has_no_value_type<TwoTypes<int&, int>>);
129 
130 struct S2 {};
131 template <>
132 struct std::indirectly_readable_traits<S2> {
133   using value_type = int;
134 };
135 static_assert(value_type_matches<S2, int>);
136 static_assert(value_type_matches<const S2, int>);
137 static_assert(has_no_value_type<volatile S2>);
138 static_assert(has_no_value_type<const volatile S2>);
139 static_assert(has_no_value_type<S2&>);
140 static_assert(has_no_value_type<const S2&>);
141 
142 static_assert(check_member<std::vector<int>, int>());
143 static_assert(check_member<std::vector<int>::iterator, int>());
144 static_assert(check_member<std::vector<int>::const_iterator, int>());
145 static_assert(check_member<std::istream_iterator<int>, int>());
146 static_assert(check_member<std::istreambuf_iterator<char>, char>());
147 static_assert(check_member<std::optional<int>, int>());
148 static_assert(check_member<std::shared_ptr<long>, long>());
149 static_assert(check_member<std::shared_ptr<const long>, long>());
150 static_assert(has_no_value_type<void>);
151 static_assert(has_no_value_type<int>);
152 static_assert(has_no_value_type<std::nullptr_t>);
153