1*4bdff4beSrobert // -*- C++ -*- 2*4bdff4beSrobert //===----------------------------------------------------------------------===// 3*4bdff4beSrobert // 4*4bdff4beSrobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5*4bdff4beSrobert // See https://llvm.org/LICENSE.txt for license information. 6*4bdff4beSrobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7*4bdff4beSrobert // 8*4bdff4beSrobert //===----------------------------------------------------------------------===// 9*4bdff4beSrobert 10*4bdff4beSrobert #ifndef _LIBCPP___RANGES_JOIN_VIEW_H 11*4bdff4beSrobert #define _LIBCPP___RANGES_JOIN_VIEW_H 12*4bdff4beSrobert 13*4bdff4beSrobert #include <__concepts/constructible.h> 14*4bdff4beSrobert #include <__concepts/convertible_to.h> 15*4bdff4beSrobert #include <__concepts/copyable.h> 16*4bdff4beSrobert #include <__concepts/derived_from.h> 17*4bdff4beSrobert #include <__concepts/equality_comparable.h> 18*4bdff4beSrobert #include <__config> 19*4bdff4beSrobert #include <__iterator/concepts.h> 20*4bdff4beSrobert #include <__iterator/iter_move.h> 21*4bdff4beSrobert #include <__iterator/iter_swap.h> 22*4bdff4beSrobert #include <__iterator/iterator_traits.h> 23*4bdff4beSrobert #include <__iterator/iterator_with_data.h> 24*4bdff4beSrobert #include <__iterator/segmented_iterator.h> 25*4bdff4beSrobert #include <__ranges/access.h> 26*4bdff4beSrobert #include <__ranges/all.h> 27*4bdff4beSrobert #include <__ranges/concepts.h> 28*4bdff4beSrobert #include <__ranges/empty.h> 29*4bdff4beSrobert #include <__ranges/non_propagating_cache.h> 30*4bdff4beSrobert #include <__ranges/range_adaptor.h> 31*4bdff4beSrobert #include <__ranges/view_interface.h> 32*4bdff4beSrobert #include <__type_traits/maybe_const.h> 33*4bdff4beSrobert #include <__utility/forward.h> 34*4bdff4beSrobert #include <optional> 35*4bdff4beSrobert #include <type_traits> 36*4bdff4beSrobert 37*4bdff4beSrobert #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 38*4bdff4beSrobert # pragma GCC system_header 39*4bdff4beSrobert #endif 40*4bdff4beSrobert 41*4bdff4beSrobert _LIBCPP_BEGIN_NAMESPACE_STD 42*4bdff4beSrobert 43*4bdff4beSrobert // Note: `join_view` is still marked experimental because there is an ABI-breaking change that affects `join_view` in 44*4bdff4beSrobert // the pipeline (https://isocpp.org/files/papers/D2770R0.html). 45*4bdff4beSrobert // TODO: make `join_view` non-experimental once D2770 is implemented. 46*4bdff4beSrobert #if _LIBCPP_STD_VER > 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) 47*4bdff4beSrobert 48*4bdff4beSrobert namespace ranges { 49*4bdff4beSrobert template<class> 50*4bdff4beSrobert struct __join_view_iterator_category {}; 51*4bdff4beSrobert 52*4bdff4beSrobert template<class _View> 53*4bdff4beSrobert requires is_reference_v<range_reference_t<_View>> && 54*4bdff4beSrobert forward_range<_View> && 55*4bdff4beSrobert forward_range<range_reference_t<_View>> 56*4bdff4beSrobert struct __join_view_iterator_category<_View> { 57*4bdff4beSrobert using _OuterC = typename iterator_traits<iterator_t<_View>>::iterator_category; 58*4bdff4beSrobert using _InnerC = typename iterator_traits<iterator_t<range_reference_t<_View>>>::iterator_category; 59*4bdff4beSrobert 60*4bdff4beSrobert using iterator_category = _If< 61*4bdff4beSrobert derived_from<_OuterC, bidirectional_iterator_tag> && derived_from<_InnerC, bidirectional_iterator_tag> && 62*4bdff4beSrobert common_range<range_reference_t<_View>>, 63*4bdff4beSrobert bidirectional_iterator_tag, 64*4bdff4beSrobert _If< 65*4bdff4beSrobert derived_from<_OuterC, forward_iterator_tag> && derived_from<_InnerC, forward_iterator_tag>, 66*4bdff4beSrobert forward_iterator_tag, 67*4bdff4beSrobert input_iterator_tag 68*4bdff4beSrobert > 69*4bdff4beSrobert >; 70*4bdff4beSrobert }; 71*4bdff4beSrobert 72*4bdff4beSrobert template<input_range _View> 73*4bdff4beSrobert requires view<_View> && input_range<range_reference_t<_View>> 74*4bdff4beSrobert class join_view 75*4bdff4beSrobert : public view_interface<join_view<_View>> { 76*4bdff4beSrobert private: 77*4bdff4beSrobert using _InnerRange = range_reference_t<_View>; 78*4bdff4beSrobert 79*4bdff4beSrobert template<bool> struct __iterator; 80*4bdff4beSrobert 81*4bdff4beSrobert template<bool> struct __sentinel; 82*4bdff4beSrobert 83*4bdff4beSrobert template <class> 84*4bdff4beSrobert friend struct std::__segmented_iterator_traits; 85*4bdff4beSrobert 86*4bdff4beSrobert static constexpr bool _UseCache = !is_reference_v<_InnerRange>; 87*4bdff4beSrobert using _Cache = _If<_UseCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>; 88*4bdff4beSrobert _LIBCPP_NO_UNIQUE_ADDRESS _Cache __cache_; 89*4bdff4beSrobert _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); 90*4bdff4beSrobert 91*4bdff4beSrobert public: 92*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 93*4bdff4beSrobert join_view() requires default_initializable<_View> = default; 94*4bdff4beSrobert 95*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 96*4bdff4beSrobert constexpr explicit join_view(_View __base) 97*4bdff4beSrobert : __base_(std::move(__base)) {} 98*4bdff4beSrobert 99*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 100*4bdff4beSrobert constexpr _View base() const& requires copy_constructible<_View> { return __base_; } 101*4bdff4beSrobert 102*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 103*4bdff4beSrobert constexpr _View base() && { return std::move(__base_); } 104*4bdff4beSrobert 105*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 106*4bdff4beSrobert constexpr auto begin() { 107*4bdff4beSrobert constexpr bool __use_const = __simple_view<_View> && 108*4bdff4beSrobert is_reference_v<range_reference_t<_View>>; 109*4bdff4beSrobert return __iterator<__use_const>{*this, ranges::begin(__base_)}; 110*4bdff4beSrobert } 111*4bdff4beSrobert 112*4bdff4beSrobert template<class _V2 = _View> 113*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 114*4bdff4beSrobert constexpr auto begin() const 115*4bdff4beSrobert requires input_range<const _V2> && 116*4bdff4beSrobert is_reference_v<range_reference_t<const _V2>> 117*4bdff4beSrobert { 118*4bdff4beSrobert return __iterator<true>{*this, ranges::begin(__base_)}; 119*4bdff4beSrobert } 120*4bdff4beSrobert 121*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 122*4bdff4beSrobert constexpr auto end() { 123*4bdff4beSrobert if constexpr (forward_range<_View> && 124*4bdff4beSrobert is_reference_v<_InnerRange> && 125*4bdff4beSrobert forward_range<_InnerRange> && 126*4bdff4beSrobert common_range<_View> && 127*4bdff4beSrobert common_range<_InnerRange>) 128*4bdff4beSrobert return __iterator<__simple_view<_View>>{*this, ranges::end(__base_)}; 129*4bdff4beSrobert else 130*4bdff4beSrobert return __sentinel<__simple_view<_View>>{*this}; 131*4bdff4beSrobert } 132*4bdff4beSrobert 133*4bdff4beSrobert template<class _V2 = _View> 134*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 135*4bdff4beSrobert constexpr auto end() const 136*4bdff4beSrobert requires input_range<const _V2> && 137*4bdff4beSrobert is_reference_v<range_reference_t<const _V2>> 138*4bdff4beSrobert { 139*4bdff4beSrobert using _ConstInnerRange = range_reference_t<const _View>; 140*4bdff4beSrobert if constexpr (forward_range<const _View> && 141*4bdff4beSrobert is_reference_v<_ConstInnerRange> && 142*4bdff4beSrobert forward_range<_ConstInnerRange> && 143*4bdff4beSrobert common_range<const _View> && 144*4bdff4beSrobert common_range<_ConstInnerRange>) { 145*4bdff4beSrobert return __iterator<true>{*this, ranges::end(__base_)}; 146*4bdff4beSrobert } else { 147*4bdff4beSrobert return __sentinel<true>{*this}; 148*4bdff4beSrobert } 149*4bdff4beSrobert } 150*4bdff4beSrobert }; 151*4bdff4beSrobert 152*4bdff4beSrobert template<input_range _View> 153*4bdff4beSrobert requires view<_View> && input_range<range_reference_t<_View>> 154*4bdff4beSrobert template<bool _Const> 155*4bdff4beSrobert struct join_view<_View>::__sentinel { 156*4bdff4beSrobert template<bool> 157*4bdff4beSrobert friend struct __sentinel; 158*4bdff4beSrobert 159*4bdff4beSrobert private: 160*4bdff4beSrobert using _Parent = __maybe_const<_Const, join_view<_View>>; 161*4bdff4beSrobert using _Base = __maybe_const<_Const, _View>; 162*4bdff4beSrobert sentinel_t<_Base> __end_ = sentinel_t<_Base>(); 163*4bdff4beSrobert 164*4bdff4beSrobert public: 165*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 166*4bdff4beSrobert __sentinel() = default; 167*4bdff4beSrobert 168*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 169*4bdff4beSrobert constexpr explicit __sentinel(_Parent& __parent) 170*4bdff4beSrobert : __end_(ranges::end(__parent.__base_)) {} 171*4bdff4beSrobert 172*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 173*4bdff4beSrobert constexpr __sentinel(__sentinel<!_Const> __s) 174*4bdff4beSrobert requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>> 175*4bdff4beSrobert : __end_(std::move(__s.__end_)) {} 176*4bdff4beSrobert 177*4bdff4beSrobert template<bool _OtherConst> 178*4bdff4beSrobert requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> 179*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 180*4bdff4beSrobert friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { 181*4bdff4beSrobert return __x.__outer_ == __y.__end_; 182*4bdff4beSrobert } 183*4bdff4beSrobert }; 184*4bdff4beSrobert 185*4bdff4beSrobert // https://reviews.llvm.org/D142811#inline-1383022 186*4bdff4beSrobert // To simplify the segmented iterator traits specialization, 187*4bdff4beSrobert // make the iterator `final` 188*4bdff4beSrobert template<input_range _View> 189*4bdff4beSrobert requires view<_View> && input_range<range_reference_t<_View>> 190*4bdff4beSrobert template<bool _Const> 191*4bdff4beSrobert struct join_view<_View>::__iterator final 192*4bdff4beSrobert : public __join_view_iterator_category<__maybe_const<_Const, _View>> { 193*4bdff4beSrobert 194*4bdff4beSrobert template<bool> 195*4bdff4beSrobert friend struct __iterator; 196*4bdff4beSrobert 197*4bdff4beSrobert template <class> 198*4bdff4beSrobert friend struct std::__segmented_iterator_traits; 199*4bdff4beSrobert 200*4bdff4beSrobert static constexpr bool __is_join_view_iterator = true; 201*4bdff4beSrobert 202*4bdff4beSrobert private: 203*4bdff4beSrobert using _Parent = __maybe_const<_Const, join_view<_View>>; 204*4bdff4beSrobert using _Base = __maybe_const<_Const, _View>; 205*4bdff4beSrobert using _Outer = iterator_t<_Base>; 206*4bdff4beSrobert using _Inner = iterator_t<range_reference_t<_Base>>; 207*4bdff4beSrobert using _InnerRange = range_reference_t<_View>; 208*4bdff4beSrobert 209*4bdff4beSrobert static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>; 210*4bdff4beSrobert 211*4bdff4beSrobert public: 212*4bdff4beSrobert _Outer __outer_ = _Outer(); 213*4bdff4beSrobert 214*4bdff4beSrobert private: 215*4bdff4beSrobert optional<_Inner> __inner_; 216*4bdff4beSrobert _Parent *__parent_ = nullptr; 217*4bdff4beSrobert 218*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 219*4bdff4beSrobert constexpr void __satisfy() { 220*4bdff4beSrobert for (; __outer_ != ranges::end(__parent_->__base_); ++__outer_) { 221*4bdff4beSrobert auto&& __inner = [&]() -> auto&& { 222*4bdff4beSrobert if constexpr (__ref_is_glvalue) 223*4bdff4beSrobert return *__outer_; 224*4bdff4beSrobert else 225*4bdff4beSrobert return __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__outer_; }); 226*4bdff4beSrobert }(); 227*4bdff4beSrobert __inner_ = ranges::begin(__inner); 228*4bdff4beSrobert if (*__inner_ != ranges::end(__inner)) 229*4bdff4beSrobert return; 230*4bdff4beSrobert } 231*4bdff4beSrobert 232*4bdff4beSrobert if constexpr (__ref_is_glvalue) 233*4bdff4beSrobert __inner_.reset(); 234*4bdff4beSrobert } 235*4bdff4beSrobert 236*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner) 237*4bdff4beSrobert : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {} 238*4bdff4beSrobert 239*4bdff4beSrobert public: 240*4bdff4beSrobert using iterator_concept = _If< 241*4bdff4beSrobert __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<range_reference_t<_Base>> && 242*4bdff4beSrobert common_range<range_reference_t<_Base>>, 243*4bdff4beSrobert bidirectional_iterator_tag, 244*4bdff4beSrobert _If< 245*4bdff4beSrobert __ref_is_glvalue && forward_range<_Base> && forward_range<range_reference_t<_Base>>, 246*4bdff4beSrobert forward_iterator_tag, 247*4bdff4beSrobert input_iterator_tag 248*4bdff4beSrobert > 249*4bdff4beSrobert >; 250*4bdff4beSrobert 251*4bdff4beSrobert using value_type = range_value_t<range_reference_t<_Base>>; 252*4bdff4beSrobert 253*4bdff4beSrobert using difference_type = common_type_t< 254*4bdff4beSrobert range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>; 255*4bdff4beSrobert 256*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 257*4bdff4beSrobert __iterator() requires default_initializable<_Outer> = default; 258*4bdff4beSrobert 259*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 260*4bdff4beSrobert constexpr __iterator(_Parent& __parent, _Outer __outer) 261*4bdff4beSrobert : __outer_(std::move(__outer)) 262*4bdff4beSrobert , __parent_(std::addressof(__parent)) { 263*4bdff4beSrobert __satisfy(); 264*4bdff4beSrobert } 265*4bdff4beSrobert 266*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 267*4bdff4beSrobert constexpr __iterator(__iterator<!_Const> __i) 268*4bdff4beSrobert requires _Const && 269*4bdff4beSrobert convertible_to<iterator_t<_View>, _Outer> && 270*4bdff4beSrobert convertible_to<iterator_t<_InnerRange>, _Inner> 271*4bdff4beSrobert : __outer_(std::move(__i.__outer_)) 272*4bdff4beSrobert , __inner_(std::move(__i.__inner_)) 273*4bdff4beSrobert , __parent_(__i.__parent_) {} 274*4bdff4beSrobert 275*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 276*4bdff4beSrobert constexpr decltype(auto) operator*() const { 277*4bdff4beSrobert return **__inner_; 278*4bdff4beSrobert } 279*4bdff4beSrobert 280*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 281*4bdff4beSrobert constexpr _Inner operator->() const 282*4bdff4beSrobert requires __has_arrow<_Inner> && copyable<_Inner> 283*4bdff4beSrobert { 284*4bdff4beSrobert return *__inner_; 285*4bdff4beSrobert } 286*4bdff4beSrobert 287*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 288*4bdff4beSrobert constexpr __iterator& operator++() { 289*4bdff4beSrobert auto&& __inner = [&]() -> auto&& { 290*4bdff4beSrobert if constexpr (__ref_is_glvalue) 291*4bdff4beSrobert return *__outer_; 292*4bdff4beSrobert else 293*4bdff4beSrobert return *__parent_->__cache_; 294*4bdff4beSrobert }(); 295*4bdff4beSrobert if (++*__inner_ == ranges::end(__inner)) { 296*4bdff4beSrobert ++__outer_; 297*4bdff4beSrobert __satisfy(); 298*4bdff4beSrobert } 299*4bdff4beSrobert return *this; 300*4bdff4beSrobert } 301*4bdff4beSrobert 302*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 303*4bdff4beSrobert constexpr void operator++(int) { 304*4bdff4beSrobert ++*this; 305*4bdff4beSrobert } 306*4bdff4beSrobert 307*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 308*4bdff4beSrobert constexpr __iterator operator++(int) 309*4bdff4beSrobert requires __ref_is_glvalue && 310*4bdff4beSrobert forward_range<_Base> && 311*4bdff4beSrobert forward_range<range_reference_t<_Base>> 312*4bdff4beSrobert { 313*4bdff4beSrobert auto __tmp = *this; 314*4bdff4beSrobert ++*this; 315*4bdff4beSrobert return __tmp; 316*4bdff4beSrobert } 317*4bdff4beSrobert 318*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 319*4bdff4beSrobert constexpr __iterator& operator--() 320*4bdff4beSrobert requires __ref_is_glvalue && 321*4bdff4beSrobert bidirectional_range<_Base> && 322*4bdff4beSrobert bidirectional_range<range_reference_t<_Base>> && 323*4bdff4beSrobert common_range<range_reference_t<_Base>> 324*4bdff4beSrobert { 325*4bdff4beSrobert if (__outer_ == ranges::end(__parent_->__base_)) 326*4bdff4beSrobert __inner_ = ranges::end(*--__outer_); 327*4bdff4beSrobert 328*4bdff4beSrobert // Skip empty inner ranges when going backwards. 329*4bdff4beSrobert while (*__inner_ == ranges::begin(*__outer_)) { 330*4bdff4beSrobert __inner_ = ranges::end(*--__outer_); 331*4bdff4beSrobert } 332*4bdff4beSrobert 333*4bdff4beSrobert --*__inner_; 334*4bdff4beSrobert return *this; 335*4bdff4beSrobert } 336*4bdff4beSrobert 337*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 338*4bdff4beSrobert constexpr __iterator operator--(int) 339*4bdff4beSrobert requires __ref_is_glvalue && 340*4bdff4beSrobert bidirectional_range<_Base> && 341*4bdff4beSrobert bidirectional_range<range_reference_t<_Base>> && 342*4bdff4beSrobert common_range<range_reference_t<_Base>> 343*4bdff4beSrobert { 344*4bdff4beSrobert auto __tmp = *this; 345*4bdff4beSrobert --*this; 346*4bdff4beSrobert return __tmp; 347*4bdff4beSrobert } 348*4bdff4beSrobert 349*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 350*4bdff4beSrobert friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) 351*4bdff4beSrobert requires __ref_is_glvalue && 352*4bdff4beSrobert equality_comparable<iterator_t<_Base>> && 353*4bdff4beSrobert equality_comparable<iterator_t<range_reference_t<_Base>>> 354*4bdff4beSrobert { 355*4bdff4beSrobert return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_; 356*4bdff4beSrobert } 357*4bdff4beSrobert 358*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 359*4bdff4beSrobert friend constexpr decltype(auto) iter_move(const __iterator& __i) 360*4bdff4beSrobert noexcept(noexcept(ranges::iter_move(*__i.__inner_))) 361*4bdff4beSrobert { 362*4bdff4beSrobert return ranges::iter_move(*__i.__inner_); 363*4bdff4beSrobert } 364*4bdff4beSrobert 365*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI 366*4bdff4beSrobert friend constexpr void iter_swap(const __iterator& __x, const __iterator& __y) 367*4bdff4beSrobert noexcept(noexcept(ranges::iter_swap(*__x.__inner_, *__y.__inner_))) 368*4bdff4beSrobert requires indirectly_swappable<_Inner> 369*4bdff4beSrobert { 370*4bdff4beSrobert return ranges::iter_swap(*__x.__inner_, *__y.__inner_); 371*4bdff4beSrobert } 372*4bdff4beSrobert }; 373*4bdff4beSrobert 374*4bdff4beSrobert template<class _Range> 375*4bdff4beSrobert explicit join_view(_Range&&) -> join_view<views::all_t<_Range>>; 376*4bdff4beSrobert 377*4bdff4beSrobert namespace views { 378*4bdff4beSrobert namespace __join_view { 379*4bdff4beSrobert struct __fn : __range_adaptor_closure<__fn> { 380*4bdff4beSrobert template<class _Range> 381*4bdff4beSrobert [[nodiscard]] _LIBCPP_HIDE_FROM_ABI 382*4bdff4beSrobert constexpr auto operator()(_Range&& __range) const 383*4bdff4beSrobert noexcept(noexcept(join_view<all_t<_Range&&>>(std::forward<_Range>(__range)))) 384*4bdff4beSrobert -> decltype( join_view<all_t<_Range&&>>(std::forward<_Range>(__range))) 385*4bdff4beSrobert { return join_view<all_t<_Range&&>>(std::forward<_Range>(__range)); } 386*4bdff4beSrobert }; 387*4bdff4beSrobert } // namespace __join_view 388*4bdff4beSrobert inline namespace __cpo { 389*4bdff4beSrobert inline constexpr auto join = __join_view::__fn{}; 390*4bdff4beSrobert } // namespace __cpo 391*4bdff4beSrobert } // namespace views 392*4bdff4beSrobert } // namespace ranges 393*4bdff4beSrobert 394*4bdff4beSrobert template <class _JoinViewIterator> 395*4bdff4beSrobert requires(_JoinViewIterator::__is_join_view_iterator && 396*4bdff4beSrobert ranges::common_range<typename _JoinViewIterator::_Parent> && 397*4bdff4beSrobert __is_cpp17_random_access_iterator<typename _JoinViewIterator::_Outer>::value && 398*4bdff4beSrobert __is_cpp17_random_access_iterator<typename _JoinViewIterator::_Inner>::value) 399*4bdff4beSrobert struct __segmented_iterator_traits<_JoinViewIterator> { 400*4bdff4beSrobert 401*4bdff4beSrobert using __segment_iterator = 402*4bdff4beSrobert _LIBCPP_NODEBUG __iterator_with_data<typename _JoinViewIterator::_Outer, typename _JoinViewIterator::_Parent*>; 403*4bdff4beSrobert using __local_iterator = typename _JoinViewIterator::_Inner; 404*4bdff4beSrobert 405*4bdff4beSrobert // TODO: Would it make sense to enable the optimization for other iterator types? 406*4bdff4beSrobert 407*4bdff4beSrobert static constexpr _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_JoinViewIterator __iter) { 408*4bdff4beSrobert if (ranges::empty(__iter.__parent_->__base_)) 409*4bdff4beSrobert return {}; 410*4bdff4beSrobert if (!__iter.__inner_.has_value()) 411*4bdff4beSrobert return __segment_iterator(--__iter.__outer_, __iter.__parent_); 412*4bdff4beSrobert return __segment_iterator(__iter.__outer_, __iter.__parent_); 413*4bdff4beSrobert } 414*4bdff4beSrobert 415*4bdff4beSrobert static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_JoinViewIterator __iter) { 416*4bdff4beSrobert if (ranges::empty(__iter.__parent_->__base_)) 417*4bdff4beSrobert return {}; 418*4bdff4beSrobert if (!__iter.__inner_.has_value()) 419*4bdff4beSrobert return ranges::end(*--__iter.__outer_); 420*4bdff4beSrobert return *__iter.__inner_; 421*4bdff4beSrobert } 422*4bdff4beSrobert 423*4bdff4beSrobert static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __begin(__segment_iterator __iter) { 424*4bdff4beSrobert return ranges::begin(*__iter.__get_iter()); 425*4bdff4beSrobert } 426*4bdff4beSrobert 427*4bdff4beSrobert static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __end(__segment_iterator __iter) { 428*4bdff4beSrobert return ranges::end(*__iter.__get_iter()); 429*4bdff4beSrobert } 430*4bdff4beSrobert 431*4bdff4beSrobert static constexpr _LIBCPP_HIDE_FROM_ABI _JoinViewIterator 432*4bdff4beSrobert __compose(__segment_iterator __seg_iter, __local_iterator __local_iter) { 433*4bdff4beSrobert return _JoinViewIterator( 434*4bdff4beSrobert std::move(__seg_iter).__get_data(), std::move(__seg_iter).__get_iter(), std::move(__local_iter)); 435*4bdff4beSrobert } 436*4bdff4beSrobert }; 437*4bdff4beSrobert 438*4bdff4beSrobert #endif // #if _LIBCPP_STD_VER > 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) 439*4bdff4beSrobert 440*4bdff4beSrobert _LIBCPP_END_NAMESPACE_STD 441*4bdff4beSrobert 442*4bdff4beSrobert #endif // _LIBCPP___RANGES_JOIN_VIEW_H 443