1 // Utilities for representing and manipulating ranges -*- C++ -*- 2 3 // Copyright (C) 2019-2022 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file bits/ranges_util.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. @headername{ranges} 28 */ 29 30 #ifndef _RANGES_UTIL_H 31 #define _RANGES_UTIL_H 1 32 33 #if __cplusplus > 201703L 34 # include <bits/ranges_base.h> 35 # include <bits/utility.h> 36 37 #ifdef __cpp_lib_ranges 38 namespace std _GLIBCXX_VISIBILITY(default) 39 { 40 _GLIBCXX_BEGIN_NAMESPACE_VERSION 41 namespace ranges 42 { 43 // C++20 24.5 [range.utility] Range utilities 44 45 namespace __detail 46 { 47 template<typename _Range> 48 concept __simple_view = view<_Range> && range<const _Range> 49 && same_as<iterator_t<_Range>, iterator_t<const _Range>> 50 && same_as<sentinel_t<_Range>, sentinel_t<const _Range>>; 51 52 template<typename _It> 53 concept __has_arrow = input_iterator<_It> 54 && (is_pointer_v<_It> || requires(_It __it) { __it.operator->(); }); 55 56 template<typename _Tp, typename _Up> 57 concept __different_from 58 = !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>; 59 } // namespace __detail 60 61 /// The ranges::view_interface class template 62 template<typename _Derived> 63 requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>> 64 class view_interface 65 { 66 private: 67 constexpr _Derived& _M_derived() noexcept 68 { 69 static_assert(derived_from<_Derived, view_interface<_Derived>>); 70 static_assert(view<_Derived>); 71 return static_cast<_Derived&>(*this); 72 } 73 74 constexpr const _Derived& _M_derived() const noexcept 75 { 76 static_assert(derived_from<_Derived, view_interface<_Derived>>); 77 static_assert(view<_Derived>); 78 return static_cast<const _Derived&>(*this); 79 } 80 81 static constexpr bool 82 _S_bool(bool) noexcept; // not defined 83 84 template<typename _Tp> 85 static constexpr bool 86 _S_empty(_Tp& __t) 87 noexcept(noexcept(_S_bool(ranges::begin(__t) == ranges::end(__t)))) 88 { return ranges::begin(__t) == ranges::end(__t); } 89 90 template<typename _Tp> 91 static constexpr auto 92 _S_size(_Tp& __t) 93 noexcept(noexcept(ranges::end(__t) - ranges::begin(__t))) 94 { return ranges::end(__t) - ranges::begin(__t); } 95 96 public: 97 constexpr bool 98 empty() 99 noexcept(noexcept(_S_empty(_M_derived()))) 100 requires forward_range<_Derived> 101 { return _S_empty(_M_derived()); } 102 103 constexpr bool 104 empty() const 105 noexcept(noexcept(_S_empty(_M_derived()))) 106 requires forward_range<const _Derived> 107 { return _S_empty(_M_derived()); } 108 109 constexpr explicit 110 operator bool() noexcept(noexcept(ranges::empty(_M_derived()))) 111 requires requires { ranges::empty(_M_derived()); } 112 { return !ranges::empty(_M_derived()); } 113 114 constexpr explicit 115 operator bool() const noexcept(noexcept(ranges::empty(_M_derived()))) 116 requires requires { ranges::empty(_M_derived()); } 117 { return !ranges::empty(_M_derived()); } 118 119 constexpr auto 120 data() noexcept(noexcept(ranges::begin(_M_derived()))) 121 requires contiguous_iterator<iterator_t<_Derived>> 122 { return std::to_address(ranges::begin(_M_derived())); } 123 124 constexpr auto 125 data() const noexcept(noexcept(ranges::begin(_M_derived()))) 126 requires range<const _Derived> 127 && contiguous_iterator<iterator_t<const _Derived>> 128 { return std::to_address(ranges::begin(_M_derived())); } 129 130 constexpr auto 131 size() noexcept(noexcept(_S_size(_M_derived()))) 132 requires forward_range<_Derived> 133 && sized_sentinel_for<sentinel_t<_Derived>, iterator_t<_Derived>> 134 { return _S_size(_M_derived()); } 135 136 constexpr auto 137 size() const noexcept(noexcept(_S_size(_M_derived()))) 138 requires forward_range<const _Derived> 139 && sized_sentinel_for<sentinel_t<const _Derived>, 140 iterator_t<const _Derived>> 141 { return _S_size(_M_derived()); } 142 143 constexpr decltype(auto) 144 front() requires forward_range<_Derived> 145 { 146 __glibcxx_assert(!empty()); 147 return *ranges::begin(_M_derived()); 148 } 149 150 constexpr decltype(auto) 151 front() const requires forward_range<const _Derived> 152 { 153 __glibcxx_assert(!empty()); 154 return *ranges::begin(_M_derived()); 155 } 156 157 constexpr decltype(auto) 158 back() 159 requires bidirectional_range<_Derived> && common_range<_Derived> 160 { 161 __glibcxx_assert(!empty()); 162 return *ranges::prev(ranges::end(_M_derived())); 163 } 164 165 constexpr decltype(auto) 166 back() const 167 requires bidirectional_range<const _Derived> 168 && common_range<const _Derived> 169 { 170 __glibcxx_assert(!empty()); 171 return *ranges::prev(ranges::end(_M_derived())); 172 } 173 174 template<random_access_range _Range = _Derived> 175 constexpr decltype(auto) 176 operator[](range_difference_t<_Range> __n) 177 { return ranges::begin(_M_derived())[__n]; } 178 179 template<random_access_range _Range = const _Derived> 180 constexpr decltype(auto) 181 operator[](range_difference_t<_Range> __n) const 182 { return ranges::begin(_M_derived())[__n]; } 183 }; 184 185 namespace __detail 186 { 187 template<typename _From, typename _To> 188 concept __uses_nonqualification_pointer_conversion 189 = is_pointer_v<_From> && is_pointer_v<_To> 190 && !convertible_to<remove_pointer_t<_From>(*)[], 191 remove_pointer_t<_To>(*)[]>; 192 193 template<typename _From, typename _To> 194 concept __convertible_to_non_slicing = convertible_to<_From, _To> 195 && !__uses_nonqualification_pointer_conversion<decay_t<_From>, 196 decay_t<_To>>; 197 198 template<typename _Tp> 199 concept __pair_like 200 = !is_reference_v<_Tp> && requires(_Tp __t) 201 { 202 typename tuple_size<_Tp>::type; 203 requires derived_from<tuple_size<_Tp>, integral_constant<size_t, 2>>; 204 typename tuple_element_t<0, remove_const_t<_Tp>>; 205 typename tuple_element_t<1, remove_const_t<_Tp>>; 206 { get<0>(__t) } -> convertible_to<const tuple_element_t<0, _Tp>&>; 207 { get<1>(__t) } -> convertible_to<const tuple_element_t<1, _Tp>&>; 208 }; 209 210 template<typename _Tp, typename _Up, typename _Vp> 211 concept __pair_like_convertible_from 212 = !range<_Tp> && __pair_like<_Tp> 213 && constructible_from<_Tp, _Up, _Vp> 214 && __convertible_to_non_slicing<_Up, tuple_element_t<0, _Tp>> 215 && convertible_to<_Vp, tuple_element_t<1, _Tp>>; 216 217 } // namespace __detail 218 219 namespace views { struct _Drop; } // defined in <ranges> 220 221 enum class subrange_kind : bool { unsized, sized }; 222 223 /// The ranges::subrange class template 224 template<input_or_output_iterator _It, sentinel_for<_It> _Sent = _It, 225 subrange_kind _Kind = sized_sentinel_for<_Sent, _It> 226 ? subrange_kind::sized : subrange_kind::unsized> 227 requires (_Kind == subrange_kind::sized || !sized_sentinel_for<_Sent, _It>) 228 class subrange : public view_interface<subrange<_It, _Sent, _Kind>> 229 { 230 private: 231 static constexpr bool _S_store_size 232 = _Kind == subrange_kind::sized && !sized_sentinel_for<_Sent, _It>; 233 234 friend struct views::_Drop; // Needs to inspect _S_store_size. 235 236 _It _M_begin = _It(); 237 [[no_unique_address]] _Sent _M_end = _Sent(); 238 239 using __size_type 240 = __detail::__make_unsigned_like_t<iter_difference_t<_It>>; 241 242 template<typename, bool = _S_store_size> 243 struct _Size 244 { }; 245 246 template<typename _Tp> 247 struct _Size<_Tp, true> 248 { _Tp _M_size; }; 249 250 [[no_unique_address]] _Size<__size_type> _M_size = {}; 251 252 public: 253 subrange() requires default_initializable<_It> = default; 254 255 constexpr 256 subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s) 257 noexcept(is_nothrow_constructible_v<_It, decltype(__i)> 258 && is_nothrow_constructible_v<_Sent, _Sent&>) 259 requires (!_S_store_size) 260 : _M_begin(std::move(__i)), _M_end(__s) 261 { } 262 263 constexpr 264 subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s, 265 __size_type __n) 266 noexcept(is_nothrow_constructible_v<_It, decltype(__i)> 267 && is_nothrow_constructible_v<_Sent, _Sent&>) 268 requires (_Kind == subrange_kind::sized) 269 : _M_begin(std::move(__i)), _M_end(__s) 270 { 271 if constexpr (_S_store_size) 272 _M_size._M_size = __n; 273 } 274 275 template<__detail::__different_from<subrange> _Rng> 276 requires borrowed_range<_Rng> 277 && __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It> 278 && convertible_to<sentinel_t<_Rng>, _Sent> 279 constexpr 280 subrange(_Rng&& __r) 281 noexcept(noexcept(subrange(__r, ranges::size(__r)))) 282 requires _S_store_size && sized_range<_Rng> 283 : subrange(__r, ranges::size(__r)) 284 { } 285 286 template<__detail::__different_from<subrange> _Rng> 287 requires borrowed_range<_Rng> 288 && __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It> 289 && convertible_to<sentinel_t<_Rng>, _Sent> 290 constexpr 291 subrange(_Rng&& __r) 292 noexcept(noexcept(subrange(ranges::begin(__r), ranges::end(__r)))) 293 requires (!_S_store_size) 294 : subrange(ranges::begin(__r), ranges::end(__r)) 295 { } 296 297 template<borrowed_range _Rng> 298 requires __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It> 299 && convertible_to<sentinel_t<_Rng>, _Sent> 300 constexpr 301 subrange(_Rng&& __r, __size_type __n) 302 noexcept(noexcept(subrange(ranges::begin(__r), ranges::end(__r), __n))) 303 requires (_Kind == subrange_kind::sized) 304 : subrange{ranges::begin(__r), ranges::end(__r), __n} 305 { } 306 307 template<__detail::__different_from<subrange> _PairLike> 308 requires __detail::__pair_like_convertible_from<_PairLike, const _It&, 309 const _Sent&> 310 constexpr 311 operator _PairLike() const 312 { return _PairLike(_M_begin, _M_end); } 313 314 constexpr _It 315 begin() const requires copyable<_It> 316 { return _M_begin; } 317 318 [[nodiscard]] constexpr _It 319 begin() requires (!copyable<_It>) 320 { return std::move(_M_begin); } 321 322 constexpr _Sent end() const { return _M_end; } 323 324 constexpr bool empty() const { return _M_begin == _M_end; } 325 326 constexpr __size_type 327 size() const requires (_Kind == subrange_kind::sized) 328 { 329 if constexpr (_S_store_size) 330 return _M_size._M_size; 331 else 332 return __detail::__to_unsigned_like(_M_end - _M_begin); 333 } 334 335 [[nodiscard]] constexpr subrange 336 next(iter_difference_t<_It> __n = 1) const & 337 requires forward_iterator<_It> 338 { 339 auto __tmp = *this; 340 __tmp.advance(__n); 341 return __tmp; 342 } 343 344 [[nodiscard]] constexpr subrange 345 next(iter_difference_t<_It> __n = 1) && 346 { 347 advance(__n); 348 return std::move(*this); 349 } 350 351 [[nodiscard]] constexpr subrange 352 prev(iter_difference_t<_It> __n = 1) const 353 requires bidirectional_iterator<_It> 354 { 355 auto __tmp = *this; 356 __tmp.advance(-__n); 357 return __tmp; 358 } 359 360 constexpr subrange& 361 advance(iter_difference_t<_It> __n) 362 { 363 // _GLIBCXX_RESOLVE_LIB_DEFECTS 364 // 3433. subrange::advance(n) has UB when n < 0 365 if constexpr (bidirectional_iterator<_It>) 366 if (__n < 0) 367 { 368 ranges::advance(_M_begin, __n); 369 if constexpr (_S_store_size) 370 _M_size._M_size += __detail::__to_unsigned_like(-__n); 371 return *this; 372 } 373 374 __glibcxx_assert(__n >= 0); 375 auto __d = __n - ranges::advance(_M_begin, __n, _M_end); 376 if constexpr (_S_store_size) 377 _M_size._M_size -= __detail::__to_unsigned_like(__d); 378 return *this; 379 } 380 }; 381 382 template<input_or_output_iterator _It, sentinel_for<_It> _Sent> 383 subrange(_It, _Sent) -> subrange<_It, _Sent>; 384 385 template<input_or_output_iterator _It, sentinel_for<_It> _Sent> 386 subrange(_It, _Sent, 387 __detail::__make_unsigned_like_t<iter_difference_t<_It>>) 388 -> subrange<_It, _Sent, subrange_kind::sized>; 389 390 template<borrowed_range _Rng> 391 subrange(_Rng&&) 392 -> subrange<iterator_t<_Rng>, sentinel_t<_Rng>, 393 (sized_range<_Rng> 394 || sized_sentinel_for<sentinel_t<_Rng>, iterator_t<_Rng>>) 395 ? subrange_kind::sized : subrange_kind::unsized>; 396 397 template<borrowed_range _Rng> 398 subrange(_Rng&&, 399 __detail::__make_unsigned_like_t<range_difference_t<_Rng>>) 400 -> subrange<iterator_t<_Rng>, sentinel_t<_Rng>, subrange_kind::sized>; 401 402 template<size_t _Num, class _It, class _Sent, subrange_kind _Kind> 403 requires (_Num < 2) 404 constexpr auto 405 get(const subrange<_It, _Sent, _Kind>& __r) 406 { 407 if constexpr (_Num == 0) 408 return __r.begin(); 409 else 410 return __r.end(); 411 } 412 413 template<size_t _Num, class _It, class _Sent, subrange_kind _Kind> 414 requires (_Num < 2) 415 constexpr auto 416 get(subrange<_It, _Sent, _Kind>&& __r) 417 { 418 if constexpr (_Num == 0) 419 return __r.begin(); 420 else 421 return __r.end(); 422 } 423 424 template<typename _It, typename _Sent, subrange_kind _Kind> 425 inline constexpr bool 426 enable_borrowed_range<subrange<_It, _Sent, _Kind>> = true; 427 428 template<range _Range> 429 using borrowed_subrange_t = __conditional_t<borrowed_range<_Range>, 430 subrange<iterator_t<_Range>>, 431 dangling>; 432 } // namespace ranges 433 434 // The following ranges algorithms are used by <ranges>, and are defined here 435 // so that <ranges> can avoid including all of <bits/ranges_algo.h>. 436 namespace ranges 437 { 438 struct __find_fn 439 { 440 template<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp, 441 typename _Proj = identity> 442 requires indirect_binary_predicate<ranges::equal_to, 443 projected<_Iter, _Proj>, const _Tp*> 444 constexpr _Iter 445 operator()(_Iter __first, _Sent __last, 446 const _Tp& __value, _Proj __proj = {}) const 447 { 448 while (__first != __last 449 && !(std::__invoke(__proj, *__first) == __value)) 450 ++__first; 451 return __first; 452 } 453 454 template<input_range _Range, typename _Tp, typename _Proj = identity> 455 requires indirect_binary_predicate<ranges::equal_to, 456 projected<iterator_t<_Range>, _Proj>, 457 const _Tp*> 458 constexpr borrowed_iterator_t<_Range> 459 operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const 460 { 461 return (*this)(ranges::begin(__r), ranges::end(__r), 462 __value, std::move(__proj)); 463 } 464 }; 465 466 inline constexpr __find_fn find{}; 467 468 struct __find_if_fn 469 { 470 template<input_iterator _Iter, sentinel_for<_Iter> _Sent, 471 typename _Proj = identity, 472 indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> 473 constexpr _Iter 474 operator()(_Iter __first, _Sent __last, 475 _Pred __pred, _Proj __proj = {}) const 476 { 477 while (__first != __last 478 && !(bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) 479 ++__first; 480 return __first; 481 } 482 483 template<input_range _Range, typename _Proj = identity, 484 indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> 485 _Pred> 486 constexpr borrowed_iterator_t<_Range> 487 operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const 488 { 489 return (*this)(ranges::begin(__r), ranges::end(__r), 490 std::move(__pred), std::move(__proj)); 491 } 492 }; 493 494 inline constexpr __find_if_fn find_if{}; 495 496 struct __find_if_not_fn 497 { 498 template<input_iterator _Iter, sentinel_for<_Iter> _Sent, 499 typename _Proj = identity, 500 indirect_unary_predicate<projected<_Iter, _Proj>> _Pred> 501 constexpr _Iter 502 operator()(_Iter __first, _Sent __last, 503 _Pred __pred, _Proj __proj = {}) const 504 { 505 while (__first != __last 506 && (bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) 507 ++__first; 508 return __first; 509 } 510 511 template<input_range _Range, typename _Proj = identity, 512 indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> 513 _Pred> 514 constexpr borrowed_iterator_t<_Range> 515 operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const 516 { 517 return (*this)(ranges::begin(__r), ranges::end(__r), 518 std::move(__pred), std::move(__proj)); 519 } 520 }; 521 522 inline constexpr __find_if_not_fn find_if_not{}; 523 524 template<typename _Iter1, typename _Iter2> 525 struct in_in_result 526 { 527 [[no_unique_address]] _Iter1 in1; 528 [[no_unique_address]] _Iter2 in2; 529 530 template<typename _IIter1, typename _IIter2> 531 requires convertible_to<const _Iter1&, _IIter1> 532 && convertible_to<const _Iter2&, _IIter2> 533 constexpr 534 operator in_in_result<_IIter1, _IIter2>() const & 535 { return {in1, in2}; } 536 537 template<typename _IIter1, typename _IIter2> 538 requires convertible_to<_Iter1, _IIter1> 539 && convertible_to<_Iter2, _IIter2> 540 constexpr 541 operator in_in_result<_IIter1, _IIter2>() && 542 { return {std::move(in1), std::move(in2)}; } 543 }; 544 545 template<typename _Iter1, typename _Iter2> 546 using mismatch_result = in_in_result<_Iter1, _Iter2>; 547 548 struct __mismatch_fn 549 { 550 template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1, 551 input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, 552 typename _Pred = ranges::equal_to, 553 typename _Proj1 = identity, typename _Proj2 = identity> 554 requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> 555 constexpr mismatch_result<_Iter1, _Iter2> 556 operator()(_Iter1 __first1, _Sent1 __last1, 557 _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, 558 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const 559 { 560 while (__first1 != __last1 && __first2 != __last2 561 && (bool)std::__invoke(__pred, 562 std::__invoke(__proj1, *__first1), 563 std::__invoke(__proj2, *__first2))) 564 { 565 ++__first1; 566 ++__first2; 567 } 568 return { std::move(__first1), std::move(__first2) }; 569 } 570 571 template<input_range _Range1, input_range _Range2, 572 typename _Pred = ranges::equal_to, 573 typename _Proj1 = identity, typename _Proj2 = identity> 574 requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, 575 _Pred, _Proj1, _Proj2> 576 constexpr mismatch_result<iterator_t<_Range1>, iterator_t<_Range2>> 577 operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, 578 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const 579 { 580 return (*this)(ranges::begin(__r1), ranges::end(__r1), 581 ranges::begin(__r2), ranges::end(__r2), 582 std::move(__pred), 583 std::move(__proj1), std::move(__proj2)); 584 } 585 }; 586 587 inline constexpr __mismatch_fn mismatch{}; 588 589 struct __search_fn 590 { 591 template<forward_iterator _Iter1, sentinel_for<_Iter1> _Sent1, 592 forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, 593 typename _Pred = ranges::equal_to, 594 typename _Proj1 = identity, typename _Proj2 = identity> 595 requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> 596 constexpr subrange<_Iter1> 597 operator()(_Iter1 __first1, _Sent1 __last1, 598 _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, 599 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const 600 { 601 if (__first1 == __last1 || __first2 == __last2) 602 return {__first1, __first1}; 603 604 for (;;) 605 { 606 for (;;) 607 { 608 if (__first1 == __last1) 609 return {__first1, __first1}; 610 if (std::__invoke(__pred, 611 std::__invoke(__proj1, *__first1), 612 std::__invoke(__proj2, *__first2))) 613 break; 614 ++__first1; 615 } 616 auto __cur1 = __first1; 617 auto __cur2 = __first2; 618 for (;;) 619 { 620 if (++__cur2 == __last2) 621 return {__first1, ++__cur1}; 622 if (++__cur1 == __last1) 623 return {__cur1, __cur1}; 624 if (!(bool)std::__invoke(__pred, 625 std::__invoke(__proj1, *__cur1), 626 std::__invoke(__proj2, *__cur2))) 627 { 628 ++__first1; 629 break; 630 } 631 } 632 } 633 } 634 635 template<forward_range _Range1, forward_range _Range2, 636 typename _Pred = ranges::equal_to, 637 typename _Proj1 = identity, typename _Proj2 = identity> 638 requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, 639 _Pred, _Proj1, _Proj2> 640 constexpr borrowed_subrange_t<_Range1> 641 operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, 642 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const 643 { 644 return (*this)(ranges::begin(__r1), ranges::end(__r1), 645 ranges::begin(__r2), ranges::end(__r2), 646 std::move(__pred), 647 std::move(__proj1), std::move(__proj2)); 648 } 649 }; 650 651 inline constexpr __search_fn search{}; 652 } // namespace ranges 653 654 using ranges::get; 655 656 template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> 657 struct tuple_size<ranges::subrange<_Iter, _Sent, _Kind>> 658 : integral_constant<size_t, 2> 659 { }; 660 661 template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> 662 struct tuple_element<0, ranges::subrange<_Iter, _Sent, _Kind>> 663 { using type = _Iter; }; 664 665 template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> 666 struct tuple_element<1, ranges::subrange<_Iter, _Sent, _Kind>> 667 { using type = _Sent; }; 668 669 template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> 670 struct tuple_element<0, const ranges::subrange<_Iter, _Sent, _Kind>> 671 { using type = _Iter; }; 672 673 template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind> 674 struct tuple_element<1, const ranges::subrange<_Iter, _Sent, _Kind>> 675 { using type = _Sent; }; 676 677 _GLIBCXX_END_NAMESPACE_VERSION 678 } // namespace std 679 #endif // library concepts 680 #endif // C++20 681 #endif // _RANGES_UTIL_H 682