xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/bits/ranges_base.h (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 // Core concepts and definitions for <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_base.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 _GLIBCXX_RANGES_BASE_H
31 #define _GLIBCXX_RANGES_BASE_H 1
32 
33 #pragma GCC system_header
34 
35 #if __cplusplus > 201703L
36 #include <bits/iterator_concepts.h>
37 #include <ext/numeric_traits.h>
38 #include <bits/max_size_type.h>
39 
40 #ifdef __cpp_lib_concepts
_GLIBCXX_VISIBILITY(default)41 namespace std _GLIBCXX_VISIBILITY(default)
42 {
43 _GLIBCXX_BEGIN_NAMESPACE_VERSION
44 namespace ranges
45 {
46   template<typename>
47     inline constexpr bool disable_sized_range = false;
48 
49   template<typename _Tp>
50     inline constexpr bool enable_borrowed_range = false;
51 
52   namespace __detail
53   {
54     constexpr __max_size_type
55     __to_unsigned_like(__max_size_type __t) noexcept
56     { return __t; }
57 
58     constexpr __max_size_type
59     __to_unsigned_like(__max_diff_type __t) noexcept
60     { return __max_size_type(__t); }
61 
62     template<integral _Tp>
63       constexpr auto
64       __to_unsigned_like(_Tp __t) noexcept
65       { return static_cast<make_unsigned_t<_Tp>>(__t); }
66 
67 #if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
68     constexpr unsigned __int128
69     __to_unsigned_like(__int128 __t) noexcept
70     { return __t; }
71 
72     constexpr unsigned __int128
73     __to_unsigned_like(unsigned __int128 __t) noexcept
74     { return __t; }
75 #endif
76 
77     template<typename _Tp>
78       using __make_unsigned_like_t
79 	= decltype(__detail::__to_unsigned_like(std::declval<_Tp>()));
80 
81     // Part of the constraints of ranges::borrowed_range
82     template<typename _Tp>
83       concept __maybe_borrowed_range
84 	= is_lvalue_reference_v<_Tp>
85 	  || enable_borrowed_range<remove_cvref_t<_Tp>>;
86 
87   } // namespace __detail
88 
89   namespace __cust_access
90   {
91     using std::ranges::__detail::__maybe_borrowed_range;
92     using std::__detail::__range_iter_t;
93 
94     struct _Begin
95     {
96     private:
97       template<typename _Tp>
98 	static constexpr bool
99 	_S_noexcept()
100 	{
101 	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
102 	    return true;
103 	  else if constexpr (__member_begin<_Tp>)
104 	    return noexcept(__decay_copy(std::declval<_Tp&>().begin()));
105 	  else
106 	    return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
107 	}
108 
109     public:
110       template<__maybe_borrowed_range _Tp>
111 	requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
112 	  || __adl_begin<_Tp>
113 	constexpr auto
114 	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
115 	{
116 	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
117 	    {
118 	      static_assert(is_lvalue_reference_v<_Tp>);
119 	      return __t + 0;
120 	    }
121 	  else if constexpr (__member_begin<_Tp>)
122 	    return __t.begin();
123 	  else
124 	    return begin(__t);
125 	}
126     };
127 
128     template<typename _Tp>
129       concept __member_end = requires(_Tp& __t)
130 	{
131 	  { __decay_copy(__t.end()) } -> sentinel_for<__range_iter_t<_Tp>>;
132 	};
133 
134     // Poison pills so that unqualified lookup doesn't find std::end.
135     void end(auto&) = delete;
136     void end(const auto&) = delete;
137 
138     template<typename _Tp>
139       concept __adl_end = __class_or_enum<remove_reference_t<_Tp>>
140 	&& requires(_Tp& __t)
141 	{
142 	  { __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
143 	};
144 
145     struct _End
146     {
147     private:
148       template<typename _Tp>
149 	static constexpr bool
150 	_S_noexcept()
151 	{
152 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
153 	    return true;
154 	  else if constexpr (__member_end<_Tp>)
155 	    return noexcept(__decay_copy(std::declval<_Tp&>().end()));
156 	  else
157 	    return noexcept(__decay_copy(end(std::declval<_Tp&>())));
158 	}
159 
160     public:
161       template<__maybe_borrowed_range _Tp>
162 	requires is_bounded_array_v<remove_reference_t<_Tp>>
163 	  || __member_end<_Tp> || __adl_end<_Tp>
164 	constexpr auto
165 	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
166 	{
167 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
168 	    {
169 	      static_assert(is_lvalue_reference_v<_Tp>);
170 	      return __t + extent_v<remove_reference_t<_Tp>>;
171 	    }
172 	  else if constexpr (__member_end<_Tp>)
173 	    return __t.end();
174 	  else
175 	    return end(__t);
176 	}
177     };
178 
179     // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&.
180     template<typename _To, typename _Tp>
181       constexpr decltype(auto)
182       __as_const(_Tp& __t) noexcept
183       {
184 	static_assert(std::is_same_v<_To&, _Tp&>);
185 
186 	if constexpr (is_lvalue_reference_v<_To>)
187 	  return const_cast<const _Tp&>(__t);
188 	else
189 	  return static_cast<const _Tp&&>(__t);
190       }
191 
192     struct _CBegin
193     {
194       template<typename _Tp>
195 	[[nodiscard]]
196 	constexpr auto
197 	operator()(_Tp&& __e) const
198 	noexcept(noexcept(_Begin{}(__cust_access::__as_const<_Tp>(__e))))
199 	requires requires { _Begin{}(__cust_access::__as_const<_Tp>(__e)); }
200 	{
201 	  return _Begin{}(__cust_access::__as_const<_Tp>(__e));
202 	}
203     };
204 
205     struct _CEnd final
206     {
207       template<typename _Tp>
208 	[[nodiscard]]
209 	constexpr auto
210 	operator()(_Tp&& __e) const
211 	noexcept(noexcept(_End{}(__cust_access::__as_const<_Tp>(__e))))
212 	requires requires { _End{}(__cust_access::__as_const<_Tp>(__e)); }
213 	{
214 	  return _End{}(__cust_access::__as_const<_Tp>(__e));
215 	}
216     };
217 
218     template<typename _Tp>
219       concept __member_rbegin = requires(_Tp& __t)
220 	{
221 	  { __decay_copy(__t.rbegin()) } -> input_or_output_iterator;
222 	};
223 
224     void rbegin(auto&) = delete;
225     void rbegin(const auto&) = delete;
226 
227     template<typename _Tp>
228       concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>>
229 	&& requires(_Tp& __t)
230 	{
231 	  { __decay_copy(rbegin(__t)) } -> input_or_output_iterator;
232 	};
233 
234     template<typename _Tp>
235       concept __reversable = requires(_Tp& __t)
236 	{
237 	  { _Begin{}(__t) } -> bidirectional_iterator;
238 	  { _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>;
239 	};
240 
241     struct _RBegin
242     {
243     private:
244       template<typename _Tp>
245 	static constexpr bool
246 	_S_noexcept()
247 	{
248 	  if constexpr (__member_rbegin<_Tp>)
249 	    return noexcept(__decay_copy(std::declval<_Tp&>().rbegin()));
250 	  else if constexpr (__adl_rbegin<_Tp>)
251 	    return noexcept(__decay_copy(rbegin(std::declval<_Tp&>())));
252 	  else
253 	    {
254 	      if constexpr (noexcept(_End{}(std::declval<_Tp&>())))
255 		{
256 		  using _It = decltype(_End{}(std::declval<_Tp&>()));
257 		  // std::reverse_iterator copy-initializes its member.
258 		  return is_nothrow_copy_constructible_v<_It>;
259 		}
260 	      else
261 		return false;
262 	    }
263 	}
264 
265     public:
266       template<__maybe_borrowed_range _Tp>
267 	requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
268 	constexpr auto
269 	operator()[[nodiscard]](_Tp&& __t) const
270 	noexcept(_S_noexcept<_Tp&>())
271 	{
272 	  if constexpr (__member_rbegin<_Tp>)
273 	    return __t.rbegin();
274 	  else if constexpr (__adl_rbegin<_Tp>)
275 	    return rbegin(__t);
276 	  else
277 	    return std::make_reverse_iterator(_End{}(__t));
278 	}
279     };
280 
281     template<typename _Tp>
282       concept __member_rend = requires(_Tp& __t)
283 	{
284 	  { __decay_copy(__t.rend()) }
285 	    -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
286 	};
287 
288     void rend(auto&) = delete;
289     void rend(const auto&) = delete;
290 
291     template<typename _Tp>
292       concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>>
293 	&& requires(_Tp& __t)
294 	{
295 	  { __decay_copy(rend(__t)) }
296 	    -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
297 	};
298 
299     struct _REnd
300     {
301     private:
302       template<typename _Tp>
303 	static constexpr bool
304 	_S_noexcept()
305 	{
306 	  if constexpr (__member_rend<_Tp>)
307 	    return noexcept(__decay_copy(std::declval<_Tp&>().rend()));
308 	  else if constexpr (__adl_rend<_Tp>)
309 	    return noexcept(__decay_copy(rend(std::declval<_Tp&>())));
310 	  else
311 	    {
312 	      if constexpr (noexcept(_Begin{}(std::declval<_Tp&>())))
313 		{
314 		  using _It = decltype(_Begin{}(std::declval<_Tp&>()));
315 		  // std::reverse_iterator copy-initializes its member.
316 		  return is_nothrow_copy_constructible_v<_It>;
317 		}
318 	      else
319 		return false;
320 	    }
321 	}
322 
323     public:
324       template<__maybe_borrowed_range _Tp>
325 	requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
326 	constexpr auto
327 	operator()[[nodiscard]](_Tp&& __t) const
328 	noexcept(_S_noexcept<_Tp&>())
329 	{
330 	  if constexpr (__member_rend<_Tp>)
331 	    return __t.rend();
332 	  else if constexpr (__adl_rend<_Tp>)
333 	    return rend(__t);
334 	  else
335 	    return std::make_reverse_iterator(_Begin{}(__t));
336 	}
337     };
338 
339     struct _CRBegin
340     {
341       template<typename _Tp>
342 	[[nodiscard]]
343 	constexpr auto
344 	operator()(_Tp&& __e) const
345 	noexcept(noexcept(_RBegin{}(__cust_access::__as_const<_Tp>(__e))))
346 	requires requires { _RBegin{}(__cust_access::__as_const<_Tp>(__e)); }
347 	{
348 	  return _RBegin{}(__cust_access::__as_const<_Tp>(__e));
349 	}
350     };
351 
352     struct _CREnd
353     {
354       template<typename _Tp>
355 	[[nodiscard]]
356 	constexpr auto
357 	operator()(_Tp&& __e) const
358 	noexcept(noexcept(_REnd{}(__cust_access::__as_const<_Tp>(__e))))
359 	requires requires { _REnd{}(__cust_access::__as_const<_Tp>(__e)); }
360 	{
361 	  return _REnd{}(__cust_access::__as_const<_Tp>(__e));
362 	}
363     };
364 
365     template<typename _Tp>
366       concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>>
367 	&& requires(_Tp& __t)
368 	{
369 	  { __decay_copy(__t.size()) } -> __detail::__is_integer_like;
370 	};
371 
372     void size(auto&) = delete;
373     void size(const auto&) = delete;
374 
375     template<typename _Tp>
376       concept __adl_size = __class_or_enum<remove_reference_t<_Tp>>
377 	&& !disable_sized_range<remove_cvref_t<_Tp>>
378 	&& requires(_Tp& __t)
379 	{
380 	  { __decay_copy(size(__t)) } -> __detail::__is_integer_like;
381 	};
382 
383     template<typename _Tp>
384       concept __sentinel_size = requires(_Tp& __t)
385 	{
386 	  requires (!is_unbounded_array_v<remove_reference_t<_Tp>>);
387 
388 	  { _Begin{}(__t) } -> forward_iterator;
389 
390 	  { _End{}(__t) } -> sized_sentinel_for<decltype(_Begin{}(__t))>;
391 
392 	  __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
393 	};
394 
395     struct _Size
396     {
397     private:
398       template<typename _Tp>
399 	static constexpr bool
400 	_S_noexcept()
401 	{
402 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
403 	    return true;
404 	  else if constexpr (__member_size<_Tp>)
405 	    return noexcept(__decay_copy(std::declval<_Tp&>().size()));
406 	  else if constexpr (__adl_size<_Tp>)
407 	    return noexcept(__decay_copy(size(std::declval<_Tp&>())));
408 	  else if constexpr (__sentinel_size<_Tp>)
409 	    return noexcept(_End{}(std::declval<_Tp&>())
410 			    - _Begin{}(std::declval<_Tp&>()));
411 	}
412 
413     public:
414       template<typename _Tp>
415 	requires is_bounded_array_v<remove_reference_t<_Tp>>
416 	  || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
417 	constexpr auto
418 	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
419 	{
420 	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
421 	    return extent_v<remove_reference_t<_Tp>>;
422 	  else if constexpr (__member_size<_Tp>)
423 	    return __t.size();
424 	  else if constexpr (__adl_size<_Tp>)
425 	    return size(__t);
426 	  else if constexpr (__sentinel_size<_Tp>)
427 	    return __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
428 	}
429     };
430 
431     struct _SSize
432     {
433       // _GLIBCXX_RESOLVE_LIB_DEFECTS
434       // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
435       template<typename _Tp>
436 	requires requires (_Tp& __t) { _Size{}(__t); }
437 	constexpr auto
438 	operator()[[nodiscard]](_Tp&& __t) const noexcept(noexcept(_Size{}(__t)))
439 	{
440 	  auto __size = _Size{}(__t);
441 	  using __size_type = decltype(__size);
442 	  // Return the wider of ptrdiff_t and make-signed-like-t<__size_type>.
443 	  if constexpr (integral<__size_type>)
444 	    {
445 	      using __gnu_cxx::__int_traits;
446 	      if constexpr (__int_traits<__size_type>::__digits
447 			    < __int_traits<ptrdiff_t>::__digits)
448 		return static_cast<ptrdiff_t>(__size);
449 	      else
450 		return static_cast<make_signed_t<__size_type>>(__size);
451 	    }
452 #if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
453 	  // For strict-ansi modes integral<__int128> is false
454 	  else if constexpr (__detail::__is_int128<__size_type>)
455 	    return static_cast<__int128>(__size);
456 #endif
457 	  else // Must be one of __max_diff_type or __max_size_type.
458 	    return __detail::__max_diff_type(__size);
459 	}
460     };
461 
462     template<typename _Tp>
463       concept __member_empty = requires(_Tp& __t) { bool(__t.empty()); };
464 
465     template<typename _Tp>
466       concept __size0_empty = requires(_Tp& __t) { _Size{}(__t) == 0; };
467 
468     template<typename _Tp>
469       concept __eq_iter_empty = requires(_Tp& __t)
470 	{
471 	  requires (!is_unbounded_array_v<remove_reference_t<_Tp>>);
472 
473 	  { _Begin{}(__t) } -> forward_iterator;
474 
475 	  bool(_Begin{}(__t) == _End{}(__t));
476 	};
477 
478     struct _Empty
479     {
480     private:
481       template<typename _Tp>
482 	static constexpr bool
483 	_S_noexcept()
484 	{
485 	  if constexpr (__member_empty<_Tp>)
486 	    return noexcept(bool(std::declval<_Tp&>().empty()));
487 	  else if constexpr (__size0_empty<_Tp>)
488 	    return noexcept(_Size{}(std::declval<_Tp&>()) == 0);
489 	  else
490 	    return noexcept(bool(_Begin{}(std::declval<_Tp&>())
491 		== _End{}(std::declval<_Tp&>())));
492 	}
493 
494     public:
495       template<typename _Tp>
496 	requires __member_empty<_Tp> || __size0_empty<_Tp>
497 	  || __eq_iter_empty<_Tp>
498 	constexpr bool
499 	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp&>())
500 	{
501 	  if constexpr (__member_empty<_Tp>)
502 	    return bool(__t.empty());
503 	  else if constexpr (__size0_empty<_Tp>)
504 	    return _Size{}(__t) == 0;
505 	  else
506 	    return bool(_Begin{}(__t) == _End{}(__t));
507 	}
508     };
509 
510     template<typename _Tp>
511       concept __pointer_to_object = is_pointer_v<_Tp>
512 				    && is_object_v<remove_pointer_t<_Tp>>;
513 
514     template<typename _Tp>
515       concept __member_data = requires(_Tp& __t)
516 	{
517 	  { __decay_copy(__t.data()) } -> __pointer_to_object;
518 	};
519 
520     template<typename _Tp>
521       concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>;
522 
523     struct _Data
524     {
525     private:
526       template<typename _Tp>
527 	static constexpr bool
528 	_S_noexcept()
529 	{
530 	  if constexpr (__member_data<_Tp>)
531 	    return noexcept(__decay_copy(std::declval<_Tp&>().data()));
532 	  else
533 	    return noexcept(_Begin{}(std::declval<_Tp&>()));
534 	}
535 
536     public:
537       template<__maybe_borrowed_range _Tp>
538 	requires __member_data<_Tp> || __begin_data<_Tp>
539 	constexpr auto
540 	operator()[[nodiscard]](_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
541 	{
542 	  if constexpr (__member_data<_Tp>)
543 	    return __t.data();
544 	  else
545 	    return std::to_address(_Begin{}(__t));
546 	}
547     };
548 
549     struct _CData
550     {
551       template<typename _Tp>
552 	[[nodiscard]]
553 	constexpr auto
554 	operator()(_Tp&& __e) const
555 	noexcept(noexcept(_Data{}(__cust_access::__as_const<_Tp>(__e))))
556 	requires requires { _Data{}(__cust_access::__as_const<_Tp>(__e)); }
557 	{
558 	  return _Data{}(__cust_access::__as_const<_Tp>(__e));
559 	}
560     };
561 
562   } // namespace __cust_access
563 
564   inline namespace __cust
565   {
566     inline constexpr __cust_access::_Begin begin{};
567     inline constexpr __cust_access::_End end{};
568     inline constexpr __cust_access::_CBegin cbegin{};
569     inline constexpr __cust_access::_CEnd cend{};
570     inline constexpr __cust_access::_RBegin rbegin{};
571     inline constexpr __cust_access::_REnd rend{};
572     inline constexpr __cust_access::_CRBegin crbegin{};
573     inline constexpr __cust_access::_CREnd crend{};
574     inline constexpr __cust_access::_Size size{};
575     inline constexpr __cust_access::_SSize ssize{};
576     inline constexpr __cust_access::_Empty empty{};
577     inline constexpr __cust_access::_Data data{};
578     inline constexpr __cust_access::_CData cdata{};
579   }
580 
581   /// [range.range] The range concept.
582   template<typename _Tp>
583     concept range = requires(_Tp& __t)
584       {
585 	ranges::begin(__t);
586 	ranges::end(__t);
587       };
588 
589   /// [range.range] The borrowed_range concept.
590   template<typename _Tp>
591     concept borrowed_range
592       = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
593 
594   template<typename _Tp>
595     using iterator_t = std::__detail::__range_iter_t<_Tp>;
596 
597   template<range _Range>
598     using sentinel_t = decltype(ranges::end(std::declval<_Range&>()));
599 
600   template<range _Range>
601     using range_difference_t = iter_difference_t<iterator_t<_Range>>;
602 
603   template<range _Range>
604     using range_value_t = iter_value_t<iterator_t<_Range>>;
605 
606   template<range _Range>
607     using range_reference_t = iter_reference_t<iterator_t<_Range>>;
608 
609   template<range _Range>
610     using range_rvalue_reference_t
611       = iter_rvalue_reference_t<iterator_t<_Range>>;
612 
613   /// [range.sized] The sized_range concept.
614   template<typename _Tp>
615     concept sized_range = range<_Tp>
616       && requires(_Tp& __t) { ranges::size(__t); };
617 
618   template<sized_range _Range>
619     using range_size_t = decltype(ranges::size(std::declval<_Range&>()));
620 
621   template<typename _Derived>
622     requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
623     class view_interface; // defined in <bits/ranges_util.h>
624 
625   namespace __detail
626   {
627     template<typename _Tp, typename _Up>
628       requires (!same_as<_Tp, view_interface<_Up>>)
629       void __is_derived_from_view_interface_fn(const _Tp&,
630 					       const view_interface<_Up>&); // not defined
631 
632     // Returns true iff _Tp has exactly one public base class that's a
633     // specialization of view_interface.
634     template<typename _Tp>
635       concept __is_derived_from_view_interface
636 	= requires (_Tp __t) { __is_derived_from_view_interface_fn(__t, __t); };
637   } // namespace __detail
638 
639   /// [range.view] The ranges::view_base type.
640   struct view_base { };
641 
642   /// [range.view] The ranges::enable_view boolean.
643   template<typename _Tp>
644     inline constexpr bool enable_view = derived_from<_Tp, view_base>
645       || __detail::__is_derived_from_view_interface<_Tp>;
646 
647   /// [range.view] The ranges::view concept.
648   template<typename _Tp>
649     concept view
650       = range<_Tp> && movable<_Tp> && enable_view<_Tp>;
651 
652   // [range.refinements]
653 
654   /// A range for which ranges::begin returns an output iterator.
655   template<typename _Range, typename _Tp>
656     concept output_range
657       = range<_Range> && output_iterator<iterator_t<_Range>, _Tp>;
658 
659   /// A range for which ranges::begin returns an input iterator.
660   template<typename _Tp>
661     concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>;
662 
663   /// A range for which ranges::begin returns a forward iterator.
664   template<typename _Tp>
665     concept forward_range
666       = input_range<_Tp> && forward_iterator<iterator_t<_Tp>>;
667 
668   /// A range for which ranges::begin returns a bidirectional iterator.
669   template<typename _Tp>
670     concept bidirectional_range
671       = forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp>>;
672 
673   /// A range for which ranges::begin returns a random access iterator.
674   template<typename _Tp>
675     concept random_access_range
676       = bidirectional_range<_Tp> && random_access_iterator<iterator_t<_Tp>>;
677 
678   /// A range for which ranges::begin returns a contiguous iterator.
679   template<typename _Tp>
680     concept contiguous_range
681       = random_access_range<_Tp> && contiguous_iterator<iterator_t<_Tp>>
682       && requires(_Tp& __t)
683       {
684 	{ ranges::data(__t) } -> same_as<add_pointer_t<range_reference_t<_Tp>>>;
685       };
686 
687   /// A range for which ranges::begin and ranges::end return the same type.
688   template<typename _Tp>
689     concept common_range
690       = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>;
691 
692   namespace __detail
693   {
694     template<typename _Tp>
695       inline constexpr bool __is_initializer_list = false;
696 
697     template<typename _Tp>
698       inline constexpr bool __is_initializer_list<initializer_list<_Tp>> = true;
699   } // namespace __detail
700 
701   /// A range which can be safely converted to a view.
702   template<typename _Tp>
703     concept viewable_range = range<_Tp>
704       && ((view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>)
705 	  || (!view<remove_cvref_t<_Tp>>
706 	      && (is_lvalue_reference_v<_Tp>
707 		  || (movable<remove_reference_t<_Tp>>
708 		      && !__detail::__is_initializer_list<remove_cvref_t<_Tp>>))));
709 
710   // [range.iter.ops] range iterator operations
711 
712   struct __advance_fn final
713   {
714     template<input_or_output_iterator _It>
715       constexpr void
716       operator()(_It& __it, iter_difference_t<_It> __n) const
717       {
718 	if constexpr (random_access_iterator<_It>)
719 	  __it += __n;
720 	else if constexpr (bidirectional_iterator<_It>)
721 	  {
722 	    if (__n > 0)
723 	      {
724 		do
725 		  {
726 		    ++__it;
727 		  }
728 		while (--__n);
729 	      }
730 	    else if (__n < 0)
731 	      {
732 		do
733 		  {
734 		    --__it;
735 		  }
736 		while (++__n);
737 	      }
738 	  }
739 	else
740 	  {
741 	    // cannot decrement a non-bidirectional iterator
742 	    __glibcxx_assert(__n >= 0);
743 	    while (__n-- > 0)
744 	      ++__it;
745 	  }
746       }
747 
748     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
749       constexpr void
750       operator()(_It& __it, _Sent __bound) const
751       {
752 	if constexpr (assignable_from<_It&, _Sent>)
753 	  __it = std::move(__bound);
754 	else if constexpr (sized_sentinel_for<_Sent, _It>)
755 	  (*this)(__it, __bound - __it);
756 	else
757 	  {
758 	    while (__it != __bound)
759 	      ++__it;
760 	  }
761       }
762 
763     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
764       constexpr iter_difference_t<_It>
765       operator()(_It& __it, iter_difference_t<_It> __n, _Sent __bound) const
766       {
767 	if constexpr (sized_sentinel_for<_Sent, _It>)
768 	  {
769 	    const auto __diff = __bound - __it;
770 
771 	    if (__diff == 0)
772 	      return __n;
773 	    else if (__diff > 0 ? __n >= __diff : __n <= __diff)
774 	      {
775 		(*this)(__it, __bound);
776 		return __n - __diff;
777 	      }
778 	    else if (__n != 0) [[likely]]
779 	      {
780 		// n and bound must not lead in opposite directions:
781 		__glibcxx_assert(__n < 0 == __diff < 0);
782 
783 		(*this)(__it, __n);
784 		return 0;
785 	      }
786 	    else
787 	      return 0;
788 	  }
789 	else if (__it == __bound || __n == 0)
790 	  return __n;
791 	else if (__n > 0)
792 	  {
793 	    iter_difference_t<_It> __m = 0;
794 	    do
795 	      {
796 		++__it;
797 		++__m;
798 	      }
799 	    while (__m != __n && __it != __bound);
800 	    return __n - __m;
801 	  }
802 	else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>)
803 	  {
804 	    iter_difference_t<_It> __m = 0;
805 	    do
806 	      {
807 		--__it;
808 		--__m;
809 	      }
810 	    while (__m != __n && __it != __bound);
811 	    return __n - __m;
812 	  }
813 	else
814 	  {
815 	    // cannot decrement a non-bidirectional iterator
816 	    __glibcxx_assert(__n >= 0);
817 	    return __n;
818 	  }
819       }
820 
821     void operator&() const = delete;
822   };
823 
824   inline constexpr __advance_fn advance{};
825 
826   struct __distance_fn final
827   {
828     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
829       requires (!sized_sentinel_for<_Sent, _It>)
830       constexpr iter_difference_t<_It>
831       operator()[[nodiscard]](_It __first, _Sent __last) const
832       {
833 	iter_difference_t<_It> __n = 0;
834 	while (__first != __last)
835 	  {
836 	    ++__first;
837 	    ++__n;
838 	  }
839 	return __n;
840       }
841 
842     template<input_or_output_iterator _It, sized_sentinel_for<_It> _Sent>
843       [[nodiscard]]
844       constexpr iter_difference_t<_It>
845       operator()(const _It& __first, const _Sent& __last) const
846       {
847 	return __last - __first;
848       }
849 
850     template<range _Range>
851       [[nodiscard]]
852       constexpr range_difference_t<_Range>
853       operator()(_Range&& __r) const
854       {
855 	if constexpr (sized_range<_Range>)
856 	  return static_cast<range_difference_t<_Range>>(ranges::size(__r));
857 	else
858 	  return (*this)(ranges::begin(__r), ranges::end(__r));
859       }
860 
861     void operator&() const = delete;
862   };
863 
864   inline constexpr __distance_fn distance{};
865 
866   struct __next_fn final
867   {
868     template<input_or_output_iterator _It>
869       [[nodiscard]]
870       constexpr _It
871       operator()(_It __x) const
872       {
873 	++__x;
874 	return __x;
875       }
876 
877     template<input_or_output_iterator _It>
878       [[nodiscard]]
879       constexpr _It
880       operator()(_It __x, iter_difference_t<_It> __n) const
881       {
882 	ranges::advance(__x, __n);
883 	return __x;
884       }
885 
886     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
887       [[nodiscard]]
888       constexpr _It
889       operator()(_It __x, _Sent __bound) const
890       {
891 	ranges::advance(__x, __bound);
892 	return __x;
893       }
894 
895     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
896       [[nodiscard]]
897       constexpr _It
898       operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const
899       {
900 	ranges::advance(__x, __n, __bound);
901 	return __x;
902       }
903 
904     void operator&() const = delete;
905   };
906 
907   inline constexpr __next_fn next{};
908 
909   struct __prev_fn final
910   {
911     template<bidirectional_iterator _It>
912       [[nodiscard]]
913       constexpr _It
914       operator()(_It __x) const
915       {
916 	--__x;
917 	return __x;
918       }
919 
920     template<bidirectional_iterator _It>
921       [[nodiscard]]
922       constexpr _It
923       operator()(_It __x, iter_difference_t<_It> __n) const
924       {
925 	ranges::advance(__x, -__n);
926 	return __x;
927       }
928 
929     template<bidirectional_iterator _It>
930       [[nodiscard]]
931       constexpr _It
932       operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const
933       {
934 	ranges::advance(__x, -__n, __bound);
935 	return __x;
936       }
937 
938     void operator&() const = delete;
939   };
940 
941   inline constexpr __prev_fn prev{};
942 
943   /// Type returned by algorithms instead of a dangling iterator or subrange.
944   struct dangling
945   {
946     constexpr dangling() noexcept = default;
947     template<typename... _Args>
948       constexpr dangling(_Args&&...) noexcept { }
949   };
950 
951   template<range _Range>
952     using borrowed_iterator_t = __conditional_t<borrowed_range<_Range>,
953 						iterator_t<_Range>,
954 						dangling>;
955 
956 } // namespace ranges
957 _GLIBCXX_END_NAMESPACE_VERSION
958 } // namespace std
959 #endif // library concepts
960 #endif // C++20
961 #endif // _GLIBCXX_RANGES_BASE_H
962