/// \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 #include #include #include #include #include #include #include #include #include #include #if defined(RANGES_WORKAROUND_GCC_91525) #define CPP_template_gcc_workaround CPP_template_sfinae #else #define CPP_template_gcc_workaround CPP_template #endif namespace ranges { /// \cond namespace detail { template struct slice_bounds { From from; To to; template constexpr CPP_ctor(slice_bounds)(F f, T t)( // requires convertible_to && convertible_to) : from(static_cast(f)) , to(static_cast(t)) {} }; template struct from_end_ { Int dist_; constexpr explicit from_end_(Int dist) : dist_(dist) {} CPP_template(typename Other)( // requires integer_like_ && explicitly_convertible_to) // constexpr operator from_end_() const { return from_end_{static_cast(dist_)}; } }; template using from_end_of_t = from_end_>; // clang-format off CPP_def ( template(typename Rng) concept can_empty_, requires (Rng &rng) ( ranges::empty(rng) ) ); // clang-format on constexpr bool has_fixed_size_(cardinality c) noexcept { return c >= 0 || c == infinite; } template struct dependent_ { template using invoke = T; }; template 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 struct view_interface : basic_view { protected: template using D = meta::invoke, Derived>; constexpr Derived & derived() noexcept { CPP_assert(derived_from); return static_cast(*this); } /// \overload constexpr Derived const & derived() const noexcept { CPP_assert(derived_from); return static_cast(*this); } ~view_interface() = default; 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; // A few ways of testing 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 constexpr auto empty() noexcept(noexcept( bool(ranges::size(std::declval &>()) == 0))) -> CPP_ret(bool)( // requires True && (Cardinality < 0) && (Cardinality != infinite) && (!forward_range>)&&sized_range>) { return ranges::size(derived()) == 0; } /// \overload template constexpr auto empty() const noexcept(noexcept(bool(ranges::size(std::declval const &>()) == 0))) -> CPP_ret(bool)( // requires True && (Cardinality < 0) && (Cardinality != infinite) && (!forward_range const>)&&sized_range const>) { return ranges::size(derived()) == 0; } /// \overload template constexpr auto empty() noexcept( noexcept(bool(ranges::begin(std::declval &>()) == ranges::end(std::declval &>())))) -> CPP_ret(bool)( // requires True && (!detail::has_fixed_size_(Cardinality)) && forward_range>) { return bool(ranges::begin(derived()) == ranges::end(derived())); } /// \overload template constexpr auto empty() const noexcept(noexcept(bool(ranges::begin(std::declval const &>()) == ranges::end(std::declval const &>())))) -> CPP_ret(bool)( // requires True && (!detail::has_fixed_size_(Cardinality)) && forward_range const>) { return bool(ranges::begin(derived()) == ranges::end(derived())); } CPP_template_gcc_workaround(bool True = true)( // requires True && detail::can_empty_>) // clang-format off constexpr explicit operator bool() noexcept(noexcept(ranges::empty(std::declval &>()))) { return !ranges::empty(derived()); } // clang-format on /// \overload CPP_template_gcc_workaround(bool True = true)( // requires True && detail::can_empty_ const>) // clang-format off constexpr explicit operator bool() const noexcept(noexcept(ranges::empty(std::declval const &>()))) { return !ranges::empty(derived()); } // clang-format on /// If the size of the range is known at compile-time and finite, /// return it. template static constexpr auto size() noexcept -> CPP_ret(std::size_t)( // requires True && (Cardinality >= 0)) { return static_cast(Cardinality); } /// If `sized_sentinel_for, iterator_t>` is /// satisfied, and if `Derived` is a `forward_range`, then return /// `end - begin` cast to an unsigned integer. template constexpr auto size() -> CPP_ret(detail::iter_size_t>>)( // requires True && (Cardinality < 0) && sized_sentinel_for>, iterator_t>> && forward_range>) { using size_type = detail::iter_size_t>>; return static_cast(derived().end() - derived().begin()); } /// \overload template constexpr auto size() const // -> CPP_ret(detail::iter_size_t>>)( // requires True && (Cardinality < 0) && sized_sentinel_for const>, iterator_t const>> && forward_range const>) { using size_type = detail::iter_size_t>>; return static_cast(derived().end() - derived().begin()); } /// Access the first element in a range: template constexpr auto front() -> CPP_ret(range_reference_t>)( // requires True && forward_range>) { return *derived().begin(); } /// \overload template constexpr auto front() const -> CPP_ret(range_reference_t const>)( // requires True && forward_range const>) { return *derived().begin(); } /// Access the last element in a range: template constexpr auto back() -> CPP_ret(range_reference_t>)( // requires True && common_range> && bidirectional_range>) { return *prev(derived().end()); } /// \overload template constexpr auto back() const -> CPP_ret(range_reference_t const>)( // requires True && common_range const> && bidirectional_range const>) { return *prev(derived().end()); } /// Simple indexing: template constexpr auto operator[](range_difference_t> n) -> CPP_ret(range_reference_t>)( // requires True && random_access_range>) { return derived().begin()[n]; } /// \overload template constexpr auto operator[](range_difference_t> n) const -> CPP_ret(range_reference_t const>)( // requires True && random_access_range const>) { return derived().begin()[n]; } /// Returns a reference to the element at specified location pos, with bounds /// checking. template constexpr auto at(range_difference_t> n) -> CPP_ret(range_reference_t>)( // requires True && random_access_range> && sized_range>) { using size_type = range_size_t; if(n < 0 || size_type(n) >= ranges::size(derived())) { throw std::out_of_range("view_interface::at"); } return derived().begin()[n]; } /// \overload template constexpr auto at(range_difference_t> n) const -> CPP_ret(range_reference_t const>)( // requires True && random_access_range const> && sized_range const>) { using size_type = range_size_t; 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}] CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range &>) // constexpr auto operator[](detail::slice_bounds>> offs) & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range const &>) // constexpr auto operator[](detail::slice_bounds>> offs) const & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range>) // constexpr auto operator[](detail::slice_bounds>> offs) && { return Slice{}(detail::move(derived()), offs.from, offs.to); } // rng[{4,end-2}] /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range &> && sized_range &>) // constexpr auto operator[](detail::slice_bounds>, detail::from_end_of_t>> offs) & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range const &> && sized_range const &>) // constexpr auto operator[](detail::slice_bounds>, detail::from_end_of_t>> offs) const & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range> && sized_range>) // constexpr auto operator[](detail::slice_bounds>, detail::from_end_of_t>> offs) && { return Slice{}(detail::move(derived()), offs.from, offs.to); } // rng[{end-4,end-2}] /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && (forward_range &> || (input_range &> && sized_range &>))) // constexpr auto operator[](detail::slice_bounds>, detail::from_end_of_t>> offs) & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && (forward_range const &> || (input_range const &> && sized_range const &>))) // constexpr auto operator[](detail::slice_bounds>, detail::from_end_of_t>> offs) const & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && (forward_range> || (input_range> && sized_range>))) // constexpr auto operator[](detail::slice_bounds>, detail::from_end_of_t>> offs) && { return Slice{}(detail::move(derived()), offs.from, offs.to); } // rng[{4,end}] /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range &>) // constexpr auto operator[](detail::slice_bounds>, end_fn> offs) & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range const &>) // constexpr auto operator[]( detail::slice_bounds>, end_fn> offs) const & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && input_range>) // constexpr auto operator[](detail::slice_bounds>, end_fn> offs) && { return Slice{}(detail::move(derived()), offs.from, offs.to); } // rng[{end-4,end}] /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && (forward_range &> || (input_range &> && sized_range &>))) // constexpr auto operator[]( detail::slice_bounds>, end_fn> offs) & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && (forward_range const &> || (input_range const &> && sized_range const &>))) // constexpr auto operator[]( detail::slice_bounds>, end_fn> offs) const & { return Slice{}(derived(), offs.from, offs.to); } /// \overload CPP_template(bool True = true, typename Slice = views::slice_fn)( // requires True && (forward_range> || (input_range> && sized_range>))) // constexpr auto operator[]( detail::slice_bounds>, end_fn> offs) && { return Slice{}(detail::move(derived()), offs.from, offs.to); } /// \cond /// Implicit conversion to something that looks like a container. CPP_template(typename Container, bool True = true)( // clang-format off requires detail::convertible_to_container, Container>) RANGES_DEPRECATED( "Implicit conversion from a view to a container is deprecated. " "Please use ranges::to in instead.") constexpr operator Container() // clang-format on { return ranges::to(derived()); } /// \overload CPP_template(typename Container, bool True = true)( // clang-format off requires detail::convertible_to_container const, Container>) RANGES_DEPRECATED( "Implicit conversion from a view to a container is deprecated. " "Please use ranges::to in instead.") constexpr operator Container() const // clang-format on { return ranges::to(derived()); } /// \endcond private: /// \brief Print a range to an ostream template friend auto operator<<(std::ostream & sout, Derived const & rng) -> CPP_broken_friend_ret(std::ostream &)( // requires True && input_range const>) { return detail::print_rng_(sout, rng); } /// \overload template friend auto operator<<(std::ostream & sout, Derived & rng) -> CPP_broken_friend_ret(std::ostream &)( // requires True && (!range const>)&&input_range>) { return detail::print_rng_(sout, rng); } /// \overload template friend auto operator<<(std::ostream & sout, Derived && rng) -> CPP_broken_friend_ret(std::ostream &)( // requires True && (!range const>)&&input_range>) { return detail::print_rng_(sout, rng); } }; namespace cpp20 { CPP_template(typename Derived)( // requires std::is_class::value && same_as>>) // using view_interface = ranges::view_interface; } /// @} } // namespace ranges #endif