/// \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 template #endif namespace ranges { /// \cond namespace detail { template struct slice_bounds { From from; To to; template(typename F, typename T)( requires convertible_to AND convertible_to) constexpr slice_bounds(F f, T t) : from(static_cast(f)) , to(static_cast(t)) {} }; template struct from_end_ { Int dist_; constexpr explicit from_end_(Int dist) : dist_(dist) {} template(typename Other)( requires integer_like_ AND 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 /// \concept _can_empty_ /// \brief The \c _can_empty_ concept template CPP_requires(_can_empty_, requires(Rng & rng) // ( ranges::empty(rng) )); /// \concept can_empty_ /// \brief The \c can_empty_ concept template CPP_concept can_empty_ = // CPP_requires_ref(detail::_can_empty_, Rng); // clang-format on template RANGES_INLINE_VAR constexpr bool has_fixed_size_ = (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); } 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_)) { return Cardinality == 0; } /// \overload template(bool True = true)( requires True AND (Cardinality < 0) AND (Cardinality != infinite) AND (!forward_range>) AND sized_range>) constexpr bool empty() // noexcept(noexcept(bool(ranges::size(std::declval &>()) == 0))) { return ranges::size(derived()) == 0; } /// \overload template(bool True = true)( requires True AND (Cardinality < 0) AND (Cardinality != infinite) AND (!forward_range const>) AND sized_range const>) constexpr bool empty() const // noexcept(noexcept(bool(ranges::size(std::declval const &>()) == 0))) { return ranges::size(derived()) == 0; } /// \overload template(bool True = true)( requires True AND (!detail::has_fixed_size_) AND forward_range>) constexpr bool empty() noexcept( noexcept(bool(ranges::begin(std::declval &>()) == ranges::end(std::declval &>())))) { return bool(ranges::begin(derived()) == ranges::end(derived())); } /// \overload template(bool True = true)( requires True AND (!detail::has_fixed_size_) AND forward_range const>) constexpr bool empty() const noexcept(noexcept(bool(ranges::begin(std::declval const &>()) == ranges::end(std::declval 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(bool True = true, int = 42)( requires True AND (Cardinality >= 0)) // static constexpr std::size_t size() noexcept { 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(bool True = true)( requires True AND (Cardinality < 0) AND sized_sentinel_for>, iterator_t>> AND forward_range>) constexpr detail::iter_size_t>> size() { using size_type = detail::iter_size_t>>; return static_cast(derived().end() - derived().begin()); } /// \overload template(bool True = true)( requires True AND (Cardinality < 0) AND sized_sentinel_for const>, iterator_t const>> AND forward_range const>) constexpr detail::iter_size_t>> size() const // { using size_type = detail::iter_size_t>>; return static_cast(derived().end() - derived().begin()); } /// Access the first element in a range: template(bool True = true)( requires True AND forward_range>) constexpr range_reference_t> front() { return *derived().begin(); } /// \overload template(bool True = true)( requires True AND forward_range const>) constexpr range_reference_t const> front() const { return *derived().begin(); } /// Access the last element in a range: template(bool True = true)( requires True AND common_range> AND bidirectional_range>) constexpr range_reference_t> back() { return *prev(derived().end()); } /// \overload template(bool True = true)( requires True AND common_range const> AND bidirectional_range const>) constexpr range_reference_t const> back() const { return *prev(derived().end()); } /// Simple indexing: template(bool True = true)( requires True AND random_access_range>) constexpr range_reference_t> operator[](range_difference_t> n) { return derived().begin()[n]; } /// \overload template(bool True = true)( requires True AND random_access_range const>) constexpr range_reference_t const> // operator[](range_difference_t> 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>>) constexpr std::add_pointer_t>> data() // { return std::addressof(*ranges::begin(derived())); } /// \overload template(bool True = true)( requires True AND contiguous_iterator const>>) constexpr std::add_pointer_t 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> AND sized_range>) constexpr range_reference_t> at(range_difference_t> n) { 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(bool True = true)( requires True AND random_access_range const> AND sized_range const>) constexpr range_reference_t const> at(range_difference_t> n) 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}] template(bool True = true, typename Slice = views::slice_fn)( requires True AND input_range &>) constexpr auto operator[](detail::slice_bounds>> offs) & { return Slice{}(derived(), offs.from, offs.to); } /// \overload template(bool True = true, typename Slice = views::slice_fn)( requires True AND input_range const &>) constexpr auto operator[](detail::slice_bounds>> offs) const & { return Slice{}(derived(), offs.from, offs.to); } /// \overload template(bool True = true, typename Slice = views::slice_fn)( requires True AND input_range>) constexpr auto operator[](detail::slice_bounds>> 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 &> AND sized_range &>) constexpr auto // operator[](detail::slice_bounds>, detail::from_end_of_t>> offs) & { return Slice{}(derived(), offs.from, offs.to); } /// \overload template(bool True = true, typename Slice = views::slice_fn)( requires True AND input_range const &> AND sized_range const &>) constexpr auto // operator[](detail::slice_bounds>, detail::from_end_of_t>> offs) const & { return Slice{}(derived(), offs.from, offs.to); } /// \overload template(bool True = true, typename Slice = views::slice_fn)( requires True AND input_range> AND 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 template(bool True = true, typename Slice = views::slice_fn)( requires True AND (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 template(bool True = true, typename Slice = views::slice_fn)( requires True AND (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 template(bool True = true, typename Slice = views::slice_fn)( requires True AND (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 template(bool True = true, typename Slice = views::slice_fn)( requires True AND input_range &>) constexpr auto // operator[](detail::slice_bounds>, 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 const &>) constexpr auto // operator[](detail::slice_bounds>, 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>) constexpr auto // operator[](detail::slice_bounds>, 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 &> || (input_range &> && sized_range &>))) // constexpr auto // operator[](detail::slice_bounds>, 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 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 template(bool True = true, typename Slice = views::slice_fn)( requires True AND (forward_range> || (input_range> && sized_range>))) // constexpr auto // operator[](detail::slice_bounds>, 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 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); } #endif }; namespace cpp20 { template(typename Derived)( requires std::is_class::value AND same_as>>) using view_interface = ranges::view_interface; } /// @} } // namespace ranges #include #endif