Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Association.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_Association_h_
5#define _Stroika_Foundation_Containers_Association_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/Common.h"
11#include "Stroika/Foundation/Common/Concepts.h"
12#include "Stroika/Foundation/Common/KeyValuePair.h"
13#include "Stroika/Foundation/Containers/Common.h"
15
16/*
17 * \file
18 *
19 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
20 *
21 * TODO:
22 * @todo Support more backends
23 * Especially HashTable, RedBlackTree, and stlhashmap
24 *
25 * @todo Not sure where this note goes - but eventually add "Database-Based" implementation of mapping
26 * and/or external file. Maybe also map to DynamoDB, MongoDB, etc... (but not here under Mapping,
27 * other db module would inherit from mapping).
28 *
29 * @todo Keys() method should probably return Set<key_type> - instead of Iterable<key_type>, but concerned about
30 * creating container type interdependencies
31 *
32 * @todo Maybe add optional (return value) arg to Remove()
33 * auto providerToMaybeRemove = fLoadedProviders_.LookupOneValue (providerName);
34 * fLoadedProviders_.Remove (providerName);
35 * if (not fLoadedProviders_.ContainsKey (providerName)) {
36 * DbgTrace (L"calling OSSL_PROVIDER_unload");
37 * Verify (::OSSL_PROVIDER_unload (providerToMaybeRemove) == 1);
38 * }
39 * Above involves two lookups instead of one. Could have Remove () optionally return iterator pointing to next element?
40 * But that only works for stdmap based impl� Could have optional return count of number of remaining with that key.
41 * Maybe too specific to this situation? But at least no cost (pass nullptr by default � add size_t* = nullptr arg
42 * to rep code and for stl can find quickly and for others need to hunt).
43 *
44 */
45
47
49 using Common::IEqualsComparer;
50 using Common::KeyValuePair;
51 using Traversal::IInputIterator;
52 using Traversal::IIterableOfTo;
53 using Traversal::Iterable;
54 using Traversal::Iterator;
55
56 /**
57 * \brief An Association pairs key values with (possibly multiple or none) mapped_type values. Like Mapping<>, but allowing multiple items associated with 'key'
58 *
59 * Association which allows for the association of two elements: a key and
60 * a value. Unlike a Mapping<>, this association may not be unique..
61 *
62 * @see SortedAssociation<Key,T>
63 *
64 * @aliases MultiMap
65 *
66 * \note The term 'KEY' usually implies a UNIQUE mapping to the associated value, but DOES NOT do so in this container ArcheType.
67 * Though databases generally use key to imply unique, https://en.cppreference.com/w/cpp/container/multimap, for example, does not.
68 *
69 * \note Design Note:
70 * \note We used Iterable<KeyValuePair<Key,T>> instead of Iterable<pair<Key,T>> because it makes for
71 * more readable usage (foo.fKey versus foo.first, and foo.fValue versus foo.second).
72 *
73 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
74 *
75 * \em Concrete Implementations:
76 * o @see Concrete::Association_Array<>
77 * o @see Concrete::Association_LinkedList<>
78 * o @see Concrete::SortedAssociation_stdmap<>
79 * o @see Concrete::SortedAssociation_SkipList<>
80 *
81 * \em Factory:
82 * @see <> to see default implementations.
83 *
84 * \note <a href="ReadMe.md#Container Element comparisons">Container Element comparisons</a>:
85 * See about ElementInOrderComparerType, ElementThreeWayComparerType and GetElementThreeWayComparer etc
86 *
87 * \em Design Note:
88 * Included <map> and have explicit CTOR for multimap<> so that Stroika Association can be used more interoperably
89 * with multimap<> - and used without an explicit CTOR. Use Explicit CTOR to avoid accidental conversions. But
90 * if you declare an API with Association<KEY_TYPE,MAPPED_VALUE_TYPE> arguments, its important STL sources passing in multimap<> work transparently.
91 *
92 * Similarly for std::initializer_list.
93 *
94 * \note See <a href="./ReadMe.md">ReadMe.md</a> for common features of all Stroika containers (especially
95 * constructors, iterators, etc)
96 *
97 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
98 * o operator==(Association& rhs) requires (equality_comparable<MAPPED_VALUE_TYPE>);
99 *
100 * Two Associations are considered equal if they contain the same elements (keys) and each key is associated
101 * with the same value. There is no need for the items to appear in the same order for the two Associations to
102 * be equal. There is no need for the backends to be of the same underlying representation either (stlmap
103 * vers LinkedList).
104 *
105 * \pre lhs and rhs arguments must have the same (or equivalent) EqualsComparers.
106 *
107 * @todo - document computational complexity
108 *
109 * ThreeWayComparer support is NOT provided for Association, because there is no intrinsic ordering among the elements
110 * of the Association (keys) - even if there was some way to compare the values.
111 */
112 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
113 class [[nodiscard]] Association : public Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> {
114 private:
116
117 protected:
118 class _IRep;
119
120 public:
121 /**
122 * Use this typedef in templates to recover the basic functional container pattern of concrete types.
123 */
125
126 public:
127 /**
128 * @see inherited::value_type
129 */
131
132 public:
133 /**
134 * like std::multimap<>::key_type
135 */
136 using key_type = KEY_TYPE;
137
138 public:
139 /**
140 * like std::multimap<>::mapped_type
141 */
142 using mapped_type = MAPPED_VALUE_TYPE;
143
144 public:
145 /**
146 */
148 Common::ComparisonRelationDeclaration<Common::ComparisonRelationType::eEquals, function<bool (ArgByValueType<key_type>, ArgByValueType<key_type>)>>;
149
150 public:
151 /**
152 * This constructor creates a concrete Association object, either empty, or initialized with any argument
153 * values.
154 *
155 * The underlying data structure (and performance characteristics) of the Association is
156 * defined by @see Factory::Association_Factory<>
157 *
158 * \par Example Usage
159 * \code
160 * Collection<pair<int,int>> c;
161 * std::map<int,int> m;
162 *
163 * Association<int,int> m1 = {{1, 1}, {2, 2}, {3, 2}};
164 * Association<int,int> m2 = m1;
165 * Association<int,int> m3{ m1 };
166 * Association<int,int> m4{ m1.begin (), m1.end () };
167 * Association<int,int> m5{ c };
168 * Association<int,int> m6{ m };
169 * Association<int,int> m7{ m.begin (), m.end () };
170 * Association<int,int> m8{ move (m1) };
171 * Association<int,int> m9{ Common::DeclareEqualsComparer ([](int l, int r) { return l == r; }) };
172 * \endcode
173 *
174 * \note Even though the initializer_list<> is of KeyValuePair, you can pass along pair<> objects just
175 * as well.
176 *
177 * \note <a href="ReadMe.md#Container Constructors">See general information about container constructors that applies here</a>
178 */
179 Association ()
180 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>);
181 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER>
182 explicit Association (KEY_EQUALS_COMPARER&& keyEqualsComparer);
183 Association (Association&&) noexcept = default;
184 Association (const Association&) noexcept = default;
185 Association (const initializer_list<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& src)
186 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>);
187 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER>
188 Association (KEY_EQUALS_COMPARER&& keyEqualsComparer, const initializer_list<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& src);
189 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
190 explicit Association (ITERABLE_OF_ADDABLE&& src)
191 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE> and
192 not derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, Association<KEY_TYPE, MAPPED_VALUE_TYPE>>)
193#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
194 : Association{}
195 {
196 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
197 _AssertRepValidType ();
198 }
199#endif
200 ;
201 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER, IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
202 Association (KEY_EQUALS_COMPARER&& keyEqualsComparer, ITERABLE_OF_ADDABLE&& src);
203 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
204 Association (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
205 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>);
206 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER, IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE,
207 sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
208 Association (KEY_EQUALS_COMPARER&& keyEqualsComparer, ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end);
209
210 protected:
211 explicit Association (shared_ptr<_IRep>&& rep) noexcept;
212 explicit Association (const shared_ptr<_IRep>& rep) noexcept;
213
214 public:
215 /**
216 */
217 nonvirtual Association& operator= (Association&&) noexcept = default;
218 nonvirtual Association& operator= (const Association&) = default;
219
220 public:
221 /**
222 */
223 nonvirtual KeyEqualsCompareFunctionType GetKeyEqualsComparer () const;
224
225 public:
226 /**
227 * Keys () returns an Iterable object with just the key part of the Association.
228 *
229 * \note Keys () will return a an Iterable producing (iterating) elements in
230 * the same order as the collection it is created from.
231 *
232 * It is equivalent to copying the underlying collection and 'projecting' the
233 * key fields.
234 *
235 * Note the returned Iterable is detached from the original, and doesn't see any changes
236 * to it, and its lifetime is like a copy of a shared_ptr - lasts as long as the
237 * reference.
238 *
239 * \em Design Note:
240 * The analagous method in C#.net - Dictionary<TKey, TValue>.KeyCollection
241 * (http://msdn.microsoft.com/en-us/library/yt2fy5zk(v=vs.110).aspx) returns a live reference
242 * to the underlying keys. We could have (fairly easily) done that, but I didn't see the point.
243 *
244 * In .net, the typical model is that you have a pointer to an object, and pass around that
245 * pointer (so by reference semantics) - so this returning a live reference makes more sense there.
246 *
247 * Since Stroika containers are logically copy-by-value (even though lazy-copied), it made more
248 * sense to apply that lazy-copy (copy-on-write) paradigm here, and make the returned set of
249 * keys a logical copy at the point 'keys' is called.
250 *
251 * See:
252 * @see MappedValues ()
253 */
254 nonvirtual Iterable<key_type> Keys () const;
255
256 public:
257 /**
258 * MappedValues () returns an Iterable object with just the value part of the Association.
259 *
260 * \note MappedValues () will return a an Iterable producing (iterating) elements in
261 * the same order as the collection it is created from.
262 *
263 * It is equivalent to copying the underlying collection and 'projecting' the
264 * value fields.
265 *
266 * Note the returned Iterable is detached from the original, and doesn't see any changes
267 * to it, and its lifetime is like a copy of a shared_ptr - lasts as long as the
268 * reference.
269 *
270 * \em Design Note:
271 * The analogous method in C#.net - Dictionary<TKey, TValue>.ValueCollection
272 * (https://msdn.microsoft.com/en-us/library/x8bctb9c%28v=vs.110%29.aspx).aspx) returns a live reference
273 * to the underlying keys. We could have (fairly easily) done that, but I didn't see the point.
274 *
275 * In .net, the typical model is that you have a pointer to an object, and pass around that
276 * pointer (so by reference semantics) - so this returning a live reference makes more sense there.
277 *
278 * Since Stroika containers are logically copy-by-value (even though lazy-copied), it made more
279 * sense to apply that lazy-copy (copy-on-write) paradigm here, and make the returned set of
280 * keys a logical copy at the point 'keys' is called.
281 *
282 * @aliases Image ()
283 *
284 * See:
285 * @see Keys ()
286 */
287 nonvirtual Iterable<mapped_type> MappedValues () const;
288
289 public:
290 /**
291 * \brief Return an Iterable<mapped_type> of all the associated items (can be empty if none). This iterable is a snapshot at the time of call (but maybe lazy COW copied snapshot so still cheap)
292 */
293 nonvirtual Traversal::Iterable<mapped_type> Lookup (ArgByValueType<key_type> key) const;
294
295 public:
296 /**
297 * \brief Lookup and return the first (maybe arbitrarily chosen which is first) value with this key, and throw if there are none.
298 *
299 * @aliases LookupOrException
300 */
301 nonvirtual optional<mapped_type> LookupOne (ArgByValueType<key_type> key) const;
302
303 public:
304 /**
305 * \brief Lookup and return the first (maybe arbitrarily chosen which is first) value with this key, and throw if there are none.
306 *
307 * @aliases LookupOrException
308 */
309 template <typename THROW_IF_MISSING>
310 nonvirtual mapped_type LookupOneChecked (ArgByValueType<key_type> key, const THROW_IF_MISSING& throwIfMissing) const;
311
312 public:
313 /**
314 * \brief Lookup and return the first (maybe arbitrarily chosen which is first) value with this key, and otherwise return argument value as default.
315 *
316 * @aliases LookupOneOrDefault
317 */
318 nonvirtual mapped_type LookupOneValue (ArgByValueType<key_type> key, ArgByValueType<mapped_type> defaultValue = mapped_type{}) const;
319
320 public:
321 /**
322 * \brief Shortcut for Lookup
323 *
324 * if key is not in the container, an empty iterable will be returned.
325 */
326 nonvirtual const Iterable<mapped_type> operator[] (ArgByValueType<key_type> key) const;
327
328 public:
329 /**
330 * Synonym for Lookup (key).has_value ()
331 *
332 * \note same as OccurrencesOf (key) != 0
333 */
334 nonvirtual bool ContainsKey (ArgByValueType<key_type> key) const;
335
336 public:
337 /**
338 * OccurrencesOf() returns the number of occurrences of 'item' in the association.
339 */
340 nonvirtual size_t OccurrencesOf (ArgByValueType<key_type> item) const;
341
342 public:
343 /**
344 * Likely inefficient, but perhaps helpful. Walks entire list of entires
345 * and applies VALUE_EQUALS_COMPARER (defaults to operator==) on each value, and returns
346 * true if contained. Perhaps not very useful but symmetric to ContainsKey().
347 */
348 template <Common::IEqualsComparer<MAPPED_VALUE_TYPE> VALUE_EQUALS_COMPARER = equal_to<MAPPED_VALUE_TYPE>>
349 nonvirtual bool ContainsMappedValue (ArgByValueType<mapped_type> v, const VALUE_EQUALS_COMPARER& valueEqualsComparer = {}) const;
350
351 public:
352 /**
353 * Add the association between key and newElt. Note, this increases teh size of the container by one, even if key was already present in the association.
354 *
355 * \note mutates container
356 */
357 nonvirtual void Add (ArgByValueType<key_type> key, ArgByValueType<mapped_type> newElt);
358 nonvirtual void Add (ArgByValueType<value_type> p);
359
360 public:
361 /**
362 * \summary Add all the argument (container or bound range of iterators) elements.
363 *
364 * @aliases AddAll/2 is alias for .net AddRange ()
365 *
366 * \note AddAll () does not return the number of items added because all items are added (so the count can be made on the iterators/diff or items.size()
367 *
368 * \note mutates container
369 */
370 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
371 nonvirtual void AddAll (ITERABLE_OF_ADDABLE&& items);
372 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
373 nonvirtual void AddAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end);
374
375 public:
376 /**
377 * \brief Remove the given item (which must exist).
378 *
379 * \note - for the argument 'key' overload, this is a change in Stroika 2.1b14: before it was legal and silently ignored if you removed an item that didn't exist.
380 *
381 * \param 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)
382 *
383 * \note mutates container
384 */
385 nonvirtual void Remove (ArgByValueType<key_type> key);
386 nonvirtual void Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI = nullptr);
387
388 public:
389 /**
390 * \brief Remove the given item, if it exists. Return true if found and removed.
391 *
392 * \note mutates container
393 */
394 nonvirtual bool RemoveIf (ArgByValueType<key_type> key);
395
396 public:
397 /**
398 * \brief RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items.
399 *
400 * The no-arg overload removes all (quickly).
401 *
402 * The overloads that remove some subset of the items returns the number of items so removed, and use RemoveIf() so that the
403 * argument items designated to be removed MAY not be present.
404 *
405 * \note mutates container
406 */
407 nonvirtual void RemoveAll ();
408 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
409 nonvirtual size_t RemoveAll (const ITERABLE_OF_KEY_OR_ADDABLE& items);
410 template <typename ITERATOR_OF_KEY_OR_ADDABLE>
411 nonvirtual size_t RemoveAll (ITERATOR_OF_KEY_OR_ADDABLE start, ITERATOR_OF_KEY_OR_ADDABLE end);
412 template <predicate<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> PREDICATE>
413 nonvirtual size_t RemoveAll (PREDICATE&& p);
414
415 public:
416 /**
417 * Update the value associated with the iterator 'i', without changing iteration order in any way (cuz the key not changed).
418 * Note - if iterating, because this modifies the underlying container, the caller should pass 'i' in as a reference parameter to 'nextI'
419 * to have it updated to safely continue iterating.
420 *
421 * \note mutates container
422 * \note As with ALL methods that modify the Association, this invalidates the iterator 'i', but if you pass nextI (can be same variable as i) - it will be updated with a valid iterator pointing to the same location.
423 */
424 nonvirtual void Update (const Iterator<value_type>& i, ArgByValueType<mapped_type> newValue, Iterator<value_type>* nextI = nullptr);
425
426 public:
427 /**
428 * Remove all items from this container UNLESS they are in the argument set to RetainAll().
429 *
430 * This restricts the 'Keys' list of Association to the argument data, but preserving
431 * any associations.
432 *
433 * \note Java comparison
434 * association.keySet.retainAll (collection);
435 *
436 * \par Example Usage
437 * \code
438 * fStaticProcessStatsForThisSpill_.RetainAll (fDynamicProcessStatsForThisSpill_.Keys ()); // lose static data for processes no longer running
439 * \endcode
440 *
441 * \note Something of an alias for 'Subset()' or 'Intersects', as this - in-place computes the subset
442 * of the Association<> that intersects with the argument keys.
443 *
444 * \todo Consider having const function Intersects() - or Subset() - that produces a copy of the results of RetrainAll()
445 * without modifying this object.
446 *
447 * \note mutates container
448 */
449 template <IIterableOfTo<KEY_TYPE> ITERABLE_OF_KEY_TYPE>
450 nonvirtual void RetainAll (const ITERABLE_OF_KEY_TYPE& items);
451
452 public:
453 /**
454 * \brief 'override' Iterable<>::Map () function so RESULT_CONTAINER defaults to Association, and improve that case to clone properties from this rep (such is rep type, comparisons etc).
455 */
456 template <typename RESULT_CONTAINER = Association<KEY_TYPE, MAPPED_VALUE_TYPE>, invocable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ELEMENT_MAPPER>
457 nonvirtual RESULT_CONTAINER Map (ELEMENT_MAPPER&& elementMapper) const
458 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, typename RESULT_CONTAINER::value_type> or
459 convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, optional<typename RESULT_CONTAINER::value_type>>)
460 ;
461
462 public:
463 /**
464 * Apply the function function to each element, and return a subset Association including just the ones for which it was true.
465 *
466 * \note Alias - this could have been called 'Subset' - as it constructs a subset association (filtering on key or key-value pairs)
467 *
468 * @see Iterable<T>::Where
469 *
470 * \par Example Usage
471 * \code
472 * Association<int, int> m{{1, 3}, {2, 4}, {3, 5}, {4, 5}, {5, 7}};
473 * EXPECT_TRUE ((m.Where ([](const KeyValuePair<int, int>& value) { return Math::IsPrime (value.fKey); }) == Association<int, int>{{2, 4}, {3, 5}, {5, 7}}));
474 * EXPECT_TRUE ((m.Where ([](int key) { return Math::IsPrime (key); }) == Association<int, int>{{2, 4}, {3, 5}, {5, 7}}));
475 * \endcode
476 */
477 template <derived_from<Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>> RESULT_CONTAINER = Association<KEY_TYPE, MAPPED_VALUE_TYPE>, typename INCLUDE_PREDICATE>
478 nonvirtual RESULT_CONTAINER Where (INCLUDE_PREDICATE&& includeIfTrue) const
479 requires (predicate<INCLUDE_PREDICATE, KEY_TYPE> or predicate<INCLUDE_PREDICATE, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>);
480
481 public:
482 /**
483 * Return a subset of this Association<> where the keys are included in the argument includeKeys set..
484 *
485 * \note Alias - this could have been called 'Subset' - as it constructs a subset Association (where the given keys intersect)
486 *
487 * @see Iterable<T>::Where
488 * @see Where
489 *
490 * \note CONCEPT - CONTAINER_OF_KEYS must support the 'Contains' API - not that set, and Iterable<> do this.
491 *
492 * \par Example Usage
493 * \code
494 * Association<int, int> m{{1, 3}, {2, 4}, {3, 5}, {4, 5}, {5, 7}};
495 * EXPECT_TRUE ((m.WithKeys ({2, 5}) == Association<int, int>{{2, 4}, {5, 7}}));
496 * \endcode
497 */
498 template <typename CONTAINER_OF_KEYS>
499 nonvirtual ArchetypeContainerType WithKeys (const CONTAINER_OF_KEYS& includeKeys) const;
500 nonvirtual ArchetypeContainerType WithKeys (const initializer_list<key_type>& includeKeys) const;
501
502 public:
503 /**
504 * This function should work for any container which accepts
505 * (ITERATOR_OF<KeyValuePair<Key,Value>>,ITERATOR_OF<KeyValuePair<Key,Value>>) OR
506 * (ITERATOR_OF<pair<Key,Value>>,ITERATOR_OF<pair<Key,Value>>).
507 *
508 * These As<> overloads also may require the presence of an insert(ITERATOR, Value) method
509 * of CONTAINER_OF_Key_T.
510 *
511 * So - for example, Sequence<KeyValuePair<key_type,ValueType>>, map<key_type,ValueType>,
512 * vector<pair<key_type,ValueType>>, etc...
513 */
514 template <typename CONTAINER_OF_Key_T>
515 nonvirtual CONTAINER_OF_Key_T As () const;
516
517 protected:
518 /**
519 * \brief Utility to get WRITABLE underlying shared_ptr (replacement for what we normally do - _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ())
520 * but where we also handle the cloning/patching of the associated iterator
521 *
522 * When you have a non-const operation (such as Remove) with an argument of an Iterator<>, then due to COW,
523 * you may end up cloning the container rep, and yet the Iterator<> contains a pointer to the earlier rep (and so maybe unusable).
524 *
525 * Prior to Stroika 2.1b14, this was handled elegantly, and automatically, by the iterator patching mechanism. But that was deprecated (due to cost, and
526 * rarity of use), in favor of this more restricted feature, where we just patch the iterators on an as-needed basis.
527 *
528 * \todo @todo - could be smarter about moves and avoid some copies here - I think, and this maybe performance sensitive enough to look into that... (esp for COMMON case where no COW needed)
529 */
530 nonvirtual tuple<_IRep*, Iterator<value_type>> _GetWritableRepAndPatchAssociatedIterator (const Iterator<value_type>& i);
531
532 public:
533 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (Common::IEqualsComparer<MAPPED_VALUE_TYPE>) VALUE_EQUALS_COMPARER = equal_to<MAPPED_VALUE_TYPE>>
534 struct EqualsComparer;
535
536 public:
537 /**
538 * simply indirect to @Association<>::EqualsComparer;
539 * only defined if there is a default equals comparer for mapped_type
540 *
541 * \note since the order of iteration for an association is undefined, two associations maybe equal, but not enumerate out the same way.
542 */
543 nonvirtual bool operator== (const Association& rhs) const
544 requires (equality_comparable<MAPPED_VALUE_TYPE>);
545
546 public:
547 /**
548 * \brief like Add (key, newValue) - BUT newValue is COMBINED with the 'f' argument.
549 *
550 * The accumulator function combines the previous value associated with the new value given (using initialValue if key was not already present in the map).
551 */
552 nonvirtual void Accumulate (
553 ArgByValueType<key_type> key, ArgByValueType<mapped_type> newValue,
554 const function<mapped_type (ArgByValueType<mapped_type>, ArgByValueType<mapped_type>)>& f =
555 [] (ArgByValueType<mapped_type> l, ArgByValueType<mapped_type> r) -> mapped_type { return l + r; },
556 mapped_type initialValue = {});
557
558 public:
559 /**
560 * \brief STL-ish alias for Remove ().
561 */
562 nonvirtual void erase (ArgByValueType<key_type> key);
563 nonvirtual Iterator<value_type> erase (const Iterator<value_type>& i);
564
565 public:
566 /**
567 * \brief STL-ish alias for RemoveAll ().
568 */
569 nonvirtual void clear ();
570
571 public:
572 /**
573 */
574 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
575 nonvirtual Association operator+ (const ITERABLE_OF_ADDABLE& items) const;
576
577 public:
578 /**
579 */
580 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
581 nonvirtual Association& operator+= (const ITERABLE_OF_ADDABLE& items);
582
583 public:
584 /**
585 */
586 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
587 nonvirtual Association& operator-= (const ITERABLE_OF_KEY_OR_ADDABLE& items);
588
589 protected:
590 /**
591 */
592 template <typename T2>
593 using _SafeReadRepAccessor = typename inherited::template _SafeReadRepAccessor<T2>;
594
595 protected:
596 /**
597 */
598 template <typename T2>
599 using _SafeReadWriteRepAccessor = typename inherited::template _SafeReadWriteRepAccessor<T2>;
600
601 protected:
602 nonvirtual void _AssertRepValidType () const;
603 };
604
605 /**
606 * \brief Implementation detail for Association<T> implementors.
607 *
608 * Protected abstract interface to support concrete implementations of
609 * the Association<T> container API.
610 */
611 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
612 class Association<KEY_TYPE, MAPPED_VALUE_TYPE>::_IRep : public Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>::_IRep {
613 private:
614 using inherited = typename Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>::_IRep;
615
616 protected:
617 _IRep () = default;
618
619 public:
620 virtual ~_IRep () = default;
621
622 public:
623 virtual KeyEqualsCompareFunctionType GetKeyEqualsComparer () const = 0;
624 virtual shared_ptr<_IRep> CloneEmpty () const = 0;
625 virtual shared_ptr<_IRep> CloneAndPatchIterator (Iterator<value_type>* i) const = 0;
626 // always clear/set item, and ensure return value == item->IsValidItem());
627 // 'item' arg CAN be nullptr
628 virtual Iterable<mapped_type> Lookup (ArgByValueType<KEY_TYPE> key) const = 0;
629 virtual void Add (ArgByValueType<KEY_TYPE> key, ArgByValueType<mapped_type> newElt) = 0;
630 virtual bool RemoveIf (ArgByValueType<KEY_TYPE> key) = 0;
631 // if nextI is non-null, its filled in with the next item in iteration order after i (has been removed)
632 virtual void Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI) = 0;
633 virtual void Update (const Iterator<value_type>& i, ArgByValueType<mapped_type> newValue, Iterator<value_type>* nextI) = 0;
634 };
635
636 /**
637 * \brief Compare Associations<>s for equality.
638 *
639 * Two associations are equal, if they have the same domain, the same range, and each element in the domain
640 * has the same elements in its range (though there is NO NEED for the domain elements or range elements or associated elements
641 * to be in the same order).
642 *
643 * \note This maybe expensive to compute, since all these different orderings are allowed when items still compare equal. However,
644 * the code makes some effort to make sure the common cases where things are all in the same order are detected as equal
645 * quickly.
646 *
647 * \note Not to be confused with GetKeyEqualsComparer () which compares KEY ELEMENTS of Association for equality.
648 */
649 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
650 template <qCompilerAndStdLib_ConstraintDiffersInTemplateRedeclaration_BWA (Common::IEqualsComparer<MAPPED_VALUE_TYPE>) VALUE_EQUALS_COMPARER>
651 struct Association<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer
652 : Common::ComparisonRelationDeclarationBase<Common::ComparisonRelationType::eEquals> {
653 constexpr EqualsComparer (const VALUE_EQUALS_COMPARER& valueEqualsComparer = {});
654 nonvirtual bool operator() (const Association& lhs, const Association& rhs) const;
655 [[no_unique_address]] VALUE_EQUALS_COMPARER fValueEqualsComparer;
656 };
657
658}
659
660/*
661 ********************************************************************************
662 ******************************* Implementation Details *************************
663 ********************************************************************************
664 */
665#include "Association.inl"
666
667#endif /*_Stroika_Foundation_Containers_Association_h_ */
Implementation detail for Association<T> implementors.
An Association pairs key values with (possibly multiple or none) mapped_type values....
nonvirtual CONTAINER_OF_Key_T As() const
nonvirtual bool RemoveIf(ArgByValueType< key_type > key)
Remove the given item, if it exists. Return true if found and removed.
nonvirtual void Remove(ArgByValueType< key_type > key)
Remove the given item (which must exist).
nonvirtual void Update(const Iterator< value_type > &i, ArgByValueType< mapped_type > newValue, Iterator< value_type > *nextI=nullptr)
nonvirtual void RetainAll(const ITERABLE_OF_KEY_TYPE &items)
nonvirtual void Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt)
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
nonvirtual void AddAll(ITERABLE_OF_ADDABLE &&items)
nonvirtual Traversal::Iterable< mapped_type > Lookup(ArgByValueType< key_type > key) const
Return an Iterable<mapped_type> of all the associated items (can be empty if none)....
typename inherited::value_type value_type
nonvirtual ArchetypeContainerType WithKeys(const CONTAINER_OF_KEYS &includeKeys) const
nonvirtual bool ContainsMappedValue(ArgByValueType< mapped_type > v, const VALUE_EQUALS_COMPARER &valueEqualsComparer={}) const
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
T value_type
value_type is an alias for the type iterated over - like vector<T>::value_type
Definition Iterable.h:248
An Iterator<T> is a copyable object which allows traversing the contents of some container....
Definition Iterator.h:225
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
Definition TypeHints.h:32