1 /// \file
2 // Range v3 library
3 //
4 //  Copyright Eric Niebler 2013-present
5 //
6 //  Use, modification and distribution is subject to the
7 //  Boost Software License, Version 1.0. (See accompanying
8 //  file LICENSE_1_0.txt or copy at
9 //  http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // Project home: https://github.com/ericniebler/range-v3
12 //
13 
14 #ifndef RANGES_V3_VIEW_IOTA_HPP
15 #define RANGES_V3_VIEW_IOTA_HPP
16 
17 #include <climits>
18 #include <cstdint>
19 #include <limits>
20 #include <type_traits>
21 
22 #include <meta/meta.hpp>
23 
24 #include <concepts/concepts.hpp>
25 
26 #include <range/v3/range_fwd.hpp>
27 
28 #include <range/v3/iterator/default_sentinel.hpp>
29 #include <range/v3/iterator/diffmax_t.hpp>
30 #include <range/v3/utility/static_const.hpp>
31 #include <range/v3/view/delimit.hpp>
32 #include <range/v3/view/facade.hpp>
33 
34 #include <range/v3/detail/prologue.hpp>
35 
36 RANGES_DIAGNOSTIC_PUSH
37 RANGES_DIAGNOSTIC_IGNORE_UNSIGNED_MATH
38 RANGES_DIAGNOSTIC_IGNORE_TRUNCATION
39 
40 namespace ranges
41 {
42     /// \cond
43     namespace detail
44     {
45         template<std::size_t N, typename = void>
46         struct promote_as_signed_
47         {
48             // This shouldn't cause us to LOSE precision, but maybe it doesn't
49             // net us any either.
50             static_assert(sizeof(std::intmax_t) * CHAR_BIT >= N,
51                           "Possible extended integral type?");
52             using difference_type = diffmax_t;
53         };
54 
55         template<std::size_t N>
56         struct promote_as_signed_<N, enable_if_t<(N < 16)>>
57         {
58             using difference_type = std::int_fast16_t;
59         };
60 
61         template<std::size_t N>
62         struct promote_as_signed_<N, enable_if_t<(N >= 16 && N < 32)>>
63         {
64             using difference_type = std::int_fast32_t;
65         };
66 
67         template<std::size_t N>
68         struct promote_as_signed_<N, enable_if_t<(N >= 32 && N < 64)>>
69         {
70             using difference_type = std::int_fast64_t;
71         };
72 
73         template<typename I>
74         using iota_difference_t = typename meta::conditional_t<
75             std::is_integral<I>::value && sizeof(I) == sizeof(iter_difference_t<I>),
76             promote_as_signed_<sizeof(iter_difference_t<I>) * CHAR_BIT>,
77             with_difference_type_<iter_difference_t<I>>>::difference_type;
78 
79         // clang-format off
80         template<typename I>
81         CPP_requires(_decrementable_,
82             requires(I i) //
83             (
84                 --i,
85                 i--,
86                 concepts::requires_<same_as<I&, decltype(--i)>>,
87                 concepts::requires_<same_as<I, decltype(i--)>>
88             ));
89         template<typename I>
90         CPP_concept decrementable_ =
91             incrementable<I> &&
92             CPP_requires_ref(detail::_decrementable_, I);
93 
94         template<typename I>
95         CPP_requires(_advanceable_,
96             requires(I i, I const j, iota_difference_t<I> const n) //
97             (
98                 j - j,
99                 i += n,
100                 i -= n,
101                 static_cast<I>(j - n),
102                 static_cast<I>(j + n),
103                 static_cast<I>(n + j),
104                 // NOT TO SPEC:
105                 // Unsigned integers are advanceable, but subtracting them results in
106                 // an unsigned integral, which is not the same as the difference type,
107                 // which is signed.
108                 concepts::requires_<convertible_to<decltype(j - j), iota_difference_t<I>>>,
109                 concepts::requires_<same_as<I&, decltype(i += n)>>,
110                 concepts::requires_<same_as<I&, decltype(i -= n)>> //,
111                 // concepts::requires_<convertible_to<decltype(i - n), I>>,
112                 // concepts::requires_<convertible_to<decltype(i + n), I>>,
113                 // concepts::requires_<convertible_to<decltype(n + i), I>>
114             ));
115         template<typename I>
116         CPP_concept advanceable_ =
117             decrementable_<I> && totally_ordered<I> &&
118             CPP_requires_ref(detail::_advanceable_, I);
119         // clang-format on
120 
121         template(typename I)(
122             /// \pre
123             requires (!unsigned_integral<I>)) //
124         void iota_advance_(I & i, iota_difference_t<I> n)
125         {
126             // TODO: bounds-check this
127             i += n;
128         }
129 
130         template(typename Int)(
131             /// \pre
132             requires unsigned_integral<Int>)
133         void iota_advance_(Int & i, iota_difference_t<Int> n)
134         {
135             // TODO: bounds-check this
136             if(n >= 0)
137                 i += static_cast<Int>(n);
138             else
139                 i -= static_cast<Int>(-n);
140         }
141 
142         template(typename I)(
143             /// \pre
144             requires advanceable_<I> AND (!integral<I>)) //
145         iota_difference_t<I> iota_distance_(I const & i, I const & s)
146         {
147             return static_cast<iota_difference_t<I>>(s - i);
148         }
149 
150         template(typename Int)(
151             /// \pre
152             requires signed_integral<Int>)
iota_distance_(Int i0,Int i1)153         iota_difference_t<Int> iota_distance_(Int i0, Int i1)
154         {
155             // TODO: bounds-check this
156             return static_cast<iota_difference_t<Int>>(
157                 static_cast<iota_difference_t<Int>>(i1) -
158                 static_cast<iota_difference_t<Int>>(i0));
159         }
160 
161         template(typename Int)(
162             /// \pre
163             requires unsigned_integral<Int>)
iota_distance_(Int i0,Int i1)164         iota_difference_t<Int> iota_distance_(Int i0, Int i1)
165         {
166             // TODO: bounds-check this
167             return (i0 > i1) ? static_cast<iota_difference_t<Int>>(
168                                    -static_cast<iota_difference_t<Int>>(i0 - i1))
169                              : static_cast<iota_difference_t<Int>>(i1 - i0);
170         }
171     } // namespace detail
172     /// \endcond
173 
174     /// \addtogroup group-views
175     /// @{
176 
177     /// An iota view in a closed range
178     template<typename From, typename To /* = From */>
179     struct RANGES_EMPTY_BASES closed_iota_view
180       : view_facade<closed_iota_view<From, To>, finite>
181     {
182     private:
183         friend range_access;
184 
185         From from_ = From();
186         RANGES_NO_UNIQUE_ADDRESS To to_ = To();
187 
188         struct cursor
189         {
190             using difference_type = detail::iota_difference_t<From>;
191 
192         private:
193             friend range_access;
194             From from_ = From();
195             RANGES_NO_UNIQUE_ADDRESS To to_ = To();
196             bool done_ = false;
197 
readranges::closed_iota_view::cursor198             From read() const
199             {
200                 RANGES_EXPECT(!done_);
201                 return from_;
202             }
nextranges::closed_iota_view::cursor203             void next()
204             {
205                 RANGES_EXPECT(!done_);
206                 if(from_ == to_)
207                     done_ = true;
208                 else
209                     ++from_;
210             }
equalranges::closed_iota_view::cursor211             bool equal(default_sentinel_t) const
212             {
213                 return done_;
214             }
215             CPP_member
equalranges::closed_iota_view::cursor216             auto equal(cursor const & that) const //
217                 -> CPP_ret(bool)(
218                     /// \pre
219                     requires equality_comparable<From>)
220             {
221                 return that.from_ == from_ && that.done_ == done_;
222             }
223             CPP_member
prevranges::closed_iota_view::cursor224             auto prev() //
225                 -> CPP_ret(void)(
226                     /// \pre
227                     requires detail::decrementable_<From>)
228             {
229                 if(done_)
230                     done_ = false;
231                 else
232                     --from_;
233             }
234             CPP_member
advanceranges::closed_iota_view::cursor235             auto advance(difference_type n) //
236                 -> CPP_ret(void)(
237                     /// \pre
238                     requires detail::advanceable_<From>)
239             {
240                 if(n > 0)
241                 {
242                     RANGES_ENSURE(detail::iota_distance_(from_, to_) >= n - !done_);
243                     detail::iota_advance_(
244                         from_,
245                         n - (done_ = (detail::iota_distance_(from_, to_) <= n - !done_)));
246                 }
247                 else if(n < 0)
248                     detail::iota_advance_(from_, n + std::exchange(done_, false));
249             }
250             CPP_member
distance_toranges::closed_iota_view::cursor251             auto distance_to(cursor const & that) const //
252                 -> CPP_ret(difference_type)(
253                     /// \pre
254                     requires detail::advanceable_<From>)
255             {
256                 using D = difference_type;
257                 return static_cast<D>(detail::iota_distance_(from_, that.from_)) +
258                        ((D)that.done_ - (D)done_);
259             }
260             CPP_member
distance_toranges::closed_iota_view::cursor261             auto distance_to(default_sentinel_t) const //
262                 -> CPP_ret(difference_type)(
263                     /// \pre
264                     requires sized_sentinel_for<To, From>)
265             {
266                 return difference_type(to_ - from_) + !done_;
267             }
268 
269         public:
270             cursor() = default;
cursorranges::closed_iota_view::cursor271             constexpr cursor(From from, To to, bool done = false)
272               : from_(std::move(from))
273               , to_(std::move(to))
274               , done_(done)
275             {}
276         };
277 
begin_cursorranges::closed_iota_view278         cursor begin_cursor() const
279         {
280             return {from_, to_};
281         }
282         CPP_member
end_cursorranges::closed_iota_view283         auto end_cursor() const //
284             -> CPP_ret(cursor)(
285                 /// \pre
286                 requires same_as<From, To>)
287         {
288             return {to_, to_, true};
289         }
290         CPP_member
end_cursorranges::closed_iota_view291         auto end_cursor() const //
292             -> CPP_ret(default_sentinel_t)(
293                 /// \pre
294                 requires (!same_as<From, To>))
295         {
296             return {};
297         }
298 
check_bounds_ranges::closed_iota_view299         constexpr void check_bounds_(std::true_type)
300         {
301             RANGES_EXPECT(from_ <= to_);
302         }
check_bounds_ranges::closed_iota_view303         constexpr void check_bounds_(std::false_type)
304         {}
305 
306     public:
307         closed_iota_view() = default;
closed_iota_viewranges::closed_iota_view308         constexpr closed_iota_view(meta::id_t<From> from, meta::id_t<To> to)
309           : from_(std::move(from))
310           , to_(std::move(to))
311         {
312             check_bounds_(meta::bool_<totally_ordered_with<From, To>>{});
313         }
314     };
315 
316     template<typename From, typename To>
317     RANGES_INLINE_VAR constexpr bool enable_borrowed_range<closed_iota_view<From, To>> =
318         true;
319 
320 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
321     template(typename From, typename To)(
322         /// \pre
323         requires weakly_incrementable<From> AND semiregular<To> AND
324         (!integral<From> || !integral<To> ||
325          std::is_signed<From>::value == std::is_signed<To>::value)) //
326         closed_iota_view(From, To)
327             ->closed_iota_view<From, To>;
328 #endif
329 
330     template<typename From, typename To /* = unreachable_sentinel_t*/>
331     struct RANGES_EMPTY_BASES iota_view
332       : view_facade<iota_view<From, To>,
333                     same_as<To, unreachable_sentinel_t>
334                         ? infinite
335                         : std::is_integral<From>::value && std::is_integral<To>::value
336                               ? finite
337                               : unknown>
338     {
339     private:
340         friend range_access;
341         From from_ = From();
342         RANGES_NO_UNIQUE_ADDRESS To to_ = To();
343 
344         struct cursor;
345         struct sentinel
346         {
347         private:
348             friend struct cursor;
349             RANGES_NO_UNIQUE_ADDRESS To to_;
350 
351         public:
352             sentinel() = default;
sentinelranges::iota_view::sentinel353             constexpr explicit sentinel(To to)
354               : to_(std::move(to))
355             {}
356         };
357 
358         struct cursor
359         {
360             using difference_type = detail::iota_difference_t<From>;
361 
362         private:
363             friend range_access;
364             From from_;
365 
readranges::iota_view::cursor366             From read() const
367             {
368                 return from_;
369             }
nextranges::iota_view::cursor370             void next()
371             {
372                 ++from_;
373             }
equalranges::iota_view::cursor374             bool equal(sentinel const & that) const
375             {
376                 return from_ == that.to_;
377             }
378             CPP_member
equalranges::iota_view::cursor379             auto equal(cursor const & that) const //
380                 -> CPP_ret(bool)(
381                     /// \pre
382                     requires equality_comparable<From>)
383             {
384                 return that.from_ == from_;
385             }
386             CPP_member
prevranges::iota_view::cursor387             auto prev() //
388                 -> CPP_ret(void)(
389                     /// \pre
390                     requires detail::decrementable_<From>)
391             {
392                 --from_;
393             }
394             CPP_member
advanceranges::iota_view::cursor395             auto advance(difference_type n) //
396                 -> CPP_ret(void)(
397                     /// \pre
398                     requires detail::advanceable_<From>)
399             {
400                 detail::iota_advance_(from_, n);
401             }
402             // Not to spec: TODO the relational operators will effectively be constrained
403             // with Advanceable, but they should be constrained with totally_ordered.
404             // Reimplement iota_view without view_facade or basic_iterator.
405             CPP_member
distance_toranges::iota_view::cursor406             auto distance_to(cursor const & that) const //
407                 -> CPP_ret(difference_type)(
408                     /// \pre
409                     requires detail::advanceable_<From>)
410             {
411                 return detail::iota_distance_(from_, that.from_);
412             }
413             // Extension: see https://github.com/ericniebler/stl2/issues/613
414             CPP_member
distance_toranges::iota_view::cursor415             auto distance_to(sentinel const & that) const //
416                 -> CPP_ret(difference_type)(
417                     /// \pre
418                     requires sized_sentinel_for<To, From>)
419             {
420                 return that.to_ - from_;
421             }
422 
423         public:
424             cursor() = default;
cursorranges::iota_view::cursor425             constexpr explicit cursor(From from)
426               : from_(std::move(from))
427             {}
428         };
begin_cursorranges::iota_view429         cursor begin_cursor() const
430         {
431             return cursor{from_};
432         }
433         CPP_member
CPP_funranges::iota_view434         auto CPP_fun(end_cursor)()(const //
435             requires(same_as<To, unreachable_sentinel_t>))
436         {
437             return unreachable;
438         }
439         CPP_member
CPP_funranges::iota_view440         auto CPP_fun(end_cursor)()(const //
441             requires(!same_as<To, unreachable_sentinel_t>))
442         {
443             return meta::conditional_t<same_as<From, To>, cursor, sentinel>{to_};
444         }
check_bounds_ranges::iota_view445         constexpr void check_bounds_(std::true_type)
446         {
447             RANGES_EXPECT(from_ <= to_);
448         }
check_bounds_ranges::iota_view449         constexpr void check_bounds_(std::false_type)
450         {}
451 
452     public:
453 #ifdef RANGES_WORKAROUND_MSVC_934264
454         constexpr
455 #endif // RANGES_WORKAROUND_MSVC_934264
456             iota_view() = default;
iota_viewranges::iota_view457         constexpr explicit iota_view(From from)
458           : from_(std::move(from))
459         {}
iota_viewranges::iota_view460         constexpr iota_view(meta::id_t<From> from, meta::id_t<To> to)
461           : from_(std::move(from))
462           , to_(std::move(to))
463         {
464             check_bounds_(meta::bool_<totally_ordered_with<From, To>>{});
465         }
466     };
467 
468     template<typename From, typename To>
469     RANGES_INLINE_VAR constexpr bool enable_borrowed_range<iota_view<From, To>> = true;
470 
471 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
472     template(typename From, typename To)(
473         /// \pre
474         requires weakly_incrementable<From> AND semiregular<To> AND
475         (!integral<From> || !integral<To> ||
476          std::is_signed<From>::value == std::is_signed<To>::value)) //
477         iota_view(From, To)
478             ->iota_view<From, To>;
479 #endif
480 
481     namespace views
482     {
483         struct iota_fn
484         {
485             template(typename From)(
486                 /// \pre
487                 requires weakly_incrementable<From>)
operator ()ranges::views::iota_fn488             iota_view<From> operator()(From value) const
489             {
490                 return iota_view<From>{std::move(value)};
491             }
492             template(typename From, typename To)(
493                 /// \pre
494                 requires weakly_incrementable<From> AND semiregular<To> AND
495                     detail::weakly_equality_comparable_with_<From, To> AND
496                 (!integral<From> || !integral<To> ||
497                  std::is_signed<From>::value == std::is_signed<To>::value)) //
operator ()ranges::views::iota_fn498             iota_view<From, To> operator()(From from, To to) const
499             {
500                 return {std::move(from), std::move(to)};
501             }
502         };
503 
504         struct closed_iota_fn
505         {
506             template(typename From, typename To)(
507                 /// \pre
508                 requires weakly_incrementable<From> AND semiregular<To> AND
509                         detail::weakly_equality_comparable_with_<From, To> AND
510                     (!integral<From> || !integral<To> ||
511                      std::is_signed<From>::value == std::is_signed<To>::value)) //
operator ()ranges::views::closed_iota_fn512             closed_iota_view<From, To> operator()(From from, To to) const
513             {
514                 return {std::move(from), std::move(to)};
515             }
516         };
517 
518         /// \relates iota_fn
519         /// \ingroup group-views
520         RANGES_INLINE_VARIABLE(iota_fn, iota)
521 
522         /// \relates closed_iota_fn
523         /// \ingroup group-views
524         RANGES_INLINE_VARIABLE(closed_iota_fn, closed_iota)
525 
526         struct ints_fn : iota_view<int>
527         {
528             ints_fn() = default;
529 
530             template(typename Val)(
531                 /// \pre
532                 requires integral<Val>)
533             RANGES_DEPRECATED(
534                 "This potentially confusing API is deprecated. Prefer to "
535                 "explicitly specify the upper bound as with ranges::unreachable, as in "
536                 "views::ints( n, unreachable )")
operator ()ranges::views::ints_fn537             constexpr iota_view<Val> operator()(Val value) const //
538             {
539                 return iota_view<Val>{value};
540             }
541             template(typename Val)(
542                 /// \pre
543                 requires integral<Val>)
operator ()ranges::views::ints_fn544             constexpr iota_view<Val> operator()(Val value, unreachable_sentinel_t) const
545             {
546                 return iota_view<Val>{value};
547             }
548             template(typename Val)(
549                 /// \pre
550                 requires integral<Val>)
operator ()ranges::views::ints_fn551             constexpr iota_view<Val, Val> operator()(Val from, Val to) const
552             {
553                 return {from, to};
554             }
555         };
556 
557         /// \relates ints_fn
558         /// \ingroup group-views
559         RANGES_INLINE_VARIABLE(ints_fn, ints)
560     } // namespace views
561 
562     namespace cpp20
563     {
564         namespace views
565         {
566             using ranges::views::iota;
567         }
568     } // namespace cpp20
569     /// @}
570 } // namespace ranges
571 
572 #include <range/v3/detail/satisfy_boost_range.hpp>
573 RANGES_SATISFY_BOOST_RANGE(::ranges::closed_iota_view)
574 RANGES_SATISFY_BOOST_RANGE(::ranges::iota_view)
575 
576 RANGES_DIAGNOSTIC_POP
577 
578 #include <range/v3/detail/epilogue.hpp>
579 
580 #endif
581