Set<T> is a container of T, where once an item is added, additionally adds () do nothing. More...
#include <Set.h>
Classes | |
class | _IRep |
Implementation detail for Set<T> implementors. More... | |
struct | EqualsComparer |
Compare Set<>s or Iterable<>s for equality. More... | |
Public Types | |
using | ArchetypeContainerType = Set |
using | value_type = typename inherited::value_type |
using | const_iterator = typename inherited::const_iterator |
using | ElementEqualityComparerType = Common::ComparisonRelationDeclaration< Common::ComparisonRelationType::eEquals, function< bool(T, T)> > |
![]() | |
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 | |
Set () | |
nonvirtual ElementEqualityComparerType | GetElementEqualsComparer () const |
nonvirtual bool | contains (ArgByValueType< value_type > item) const |
nonvirtual bool | ContainsAll (const Iterable< value_type > &items) const |
nonvirtual bool | ContainsAny (const Iterable< value_type > &items) const |
nonvirtual bool | IsSubsetOf (const Set &superset) const |
nonvirtual optional< value_type > | Lookup (ArgByValueType< value_type > item) const |
nonvirtual void | Add (ArgByValueType< value_type > item) |
nonvirtual bool | AddIf (ArgByValueType< value_type > item) |
template<IInputIterator< T > ITERATOR_OF_ADDABLE, sentinel_for< remove_cvref_t< ITERATOR_OF_ADDABLE > > ITERATOR_OF_ADDABLE2> | |
nonvirtual void | AddAll (ITERATOR_OF_ADDABLE &&start, ITERATOR_OF_ADDABLE2 &&end) |
nonvirtual void | Remove (ArgByValueType< value_type > item) |
Remove the item (given by value or iterator pointing to it) from the contain. The item MUST exist. | |
nonvirtual bool | RemoveIf (ArgByValueType< value_type > item) |
template<IInputIterator< T > ITERATOR_OF_ADDABLE> | |
nonvirtual size_t | RemoveAll (ITERATOR_OF_ADDABLE &&start, ITERATOR_OF_ADDABLE &&end) |
RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items. | |
template<typename RESULT_CONTAINER = Set<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 |
'override' Iterable<>::Map () function so RESULT_CONTAINER defaults to Set, and improve that case to clone properties from this rep (such is rep type, ordering, etc). | |
template<derived_from< Iterable< T > > RESULT_CONTAINER = Set<T>, predicate< T > INCLUDE_PREDICATE> | |
nonvirtual RESULT_CONTAINER | Where (INCLUDE_PREDICATE &&includeIfTrue) const |
nonvirtual bool | operator== (const Set &rhs) const |
nonvirtual bool | Intersects (const Iterable< value_type > &rhs) const |
return true iff the Intersection () is non-empty | |
nonvirtual Set & | operator+= (ArgByValueType< value_type > item) |
nonvirtual Set & | operator-= (ArgByValueType< value_type > item) |
nonvirtual Set & | operator^= (const Iterable< value_type > &items) |
nonvirtual void | clear () |
nonvirtual Iterator< value_type > | find (ArgByValueType< value_type > item) const |
nonvirtual pair< const_iterator, bool > | insert (ArgByValueType< value_type > item) |
nonvirtual void | erase (ArgByValueType< value_type > item) |
STL-ish alias for Remove (). | |
nonvirtual Set | CloneEmpty () const |
for return Set<T> { s->GetEqualsComparer(); } - except more efficient - clones settings/dynamic subtype but not data for the Set | |
![]() | |
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, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) 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, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const |
Run the argument bool-returning function (or lambda) on each element of the container, and return an iterator pointing at the first element (depending on seq) found true. (or use First() to do same thing but return optional<>) | |
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 Iterable< T > | Top () const |
return the top/largest (possibly just 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{}, Execution::SequencePolicy seq=Execution::SequencePolicy::ePar) 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. | |
Protected Member Functions | |
nonvirtual tuple< _IRep *, Iterator< value_type > > | _GetWritableRepAndPatchAssociatedIterator (const Iterator< value_type > &i) |
Utility to get WRITABLE underlying shared_ptr (replacement for what we normally do - _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ()) but where we also handle the cloning/patching of the associated iterator. | |
![]() | |
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::SharedByValue_State | _GetSharingState () const |
Additional Inherited Members | |
![]() | |
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{}, bool useIterableSize=false) |
static constexpr default_sentinel_t | end () noexcept |
Support for ranged for, and STL syntax in general. | |
![]() | |
template<same_as< Characters::String > RESULT_T = Characters::String> | |
static const function< RESULT_T(T)> | kDefaultToStringConverter |
![]() | |
using | _SharedByValueRepType = Memory::SharedByValue< _IRep, Memory::SharedByValue_Traits< _IRep, shared_ptr< _IRep >, Rep_Cloner_ > > |
Lazy-copying smart pointer mostly used by implementors (can generally be ignored by users). However, protected because manipulation needed in some subclasses (rarely) - like UpdatableIteratable. | |
![]() | |
_SharedByValueRepType | _fRep |
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
The Set class is based on SmallTalk-80, The Language & Its Implementation, page 148. The basic idea here is that you cannot have multiple copies of the same thing into the set (like a mathematical set).
vs std::set<T>: Stroika's Set<T> is like std::set<T>, except that o you can separately select different algorithms (besides red-black tree) and not change the API used (Set<T>). o You don't need to have a less<T> method defined. You just need to provide some mechanism (either operator== or argument to constructor) saying how to compare elements for equality o If you have a less<T> already defined, like std::set<T>, this will be used by default to construct a tree-based set. o Sets can also be implemented by hash-tables, etc.
Concrete Implementations: o
Factory:
Design Note: Included <set> and have explicit CTOR for set<> so that Stroika Set can be used more interoperably with set<> - and used without an explicit CTOR. Use Explicit CTOR to avoid accidental conversions. But if you declare an API with Set<T> arguments, its important STL sources passing in set<T> work transparently.
Similarly for std::initializer_list.
o ordering (<,<=> etc) not provided, because a set has no intrinsic ordering between the set elements o when comparing a Set to any Iterable<> - this is treated as 'set' equality comparison
It remains questionable whether or not we should have overloads for comparing Set<> and Iterable<>. When also done with other containers like Sequence, this could produce ambiguity. (like comparing Set with Sequence). But that's probably OK, because when we have ambiguity, we can always explicitly resolve it. So keep these overloads which are pretty convenient.
Definition at line 105 of file Library/Sources/Stroika/Foundation/Containers/Set.h.
using Stroika::Foundation::Containers::Set< T >::ArchetypeContainerType = Set |
Use this typedef in templates to recover the basic functional container pattern of concrete types.
Definition at line 116 of file Library/Sources/Stroika/Foundation/Containers/Set.h.
using Stroika::Foundation::Containers::Set< T >::value_type = typename inherited::value_type |
Definition at line 122 of file Library/Sources/Stroika/Foundation/Containers/Set.h.
using Stroika::Foundation::Containers::Set< T >::const_iterator = typename inherited::const_iterator |
Definition at line 128 of file Library/Sources/Stroika/Foundation/Containers/Set.h.
using Stroika::Foundation::Containers::Set< T >::ElementEqualityComparerType = Common::ComparisonRelationDeclaration<Common::ComparisonRelationType::eEquals, function<bool (T, T)> > |
This is the type returned by GetElementEqualsComparer () and CAN be used as the argument to a Set<> as EqualityComparer, but we allow any template in the Set<> CTOR for an equalityComparer that follows the IEqualsComparer () concept.
Definition at line 137 of file Library/Sources/Stroika/Foundation/Containers/Set.h.
Stroika::Foundation::Containers::Set< T >::Set | ( | ) |
For the CTOR overload with ITERABLE_OF_ADDABLE, its anything that supports c.begin(), c.end () to find all the elements.
All constructors either copy their source comparer (copy/move CTOR), or use the provided argument comparer (which in turn defaults to equal_to<T>).
auto Stroika::Foundation::Containers::Set< T >::GetElementEqualsComparer | ( | ) | const |
Return the function used to compare if two elements are equal
bool Stroika::Foundation::Containers::Set< T >::contains | ( | ArgByValueType< value_type > | item | ) | const |
bool Stroika::Foundation::Containers::Set< T >::ContainsAll | ( | const Iterable< value_type > & | items | ) | const |
bool Stroika::Foundation::Containers::Set< T >::ContainsAny | ( | const Iterable< value_type > & | items | ) | const |
bool Stroika::Foundation::Containers::Set< T >::IsSubsetOf | ( | const Set< T > & | superset | ) | const |
auto Stroika::Foundation::Containers::Set< T >::Lookup | ( | ArgByValueType< value_type > | item | ) | const |
void Stroika::Foundation::Containers::Set< T >::Add | ( | ArgByValueType< value_type > | item | ) |
Add when T is already present has may have no effect (logically has no effect) on the container (not an error or exception).
So for a user-defined type T (or any type where the caller specifies the compare function) it is left undefined whether or not the new (not included) attributes associated with the added item make it into the Set.
If you really want an association list (Mapping) from one thing to another, use that.
If you really want a 'set' where the object has a bunch of extra attributes, but compares 'equal', and you want to preserve those extra attributes, use KeyedCollection<T>.
bool Stroika::Foundation::Containers::Set< T >::AddIf | ( | ArgByValueType< value_type > | item | ) |
Add item if not already present, and return true if added, and false if already present. Note - we chose to return true in the case of addition because this is the case most likely when a caller would want to take action.
nonvirtual void Stroika::Foundation::Containers::Set< T >::AddAll | ( | ITERATOR_OF_ADDABLE && | start, |
ITERATOR_OF_ADDABLE2 && | end | ||
) |
void Stroika::Foundation::Containers::Set< T >::Remove | ( | ArgByValueType< value_type > | item | ) |
Remove the item (given by value or iterator pointing to it) from the contain. The item MUST exist.
nextI | - if provided (not null) - will be filled in with the next value after where iterator i is pointing - since i is invalidated by changing the container) |
bool Stroika::Foundation::Containers::Set< T >::RemoveIf | ( | ArgByValueType< value_type > | item | ) |
RemoveIf item if present. Whether present or not it does the same thing and assures the item is no longer present, but returns true iff the call made a change (removed the item).
Note - we chose to return true in the case of removal because this is the case most likely when a caller would want to take action.
nonvirtual size_t Stroika::Foundation::Containers::Set< T >::RemoveAll | ( | ITERATOR_OF_ADDABLE && | start, |
ITERATOR_OF_ADDABLE && | end | ||
) |
RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items.
The no-arg overload removes all (quickly).
The overloads that remove some subset of the items returns the number of items so removed.
nonvirtual RESULT_CONTAINER Stroika::Foundation::Containers::Set< T >::Where | ( | INCLUDE_PREDICATE && | includeIfTrue | ) | const |
Apply the function function to each element, and return all the ones for which it was true.
bool Stroika::Foundation::Containers::Set< T >::operator== | ( | const Set< T > & | rhs | ) | const |
bool Stroika::Foundation::Containers::Set< T >::Intersects | ( | const Iterable< value_type > & | rhs | ) | const |
Set< T > & Stroika::Foundation::Containers::Set< T >::operator+= | ( | ArgByValueType< value_type > | item | ) |
Set< T > & Stroika::Foundation::Containers::Set< T >::operator-= | ( | ArgByValueType< value_type > | item | ) |
Set< T > & Stroika::Foundation::Containers::Set< T >::operator^= | ( | const Iterable< value_type > & | items | ) |
void Stroika::Foundation::Containers::Set< T >::clear | ( | ) |
auto Stroika::Foundation::Containers::Set< T >::find | ( | ArgByValueType< value_type > | item | ) | const |
auto Stroika::Foundation::Containers::Set< T >::insert | ( | ArgByValueType< value_type > | item | ) |
void Stroika::Foundation::Containers::Set< T >::erase | ( | ArgByValueType< value_type > | item | ) |
|
protected |
Utility to get WRITABLE underlying shared_ptr (replacement for what we normally do - _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ()) but where we also handle the cloning/patching of the associated iterator.
When you have a non-const operation (such as Remove) with an argument of an Iterator<>, then due to COW, you may end up cloning the container rep, and yet the Iterator<> contains a pointer to the earlier rep (and so maybe unusable).
Prior to Stroika 2.1b14, this was handled elegantly, and automatically, by the iterator patching mechanism. But that was deprecated (due to cost, and rarity of use), in favor of this more restricted feature, where we just patch the iterators on an as-needed basis.