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