OpenKalman
iterator.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2025 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
17 #ifndef OPENKALMAN_COMPATIBILITY_ITERATOR_HPP
18 #define OPENKALMAN_COMPATIBILITY_ITERATOR_HPP
19 
20 #include <iterator>
21 #include "language-features.hpp"
22 #include "core-concepts.hpp"
23 #include "object-concepts.hpp"
24 #include "internal/exposition.hpp"
25 #include "common.hpp"
26 
27 namespace OpenKalman::stdex
28 {
29 #ifdef __cpp_lib_ranges
30  using std::indirectly_readable_traits;
31  using std::incrementable_traits;
32  using std::contiguous_iterator_tag;
33  using std::iterator_traits;
34  using std::iter_value_t;
35  using std::iter_reference_t;
36  using std::iter_difference_t;
37  using std::iter_rvalue_reference_t;
38  using std::indirectly_readable;
39  using std::iter_common_reference_t;
40 #if __cplusplus >= 202302L
41  using std::iter_const_reference_t;
42 #endif
43  using std::indirectly_writable;
44  using std::weakly_incrementable;
45  using std::input_or_output_iterator;
46  using std::input_iterator;
47  using std::output_iterator;
48  using std::incrementable;
49  using std::forward_iterator;
50  using std::bidirectional_iterator;
51  using std::random_access_iterator;
52  using std::sentinel_for;
53  using std::sized_sentinel_for;
54  using std::unreachable_sentinel_t;
55  using std::unreachable_sentinel;
56 
57  using std::indirectly_copyable;
58 #else
59 
60  // ---
61  // indirectly_readable_traits
62  // ---
63 
64  namespace detail_indirectly_readable
65  {
66  struct no_value_type {};
67 
68  template<typename, typename = void>
69  struct cond_value_type {};
70 
71  template<typename T>
72  struct cond_value_type<T, std::enable_if_t<std::is_object_v<T>>> { using value_type = std::remove_cv_t<T>; };
73 
74  template<typename, typename = void>
75  struct has_member_value_type_impl : std::false_type {};
76 
77  template<typename T>
78  struct has_member_value_type_impl<T, std::void_t<typename T::value_type>> : std::true_type {};
79 
80  template<typename T>
81  inline constexpr bool has_member_value_type = has_member_value_type_impl<T>::value;
82 
83  template<typename, typename = void>
84  struct has_member_element_type_impl : std::false_type {};
85 
86  template<typename T>
87  struct has_member_element_type_impl<T, std::void_t<typename T::element_type>> : std::true_type {};
88 
89  template<typename T>
90  inline constexpr bool has_member_element_type = has_member_element_type_impl<T>::value;
91  }
92 
93 
94  template<typename I, typename = void>
96 
97  template<typename T>
99 
100  template<typename I>
101  struct indirectly_readable_traits<I, std::enable_if_t<std::is_array_v<I>>>
102  { using value_type = std::remove_cv_t<std::remove_extent_t<I>>; };
103 
104  template<typename T>
106 
107  template<typename T>
108  struct indirectly_readable_traits<T, std::enable_if_t<
109  detail_indirectly_readable::has_member_value_type<T> and
110  not detail_indirectly_readable::has_member_element_type<T>>>
111  : detail_indirectly_readable::cond_value_type<typename T::value_type> {};
112 
113  template<typename T>
114  struct indirectly_readable_traits<T, std::enable_if_t<
115  not detail_indirectly_readable::has_member_value_type<T> and
116  detail_indirectly_readable::has_member_element_type<T>>>
117  : detail_indirectly_readable::cond_value_type<typename T::element_type> {};
118 
119  template<typename T>
120  struct indirectly_readable_traits<T, std::enable_if_t<
121  detail_indirectly_readable::has_member_value_type<T> and
122  detail_indirectly_readable::has_member_element_type<T>>>
123  : std::conditional_t<
124  std::is_same_v<std::remove_cv_t<typename T::element_type>, std::remove_cv_t<typename T::value_type>>,
125  detail_indirectly_readable::cond_value_type<typename T::value_type>,
126  detail_indirectly_readable::no_value_type> {};
127 
128 
129  // ---
130  // incrementable_traits
131  // ---
132 
133  namespace detail
134  {
135  template<typename, typename = void>
136  struct has_member_difference_type : std::false_type {};
137 
138  template<typename T>
139  struct has_member_difference_type<T, std::void_t<typename T::difference_type>> : std::true_type {};
140  }
141 
142 
143  template<typename I, typename = void>
145 
146  template<typename T>
147  struct incrementable_traits<T, std::enable_if_t<std::is_pointer_v<T> and std::is_object_v<std::remove_pointer_t<T>>>>
148  {
149  using difference_type = std::ptrdiff_t;
150  };
151 
152  template<typename T>
154 
155  template<typename T>
156  struct incrementable_traits<T, std::enable_if_t<not std::is_pointer_v<T> and detail::has_member_difference_type<T>::value>>
157  {
158  using difference_type = typename T::difference_type;
159  };
160 
161  template<typename T>
162  struct incrementable_traits<T, std::enable_if_t<not std::is_pointer_v<T> and not detail::has_member_difference_type<T>::value and
163  std::is_integral_v<decltype(std::declval<const T&>() - std::declval<const T&>())>>>
164  {
165  using difference_type = std::make_signed_t<decltype(std::declval<T>() - std::declval<T>())>;
166  };
167 
168 
169  struct contiguous_iterator_tag;
170 
171  // ---
172  // iterator_traits
173  // ---
174 
175  namespace detail
176  {
177  template<typename T, typename = void>
178  struct iterator_traits_defined : std::false_type {};
179 
180  template<typename It>
181  struct iterator_traits_defined<It, std::void_t<
182  typename It::iterator_category,
183  typename It::value_type,
184  typename It::difference_type,
185  typename It::reference>>
186  : std::true_type {};
187 
188 
189  template<typename T, typename = void>
190  struct iterator_traits_pointer_defined : std::false_type {};
191 
192  template<typename It>
193  struct iterator_traits_pointer_defined<It, std::void_t<typename It::pointer>>
194  : std::true_type {};
195 
196 
197  template<typename T, typename = void>
198  struct iterator_traits_reference_defined : std::false_type {};
199 
200  template<typename It>
201  struct iterator_traits_reference_defined<It, std::void_t<typename It::reference>>
202  : std::true_type {};
203 
204 
205  template<typename T, typename = void>
206  struct iterator_traits_arrow_valid : std::false_type {};
207 
208  template<typename It>
209  struct iterator_traits_arrow_valid<It, std::void_t<decltype(std::declval<It&>().operator->())>>
210  : std::true_type {};
211 
212 
213  template<typename T, typename = void, typename = void>
214  struct legacy_iterator : std::false_type {};
215 
216  template<typename T>
217  struct legacy_iterator<T,
218  std::enable_if_t<
219  stdex::copyable<T> and
220  stdex::same_as<decltype(++std::declval<T>()), T&>>,
221  std::void_t<
222  decltype(*std::declval<T>())&,
223  decltype(*std::declval<T>()++)&>>
224  : std::true_type {};
225 
226 
227  template<typename T, typename = void, typename = void>
228  struct legacy_input_iterator : std::false_type {};
229 
230  template<typename T>
232  std::enable_if_t<stdex::signed_integral<typename stdex::incrementable_traits<T>::difference_type>>,
233  std::void_t<
234  typename stdex::incrementable_traits<T>::difference_type,
235  typename stdex::indirectly_readable_traits<T>::value_type,
236  typename stdex::common_reference<decltype(*std::declval<T&>())&&, typename stdex::indirectly_readable_traits<T>::value_type&>::type,
237  decltype(*std::declval<T>()++),
238  typename stdex::common_reference<decltype(*std::declval<T>()++)&&, typename stdex::indirectly_readable_traits<T>::value_type&>::type>>
239  : std::true_type {};
240 
241 
242  template<typename T, typename = void>
244 
245  template<typename T>
247  std::void_t<typename stdex::incrementable_traits<T>::difference_type>>
248  {
250  };
251  }
252 
253 
254  template<typename Iter, typename = void>
255  struct iterator_traits {};
256 
257  template<typename It>
258  struct iterator_traits<It, std::enable_if_t<detail::iterator_traits_defined<It>::value>>
259  {
260  using difference_type = typename It::difference_type;
261  using value_type = typename It::value_type;
262  using pointer = std::conditional_t<detail::iterator_traits_pointer_defined<It>::value, typename It::pointer, void>;
263  using reference = typename It::reference;
264  using iterator_category = typename It::iterator_category;
265  };
266 
267  template<typename Iter>
268  struct iterator_traits<Iter, std::enable_if_t<
269  not detail::iterator_traits_defined<Iter>::value and
270  not detail::legacy_iterator<Iter>::value and
271  detail::legacy_input_iterator<Iter>::value>>
273  {
274  using difference_type = typename stdex::incrementable_traits<Iter>::difference_type;
275  using value_type = typename stdex::indirectly_readable_traits<Iter>::value_type;
276  using pointer = std::conditional_t<
278  typename Iter::pointer,
279  std::conditional_t<
281  decltype(std::declval<Iter&>().operator->()),
282  void>>;
283  using reference = std::conditional_t<
285  typename Iter::reference,
286  decltype(*std::declval<Iter&>())>;
287  using iterator_category = std::random_access_iterator_tag; // \todo This is incorrect
288  };
289 
290  template<typename Iter>
291  struct iterator_traits<Iter, std::enable_if_t<
292  not detail::iterator_traits_defined<Iter>::value and
293  detail::legacy_iterator<Iter>::value and
294  not detail::legacy_input_iterator<Iter>::value>>
296  {
297  using value_type = void;
298  using pointer = void;
299  using reference = void;
300  using iterator_category = std::output_iterator_tag;
301  using iterator_concept = stdex::contiguous_iterator_tag;
302  };
303 
304  template<typename T>
305  struct iterator_traits<T*>
306  {
307  using difference_type = std::ptrdiff_t;
308  using value_type = std::remove_cv_t<T>;
309  using pointer = T*;
310  using reference = T&;
311  using iterator_category = std::random_access_iterator_tag;
312  using iterator_concept = stdex::contiguous_iterator_tag;
313  };
314 
315 
316  // ---
317  // primitives
318  // ---
319 
320  namespace detail
321  {
322  template<typename T, typename = void>
324 
325  template<typename T>
326  struct iter_value_impl<T, std::void_t<typename stdex::iterator_traits<T>::value_type>> : stdex::iterator_traits<T> {};
327 
328 
329  template<typename T, typename = void>
331 
332  template<typename T>
333  struct iter_difference_impl<T, std::void_t<typename stdex::iterator_traits<T>::difference_type>> : stdex::iterator_traits<T> {};
334  }
335 
336 
337  template<typename I>
338  using iter_value_t = typename detail::iter_value_impl<stdex::remove_cvref_t<I>>::value_type;
339 
340  template<typename I>
341  using iter_reference_t = decltype(*std::declval<I&>());
342 
343  template<typename I>
344  using iter_difference_t = typename detail::iter_difference_impl<stdex::remove_cvref_t<I>>::difference_type;
345 
346  template<typename I>
347  using iter_rvalue_reference_t = decltype(std::move(*std::declval<I&>()));
348 
349 
350  // ---
351  // indirectly_readable
352  // ---
353 
354  namespace detail
355  {
356  template<typename I, typename = void, typename = void>
357  struct is_indirectly_readable : std::false_type {};
358 
359  template<typename I>
361  std::void_t<iter_value_t<I>, iter_reference_t<I>, iter_rvalue_reference_t<I>>,
362  std::enable_if_t<std::is_same<decltype(*std::declval<I>()), iter_reference_t<I>>::value>> : std::true_type {};
363  }
364 
365 
366  template<typename I>
367  inline constexpr bool indirectly_readable = detail::is_indirectly_readable<stdex::remove_cvref_t<I>>::value;
368 
369 
370  template<typename T, std::enable_if_t<indirectly_readable<T>, int > = 0>
371  using iter_common_reference_t = stdex::common_reference_t<iter_reference_t<T>, iter_value_t<T>&>;
372 
373 #endif
374 
375 
376 #if __cplusplus < 202302L
377  template<typename T, std::enable_if_t<indirectly_readable<T>, int > = 0>
378  using iter_const_reference_t = stdex::common_reference_t<const iter_value_t<T>&&, iter_reference_t<T>>;
379 #endif
380 
381 
382 #ifndef __cpp_lib_ranges
383  // ---
384  // indirectly_writable
385  // ---
386 
387  namespace detail
388  {
389  template<typename Out, typename T, typename = void>
390  struct is_indirectly_writable : std::false_type {};
391 
392  template<typename Out, typename T>
393  struct is_indirectly_writable<Out, T,
394  std::void_t<
395  decltype(*std::declval<Out&>() = std::declval<T&&>()),
396  decltype(*std::declval<Out&&>() = std::declval<T&&>()),
397  decltype(const_cast<const iter_reference_t<Out>&&>(*std::declval<Out&>()) = std::declval<T&&>()),
398  decltype(const_cast<const iter_reference_t<Out>&&>(*std::declval<Out&&>()) = std::declval<T&&>())
399  >> : std::true_type {};
400  }
401 
402 
403  template<typename Out, typename T>
404  inline constexpr bool indirectly_writable = detail::is_indirectly_writable<Out, T>::value;
405 
406 
407  // ---
408  // weakly_incrementable
409  // ---
410 
411  namespace detail
412  {
413  template<typename I, typename = void, typename = void>
414  struct is_weakly_incrementable : std::false_type {};
415 
416  template<typename I>
417  struct is_weakly_incrementable<I, std::void_t<iter_difference_t<I>, decltype(std::declval<I&>()++)>,
418  std::enable_if_t<std::is_same<decltype(++std::declval<I&>()), I&>::value>> : std::true_type {};
419  }
420 
421 
422  template<typename I>
423  inline constexpr bool weakly_incrementable = detail::is_weakly_incrementable<I>::value;
424 
425 
426  // ---
427  // input_or_output_iterator
428  // ---
429 
430  namespace detail
431  {
432  template<typename I, typename = void, typename = void>
433  struct is_input_or_output_iterator : std::false_type {};
434 
435  template<typename I>
437  std::void_t<iter_value_t<I>, iter_reference_t<I>, iter_rvalue_reference_t<I>>,
438  std::enable_if_t<std::is_same<decltype(*std::declval<I>()), iter_reference_t<I>>::value>> : std::true_type {};
439  }
440 
441 
442  template<typename I>
443  inline constexpr bool input_or_output_iterator = detail::is_input_or_output_iterator<I>::value and weakly_incrementable<I>;
444 
445 
446  // ---
447  // input_iterator
448  // ---
449 
450  template<typename I>
451  inline constexpr bool input_iterator =
452  input_or_output_iterator<I> and
453  indirectly_readable<I>;
454 
455 
456  // ---
457  // output_iterator
458  // ---
459 
460  namespace detail
461  {
462  template<typename I, typename T, typename = void>
463  struct output_iterator_impl : std::false_type {};
464 
465  template<typename I, typename T>
466  struct output_iterator_impl<I, T, std::void_t<decltype(*std::declval<I&>()++ = std::declval<T&&>())>> : std::true_type {};
467  }
468 
469 
470  template<typename I, typename T>
471  inline constexpr bool output_iterator =
472  input_or_output_iterator<I> and
473  indirectly_writable<I, T> and
475 
476 
477  // ---
478  // incrementable
479  // ---
480 
481  namespace detail
482  {
483  template<typename I, typename = void>
484  struct is_incrementable : std::false_type {};
485 
486  template<typename I>
487  struct is_incrementable<I, std::enable_if_t<std::is_same<decltype(std::declval<I&>()++), I>::value>> : std::true_type {};
488  }
489 
490 
491  template<typename I>
492  inline constexpr bool incrementable =
493  stdex::copy_constructible<I> and
494  std::is_object_v<I> and
495  std::is_move_constructible_v<I> and
496  std::is_assignable_v<I&, I> and
497  std::is_assignable_v<I&, I&> and
498  std::is_assignable_v<I&, const I&> and
499  std::is_assignable_v<I&, const I> and
500  default_initializable<I> and
501  weakly_incrementable<I> and
503 
504 
505  // ---
506  // forward_iterator
507  // ---
508 
509  template<typename I>
510  inline constexpr bool forward_iterator =
511  input_iterator<I> and
512  incrementable<I>;
513 
514 
515  // ---
516  // bidirectional_iterator
517  // ---
518 
519  namespace detail
520  {
521  template<typename I, typename = void>
522  struct is_bidirectional_iterator : std::false_type {};
523 
524  template<typename I>
525  struct is_bidirectional_iterator<I, std::enable_if_t<
526  stdex::same_as<decltype(--std::declval<I&>()), I&> and
527  stdex::same_as<decltype(std::declval<I&>()--), I>>> : std::true_type {};
528  }
529 
530 
531  template<typename I>
532  inline constexpr bool bidirectional_iterator =
533  forward_iterator<I> and
535 
536 
537  // ---
538  // sentinel_for, sized_sentinel_for
539  // ---
540 
541  namespace detail
542  {
543  template<typename T, typename U, typename = void>
544  struct subtractable : std::false_type {};
545 
546  template<typename I, typename S>
547  struct subtractable<I, S, std::enable_if_t<
548  stdex::same_as<decltype(std::declval<const S&>() - std::declval<const I&>()), iter_difference_t<I>> and
549  stdex::same_as<decltype(std::declval<const I&>() - std::declval<const S&>()), iter_difference_t<I>>
550  >> : std::true_type {};
551 
552  }
553 
554 
555  template<typename S, typename I>
556  inline constexpr bool sentinel_for =
557  stdex::semiregular<S> and input_or_output_iterator<I> and OpenKalman::internal::WeaklyEqualityComparableWith<S, I>;
558 
559 
560  template<typename S, typename I>
561  inline constexpr bool sized_sentinel_for = sentinel_for<S, I> and
562  /*not std::disable_sized_sentinel_for<std::remove_cv_t<S>, std::remove_cv_t<I>> and */
564 
565 
566  // ---
567  // random_access_iterator
568  // ---
569 
570  namespace detail
571  {
572  template<typename I, typename = void>
573  struct is_random_access_iterator : std::false_type {};
574 
575  template<typename I>
576  struct is_random_access_iterator<I, std::enable_if_t<
577  stdex::same_as<decltype(std::declval<I&>() += std::declval<iter_difference_t<I>>()), I&> and
578  stdex::same_as<decltype(std::declval<const I&>() + std::declval<iter_difference_t<I>>()), I> and
579  stdex::same_as<decltype(std::declval<iter_difference_t<I>>() + std::declval<const I&>()), I> and
580  stdex::same_as<decltype(std::declval<I&>() -= std::declval<iter_difference_t<I>>()), I&> and
581  stdex::same_as<decltype(std::declval<const I&>() - std::declval<iter_difference_t<I>>()), I> and
582  stdex::same_as<decltype(std::declval<const I&>()[std::declval<iter_difference_t<I>>()]), iter_reference_t<I>>
583  >> : std::true_type {};
584  }
585 
586 
587  template<typename I>
588  inline constexpr bool random_access_iterator =
589  bidirectional_iterator<I> and
590  stdex::totally_ordered<I> and
591  stdex::sized_sentinel_for<I, I> and
593 
594 
595  // ---
596  // unreachable_sentinel_t, unreachable_sentinel
597  // ---
598 
600  {
601  template<typename I, std::enable_if_t<weakly_incrementable<I>, int> = 0>
602  friend constexpr bool
603  operator==(unreachable_sentinel_t, unreachable_sentinel_t) noexcept { return false; };
604 
605  template<typename I, std::enable_if_t<weakly_incrementable<I>, int> = 0>
606  friend constexpr bool
607  operator==(unreachable_sentinel_t, const I&) noexcept { return false; };
608 
609  template<typename I, std::enable_if_t<weakly_incrementable<I>, int> = 0>
610  friend constexpr bool
611  operator==(const I&, unreachable_sentinel_t) noexcept { return false; };
612 
613  template<typename I, std::enable_if_t<weakly_incrementable<I>, int> = 0>
614  friend constexpr bool
615  operator!=(unreachable_sentinel_t, unreachable_sentinel_t) noexcept { return true; };
616 
617  template<typename I, std::enable_if_t<weakly_incrementable<I>, int> = 0>
618  friend constexpr bool
619  operator!=(unreachable_sentinel_t, const I&) noexcept { return true; };
620 
621  template<typename I, std::enable_if_t<weakly_incrementable<I>, int> = 0>
622  friend constexpr bool
623  operator!=(const I&, unreachable_sentinel_t) noexcept { return true; };
624 
625  };
626 
627 
628  inline constexpr unreachable_sentinel_t unreachable_sentinel {};
629 
630 
631  // ---
632  // indirectly_copyable
633  // ---
634 
635  template<typename In, typename Out>
636  inline constexpr bool indirectly_copyable =
637  indirectly_readable<In> and
638  indirectly_writable<Out, iter_reference_t<In>>;
639 
640 #endif
641 
642 }
643 
644 
645 #endif
Definition: iterator.hpp:255
Definition: iterator.hpp:544
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
Definitions relating to standard c++ library concepts.
Definition: iterator.hpp:144
Exposition-only definitions from teh c++ language standard.
Definitions relating to the availability of c++ language features.
Definition: iterator.hpp:214
Definition: iterator.hpp:599
Definitions relating to standard c++ library concepts.
Definition: iterator.hpp:323
Definition: basics.hpp:55