1 /// \file
2 // Range v3 library
3 //
4 //  Copyright Eric Niebler 2014-present
5 //  Copyright Casey Carter 2016
6 //
7 //  Use, modification and distribution is subject to the
8 //  Boost Software License, Version 1.0. (See accompanying
9 //  file LICENSE_1_0.txt or copy at
10 //  http://www.boost.org/LICENSE_1_0.txt)
11 //
12 // Project home: https://github.com/ericniebler/range-v3
13 //
14 
15 #ifndef RANGES_V3_DETAIL_RANGE_ACCESS_HPP
16 #define RANGES_V3_DETAIL_RANGE_ACCESS_HPP
17 
18 #include <cstddef>
19 #include <utility>
20 
21 #include <meta/meta.hpp>
22 
23 #include <concepts/concepts.hpp>
24 
25 #include <range/v3/range_fwd.hpp>
26 
27 #include <range/v3/iterator/concepts.hpp>
28 
29 #include <range/v3/detail/prologue.hpp>
30 
31 namespace ranges
32 {
33     /// \addtogroup group-views
34     /// @{
35     struct range_access
36     {
37         /// \cond
38     private:
39         template<typename T>
40         static std::false_type single_pass_2_(long);
41         template<typename T>
42         static typename T::single_pass single_pass_2_(int);
43 
44         template<typename T>
45         struct single_pass_
46         {
47             using type = decltype(range_access::single_pass_2_<T>(42));
48         };
49 
50         template<typename T>
51         static std::false_type contiguous_2_(long);
52         template<typename T>
53         static typename T::contiguous contiguous_2_(int);
54 
55         template<typename T>
56         struct contiguous_
57         {
58             using type = decltype(range_access::contiguous_2_<T>(42));
59         };
60 
61         template<typename T>
62         static basic_mixin<T> mixin_base_2_(long);
63         template<typename T>
64         static typename T::mixin mixin_base_2_(int);
65 
66         template<typename Cur>
67         struct mixin_base_
68         {
69             using type = decltype(range_access::mixin_base_2_<Cur>(42));
70         };
71 
72 
73     public:
74         template<typename Cur>
75         using single_pass_t = meta::_t<single_pass_<Cur>>;
76 
77         template<typename Cur>
78         using contiguous_t = meta::_t<contiguous_<Cur>>;
79 
80         template<typename Cur>
81         using mixin_base_t = meta::_t<mixin_base_<Cur>>;
82 
83         // clang-format off
84         template<typename Rng>
85         static constexpr auto CPP_auto_fun(begin_cursor)(Rng &rng)
86         (
87             return rng.begin_cursor()
88         )
89         template<typename Rng>
90         static constexpr auto CPP_auto_fun(end_cursor)(Rng &rng)
91         (
92             return rng.end_cursor()
93         )
94 
95         template<typename Rng>
96         static constexpr auto CPP_auto_fun(begin_adaptor)(Rng &rng)
97         (
98             return rng.begin_adaptor()
99         )
100         template<typename Rng>
101         static constexpr auto CPP_auto_fun(end_adaptor)(Rng &rng)
102         (
103             return rng.end_adaptor()
104         )
105 
106         template<typename Cur>
107         static constexpr auto CPP_auto_fun(read)(Cur const &pos)
108         (
109             return pos.read()
110         )
111         template<typename Cur>
112         static constexpr auto CPP_auto_fun(arrow)(Cur const &pos)
113         (
114             return pos.arrow()
115         )
116         template<typename Cur>
117         static constexpr auto CPP_auto_fun(move)(Cur const &pos)
118         (
119             return pos.move()
120         )
121         template<typename Cur, typename T>
122         static constexpr auto CPP_auto_fun(write)(Cur &pos, T &&t)
123         (
124             return pos.write((T &&) t)
125         )
126         template<typename Cur>
127         static constexpr auto CPP_auto_fun(next)(Cur & pos)
128         (
129             return pos.next()
130         )
131         template<typename Cur, typename O>
132         static constexpr auto CPP_auto_fun(equal)(Cur const &pos, O const &other)
133         (
134             return pos.equal(other)
135         )
136         template<typename Cur>
137         static constexpr auto CPP_auto_fun(prev)(Cur & pos)
138         (
139             return pos.prev()
140         )
141         template<typename Cur, typename D>
142         static constexpr auto CPP_auto_fun(advance)(Cur & pos, D n)
143         (
144             return pos.advance(n)
145         )
146         template<typename Cur, typename O>
147         static constexpr auto CPP_auto_fun(distance_to)(Cur const &pos, O const &other)
148         (
149             return pos.distance_to(other)
150         )
151 
152     private:
153         template<typename Cur>
154         using sized_cursor_difference_t = decltype(
155             range_access::distance_to(std::declval<Cur>(), std::declval<Cur>()));
156         // clang-format on
157 
158         template<typename T>
159         static std::ptrdiff_t cursor_difference_2_(detail::ignore_t);
160         template<typename T>
161         static sized_cursor_difference_t<T> cursor_difference_2_(long);
162         template<typename T>
163         static typename T::difference_type cursor_difference_2_(int);
164 
165         template<typename T>
166         using cursor_reference_t = decltype(std::declval<T const &>().read());
167 
168         template<typename T>
169         static meta::id<uncvref_t<cursor_reference_t<T>>> cursor_value_2_(long);
170         template<typename T>
171         static meta::id<typename T::value_type> cursor_value_2_(int);
172 
173 #ifdef RANGES_WORKAROUND_CWG_1554
174         template<typename Cur>
175         struct cursor_difference
176         {
177             using type = decltype(range_access::cursor_difference_2_<Cur>(42));
178         };
179 
180         template<typename Cur>
181         struct cursor_value : decltype(range_access::cursor_value_2_<Cur>(42))
182         {};
183 #endif // RANGES_WORKAROUND_CWG_1554
184     public:
185 #ifdef RANGES_WORKAROUND_CWG_1554
186         template<typename Cur>
187         using cursor_difference_t = meta::_t<cursor_difference<Cur>>;
188 
189         template<typename Cur>
190         using cursor_value_t = meta::_t<cursor_value<Cur>>;
191 #else  // ^^^ workaround ^^^ / vvv no workaround vvv
192         template<typename Cur>
193         using cursor_difference_t = decltype(range_access::cursor_difference_2_<Cur>(42));
194 
195         template<typename Cur>
196         using cursor_value_t = meta::_t<decltype(range_access::cursor_value_2_<Cur>(42))>;
197 #endif // RANGES_WORKAROUND_CWG_1554
198 
199         template<typename Cur>
posranges::range_access200         static constexpr Cur & pos(basic_iterator<Cur> & it) noexcept
201         {
202             return it.pos();
203         }
204         template<typename Cur>
posranges::range_access205         static constexpr Cur const & pos(basic_iterator<Cur> const & it) noexcept
206         {
207             return it.pos();
208         }
209         template<typename Cur>
posranges::range_access210         static constexpr Cur && pos(basic_iterator<Cur> && it) noexcept
211         {
212             return detail::move(it.pos());
213         }
214 
215         template<typename Cur>
cursorranges::range_access216         static constexpr Cur cursor(basic_iterator<Cur> it)
217         {
218             return std::move(it.pos());
219         }
220         /// endcond
221     };
222     /// @}
223 
224     /// \cond
225     namespace detail
226     {
227         //
228         // Concepts that the range cursor must model
229         // clang-format off
230         //
231         template<typename T>
232         CPP_concept cursor =
233             semiregular<T> && semiregular<range_access::mixin_base_t<T>> &&
234             constructible_from<range_access::mixin_base_t<T>, T> &&
235             constructible_from<range_access::mixin_base_t<T>, T const &>;
236             // Axiom: mixin_base_t<T> has a member get(), accessible to derived classes,
237             //   which perfectly-returns the contained cursor object and does not throw
238             //   exceptions.
239 
240         template<typename T>
241         CPP_requires(has_cursor_next_,
242             requires(T & t)
243             (
244                 range_access::next(t)
245             ));
246         template<typename T>
247         CPP_concept has_cursor_next = CPP_requires_ref(detail::has_cursor_next_, T);
248 
249         template<typename S, typename C>
250         CPP_requires(sentinel_for_cursor_,
251             requires(S & s, C & c) //
252             (
253                 range_access::equal(c, s),
254                 concepts::requires_<convertible_to<decltype(
255                     range_access::equal(c, s)), bool>>
256             ));
257         template<typename S, typename C>
258         CPP_concept sentinel_for_cursor =
259             semiregular<S> &&
260             cursor<C> &&
261             CPP_requires_ref(detail::sentinel_for_cursor_, S, C);
262 
263         template<typename T>
264         CPP_requires(readable_cursor_,
265             requires(T & t) //
266             (
267                 range_access::read(t)
268             ));
269         template<typename T>
270         CPP_concept readable_cursor = CPP_requires_ref(detail::readable_cursor_, T);
271 
272         template<typename T>
273         CPP_requires(has_cursor_arrow_,
274             requires(T const & t) //
275             (
276                 range_access::arrow(t)
277             ));
278         template<typename T>
279         CPP_concept has_cursor_arrow = CPP_requires_ref(detail::has_cursor_arrow_, T);
280 
281         template<typename T, typename U>
282         CPP_requires(writable_cursor_,
283             requires(T & t, U && u) //
284             (
285                 range_access::write(t, (U &&) u)
286             ));
287         template<typename T, typename U>
288         CPP_concept writable_cursor =
289             CPP_requires_ref(detail::writable_cursor_, T, U);
290 
291         template<typename S, typename C>
292         CPP_requires(sized_sentinel_for_cursor_,
293             requires(S & s, C & c) //
294             (
295                 range_access::distance_to(c, s),
296                 concepts::requires_<signed_integer_like_<decltype(
297                     range_access::distance_to(c, s))>>
298             )
299         );
300         template<typename S, typename C>
301         CPP_concept sized_sentinel_for_cursor =
302             sentinel_for_cursor<S, C> &&
303             CPP_requires_ref(detail::sized_sentinel_for_cursor_, S, C);
304 
305         template<typename T, typename U>
306         CPP_concept output_cursor =
307             writable_cursor<T, U> && cursor<T>;
308 
309         template<typename T>
310         CPP_concept input_cursor =
311             readable_cursor<T> && cursor<T> && has_cursor_next<T>;
312 
313         template<typename T>
314         CPP_concept forward_cursor =
315             input_cursor<T> && sentinel_for_cursor<T, T> &&
316             !range_access::single_pass_t<uncvref_t<T>>::value;
317 
318         template<typename T>
319         CPP_requires(bidirectional_cursor_,
320             requires(T & t) //
321             (
322                 range_access::prev(t)
323             ));
324         template<typename T>
325         CPP_concept bidirectional_cursor =
326             forward_cursor<T> &&
327             CPP_requires_ref(detail::bidirectional_cursor_, T);
328 
329         template<typename T>
330         CPP_requires(random_access_cursor_,
331             requires(T & t) //
332             (
333                 range_access::advance(t, range_access::distance_to(t, t))
334             ));
335         template<typename T>
336         CPP_concept random_access_cursor =
337             bidirectional_cursor<T> && //
338             sized_sentinel_for_cursor<T, T> && //
339             CPP_requires_ref(detail::random_access_cursor_, T);
340 
341         template(class T)(
342             /// \pre
343             requires std::is_lvalue_reference<T>::value)
344         void is_lvalue_reference(T&&);
345 
346         template<typename T>
347         CPP_requires(contiguous_cursor_,
348             requires(T & t) //
349             (
350                 detail::is_lvalue_reference(range_access::read(t))
351             ));
352         template<typename T>
353         CPP_concept contiguous_cursor =
354             random_access_cursor<T> && //
355             range_access::contiguous_t<uncvref_t<T>>::value && //
356             CPP_requires_ref(detail::contiguous_cursor_, T);
357         // clang-format on
358 
359         template<typename Cur, bool IsReadable>
360         RANGES_INLINE_VAR constexpr bool is_writable_cursor_ = true;
361 
362         template<typename Cur>
363         RANGES_INLINE_VAR constexpr bool is_writable_cursor_<Cur, true> =
364             (bool) writable_cursor<Cur, range_access::cursor_value_t<Cur>>;
365 
366         template<typename Cur>
367         RANGES_INLINE_VAR constexpr bool is_writable_cursor_v =
368             is_writable_cursor_<Cur, (bool)readable_cursor<Cur>>;
369     } // namespace detail
370     /// \endcond
371 } // namespace ranges
372 
373 #include <range/v3/detail/epilogue.hpp>
374 
375 #endif
376