| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 |
- /// \file
- // Range v3 library
- //
- // Copyright Eric Niebler 2013-present
- //
- // Use, modification and distribution is subject to the
- // Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // Project home: https://github.com/ericniebler/range-v3
- //
- #ifndef RANGES_V3_VIEW_IOTA_HPP
- #define RANGES_V3_VIEW_IOTA_HPP
- #include <climits>
- #include <cstdint>
- #include <limits>
- #include <type_traits>
- #include <meta/meta.hpp>
- #include <concepts/concepts.hpp>
- #include <range/v3/range_fwd.hpp>
- #include <range/v3/iterator/default_sentinel.hpp>
- #include <range/v3/iterator/diffmax_t.hpp>
- #include <range/v3/utility/static_const.hpp>
- #include <range/v3/view/delimit.hpp>
- #include <range/v3/view/facade.hpp>
- #include <range/v3/detail/prologue.hpp>
- RANGES_DIAGNOSTIC_PUSH
- RANGES_DIAGNOSTIC_IGNORE_UNSIGNED_MATH
- RANGES_DIAGNOSTIC_IGNORE_TRUNCATION
- namespace ranges
- {
- /// \cond
- namespace detail
- {
- template<std::size_t N, typename = void>
- struct promote_as_signed_
- {
- // This shouldn't cause us to LOSE precision, but maybe it doesn't
- // net us any either.
- static_assert(sizeof(std::intmax_t) * CHAR_BIT >= N,
- "Possible extended integral type?");
- using difference_type = diffmax_t;
- };
- template<std::size_t N>
- struct promote_as_signed_<N, enable_if_t<(N < 16)>>
- {
- using difference_type = std::int_fast16_t;
- };
- template<std::size_t N>
- struct promote_as_signed_<N, enable_if_t<(N >= 16 && N < 32)>>
- {
- using difference_type = std::int_fast32_t;
- };
- template<std::size_t N>
- struct promote_as_signed_<N, enable_if_t<(N >= 32 && N < 64)>>
- {
- using difference_type = std::int_fast64_t;
- };
- template<typename I>
- using iota_difference_t = typename meta::conditional_t<
- std::is_integral<I>::value && sizeof(I) == sizeof(iter_difference_t<I>),
- promote_as_signed_<sizeof(iter_difference_t<I>) * CHAR_BIT>,
- with_difference_type_<iter_difference_t<I>>>::difference_type;
- // clang-format off
- /// \concept _decrementable_
- /// \brief The \c _decrementable_ concept
- template<typename I>
- CPP_requires(_decrementable_,
- requires(I i) //
- (
- --i,
- i--,
- concepts::requires_<same_as<I&, decltype(--i)>>,
- concepts::requires_<same_as<I, decltype(i--)>>
- ));
- /// \concept decrementable_
- /// \brief The \c decrementable_ concept
- template<typename I>
- CPP_concept decrementable_ =
- incrementable<I> &&
- CPP_requires_ref(detail::_decrementable_, I);
- /// \concept _advanceable_
- /// \brief The \c _advanceable_ concept
- template<typename I>
- CPP_requires(_advanceable_,
- requires(I i, I const j, iota_difference_t<I> const n) //
- (
- j - j,
- i += n,
- i -= n,
- static_cast<I>(j - n),
- static_cast<I>(j + n),
- static_cast<I>(n + j),
- // NOT TO SPEC:
- // Unsigned integers are advanceable, but subtracting them results in
- // an unsigned integral, which is not the same as the difference type,
- // which is signed.
- concepts::requires_<convertible_to<decltype(j - j), iota_difference_t<I>>>,
- concepts::requires_<same_as<I&, decltype(i += n)>>,
- concepts::requires_<same_as<I&, decltype(i -= n)>> //,
- // concepts::requires_<convertible_to<decltype(i - n), I>>,
- // concepts::requires_<convertible_to<decltype(i + n), I>>,
- // concepts::requires_<convertible_to<decltype(n + i), I>>
- ));
- /// \concept advanceable_
- /// \brief The \c advanceable_ concept
- template<typename I>
- CPP_concept advanceable_ =
- decrementable_<I> && totally_ordered<I> &&
- CPP_requires_ref(detail::_advanceable_, I);
- // clang-format on
- template(typename I)(
- requires (!unsigned_integral<I>)) //
- void iota_advance_(I & i, iota_difference_t<I> n)
- {
- // TODO: bounds-check this
- i += n;
- }
- template(typename Int)(
- requires unsigned_integral<Int>)
- void iota_advance_(Int & i, iota_difference_t<Int> n)
- {
- // TODO: bounds-check this
- if(n >= 0)
- i += static_cast<Int>(n);
- else
- i -= static_cast<Int>(-n);
- }
- template(typename I)(
- requires advanceable_<I> AND (!integral<I>)) //
- iota_difference_t<I> iota_distance_(I const & i, I const & s)
- {
- return static_cast<iota_difference_t<I>>(s - i);
- }
- template(typename Int)(
- requires signed_integral<Int>)
- iota_difference_t<Int> iota_distance_(Int i0, Int i1)
- {
- // TODO: bounds-check this
- return static_cast<iota_difference_t<Int>>(
- static_cast<iota_difference_t<Int>>(i1) -
- static_cast<iota_difference_t<Int>>(i0));
- }
- template(typename Int)(
- requires unsigned_integral<Int>)
- iota_difference_t<Int> iota_distance_(Int i0, Int i1)
- {
- // TODO: bounds-check this
- return (i0 > i1) ? static_cast<iota_difference_t<Int>>(
- -static_cast<iota_difference_t<Int>>(i0 - i1))
- : static_cast<iota_difference_t<Int>>(i1 - i0);
- }
- } // namespace detail
- /// \endcond
- /// \addtogroup group-views
- /// @{
- /// An iota view in a closed range
- template<typename From, typename To /* = From */>
- struct RANGES_EMPTY_BASES closed_iota_view
- : view_facade<closed_iota_view<From, To>, finite>
- {
- private:
- friend range_access;
- From from_ = From();
- RANGES_NO_UNIQUE_ADDRESS To to_ = To();
- struct cursor
- {
- using difference_type = detail::iota_difference_t<From>;
- private:
- friend range_access;
- From from_ = From();
- RANGES_NO_UNIQUE_ADDRESS To to_ = To();
- bool done_ = false;
- From read() const
- {
- RANGES_EXPECT(!done_);
- return from_;
- }
- void next()
- {
- RANGES_EXPECT(!done_);
- if(from_ == to_)
- done_ = true;
- else
- ++from_;
- }
- bool equal(default_sentinel_t) const
- {
- return done_;
- }
- CPP_member
- auto equal(cursor const & that) const //
- -> CPP_ret(bool)(
- requires equality_comparable<From>)
- {
- return that.from_ == from_ && that.done_ == done_;
- }
- CPP_member
- auto prev() //
- -> CPP_ret(void)(
- requires detail::decrementable_<From>)
- {
- if(done_)
- done_ = false;
- else
- --from_;
- }
- CPP_member
- auto advance(difference_type n) //
- -> CPP_ret(void)(
- requires detail::advanceable_<From>)
- {
- if(n > 0)
- {
- RANGES_ENSURE(detail::iota_distance_(from_, to_) >= n - !done_);
- detail::iota_advance_(
- from_,
- n - (done_ = (detail::iota_distance_(from_, to_) <= n - !done_)));
- }
- else if(n < 0)
- detail::iota_advance_(from_, n + std::exchange(done_, false));
- }
- CPP_member
- auto distance_to(cursor const & that) const //
- -> CPP_ret(difference_type)(
- requires detail::advanceable_<From>)
- {
- using D = difference_type;
- return static_cast<D>(detail::iota_distance_(from_, that.from_)) +
- ((D)that.done_ - (D)done_);
- }
- CPP_member
- auto distance_to(default_sentinel_t) const //
- -> CPP_ret(difference_type)(
- requires sized_sentinel_for<To, From>)
- {
- return difference_type(to_ - from_) + !done_;
- }
- public:
- cursor() = default;
- constexpr cursor(From from, To to, bool done = false)
- : from_(std::move(from))
- , to_(std::move(to))
- , done_(done)
- {}
- };
- cursor begin_cursor() const
- {
- return {from_, to_};
- }
- CPP_member
- auto end_cursor() const //
- -> CPP_ret(cursor)(
- requires same_as<From, To>)
- {
- return {to_, to_, true};
- }
- CPP_member
- auto end_cursor() const //
- -> CPP_ret(default_sentinel_t)(
- requires (!same_as<From, To>))
- {
- return {};
- }
- constexpr void check_bounds_(std::true_type)
- {
- RANGES_EXPECT(from_ <= to_);
- }
- constexpr void check_bounds_(std::false_type)
- {}
- public:
- closed_iota_view() = default;
- constexpr closed_iota_view(meta::id_t<From> from, meta::id_t<To> to)
- : from_(std::move(from))
- , to_(std::move(to))
- {
- check_bounds_(meta::bool_<totally_ordered_with<From, To>>{});
- }
- };
- template<typename From, typename To>
- RANGES_INLINE_VAR constexpr bool enable_borrowed_range<closed_iota_view<From, To>> =
- true;
- #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
- template(typename From, typename To)(
- requires weakly_incrementable<From> AND semiregular<To> AND
- (!integral<From> || !integral<To> ||
- std::is_signed<From>::value == std::is_signed<To>::value)) //
- closed_iota_view(From, To)
- ->closed_iota_view<From, To>;
- #endif
- template<typename From, typename To /* = unreachable_sentinel_t*/>
- struct RANGES_EMPTY_BASES iota_view
- : view_facade<iota_view<From, To>,
- same_as<To, unreachable_sentinel_t>
- ? infinite
- : std::is_integral<From>::value && std::is_integral<To>::value
- ? finite
- : unknown>
- {
- private:
- friend range_access;
- From from_ = From();
- RANGES_NO_UNIQUE_ADDRESS To to_ = To();
- struct cursor;
- struct sentinel
- {
- private:
- friend struct cursor;
- RANGES_NO_UNIQUE_ADDRESS To to_;
- public:
- sentinel() = default;
- constexpr explicit sentinel(To to)
- : to_(std::move(to))
- {}
- };
- struct cursor
- {
- using difference_type = detail::iota_difference_t<From>;
- private:
- friend range_access;
- From from_;
- From read() const
- {
- return from_;
- }
- void next()
- {
- ++from_;
- }
- bool equal(sentinel const & that) const
- {
- return from_ == that.to_;
- }
- CPP_member
- auto equal(cursor const & that) const //
- -> CPP_ret(bool)(
- requires equality_comparable<From>)
- {
- return that.from_ == from_;
- }
- CPP_member
- auto prev() //
- -> CPP_ret(void)(
- requires detail::decrementable_<From>)
- {
- --from_;
- }
- CPP_member
- auto advance(difference_type n) //
- -> CPP_ret(void)(
- requires detail::advanceable_<From>)
- {
- detail::iota_advance_(from_, n);
- }
- // Not to spec: TODO the relational operators will effectively be constrained
- // with Advanceable, but they should be constrained with totally_ordered.
- // Reimplement iota_view without view_facade or basic_iterator.
- CPP_member
- auto distance_to(cursor const & that) const //
- -> CPP_ret(difference_type)(
- requires detail::advanceable_<From>)
- {
- return detail::iota_distance_(from_, that.from_);
- }
- // Extension: see https://github.com/ericniebler/stl2/issues/613
- CPP_member
- auto distance_to(sentinel const & that) const //
- -> CPP_ret(difference_type)(
- requires sized_sentinel_for<To, From>)
- {
- return that.to_ - from_;
- }
- public:
- cursor() = default;
- constexpr explicit cursor(From from)
- : from_(std::move(from))
- {}
- };
- cursor begin_cursor() const
- {
- return cursor{from_};
- }
- CPP_auto_member
- auto CPP_fun(end_cursor)()(const //
- requires(same_as<To, unreachable_sentinel_t>))
- {
- return unreachable;
- }
- CPP_auto_member
- auto CPP_fun(end_cursor)()(const //
- requires(!same_as<To, unreachable_sentinel_t>))
- {
- return meta::conditional_t<same_as<From, To>, cursor, sentinel>{to_};
- }
- constexpr void check_bounds_(std::true_type)
- {
- RANGES_EXPECT(from_ <= to_);
- }
- constexpr void check_bounds_(std::false_type)
- {}
- public:
- #ifdef RANGES_WORKAROUND_MSVC_934264
- constexpr
- #endif // RANGES_WORKAROUND_MSVC_934264
- iota_view() = default;
- constexpr explicit iota_view(From from)
- : from_(std::move(from))
- {}
- constexpr iota_view(meta::id_t<From> from, meta::id_t<To> to)
- : from_(std::move(from))
- , to_(std::move(to))
- {
- check_bounds_(meta::bool_<totally_ordered_with<From, To>>{});
- }
- };
- template<typename From, typename To>
- RANGES_INLINE_VAR constexpr bool enable_borrowed_range<iota_view<From, To>> = true;
- #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
- template(typename From, typename To)(
- requires weakly_incrementable<From> AND semiregular<To> AND
- (!integral<From> || !integral<To> ||
- std::is_signed<From>::value == std::is_signed<To>::value)) //
- iota_view(From, To)
- ->iota_view<From, To>;
- #endif
- namespace views
- {
- struct iota_fn
- {
- template(typename From)(
- requires weakly_incrementable<From>)
- iota_view<From> operator()(From value) const
- {
- return iota_view<From>{std::move(value)};
- }
- template(typename From, typename To)(
- requires weakly_incrementable<From> AND semiregular<To> AND
- detail::weakly_equality_comparable_with_<From, To> AND
- (!integral<From> || !integral<To> ||
- std::is_signed<From>::value == std::is_signed<To>::value)) //
- iota_view<From, To> operator()(From from, To to) const
- {
- return {std::move(from), std::move(to)};
- }
- };
- struct closed_iota_fn
- {
- template(typename From, typename To)(
- requires weakly_incrementable<From> AND semiregular<To> AND
- detail::weakly_equality_comparable_with_<From, To> AND
- (!integral<From> || !integral<To> ||
- std::is_signed<From>::value == std::is_signed<To>::value)) //
- closed_iota_view<From, To> operator()(From from, To to) const
- {
- return {std::move(from), std::move(to)};
- }
- };
- /// \relates iota_fn
- /// \ingroup group-views
- RANGES_INLINE_VARIABLE(iota_fn, iota)
- /// \relates closed_iota_fn
- /// \ingroup group-views
- RANGES_INLINE_VARIABLE(closed_iota_fn, closed_iota)
- /// # ranges::views::ints
- /// The ints view returns a range of monotonically increasing ints.
- ///
- /// ## Example
- /// \snippet example/view/ints.cpp ints example
- ///
- /// ### Output
- /// \include example/view/ints_golden.txt
- ///
- /// ## Syntax
- /// ```cpp
- /// auto output_range = ranges::views::ints(lower_bound, upper_bound);
- /// ```
- ///
- /// ## Parameters
- /// <pre><b>lower_bound</b></pre>
- /// - Optional lower bound
- ///
- /// <pre><b>upper_bound</b></pre>
- /// - Exclusive upper bound
- /// - Required when `lower_bound` is specified
- /// - To create an infinite range with a `lower_bound`, use
- /// `ranges::unreachable` as the `upper_bound`
- ///
- /// <pre><b>output_range</b></pre>
- /// - Range of monotonically increasing ints
- /// - When an `upper_bound` is not specified, the range is quasi-infinite
- ///
- struct ints_fn : iota_view<int>
- {
- ints_fn() = default;
- template(typename Val)(
- requires integral<Val>)
- RANGES_DEPRECATED(
- "This potentially confusing API is deprecated. Prefer to "
- "explicitly specify the upper bound as with ranges::unreachable, as in "
- "views::ints( n, unreachable )")
- constexpr iota_view<Val> operator()(Val value) const //
- {
- return iota_view<Val>{value};
- }
- template(typename Val)(
- requires integral<Val>)
- constexpr iota_view<Val> operator()(Val value, unreachable_sentinel_t) const
- {
- return iota_view<Val>{value};
- }
- template(typename Val)(
- requires integral<Val>)
- constexpr iota_view<Val, Val> operator()(Val from, Val to) const
- {
- return {from, to};
- }
- };
- /// \relates ints_fn
- /// \ingroup group-views
- RANGES_INLINE_VARIABLE(ints_fn, ints)
- } // namespace views
- namespace cpp20
- {
- namespace views
- {
- using ranges::views::iota;
- }
- } // namespace cpp20
- /// @}
- } // namespace ranges
- #include <range/v3/detail/satisfy_boost_range.hpp>
- RANGES_SATISFY_BOOST_RANGE(::ranges::closed_iota_view)
- RANGES_SATISFY_BOOST_RANGE(::ranges::iota_view)
- RANGES_DIAGNOSTIC_POP
- #include <range/v3/detail/epilogue.hpp>
- #endif
|