template<class R> concept simple-view = // exposition only View<R> && Range<const R> && Same<iterator_t<R>, iterator_t<const R>> && Same<sentinel_t<R>, sentinel_t<const R>>; template<InputIterator I> concept has-arrow = // exposition only is_pointer_v<I> || requires(I i) { i.operator->(); }; template<class T, class U> concept not-same-as = // exposition only !Same<remove_cvref_t<T>, remove_cvref_t<U>>;
namespace std::ranges { template<Range R> struct range-common-iterator-impl { // exposition only using type = common_iterator<iterator_t<R>, sentinel_t<R>>; }; template<CommonRange R> struct range-common-iterator-impl<R> { // exposition only using type = iterator_t<R>; }; template<Range R> using range-common-iterator = // exposition only typename range-common-iterator-impl<R>::type; template<class D> requires is_class_v<D> && Same<D, remove_cv_t<D>> class view_interface : public view_base { private: constexpr D& derived() noexcept { // exposition only return static_cast<D&>(*this); } constexpr const D& derived() const noexcept { // exposition only return static_cast<const D&>(*this); } public: constexpr bool empty() requires ForwardRange<D> { return ranges::begin(derived()) == ranges::end(derived()); } constexpr bool empty() const requires ForwardRange<const D> { return ranges::begin(derived()) == ranges::end(derived()); } constexpr explicit operator bool() requires requires { ranges::empty(derived()); } { return !ranges::empty(derived()); } constexpr explicit operator bool() const requires requires { ranges::empty(derived()); } { return !ranges::empty(derived()); } constexpr auto data() requires ContiguousIterator<iterator_t<D>> { return ranges::empty(derived()) ? nullptr : addressof(*ranges::begin(derived())); } constexpr auto data() const requires Range<const D> && ContiguousIterator<iterator_t<const D>> { return ranges::empty(derived()) ? nullptr : addressof(*ranges::begin(derived())); } constexpr auto size() requires ForwardRange<D> && SizedSentinel<sentinel_t<D>, iterator_t<D>> { return ranges::end(derived()) - ranges::begin(derived()); } constexpr auto size() const requires ForwardRange<const D> && SizedSentinel<sentinel_t<const D>, iterator_t<const D>> { return ranges::end(derived()) - ranges::begin(derived()); } constexpr decltype(auto) front() requires ForwardRange<D>; constexpr decltype(auto) front() const requires ForwardRange<const D>; constexpr decltype(auto) back() requires BidirectionalRange<D> && CommonRange<D>; constexpr decltype(auto) back() const requires BidirectionalRange<const D> && CommonRange<const D>; template<RandomAccessRange R = D> constexpr decltype(auto) operator[](iter_difference_t<iterator_t<R>> n) { return ranges::begin(derived())[n]; } template<RandomAccessRange R = const D> constexpr decltype(auto) operator[](iter_difference_t<iterator_t<R>> n) const { return ranges::begin(derived())[n]; } }; }
constexpr decltype(auto) front() requires ForwardRange<D>;
constexpr decltype(auto) front() const requires ForwardRange<const D>;
constexpr decltype(auto) back() requires BidirectionalRange<D> && CommonRange<D>;
constexpr decltype(auto) back() const
requires BidirectionalRange<const D> && CommonRange<const D>;
namespace std::ranges { template<class T> concept pair-like = // exposition only !is_reference_v<T> && requires(T t) { typename tuple_size<T>::type; // ensures tuple_size<T> is complete requires DerivedFrom<tuple_size<T>, integral_constant<size_t, 2>>; typename tuple_element_t<0, remove_const_t<T>>; typename tuple_element_t<1, remove_const_t<T>>; { get<0>(t) } -> const tuple_element_t<0, T>&; { get<1>(t) } -> const tuple_element_t<1, T>&; }; template<class T, class U, class V> concept pair-like-convertible-to = // exposition only !Range<T> && pair-like<remove_reference_t<T>> && requires(T&& t) { { get<0>(std::forward<T>(t)) } -> ConvertibleTo<U>; { get<1>(std::forward<T>(t)) } -> ConvertibleTo<V>; }; template<class T, class U, class V> concept pair-like-convertible-from = // exposition only !Range<T> && pair-like<T> && Constructible<T, U, V>; template<class T> concept iterator-sentinel-pair = // exposition only !Range<T> && pair-like<T> && Sentinel<tuple_element_t<1, T>, tuple_element_t<0, T>>; template<Iterator I, Sentinel<I> S = I, subrange_kind K = SizedSentinel<S, I> ? subrange_kind::sized : subrange_kind::unsized> requires (K == subrange_kind::sized || !SizedSentinel<S, I>) class subrange : public view_interface<subrange<I, S, K>> { private: static constexpr bool StoreSize = // exposition only K == subrange_kind::sized && !SizedSentinel<S, I>; I begin_ = I(); // exposition only S end_ = S(); // exposition only iter_difference_t<I> size_ = 0; // exposition only; present only // when StoreSize is true public: subrange() = default; constexpr subrange(I i, S s) requires (!StoreSize); constexpr subrange(I i, S s, iter_difference_t<I> n) requires (K == subrange_kind::sized); template<not-same-as<subrange> R> requires forwarding-range<R> && ConvertibleTo<iterator_t<R>, I> && ConvertibleTo<sentinel_t<R>, S> constexpr subrange(R&& r) requires (!StoreSize || SizedRange<R>); template<forwarding-range R> requires ConvertibleTo<iterator_t<R>, I> && ConvertibleTo<sentinel_t<R>, S> constexpr subrange(R&& r, iter_difference_t<I> n) requires (K == subrange_kind::sized) : subrange{ranges::begin(r), ranges::end(r), n} {} template<not-same-as<subrange> PairLike> requires pair-like-convertible-to<PairLike, I, S> constexpr subrange(PairLike&& r) requires (!StoreSize) : subrange{std::get<0>(std::forward<PairLike>(r)), std::get<1>(std::forward<PairLike>(r))} {} template<pair-like-convertible-to<I, S> PairLike> constexpr subrange(PairLike&& r, iter_difference_t<I> n) requires (K == subrange_kind::sized) : subrange{std::get<0>(std::forward<PairLike>(r)), std::get<1>(std::forward<PairLike>(r)), n} {} template<not-same-as<subrange> PairLike> requires pair-like-convertible-from<PairLike, const I&, const S&> constexpr operator PairLike() const; constexpr I begin() const; constexpr S end() const; constexpr bool empty() const; constexpr iter_difference_t<I> size() const requires (K == subrange_kind::sized); [[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) const; [[nodiscard]] constexpr subrange prev(iter_difference_t<I> n = 1) const requires BidirectionalIterator<I>; constexpr subrange& advance(iter_difference_t<I> n); friend constexpr I begin(subrange&& r) { return r.begin(); } friend constexpr S end(subrange&& r) { return r.end(); } }; template<Iterator I, Sentinel<I> S> subrange(I, S, iter_difference_t<I>) -> subrange<I, S, subrange_kind::sized>; template<iterator-sentinel-pair P> subrange(P) -> subrange<tuple_element_t<0, P>, tuple_element_t<1, P>>; template<iterator-sentinel-pair P> subrange(P, iter_difference_t<tuple_element_t<0, P>>) -> subrange<tuple_element_t<0, P>, tuple_element_t<1, P>, subrange_kind::sized>; template<forwarding-range R> subrange(R&&) -> subrange<iterator_t<R>, sentinel_t<R>, (SizedRange<R> || SizedSentinel<sentinel_t<R>, iterator_t<R>>) ? subrange_kind::sized : subrange_kind::unsized>; template<forwarding-range R> subrange(R&&, iter_difference_t<iterator_t<R>>) -> subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>; template<size_t N, class I, class S, subrange_kind K> requires (N < 2) constexpr auto get(const subrange<I, S, K>& r); } namespace std { using ranges::get; }
constexpr subrange(I i, S s) requires (!StoreSize);
constexpr subrange(I i, S s, iter_difference_t<I> n)
requires (K == subrange_kind::sized);
template<not-same-as<subrange> R>
requires forwarding-range<R> &&
ConvertibleTo<iterator_t<R>, I> && ConvertibleTo<sentinel_t<R>, S>
constexpr subrange(R&& r) requires (!StoreSize || SizedRange<R>);
template<not-same-as<subrange> PairLike>
requires pair-like-convertible-from<PairLike, const I&, const S&>
constexpr operator PairLike() const;
constexpr I begin() const;
constexpr S end() const;
constexpr bool empty() const;
constexpr iter_difference_t<I> size() const
requires (K == subrange_kind::sized);
[[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) const;
[[nodiscard]] constexpr subrange prev(iter_difference_t<I> n = 1) const
requires BidirectionalIterator<I>;
constexpr subrange& advance(iter_difference_t<I> n);
template<size_t N, class I, class S, subrange_kind K>
requires (N < 2)
constexpr auto get(const subrange<I, S, K>& r);