Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Mapping.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_Mapping_h_
5#define _Stroika_Foundation_Containers_Mapping_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 (though these two basically implemented via STL but better docs/exposition of we have simple impl ourselves).
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 */
33
35
37 using Common::IEqualsComparer;
38 using Common::KeyValuePair;
39 using Traversal::IInputIterator;
40 using Traversal::IIterableOfTo;
41 using Traversal::Iterable;
42 using Traversal::Iterator;
43
44 /**
45 * \brief document requirements for a Mapping key
46 *
47 * \note we do NOT require equality_comparable<KEY_TYPE>, but if its not, Mapping's must be created with a comparison function.
48 */
49 template <typename KEY_TYPE>
50 concept Mapping_IKey = copy_constructible<KEY_TYPE>;
51
52 /**
53 * \brief document requirements for a Mapping value
54 *
55 * \note the assignable_from is needed for
56 * void Update (const Iterator<value_type>& i, ArgByValueType<mapped_type> newValue, Iterator<value_type>* nextI)
57 * We COULD remove the element and re-add there if not assignable. But that would appear to be adding a modest amount of complexity (association faces this too and many backends)
58 * for little gain (allowing Mapping<A, const B>).
59 */
60 template <typename MAPPED_VALUE_TYPE>
61 concept Mapping_IMappedValue = copy_constructible<MAPPED_VALUE_TYPE> and assignable_from<MAPPED_VALUE_TYPE&, MAPPED_VALUE_TYPE>;
62
63 /**
64 * Mapping which allows for the association of two elements: a key and
65 * a value. The key UNIQUELY specifies its associated value.
66 *
67 * @see SortedMapping<Key,T>
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::Mapping_Array<>
77 * o @see Concrete::Mapping_LinkedList<>
78 * o @see Concrete::Mapping_stdhashmap<>
79 * o @see Concrete::SortedMapping_SkipList<>
80 * o @see Concrete::SortedMapping_stdmap<>
81 *
82 * \em Factory:
83 * @see Mapping_Factory<> to see default implementations.
84 *
85 * \em Design Note:
86 * Included <map> and have explicit CTOR for map<> so that Stroika Mapping can be used more interoperably
87 * with map<> - and used without an explicit CTOR. Use Explicit CTOR to avoid accidental conversions. But
88 * if you declare an API with Mapping<KEY_TYPE,MAPPED_VALUE_TYPE> arguments, its important STL sources passing in map<> work transparently.
89 *
90 * Similarly for std::initializer_list.
91 *
92 * \note <a href="ReadMe.md#Container Element comparisons">Container Element comparisons</a>:
93 * See about ElementInOrderComparerType, ElementThreeWayComparerType and GetElementThreeWayComparer etc
94 *
95 * \note See <a href="./ReadMe.md">ReadMe.md</a> for common features of all Stroika containers (especially
96 * constructors, iterators, etc)
97 *
98 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
99 * o static_assert (equality_comparable<VALUE_TYPE> ==> equality_comparable<Mapping<KEY, VALUE_TYPE>>);
100 *
101 * Two Mappings are considered equal if they contain the same elements (keys) and each key is associated
102 * with the same value. There is no need for the items to appear in the same order for the two Mappings to
103 * be equal. There is no need for the backends to be of the same underlying representation either (stl map
104 * vers linked list).
105 *
106 * \pre lhs and rhs arguments must have the same (or equivalent) EqualsComparers.
107 *
108 * @todo - document computational complexity
109 *
110 * ThreeWayComparer support is NOT provided for Mapping, because there is no intrinsic ordering among the elements
111 * of the mapping (keys) - even if there was some way to compare the values.
112 */
113 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
114 class [[nodiscard]] Mapping : public Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> {
115 public:
116 /**
117 * Note - use static_assert rather than typename constraints because sometimes (like VariantValue use of Mapping<String,VariantValue>)
118 * constraint evaluation is a problem with incomplete types.
119 */
120 static_assert (Mapping_IKey<KEY_TYPE>);
122
123 private:
125
126 protected:
127 class _IRep;
128
129 public:
130 /**
131 * Use this typedef in templates to recover the basic functional container pattern of concrete types.
132 */
134
135 public:
136 /**
137 * @see inherited::value_type
138 */
140
141 public:
142 /**
143 * like std::map<>::key_type
144 */
145 using key_type = KEY_TYPE;
146
147 public:
148 /**
149 * like std::map<>::mapped_type
150 */
151 using mapped_type = MAPPED_VALUE_TYPE;
152
153 public:
154 /**
155 * This is the type returned by GetKeyEqualsComparer () and CAN be used as the argument to a Mapping<> as KeyEqualityComparer, but
156 * we allow any template in the Mapping<> CTOR for a keyEqualityComparer that follows the IEqualsComparer concept.
157 */
159 Common::ComparisonRelationDeclaration<Common::ComparisonRelationType::eEquals, function<bool (ArgByValueType<key_type>, ArgByValueType<key_type>)>>;
160 static_assert (IEqualsComparer<KeyEqualsCompareFunctionType, key_type>);
161
162 public:
163 /**
164 * This constructor creates a concrete mapping object, either empty, or initialized with any argument
165 * values.
166 *
167 * The underlying data structure (and performance characteristics) of the Mapping is
168 * defined by @see Factory::Mapping_Factory<>
169 *
170 * \par Example Usage
171 * \code
172 * Collection<pair<int,int>> c;
173 * std::map<int,int> m;
174 *
175 * Mapping<int,int> m1 = {pair<int, int>{1, 1}, pair<int, int>{2, 2}, pair<int, int>{3, 2}};
176 * Mapping<int,int> m2 = m1;
177 * Mapping<int,int> m3{ m1 };
178 * Mapping<int,int> m4{ m1.begin (), m1.end () };
179 * Mapping<int,int> m5{ c };
180 * Mapping<int,int> m6{ m };
181 * Mapping<int,int> m7{ m.begin (), m.end () };
182 * Mapping<int,int> m8{ move (m1) };
183 * Mapping<int,int> m9{ Common::DeclareEqualsComparer ([](int l, int r) { return l == r; }) };
184 * \endcode
185 *
186 * \note Even though the initializer_list<> is of KeyValuePair, you can pass along pair<> objects just
187 * as well.
188 *
189 * \note <a href="ReadMe.md#Container Constructors">See general information about container constructors that applies here</a>
190 */
191 Mapping ()
192 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>);
193 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER>
194 explicit Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer);
195 Mapping (Mapping&&) noexcept = default;
196 Mapping (const Mapping&) noexcept = default;
197 Mapping (const initializer_list<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& src)
198 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>);
199 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER>
200 Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer, const initializer_list<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& src);
201 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
202 explicit Mapping (ITERABLE_OF_ADDABLE&& src)
203 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE> and
204 not derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>>)
205#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
206 : Mapping{}
207 {
208 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
209 _AssertRepValidType ();
210 }
211#endif
212 ;
213 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER, IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
214 Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer, ITERABLE_OF_ADDABLE&& src);
215 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
216 Mapping (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
217 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>);
218 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER, IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE,
219 sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
220 Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer, ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end);
221
222 protected:
223 explicit Mapping (shared_ptr<_IRep>&& rep) noexcept;
224 explicit Mapping (const shared_ptr<_IRep>& rep) noexcept;
225
226 public:
227 /**
228 */
229 nonvirtual Mapping& operator= (Mapping&&) noexcept = default;
230 nonvirtual Mapping& operator= (const Mapping&) = default;
231
232 public:
233 /**
234 */
235 nonvirtual KeyEqualsCompareFunctionType GetKeyEqualsComparer () const;
236
237 public:
238 /**
239 * Keys () returns an Iterable object with just the key part of the Mapping.
240 *
241 * \note Keys () will return a an Iterable producing (iterating) elements in
242 * the same order as the Mapping it is created from.
243 *
244 * It is equivalent to copying the underlying Mapping and 'projecting' the
245 * key fields (so the result will be sorted in a SortedMapping).
246 *
247 * This means that Keys() is detached from the original Mapping (should that change)
248 * and its lifetime may extend past the lifetime of the original mapping.
249 *
250 * \em Design Note:
251 * The analogous method in C#.net - Dictionary<TKey, TValue>.KeyCollection
252 * (http://msdn.microsoft.com/en-us/library/yt2fy5zk(v=vs.110).aspx) returns a live reference
253 * to the underlying keys. We could have (fairly easily) done that, but I didn't see the point.
254 *
255 * In .net, the typical model is that you have a pointer to an object, and pass around that
256 * pointer (so by reference semantics) - so this returning a live reference makes more sense there.
257 *
258 * Since Stroika containers are logically copy-by-value (even though lazy-copied), it made more
259 * sense to apply that lazy-copy (copy-on-write) paradigm here, and make the returned set of
260 * keys a logical copy at the point 'keys' is called.
261 *
262 * See:
263 * @see MappedValues ()
264 */
265 nonvirtual Iterable<key_type> Keys () const;
266
267 public:
268 /**
269 * MappedValues () returns an Iterable object with just the value part of the Mapping.
270 *
271 * \note MappedValues () will return a an Iterable producing (iterating) elements in
272 * the same order as the collection it is created from.
273 *
274 * It is equivalent to copying the underlying collection and 'projecting' the
275 * value fields.
276 *
277 * This means that Keys() is detached from the original Mapping (should that change)
278 * and its lifetime may extend past the lifetime of the original mapping.
279 *
280 * \em Design Note:
281 * The analogous method in C#.net - Dictionary<TKey, TValue>.ValueCollection
282 * (https://msdn.microsoft.com/en-us/library/x8bctb9c%28v=vs.110%29.aspx).aspx) returns a live reference
283 * to the underlying keys. We could have (fairly easily) done that, but I didn't see the point.
284 *
285 * In .net, the typical model is that you have a pointer to an object, and pass around that
286 * pointer (so by reference semantics) - so this returning a live reference makes more sense there.
287 *
288 * Since Stroika containers are logically copy-by-value (even though lazy-copied), it made more
289 * sense to apply that lazy-copy (copy-on-write) paradigm here, and make the returned set of
290 * keys a logical copy at the point 'keys' is called.
291 *
292 * @aliases Image ()
293 *
294 * See:
295 * @see Keys ()
296 */
297 nonvirtual Iterable<mapped_type> MappedValues () const;
298
299 public:
300 /**
301 * Note - as since Lookup/1 returns an optional<T> - it can be used very easily to provide
302 * a default value on Lookup (so for case where not present) - as in:
303 * return m.Lookup (key).Value (putDefaultValueHere);
304 *
305 * Note - for both overloads taking an item pointer, the pointer may be nullptr (in which case not assigned to).
306 * But if present, will always be assigned to if Lookup returns true (found). And for the optional overload
307 * \pre Ensure (item == nullptr or returnValue == item->has_value());
308 *
309 * @aliases Lookup (key, mapped_type* value) - is equivalent to .Net TryGetValue ()
310 *
311 * \@todo http://stroika-bugs.sophists.com/browse/STK-928 - add overload 'returning' Iterator<>, so can use with Update method
312 */
313 nonvirtual optional<mapped_type> Lookup (ArgByValueType<key_type> key) const;
314 nonvirtual bool Lookup (ArgByValueType<key_type> key, optional<mapped_type>* item) const;
315 nonvirtual bool Lookup (ArgByValueType<key_type> key, mapped_type* item) const;
316 nonvirtual bool Lookup (ArgByValueType<key_type> key, nullptr_t) const;
317
318 public:
319 /**
320 * @aliases LookupOrException
321 */
322 template <typename THROW_IF_MISSING>
323 nonvirtual mapped_type LookupChecked (ArgByValueType<key_type> key, const THROW_IF_MISSING& throwIfMissing) const;
324
325 public:
326 /**
327 * Always safe to call. If result of Lookup () !has_value, returns argument 'default' or 'sentinel' value.
328 *
329 * @aliases LookupOrDefault
330 */
331 nonvirtual mapped_type LookupValue (ArgByValueType<key_type> key, ArgByValueType<mapped_type> defaultValue = mapped_type{}) const;
332
333 public:
334 /**
335 * \pre ContainsKey (key);
336 *
337 * \note Design Note:
338 * Defined operator[](KEY_TYPE) const - to return const MAPPED_VALUE_TYPE, instead of optional<MAPPED_VALUE_TYPE> because
339 * this adds no value - you can always use Lookup or LookupValue. The reason to use operator[] is
340 * as convenient syntactic sugar. But if you have to check (the elt not necessarily present) - then you
341 * may as well use Lookup () - cuz the code's going to look ugly anyhow.
342 *
343 * Defined operator[](KEY_TYPE) const - to return MAPPED_VALUE_TYPE instead of MAPPED_VALUE_TYPE& because we then couldn't control
344 * the lifetime of that reference, and it would be unsafe as the underlying object was changed.
345 *
346 * And therefore we return CONST of that type so that code like m["xx"].a = 3 won't compile (and wont just assign to a temporary that disappears
347 * leading to confusion).
348 *
349 * \note In the future, it may make sense to have operator[] return a PROXY OBJECT, so that it MIGHT be assignable. But that wouldn't work with
350 * cases like Mapping<String,OBJ> where you wanted to access OBJs fields as in m["xx"].a = 3
351 *
352 */
353 nonvirtual add_const_t<mapped_type> operator[] (ArgByValueType<key_type> key) const;
354
355 public:
356 /**
357 * Synonym for Lookup (key).has_value ()
358 */
359 nonvirtual bool ContainsKey (ArgByValueType<key_type> key) const;
360
361 public:
362 /**
363 * Likely inefficient for a map, but perhaps helpful. Walks entire list of entires
364 * and applies VALUE_EQUALS_COMPARER (defaults to operator==) on each value, and returns
365 * true if contained. Perhaps not very useful but symmetric to ContainsKey().
366 */
367 template <typename VALUE_EQUALS_COMPARER = equal_to<MAPPED_VALUE_TYPE>>
368 nonvirtual bool ContainsMappedValue (ArgByValueType<mapped_type> v, VALUE_EQUALS_COMPARER&& valueEqualsComparer = {}) const;
369
370 public:
371 /**
372 * Add the association between key and newElt.
373 *
374 * If key was already associated with something, consult argument addReplaceMode (defaults to AddReplaceMode::eAddReplaces).
375 * if 'replaces' then replace, and if 'addif' then do nothing on Add ()
376 *
377 * \returns bool: The (generally ignored) return value boolean indicates if a new item was added (so size of iterable increased).
378 * This value returned is FALSE for the case of when the value remains unchanged or even if the value is updated (overwriting the previous association).
379 *
380 * Also - we guarantee that even if the association is different, if the key has not changed,
381 * then the iteration order is not changed (helpful for AddAll() semantics, and perhaps elsewhere).
382 *
383 * \note This behavior when the entry already exists differs from the behavior of std::map::insert (@see http://en.cppreference.com/w/cpp/container/map/insert)
384 * "Inserts element(s) into the container, if the container doesn't already contain an element with an equivalent key".
385 * This behavior is analogous to the new std-c++17 std::map::insert_or_assign () - @see http://en.cppreference.com/w/cpp/container/map/insert_or_assign
386 *
387 * \note mutates container
388 *
389 * \note - this returns true if a CLEAR change happened. But mappings don't have a VALUE_COMPARER by default. So no way
390 * to return if the MAPPING ITSELF changed. @todo - CONSIDER adding optional VALUE_COMPARER to AddIf, so it can return
391 * true if the mapping CHANGES (mapped to value changes). May need a different name (meaning maybe we've picked a bad name here)
392 *
393 * \note Similar to Set<>::AddIf() - but here there is the ambiguity about whether to change what is mapped to (which we do differently
394 * between Add and AddIf) and no such issue exists with Set<>::AddIf. But return true if they make a change.
395 */
396 nonvirtual bool Add (ArgByValueType<key_type> key, ArgByValueType<mapped_type> newElt, AddReplaceMode addReplaceMode = AddReplaceMode::eAddReplaces);
397 nonvirtual bool Add (ArgByValueType<value_type> p, AddReplaceMode addReplaceMode = AddReplaceMode::eAddReplaces);
398
399 public:
400 /**
401 * \summary Add all the argument (container or bound range of iterators) elements; if replaceExistingMapping true (default) force replace on each. Return count of added items (not count of updated items)
402 *
403 * @aliases AddAll/2 is alias for .net AddRange ()
404 *
405 * \note mutates container
406 */
407 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
408 nonvirtual unsigned int AddAll (ITERABLE_OF_ADDABLE&& items, AddReplaceMode addReplaceMode = AddReplaceMode::eAddReplaces);
409 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
410 nonvirtual unsigned int AddAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end,
411 AddReplaceMode addReplaceMode = AddReplaceMode::eAddReplaces);
412
413 public:
414 /**
415 * \brief Remove the given item (which must exist).
416 *
417 * \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.
418 *
419 * \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)
420 *
421 * \note mutates container
422 */
423 nonvirtual void Remove (ArgByValueType<key_type> key);
424 nonvirtual void Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI = nullptr);
425
426 public:
427 /**
428 * \brief Remove the given item, if it exists. Return true if found and removed.
429 *
430 * \note mutates container
431 */
432 nonvirtual bool RemoveIf (ArgByValueType<key_type> key);
433
434 public:
435 /**
436 * \brief RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items.
437 *
438 * The no-arg overload removes all (quickly).
439 *
440 * The overloads that remove some subset of the items returns the number of items so removed, and use RemoveIf() so that the
441 * argument items designated to be removed MAY not be present.
442 *
443 * \note mutates container
444 */
445 nonvirtual void RemoveAll ();
446 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
447 nonvirtual size_t RemoveAll (const ITERABLE_OF_KEY_OR_ADDABLE& items);
448 template <typename ITERATOR_OF_KEY_OR_ADDABLE>
449 nonvirtual size_t RemoveAll (ITERATOR_OF_KEY_OR_ADDABLE start, ITERATOR_OF_KEY_OR_ADDABLE end);
450 template <predicate<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> PREDICATE>
451 nonvirtual size_t RemoveAll (PREDICATE&& p);
452
453 public:
454 /**
455 * Update the value associated with the iterator 'i', without changing iteration order in any way (cuz the key not changed).
456 * Note - if iterating, because this modifies the underlying container, the caller should pass 'i' in as a reference parameter to 'nextI'
457 * to have it updated to safely continue iterating.
458 *
459 * \note mutates container
460 * \note As with ALL methods that modify the Mapping, 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.
461 */
462 nonvirtual void Update (const Iterator<value_type>& i, ArgByValueType<mapped_type> newValue, Iterator<value_type>* nextI = nullptr);
463
464 public:
465 /**
466 * Remove all items from this container UNLESS they are in the argument set to RetainAll().
467 *
468 * This restricts the 'Keys' list of Mapping to the argument data, but preserving
469 * any associations.
470 *
471 * \note Java comparison
472 * mapping.keySet.retainAll (collection);
473 *
474 * \par Example Usage
475 * \code
476 * fStaticProcessStatsForThisSpill_.RetainAll (fDynamicProcessStatsForThisSpill_.Keys ()); // lose static data for processes no longer running
477 * \endcode
478 *
479 * \note Something of an alias for 'Subset()' or 'Intersects', as this - in-place computes the subset
480 * of the Mapping<> that intersects with the argument keys.
481 *
482 * \todo Consider having const function Intersects() - or Subset() - that produces a copy of the results of RetrainAll()
483 * without modifying this object.
484 *
485 * \note mutates container
486 */
487 template <IIterableOfTo<KEY_TYPE> ITERABLE_OF_KEY_TYPE>
488 nonvirtual void RetainAll (const ITERABLE_OF_KEY_TYPE& items);
489
490 public:
491 /**
492 * \brief 'override' Iterable<>::Map () function so container template defaults to Mapping, and improve that case to also clone properties like sort order from this mapping
493 */
494 template <typename RESULT_CONTAINER = Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>, invocable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ELEMENT_MAPPER>
495 nonvirtual RESULT_CONTAINER Map (ELEMENT_MAPPER&& elementMapper) const
496 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, typename RESULT_CONTAINER::value_type> or
497 convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, optional<typename RESULT_CONTAINER::value_type>>)
498 ;
499
500 public:
501 /**
502 * Apply the function function to each element, and return a subset Mapping including just the ones for which it was true.
503 *
504 * @aliases 'Subset' - as it constructs a subset mapping (filtering on key or key-value pairs)
505 *
506 * @see Iterable<T>::Where
507 *
508 * \par Example Usage
509 * \code
510 * Mapping<int, int> m{{1, 3}, {2, 4}, {3, 5}, {4, 5}, {5, 7}};
511 * EXPECT_TRUE ((m.Where ([] (const KeyValuePair<int, int>& value) { return Math::IsPrime (value.fKey); }) == Mapping<int, int>{{2, 4}, {3, 5}, {5, 7}}));
512 * EXPECT_TRUE ((m.Where ([] (int key) { return Math::IsPrime (key); }) == Mapping<int, int>{{2, 4}, {3, 5}, {5, 7}}));
513 * \endcode
514 */
515 template <derived_from<Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>> RESULT_CONTAINER = Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>, typename INCLUDE_PREDICATE>
516 nonvirtual RESULT_CONTAINER Where (INCLUDE_PREDICATE&& includeIfTrue) const
517 requires (predicate<INCLUDE_PREDICATE, KEY_TYPE> or predicate<INCLUDE_PREDICATE, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>);
518
519 public:
520 /**
521 * Return a subset of this Mapping<> where the keys are included in the argument includeKeys set..
522 *
523 * @aliases Subset - as it constructs a subset mapping (where the given keys intersect)
524 *
525 * @see Iterable<T>::Where
526 * @see Where
527 *
528 * \note CONCEPT - CONTAINER_OF_KEYS must support the 'Contains' API - not that set, and Iterable<> do this.
529 *
530 * \par Example Usage
531 * \code
532 * Mapping<int, int> m{{1, 3}, {2, 4}, {3, 5}, {4, 5}, {5, 7}};
533 * EXPECT_TRUE ((m.WithKeys ({2, 5}) == Mapping<int, int>{{2, 4}, {5, 7}}));
534 * \endcode
535 */
536 template <typename CONTAINER_OF_KEYS>
537 nonvirtual ArchetypeContainerType WithKeys (const CONTAINER_OF_KEYS& includeKeys) const;
538 nonvirtual ArchetypeContainerType WithKeys (const initializer_list<key_type>& includeKeys) const;
539
540 public:
541 /**
542 * This function should work for any container which accepts
543 * (ITERATOR_OF<KeyValuePair<Key,Value>>,ITERATOR_OF<KeyValuePair<Key,Value>>) OR
544 * (ITERATOR_OF<pair<Key,Value>>,ITERATOR_OF<pair<Key,Value>>).
545 *
546 * These As<> overloads also may require the presence of an insert(ITERATOR, Value) method
547 * of CONTAINER_OF_Key_T.
548 *
549 * So - for example, Sequence<KeyValuePair<key_type,ValueType>>, map<key_type,ValueType>,
550 * vector<pair<key_type,ValueType>>, etc...
551 */
552 template <typename CONTAINER_OF_Key_T>
553 nonvirtual CONTAINER_OF_Key_T As () const;
554
555 protected:
556 /**
557 * \brief Utility to get WRITABLE underlying shared_ptr (replacement for what we normally do - _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ())
558 * but where we also handle the cloning/patching of the associated iterator
559 *
560 * When you have a non-const operation (such as Remove) with an argument of an Iterator<>, then due to COW,
561 * you may end up cloning the container rep, and yet the Iterator<> contains a pointer to the earlier rep (and so maybe unusable).
562 *
563 * Prior to Stroika 2.1b14, this was handled elegantly, and automatically, by the iterator patching mechanism. But that was deprecated (due to cost, and
564 * rarity of use), in favor of this more restricted feature, where we just patch the iterators on an as-needed basis.
565 *
566 * \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)
567 */
568 nonvirtual tuple<_IRep*, Iterator<value_type>> _GetWritableRepAndPatchAssociatedIterator (const Iterator<value_type>& i);
569
570 private:
571 template <typename CONTAINER_OF_Key_T>
572 nonvirtual CONTAINER_OF_Key_T As_ () const;
573
574 public:
575 template <typename VALUE_EQUALS_COMPARER = equal_to<MAPPED_VALUE_TYPE>>
576 struct EqualsComparer;
577
578 public:
579 /**
580 * \brief compares if the two mappings have the same keys, and corresponding values (doesn't check ordering same). Note this can be costly, as the Mappings are not necessarily in the same order
581 *
582 * simply indirect to @Mapping<>::EqualsComparer;
583 * only defined if there is a default equals comparer for mapped_type
584 */
585 nonvirtual bool operator== (const Mapping& rhs) const
586 requires (equality_comparable<MAPPED_VALUE_TYPE>);
587
588 public:
589 /**
590 * \brief like Add (key, newValue) - BUT newValue is COMBINED with the 'f' argument.
591 *
592 * The accumulator function combines the previous value associated with the new value given (using initialValue if key was not already present in the map).
593 */
594 nonvirtual void Accumulate (
595 ArgByValueType<key_type> key, ArgByValueType<mapped_type> newValue,
596 const function<mapped_type (ArgByValueType<mapped_type>, ArgByValueType<mapped_type>)>& f =
597 [] (ArgByValueType<mapped_type> l, ArgByValueType<mapped_type> r) -> mapped_type { return l + r; },
598 mapped_type initialValue = {});
599
600 public:
601 /**
602 * @aliases Add ().
603 *
604 * \see https://en.cppreference.com/w/cpp/container/map/insert
605 *
606 * \note - we only provide a very small subset of the possible variations of insert from STL, but this is probably the most common
607 */
608 nonvirtual void insert (ArgByValueType<value_type> kvp);
609
610 public:
611 /**
612 * @aliases Remove ().
613 *
614 * \note - beware of using erase(iterator) - probably should use Stroika 'Remove' so you can pass extra parameter to get iterator patched.
615 * At any rate, beware its illegal to use 'i' after erasing at i (detected by Stroika when use use it).
616 */
617 nonvirtual void erase (ArgByValueType<key_type> key);
618 nonvirtual Iterator<value_type> erase (const Iterator<value_type>& i);
619
620 public:
621 /**
622 * @aliases RemoveAll ().
623 */
624 nonvirtual void clear ();
625
626 public:
627 /**
628 */
629 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
630 nonvirtual Mapping operator+ (const ITERABLE_OF_ADDABLE& items) const;
631
632 public:
633 /**
634 */
635 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
636 nonvirtual Mapping& operator+= (const ITERABLE_OF_ADDABLE& items);
637
638 public:
639 /**
640 */
641 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
642 nonvirtual Mapping& operator-= (const ITERABLE_OF_KEY_OR_ADDABLE& items);
643
644 protected:
645 /**
646 */
647 template <typename T2>
648 using _SafeReadRepAccessor = typename inherited::template _SafeReadRepAccessor<T2>;
649
650 protected:
651 /**
652 */
653 template <typename T2>
654 using _SafeReadWriteRepAccessor = typename inherited::template _SafeReadWriteRepAccessor<T2>;
655
656 protected:
657 nonvirtual void _AssertRepValidType () const;
658 };
659
660 /**
661 * \brief Implementation detail for Mapping<T> implementors.
662 *
663 * Protected abstract interface to support concrete implementations of
664 * the Mapping<T> container API.
665 */
666 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
667 class Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::_IRep : public Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>::_IRep {
668 private:
669 using inherited = typename Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>::_IRep;
670
671 protected:
672 _IRep () = default;
673
674 public:
675 virtual ~_IRep () = default;
676
677 public:
678 virtual KeyEqualsCompareFunctionType GetKeyEqualsComparer () const = 0;
679 virtual shared_ptr<_IRep> CloneEmpty () const = 0;
680 virtual shared_ptr<_IRep> CloneAndPatchIterator (Iterator<value_type>* i) const = 0;
681 // always clear/set item, and ensure return value == item->IsValidItem());
682 // 'item' arg CAN be nullptr
683 virtual bool Lookup (ArgByValueType<KEY_TYPE> key, optional<mapped_type>* item) const = 0;
684 // return true if NEW mapping added (container enlarged) - if replaceExistingMapping we unconditionally update but can still return false
685 virtual bool Add (ArgByValueType<KEY_TYPE> key, ArgByValueType<mapped_type> newElt, AddReplaceMode addReplaceMode) = 0;
686 virtual bool RemoveIf (ArgByValueType<KEY_TYPE> key) = 0;
687 // if nextI is non-null, its filled in with the next item in iteration order after i (has been removed)
688 virtual void Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI) = 0;
689 virtual void Update (const Iterator<value_type>& i, ArgByValueType<mapped_type> newValue, Iterator<value_type>* nextI) = 0;
690 };
691
692 /**
693 * \brief Compare Mappings<>s for equality. Note this can be costly, as the Mappings are not necessarily in the same order.
694 *
695 * \note Not to be confused with GetKeyEqualsComparer () which compares KEY ELEMENTS of Mapping for equality.
696 */
697 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
698 template <typename VALUE_EQUALS_COMPARER>
699 struct Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer
700 : Common::ComparisonRelationDeclarationBase<Common::ComparisonRelationType::eEquals> {
701 constexpr EqualsComparer (const VALUE_EQUALS_COMPARER& valueEqualsComparer = {});
702 nonvirtual bool operator() (const Mapping& lhs, const Mapping& rhs) const;
703 [[no_unique_address]] VALUE_EQUALS_COMPARER fValueEqualsComparer;
704 };
705
706}
707
708/*
709 ********************************************************************************
710 ******************************* Implementation Details *************************
711 ********************************************************************************
712 */
713#include "Mapping.inl"
714
715#endif /*_Stroika_Foundation_Containers_Mapping_h_ */
Implementation detail for Mapping<T> implementors.
Definition Mapping.h:667
nonvirtual CONTAINER_OF_Key_T As() const
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
Definition Mapping.inl:190
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
Definition Mapping.inl:144
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
nonvirtual unsigned int AddAll(ITERABLE_OF_ADDABLE &&items, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual bool ContainsMappedValue(ArgByValueType< mapped_type > v, VALUE_EQUALS_COMPARER &&valueEqualsComparer={}) const
nonvirtual void Update(const Iterator< value_type > &i, ArgByValueType< mapped_type > newValue, Iterator< value_type > *nextI=nullptr)
Definition Mapping.inl:312
nonvirtual ArchetypeContainerType WithKeys(const CONTAINER_OF_KEYS &includeKeys) const
nonvirtual bool RemoveIf(ArgByValueType< key_type > key)
Remove the given item, if it exists. Return true if found and removed.
Definition Mapping.inl:237
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
'override' Iterable<>::Map () function so container template defaults to Mapping, and improve that ca...
nonvirtual void Remove(ArgByValueType< key_type > key)
Remove the given item (which must exist).
Definition Mapping.inl:225
typename inherited::value_type value_type
Definition Mapping.h:139
nonvirtual void RetainAll(const ITERABLE_OF_KEY_TYPE &items)
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
document requirements for a Mapping key
Definition Mapping.h:50
document requirements for a Mapping value
Definition Mapping.h:61
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
AddReplaceMode
Mode flag to say if Adding to a container replaces, or if the first addition wins.
Compare Mappings<>s for equality. Note this can be costly, as the Mappings are not necessarily in the...
Definition Mapping.h:700