1 | // Core concepts and definitions for <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_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 |
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()(_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()(_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 | constexpr auto |
196 | operator()(_Tp&& __e) const |
197 | noexcept(noexcept(_Begin{}(__cust_access::__as_const<_Tp>(__e)))) |
198 | requires requires { _Begin{}(__cust_access::__as_const<_Tp>(__e)); } |
199 | { |
200 | return _Begin{}(__cust_access::__as_const<_Tp>(__e)); |
201 | } |
202 | }; |
203 | |
204 | struct _CEnd |
205 | { |
206 | template<typename _Tp> |
207 | constexpr auto |
208 | operator()(_Tp&& __e) const |
209 | noexcept(noexcept(_End{}(__cust_access::__as_const<_Tp>(__e)))) |
210 | requires requires { _End{}(__cust_access::__as_const<_Tp>(__e)); } |
211 | { |
212 | return _End{}(__cust_access::__as_const<_Tp>(__e)); |
213 | } |
214 | }; |
215 | |
216 | template<typename _Tp> |
217 | concept __member_rbegin = requires(_Tp& __t) |
218 | { |
219 | { __decay_copy(__t.rbegin()) } -> input_or_output_iterator; |
220 | }; |
221 | |
222 | void rbegin(auto&) = delete; |
223 | void rbegin(const auto&) = delete; |
224 | |
225 | template<typename _Tp> |
226 | concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>> |
227 | && requires(_Tp& __t) |
228 | { |
229 | { __decay_copy(rbegin(__t)) } -> input_or_output_iterator; |
230 | }; |
231 | |
232 | template<typename _Tp> |
233 | concept __reversable = requires(_Tp& __t) |
234 | { |
235 | { _Begin{}(__t) } -> bidirectional_iterator; |
236 | { _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>; |
237 | }; |
238 | |
239 | struct _RBegin |
240 | { |
241 | private: |
242 | template<typename _Tp> |
243 | static constexpr bool |
244 | _S_noexcept() |
245 | { |
246 | if constexpr (__member_rbegin<_Tp>) |
247 | return noexcept(__decay_copy(std::declval<_Tp&>().rbegin())); |
248 | else if constexpr (__adl_rbegin<_Tp>) |
249 | return noexcept(__decay_copy(rbegin(std::declval<_Tp&>()))); |
250 | else |
251 | { |
252 | if constexpr (noexcept(_End{}(std::declval<_Tp&>()))) |
253 | { |
254 | using _It = decltype(_End{}(std::declval<_Tp&>())); |
255 | // std::reverse_iterator copy-initializes its member. |
256 | return is_nothrow_copy_constructible_v<_It>; |
257 | } |
258 | else |
259 | return false; |
260 | } |
261 | } |
262 | |
263 | public: |
264 | template<__maybe_borrowed_range _Tp> |
265 | requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp> |
266 | constexpr auto |
267 | operator()(_Tp&& __t) const |
268 | noexcept(_S_noexcept<_Tp&>()) |
269 | { |
270 | if constexpr (__member_rbegin<_Tp>) |
271 | return __t.rbegin(); |
272 | else if constexpr (__adl_rbegin<_Tp>) |
273 | return rbegin(__t); |
274 | else |
275 | return std::make_reverse_iterator(_End{}(__t)); |
276 | } |
277 | }; |
278 | |
279 | template<typename _Tp> |
280 | concept __member_rend = requires(_Tp& __t) |
281 | { |
282 | { __decay_copy(__t.rend()) } |
283 | -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>; |
284 | }; |
285 | |
286 | void rend(auto&) = delete; |
287 | void rend(const auto&) = delete; |
288 | |
289 | template<typename _Tp> |
290 | concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>> |
291 | && requires(_Tp& __t) |
292 | { |
293 | { __decay_copy(rend(__t)) } |
294 | -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>; |
295 | }; |
296 | |
297 | struct _REnd |
298 | { |
299 | private: |
300 | template<typename _Tp> |
301 | static constexpr bool |
302 | _S_noexcept() |
303 | { |
304 | if constexpr (__member_rend<_Tp>) |
305 | return noexcept(__decay_copy(std::declval<_Tp&>().rend())); |
306 | else if constexpr (__adl_rend<_Tp>) |
307 | return noexcept(__decay_copy(rend(std::declval<_Tp&>()))); |
308 | else |
309 | { |
310 | if constexpr (noexcept(_Begin{}(std::declval<_Tp&>()))) |
311 | { |
312 | using _It = decltype(_Begin{}(std::declval<_Tp&>())); |
313 | // std::reverse_iterator copy-initializes its member. |
314 | return is_nothrow_copy_constructible_v<_It>; |
315 | } |
316 | else |
317 | return false; |
318 | } |
319 | } |
320 | |
321 | public: |
322 | template<__maybe_borrowed_range _Tp> |
323 | requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp> |
324 | constexpr auto |
325 | operator()(_Tp&& __t) const |
326 | noexcept(_S_noexcept<_Tp&>()) |
327 | { |
328 | if constexpr (__member_rend<_Tp>) |
329 | return __t.rend(); |
330 | else if constexpr (__adl_rend<_Tp>) |
331 | return rend(__t); |
332 | else |
333 | return std::make_reverse_iterator(_Begin{}(__t)); |
334 | } |
335 | }; |
336 | |
337 | struct _CRBegin |
338 | { |
339 | template<typename _Tp> |
340 | constexpr auto |
341 | operator()(_Tp&& __e) const |
342 | noexcept(noexcept(_RBegin{}(__cust_access::__as_const<_Tp>(__e)))) |
343 | requires requires { _RBegin{}(__cust_access::__as_const<_Tp>(__e)); } |
344 | { |
345 | return _RBegin{}(__cust_access::__as_const<_Tp>(__e)); |
346 | } |
347 | }; |
348 | |
349 | struct _CREnd |
350 | { |
351 | template<typename _Tp> |
352 | constexpr auto |
353 | operator()(_Tp&& __e) const |
354 | noexcept(noexcept(_REnd{}(__cust_access::__as_const<_Tp>(__e)))) |
355 | requires requires { _REnd{}(__cust_access::__as_const<_Tp>(__e)); } |
356 | { |
357 | return _REnd{}(__cust_access::__as_const<_Tp>(__e)); |
358 | } |
359 | }; |
360 | |
361 | template<typename _Tp> |
362 | concept __member_size = !disable_sized_range<remove_cvref_t<_Tp>> |
363 | && requires(_Tp& __t) |
364 | { |
365 | { __decay_copy(__t.size()) } -> __detail::__is_integer_like; |
366 | }; |
367 | |
368 | void size(auto&) = delete; |
369 | void size(const auto&) = delete; |
370 | |
371 | template<typename _Tp> |
372 | concept __adl_size = __class_or_enum<remove_reference_t<_Tp>> |
373 | && !disable_sized_range<remove_cvref_t<_Tp>> |
374 | && requires(_Tp& __t) |
375 | { |
376 | { __decay_copy(size(__t)) } -> __detail::__is_integer_like; |
377 | }; |
378 | |
379 | template<typename _Tp> |
380 | concept __sentinel_size = requires(_Tp& __t) |
381 | { |
382 | requires (!is_unbounded_array_v<remove_reference_t<_Tp>>); |
383 | |
384 | { _Begin{}(__t) } -> forward_iterator; |
385 | |
386 | { _End{}(__t) } -> sized_sentinel_for<decltype(_Begin{}(__t))>; |
387 | |
388 | __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t)); |
389 | }; |
390 | |
391 | struct _Size |
392 | { |
393 | private: |
394 | template<typename _Tp> |
395 | static constexpr bool |
396 | _S_noexcept() |
397 | { |
398 | if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>) |
399 | return true; |
400 | else if constexpr (__member_size<_Tp>) |
401 | return noexcept(__decay_copy(std::declval<_Tp&>().size())); |
402 | else if constexpr (__adl_size<_Tp>) |
403 | return noexcept(__decay_copy(size(std::declval<_Tp&>()))); |
404 | else if constexpr (__sentinel_size<_Tp>) |
405 | return noexcept(_End{}(std::declval<_Tp&>()) |
406 | - _Begin{}(std::declval<_Tp&>())); |
407 | } |
408 | |
409 | public: |
410 | template<typename _Tp> |
411 | requires is_bounded_array_v<remove_reference_t<_Tp>> |
412 | || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp> |
413 | constexpr auto |
414 | operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) |
415 | { |
416 | if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>) |
417 | return extent_v<remove_reference_t<_Tp>>; |
418 | else if constexpr (__member_size<_Tp>) |
419 | return __t.size(); |
420 | else if constexpr (__adl_size<_Tp>) |
421 | return size(__t); |
422 | else if constexpr (__sentinel_size<_Tp>) |
423 | return __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t)); |
424 | } |
425 | }; |
426 | |
427 | struct _SSize |
428 | { |
429 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
430 | // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E) |
431 | template<typename _Tp> |
432 | requires requires (_Tp& __t) { _Size{}(__t); } |
433 | constexpr auto |
434 | operator()(_Tp&& __t) const noexcept(noexcept(_Size{}(__t))) |
435 | { |
436 | auto __size = _Size{}(__t); |
437 | using __size_type = decltype(__size); |
438 | // Return the wider of ptrdiff_t and make-signed-like-t<__size_type>. |
439 | if constexpr (integral<__size_type>) |
440 | { |
441 | using __gnu_cxx::__int_traits; |
442 | if constexpr (__int_traits<__size_type>::__digits |
443 | < __int_traits<ptrdiff_t>::__digits) |
444 | return static_cast<ptrdiff_t>(__size); |
445 | else |
446 | return static_cast<make_signed_t<__size_type>>(__size); |
447 | } |
448 | #if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ |
449 | // For strict-ansi modes integral<__int128> is false |
450 | else if constexpr (__detail::__is_int128<__size_type>) |
451 | return static_cast<__int128>(__size); |
452 | #endif |
453 | else // Must be one of __max_diff_type or __max_size_type. |
454 | return __detail::__max_diff_type(__size); |
455 | } |
456 | }; |
457 | |
458 | template<typename _Tp> |
459 | concept __member_empty = requires(_Tp& __t) { bool(__t.empty()); }; |
460 | |
461 | template<typename _Tp> |
462 | concept __size0_empty = requires(_Tp& __t) { _Size{}(__t) == 0; }; |
463 | |
464 | template<typename _Tp> |
465 | concept __eq_iter_empty = requires(_Tp& __t) |
466 | { |
467 | requires (!is_unbounded_array_v<remove_reference_t<_Tp>>); |
468 | |
469 | { _Begin{}(__t) } -> forward_iterator; |
470 | |
471 | bool(_Begin{}(__t) == _End{}(__t)); |
472 | }; |
473 | |
474 | struct _Empty |
475 | { |
476 | private: |
477 | template<typename _Tp> |
478 | static constexpr bool |
479 | _S_noexcept() |
480 | { |
481 | if constexpr (__member_empty<_Tp>) |
482 | return noexcept(bool(std::declval<_Tp&>().empty())); |
483 | else if constexpr (__size0_empty<_Tp>) |
484 | return noexcept(_Size{}(std::declval<_Tp&>()) == 0); |
485 | else |
486 | return noexcept(bool(_Begin{}(std::declval<_Tp&>()) |
487 | == _End{}(std::declval<_Tp&>()))); |
488 | } |
489 | |
490 | public: |
491 | template<typename _Tp> |
492 | requires __member_empty<_Tp> || __size0_empty<_Tp> |
493 | || __eq_iter_empty<_Tp> |
494 | constexpr bool |
495 | operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp&>()) |
496 | { |
497 | if constexpr (__member_empty<_Tp>) |
498 | return bool(__t.empty()); |
499 | else if constexpr (__size0_empty<_Tp>) |
500 | return _Size{}(__t) == 0; |
501 | else |
502 | return bool(_Begin{}(__t) == _End{}(__t)); |
503 | } |
504 | }; |
505 | |
506 | template<typename _Tp> |
507 | concept __pointer_to_object = is_pointer_v<_Tp> |
508 | && is_object_v<remove_pointer_t<_Tp>>; |
509 | |
510 | template<typename _Tp> |
511 | concept __member_data = requires(_Tp& __t) |
512 | { |
513 | { __decay_copy(__t.data()) } -> __pointer_to_object; |
514 | }; |
515 | |
516 | template<typename _Tp> |
517 | concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>; |
518 | |
519 | struct _Data |
520 | { |
521 | private: |
522 | template<typename _Tp> |
523 | static constexpr bool |
524 | _S_noexcept() |
525 | { |
526 | if constexpr (__member_data<_Tp>) |
527 | return noexcept(__decay_copy(std::declval<_Tp&>().data())); |
528 | else |
529 | return noexcept(_Begin{}(std::declval<_Tp&>())); |
530 | } |
531 | |
532 | public: |
533 | template<__maybe_borrowed_range _Tp> |
534 | requires __member_data<_Tp> || __begin_data<_Tp> |
535 | constexpr auto |
536 | operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>()) |
537 | { |
538 | if constexpr (__member_data<_Tp>) |
539 | return __t.data(); |
540 | else |
541 | return std::to_address(_Begin{}(__t)); |
542 | } |
543 | }; |
544 | |
545 | struct _CData |
546 | { |
547 | template<typename _Tp> |
548 | constexpr auto |
549 | operator()(_Tp&& __e) const |
550 | noexcept(noexcept(_Data{}(__cust_access::__as_const<_Tp>(__e)))) |
551 | requires requires { _Data{}(__cust_access::__as_const<_Tp>(__e)); } |
552 | { |
553 | return _Data{}(__cust_access::__as_const<_Tp>(__e)); |
554 | } |
555 | }; |
556 | |
557 | } // namespace __cust_access |
558 | |
559 | inline namespace __cust |
560 | { |
561 | inline constexpr __cust_access::_Begin begin{}; |
562 | inline constexpr __cust_access::_End end{}; |
563 | inline constexpr __cust_access::_CBegin cbegin{}; |
564 | inline constexpr __cust_access::_CEnd cend{}; |
565 | inline constexpr __cust_access::_RBegin rbegin{}; |
566 | inline constexpr __cust_access::_REnd rend{}; |
567 | inline constexpr __cust_access::_CRBegin crbegin{}; |
568 | inline constexpr __cust_access::_CREnd crend{}; |
569 | inline constexpr __cust_access::_Size size{}; |
570 | inline constexpr __cust_access::_SSize ssize{}; |
571 | inline constexpr __cust_access::_Empty empty{}; |
572 | inline constexpr __cust_access::_Data data{}; |
573 | inline constexpr __cust_access::_CData cdata{}; |
574 | } |
575 | |
576 | /// [range.range] The range concept. |
577 | template<typename _Tp> |
578 | concept range = requires(_Tp& __t) |
579 | { |
580 | ranges::begin(__t); |
581 | ranges::end(__t); |
582 | }; |
583 | |
584 | /// [range.range] The borrowed_range concept. |
585 | template<typename _Tp> |
586 | concept borrowed_range |
587 | = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>; |
588 | |
589 | template<typename _Tp> |
590 | using iterator_t = std::__detail::__range_iter_t<_Tp>; |
591 | |
592 | template<range _Range> |
593 | using sentinel_t = decltype(ranges::end(std::declval<_Range&>())); |
594 | |
595 | template<range _Range> |
596 | using range_difference_t = iter_difference_t<iterator_t<_Range>>; |
597 | |
598 | template<range _Range> |
599 | using range_value_t = iter_value_t<iterator_t<_Range>>; |
600 | |
601 | template<range _Range> |
602 | using range_reference_t = iter_reference_t<iterator_t<_Range>>; |
603 | |
604 | template<range _Range> |
605 | using range_rvalue_reference_t |
606 | = iter_rvalue_reference_t<iterator_t<_Range>>; |
607 | |
608 | /// [range.sized] The sized_range concept. |
609 | template<typename _Tp> |
610 | concept sized_range = range<_Tp> |
611 | && requires(_Tp& __t) { ranges::size(__t); }; |
612 | |
613 | template<sized_range _Range> |
614 | using range_size_t = decltype(ranges::size(std::declval<_Range&>())); |
615 | |
616 | /// [range.view] The ranges::view_base type. |
617 | struct view_base { }; |
618 | |
619 | /// [range.view] The ranges::enable_view boolean. |
620 | template<typename _Tp> |
621 | inline constexpr bool enable_view = derived_from<_Tp, view_base>; |
622 | |
623 | /// [range.view] The ranges::view concept. |
624 | template<typename _Tp> |
625 | concept view |
626 | = range<_Tp> && movable<_Tp> && enable_view<_Tp>; |
627 | |
628 | // [range.refinements] |
629 | |
630 | /// A range for which ranges::begin returns an output iterator. |
631 | template<typename _Range, typename _Tp> |
632 | concept output_range |
633 | = range<_Range> && output_iterator<iterator_t<_Range>, _Tp>; |
634 | |
635 | /// A range for which ranges::begin returns an input iterator. |
636 | template<typename _Tp> |
637 | concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>; |
638 | |
639 | /// A range for which ranges::begin returns a forward iterator. |
640 | template<typename _Tp> |
641 | concept forward_range |
642 | = input_range<_Tp> && forward_iterator<iterator_t<_Tp>>; |
643 | |
644 | /// A range for which ranges::begin returns a bidirectional iterator. |
645 | template<typename _Tp> |
646 | concept bidirectional_range |
647 | = forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp>>; |
648 | |
649 | /// A range for which ranges::begin returns a random access iterator. |
650 | template<typename _Tp> |
651 | concept random_access_range |
652 | = bidirectional_range<_Tp> && random_access_iterator<iterator_t<_Tp>>; |
653 | |
654 | /// A range for which ranges::begin returns a contiguous iterator. |
655 | template<typename _Tp> |
656 | concept contiguous_range |
657 | = random_access_range<_Tp> && contiguous_iterator<iterator_t<_Tp>> |
658 | && requires(_Tp& __t) |
659 | { |
660 | { ranges::data(__t) } -> same_as<add_pointer_t<range_reference_t<_Tp>>>; |
661 | }; |
662 | |
663 | /// A range for which ranges::begin and ranges::end return the same type. |
664 | template<typename _Tp> |
665 | concept common_range |
666 | = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>; |
667 | |
668 | /// A range which can be safely converted to a view. |
669 | template<typename _Tp> |
670 | concept viewable_range = range<_Tp> |
671 | && ((view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>) |
672 | || (!view<remove_cvref_t<_Tp>> && borrowed_range<_Tp>)); |
673 | |
674 | // [range.iter.ops] range iterator operations |
675 | |
676 | struct __advance_fn |
677 | { |
678 | template<input_or_output_iterator _It> |
679 | constexpr void |
680 | operator()(_It& __it, iter_difference_t<_It> __n) const |
681 | { |
682 | if constexpr (random_access_iterator<_It>) |
683 | __it += __n; |
684 | else if constexpr (bidirectional_iterator<_It>) |
685 | { |
686 | if (__n > 0) |
687 | { |
688 | do |
689 | { |
690 | ++__it; |
691 | } |
692 | while (--__n); |
693 | } |
694 | else if (__n < 0) |
695 | { |
696 | do |
697 | { |
698 | --__it; |
699 | } |
700 | while (++__n); |
701 | } |
702 | } |
703 | else |
704 | { |
705 | // cannot decrement a non-bidirectional iterator |
706 | __glibcxx_assert(__n >= 0); |
707 | while (__n-- > 0) |
708 | ++__it; |
709 | } |
710 | } |
711 | |
712 | template<input_or_output_iterator _It, sentinel_for<_It> _Sent> |
713 | constexpr void |
714 | operator()(_It& __it, _Sent __bound) const |
715 | { |
716 | if constexpr (assignable_from<_It&, _Sent>) |
717 | __it = std::move(__bound); |
718 | else if constexpr (sized_sentinel_for<_Sent, _It>) |
719 | (*this)(__it, __bound - __it); |
720 | else |
721 | { |
722 | while (__it != __bound) |
723 | ++__it; |
724 | } |
725 | } |
726 | |
727 | template<input_or_output_iterator _It, sentinel_for<_It> _Sent> |
728 | constexpr iter_difference_t<_It> |
729 | operator()(_It& __it, iter_difference_t<_It> __n, _Sent __bound) const |
730 | { |
731 | if constexpr (sized_sentinel_for<_Sent, _It>) |
732 | { |
733 | const auto __diff = __bound - __it; |
734 | |
735 | if (__diff == 0) |
736 | return __n; |
737 | else if (__diff > 0 ? __n >= __diff : __n <= __diff) |
738 | { |
739 | (*this)(__it, __bound); |
740 | return __n - __diff; |
741 | } |
742 | else if (__n != 0) [[likely]] |
743 | { |
744 | // n and bound must not lead in opposite directions: |
745 | __glibcxx_assert(__n < 0 == __diff < 0); |
746 | |
747 | (*this)(__it, __n); |
748 | return 0; |
749 | } |
750 | else |
751 | return 0; |
752 | } |
753 | else if (__it == __bound || __n == 0) |
754 | return __n; |
755 | else if (__n > 0) |
756 | { |
757 | iter_difference_t<_It> __m = 0; |
758 | do |
759 | { |
760 | ++__it; |
761 | ++__m; |
762 | } |
763 | while (__m != __n && __it != __bound); |
764 | return __n - __m; |
765 | } |
766 | else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>) |
767 | { |
768 | iter_difference_t<_It> __m = 0; |
769 | do |
770 | { |
771 | --__it; |
772 | --__m; |
773 | } |
774 | while (__m != __n && __it != __bound); |
775 | return __n - __m; |
776 | } |
777 | else |
778 | { |
779 | // cannot decrement a non-bidirectional iterator |
780 | __glibcxx_assert(__n >= 0); |
781 | return __n; |
782 | } |
783 | } |
784 | }; |
785 | |
786 | inline constexpr __advance_fn advance{}; |
787 | |
788 | struct __distance_fn |
789 | { |
790 | template<input_or_output_iterator _It, sentinel_for<_It> _Sent> |
791 | constexpr iter_difference_t<_It> |
792 | operator()(_It __first, _Sent __last) const |
793 | { |
794 | if constexpr (sized_sentinel_for<_Sent, _It>) |
795 | return __last - __first; |
796 | else |
797 | { |
798 | iter_difference_t<_It> __n = 0; |
799 | while (__first != __last) |
800 | { |
801 | ++__first; |
802 | ++__n; |
803 | } |
804 | return __n; |
805 | } |
806 | } |
807 | |
808 | template<range _Range> |
809 | constexpr range_difference_t<_Range> |
810 | operator()(_Range&& __r) const |
811 | { |
812 | if constexpr (sized_range<_Range>) |
813 | return static_cast<range_difference_t<_Range>>(ranges::size(__r)); |
814 | else |
815 | return (*this)(ranges::begin(__r), ranges::end(__r)); |
816 | } |
817 | }; |
818 | |
819 | inline constexpr __distance_fn distance{}; |
820 | |
821 | struct __next_fn |
822 | { |
823 | template<input_or_output_iterator _It> |
824 | constexpr _It |
825 | operator()(_It __x) const |
826 | { |
827 | ++__x; |
828 | return __x; |
829 | } |
830 | |
831 | template<input_or_output_iterator _It> |
832 | constexpr _It |
833 | operator()(_It __x, iter_difference_t<_It> __n) const |
834 | { |
835 | ranges::advance(__x, __n); |
836 | return __x; |
837 | } |
838 | |
839 | template<input_or_output_iterator _It, sentinel_for<_It> _Sent> |
840 | constexpr _It |
841 | operator()(_It __x, _Sent __bound) const |
842 | { |
843 | ranges::advance(__x, __bound); |
844 | return __x; |
845 | } |
846 | |
847 | template<input_or_output_iterator _It, sentinel_for<_It> _Sent> |
848 | constexpr _It |
849 | operator()(_It __x, iter_difference_t<_It> __n, _Sent __bound) const |
850 | { |
851 | ranges::advance(__x, __n, __bound); |
852 | return __x; |
853 | } |
854 | }; |
855 | |
856 | inline constexpr __next_fn next{}; |
857 | |
858 | struct __prev_fn |
859 | { |
860 | template<bidirectional_iterator _It> |
861 | constexpr _It |
862 | operator()(_It __x) const |
863 | { |
864 | --__x; |
865 | return __x; |
866 | } |
867 | |
868 | template<bidirectional_iterator _It> |
869 | constexpr _It |
870 | operator()(_It __x, iter_difference_t<_It> __n) const |
871 | { |
872 | ranges::advance(__x, -__n); |
873 | return __x; |
874 | } |
875 | |
876 | template<bidirectional_iterator _It> |
877 | constexpr _It |
878 | operator()(_It __x, iter_difference_t<_It> __n, _It __bound) const |
879 | { |
880 | ranges::advance(__x, -__n, __bound); |
881 | return __x; |
882 | } |
883 | }; |
884 | |
885 | inline constexpr __prev_fn prev{}; |
886 | |
887 | /// Type returned by algorithms instead of a dangling iterator or subrange. |
888 | struct dangling |
889 | { |
890 | constexpr dangling() noexcept = default; |
891 | template<typename... _Args> |
892 | constexpr dangling(_Args&&...) noexcept { } |
893 | }; |
894 | |
895 | template<range _Range> |
896 | using borrowed_iterator_t = conditional_t<borrowed_range<_Range>, |
897 | iterator_t<_Range>, |
898 | dangling>; |
899 | |
900 | } // namespace ranges |
901 | _GLIBCXX_END_NAMESPACE_VERSION |
902 | } // namespace std |
903 | #endif // library concepts |
904 | #endif // C++20 |
905 | #endif // _GLIBCXX_RANGES_BASE_H |
906 | |