Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Iterator.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Traversal_Iterator_h_
5#define _Stroika_Foundation_Traversal_Iterator_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <compare>
10#include <iterator>
11#include <memory>
12#include <optional>
13#include <string>
14
15#include "Stroika/Foundation/Common/Common.h"
17
18/**
19 *
20 * \file
21 *
22 * TODO
23 * @todo http://stroika-bugs.sophists.com/browse/STK-446 - AssertExternallySynchronizedMutex
24 *
25 * @todo Consider if we want to make the promise currently defined below in Equals()
26 * about iterating two originally equal iterators. The trouble is - this doesn
27 * work with generators!!! -- REVIEW-- LGP 2013-12-30
28 *
29 * THIS IS BAD AND MUST BE REWRITEN - NOT WAHT WE WANT - TOO STRONG A PROMISE.
30 *
31 * @todo Speed tweaks
32 *
33 * The Major Design limitation of this approach to iterators is that it requires a non-inlinable
34 * function call per iteration (roughly). Basically - if you pass a callback into an iterator rep
35 * then to APPLY that function on each iteration requires a non-inlinable (indirect through pointer)
36 * function call, or if you do the reverse, and directly use the iterator so no you can inline
37 * apply the function, you must call a virtual function for each iteration to bump the next pointer.
38 *
39 * Fundamentally - you have multiple polymorphism (on representation of container and thing to apply
40 * at each iteration).
41 *
42 * Two tricks:
43 * (1) Paging.
44 * Read a bunch at a time. This is tricky to implement and doesn't affect overall computational
45 * complexity (because it reduces number of virtual calls by a constant factor). But if that
46 * constant factor is big enough - 10-100-1000? - that still could be relevant pragmatically.
47 *
48 * The biggest challenge is preserving the existing safety and patch semantics generically,
49 * in light of update during iteration, and making sure for uses where that doesn't help its
50 * not allowed to hurt.
51 *
52 * (2) special case common combinations. For example - at the point in the code where you have:
53 * Iterator<T> i;
54 * for (; i != e.end (); ++i) {
55 * do_this();
56 * }
57 *
58 * One could put in special purpose code for the Iterator<T>::operator++ that said:
59 * if (dynamic_cast<Sequence_Array::_IRep*> (myIRep) != nullptr) {
60 * then peek and cheat...
61 * }
62 * Maybe when the iterator is constructed - it checks for a couple important types
63 * and sets a flag, so the only cost when this doesn't work is checking that bool flag.
64 * And the benefit in the more common case is you avoid the virtual function call! so the it++ can be
65 * inlined (a big win often times).
66 *
67 */
68
69namespace Stroika::Foundation::Traversal {
70
71 /**
72 * Identical type to std::iterator<> - but duplicated here because std::iterator<> was deprecated in C++17.
73 * We just need a handy way to capture all the defaults/properties for our iterator class.
74 */
75 template <typename CATEGORY, typename T, typename DIFF = ptrdiff_t, typename POINTER = const T*, typename REFERENCE = const T&>
77 using iterator_category = CATEGORY;
78 using value_type = T;
79 using difference_type = DIFF;
80 using pointer = POINTER;
81 using reference = REFERENCE;
82 };
83
84 /**
85 * \brief
86 * An Iterator<T> is a copyable object which allows traversing the contents of some container. It is like an std::const_iterator.
87 *
88 * \@todo EXPLAIN HOW THIS IS CONNECTED TO c++20 'range' and probably make this work with ranges!!!
89 *
90 * An Iterator<T> is typically associated with some container (that is being iterated over)
91 * and which allows traversal from start to finish.
92 * (The iterator itself essentially provides a notion of *start* to *finish*).
93 *
94 * There need not actually be a 'container' object. Other 'iterators' can be created, so long as
95 * they act like an iterator.
96 *
97 * An Iterator<T> is a copyable object which can safely be used to capture (copy) the state of
98 * iteration and continue iterating from that spot.
99 *
100 * An Iterator<T> be be thought of as (const) referencing a container (or other information source)
101 *
102 * It is (since Stroika 2.1b14) illegal to use an iterator after its underlying container
103 * has been modified (rule as in STL, but unlike most STLs, Stroika will automatically detect such
104 * illegal use in debug builds).
105 *
106 * Iterators CAN be used to MODIFY a container, but not directly - only by passing that iterator as an
107 * argument to a container method (such as Remove). Here the iterator cannot actually update the container
108 * but acts as an marker/indicator of what element to update. Such APIs will optionally return an updated iterator,
109 * so that you can continue with iteration (if desired).
110 *
111 * \note PRIOR to Stroika 2.1b14 it was true that
112 *
113 * "If the underlying container is modified, the iterator will be automatically
114 * updated to logically account for that update. Iterators are robust in the presence
115 * of changes to their underlying container. Adding or removing items from a container
116 * will not invalidate the iteration."
117 *
118 * "Different kinds of containers can make further guarantees about the behavior of iterators
119 * in the presence of container modifications. For example a SequenceIterator will always
120 * traverse any items added after the current traversal index, and will never traverse items
121 * added with an index before the current traversal index.
122 *
123 * But this is NO LONGER TRUE.
124 *
125 * \par Example Usage
126 * \code
127 * for (Iterator<T> i = container.MakeIterator (); not i.Done (); i.Next ()) {
128 * f (i.Current ());
129 * }
130 * \endcode
131 *
132 * or:
133 * \code
134 * for (Iterator<T> i = container.begin (); i; ++i) {
135 * f (*i);
136 * }
137 * \endcode
138 *
139 * or:
140 * \code
141 * for (Iterator<T> i = container.begin (); i != container.end (); ++i) {
142 * f (*i);
143 * }
144 * \endcode
145 *
146 * or:
147 * \code
148 * for (T i : container) {
149 * f (i);
150 * }
151 * \endcode
152 *
153 * Key Differences between Stroika Iterators and STL Iterators:
154 *
155 * 1. Stroika iterators (in debug builds) will detect if they are used after
156 * the underlying container has changed (some STL's may do this too?)
157 *
158 * 2. Stroika iterators carry around their 'done' state all in one object.
159 * For compatibility with existing C++ idiom, and some C++11 language features
160 * Stroika iterators inherit from std::iterator<> and allow use of end(),
161 * and i != end() to check for if an iterator is done. But internally,
162 * Stroika just checks i.Done(), and so can users of Stroika iterators.
163 *
164 * 3. Stroika iterators are not 'random access'. They just go forwards, one step at a
165 * time. In STL, some kinds of iterators act more like pointers where you can do
166 * address arithmetic.
167 * <<<< RETHINK - WE WANT BIDIITERATOR/ETC>>>>
168 *
169 * 4. In STL, reverse iterators are a special type, incompatible with regular iterators.
170 * In Stroika, reverse iterators are also created with rbegin(), rend (), but
171 * their type is no different than regular iterators.
172 * <<<< NYI >>>>
173 *
174 * Some Rules about Iterators:
175 *
176 * 1. Iterators can be copied. They always refer to the same
177 * place they did before the copy, and the old iterator is unaffected
178 * by iteration in the new iterator.
179 *
180 * Interesting Design (Implementation) Notes:
181 *
182 * - We considered a design for Current() - where it would dynamically
183 * grab the current value, as opposed to being defined to be frozen/copied
184 * at the time of iteration.
185 *
186 * The advantage of the path not taken is that if you iterated several times without
187 * examining the current value, and if the cost of copying was relatively large, this
188 * definition would have worked out better.
189 *
190 * However, because I think its far more frequent that the copies are cheap, the
191 * user will want to look at each value, and the cost in terms of thread locking
192 * and probably virtual function calls, the current approach of freezing / copying
193 * on iteration seemed better.
194 *
195 * \note Design Note
196 * Until Stroika 2.1d6, Iterator<> used CopyOnWrite (COW) - SharedByValue, instead of unique_ptr.
197 *
198 * SharedByValue costs a bit more when the iterators are never copied. But saves a lot of cost when iterators
199 * are copied (cuz with unique_ptr they need to actually be cloned).
200 *
201 * I DID run some simple tests to see how often we even use the Clone method. It turns out - quite rarely.
202 * And most can be eliminated by slightly better Move constructor support on the iterator class.
203 *
204 * \note Satisfies Concepts:
205 * o static_assert (regular<Iterator<T>>);
206 * o static_assert (input_iterator<Iterator<T>>);
207 * o static_assert (sentinel_for<default_sentinel_t, Iterator<T>>);
208 *
209 * @see Iterable<T>
210 *
211 * \note \em Thread-Safety
212 *
213 * Iterator<T> instances are \em not thread-safe. That is - they cannot be read and
214 * or written from multiple threads at a time.
215 *
216 * However, given how Iterators are meant to be, and are typically, used, this presents
217 * no problem.
218 *
219 * They can be safely transferred across threads, and the underlying things being iterated over
220 * can be safely and transparently read/written from other threads
221 *
222 * <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
223 */
224 template <typename T, typename ITERATOR_TRAITS = DefaultIteratorTraits<forward_iterator_tag, T>>
225 class Iterator {
226 public:
227 static_assert (constructible_from<optional<T>, T>,
228 "Must be able to create optional<T> to use Iterator, because Iterator uses this internally");
229 static_assert (copyable<T>); // cannot use as type constraint on T cuz fails?? ill understood - probably complex usages with incomplete types..
230
231 public:
232 /**
233 * \brief difference_type = typename ITERATOR_TRAITS::difference_type;
234 */
235 using difference_type = typename ITERATOR_TRAITS::difference_type;
236
237 public:
238 /**
239 * \brief value_type = typename ITERATOR_TRAITS::value_type;
240 */
241 using value_type = typename ITERATOR_TRAITS::value_type;
242
243 public:
244 /**
245 * \brief pointer = typename ITERATOR_TRAITS::pointer;
246 */
247 using pointer = typename ITERATOR_TRAITS::pointer;
248
249 public:
250 /**
251 * \brief reference = typename ITERATOR_TRAITS::reference;
252 */
253 using reference = typename ITERATOR_TRAITS::reference;
254
255 public:
256 /**
257 * \brief iterator_category = typename ITERATOR_TRAITS::iterator_category;
258 */
259 using iterator_category = typename ITERATOR_TRAITS::iterator_category;
260
261 public:
262 class IRep;
263
264 public:
265 /**
266 */
267 using RepSmartPtr [[deprecated ("Since Stroika v3.0d1 - just use unique_ptr<IRep> directly")]] = unique_ptr<IRep>;
268
269 private:
270 /*
271 * Mostly internal type to select a constructor for the special END iterator.
272 */
273 enum class ConstructionFlagForceAtEnd_ {
274 ForceAtEnd
275 };
276
277 public:
278 /**
279 * \brief
280 * This overload is usually not called directly. Instead, iterators are
281 * usually created from a container (eg. Bag<T>::begin()).
282 *
283 * Iterators are safely copyable, preserving their current position.
284 *
285 * CTOR overload taking nullptr - is the same as GetEmptyIterator ()
286 *
287 * \note since copy constructor calls Clone_, these can throw exceptions but move copies/assignments are no-except
288 *
289 * \note for ranges to work, the return type of Iterable<T>::end () must be a 'sentinel_for' compatible concept
290 * which implies it must be default constructible. So interpret default construction of Iterator as meaning empty/end sentinel.
291 *
292 * \pre RequireNotNull (rep.get ())
293 */
294 Iterator (const unique_ptr<IRep>& rep) noexcept;
295 Iterator (unique_ptr<IRep>&& rep) noexcept;
296 Iterator (Iterator&& src) noexcept;
297 Iterator (const Iterator& src);
298 constexpr Iterator (const default_sentinel_t&) noexcept;
299 constexpr Iterator (nullptr_t) noexcept;
300 constexpr Iterator () noexcept;
301
302 private:
303 constexpr Iterator (ConstructionFlagForceAtEnd_) noexcept;
304
305 public:
306 /**
307 * \brief Iterators are safely copyable, preserving their current position. Copy-Assigning could throw since it probably involves a Clone()
308 */
309 nonvirtual Iterator& operator= (Iterator&& rhs) noexcept;
310 nonvirtual Iterator& operator= (const Iterator& rhs);
311
312 public:
313 /**
314 * \brief
315 * Return the Current value pointed to by the Iterator<T> (same as Current())
316 *
317 * Support for range-based-for, and STL style iteration in general (containers must also
318 * support begin, end).
319 *
320 * This function is a synonym for @ref Current();
321 *
322 * \note Until Stroika 2.1r1, this returned T, and was switched to return const T& on the theory that it might
323 * perform better, but testing has not confirmed that (though this does appear to be existing practice in things like STL).
324 *
325 * \note It is illegal (but goes undetected) to hang onto (and use) the reference returned past when the iterator is next modified
326 *
327 * \note use of for (auto& c : Iterable<>) won't work with Stroika Iterator<> classes since operator* returns const reference only
328 * as we don't allow updating containers by fiddling with the iterator only.
329 */
330 nonvirtual const T& operator* () const;
331
332 public:
333 /**
334 * \brief
335 * Return a pointer to the current value pointed to by the Iterator<T> (like Current())
336 *
337 * This function allows you to write i->b, where i is an iterator and b is a member of the type
338 * iterated over by i.
339 *
340 * Note - the lifetime of this pointer is short - only until the next operation on the wrapper
341 * class instance Iterator<T>.
342 */
343 nonvirtual const value_type* operator->() const;
344
345 public:
346 /**
347 * \brief
348 * preincrement
349 *
350 * Advance iterator; support for range-based-for, and STL style iteration in
351 * general (containers must also support begin, end).
352 *
353 * Advance iterator; support for range-based-for, and STL style iteration in general
354 * (containers must also support begin, end).
355 *
356 * operator++ can be called anytime as long as Done () is not true (must be called
357 * prior to operator++). It then it iterates to the item in the container (i.e. it
358 * changes the value returned by Current).
359 *
360 * Note - the value return by Current() is frozen (until the next operator++() call)
361 * when this method is called. Its legal to update the underlying container, but those
362 * values won't be seen until the next iteration.
363 *
364 * \note As of Stroika v3.0d1, we again support post-increment (operator++ (int)), NOT because its useful, but because its required by std+c++
365 * to be considered an input iterator (see https://en.cppreference.com/w/cpp/iterator/weakly_incrementable).
366 *
367 * It is slower, and not recommended. BUT because of this - supported.
368 */
369 nonvirtual Iterator& operator++ ();
370 nonvirtual Iterator operator++ (int);
371
372 public:
373 /*
374 * \pre operator++ can be called 'i' times (on a copy of this), and the result returned.
375 *
376 * \note don't use unsigned 'i' because that works less well with overloads and ambiguity.
377 * \note similar to std::advance, but allows for simpler usage (i + n)
378 */
379 nonvirtual Iterator operator+ (int i) const;
380
381 public:
382 /*
383 * \brief return not Done ()
384 *
385 * \em Design Note:
386 * I HATE type punning - which this is. And I may want to lose this.
387 *
388 * However, this API works beautifully with Iterable<>::Find - and perhaps other things that
389 * return iterators.
390 *
391 * also, it allows
392 * Iterator<T> n = ...;
393 * while (n) {
394 * }
395 * not sure that's better than while (not n.Done ())???
396 */
397 nonvirtual explicit operator bool () const;
398
399 public:
400 /**
401 * \brief Equals () checks if two iterators are equal to one another (point to the same position in the sequence).
402 *
403 * \em NB: Equals () is the same notion of equality as used by STL iterators.
404 *
405 * \em NB: It is \pre required that the two iterators being compared must come from the same source, or from the special source nullptr.
406 *
407 * Very roughly, the idea is that to be 'equal' - two iterators must be iterating over the same source,
408 * and be up to the same position. The slight exception to this is that any two iterators that are Done()
409 * are considered Equals (). This is mainly because we use a different representation for 'done'
410 * iterators.
411 *
412 * @TODO - NOTE - SEE TODO ABOUT ABOUT THIS GUARANTEE??? - NO - TOO STRONG - REVISE!!!
413 *
414 * Note - for Equals. The following assertion will succeed:
415 *
416 * Iterator<T> x = getIterator();
417 * Iterator<T> y = x;
418 * x++;
419 * y++;
420 * Assert (Equals (x, y)); // assume x and y not already 'at end' then...
421 * // will always succeed (x++ and y++ )
422 *
423 * However,
424 * Iterator<T> x = getIterator();
425 * Iterator<T> y = x;
426 * x++;
427 * modify_underlying_container()
428 * y++;
429 * if (Equals (x, y)) {
430 * may or may not be so
431 * }
432 *
433 * Note that Equals is *commutative*.
434 */
435 nonvirtual bool operator== (const Iterator& rhs) const;
436 nonvirtual bool operator== (const default_sentinel_t& rhs) const;
437
438 public:
439 /**
440 * \brief
441 * Returns the value of the current item visited by the Iterator<T>, and is illegal to call if Done()
442 *
443 * Current() returns the value of the current item visited by the Iterator<T>.
444 *
445 * Only one things can change the current value of Current():
446 * o any non-const method of the iterator
447 *
448 * Two subsequent calls to *it *cannot* return different values with no
449 * intervening (non-const) calls on the iterator.
450 *
451 * The value of returned is undefined (Assertion error) if called when Done().
452 *
453 * operator*() is a common synonym for Current().
454 *
455 * @see operator*()
456 * @see operator++()
457 *
458 * \note Until Stroika 2.1r1, this returned T, and was switched to return const T& on the theory that it might
459 * perform better, but testing has not confirmed that (though this does appear to be existing practice in things like STL).
460 *
461 * \note It is illegal (but goes undetected) to hang onto (and use) the reference returned past when the iterator is next modified
462 */
463 nonvirtual const T& Current () const;
464
465 public:
466 /**
467 * \brief
468 * Done () means there is nothing left in this iterator (a synonym for (it == container.end ()).
469 *
470 * Done () means there is nothing left to visit in this iterator.
471 *
472 * Once an iterator is Done(), it can never transition to 'not Done()'.
473 *
474 * When an iterator is Done(), it is illegal to call Current().
475 *
476 * Calling Done() *may* change (initialize) the value which would be returned by the next
477 * call to Current().
478 *
479 * NB: There are *no* modifications to an underlying container which will directly change
480 * the value of Done(). This value only changes the next time the cursor is advanced
481 * via a call to operator++();
482 *
483 * if it comes from container, then (it == container.end ()) is true iff it.Done()
484 */
485 nonvirtual bool Done () const;
486
487 public:
488 /**
489 * \brief
490 * Set to done and disassociate with owner.
491 *
492 * Equivalent to *this = GetEmptyIterator();
493 *
494 * @aliases clear ()
495 */
496 nonvirtual void reset ();
497
498 public:
499 /**
500 * \brief
501 * Set to done and disassociate with owner.
502 *
503 * Equivalent to *this = GetEmptyIterator();
504 *
505 * @aliases reset ()
506 */
507 nonvirtual void clear ();
508
509 public:
510 /**
511 * \brief
512 * Used by *someContainer*::end ()
513 *
514 * GetEmptyIterator () returns a special iterator which is always empty - always 'at the end'.
515 * This is handy in implementing STL-style 'if (a != b)' style iterator comparisons.
516 *
517 * \note this is something like the c++20 ranges sentinel idea, except that we don't use a separate type (perhaps a mistake on my part).
518 */
519 static constexpr default_sentinel_t GetEmptyIterator () noexcept;
520
521 public:
522 /**
523 * \brief
524 * Get a reference to the IRep owned by the iterator. This is an implementation detail,
525 * mainly intended for implementors.
526 *
527 * Get a reference to the IRep owned by the iterator.
528 * This is an implementation detail, mainly intended for implementors.
529 */
530 nonvirtual IRep& GetRep ();
531
532 public:
533 /**
534 * \brief
535 * Get a reference to the IRep owned by the iterator. This is an implementation detail,
536 * mainly intended for implementors.
537 *
538 * Get a reference to the IRep owned by the iterator.
539 * This is an implementation detail, mainly intended for implementors.
540 */
541 nonvirtual const IRep& ConstGetRep () const;
542
543 public:
544 /*
545 * \brief Refresh the current iterator state based on what is in the underlying IRep
546 *
547 * Useful when you change the rep directly. This should VERY RARELY be needed - just in implementing iterator patching (say during a remove).
548 */
549 nonvirtual void Refresh ();
550
551 public:
552 /**
553 * \brief, does nothing if !qStroika_Foundation_Debug_AssertionsChecked, but if qStroika_Foundation_Debug_AssertionsChecked, checks internal state and asserts in good shape
554 */
555 nonvirtual void Invariant () const noexcept;
556
557 private:
558 unique_ptr<IRep> fRep_;
559 optional<T> fCurrentValue_;
560
561 private:
562 static unique_ptr<IRep> Clone_ (const IRep& rep);
563
564 public:
565 template <typename SHARED_T>
566 using PtrImplementationTemplate [[deprecated ("Since Stroika v3.0d1 - use unique_ptr directly")]] = unique_ptr<SHARED_T>;
567 template <typename SHARED_T, typename... ARGS_TYPE>
568 [[deprecated ("Since Stroika v3.0d1 - make_unique directly")]] static unique_ptr<SHARED_T> MakeSmartPtr (ARGS_TYPE&&... args)
569 {
570 return make_unique<SHARED_T> (forward<ARGS_TYPE> (args)...);
571 }
572 };
573
574 /**
575 *
576 * \brief Implementation detail for iterator implementors.
577 *
578 * IRep is a support class used to implement the @ref Iterator<T> pattern.
579 *
580 * \note IRep subclasses are constructed already pointing at the first element.
581 * So a leading call to More (&value, false); can be used to fetch the first value
582 * and value.has_value() will be false if there were no values
583 *
584 * Subclassed by concrete container writers.
585 *
586 * \note Design Note:
587 * o More (optional<T>*, bool advance) API combines operator++ and iterator != end ()
588 * o The reason it combines the two, is because they TYPICALLY are done together at the same time,
589 * and its a virtual call, so combining the two into a single call will most frequently be a
590 * performance optimization.
591 *
592 * typical uses:
593 *
594 * it++ -> More (&ignoredValue, true)
595 * *it -> More (&v, false); return *v;
596 * Done -> More (&v, false); return v.has_value();
597 */
598 template <typename T, typename ITERATOR_TRAITS>
599 class Iterator<T, ITERATOR_TRAITS>::IRep {
600 protected:
601 IRep () = default;
602
603 public:
604 virtual ~IRep () = default;
605
606 public:
607 using RepSmartPtr [[deprecated ("Since Stroika v3.0d1 - use unique_ptr<IRep> directly")]] = unique_ptr<IRep>;
608
609 public:
610 /**
611 * Clone() makes a copy of the state of this iterator, which can separately be tracked with Equals ()
612 * and/or More() to get values and move forward through the iteration.
613 */
614 virtual unique_ptr<IRep> Clone () const = 0;
615 /**
616 * More () takes two required arguments - one an optional<T>* result, and the other a flag about whether or
617 * not to advance.
618 *
619 * If advance is true, it moves the iterator to the next legal position
620 *
621 * \note (requires not Done() before advancing) - NEW Since Stroika 2.1b14
622 *
623 * BEFORE 2.1b14: It WAS legal to call More () with advance true even when already at the end of iteration.
624 * This design choice was made to be multi-threading friendly.
625 *
626 * This function returns the current value in result if the iterator is positioned at a valid position,
627 * and sets result to an nullopt if at the end - its 'at end'.
628 *
629 * \pre result != nullptr
630 *
631 * \em Design Note
632 * We chose to use a pointer parameter instead of a return value to avoid extra
633 * initialization/copying. Note that the return value optimization rule doesn't apply
634 * to assignment, but only initialization.
635 *
636 */
637 virtual void More (optional<T>* result, bool advance) = 0;
638 /**
639 * \brief two iterators must be iterating over the same source, and be up to the same position.
640 *
641 * \pre rhs != nullptr
642 *
643 * \pre this and rhs must be of the same dynamic type, and come from the same iterable object
644 *
645 * @see Iterator<T>::Equals for details
646 */
647 virtual bool Equals (const IRep* rhs) const = 0;
648#if qStroika_Foundation_Debug_AssertionsChecked
649 /**
650 */
651 virtual void Invariant () const noexcept;
652#endif
653 };
654
655 /**
656 * \brief More clear way of writing '&*' - convert iterator to pointer.
657 *
658 * Sometimes (especially when interacting with low level code) its handy to convert an iterator
659 * to a pointer. This is always legal for a short period (@todo reference to docs/why).
660 *
661 * But the idiom is somewhat queer, and wrapping in this method makes it a bit more clear.
662 *
663 * \note This returns a const pointer for a const_iterator, and a pointer for a regular (non-cost) iterator.
664 */
665 template <typename ITERATOR>
666 constexpr typename iterator_traits<ITERATOR>::pointer Iterator2Pointer (ITERATOR i);
667
668 /**
669 * IInputIterator concept: std::input_iterator and iterated over values convertible to OF_T
670 *
671 * \note this does not require the input iterator is OF T objects, merely that the T objects it iterates over
672 * can be converted to OF_T objects.
673 */
674 template <typename ITERATOR, typename OF_T>
675 concept IInputIterator = input_iterator<ITERATOR> and is_convertible_v<std::iter_value_t<ITERATOR>, OF_T>;
676 static_assert (IInputIterator<Iterator<int>, int>);
677 static_assert (IInputIterator<Iterator<long int>, int>);
678 static_assert (IInputIterator<Iterator<int>, long int>);
679 static_assert (not IInputIterator<Iterator<string>, int>);
680
681 // see Satisfies Concepts
682 // @todo would be nice to include these tests generically as part of template declaration, but cannot figure out how
683 // to get that working (probably due to when incomplete types evaluated) --LGP 2024-08-21
684 static_assert (input_iterator<Iterator<int>>);
685 static_assert (regular<Iterator<int>>);
686 static_assert (sentinel_for<default_sentinel_t, Iterator<int>>);
687
688}
689
690/*
691 ********************************************************************************
692 ******************************* Implementation Details *************************
693 ********************************************************************************
694 */
695
696#include "Iterator.inl"
697
698#endif /*_Stroika_Foundation_Traversal_Iterator_h_ */
constexpr iterator_traits< ITERATOR >::pointer Iterator2Pointer(ITERATOR i)
More clear way of writing '&*' - convert iterator to pointer.
Definition Iterator.inl:258
Implementation detail for iterator implementors.
Definition Iterator.h:599
virtual bool Equals(const IRep *rhs) const =0
two iterators must be iterating over the same source, and be up to the same position.
virtual void More(optional< T > *result, bool advance)=0
virtual unique_ptr< IRep > Clone() const =0
An Iterator<T> is a copyable object which allows traversing the contents of some container....
Definition Iterator.h:225
nonvirtual void reset()
Set to done and disassociate with owner.
Definition Iterator.inl:153
typename ITERATOR_TRAITS::iterator_category iterator_category
iterator_category = typename ITERATOR_TRAITS::iterator_category;
Definition Iterator.h:259
nonvirtual IRep & GetRep()
Get a reference to the IRep owned by the iterator. This is an implementation detail,...
Definition Iterator.inl:112
nonvirtual const IRep & ConstGetRep() const
Get a reference to the IRep owned by the iterator. This is an implementation detail,...
Definition Iterator.inl:118
typename ITERATOR_TRAITS::difference_type difference_type
difference_type = typename ITERATOR_TRAITS::difference_type;
Definition Iterator.h:235
typename ITERATOR_TRAITS::pointer pointer
pointer = typename ITERATOR_TRAITS::pointer;
Definition Iterator.h:247
nonvirtual void clear()
Set to done and disassociate with owner.
Definition Iterator.inl:158
typename ITERATOR_TRAITS::value_type value_type
value_type = typename ITERATOR_TRAITS::value_type;
Definition Iterator.h:241
nonvirtual void Invariant() const noexcept
, does nothing if !qStroika_Foundation_Debug_AssertionsChecked, but if qStroika_Foundation_Debug_Asse...
Definition Iterator.inl:130
nonvirtual const T & Current() const
Returns the value of the current item visited by the Iterator<T>, and is illegal to call if Done()
Definition Iterator.inl:139
typename ITERATOR_TRAITS::reference reference
reference = typename ITERATOR_TRAITS::reference;
Definition Iterator.h:253
static constexpr default_sentinel_t GetEmptyIterator() noexcept
Used by someContainer::end ()
Definition Iterator.inl:247
nonvirtual bool Done() const
Done () means there is nothing left in this iterator (a synonym for (it == container....
Definition Iterator.inl:147