| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- /// \file
- // Range v3 library
- //
- // Copyright Eric Niebler 2014-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_INTERFACE_HPP
- #define RANGES_V3_VIEW_INTERFACE_HPP
- #include <iosfwd>
- #include <meta/meta.hpp>
- #include <concepts/concepts.hpp>
- #include <range/v3/range_fwd.hpp>
- #include <range/v3/iterator/common_iterator.hpp>
- #include <range/v3/iterator/operations.hpp>
- #include <range/v3/range/access.hpp>
- #include <range/v3/range/concepts.hpp>
- #include <range/v3/range/primitives.hpp>
- #include <range/v3/range/traits.hpp>
- #include <range/v3/detail/prologue.hpp>
- #if defined(RANGES_WORKAROUND_GCC_91525)
- #define CPP_template_gcc_workaround CPP_template_sfinae
- #else
- #define CPP_template_gcc_workaround template
- #endif
- namespace ranges
- {
- /// \cond
- namespace detail
- {
- template<typename From, typename To = From>
- struct slice_bounds
- {
- From from;
- To to;
- template(typename F, typename T)(
- requires convertible_to<F, From> AND convertible_to<T, To>)
- constexpr slice_bounds(F f, T t)
- : from(static_cast<From>(f))
- , to(static_cast<To>(t))
- {}
- };
- template<typename Int>
- struct from_end_
- {
- Int dist_;
- constexpr explicit from_end_(Int dist)
- : dist_(dist)
- {}
- template(typename Other)(
- requires integer_like_<Other> AND explicitly_convertible_to<Other, Int>)
- constexpr operator from_end_<Other>() const
- {
- return from_end_<Other>{static_cast<Other>(dist_)};
- }
- };
- template<typename Rng>
- using from_end_of_t = from_end_<range_difference_t<Rng>>;
- // clang-format off
- /// \concept _can_empty_
- /// \brief The \c _can_empty_ concept
- template<typename Rng>
- CPP_requires(_can_empty_,
- requires(Rng & rng) //
- (
- ranges::empty(rng)
- ));
- /// \concept can_empty_
- /// \brief The \c can_empty_ concept
- template<typename Rng>
- CPP_concept can_empty_ = //
- CPP_requires_ref(detail::_can_empty_, Rng);
- // clang-format on
- template<cardinality C>
- RANGES_INLINE_VAR constexpr bool has_fixed_size_ = (C >= 0 || C == infinite);
- template<bool>
- struct dependent_
- {
- template<typename T>
- using invoke = T;
- };
- template<typename Stream, typename Rng>
- Stream & print_rng_(Stream & sout, Rng & rng)
- {
- sout << '[';
- auto it = ranges::begin(rng);
- auto const e = ranges::end(rng);
- if(it != e)
- {
- for(;;)
- {
- sout << *it;
- if(++it == e)
- break;
- sout << ',';
- }
- }
- sout << ']';
- return sout;
- }
- } // namespace detail
- /// \endcond
- /// \addtogroup group-views
- /// @{
- template<typename Derived, cardinality Cardinality /* = finite*/>
- struct view_interface : basic_view<Cardinality>
- {
- protected:
- template<bool B>
- using D = meta::invoke<detail::dependent_<B>, Derived>;
- constexpr Derived & derived() noexcept
- {
- CPP_assert(derived_from<Derived, view_interface>);
- return static_cast<Derived &>(*this);
- }
- /// \overload
- constexpr Derived const & derived() const noexcept
- {
- CPP_assert(derived_from<Derived, view_interface>);
- return static_cast<Derived const &>(*this);
- }
- public:
- view_interface() = default;
- view_interface(view_interface &&) = default;
- view_interface(view_interface const &) = default;
- view_interface & operator=(view_interface &&) = default;
- view_interface & operator=(view_interface const &) = default;
- /// \brief Test whether a range can be empty:
- CPP_member
- constexpr auto empty() const noexcept //
- -> CPP_ret(bool)(
- requires (detail::has_fixed_size_<Cardinality>))
- {
- return Cardinality == 0;
- }
- /// \overload
- template(bool True = true)(
- requires True AND (Cardinality < 0) AND (Cardinality != infinite) AND
- (!forward_range<D<True>>) AND sized_range<D<True>>)
- constexpr bool empty() //
- noexcept(noexcept(bool(ranges::size(std::declval<D<True> &>()) == 0)))
- {
- return ranges::size(derived()) == 0;
- }
- /// \overload
- template(bool True = true)(
- requires True AND (Cardinality < 0) AND (Cardinality != infinite) AND
- (!forward_range<D<True> const>) AND sized_range<D<True> const>)
- constexpr bool empty() const //
- noexcept(noexcept(bool(ranges::size(std::declval<D<True> const &>()) == 0)))
- {
- return ranges::size(derived()) == 0;
- }
- /// \overload
- template(bool True = true)(
- requires True AND (!detail::has_fixed_size_<Cardinality>) AND
- forward_range<D<True>>)
- constexpr bool empty() noexcept(
- noexcept(bool(ranges::begin(std::declval<D<True> &>()) ==
- ranges::end(std::declval<D<True> &>()))))
- {
- return bool(ranges::begin(derived()) == ranges::end(derived()));
- }
- /// \overload
- template(bool True = true)(
- requires True AND (!detail::has_fixed_size_<Cardinality>) AND
- forward_range<D<True> const>)
- constexpr bool empty() const
- noexcept(noexcept(bool(ranges::begin(std::declval<D<True> const &>()) ==
- ranges::end(std::declval<D<True> const &>()))))
- {
- return bool(ranges::begin(derived()) == ranges::end(derived()));
- }
- CPP_template_gcc_workaround(bool True = true)(
- requires True && detail::can_empty_<D<True>>) // clang-format off
- constexpr explicit operator bool()
- noexcept(noexcept(ranges::empty(std::declval<D<True> &>())))
- {
- return !ranges::empty(derived());
- }
- // clang-format on
- /// \overload
- CPP_template_gcc_workaround(bool True = true)(
- requires True && detail::can_empty_<D<True> const>) // clang-format off
- constexpr explicit operator bool() const
- noexcept(noexcept(ranges::empty(std::declval<D<True> const &>())))
- {
- return !ranges::empty(derived());
- }
- // clang-format on
- /// If the size of the range is known at compile-time and finite,
- /// return it.
- template(bool True = true, int = 42)(
- requires True AND (Cardinality >= 0)) //
- static constexpr std::size_t size() noexcept
- {
- return static_cast<std::size_t>(Cardinality);
- }
- /// If `sized_sentinel_for<sentinel_t<Derived>, iterator_t<Derived>>` is
- /// satisfied, and if `Derived` is a `forward_range`, then return
- /// `end - begin` cast to an unsigned integer.
- template(bool True = true)(
- requires True AND (Cardinality < 0) AND
- sized_sentinel_for<sentinel_t<D<True>>, iterator_t<D<True>>> AND
- forward_range<D<True>>)
- constexpr detail::iter_size_t<iterator_t<D<True>>> size()
- {
- using size_type = detail::iter_size_t<iterator_t<D<True>>>;
- return static_cast<size_type>(derived().end() - derived().begin());
- }
- /// \overload
- template(bool True = true)(
- requires True AND (Cardinality < 0) AND
- sized_sentinel_for<sentinel_t<D<True> const>,
- iterator_t<D<True> const>> AND
- forward_range<D<True> const>)
- constexpr detail::iter_size_t<iterator_t<D<True>>> size() const //
- {
- using size_type = detail::iter_size_t<iterator_t<D<True>>>;
- return static_cast<size_type>(derived().end() - derived().begin());
- }
- /// Access the first element in a range:
- template(bool True = true)(
- requires True AND forward_range<D<True>>)
- constexpr range_reference_t<D<True>> front()
- {
- return *derived().begin();
- }
- /// \overload
- template(bool True = true)(
- requires True AND forward_range<D<True> const>)
- constexpr range_reference_t<D<True> const> front() const
- {
- return *derived().begin();
- }
- /// Access the last element in a range:
- template(bool True = true)(
- requires True AND common_range<D<True>> AND bidirectional_range<D<True>>)
- constexpr range_reference_t<D<True>> back()
- {
- return *prev(derived().end());
- }
- /// \overload
- template(bool True = true)(
- requires True AND common_range<D<True> const> AND
- bidirectional_range<D<True> const>)
- constexpr range_reference_t<D<True> const> back() const
- {
- return *prev(derived().end());
- }
- /// Simple indexing:
- template(bool True = true)(
- requires True AND random_access_range<D<True>>)
- constexpr range_reference_t<D<True>> operator[](range_difference_t<D<True>> n)
- {
- return derived().begin()[n];
- }
- /// \overload
- template(bool True = true)(
- requires True AND random_access_range<D<True> const>)
- constexpr range_reference_t<D<True> const> //
- operator[](range_difference_t<D<True>> n) const
- {
- return derived().begin()[n];
- }
- /// Returns a pointer to the block of memory
- /// containing the elements of a contiguous range:
- template(bool True = true)(
- requires True AND contiguous_iterator<iterator_t<D<True>>>)
- constexpr std::add_pointer_t<range_reference_t<D<True>>> data() //
- {
- return std::addressof(*ranges::begin(derived()));
- }
- /// \overload
- template(bool True = true)(
- requires True AND contiguous_iterator<iterator_t<D<True> const>>)
- constexpr std::add_pointer_t<range_reference_t<D<True> const>> data() const //
- {
- return std::addressof(*ranges::begin(derived()));
- }
- /// Returns a reference to the element at specified location pos, with bounds
- /// checking.
- template(bool True = true)(
- requires True AND random_access_range<D<True>> AND sized_range<D<True>>)
- constexpr range_reference_t<D<True>> at(range_difference_t<D<True>> n)
- {
- using size_type = range_size_t<Derived>;
- if(n < 0 || size_type(n) >= ranges::size(derived()))
- {
- throw std::out_of_range("view_interface::at");
- }
- return derived().begin()[n];
- }
- /// \overload
- template(bool True = true)(
- requires True AND random_access_range<D<True> const> AND
- sized_range<D<True> const>)
- constexpr range_reference_t<D<True> const> at(range_difference_t<D<True>> n) const
- {
- using size_type = range_size_t<Derived const>;
- if(n < 0 || size_type(n) >= ranges::size(derived()))
- {
- throw std::out_of_range("view_interface::at");
- }
- return derived().begin()[n];
- }
- /// Python-ic slicing:
- // rng[{4,6}]
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True> &>)
- constexpr auto
- operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True> const &>)
- constexpr auto
- operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) const &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True>>)
- constexpr auto
- operator[](detail::slice_bounds<range_difference_t<D<True>>> offs) &&
- {
- return Slice{}(detail::move(derived()), offs.from, offs.to);
- }
- // rng[{4,end-2}]
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True> &> AND sized_range<D<True> &>)
- constexpr auto //
- operator[](detail::slice_bounds<range_difference_t<D<True>>,
- detail::from_end_of_t<D<True>>> offs) &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True> const &> AND
- sized_range<D<True> const &>)
- constexpr auto //
- operator[](detail::slice_bounds<range_difference_t<D<True>>,
- detail::from_end_of_t<D<True>>> offs) const &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True>> AND sized_range<D<True>>)
- constexpr auto //
- operator[](detail::slice_bounds<range_difference_t<D<True>>,
- detail::from_end_of_t<D<True>>> offs) &&
- {
- return Slice{}(detail::move(derived()), offs.from, offs.to);
- }
- // rng[{end-4,end-2}]
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND (forward_range<D<True> &> ||
- (input_range<D<True> &> && sized_range<D<True> &>))) //
- constexpr auto //
- operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
- detail::from_end_of_t<D<True>>> offs) &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND
- (forward_range<D<True> const &> ||
- (input_range<D<True> const &> && sized_range<D<True> const &>))) //
- constexpr auto //
- operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
- detail::from_end_of_t<D<True>>> offs) const &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND
- (forward_range<D<True>> ||
- (input_range<D<True>> && sized_range<D<True>>))) //
- constexpr auto //
- operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>,
- detail::from_end_of_t<D<True>>> offs) &&
- {
- return Slice{}(detail::move(derived()), offs.from, offs.to);
- }
- // rng[{4,end}]
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True> &>)
- constexpr auto //
- operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True> const &>)
- constexpr auto //
- operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) const &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND input_range<D<True>>)
- constexpr auto //
- operator[](detail::slice_bounds<range_difference_t<D<True>>, end_fn> offs) &&
- {
- return Slice{}(detail::move(derived()), offs.from, offs.to);
- }
- // rng[{end-4,end}]
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND
- (forward_range<D<True> &> ||
- (input_range<D<True> &> && sized_range<D<True> &>))) //
- constexpr auto //
- operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND
- (forward_range<D<True> const &> ||
- (input_range<D<True> const &> && sized_range<D<True> const &>))) //
- constexpr auto //
- operator[](
- detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) const &
- {
- return Slice{}(derived(), offs.from, offs.to);
- }
- /// \overload
- template(bool True = true, typename Slice = views::slice_fn)(
- requires True AND
- (forward_range<D<True>> ||
- (input_range<D<True>> && sized_range<D<True>>))) //
- constexpr auto //
- operator[](detail::slice_bounds<detail::from_end_of_t<D<True>>, end_fn> offs) &&
- {
- return Slice{}(detail::move(derived()), offs.from, offs.to);
- }
- private:
- #ifndef RANGES_V3_DISABLE_IO
- /// \brief Print a range to an ostream
- template<bool True = true>
- friend auto operator<<(std::ostream & sout, Derived const & rng)
- -> CPP_broken_friend_ret(std::ostream &)(
- requires True && input_range<D<True> const>)
- {
- return detail::print_rng_(sout, rng);
- }
- /// \overload
- template<bool True = true>
- friend auto operator<<(std::ostream & sout, Derived & rng)
- -> CPP_broken_friend_ret(std::ostream &)(
- requires True && (!range<D<True> const>) && input_range<D<True>>)
- {
- return detail::print_rng_(sout, rng);
- }
- /// \overload
- template<bool True = true>
- friend auto operator<<(std::ostream & sout, Derived && rng)
- -> CPP_broken_friend_ret(std::ostream &)(
- requires True && (!range<D<True> const>) && input_range<D<True>>)
- {
- return detail::print_rng_(sout, rng);
- }
- #endif
- };
- namespace cpp20
- {
- template(typename Derived)(
- requires std::is_class<Derived>::value AND
- same_as<Derived, meta::_t<std::remove_cv<Derived>>>)
- using view_interface = ranges::view_interface<Derived, ranges::unknown>;
- }
- /// @}
- } // namespace ranges
- #include <range/v3/detail/epilogue.hpp>
- #endif
|