#include "Stroika/Foundation/StroikaPreComp.h"
#include <compare>
#include <iterator>
#include <memory>
#include <optional>
#include <string>
#include "Stroika/Foundation/Common/Common.h"
#include "Stroika/Foundation/Memory/SharedByValue.h"
#include "Iterator.inl"
Go to the source code of this file.
Classes | |
struct | Stroika::Foundation::Traversal::DefaultIteratorTraits< CATEGORY, T, DIFF, POINTER, REFERENCE > |
class | Stroika::Foundation::Traversal::Iterator< T, ITERATOR_TRAITS > |
An Iterator<T> is a copyable object which allows traversing the contents of some container. It is like an std::const_iterator. More... | |
class | Stroika::Foundation::Traversal::Iterator< T, ITERATOR_TRAITS >::IRep |
Implementation detail for iterator implementors. More... | |
Namespaces | |
namespace | Stroika::Foundation |
Concepts | |
concept | Stroika::Foundation::Traversal::IInputIterator |
Functions | |
template<typename ITERATOR > | |
constexpr iterator_traits< ITERATOR >::pointer | Stroika::Foundation::Traversal::Iterator2Pointer (ITERATOR i) |
More clear way of writing '&*' - convert iterator to pointer. | |
TODO
THIS IS BAD AND MUST BE REWRITEN - NOT WAHT WE WANT - TOO STRONG A PROMISE.
The Major Design limitation of this approach to iterators is that it requires a non-inlinable function call per iteration (roughly). Basically - if you pass a callback into an iterator rep then to APPLY that function on each iteration requires a non-inlinable (indirect through pointer) function call, or if you do the reverse, and directly use the iterator so no you can inline apply the function, you must call a virtual function for each iteration to bump the next pointer. Fundamentally - you have multiple polymorphism (on representation of container and thing to apply at each iteration). Two tricks: (1) Paging. Read a bunch at a time. This is tricky to implement and doesn't affect overall computational complexity (because it reduces number of virtual calls by a constant factor). But if that constant factor is big enough - 10-100-1000? - that still could be relevant pragmatically. The biggest challenge is preserving the existing safety and patch semantics generically, in light of update during iteration, and making sure for uses where that doesn't help its not allowed to hurt. (2) special case common combinations. For example - at the point in the code where you have: Iterator<T> i; for (; i != e.end (); ++i) { do_this(); } One could put in special purpose code for the Iterator<T>::operator++ that said: if (dynamic_cast<Sequence_Array::_IRep*> (myIRep) != nullptr) { then peek and cheat... } Maybe when the iterator is constructed - it checks for a couple important types and sets a flag, so the only cost when this doesn't work is checking that bool flag. And the benefit in the more common case is you avoid the virtual function call! so the it++ can be inlined (a big win often times).
Definition in file Iterator.h.
|
constexpr |
More clear way of writing '&*' - convert iterator to pointer.
Sometimes (especially when interacting with low level code) its handy to convert an iterator to a pointer. This is always legal for a short period (
But the idiom is somewhat queer, and wrapping in this method makes it a bit more clear.
Definition at line 258 of file Iterator.inl.