Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them. More...
#include <Iterable.h>
Classes | |
| class | _IRep |
| Implementation detail for iterator implementors. More... | |
| class | _SafeReadRepAccessor |
| class | _SafeReadWriteRepAccessor |
| struct | SequentialEqualsComparer |
| struct | SequentialThreeWayComparer |
Public Types | |
| using | value_type = T |
| value_type is an alias for the type iterated over - like vector<T>::value_type | |
| using | iterator = Iterator< T > |
| using | const_iterator = Iterator< T > |
Public Member Functions | |
| Iterable (const Iterable &) noexcept=default | |
| Iterable are safely copyable (by value). Since Iterable uses COW, this just copies the underlying pointer and increments the reference count. | |
| Iterable (Iterable &&) noexcept=default | |
| Iterable are safely moveable. | |
| template<IIterableOfTo< T > CONTAINER_OF_T> requires (not derived_from<remove_cvref_t<CONTAINER_OF_T>, Iterable<T>> and (copyable<remove_cvref_t<CONTAINER_OF_T>> or same_as<remove_cvref_t<CONTAINER_OF_T>, initializer_list<T>>) ) | |
| Iterable (CONTAINER_OF_T &&from) | |
| Iterable (const initializer_list< T > &from) | |
| nonvirtual | operator bool () const |
| nonvirtual Iterator< T > | MakeIterator () const |
| Create an iterator object which can be used to traverse the 'Iterable'. | |
| nonvirtual size_t | size () const |
| Returns the number of items contained. | |
| nonvirtual bool | empty () const |
| Returns true iff size() == 0. | |
| template<Common::IPotentiallyComparer< T > EQUALS_COMPARER = equal_to<T>> | |
| nonvirtual bool | Contains (ArgByValueType< T > element, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}) const |
| nonvirtual Iterator< T > | begin () const |
| Support for ranged for, and STL syntax in general. | |
| nonvirtual void | Apply (const function< void(ArgByValueType< T > item)> &doToElement) const |
| Run the argument function (or lambda) on each element of the container. | |
| template<predicate< T > THAT_FUNCTION> | |
| nonvirtual Iterator< T > | Find (THAT_FUNCTION &&that) const |
| Run the argument bool-returning function (or lambda) on the elements of the container, and return an iterator pointing at AN element for which it returned true - not necessarily the first (see the note below; use First () if you need the first). | |
| template<IIterableOfFrom< T > CONTAINER_OF_T, typename... CONTAINER_OF_T_CONSTRUCTOR_ARGS> | |
| nonvirtual CONTAINER_OF_T | As (CONTAINER_OF_T_CONSTRUCTOR_ARGS... args) const |
| nonvirtual T | Nth (ptrdiff_t n) const |
| Find the Nth element of the Iterable<> | |
| nonvirtual T | NthValue (ptrdiff_t n, ArgByValueType< T > defaultValue={}) const |
| Find the Nth element of the Iterable<>, but allow for n to be out of range, and just return argument default-value. | |
| template<derived_from< Iterable< T > > RESULT_CONTAINER = Iterable<T>, predicate< T > INCLUDE_PREDICATE> | |
| nonvirtual RESULT_CONTAINER | Where (INCLUDE_PREDICATE &&includeIfTrue) const |
| produce a subset of this iterable where argument function returns true | |
| template<Common::IPotentiallyComparer< T > EQUALS_COMPARER = equal_to<T>> | |
| nonvirtual Iterable< T > | Distinct (EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}) const |
| template<ranges::range RESULT_CONTAINER = Iterable<T>, invocable< T > ELEMENT_MAPPER> requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, typename RESULT_CONTAINER::value_type> or convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>) | |
| nonvirtual RESULT_CONTAINER | Map (ELEMENT_MAPPER &&elementMapper) const |
| functional API which iterates over all members of an Iterable, applies a map function to each element, and collects the results in a new Iterable | |
| template<typename REDUCED_TYPE = T> | |
| nonvirtual optional< REDUCED_TYPE > | Reduce (const function< REDUCED_TYPE(ArgByValueType< T >, ArgByValueType< T >)> &op) const |
| Walk the entire list of items, and use the argument 'op' to combine (reduce) items to a resulting single item. | |
| template<typename REDUCED_TYPE = T> | |
| nonvirtual REDUCED_TYPE | ReduceValue (const function< REDUCED_TYPE(ArgByValueType< T >, ArgByValueType< T >)> &op, ArgByValueType< REDUCED_TYPE > defaultValue={}) const |
| template<typename RESULT_T = Characters::String, invocable< T > CONVERT_TO_RESULT = decltype (kDefaultToStringConverter<>), invocable< RESULT_T, RESULT_T, bool > COMBINER = decltype (Characters::kDefaultStringCombiner)> requires (convertible_to<invoke_result_t<CONVERT_TO_RESULT, T>, RESULT_T> and convertible_to<invoke_result_t<COMBINER, RESULT_T, RESULT_T, bool>, RESULT_T>) | |
| nonvirtual RESULT_T | Join (const CONVERT_TO_RESULT &convertToResult=kDefaultToStringConverter<>, const COMBINER &combiner=Characters::kDefaultStringCombiner) const |
| ape the JavaScript/python 'join' function - take the parts of 'this' iterable and combine them into a new object (typically a string) | |
| nonvirtual Iterable< T > | Skip (size_t nItems) const |
| nonvirtual Iterable< T > | Take (size_t nItems) const |
| nonvirtual Iterable< T > | Slice (size_t from, size_t to) const |
| nonvirtual optional< T > | Top () const |
| return the top/largest value (or the top N values) from this Iterable<T> | |
| template<Common::IPotentiallyComparer< T > INORDER_COMPARER_TYPE = less<T>> | |
| nonvirtual Iterable< T > | OrderBy (INORDER_COMPARER_TYPE &&inorderComparer=INORDER_COMPARER_TYPE{}) const |
| template<Common::IPotentiallyComparer< T > INORDER_COMPARER_TYPE = less<T>> | |
| nonvirtual bool | IsOrderedBy (INORDER_COMPARER_TYPE &&inorderComparer=INORDER_COMPARER_TYPE{}) const |
| nonvirtual optional< T > | First () const |
| return first element in iterable, or if 'that' specified, first where 'that' is true, (or return nullopt if none) | |
| nonvirtual T | FirstValue (ArgByValueType< T > defaultValue={}) const |
| return first element in iterable provided default | |
| nonvirtual optional< T > | Last () const |
| return last element in iterable, or if 'that' specified, last where 'that' is true, (or return missing) | |
| nonvirtual T | LastValue (ArgByValueType< T > defaultValue={}) const |
| nonvirtual bool | All (const function< bool(ArgByValueType< T >)> &testEachElt) const |
| return true iff argument predicate returns true for each element of the iterable | |
| nonvirtual optional< T > | Min () const |
| template<typename RESULT_TYPE = T> | |
| nonvirtual RESULT_TYPE | MinValue (ArgByValueType< RESULT_TYPE > defaultValue={}) const |
| nonvirtual optional< T > | Max () const |
| template<typename RESULT_TYPE = T> | |
| nonvirtual RESULT_TYPE | MaxValue (ArgByValueType< RESULT_TYPE > defaultValue={}) const |
| template<typename RESULT_TYPE = T> | |
| nonvirtual optional< RESULT_TYPE > | Mean () const |
| template<typename RESULT_TYPE = T> | |
| nonvirtual RESULT_TYPE | MeanValue (ArgByValueType< RESULT_TYPE > defaultValue={}) const |
| template<typename RESULT_TYPE = T> | |
| nonvirtual optional< RESULT_TYPE > | Sum () const |
| template<typename RESULT_TYPE = T> | |
| nonvirtual RESULT_TYPE | SumValue (ArgByValueType< RESULT_TYPE > defaultValue={}) const |
| template<constructible_from< T > RESULT_TYPE = T, Common::IPotentiallyComparer< RESULT_TYPE > INORDER_COMPARE_FUNCTION = less<RESULT_TYPE>> | |
| nonvirtual optional< RESULT_TYPE > | Median (const INORDER_COMPARE_FUNCTION &compare={}) const |
| template<constructible_from< T > RESULT_TYPE = T> | |
| nonvirtual RESULT_TYPE | MedianValue (ArgByValueType< RESULT_TYPE > defaultValue={}) const |
| nonvirtual Iterable< T > | Repeat (size_t count) const |
| nonvirtual bool | Any () const |
| Any() same as not empty (); Any (includeIfTrue) returns true iff includeIfTrue returns true on any values in iterable. | |
| nonvirtual size_t | Count () const |
| with no args, same as size, with function filter arg, returns number of items that pass. | |
| nonvirtual size_t | length () const |
| STL-ish alias for size() - really in STL only used in string, I think, but still makes sense as an alias. | |
Static Public Member Functions | |
| template<ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, IEqualsComparer< T > EQUALS_COMPARER = equal_to<T>> | |
| static bool | SetEquals (const LHS_CONTAINER_TYPE &lhs, const RHS_CONTAINER_TYPE &rhs, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}) |
| template<ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, IEqualsComparer< T > EQUALS_COMPARER = equal_to<T>> | |
| static bool | MultiSetEquals (const LHS_CONTAINER_TYPE &lhs, const RHS_CONTAINER_TYPE &rhs, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}) |
| template<ranges::range LHS_CONTAINER_TYPE, ranges::range RHS_CONTAINER_TYPE, IEqualsComparer< T > EQUALS_COMPARER = equal_to<T>> | |
| static bool | SequentialEquals (const LHS_CONTAINER_TYPE &lhs, const RHS_CONTAINER_TYPE &rhs, EQUALS_COMPARER &&equalsComparer=EQUALS_COMPARER{}) |
| static constexpr default_sentinel_t | end () noexcept |
| Support for ranged for, and STL syntax in general. | |
Static Public Attributes | |
| template<same_as< Characters::String > RESULT_T = Characters::String> | |
| static const function< RESULT_T(T)> | kDefaultToStringConverter |
Protected Member Functions | |
| Iterable (const shared_ptr< _IRep > &rep) noexcept | |
| Iterable's are typically constructed as concrete subtype objects, whose CTOR passed in a shared copyable rep. | |
| nonvirtual Memory::SharedByValueSupport::SharingState | _GetSharingState () const |
Protected Attributes | |
| _SharedByValueRepType | _fRep |
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
The Stroika iterables can be used either directly (similar to std::range), or in the STL begin/end style - and this class supports both styles of usage.
Iterable<T> also supports read-only applicative operations on the contained data.
Iterable<T> is much like idea of 'abstract readonly container', but which only supports an exceedingly simplistic pattern of access.
Important Design Note (lifetime of iterators): The Lifetime of Iterator<T> objects created by an Iterable<T> instance must always be less than the creating Iterable's lifetime.
This may not be enforced by implementations (but generally will be in debug builds). But it is a rule!
The reason for this is that the underlying memory referenced by the iterator may be going away. We could avoid this by adding a shared_ptr<> reference count into each iterator, but that would make iterator objects significantly more expensive, and with little apparent value added. Similarly for weak_ptr<> references.
Important Design Note (construct with rep, no setrep): We have no: nonvirtual void _SetRep (IterableRepSharedPtr rep);
because allowing a _SetRep() method would complicate the efforts of subclasses of Iterable<T> to assure that the underlying type is of the appropriate subtype.
For example - see Bag_Array<T>::GetRep_().
Note - instead - you can 'assign' (operator=) to replace the value (and dynamic type) of an Iterable<> (or subclass) instance.
Important Design Note (copy on write/COW): Iterable uses 'SharedByValue', so that subclasses of Iterable (especially containers) CAN implement Copy-On-Write (COW). However, not ALL Iterables implement COW. In fact, not all Iterables are mutable!
Iterable's data can come from arbitrary, programmatic sources (like a sequence of uncomputed random numbers). If you wish to capture something like an Iterable for later use, but don't want its value to change once you've captured it, consider using Collection<T> or Sequence<> which is almost the same, but will make a copy of the data, and not allow it to change without preserve COW semantics.
Design Note: Why does Iterable<T> contain a size () method?
o It’s always well defined what size() means (what you would get if you called
MakeIterable() and iterated a bunch of times til the end).
o Its almost always (and trivial) to perform that computation more efficiently than the
iterate over each element approach.
The gist of these two consideration means that if you need to find the length of
an Iterable<T>, if it was defined as a method, you can access the trivial implementation,
and if it was not defined, you would be forced into the costly implementation.
Adding size () adds no conceptual cost – because its already so well and clearly defined in terms of its basic operation (iteration). And it provides value (maybe just modest value).
Design Note: Order of Iteration.
Iterables<T> provide no promises about the order of iteration. Specific subclasses (like SortedSet<>) often will make specific guarantees about order of iteration.
We do NOT even promise you will see the same items, or seem them in the same order as you iterate (so for example, you can have a "RandomSequence<>" subclass from Iterable<> and return a different sequence of numbers each time you make an iterate and run.
Design Note:
We DO have methods SetEquals/MultiSetEquals/SequentialEquals (see below), as well as SequentialThreeWayComparer<> etc.
Design Note Methods like Min/Max/Median/Sum make little sense on empty Iterables. There were several choices available to deal with this: > Assertion > throw range_error() > return a sensible default value (e.g. 0) for empty lists > overloads to let callers select the desired behavior
Because I wanted these methods to be useful in scenarios like with database queries (inspired by Linq/ORMs) assertions seemed a poor choice.
throw range_error makes sense, but then requires lots of checking when used for throws, and that makes use needlessly complex.
So we eventually decided to use the return optional and have a variant named XXXValue () that returns the plain T with a default - since we use that pattern in so many places.
Design Note - Microsoft Linq: This API implements some of the Microsoft Linq API. https://msdn.microsoft.com/en-us/library/system.linq.enumerable_methods(v=vs.100).aspx
For example, we implement: o Map most important o Reduce important - aka accumulate o Where o Take o Skip o OrderBy o First/Last/FirstValue/LastValue (though semantics and later names differ somewhat from .net FirstOrDefault)
We choose explicitly not to implement o ToList/ToArray, no need because we have As<>, plus no List/Array classes (exactly).
Definition at line 238 of file Iterable.h.
| using Stroika::Foundation::Traversal::Iterable< T >::iterator = Iterator<T> |
For Stroika containers, all iterators are really const_iterators, but this allows for better STL interoperability.
Definition at line 257 of file Iterable.h.
| using Stroika::Foundation::Traversal::Iterable< T >::const_iterator = Iterator<T> |
For better STL interoperability.
Definition at line 263 of file Iterable.h.
|
explicit |
Make a copy of the given argument, and treat it as an iterable.
Definition at line 258 of file Iterable.inl.
| Stroika::Foundation::Traversal::Iterable< T >::Iterable | ( | const initializer_list< T > & | from | ) |
Definition at line 266 of file Iterable.inl.
|
explicitprotectednoexcept |
Iterable's are typically constructed as concrete subtype objects, whose CTOR passed in a shared copyable rep.
|
explicit |
Often handy short-hand (punning) for a container to see if zero elts, then if on it returns false.
Definition at line 271 of file Iterable.inl.
| Iterator< T > Stroika::Foundation::Traversal::Iterable< T >::MakeIterator | ( | ) | const |
Create an iterator object which can be used to traverse the 'Iterable'.
Create an iterator object which can be used to traverse the 'Iterable' - this object - and visit each element.
Definition at line 305 of file Iterable.inl.
| size_t Stroika::Foundation::Traversal::Iterable< T >::size | ( | ) | const |
Returns the number of items contained.
size () returns the number of elements in this 'Iterable' object. Its defined to be the same number of elements you would visit if you created an iterator (MakeIterator()) and visited all items. In practice, as the actual number might vary as the underlying iterable could change while being iterated over.
For example, a filesystem directory iterable could return a different length each time it was called, as files are added and removed from the filesystem.
Also note that size () can return a ridiculous number - like numeric_limits<size_t>::max () - for logically infinite sequences... like a sequence of random numbers.
Performance: The performance of size() may vary wildly. It could be anywhere from O(1) to O(N) depending on the underlying type of Iterable<T>.
Every Stroika CONTAINER does have O(1) size () - both linked lists cache their length, so every DataStructures class does (see Containers/DataStructures/ReadMe.md). The guarantee stops at Iterable<T> because an Iterable need not be a container: it may be a generator, or a lazy pipeline - Where () returns a lazy Iterable<T> - whose count cannot be known without running a predicate over every element, and running it may not even be repeatable (socket, file). That is not an implementation gap; caching cannot cache what was never computed.
Two tempting shapes were rejected: o returning numeric_limits<size_t>::max () for "unknown" - it makes an unknown look like a number, and callers do arithmetic on size (): Median () computes size ()/2, reserve (size ()) throws, size () - 1 wraps, 'i < size ()' becomes an infinite loop. It fails silently and late, and collapses three distinct states (known-and-cheap / knowable-but-expensive / unbounded) into one value. o overloading this virtual (size (SizeQuery)) to avoid adding a second one - there are 41 in-tree overrides of 'size () const override' plus out-of-tree backends, all of which would have to change, to save one vtable slot. Default arguments on virtuals also bind to the STATIC type, which is its own trap.
If it is ever actually wanted, the shape to build is NOT a virtual: "is my size () cheap" is a per-TYPE constant needing no dynamic dispatch, so put a protected bool on Iterable<T>::_IRep (defaulting to false = "I promise nothing"), set it in backends that can guarantee it, and make PeekSize () a non-virtual on Iterable<T> that reads it. That costs zero vtable slots - the objection to a virtual being that its body cannot be stripped by the linker, and _IRep is a template so it multiplies by every T - and touches none of the 41 overriders. Its weakness is an unchecked promise: a backend could lie.
What would justify building it: a real heuristic inside the no-policy overloads, where the "
Definition at line 311 of file Iterable.inl.
| bool Stroika::Foundation::Traversal::Iterable< T >::empty | ( | ) | const |
Returns true iff size() == 0.
Definition at line 317 of file Iterable.inl.
| nonvirtual bool Stroika::Foundation::Traversal::Iterable< T >::Contains | ( | ArgByValueType< T > | element, |
| EQUALS_COMPARER && | equalsComparer = EQUALS_COMPARER{} |
||
| ) | const |
Apply the (template argument) EQUALS_COMPARER to each element in the Iterable<T> and return true iff found. This invokes no virtual methods dependent (except MakeIterable or some such) and so gains no performance benefits from the organization of the underlying Iterable<T>. This is just a short hand for the direct iteration one would trivially code by hand. Still - its easier to call Contains() that to code that loop!
And note - subclasses (like Containers::Set<T>) will hide this implementation with a more efficient one (that does indirect to the backend).
Performance: This algorithm is O(N).
|
static |
SetEquals () - very inefficiently - but with constant small memory overhead - returns true if each element in the each iterable is contained in the other. The lengths may be different and even though the two Iterables<> are SetEquals().
Performance: This algorithm is O(N) * O(M) where N and M are the length of the two respective iterables.
Definition at line 360 of file Iterable.inl.
|
static |
MultiSetEquals () - very inefficiently - but with constant small memory overhead - returns true if each element in the each iterable is contained in the other the same number of times.
Performance: This algorithm is O(N^^3)
Definition at line 401 of file Iterable.inl.
|
static |
SequentialEquals () - measures if iteration over the two containers produces identical sequences of elements (identical by compare with EQUALS_COMPARER). It does not call 'size', but just iterates.
Performance: This algorithm is O(N).
Where BOTH arguments are contiguous runs of T - an Iterable<T> whose backend offers _IRep::PeekContiguousStorage (), or any other contiguous_range of T such as vector<T> or initializer_list<T> - they are compared as spans rather than by advancing two Iterator<T>s, and where EQUALS_COMPARER is the default the comparison degenerates to a memcmp.
Definition at line 436 of file Iterable.inl.
| Iterator< T > Stroika::Foundation::Traversal::Iterable< T >::begin | ( | ) | const |
Support for ranged for, and STL syntax in general.
begin ()/end() are similar to MakeIterator(), except that they allow for iterators to be used in an STL-style, which is critical for using C++ ranged iteration.
OR
Definition at line 1323 of file Iterable.inl.
|
staticconstexprnoexcept |
Support for ranged for, and STL syntax in general.
Definition at line 1328 of file Iterable.inl.
| void Stroika::Foundation::Traversal::Iterable< T >::Apply | ( | const function< void(ArgByValueType< T > item)> & | doToElement | ) | const |
Run the argument function (or lambda) on each element of the container.
Take the given function argument, and call it for each element of the container. This is equivalent to:
for (Iterator<T> i = begin (); i != end (); ++i) {
(doToElement) (*i);
}
However, Apply () MAY perform the entire iteration more quickly (depending on the kind of the container).
Apply () also MAY be much faster than normal iteration (some simple tests
So 'doToElement' must be safe under ANY of them:
o No unsynchronized side effects on shared state - it may run on several threads at once. o No dependence on the ORDER elements are visited in, nor on which thread visits them. o It must NOT throw. Every policy-taking std algorithm calls std::terminate () when an element access function exits via an exception, rather than propagating it - see [algorithms.parallel.exceptions]. The eSeq path uses the plain (policy-free) algorithm, where the exception propagates normally, so this differs by policy. o Under the unsequenced policies (eUnseq / eParUnseq) it must additionally avoid vectorization-unsafe operations - allocation, and taking a lock. Calls may interleave WITHIN a single thread there, so a mutex can deadlock against itself.
If 'doToElement' cannot meet all of that, pass Execution::SequencePolicy::eSeq explicitly. That is not a workaround - it is how you state the sequential semantics are load-bearing, and it keeps working when the unspecified overload starts choosing for itself.
Definition at line 1333 of file Iterable.inl.
| nonvirtual Iterator< T > Stroika::Foundation::Traversal::Iterable< T >::Find | ( | THAT_FUNCTION && | that | ) | const |
Run the argument bool-returning function (or lambda) on the elements of the container, and return an iterator pointing at AN element for which it returned true - not necessarily the first (see the note below; use First () if you need the first).
Take the given function argument, and call it for the elements of the container. A simple implementation - and what the default one does - is:
for (Iterator<T> i = begin (); i != end (); ++i) {
if (that (*i)) {
return it;
}
}
return end();
...but that is an EXAMPLE, not the specification: a backend is free to consult an index, or to search several elements at once, so it may return a different match than the loop above would, and it may call 'that' on elements the loop would have stopped short of.
This function returns an iterator pointing to an element for which 'that' returned true (for example the element you were searching for?). It returns the special iterator end() to indicate no call to 'that' returned true.
Also, note that this function does NOT change any elements of the Iterable.
This is deliberately NOT tied to the SequencePolicy. 'Which match' is a statement about the freedom the algorithm has, not about how it happens to be executing, and keeping the two separate leaves a backend free to answer from a hash bucket, a SIMD scan, or a parallel one without the answer's meaning changing with the policy argument. It also keeps 'seq' meaning what it means in std::<execution>, where the policy never changes WHICH element std::find_if () returns.
Note also that for an UNORDERED Iterable (Set<T>, Mapping<>, Collection<T>) 'first' is a property of the current iteration order rather than of the data, so the guarantee would be close to vacuous there in any case.
The overloads taking 'startAt' below are the exception - 'search onward from here' is inherently ordered, and they keep that meaning.
Note that this used to be called 'ContainsWith' - because it can act the same way (due to operator bool () method of Iterator<T>).
So 'that' (and 'equalsComparer') must be safe under ANY of them:
o No unsynchronized side effects on shared state - it may run on several threads at once. Note this is the requirement people most often miss on Find (), because a predicate that records what it saw looks harmless. o No dependence on the ORDER elements are visited in, on which thread visits them, or on HOW MANY times it is called - a parallel search may keep testing elements after another thread has already matched, so it can be called more times than a sequential scan would. o It must NOT throw. Every policy-taking std algorithm calls std::terminate () when an element access function exits via an exception, rather than propagating it - see [algorithms.parallel.exceptions]. o Under the unsequenced policies (eUnseq / eParUnseq) it must additionally avoid vectorization-unsafe operations - allocation, and taking a lock. Calls may interleave WITHIN a single thread there, so a mutex can deadlock against itself.
If your predicate cannot meet all of that, pass Execution::SequencePolicy::eSeq explicitly. That is not a workaround - it is how you state the sequential semantics are load-bearing.
To pass a policy with the DEFAULT comparer, name the comparer: Find (v, equal_to<T>{}, ePar). There is deliberately no Find (v, seq) shorthand - it would read as an overload set where the second argument means two unrelated things.
| nonvirtual CONTAINER_OF_T Stroika::Foundation::Traversal::Iterable< T >::As | ( | CONTAINER_OF_T_CONSTRUCTOR_ARGS... | args | ) | const |
As<CONTAINER_OF_T> () can be used to easily map an iterable to another container (for example STL container) which supports begin/end iterator constructor. This is really just a shorthand for CONTAINER_OF_T{this->begin (), this->end ()};
Note - this also works with (nearly all) of the Stroika containers as well (e.g. Set<T> x; x.As<Sequence<T>> ());
Design Note: We chose NOT to include an overload taking iterators because there was no connection between 'this' and the used iterators, so you may as well just directly call CONTAINER_OF_T{it1, it2}.
| T Stroika::Foundation::Traversal::Iterable< T >::Nth | ( | ptrdiff_t | n | ) | const |
Find the Nth element of the Iterable<>
if n < 0, treated as from the end, so actual index = size () + n
Definition at line 1471 of file Iterable.inl.
| T Stroika::Foundation::Traversal::Iterable< T >::NthValue | ( | ptrdiff_t | n, |
| ArgByValueType< T > | defaultValue = {} |
||
| ) | const |
Find the Nth element of the Iterable<>, but allow for n to be out of range, and just return argument default-value.
Definition at line 1487 of file Iterable.inl.
| nonvirtual RESULT_CONTAINER Stroika::Foundation::Traversal::Iterable< T >::Where | ( | INCLUDE_PREDICATE && | includeIfTrue | ) | const |
produce a subset of this iterable where argument function returns true
BASED ON Microsoft .net Linq.
This returns either an Iterable<T>, or a concrete container (provided template argument). If returning just an Iterable<T>, then the result is lazy evaluated. If a concrete container is provided, its fully constructed when Where returns.
| nonvirtual Iterable< T > Stroika::Foundation::Traversal::Iterable< T >::Distinct | ( | EQUALS_COMPARER && | equalsComparer = EQUALS_COMPARER{} | ) | const |
BASED ON Microsoft .net Linq.
This returns an Iterable<T> that contains just the subset of the items which are distinct (equality comparer)
| nonvirtual RESULT_CONTAINER Stroika::Foundation::Traversal::Iterable< T >::Map | ( | ELEMENT_MAPPER && | elementMapper | ) | const |
functional API which iterates over all members of an Iterable, applies a map function to each element, and collects the results in a new Iterable
This is like the map() function in so many other languages, like lisp, JavaScript, etc, not like the STL::map class.
The transformation may be a projection, or complete transformation. If the 'extract' function returns optional<RESULT_COLLECTION::value_type>, then a missing value is treated as removal from the source list (in the resulting generated list).
The overloads returning RESULT_CONTAINER DO however immediately construct RESULT_CONTAINER, and fill it in the the result of traversal before Map () returns.
This can also easily be used to TRANSFORM an iterable.
Overload which returns optional<RESULT> and nullopt interpreted as skipping that element
| nonvirtual optional< REDUCED_TYPE > Stroika::Foundation::Traversal::Iterable< T >::Reduce | ( | const function< REDUCED_TYPE(ArgByValueType< T >, ArgByValueType< T >)> & | op | ) | const |
Walk the entire list of items, and use the argument 'op' to combine (reduce) items to a resulting single item.
See:
| nonvirtual REDUCED_TYPE Stroika::Foundation::Traversal::Iterable< T >::ReduceValue | ( | const function< REDUCED_TYPE(ArgByValueType< T >, ArgByValueType< T >)> & | op, |
| ArgByValueType< REDUCED_TYPE > | defaultValue = {} |
||
| ) | const |
| nonvirtual RESULT_T Stroika::Foundation::Traversal::Iterable< T >::Join | ( | const CONVERT_TO_RESULT & | convertToResult = kDefaultToStringConverter<>, |
| const COMBINER & | combiner = Characters::kDefaultStringCombiner |
||
| ) | const |
ape the JavaScript/python 'join' function - take the parts of 'this' iterable and combine them into a new object (typically a string)
This Join () API - if you use the template, is fairly generic and lets the caller iterate over subelements of this iterable, and combine them into a new thing (
For the very common case of accumulating objects into a String, there are additional (stringish) overloads that more closely mimic what you can do in JavaScript/python.
Gist of arguments o convertToResult: - OPTIONAL converter from T to String o combiner: - OPTIONAL thing that joins two RESULT_T (result of above covertToResult - typically String) and combiner MAYBE replaced with String (separator and optionally finalStringSeparator)
See:
| Iterable< T > Stroika::Foundation::Traversal::Iterable< T >::Skip | ( | size_t | nItems | ) | const |
BASED ON Microsoft .net Linq.
This returns an Iterable<T> with a subset of data after skipping the argument number of items. If the number of items skipped is greater or equal to the length of the original Iterable, then an empty Iterable is returned.
Definition at line 776 of file Iterable.inl.
| Iterable< T > Stroika::Foundation::Traversal::Iterable< T >::Take | ( | size_t | nItems | ) | const |
BASED ON Microsoft .net Linq.
This returns an Iterable<T> with up to nItems taken from the front of this starting iterable. If this Iterable is shorter, Take () returns just the original Iterable
Definition at line 799 of file Iterable.inl.
| Iterable< T > Stroika::Foundation::Traversal::Iterable< T >::Slice | ( | size_t | from, |
| size_t | to | ||
| ) | const |
This returns an Iterable<T> based on the current iterable, with the subset from position from to to. If some items don't exist, the resulting list is shortened (not an assertion error). Item at from is included in the output, but item 'to' is not included.
Definition at line 822 of file Iterable.inl.
| optional< T > Stroika::Foundation::Traversal::Iterable< T >::Top | ( | ) | const |
return the top/largest value (or the top N values) from this Iterable<T>
The overloads WITHOUT an 'n' argument return the single top element, as an optional<T> which is nullopt iff the Iterable is empty. The overloads WITH an 'n' return the top n, as an Iterable<T> (n is allowed to exceed size (), in which case you just get everything, ordered).
Provide a function object that says how you want to compare the 'T' elements; 'top' means the element that would come FIRST in that order. It defaults to std::greater<T>, so by default 'top' is the largest.
Performance: let S = this->size(); o no 'n' argument: O(S) o with 'n': O(S) * ln (N) ; so S*log(S) if you get all of them, but if you just need the top three, its O(S)
Definition at line 898 of file Iterable.inl.
| nonvirtual Iterable< T > Stroika::Foundation::Traversal::Iterable< T >::OrderBy | ( | INORDER_COMPARER_TYPE && | inorderComparer = INORDER_COMPARER_TYPE{} | ) | const |
BASED ON Microsoft .net Linq.
So when you use that overload, your comparer must be fit to run under ANY of them:
o PURE - callable concurrently, with no side effects on shared state, and no dependence on how many times, in what order, or on which thread it is called. A sort calls the comparer an unspecified number of times even sequentially; parallel just makes that more visible. o NON-THROWING. This one is easy to miss, and it is not implied by purity: eSeq sorts via the plain stable_sort (), where an exception from your comparer propagates normally, but every parallel policy goes through a policy-taking std algorithm, and there an exception escaping an element access function calls std::terminate () - see [algorithms.parallel.exceptions]. A pure comparer can still throw (bad_alloc comparing Strings, say). Nothing warns you; the process just dies. o Under the unsequenced policies (eUnseq / eParUnseq), additionally free of vectorization-unsafe operations - allocation, and taking a lock. Calls may interleave WITHIN a single thread there, so a mutex can deadlock against itself.
If your comparer cannot meet all of that, pass Execution::SequencePolicy::eSeq explicitly. That is not a workaround - it is how you say the sequential semantics are load-bearing, and it keeps working when the unspecified overload starts choosing for itself.
See:
| nonvirtual bool Stroika::Foundation::Traversal::Iterable< T >::IsOrderedBy | ( | INORDER_COMPARER_TYPE && | inorderComparer = INORDER_COMPARER_TYPE{} | ) | const |
| optional< T > Stroika::Foundation::Traversal::Iterable< T >::First | ( | ) | const |
return first element in iterable, or if 'that' specified, first where 'that' is true, (or return nullopt if none)
Definition at line 996 of file Iterable.inl.
| T Stroika::Foundation::Traversal::Iterable< T >::FirstValue | ( | ArgByValueType< T > | defaultValue = {} | ) | const |
return first element in iterable provided default
Definition at line 1043 of file Iterable.inl.
| optional< T > Stroika::Foundation::Traversal::Iterable< T >::Last | ( | ) | const |
return last element in iterable, or if 'that' specified, last where 'that' is true, (or return missing)
Definition at line 1055 of file Iterable.inl.
| T Stroika::Foundation::Traversal::Iterable< T >::LastValue | ( | ArgByValueType< T > | defaultValue = {} | ) | const |
BASED ON Microsoft .net Linq. (LastOrDefault)
See:
Definition at line 1095 of file Iterable.inl.
| bool Stroika::Foundation::Traversal::Iterable< T >::All | ( | const function< bool(ArgByValueType< T >)> & | testEachElt | ) | const |
return true iff argument predicate returns true for each element of the iterable
Definition at line 1107 of file Iterable.inl.
| optional< T > Stroika::Foundation::Traversal::Iterable< T >::Min | ( | ) | const |
BASED ON Microsoft .net Linq.
See: https://msdn.microsoft.com/en-us/library/bb503062%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396 @Max
Definition at line 1143 of file Iterable.inl.
| nonvirtual RESULT_TYPE Stroika::Foundation::Traversal::Iterable< T >::MinValue | ( | ArgByValueType< RESULT_TYPE > | defaultValue = {} | ) | const |
| optional< T > Stroika::Foundation::Traversal::Iterable< T >::Max | ( | ) | const |
BASED ON Microsoft .net Linq.
EXAMPLE:
See: https://msdn.microsoft.com/en-us/library/bb503062%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396 @Min
Definition at line 1167 of file Iterable.inl.
| nonvirtual RESULT_TYPE Stroika::Foundation::Traversal::Iterable< T >::MaxValue | ( | ArgByValueType< RESULT_TYPE > | defaultValue = {} | ) | const |
| nonvirtual optional< RESULT_TYPE > Stroika::Foundation::Traversal::Iterable< T >::Mean | ( | ) | const |
BASED ON Microsoft .net Linq.
AKA "Average"
See: https://msdn.microsoft.com/en-us/library/bb548647(v=vs.100).aspx
| nonvirtual RESULT_TYPE Stroika::Foundation::Traversal::Iterable< T >::MeanValue | ( | ArgByValueType< RESULT_TYPE > | defaultValue = {} | ) | const |
| nonvirtual optional< RESULT_TYPE > Stroika::Foundation::Traversal::Iterable< T >::Sum | ( | ) | const |
BASED ON Microsoft .net Linq.
See: https://msdn.microsoft.com/en-us/library/system.linq.enumerable.sum(v=vs.110).aspx
| nonvirtual RESULT_TYPE Stroika::Foundation::Traversal::Iterable< T >::SumValue | ( | ArgByValueType< RESULT_TYPE > | defaultValue = {} | ) | const |
| nonvirtual optional< RESULT_TYPE > Stroika::Foundation::Traversal::Iterable< T >::Median | ( | const INORDER_COMPARE_FUNCTION & | compare = {} | ) | const |
| nonvirtual RESULT_TYPE Stroika::Foundation::Traversal::Iterable< T >::MedianValue | ( | ArgByValueType< RESULT_TYPE > | defaultValue = {} | ) | const |
| Iterable< T > Stroika::Foundation::Traversal::Iterable< T >::Repeat | ( | size_t | count | ) | const |
Return this iterable n (count) times. count may be zero, or any other unsigned integer. Repeat (0) returns an empty list, and Repeat (1) returns *this;
Similar to https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.repeat?view=netcore-3.1
Definition at line 1263 of file Iterable.inl.
| bool Stroika::Foundation::Traversal::Iterable< T >::Any | ( | ) | const |
Any() same as not empty (); Any (includeIfTrue) returns true iff includeIfTrue returns true on any values in iterable.
Definition at line 1292 of file Iterable.inl.
| size_t Stroika::Foundation::Traversal::Iterable< T >::Count | ( | ) | const |
with no args, same as size, with function filter arg, returns number of items that pass.
Definition at line 1302 of file Iterable.inl.
|
protected |
Don't call this lightly. This is just meant for low level or debugging, and for subclass optimizations based on the state of the shared common object.
Definition at line 300 of file Iterable.inl.
|
static |
kDefaultToStringConverter encapsulates the algorithm used to map T objects to printable strings. As this is mainly used for debugging, it defaults to using Characters::ToString() - and so maybe lossy.
For plain Strings - however, it just uses Common::Identity (no mapping). So that when used in Join - you get no changes to the argument strings (by default - easy to pass in lambda todo what you want to Join).
Definition at line 1011 of file Iterable.h.
|
protected |
Rarely access in subclasses, but its occasionally needed, like in UpdatableIterator<T>
Definition at line 1609 of file Iterable.h.