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