xref: /freebsd-src/contrib/llvm-project/libcxx/include/__iterator/iterator_traits.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1fe6060f1SDimitry Andric // -*- C++ -*-
2fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
3fe6060f1SDimitry Andric //
4fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7fe6060f1SDimitry Andric //
8fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
9fe6060f1SDimitry Andric 
10fe6060f1SDimitry Andric #ifndef _LIBCPP___ITERATOR_ITERATOR_TRAITS_H
11fe6060f1SDimitry Andric #define _LIBCPP___ITERATOR_ITERATOR_TRAITS_H
12fe6060f1SDimitry Andric 
13bdd1243dSDimitry Andric #include <__concepts/arithmetic.h>
14bdd1243dSDimitry Andric #include <__concepts/constructible.h>
15bdd1243dSDimitry Andric #include <__concepts/convertible_to.h>
16bdd1243dSDimitry Andric #include <__concepts/copyable.h>
17bdd1243dSDimitry Andric #include <__concepts/equality_comparable.h>
18bdd1243dSDimitry Andric #include <__concepts/same_as.h>
19bdd1243dSDimitry Andric #include <__concepts/totally_ordered.h>
20fe6060f1SDimitry Andric #include <__config>
21bdd1243dSDimitry Andric #include <__fwd/pair.h>
22fe6060f1SDimitry Andric #include <__iterator/incrementable_traits.h>
23fe6060f1SDimitry Andric #include <__iterator/readable_traits.h>
24bdd1243dSDimitry Andric #include <__type_traits/common_reference.h>
25bdd1243dSDimitry Andric #include <__type_traits/conditional.h>
26bdd1243dSDimitry Andric #include <__type_traits/disjunction.h>
27bdd1243dSDimitry Andric #include <__type_traits/is_convertible.h>
28bdd1243dSDimitry Andric #include <__type_traits/is_object.h>
29bdd1243dSDimitry Andric #include <__type_traits/is_primary_template.h>
30bdd1243dSDimitry Andric #include <__type_traits/is_reference.h>
31bdd1243dSDimitry Andric #include <__type_traits/is_valid_expansion.h>
32bdd1243dSDimitry Andric #include <__type_traits/remove_const.h>
33bdd1243dSDimitry Andric #include <__type_traits/remove_cv.h>
34bdd1243dSDimitry Andric #include <__type_traits/remove_cvref.h>
35bdd1243dSDimitry Andric #include <__type_traits/void_t.h>
36bdd1243dSDimitry Andric #include <__utility/declval.h>
3761cfbce3SDimitry Andric #include <cstddef>
38fe6060f1SDimitry Andric 
39fe6060f1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
40fe6060f1SDimitry Andric #  pragma GCC system_header
41fe6060f1SDimitry Andric #endif
42fe6060f1SDimitry Andric 
43fe6060f1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
44fe6060f1SDimitry Andric 
4506c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
46fe6060f1SDimitry Andric 
47fe6060f1SDimitry Andric template <class _Tp>
48fe6060f1SDimitry Andric using __with_reference = _Tp&;
49fe6060f1SDimitry Andric 
50fe6060f1SDimitry Andric template <class _Tp>
51cb14a3feSDimitry Andric concept __can_reference = requires { typename __with_reference<_Tp>; };
52fe6060f1SDimitry Andric 
53fe6060f1SDimitry Andric template <class _Tp>
54fe6060f1SDimitry Andric concept __dereferenceable = requires(_Tp& __t) {
5581ad6265SDimitry Andric   { *__t } -> __can_reference; // not required to be equality-preserving
56fe6060f1SDimitry Andric };
57fe6060f1SDimitry Andric 
58fe6060f1SDimitry Andric // [iterator.traits]
59fe6060f1SDimitry Andric template <__dereferenceable _Tp>
60bdd1243dSDimitry Andric using iter_reference_t = decltype(*std::declval<_Tp&>());
61fe6060f1SDimitry Andric 
6206c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 20
63fe6060f1SDimitry Andric 
64fe6060f1SDimitry Andric template <class _Iter>
65fe6060f1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS iterator_traits;
66fe6060f1SDimitry Andric 
67fe6060f1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS input_iterator_tag {};
68fe6060f1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS output_iterator_tag {};
69fe6060f1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS forward_iterator_tag : public input_iterator_tag {};
70fe6060f1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS bidirectional_iterator_tag : public forward_iterator_tag {};
71fe6060f1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS random_access_iterator_tag : public bidirectional_iterator_tag {};
7206c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
73fe6060f1SDimitry Andric struct _LIBCPP_TEMPLATE_VIS contiguous_iterator_tag : public random_access_iterator_tag {};
74fe6060f1SDimitry Andric #endif
75fe6060f1SDimitry Andric 
76fe6060f1SDimitry Andric template <class _Iter>
77fe6060f1SDimitry Andric struct __iter_traits_cache {
78cb14a3feSDimitry Andric   using type = _If< __is_primary_template<iterator_traits<_Iter> >::value, _Iter, iterator_traits<_Iter> >;
79fe6060f1SDimitry Andric };
80fe6060f1SDimitry Andric template <class _Iter>
81fe6060f1SDimitry Andric using _ITER_TRAITS = typename __iter_traits_cache<_Iter>::type;
82fe6060f1SDimitry Andric 
83fe6060f1SDimitry Andric struct __iter_concept_concept_test {
84fe6060f1SDimitry Andric   template <class _Iter>
85fe6060f1SDimitry Andric   using _Apply = typename _ITER_TRAITS<_Iter>::iterator_concept;
86fe6060f1SDimitry Andric };
87fe6060f1SDimitry Andric struct __iter_concept_category_test {
88fe6060f1SDimitry Andric   template <class _Iter>
89fe6060f1SDimitry Andric   using _Apply = typename _ITER_TRAITS<_Iter>::iterator_category;
90fe6060f1SDimitry Andric };
91fe6060f1SDimitry Andric struct __iter_concept_random_fallback {
92fe6060f1SDimitry Andric   template <class _Iter>
93cb14a3feSDimitry Andric   using _Apply = __enable_if_t< __is_primary_template<iterator_traits<_Iter> >::value, random_access_iterator_tag >;
94fe6060f1SDimitry Andric };
95fe6060f1SDimitry Andric 
96cb14a3feSDimitry Andric template <class _Iter, class _Tester>
97cb14a3feSDimitry Andric struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {};
98fe6060f1SDimitry Andric 
99fe6060f1SDimitry Andric template <class _Iter>
100fe6060f1SDimitry Andric struct __iter_concept_cache {
101cb14a3feSDimitry Andric   using type = _Or< __test_iter_concept<_Iter, __iter_concept_concept_test>,
102fe6060f1SDimitry Andric                     __test_iter_concept<_Iter, __iter_concept_category_test>,
103cb14a3feSDimitry Andric                     __test_iter_concept<_Iter, __iter_concept_random_fallback> >;
104fe6060f1SDimitry Andric };
105fe6060f1SDimitry Andric 
106fe6060f1SDimitry Andric template <class _Iter>
107fe6060f1SDimitry Andric using _ITER_CONCEPT = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>;
108fe6060f1SDimitry Andric 
109fe6060f1SDimitry Andric template <class _Tp>
110cb14a3feSDimitry Andric struct __has_iterator_typedefs {
111fe6060f1SDimitry Andric private:
112cb14a3feSDimitry Andric   template <class _Up>
113cb14a3feSDimitry Andric   static false_type __test(...);
114cb14a3feSDimitry Andric   template <class _Up>
115cb14a3feSDimitry Andric   static true_type
116cb14a3feSDimitry Andric   __test(__void_t<typename _Up::iterator_category>* = nullptr,
117bdd1243dSDimitry Andric          __void_t<typename _Up::difference_type>*   = nullptr,
118bdd1243dSDimitry Andric          __void_t<typename _Up::value_type>*        = nullptr,
119bdd1243dSDimitry Andric          __void_t<typename _Up::reference>*         = nullptr,
120bdd1243dSDimitry Andric          __void_t<typename _Up::pointer>*           = nullptr);
121cb14a3feSDimitry Andric 
122fe6060f1SDimitry Andric public:
1237a6dacacSDimitry Andric   static const bool value = decltype(__test<_Tp>(nullptr, nullptr, nullptr, nullptr, nullptr))::value;
124fe6060f1SDimitry Andric };
125fe6060f1SDimitry Andric 
126fe6060f1SDimitry Andric template <class _Tp>
127cb14a3feSDimitry Andric struct __has_iterator_category {
128fe6060f1SDimitry Andric private:
129cb14a3feSDimitry Andric   template <class _Up>
130cb14a3feSDimitry Andric   static false_type __test(...);
131cb14a3feSDimitry Andric   template <class _Up>
132cb14a3feSDimitry Andric   static true_type __test(typename _Up::iterator_category* = nullptr);
133cb14a3feSDimitry Andric 
134fe6060f1SDimitry Andric public:
13581ad6265SDimitry Andric   static const bool value = decltype(__test<_Tp>(nullptr))::value;
136fe6060f1SDimitry Andric };
137fe6060f1SDimitry Andric 
138fe6060f1SDimitry Andric template <class _Tp>
139cb14a3feSDimitry Andric struct __has_iterator_concept {
140fe6060f1SDimitry Andric private:
141cb14a3feSDimitry Andric   template <class _Up>
142cb14a3feSDimitry Andric   static false_type __test(...);
143cb14a3feSDimitry Andric   template <class _Up>
144cb14a3feSDimitry Andric   static true_type __test(typename _Up::iterator_concept* = nullptr);
145cb14a3feSDimitry Andric 
146fe6060f1SDimitry Andric public:
14781ad6265SDimitry Andric   static const bool value = decltype(__test<_Tp>(nullptr))::value;
148fe6060f1SDimitry Andric };
149fe6060f1SDimitry Andric 
15006c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
151fe6060f1SDimitry Andric 
15281ad6265SDimitry Andric // The `cpp17-*-iterator` exposition-only concepts have very similar names to the `Cpp17*Iterator` named requirements
15381ad6265SDimitry Andric // from `[iterator.cpp17]`. To avoid confusion between the two, the exposition-only concepts have been banished to
15481ad6265SDimitry Andric // a "detail" namespace indicating they have a niche use-case.
155fe6060f1SDimitry Andric namespace __iterator_traits_detail {
156fe6060f1SDimitry Andric template <class _Ip>
157cb14a3feSDimitry Andric concept __cpp17_iterator = requires(_Ip __i) {
15881ad6265SDimitry Andric   { *__i } -> __can_reference;
159fe6060f1SDimitry Andric   { ++__i } -> same_as<_Ip&>;
16081ad6265SDimitry Andric   { *__i++ } -> __can_reference;
161cb14a3feSDimitry Andric } && copyable<_Ip>;
162fe6060f1SDimitry Andric 
163fe6060f1SDimitry Andric template <class _Ip>
164cb14a3feSDimitry Andric concept __cpp17_input_iterator = __cpp17_iterator<_Ip> && equality_comparable<_Ip> && requires(_Ip __i) {
165fe6060f1SDimitry Andric   typename incrementable_traits<_Ip>::difference_type;
166fe6060f1SDimitry Andric   typename indirectly_readable_traits<_Ip>::value_type;
167cb14a3feSDimitry Andric   typename common_reference_t<iter_reference_t<_Ip>&&, typename indirectly_readable_traits<_Ip>::value_type&>;
168cb14a3feSDimitry Andric   typename common_reference_t<decltype(*__i++)&&, typename indirectly_readable_traits<_Ip>::value_type&>;
169fe6060f1SDimitry Andric   requires signed_integral<typename incrementable_traits<_Ip>::difference_type>;
170fe6060f1SDimitry Andric };
171fe6060f1SDimitry Andric 
172fe6060f1SDimitry Andric template <class _Ip>
173fe6060f1SDimitry Andric concept __cpp17_forward_iterator =
174cb14a3feSDimitry Andric     __cpp17_input_iterator<_Ip> && constructible_from<_Ip> && is_reference_v<iter_reference_t<_Ip>> &&
175cb14a3feSDimitry Andric     same_as<remove_cvref_t<iter_reference_t<_Ip>>, typename indirectly_readable_traits<_Ip>::value_type> &&
176fe6060f1SDimitry Andric     requires(_Ip __i) {
177fe6060f1SDimitry Andric       { __i++ } -> convertible_to<_Ip const&>;
178fe6060f1SDimitry Andric       { *__i++ } -> same_as<iter_reference_t<_Ip>>;
179fe6060f1SDimitry Andric     };
180fe6060f1SDimitry Andric 
181fe6060f1SDimitry Andric template <class _Ip>
182cb14a3feSDimitry Andric concept __cpp17_bidirectional_iterator = __cpp17_forward_iterator<_Ip> && requires(_Ip __i) {
183fe6060f1SDimitry Andric   { --__i } -> same_as<_Ip&>;
184fe6060f1SDimitry Andric   { __i-- } -> convertible_to<_Ip const&>;
185fe6060f1SDimitry Andric   { *__i-- } -> same_as<iter_reference_t<_Ip>>;
186fe6060f1SDimitry Andric };
187fe6060f1SDimitry Andric 
188fe6060f1SDimitry Andric template <class _Ip>
189fe6060f1SDimitry Andric concept __cpp17_random_access_iterator =
190cb14a3feSDimitry Andric     __cpp17_bidirectional_iterator<_Ip> && totally_ordered<_Ip> &&
191fe6060f1SDimitry Andric     requires(_Ip __i, typename incrementable_traits<_Ip>::difference_type __n) {
192fe6060f1SDimitry Andric       { __i += __n } -> same_as<_Ip&>;
193fe6060f1SDimitry Andric       { __i -= __n } -> same_as<_Ip&>;
194fe6060f1SDimitry Andric       { __i + __n } -> same_as<_Ip>;
195fe6060f1SDimitry Andric       { __n + __i } -> same_as<_Ip>;
196fe6060f1SDimitry Andric       { __i - __n } -> same_as<_Ip>;
19781ad6265SDimitry Andric       { __i - __i } -> same_as<decltype(__n)>; // NOLINT(misc-redundant-expression) ; This is llvm.org/PR54114
198fe6060f1SDimitry Andric       { __i[__n] } -> convertible_to<iter_reference_t<_Ip>>;
199fe6060f1SDimitry Andric     };
200fe6060f1SDimitry Andric } // namespace __iterator_traits_detail
201fe6060f1SDimitry Andric 
202fe6060f1SDimitry Andric template <class _Ip>
203fe6060f1SDimitry Andric concept __has_member_reference = requires { typename _Ip::reference; };
204fe6060f1SDimitry Andric 
205fe6060f1SDimitry Andric template <class _Ip>
206fe6060f1SDimitry Andric concept __has_member_pointer = requires { typename _Ip::pointer; };
207fe6060f1SDimitry Andric 
208fe6060f1SDimitry Andric template <class _Ip>
209fe6060f1SDimitry Andric concept __has_member_iterator_category = requires { typename _Ip::iterator_category; };
210fe6060f1SDimitry Andric 
211fe6060f1SDimitry Andric template <class _Ip>
212fe6060f1SDimitry Andric concept __specifies_members = requires {
213fe6060f1SDimitry Andric   typename _Ip::value_type;
214fe6060f1SDimitry Andric   typename _Ip::difference_type;
215fe6060f1SDimitry Andric   requires __has_member_reference<_Ip>;
216fe6060f1SDimitry Andric   requires __has_member_iterator_category<_Ip>;
217fe6060f1SDimitry Andric };
218fe6060f1SDimitry Andric 
219fe6060f1SDimitry Andric template <class>
220fe6060f1SDimitry Andric struct __iterator_traits_member_pointer_or_void {
221fe6060f1SDimitry Andric   using type = void;
222fe6060f1SDimitry Andric };
223fe6060f1SDimitry Andric 
224fe6060f1SDimitry Andric template <__has_member_pointer _Tp>
225fe6060f1SDimitry Andric struct __iterator_traits_member_pointer_or_void<_Tp> {
226fe6060f1SDimitry Andric   using type = typename _Tp::pointer;
227fe6060f1SDimitry Andric };
228fe6060f1SDimitry Andric 
229fe6060f1SDimitry Andric template <class _Tp>
230cb14a3feSDimitry Andric concept __cpp17_iterator_missing_members = !__specifies_members<_Tp> && __iterator_traits_detail::__cpp17_iterator<_Tp>;
231fe6060f1SDimitry Andric 
232fe6060f1SDimitry Andric template <class _Tp>
233fe6060f1SDimitry Andric concept __cpp17_input_iterator_missing_members =
234cb14a3feSDimitry Andric     __cpp17_iterator_missing_members<_Tp> && __iterator_traits_detail::__cpp17_input_iterator<_Tp>;
235fe6060f1SDimitry Andric 
236fe6060f1SDimitry Andric // Otherwise, `pointer` names `void`.
237fe6060f1SDimitry Andric template <class>
238cb14a3feSDimitry Andric struct __iterator_traits_member_pointer_or_arrow_or_void {
239cb14a3feSDimitry Andric   using type = void;
240cb14a3feSDimitry Andric };
241fe6060f1SDimitry Andric 
242fe6060f1SDimitry Andric // [iterator.traits]/3.2.1
243fe6060f1SDimitry Andric // If the qualified-id `I::pointer` is valid and denotes a type, `pointer` names that type.
244fe6060f1SDimitry Andric template <__has_member_pointer _Ip>
245cb14a3feSDimitry Andric struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> {
246cb14a3feSDimitry Andric   using type = typename _Ip::pointer;
247cb14a3feSDimitry Andric };
248fe6060f1SDimitry Andric 
249fe6060f1SDimitry Andric // Otherwise, if `decltype(declval<I&>().operator->())` is well-formed, then `pointer` names that
250fe6060f1SDimitry Andric // type.
251fe6060f1SDimitry Andric template <class _Ip>
252fe6060f1SDimitry Andric   requires requires(_Ip& __i) { __i.operator->(); } && (!__has_member_pointer<_Ip>)
253fe6060f1SDimitry Andric struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> {
254bdd1243dSDimitry Andric   using type = decltype(std::declval<_Ip&>().operator->());
255fe6060f1SDimitry Andric };
256fe6060f1SDimitry Andric 
257fe6060f1SDimitry Andric // Otherwise, `reference` names `iter-reference-t<I>`.
258fe6060f1SDimitry Andric template <class _Ip>
259cb14a3feSDimitry Andric struct __iterator_traits_member_reference {
260cb14a3feSDimitry Andric   using type = iter_reference_t<_Ip>;
261cb14a3feSDimitry Andric };
262fe6060f1SDimitry Andric 
263fe6060f1SDimitry Andric // [iterator.traits]/3.2.2
264fe6060f1SDimitry Andric // If the qualified-id `I::reference` is valid and denotes a type, `reference` names that type.
265fe6060f1SDimitry Andric template <__has_member_reference _Ip>
266cb14a3feSDimitry Andric struct __iterator_traits_member_reference<_Ip> {
267cb14a3feSDimitry Andric   using type = typename _Ip::reference;
268cb14a3feSDimitry Andric };
269fe6060f1SDimitry Andric 
270fe6060f1SDimitry Andric // [iterator.traits]/3.2.3.4
271fe6060f1SDimitry Andric // input_iterator_tag
272fe6060f1SDimitry Andric template <class _Ip>
273fe6060f1SDimitry Andric struct __deduce_iterator_category {
274fe6060f1SDimitry Andric   using type = input_iterator_tag;
275fe6060f1SDimitry Andric };
276fe6060f1SDimitry Andric 
277fe6060f1SDimitry Andric // [iterator.traits]/3.2.3.1
278fe6060f1SDimitry Andric // `random_access_iterator_tag` if `I` satisfies `cpp17-random-access-iterator`, or otherwise
279fe6060f1SDimitry Andric template <__iterator_traits_detail::__cpp17_random_access_iterator _Ip>
280fe6060f1SDimitry Andric struct __deduce_iterator_category<_Ip> {
281fe6060f1SDimitry Andric   using type = random_access_iterator_tag;
282fe6060f1SDimitry Andric };
283fe6060f1SDimitry Andric 
284fe6060f1SDimitry Andric // [iterator.traits]/3.2.3.2
285fe6060f1SDimitry Andric // `bidirectional_iterator_tag` if `I` satisfies `cpp17-bidirectional-iterator`, or otherwise
286fe6060f1SDimitry Andric template <__iterator_traits_detail::__cpp17_bidirectional_iterator _Ip>
287fe6060f1SDimitry Andric struct __deduce_iterator_category<_Ip> {
288fe6060f1SDimitry Andric   using type = bidirectional_iterator_tag;
289fe6060f1SDimitry Andric };
290fe6060f1SDimitry Andric 
291fe6060f1SDimitry Andric // [iterator.traits]/3.2.3.3
292fe6060f1SDimitry Andric // `forward_iterator_tag` if `I` satisfies `cpp17-forward-iterator`, or otherwise
293fe6060f1SDimitry Andric template <__iterator_traits_detail::__cpp17_forward_iterator _Ip>
294fe6060f1SDimitry Andric struct __deduce_iterator_category<_Ip> {
295fe6060f1SDimitry Andric   using type = forward_iterator_tag;
296fe6060f1SDimitry Andric };
297fe6060f1SDimitry Andric 
298fe6060f1SDimitry Andric template <class _Ip>
299fe6060f1SDimitry Andric struct __iterator_traits_iterator_category : __deduce_iterator_category<_Ip> {};
300fe6060f1SDimitry Andric 
301fe6060f1SDimitry Andric // [iterator.traits]/3.2.3
302fe6060f1SDimitry Andric // If the qualified-id `I::iterator-category` is valid and denotes a type, `iterator-category` names
303fe6060f1SDimitry Andric // that type.
304fe6060f1SDimitry Andric template <__has_member_iterator_category _Ip>
305fe6060f1SDimitry Andric struct __iterator_traits_iterator_category<_Ip> {
306fe6060f1SDimitry Andric   using type = typename _Ip::iterator_category;
307fe6060f1SDimitry Andric };
308fe6060f1SDimitry Andric 
309fe6060f1SDimitry Andric // otherwise, it names void.
310fe6060f1SDimitry Andric template <class>
311cb14a3feSDimitry Andric struct __iterator_traits_difference_type {
312cb14a3feSDimitry Andric   using type = void;
313cb14a3feSDimitry Andric };
314fe6060f1SDimitry Andric 
315fe6060f1SDimitry Andric // If the qualified-id `incrementable_traits<I>::difference_type` is valid and denotes a type, then
316fe6060f1SDimitry Andric // `difference_type` names that type;
317fe6060f1SDimitry Andric template <class _Ip>
318fe6060f1SDimitry Andric   requires requires { typename incrementable_traits<_Ip>::difference_type; }
319fe6060f1SDimitry Andric struct __iterator_traits_difference_type<_Ip> {
320fe6060f1SDimitry Andric   using type = typename incrementable_traits<_Ip>::difference_type;
321fe6060f1SDimitry Andric };
322fe6060f1SDimitry Andric 
323fe6060f1SDimitry Andric // [iterator.traits]/3.4
324fe6060f1SDimitry Andric // Otherwise, `iterator_traits<I>` has no members by any of the above names.
325fe6060f1SDimitry Andric template <class>
326fe6060f1SDimitry Andric struct __iterator_traits {};
327fe6060f1SDimitry Andric 
328fe6060f1SDimitry Andric // [iterator.traits]/3.1
329fe6060f1SDimitry Andric // If `I` has valid ([temp.deduct]) member types `difference-type`, `value-type`, `reference`, and
330fe6060f1SDimitry Andric // `iterator-category`, then `iterator-traits<I>` has the following publicly accessible members:
331fe6060f1SDimitry Andric template <__specifies_members _Ip>
332fe6060f1SDimitry Andric struct __iterator_traits<_Ip> {
333fe6060f1SDimitry Andric   using iterator_category = typename _Ip::iterator_category;
334fe6060f1SDimitry Andric   using value_type        = typename _Ip::value_type;
335fe6060f1SDimitry Andric   using difference_type   = typename _Ip::difference_type;
336fe6060f1SDimitry Andric   using pointer           = typename __iterator_traits_member_pointer_or_void<_Ip>::type;
337fe6060f1SDimitry Andric   using reference         = typename _Ip::reference;
338fe6060f1SDimitry Andric };
339fe6060f1SDimitry Andric 
340fe6060f1SDimitry Andric // [iterator.traits]/3.2
341fe6060f1SDimitry Andric // Otherwise, if `I` satisfies the exposition-only concept `cpp17-input-iterator`,
342fe6060f1SDimitry Andric // `iterator-traits<I>` has the following publicly accessible members:
343fe6060f1SDimitry Andric template <__cpp17_input_iterator_missing_members _Ip>
344fe6060f1SDimitry Andric struct __iterator_traits<_Ip> {
345fe6060f1SDimitry Andric   using iterator_category = typename __iterator_traits_iterator_category<_Ip>::type;
346fe6060f1SDimitry Andric   using value_type        = typename indirectly_readable_traits<_Ip>::value_type;
347fe6060f1SDimitry Andric   using difference_type   = typename incrementable_traits<_Ip>::difference_type;
348fe6060f1SDimitry Andric   using pointer           = typename __iterator_traits_member_pointer_or_arrow_or_void<_Ip>::type;
349fe6060f1SDimitry Andric   using reference         = typename __iterator_traits_member_reference<_Ip>::type;
350fe6060f1SDimitry Andric };
351fe6060f1SDimitry Andric 
352fe6060f1SDimitry Andric // Otherwise, if `I` satisfies the exposition-only concept `cpp17-iterator`, then
353fe6060f1SDimitry Andric // `iterator_traits<I>` has the following publicly accessible members:
354fe6060f1SDimitry Andric template <__cpp17_iterator_missing_members _Ip>
355fe6060f1SDimitry Andric struct __iterator_traits<_Ip> {
356fe6060f1SDimitry Andric   using iterator_category = output_iterator_tag;
357fe6060f1SDimitry Andric   using value_type        = void;
358fe6060f1SDimitry Andric   using difference_type   = typename __iterator_traits_difference_type<_Ip>::type;
359fe6060f1SDimitry Andric   using pointer           = void;
360fe6060f1SDimitry Andric   using reference         = void;
361fe6060f1SDimitry Andric };
362fe6060f1SDimitry Andric 
363fe6060f1SDimitry Andric template <class _Ip>
364fe6060f1SDimitry Andric struct iterator_traits : __iterator_traits<_Ip> {
365fe6060f1SDimitry Andric   using __primary_template = iterator_traits;
366fe6060f1SDimitry Andric };
367fe6060f1SDimitry Andric 
36806c3fb27SDimitry Andric #else  // _LIBCPP_STD_VER >= 20
369fe6060f1SDimitry Andric 
370cb14a3feSDimitry Andric template <class _Iter, bool>
371cb14a3feSDimitry Andric struct __iterator_traits {};
372fe6060f1SDimitry Andric 
373cb14a3feSDimitry Andric template <class _Iter, bool>
374cb14a3feSDimitry Andric struct __iterator_traits_impl {};
375fe6060f1SDimitry Andric 
376fe6060f1SDimitry Andric template <class _Iter>
377cb14a3feSDimitry Andric struct __iterator_traits_impl<_Iter, true> {
378fe6060f1SDimitry Andric   typedef typename _Iter::difference_type difference_type;
379fe6060f1SDimitry Andric   typedef typename _Iter::value_type value_type;
380fe6060f1SDimitry Andric   typedef typename _Iter::pointer pointer;
381fe6060f1SDimitry Andric   typedef typename _Iter::reference reference;
382fe6060f1SDimitry Andric   typedef typename _Iter::iterator_category iterator_category;
383fe6060f1SDimitry Andric };
384fe6060f1SDimitry Andric 
385fe6060f1SDimitry Andric template <class _Iter>
386fe6060f1SDimitry Andric struct __iterator_traits<_Iter, true>
387cb14a3feSDimitry Andric     : __iterator_traits_impl< _Iter,
388fe6060f1SDimitry Andric                               is_convertible<typename _Iter::iterator_category, input_iterator_tag>::value ||
389cb14a3feSDimitry Andric                                   is_convertible<typename _Iter::iterator_category, output_iterator_tag>::value > {};
390fe6060f1SDimitry Andric 
391fe6060f1SDimitry Andric // iterator_traits<Iterator> will only have the nested types if Iterator::iterator_category
392fe6060f1SDimitry Andric //    exists.  Else iterator_traits<Iterator> will be an empty class.  This is a
393fe6060f1SDimitry Andric //    conforming extension which allows some programs to compile and behave as
394fe6060f1SDimitry Andric //    the client expects instead of failing at compile time.
395fe6060f1SDimitry Andric 
396fe6060f1SDimitry Andric template <class _Iter>
397cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS iterator_traits : __iterator_traits<_Iter, __has_iterator_typedefs<_Iter>::value> {
398fe6060f1SDimitry Andric   using __primary_template = iterator_traits;
399fe6060f1SDimitry Andric };
40006c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 20
401fe6060f1SDimitry Andric 
402fe6060f1SDimitry Andric template <class _Tp>
40306c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
404fe6060f1SDimitry Andric   requires is_object_v<_Tp>
405fe6060f1SDimitry Andric #endif
406cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*> {
407fe6060f1SDimitry Andric   typedef ptrdiff_t difference_type;
408bdd1243dSDimitry Andric   typedef __remove_cv_t<_Tp> value_type;
409fe6060f1SDimitry Andric   typedef _Tp* pointer;
410fe6060f1SDimitry Andric   typedef _Tp& reference;
411fe6060f1SDimitry Andric   typedef random_access_iterator_tag iterator_category;
41206c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
413fe6060f1SDimitry Andric   typedef contiguous_iterator_tag iterator_concept;
414fe6060f1SDimitry Andric #endif
415fe6060f1SDimitry Andric };
416fe6060f1SDimitry Andric 
417fe6060f1SDimitry Andric template <class _Tp, class _Up, bool = __has_iterator_category<iterator_traits<_Tp> >::value>
418cb14a3feSDimitry Andric struct __has_iterator_category_convertible_to : is_convertible<typename iterator_traits<_Tp>::iterator_category, _Up> {
419cb14a3feSDimitry Andric };
420fe6060f1SDimitry Andric 
421fe6060f1SDimitry Andric template <class _Tp, class _Up>
422fe6060f1SDimitry Andric struct __has_iterator_category_convertible_to<_Tp, _Up, false> : false_type {};
423fe6060f1SDimitry Andric 
424fe6060f1SDimitry Andric template <class _Tp, class _Up, bool = __has_iterator_concept<_Tp>::value>
425cb14a3feSDimitry Andric struct __has_iterator_concept_convertible_to : is_convertible<typename _Tp::iterator_concept, _Up> {};
426fe6060f1SDimitry Andric 
427fe6060f1SDimitry Andric template <class _Tp, class _Up>
428fe6060f1SDimitry Andric struct __has_iterator_concept_convertible_to<_Tp, _Up, false> : false_type {};
429fe6060f1SDimitry Andric 
430fe6060f1SDimitry Andric template <class _Tp>
43106c3fb27SDimitry Andric using __has_input_iterator_category = __has_iterator_category_convertible_to<_Tp, input_iterator_tag>;
432fe6060f1SDimitry Andric 
433fe6060f1SDimitry Andric template <class _Tp>
43406c3fb27SDimitry Andric using __has_forward_iterator_category = __has_iterator_category_convertible_to<_Tp, forward_iterator_tag>;
435fe6060f1SDimitry Andric 
436fe6060f1SDimitry Andric template <class _Tp>
43706c3fb27SDimitry Andric using __has_bidirectional_iterator_category = __has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag>;
438fe6060f1SDimitry Andric 
439fe6060f1SDimitry Andric template <class _Tp>
44006c3fb27SDimitry Andric using __has_random_access_iterator_category = __has_iterator_category_convertible_to<_Tp, random_access_iterator_tag>;
441fe6060f1SDimitry Andric 
44206c3fb27SDimitry Andric // __libcpp_is_contiguous_iterator determines if an iterator is known by
443fe6060f1SDimitry Andric // libc++ to be contiguous, either because it advertises itself as such
444fe6060f1SDimitry Andric // (in C++20) or because it is a pointer type or a known trivial wrapper
445fe6060f1SDimitry Andric // around a (possibly fancy) pointer type, such as __wrap_iter<T*>.
446fe6060f1SDimitry Andric // Such iterators receive special "contiguous" optimizations in
447fe6060f1SDimitry Andric // std::copy and std::sort.
448fe6060f1SDimitry Andric //
44906c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
450fe6060f1SDimitry Andric template <class _Tp>
451cb14a3feSDimitry Andric struct __libcpp_is_contiguous_iterator
452cb14a3feSDimitry Andric     : _Or< __has_iterator_category_convertible_to<_Tp, contiguous_iterator_tag>,
453cb14a3feSDimitry Andric            __has_iterator_concept_convertible_to<_Tp, contiguous_iterator_tag> > {};
454fe6060f1SDimitry Andric #else
455fe6060f1SDimitry Andric template <class _Tp>
45606c3fb27SDimitry Andric struct __libcpp_is_contiguous_iterator : false_type {};
457fe6060f1SDimitry Andric #endif
458fe6060f1SDimitry Andric 
459fe6060f1SDimitry Andric // Any native pointer which is an iterator is also a contiguous iterator.
460fe6060f1SDimitry Andric template <class _Up>
46106c3fb27SDimitry Andric struct __libcpp_is_contiguous_iterator<_Up*> : true_type {};
462fe6060f1SDimitry Andric 
46381ad6265SDimitry Andric template <class _Iter>
46481ad6265SDimitry Andric class __wrap_iter;
46581ad6265SDimitry Andric 
466fe6060f1SDimitry Andric template <class _Tp>
467cb14a3feSDimitry Andric using __has_exactly_input_iterator_category =
468cb14a3feSDimitry Andric     integral_constant<bool,
469fe6060f1SDimitry Andric                       __has_iterator_category_convertible_to<_Tp, input_iterator_tag>::value &&
47006c3fb27SDimitry Andric                           !__has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value>;
471fe6060f1SDimitry Andric 
472753f127fSDimitry Andric template <class _Tp>
473cb14a3feSDimitry Andric using __has_exactly_forward_iterator_category =
474cb14a3feSDimitry Andric     integral_constant<bool,
475753f127fSDimitry Andric                       __has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value &&
47606c3fb27SDimitry Andric                           !__has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag>::value>;
477753f127fSDimitry Andric 
478753f127fSDimitry Andric template <class _Tp>
479cb14a3feSDimitry Andric using __has_exactly_bidirectional_iterator_category =
480cb14a3feSDimitry Andric     integral_constant<bool,
481753f127fSDimitry Andric                       __has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag>::value &&
48206c3fb27SDimitry Andric                           !__has_iterator_category_convertible_to<_Tp, random_access_iterator_tag>::value>;
483753f127fSDimitry Andric 
484fe6060f1SDimitry Andric template <class _InputIterator>
485fe6060f1SDimitry Andric using __iter_value_type = typename iterator_traits<_InputIterator>::value_type;
486fe6060f1SDimitry Andric 
487fe6060f1SDimitry Andric template <class _InputIterator>
488bdd1243dSDimitry Andric using __iter_key_type = __remove_const_t<typename iterator_traits<_InputIterator>::value_type::first_type>;
489fe6060f1SDimitry Andric 
490fe6060f1SDimitry Andric template <class _InputIterator>
491fe6060f1SDimitry Andric using __iter_mapped_type = typename iterator_traits<_InputIterator>::value_type::second_type;
492fe6060f1SDimitry Andric 
493fe6060f1SDimitry Andric template <class _InputIterator>
494cb14a3feSDimitry Andric using __iter_to_alloc_type =
495*0fca6ea1SDimitry Andric     pair<const typename iterator_traits<_InputIterator>::value_type::first_type,
496fe6060f1SDimitry Andric          typename iterator_traits<_InputIterator>::value_type::second_type>;
497fe6060f1SDimitry Andric 
498972a253aSDimitry Andric template <class _Iter>
499972a253aSDimitry Andric using __iterator_category_type = typename iterator_traits<_Iter>::iterator_category;
500972a253aSDimitry Andric 
501972a253aSDimitry Andric template <class _Iter>
502972a253aSDimitry Andric using __iterator_pointer_type = typename iterator_traits<_Iter>::pointer;
503972a253aSDimitry Andric 
50461cfbce3SDimitry Andric template <class _Iter>
50561cfbce3SDimitry Andric using __iter_diff_t = typename iterator_traits<_Iter>::difference_type;
50661cfbce3SDimitry Andric 
50706c3fb27SDimitry Andric template <class _Iter>
50806c3fb27SDimitry Andric using __iter_reference = typename iterator_traits<_Iter>::reference;
50906c3fb27SDimitry Andric 
51006c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
51106c3fb27SDimitry Andric 
51206c3fb27SDimitry Andric // [readable.traits]
51306c3fb27SDimitry Andric 
51406c3fb27SDimitry Andric // Let `RI` be `remove_cvref_t<I>`. The type `iter_value_t<I>` denotes
51506c3fb27SDimitry Andric // `indirectly_readable_traits<RI>::value_type` if `iterator_traits<RI>` names a specialization
51606c3fb27SDimitry Andric // generated from the primary template, and `iterator_traits<RI>::value_type` otherwise.
51706c3fb27SDimitry Andric // This has to be in this file and not readable_traits.h to break the include cycle between the two.
51806c3fb27SDimitry Andric template <class _Ip>
519cb14a3feSDimitry Andric using iter_value_t =
520cb14a3feSDimitry Andric     typename conditional_t<__is_primary_template<iterator_traits<remove_cvref_t<_Ip> > >::value,
52106c3fb27SDimitry Andric                            indirectly_readable_traits<remove_cvref_t<_Ip> >,
52206c3fb27SDimitry Andric                            iterator_traits<remove_cvref_t<_Ip> > >::value_type;
52306c3fb27SDimitry Andric 
52406c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 20
52561cfbce3SDimitry Andric 
526fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD
527fe6060f1SDimitry Andric 
528fe6060f1SDimitry Andric #endif // _LIBCPP___ITERATOR_ITERATOR_TRAITS_H
529