1// Copyright (C) 2022 T. Zachary Laine
2//
3// Distributed under the Boost Software License, Version 1.0. (See
4// accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6#ifndef BOOST_STL_INTERFACES_EXAMPLE_REVERSE_VIEW_HPP
7#define BOOST_STL_INTERFACES_EXAMPLE_REVERSE_VIEW_HPP
8#include "all_view.hpp"
9
10namespace detail {
11 //[ reverse_view_defn
12 // We need to treat iterator/sentinel ranges differently from iterator
13 // ranges (a.k.a. common_ranges). If the iterator and sentinel are
14 // different types, we need to advance the iterator to the end of the
15 // range before we can move through the range in reverse.
16 template<bool CommonRange>
17 struct set_rev_rng_first
18 {
19 template<typename V>
20 static auto call(V const & v)
21 {
22 return boost::stl_interfaces::make_reverse_iterator(v.end());
23 }
24 };
25
26 template<>
27 struct set_rev_rng_first<false>
28 {
29 template<typename V>
30 static auto call(V const & v)
31 {
32 auto v_f = v.begin();
33 auto const v_l = v.end();
34 while (v_f != v_l) {
35 ++v_f;
36 }
37 return boost::stl_interfaces::make_reverse_iterator(v_f);
38 }
39 };
40
41 // This view reverses whatever view you construct it from. Unlike
42 // all_view, it requires that it be constructed from a view. This is
43 // enforced through a constraint in C++20 and later, but is left up to the
44 // user in earlier C++ modes.
45#if BOOST_STL_INTERFACES_USE_CONCEPTS
46 template<std::ranges::view View>
47 requires std::is_object_v<View>
48#else
49 template<
50 typename View,
51 typename Enable = std::enable_if_t<std::is_object<View>::value>>
52#endif
53 struct reverse_view
54 : boost::stl_interfaces::view_interface<reverse_view<View>>
55 {
56 using view_iterator = iterator_t<View>;
57 using view_sentinel = sentinel_t<View>;
58
59 // This would be better off as a constraint in C++20 and later.
60 static_assert(
61 std::is_base_of<
62 std::bidirectional_iterator_tag,
63 typename std::iterator_traits<
64 view_iterator>::iterator_category>::value,
65 "A reversed view must have bidirectional iterators.");
66
67 using iterator = boost::stl_interfaces::reverse_iterator<view_iterator>;
68
69 constexpr reverse_view() = default;
70
71#if BOOST_STL_INTERFACES_USE_CONCEPTS
72 template<typename V>
73 requires std::is_same_v<std::remove_reference_t<V>, View>
74#else
75 template<
76 typename V,
77 typename E = std::enable_if_t<
78 std::is_same<std::remove_reference_t<V>, View>::value>>
79#endif
80 constexpr reverse_view(int, V && v) : v_{(V &&) v}
81 {
82 // To keep the code simpler, we just store the iterator to the end
83 // of v, whether v is a common_range or has different iterator and
84 // sentinel types.
85 first_ = set_rev_rng_first<
86 std::is_same<view_iterator, view_sentinel>::value>::call(v_);
87 }
88
89 constexpr iterator begin() const { return first_; }
90 constexpr iterator end() const
91 {
92 return boost::stl_interfaces::make_reverse_iterator(v_.begin());
93 }
94
95 // Return the underlying view that this view reverses.
96 constexpr View base() const { return v_; }
97
98 private:
99 View v_ = View();
100 iterator first_;
101 };
102
103 // is_reverse_view lets us detect construction of a reverse_view from
104 // another reverse_view, and take appropriate action (see below).
105 template<typename T>
106 struct is_reverse_view : std::false_type
107 {};
108 template<typename T>
109 struct is_reverse_view<reverse_view<T>> : std::true_type
110 {};
111
112#if defined(__cpp_deduction_guides)
113 template<typename R>
114 reverse_view(int, R &&)->detail::reverse_view<std::remove_reference_t<R>>;
115#endif
116 //]
117}
118
119#if defined(__cpp_deduction_guides)
120//[ reverse_defn
121// We want to condition how we construct our view based on whether R is itself
122// a reverse_view. If R is a reverse_view, just return the view it's
123// reversing.
124//
125// In C++20 and later, you might want to constrain this lambda to require that
126// R is a std::ranges::view, since that's what reverse_view requires.
127inline constexpr boost::stl_interfaces::closure reverse =
128 []<typename R>(R && r) {
129 if constexpr (detail::is_reverse_view<std::decay_t<R>>::value) {
130 return ((R &&) r).base();
131 } else {
132 return detail::reverse_view(0, (R &&) r);
133 }
134 };
135//]
136#endif
137
138//[ reverse_enable_borrowed_range
139// Don't forget to designate our view as a borrowed range.
140#if BOOST_STL_INTERFACES_USE_CONCEPTS
141namespace std::ranges {
142 template<typename View>
143 inline constexpr bool enable_borrowed_range<detail::reverse_view<View>> =
144 true;
145}
146#endif
147//]
148
149#endif
150

source code of boost/libs/stl_interfaces/example/reverse_view.hpp