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