libcaramel
iterator_facade.hpp
1 #pragma once
2 
3 #include <libcaramel/util/crtp.hpp>
4 
5 #include <cstddef>
6 #include <memory>
7 #include <type_traits>
8 
9 namespace caramel
10 {
11  namespace detail
12  {
13  // clang-format off
14 
15  template <typename T>
16  struct wrap_refs
17  {
18  using type = T;
19  };
20 
21  template <typename T>
22  requires std::is_reference_v<T>
23  struct wrap_refs<T>
24  {
25  using type = std::reference_wrapper<std::remove_reference_t<T>>;
26  };
27  // clang-format on
28 
29  template <typename T>
30  using wrap_refs_t = typename wrap_refs<T>::type;
31 
32  template <typename T>
33  constexpr auto unref(T&& t) noexcept -> T&&
34  {
35  return static_cast<T&&>(t);
36  }
37 
38  template <typename T>
39  constexpr auto unref(std::reference_wrapper<T> t) noexcept -> T&
40  {
41  return t;
42  }
43 
44  template <typename Any>
46  {
47  wrap_refs_t<Any> m_value;
48 
49  public:
50  explicit constexpr arrow_proxy(Any&& t) noexcept : m_value(std::forward<decltype(t)&&>(t))
51  {}
52 
53  constexpr auto operator*() noexcept -> auto& { return unref(m_value); }
54  constexpr auto operator*() const noexcept -> auto& { return unref(m_value); }
55 
56  constexpr auto operator->() noexcept { return std::addressof(**this); }
57  constexpr auto operator->() const noexcept { return std::addressof(**this); }
58  };
59 
60  template <typename T>
62 
64  {
65  };
66 
67  // clang-format off
68 
69  template <typename Sentinel, typename Iter>
70  concept sized_sentinel_of = requires(const Iter& it, const Sentinel& sentinel)
71  {
72  it.distance_to(sentinel);
73  };
74 
75  template <typename>
77  {
78  using type = std::ptrdiff_t;
79  };
80 
81  template <typename Any>
82  requires sized_sentinel_of<Any, Any>
84  {
85  static const Any& _it;
86  using type = decltype(_it.distance_to(_it));
87  };
88 
89  template <typename Any>
90  using infer_difference_type_t = typename infer_difference_type<Any>::type;
91 
92 
93  template <typename Any>
95  {
96  static const Any& _it;
97  using type = std::remove_const_t<std::remove_reference_t<decltype(*_it)>>;
98  };
99 
100  template <typename Any>
101  requires requires { typename Any::value_type; }
102  struct infer_value_type<Any>
103  {
104  using type = typename Any::value_type;
105  };
106 
107  template <typename Any>
108  using infer_value_type_t = typename infer_value_type<Any>::type;
109 
110  template<typename Any>
111  concept can_increment = requires(Any& v)
112  {
113  v.increment();
114  };
115 
116  template<typename Any>
117  concept can_decrement = requires(Any& v)
118  {
119  v.decrement();
120  };
121 
122  template <typename Any>
123  concept can_advance = requires(Any& v, const infer_difference_type_t<Any> d)
124  {
125  v.advance(d);
126  };
127 
128  template <typename Any>
129  concept random_access_iter = sized_sentinel_of<Any, Any> and can_advance<Any>;
130 
131  template <typename Any>
132  concept bidirectional_iter = random_access_iter<Any> or can_decrement<Any>;
133 
134  template <typename Any>
135  concept single_pass_iter = bool(Any::single_pass_iterator);
136 
137  template <typename Any, typename Iter>
138  concept iter_diff = std::is_convertible_v<Any, infer_difference_type_t<Iter>>;
139  // clang-format on
140  } // namespace detail
141 
142  template <typename Child>
143  class iterator_facade : public crtp<Child, iterator_facade>, public detail::iterator_facade_base
144  {
145  public:
146  constexpr auto operator==(const Child& rhs) const -> bool
147  {
148  return this->underlying().equal_to(rhs);
149  }
150 
151  constexpr decltype(auto) operator*() const { return this->underlying().dereference(); }
152  constexpr auto operator->() const
153  {
154  decltype(auto) ref = **this;
155  if constexpr (std::is_reference_v<decltype(ref)>)
156  {
157  return std::addressof(ref);
158  }
159  else
160  {
161  return detail::arrow_proxy{std::move(ref)};
162  }
163  }
164 
165  constexpr auto operator++() -> Child&
166  {
167  if constexpr (detail::can_increment<Child>)
168  {
169  this->underlying().increment();
170  }
171  else if constexpr (detail::random_access_iter<Child>)
172  {
173  this->underlying() += 1;
174  }
175  else
176  {
177  static_assert(detail::random_access_iter<Child>,
178  "Iterator subclass must provide an `increment` or `advance(n)` method");
179  }
180 
181  return this->underlying();
182  }
183 
184  constexpr auto operator++(int) // NOLINT
185  {
186  if constexpr (detail::single_pass_iter<Child>)
187  {
188  ++*this;
189  }
190  else
191  {
192  auto it = this->underlying();
193  ++*this;
194 
195  return it;
196  }
197  }
198 
199  constexpr auto operator--() -> Child& requires detail::bidirectional_iter<Child>
200  {
201  if constexpr (detail::can_decrement<Child>)
202  {
203  this->underlying().decrement();
204  }
205  else
206  {
207  this->underlying() -= 1;
208  }
209 
210  return this->underlying();
211  }
212 
213  constexpr auto operator--(int) -> Child requires detail::bidirectional_iter<Child>
214  {
215  auto it = this->underlying();
216  --*this;
217 
218  return it;
219  }
220 
221  template <detail::iter_diff<Child> Diff>
222  friend constexpr auto operator+(const Child& left, Diff off) noexcept
223  requires detail::random_access_iter<Child>
224  {
225  auto cp = left;
226  return cp += off;
227  }
228 
229  template <detail::iter_diff<Child> D>
230  friend constexpr auto operator+(D off, const Child& self) noexcept
231  requires detail::random_access_iter<Child>
232  {
233  return self + off;
234  }
235 
236  friend constexpr auto operator-(const Child& left,
237  const Child& right) requires detail::random_access_iter<Child>
238  {
239  return right.distance_to(left);
240  }
241 
242  template <detail::iter_diff<Child> D>
243  friend constexpr auto operator-(const Child& self, D off) noexcept
244  requires detail::random_access_iter<Child>
245  {
246  using diff_type = detail::infer_difference_type_t<Child>;
247  using signed_diff_type = std::make_signed_t<diff_type>;
248  return self + -static_cast<signed_diff_type>(off);
249  }
250 
251  template <detail::sized_sentinel_of<Child> S>
252  friend constexpr auto operator-(const S& s, const Child& self) noexcept
253  {
254  return self.distance_to(s);
255  }
256 
257  template <detail::iter_diff<Child> D>
258  constexpr friend auto operator+=(Child& self, D off) noexcept
259  -> Child& requires detail::random_access_iter<Child>
260  {
261  self.advance(off);
262  return self;
263  }
264 
265  template <detail::iter_diff<Child> D>
266  constexpr friend auto operator-=(Child& self, D off) noexcept
267  -> Child& requires detail::random_access_iter<Child>
268  {
269  return self = self - off;
270  }
271 
272  template <detail::iter_diff<Child> D>
273  [[nodiscard]] constexpr decltype(auto) operator[](D pos) const noexcept
274  requires detail::random_access_iter<Child>
275  {
276  return *(this->underlying() + pos);
277  }
278 
279  template <std::convertible_to<const Child&> Self, detail::sized_sentinel_of<Self> S>
280  friend constexpr auto operator<=>(const Self& self, const S& right) noexcept
281  {
282  auto dist = self - right;
283  auto rel = dist <=> 0;
284  return rel;
285  }
286  };
287 } // namespace caramel
288 
289 namespace std
290 {
291  template <std::derived_from<caramel::detail::iterator_facade_base> Derived>
292  struct iterator_traits<Derived>
293  {
294  static const Derived& _const_it;
295 
296  using value_type = caramel::detail::infer_value_type_t<Derived>;
297  using difference_type = caramel::detail::infer_difference_type_t<Derived>;
298  using reference = decltype(*_const_it);
299  using pointer = decltype(_const_it.operator->());
300 
301  // Pick the iterator category based on the interfaces that it provides
302  using iterator_category = std::conditional_t<
303  // Random access?
304  caramel::detail::random_access_iter<Derived>, std::random_access_iterator_tag,
305  // Nope
306  std::conditional_t<
307  // Bidirectional?
308  caramel::detail::bidirectional_iter<Derived>, std::bidirectional_iterator_tag,
309  // Noh
310  std::conditional_t<
311  // Is it single-pass?
312  caramel::detail::single_pass_iter<Derived>,
313  // Than means it is an input iterator
314  std::input_iterator_tag,
315  // Otherwise it is a forward iterator
316  std::forward_iterator_tag>>>;
317 
318  using iterator_concept = iterator_category;
319  };
320 } // namespace std
Definition: iterator_facade.hpp:46
Definition: iterator_facade.hpp:144
Definition: crtp.hpp:7
Definition: iterator_facade.hpp:77
Definition: iterator_facade.hpp:95
Definition: iterator_facade.hpp:64
Definition: iterator_facade.hpp:17