Horizon
Loading...
Searching...
No Matches
common_iterator.hpp
Go to the documentation of this file.
1
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#ifndef RANGES_V3_ITERATOR_COMMON_ITERATOR_HPP
15#define RANGES_V3_ITERATOR_COMMON_ITERATOR_HPP
16
17#include <cstdint>
18#include <iterator>
19#include <type_traits>
20
21#include <meta/meta.hpp>
22
23#include <concepts/concepts.hpp>
24
26
27#include <range/v3/detail/variant.hpp>
31
32#include <range/v3/detail/prologue.hpp>
33
34namespace ranges
35{
38
40 namespace detail
41 {
42 template<typename I, typename S>
43 variant<I, S> & cidata(common_iterator<I, S> & that)
44 {
45 return that.data_;
46 }
47
48 template<typename I, typename S>
49 variant<I, S> const & cidata(common_iterator<I, S> const & that)
50 {
51 return that.data_;
52 }
53 } // namespace detail
54
55#if RANGES_BROKEN_CPO_LOOKUP
56 namespace _common_iterator_
57 {
58 struct adl_hook
59 {};
60 } // namespace _common_iterator_
61#endif
63
64 template<typename I, typename S>
66#if RANGES_BROKEN_CPO_LOOKUP
67 : private _common_iterator_::adl_hook
68#endif
69 {
70 private:
72 CPP_assert(sentinel_for<S, I>);
73 CPP_assert(!same_as<I, S>);
74 variant<I, S> data_;
75
76 friend variant<I, S> & detail::cidata<>(common_iterator<I, S> &);
77 friend variant<I, S> const & detail::cidata<>(common_iterator<I, S> const &);
78 struct emplace_fn
79 {
80 variant<I, S> * data_;
81 template<typename T, std::size_t N>
82 void operator()(indexed_element<T, N> t) const
83 {
84 ranges::emplace<N>(*data_, t.get());
85 }
86 };
87 struct arrow_proxy_
88 {
89 private:
90 friend common_iterator;
91 iter_value_t<I> keep_;
92 arrow_proxy_(iter_reference_t<I> && x)
93 : keep_(std::move(x))
94 {}
95
96 public:
97 const iter_value_t<I> * operator->() const noexcept
98 {
99 return std::addressof(keep_);
100 }
101 };
102 template<typename T>
103 static T * operator_arrow_(T * p, int) noexcept
104 {
105 return p;
106 }
107 template<typename J, typename = detail::iter_arrow_t<J const>>
108 static J operator_arrow_(J const & j, int) noexcept(noexcept(J(j)))
109 {
110 return j;
111 }
112 template(typename J, typename R = iter_reference_t<J>)(
113 requires std::is_reference<R>::value) //
114 static meta::_t<std::add_pointer<R>> operator_arrow_(J const & j, long) noexcept
115 {
116 auto && r = *j;
117 return std::addressof(r);
118 }
119 template(typename J, typename V = iter_value_t<J>)(
120 requires constructible_from<V, iter_reference_t<J>>)
121 static arrow_proxy_ operator_arrow_(J const & j, ...) noexcept(noexcept(V(V(*j))))
122 {
123 return arrow_proxy_(*j);
124 }
125
126 public:
127 using difference_type = iter_difference_t<I>;
128
129 common_iterator() = default;
130 common_iterator(I i)
131 : data_(emplaced_index<0>, std::move(i))
132 {}
133 common_iterator(S s)
134 : data_(emplaced_index<1>, std::move(s))
135 {}
136 template(typename I2, typename S2)(
137 requires convertible_to<I2, I> AND convertible_to<S2, S>)
139 : data_(detail::variant_core_access::make_empty<I, S>())
140 {
141 detail::cidata(that).visit_i(emplace_fn{&data_});
142 }
143 template(typename I2, typename S2)(
144 requires convertible_to<I2, I> AND convertible_to<S2, S>)
145 common_iterator & operator=(common_iterator<I2, S2> const & that)
146 {
147 detail::cidata(that).visit_i(emplace_fn{&data_});
148 return *this;
149 }
150 iter_reference_t<I> operator*() //
151 noexcept(noexcept(iter_reference_t<I>(*std::declval<I &>())))
152 {
153 return *ranges::get<0>(data_);
154 }
155 CPP_member
156 auto operator*() const //
157 noexcept(noexcept(iter_reference_t<I>(*std::declval<I const &>())))
158 -> CPP_ret(iter_reference_t<I>)(
160 {
161 return *ranges::get<0>(data_);
162 }
163 template(typename J = I)(
164 requires indirectly_readable<J>)
165 auto operator->() const //
166 noexcept(
167 noexcept(common_iterator::operator_arrow_(std::declval<I const &>(), 42)))
168 -> decltype(common_iterator::operator_arrow_(std::declval<J const &>(), 42))
169 {
170 return common_iterator::operator_arrow_(ranges::get<0>(data_), 42);
171 }
172 common_iterator & operator++()
173 {
174 ++ranges::get<0>(data_);
175 return *this;
176 }
177#ifdef RANGES_WORKAROUND_MSVC_677925
178 template(typename I2 = I)(
179 requires (!forward_iterator<I2>)) //
180 auto operator++(int) //
181 -> decltype(std::declval<I2 &>()++)
182 {
183 return ranges::get<0>(data_)++;
184 }
185#else // ^^^ workaround ^^^ / vvv no workaround vvv
186 CPP_member
187 auto operator++(int) //
188 -> CPP_ret(decltype(std::declval<I &>()++))(
189 requires (!forward_iterator<I>))
190 {
191 return ranges::get<0>(data_)++;
192 }
193#endif // RANGES_WORKAROUND_MSVC_677925
194 CPP_member
195 auto operator++(int) //
196 -> CPP_ret(common_iterator)(
197 requires forward_iterator<I>)
198 {
199 return common_iterator(ranges::get<0>(data_)++);
200 }
201
202#if !RANGES_BROKEN_CPO_LOOKUP
203 template<typename I_ = I>
204 friend constexpr auto iter_move(common_iterator const & i) //
205 noexcept(detail::has_nothrow_iter_move_v<I>)
206 -> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
207 requires input_iterator<I_>)
208 {
209 return ranges::iter_move(ranges::get<0>(detail::cidata(i)));
210 }
211 template<typename I2, typename S2>
212 friend auto iter_swap(
213 common_iterator const & x,
216 -> CPP_broken_friend_ret(void)(
218 {
219 return ranges::iter_swap(ranges::get<0>(detail::cidata(x)),
220 ranges::get<0>(detail::cidata(y)));
221 }
222#endif
223 };
224
226#if RANGES_BROKEN_CPO_LOOKUP
227 namespace _common_iterator_
228 {
229 template<typename I, typename S>
230 constexpr auto iter_move(common_iterator<I, S> const & i) noexcept(
231 detail::has_nothrow_iter_move_v<I>)
232 -> CPP_broken_friend_ret(iter_rvalue_reference_t<I>)(
233 requires input_iterator<I>)
234 {
235 return ranges::iter_move(ranges::get<0>(detail::cidata(i)));
236 }
237 template<typename I1, typename S1, typename I2, typename S2>
238 auto iter_swap(common_iterator<I1, S1> const & x,
239 common_iterator<I2, S2> const & y) //
240 noexcept(is_nothrow_indirectly_swappable<I1, I2>::value)
241 -> CPP_broken_friend_ret(void)(
242 requires indirectly_swappable<I1, I2>)
243 {
244 return ranges::iter_swap(ranges::get<0>(detail::cidata(x)),
245 ranges::get<0>(detail::cidata(y)));
246 }
247 } // namespace _common_iterator_
248#endif
250
251 template(typename I1, typename I2, typename S1, typename S2)(
252 requires sentinel_for<S1, I2> AND sentinel_for<S2, I1> AND
253 (!equality_comparable_with<I1, I2>)) //
254 bool operator==(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
255 {
256 return detail::cidata(x).index() == 1u ? (detail::cidata(y).index() == 1u ||
257 ranges::get<0>(detail::cidata(y)) ==
258 ranges::get<1>(detail::cidata(x)))
259 : (detail::cidata(y).index() != 1u ||
260 ranges::get<0>(detail::cidata(x)) ==
261 ranges::get<1>(detail::cidata(y)));
262 }
263
264 template(typename I1, typename I2, typename S1, typename S2)(
265 requires sentinel_for<S1, I2> AND sentinel_for<S2, I1> AND
266 equality_comparable_with<I1, I2>)
267 bool operator==(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
268 {
269 return detail::cidata(x).index() == 1u
270 ? (detail::cidata(y).index() == 1u ||
271 ranges::get<0>(detail::cidata(y)) ==
272 ranges::get<1>(detail::cidata(x)))
273 : (detail::cidata(y).index() == 1u
274 ? ranges::get<0>(detail::cidata(x)) ==
275 ranges::get<1>(detail::cidata(y))
276 : ranges::get<0>(detail::cidata(x)) ==
277 ranges::get<0>(detail::cidata(y)));
278 }
279
280 template(typename I1, typename I2, typename S1, typename S2)(
281 requires sentinel_for<S1, I2> AND sentinel_for<S2, I1>)
282 bool operator!=(common_iterator<I1, S1> const & x, common_iterator<I2, S2> const & y)
283 {
284 return !(x == y);
285 }
286
287 template(typename I1, typename I2, typename S1, typename S2)(
288 requires sized_sentinel_for<I1, I2> AND sized_sentinel_for<S1, I2> AND
289 sized_sentinel_for<S2, I1>)
290 iter_difference_t<I2> operator-(common_iterator<I1, S1> const & x,
291 common_iterator<I2, S2> const & y)
292 {
293 return detail::cidata(x).index() == 1u
294 ? (detail::cidata(y).index() == 1u
295 ? 0
296 : ranges::get<1>(detail::cidata(x)) -
297 ranges::get<0>(detail::cidata(y)))
298 : (detail::cidata(y).index() == 1u
299 ? ranges::get<0>(detail::cidata(x)) -
300 ranges::get<1>(detail::cidata(y))
301 : ranges::get<0>(detail::cidata(x)) -
302 ranges::get<0>(detail::cidata(y)));
303 }
304
305 template<typename I, typename S>
306 struct indirectly_readable_traits<common_iterator<I, S>>
307 : meta::if_c<
308 (bool)indirectly_readable<I>,
309 indirectly_readable_traits<I>,
311 {};
312
314 namespace detail
315 {
316 template<typename I>
317 auto demote_common_iter_cat(...) -> nil_;
318 template<typename I>
319 auto demote_common_iter_cat(long)
320 -> with_iterator_category<std::input_iterator_tag>;
321 template(typename I)(
322 requires derived_from<typename std::iterator_traits<I>::iterator_category,
323 std::forward_iterator_tag>)
324 auto demote_common_iter_cat(int)
325 -> with_iterator_category<std::forward_iterator_tag>;
326
327 template<typename I, bool = (bool)input_iterator<I>>
328 struct common_iterator_std_traits : decltype(detail::demote_common_iter_cat<I>(0))
329 {
330 using difference_type = iter_difference_t<I>;
331 using value_type = iter_value_t<I>;
332 using reference = iter_reference_t<I>;
333 using pointer = detail::iter_pointer_t<I>;
334 using iterator_concept =
335 meta::conditional_t<(bool)forward_iterator<I>, std::forward_iterator_tag,
336 std::input_iterator_tag>;
337 };
338
339 template<typename I>
340 struct common_iterator_std_traits<I, false>
341 {
342 using difference_type = iter_difference_t<I>;
343 using value_type = void;
344 using reference = void;
345 using pointer = void;
346 using iterator_category = std::output_iterator_tag;
347 };
348
349 // An iterator adaptor that demotes a user-defined difference_type to
350 // std::intmax_t, for use when constructing containers from such
351 // iterators.
352 template<typename I>
353 struct cpp17_iterator_cursor
354 {
355 private:
356 friend range_access;
357 I it_;
358 struct mixin : basic_mixin<cpp17_iterator_cursor>
359 {
360 mixin() = default;
361 #ifndef _MSC_VER
362 using basic_mixin<cpp17_iterator_cursor>::basic_mixin;
363 #else
364 constexpr explicit mixin(cpp17_iterator_cursor && cur)
365 : basic_mixin<cpp17_iterator_cursor>(
366 static_cast<cpp17_iterator_cursor &&>(cur))
367 {}
368 constexpr explicit mixin(cpp17_iterator_cursor const & cur)
369 : basic_mixin<cpp17_iterator_cursor>(cur)
370 {}
371 #endif
372 explicit mixin(I it)
373 : mixin{cpp17_iterator_cursor{std::move(it)}}
374 {}
375 I base() const
376 {
377 return this->get().it_;
378 }
379 };
380
381 public:
382 using single_pass = meta::bool_<!forward_iterator<I>>;
383 using difference_type = std::ptrdiff_t;
384 using value_type = iter_value_t<I>;
385
386 cpp17_iterator_cursor() = default;
387 constexpr explicit cpp17_iterator_cursor(I i)
388 : it_(static_cast<I &&>(i))
389 {}
390
391 I arrow() const
392 {
393 return it_;
394 }
395 decltype(auto) read()
396 {
397 return *it_;
398 }
399 decltype(auto) read() const
400 {
401 return *it_;
402 }
403 void next()
404 {
405 ++it_;
406 }
407 bool equal(cpp17_iterator_cursor const & that) const
408 {
409 return it_ == that.it_;
410 }
411 CPP_member
412 auto prev() //
413 -> CPP_ret(void)(
414 requires bidirectional_iterator<I>)
415 {
416 --it_;
417 }
418 CPP_member
419 auto advance(std::ptrdiff_t n) //
420 -> CPP_ret(void)(
421 requires random_access_iterator<I>)
422 {
423 it_ += static_cast<iter_difference_t<I>>(n);
424 }
425 CPP_member
426 auto distance_to(cpp17_iterator_cursor const & that) //
427 -> CPP_ret(std::ptrdiff_t)(
428 requires random_access_iterator<I>)
429 {
430 auto d = that.it_ - it_;
431 RANGES_EXPECT(d <= PTRDIFF_MAX);
432 return static_cast<std::ptrdiff_t>(d);
433 }
434 };
435 } // namespace detail
437
438 namespace cpp20
439 {
441 }
443} // namespace ranges
444
446RANGES_DIAGNOSTIC_PUSH
447RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
448
449namespace std
450{
451 template<typename I, typename S>
452 struct iterator_traits<::ranges::common_iterator<I, S>>
453 : ::ranges::detail::common_iterator_std_traits<I>
454 {};
455} // namespace std
456
457RANGES_DIAGNOSTIC_POP
459
460#include <range/v3/detail/epilogue.hpp>
461
462#endif
The forward_iterator concept.
The indirectly_readable concept.
The indirectly_swappable concept.
The input_iterator concept.
The input_or_output_iterator concept.
The sentinel_for concept.
std::integral_constant< bool, B > bool_
An integral constant wrapper for bool.
Definition meta.hpp:168
typename T::type _t
Type alias for T::type.
Definition meta.hpp:141
typename detail::_cond< If >::template invoke< Then, Else > conditional_t
Select one type or another depending on a compile-time Boolean.
Definition meta.hpp:1148
Tiny meta-programming library.
Point operator-(const Point &a, const Point &b)
Subtract two points_ component-wise.
Definition shapes.h:244
An empty type.
Definition meta.hpp:135
Definition common_iterator.hpp:69
Definition variant.hpp:71
Definition variant.hpp:621