Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
Bijection.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_Bijection_h_
5#define _Stroika_Foundation_Containers_Bijection_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <utility>
10
11#include "Stroika/Foundation/Common/Common.h"
13#include "Stroika/Foundation/Common/Concepts.h"
14#include "Stroika/Foundation/Common/KeyValuePair.h"
15#include "Stroika/Foundation/Containers/Common.h"
16#include "Stroika/Foundation/DataExchange/ValidationStrategy.h"
17#include "Stroika/Foundation/Execution/Exceptions.h"
19
20/*
21 * \file
22 *
23 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
24 *
25 * TODO:
26 *
27 * @todo Best backend I can think of would be two opposing maps (or hash tables). Discuss with
28 * Sterl to see if he can think of any way todo this that doesn't double the storage
29 * of a regular Mapping (without exhaustive search on lookup from range).
30 *
31 * But currently just a functional, proof-of-concept linked list implementation.
32 *
33 * @todo Consider adding templated for RemoveAllFromPreimage/RemoveAllFromImage
34 * taking containers or iterator ranges.
35 */
36
38
40 using Common::IEqualsComparer;
41 using Common::KeyValuePair;
42 using Traversal::IInputIterator;
43 using Traversal::IIterableOfTo;
44 using Traversal::Iterable;
45 using Traversal::Iterator;
46
47 class Bijection_Base {
48 public:
49 class InjectivityViolation : public Execution::RuntimeErrorException<> {
50 private:
51 using inherited = Execution::RuntimeErrorException<>;
52
53 public:
54 InjectivityViolation ();
55 };
56 };
57
58 /**
59 * \brief Bijection allows for the bijective (1-1) association of two elements.
60 *
61 * Bijection allows for the bijective (1-1) association of two elements. This means that one element
62 * of the domain maps to exactly one element of the range, and that one element of the range maps uniquely to
63 * one element of the domain, and these mappings happen in a way that the mapping is fully invertible.
64 *
65 * @see http://en.wikipedia.org/wiki/Bijection
66 *
67 * Design Notes:
68 * \note We used Iterable<pair<DOMAIN_TYPE,RANGE_TYPE>> instead of
69 * Iterable<KeyValuePairType<DOMAIN_TYPE,RANGE_TYPE>> because its completely symmetric - both
70 * directions the values are keys.
71 *
72 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
73 *
74 * \note Bijection could not inherit from Mapping<> because the semantics of Removing a value are incompatible,
75 * and because (depending on the policy we adopt about error checking for invalid value in add) - we can have legit
76 * behavior on a Mapping BE illegal on the Bijection<>
77 *
78 * \em Concrete Implementations:
79 * o @see Concrete::Bijection_LinkedList<>
80 *
81 * \em Factory:
82 * @see Bijection_Factory<> to see default implementations.
83 *
84 * \note See <a href="./ReadMe.md">ReadMe.md</a> for common features of all Stroika containers (especially
85 * constructors, iterators, etc)
86 *
87 * \note <a href="ReadMe.md#Container Element comparisons">Container Element comparisons</a>:
88 * See about ElementInOrderComparerType, ElementThreeWayComparerType and GetElementThreeWayComparer etc
89 *
90 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
91 * o static_assert (equality_comparable<Bijection<...>>);
92 *
93 * o All Bijections MUST have = comparable DOMAIN_TYPE and RANGE_TYPE, so operator== for the bijection is well-defined.
94 *
95 * Two Bijections are considered equal if they contain the same elements (Preimage) and each key is associated
96 * with the same value. There is no need for the items to appear in the same order for the two Bijections to
97 * be equal. There is no need for the backends to be of the same underlying representation either (STL map
98 * vers linked-list).
99 *
100 * Since a Bijection is not necessarily sorted, or in any particular order, < and > are not well defined.
101 */
102 template <typename DOMAIN_TYPE, typename RANGE_TYPE>
103 class Bijection : public Iterable<pair<DOMAIN_TYPE, RANGE_TYPE>>, public Bijection_Base {
104 private:
106
107 protected:
108 class _IRep;
109
110 public:
111 /**
112 * Use this typedef in templates to recover the basic functional container pattern of concrete types.
113 */
115
116 public:
117 /**
118 * @see inherited::value_type
119 */
121
122 public:
123 /**
124 */
125 using DomainType = DOMAIN_TYPE;
126
127 public:
128 /**
129 */
130 using RangeType = RANGE_TYPE;
131
132 public:
133 /**
134 * This is the type returned by GetDomainEqualsComparer () and CAN be used as the argument to a Bijection<> as EqualityComparer, but
135 * we allow any template in the Bijection<> CTOR for an equalityComparer that follows the Common::IEqualsComparer concept.
136 */
138 Common::ComparisonRelationDeclaration<Common::ComparisonRelationType::eEquals, function<bool (ArgByValueType<DomainType>, ArgByValueType<DomainType>)>>;
139 static_assert (IEqualsComparer<DomainEqualsCompareFunctionType, DomainType>);
140
141 public:
142 /**
143 * This is the type returned by GetRangeEqualsComparer () and CAN be used as the argument to a Bijection<> as EqualityComparer, but
144 * we allow any template in the Bijection<> CTOR for an equalityComparer that follows the IEqualsComparer concept
145 */
147 Common::ComparisonRelationDeclaration<Common::ComparisonRelationType::eEquals, function<bool (RangeType, RangeType)>>;
148 static_assert (IEqualsComparer<RangeEqualsCompareFunctionType, RangeType>);
149
150 public:
151 /**
152 * This constructor creates a concrete Bijection object, either empty, or initialized with any argument
153 * values.
154 *
155 * The underlying data structure of the Bijection is defined by @see Factory::Bijection_Factory<>
156 *
157 * \note The constructor arguments DOMAIN_EQUALS_COMPARER or RANGE_EQUALS_COMPARER must be declared to be equals_comparers, to avoid
158 * ambiguity/accidental mix-ups between inorder and equals (or three way) comparers. Consider wrapping lambdas with Common::DeclareEqualsComparer
159 *
160 * \note <a href="ReadMe.md#Container Constructors">See general information about container constructors that applies here</a>
161 */
162 Bijection ()
163 requires (IEqualsComparer<equal_to<DOMAIN_TYPE>, DOMAIN_TYPE> and IEqualsComparer<equal_to<RANGE_TYPE>, RANGE_TYPE>);
164 template <IEqualsComparer<DOMAIN_TYPE> DOMAIN_EQUALS_COMPARER, IEqualsComparer<RANGE_TYPE> RANGE_EQUALS_COMPARER>
165 explicit Bijection (DOMAIN_EQUALS_COMPARER&& domainEqualsComparer, RANGE_EQUALS_COMPARER&& rangeEqualsComparer);
166 template <IEqualsComparer<DOMAIN_TYPE> DOMAIN_EQUALS_COMPARER, IEqualsComparer<RANGE_TYPE> RANGE_EQUALS_COMPARER>
167 explicit Bijection (DataExchange::ValidationStrategy injectivityCheckPolicy, DOMAIN_EQUALS_COMPARER&& domainEqualsComparer,
168 RANGE_EQUALS_COMPARER&& rangeEqualsComparer);
169 Bijection (Bijection&&) noexcept = default;
170 Bijection (const Bijection&) noexcept = default;
171 Bijection (const initializer_list<value_type>& src)
172 requires (IEqualsComparer<equal_to<DOMAIN_TYPE>, DOMAIN_TYPE> and IEqualsComparer<equal_to<RANGE_TYPE>, RANGE_TYPE>);
173 template <IEqualsComparer<DOMAIN_TYPE> DOMAIN_EQUALS_COMPARER, IEqualsComparer<RANGE_TYPE> RANGE_EQUALS_COMPARER>
174 Bijection (DOMAIN_EQUALS_COMPARER&& domainEqualsComparer, RANGE_EQUALS_COMPARER&& rangeEqualsComparer, const initializer_list<value_type>& src);
175 template <IIterableOfTo<KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>> ITERABLE_OF_ADDABLE>
176 explicit Bijection (ITERABLE_OF_ADDABLE&& src)
177 requires (not derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, Bijection<DOMAIN_TYPE, RANGE_TYPE>>)
178#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
179 : Bijection{}
180 {
181 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
182 _AssertRepValidType ();
183 }
184#endif
185 ;
186 template <IEqualsComparer<DOMAIN_TYPE> DOMAIN_EQUALS_COMPARER, IEqualsComparer<RANGE_TYPE> RANGE_EQUALS_COMPARER, IIterableOfTo<KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>> ITERABLE_OF_ADDABLE>
187 Bijection (DOMAIN_EQUALS_COMPARER&& domainEqualsComparer, RANGE_EQUALS_COMPARER&& rangeEqualsComparer, ITERABLE_OF_ADDABLE&& src);
188 template <IInputIterator<KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
189 Bijection (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
190 requires (IEqualsComparer<equal_to<DOMAIN_TYPE>, DOMAIN_TYPE> and IEqualsComparer<equal_to<RANGE_TYPE>, RANGE_TYPE>);
191 template <IEqualsComparer<DOMAIN_TYPE> DOMAIN_EQUALS_COMPARER, IEqualsComparer<RANGE_TYPE> RANGE_EQUALS_COMPARER,
192 IInputIterator<KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
193 Bijection (DOMAIN_EQUALS_COMPARER&& domainEqualsComparer, RANGE_EQUALS_COMPARER&& rangeEqualsComparer, ITERATOR_OF_ADDABLE&& start,
194 ITERATOR_OF_ADDABLE2&& end);
195
196 protected:
197 explicit Bijection (shared_ptr<_IRep>&& src) noexcept;
198 explicit Bijection (const shared_ptr<_IRep>& src) noexcept;
199
200 public:
201 /**
202 */
203 nonvirtual Bijection& operator= (Bijection&&) noexcept = default;
204 nonvirtual Bijection& operator= (const Bijection&) = default;
205
206 public:
207 /**
208 */
209 nonvirtual DomainEqualsCompareFunctionType GetDomainEqualsComparer () const;
210
211 public:
212 /**
213 */
214 nonvirtual RangeEqualsCompareFunctionType GetRangeEqualsComparer () const;
215
216 public:
217 /**
218 * Preimage () returns an Iterable object with just the domain (first) part of the Bijection.
219 *
220 * Note this method may not return a collection which is sorted. Note also, the
221 * returned value is a copy of the keys (by value) - at least logically (implementations
222 * maybe smart enough to use lazy copying).
223 *
224 * Note the returned Iterable is detached from the original, and doesn't see any changes
225 * to it, and its lifetime is like a copy of a shared_ptr - lasts as long as the
226 * reference.
227 *
228 * \em Design Note:
229 * The analagous method in C#.net - Dictionary<TKey, TValue>.KeyCollection
230 * (http://msdn.microsoft.com/en-us/library/yt2fy5zk(v=vs.110).aspx) returns a live reference
231 * to the underlying keys. We could have (fairly easily) done that, but I didn't see the point.
232 *
233 * In .net, the typical model is that you have a pointer to an object, and pass around that
234 * pointer (so by reference semantics) - so this returning a live reference makes more sense there.
235 *
236 * Since Stroika containers are logically copy-by-value (even though lazy-copied), it made more
237 * sense to apply that lazy-copy (copy-on-write) paradigm here, and make the returned set of
238 * keys a logical copy at the point 'keys' is called.
239 */
240 nonvirtual Iterable<DomainType> Preimage () const;
241
242 public:
243 /**
244 * Image () returns an Iterable object with just the range part of the Bijection.
245 *
246 * Note this method may not return a collection which is sorted. Note also, the
247 * returned value is a copy of the rangle (by value) - at least logically (implementations
248 * maybe smart enough to use lazy copying).
249 *
250 * Note the returned Iterable is detached from the original, and doesn't see any changes
251 * to it, and its lifetime is like a copy of a shared_ptr - lasts as long as the
252 * reference.
253 *
254 * \em Design Note:
255 * The analagous method in C#.net - Dictionary<TKey, TValue>.KeyCollection
256 * (https://msdn.microsoft.com/en-us/library/ekcfxy3x(v=vs.110).aspx) returns a live reference
257 * to the underlying values. We could have (fairly easily) done that, but I didn't see the point.
258 *
259 * In .net, the typical model is that you have a pointer to an object, and pass around that
260 * pointer (so by reference semantics) - so this returning a live reference makes more sense there.
261 *
262 * Since Stroika containers are logically copy-by-value (even though lazy-copied), it made more
263 * sense to apply that lazy-copy (copy-on-write) paradigm here, and make the returned set of
264 * keys a logical copy at the point 'keys' is called.
265 */
266 nonvirtual Iterable<RangeType> Image () const;
267
268 public:
269 /**
270 * Note - as since Lookup/1 returns an optional<T> - it can be used very easily to provide
271 * a default value on Lookup (so for case where not present) - as in:
272 * returm m.Lookup (key).Value (putDefaultValueHere);
273 *
274 * Note - for both overloads taking an item pointer, the pointer may be nullptr (in which case not assigned to).
275 * But if present, will always be assigned to if Lookup returns true (found). And for the optional overload
276 * \pre Ensure (item == nullptr or returnValue == item->has_value());
277 *
278 * @aliases Lookup (key, RangeType* value) - is equivalent to .Net TryGetValue ()
279 *
280 * @see LookupValue ()
281 * @see InverseLookup ()
282 * @see InverseLookupValue ()
283 */
284 nonvirtual optional<RangeType> Lookup (ArgByValueType<DomainType> key) const;
285 nonvirtual bool Lookup (ArgByValueType<DomainType> key, optional<RangeType>* item) const;
286 nonvirtual bool Lookup (ArgByValueType<DomainType> key, RangeType* item) const;
287 nonvirtual bool Lookup (ArgByValueType<DomainType> key, nullptr_t) const;
288
289 public:
290 /**
291 * Always safe to call. If result empty/missing, returns argument 'default' or 'sentinel' value.
292 *
293 * @see Lookup ()
294 * @see InverseLookup ()
295 * @see InverseLookupValue ()
296 */
297 nonvirtual RangeType LookupValue (ArgByValueType<DomainType> key, ArgByValueType<RangeType> defaultValue = RangeType ()) const;
298
299 public:
300 /**
301 * Note - as since InverseLookup/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 * returm m.InverseLookup (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 * @see Lookup ()
310 * @see LookupValue ()
311 * @see InverseLookupValue ()
312 */
313 nonvirtual optional<DomainType> InverseLookup (ArgByValueType<RangeType> key) const;
314 nonvirtual bool InverseLookup (ArgByValueType<RangeType> key, optional<DomainType>* item) const;
315 nonvirtual bool InverseLookup (ArgByValueType<RangeType> key, DomainType* item) const;
316 nonvirtual bool InverseLookup (ArgByValueType<RangeType> key, nullptr_t) const;
317
318 public:
319 /**
320 * Always safe to call. If result empty/missing, returns argument 'default' or 'sentinel' value.
321 *
322 * @see Lookup ()
323 * @see LookupValue ()
324 * @see InverseLookup ()
325 */
326 nonvirtual DomainType InverseLookupValue (ArgByValueType<RangeType> key, ArgByValueType<DomainType> defaultValue = DomainType ()) const;
327
328 public:
329 /**
330 * For each value in the source set, map it back using the bijection to the target set.
331 * \pre that each element be present in the bijection
332 */
333 nonvirtual Iterable<RangeType> MapToRange (const Iterable<DomainType>& values) const;
334
335 public:
336 /**
337 * For each value in the source set, map it back using the bijection to the target set.
338 * \pre that each element be present in the bijection
339 */
340 nonvirtual Iterable<DomainType> MapToDomain (const Iterable<RangeType>& values) const;
341
342 public:
343 /**
344 * \brief 'override' Iterable<>::Map () function so RESULT_CONTAINER defaults to Bijection, and improve that case to clone properties from this rep (such is rep type, etc).
345 */
346 template <typename RESULT_CONTAINER = Bijection<DOMAIN_TYPE, RANGE_TYPE>, invocable<pair<DOMAIN_TYPE, RANGE_TYPE>> ELEMENT_MAPPER>
347 nonvirtual RESULT_CONTAINER Map (ELEMENT_MAPPER&& elementMapper) const
348 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, pair<DOMAIN_TYPE, RANGE_TYPE>>, typename RESULT_CONTAINER::value_type> or
349 convertible_to<invoke_result_t<ELEMENT_MAPPER, pair<DOMAIN_TYPE, RANGE_TYPE>>, optional<typename RESULT_CONTAINER::value_type>>);
350
351 public:
352 /**
353 * \brief Like Iterable<T>::Where, but returning a bijection - subset of this bijection where includeIfTrue is true
354 */
355 template <derived_from<Iterable<pair<DOMAIN_TYPE, RANGE_TYPE>>> RESULT_CONTAINER = Bijection<DOMAIN_TYPE, RANGE_TYPE>, predicate<pair<DOMAIN_TYPE, RANGE_TYPE>> INCLUDE_PREDICATE>
356 nonvirtual RESULT_CONTAINER Where (INCLUDE_PREDICATE&& includeIfTrue) const;
357
358 public:
359 /**
360 * essentially 'intersect but just comparing domain'
361 */
362 nonvirtual Bijection WhereDomainIntersects (const Iterable<DomainType>& domainValues) const;
363
364 public:
365 /**
366 * essentially 'intersect but just comparing range'
367 */
368 nonvirtual Bijection WhereRangeIntersects (const Iterable<RangeType>& rangeValues) const;
369
370 public:
371 /**
372 * Synonym for (Lookup (v).has_value ()) or Preimage ().Contains (v)
373 */
374 nonvirtual bool ContainsDomainElement (ArgByValueType<DomainType> key) const;
375
376 public:
377 /**
378 * Synonym for (InverseLookup (v).has_value ()) or Image ().Contains (v)
379 */
380 nonvirtual bool ContainsRangeElement (ArgByValueType<RangeType> v) const;
381
382 public:
383 /**
384 * Add the association between key and newElt. If key was already associated with something
385 * else, the association is silently updated, and the size of the iterable does not change.
386 * Also - we guarantee that even if the association is different, if the key has not changed,
387 * then the iteration order is not changed (helpful for AddAll() semantics, and perhaps elsewhere).
388 *
389 * \note mutates container
390 */
391 nonvirtual void Add (ArgByValueType<DomainType> key, ArgByValueType<RangeType> newElt);
392 template <typename ADDABLE_T>
393 nonvirtual void Add (ADDABLE_T&& p)
394 requires (convertible_to<ADDABLE_T, pair<DOMAIN_TYPE, RANGE_TYPE>> or convertible_to<ADDABLE_T, KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>>);
395
396 public:
397 /**
398 * \@aliases .net AddRange ()
399 *
400 * \note mutates container
401 */
402 template <IIterableOfTo<KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>> CONTAINER_OF_KEYVALUE>
403 nonvirtual void AddAll (const CONTAINER_OF_KEYVALUE& items);
404 template <IInputIterator<KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>> COPY_FROM_ITERATOR_KEYVALUE, sentinel_for<remove_cvref_t<COPY_FROM_ITERATOR_KEYVALUE>> COPY_FROM_ITERATOR_KEYVALUE2>
405 nonvirtual void AddAll (COPY_FROM_ITERATOR_KEYVALUE&& start, COPY_FROM_ITERATOR_KEYVALUE2&& end);
406
407 public:
408 /**
409 * \note mutates container
410 *
411 * \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)
412 */
413 nonvirtual void Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI = nullptr);
414
415 public:
416 /**
417 * This removes any mapping from 'd' to anything. It is not an error if 'd' isn not already in the domain.
418 *
419 * \note mutates container
420 */
421 nonvirtual void RemoveDomainElement (ArgByValueType<DomainType> d);
422
423 public:
424 /**
425 * This removes any mapping from anything to 'r'. It is not an error if 'r' isn not already in the range.
426 *
427 * \note mutates container
428 */
429 nonvirtual void RemoveRangeElement (ArgByValueType<RangeType> r);
430
431 public:
432 /**
433 * \brief RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items.
434 *
435 * The no-arg overload removes all (quickly).
436 *
437 * The overloads that remove some subset of the items returns the number of items so removed.
438 *
439 * \note mutates container
440 */
441 nonvirtual void RemoveAll ();
442 template <predicate<pair<DOMAIN_TYPE, RANGE_TYPE>> PREDICATE>
443 nonvirtual size_t RemoveAll (PREDICATE&& p);
444
445 public:
446 /*
447 * Return a mapping - in the reverse direction (a Bijection is (restricted) form of mapping. The type of
448 * TARGET_CONTAINER can be either a Bijection (in the opposite direction as the source), or
449 * A Mapping<> (also in the reverse direction).
450 *
451 * Note - this returns a copy (by value) of this Bijections data.
452 */
453 template <typename TARGET_CONTAINER = Bijection<RangeType, DomainType>>
454 nonvirtual TARGET_CONTAINER Inverse () const;
455
456 public:
457 /**
458 * This function should work for any container which accepts
459 * (ITERATOR_OF<pair<Key,Value>>,ITERATOR_OF<pair<Key,Value>>).
460 *
461 * These As<> overloads also may require the presence of an insert(ITERATOR, Value) method
462 * of CONTAINER_OF_Key_T.
463 *
464 * So - for example, Sequence<pair<DomainType,RangeType>>, map<DomainType,RangeType>,
465 * vector<pair<DomainType,RangeType>>, etc...
466 *
467 * This works for:
468 * o Mapping<DOMAIN_TYPE, RANGE_TYPE>
469 * o map<DOMAIN_TYPE, RANGE_TYPE>
470 * o vector<pair<DOMAIN_TYPE, RANGE_TYPE>>
471 * o Sequence<pair<DOMAIN_TYPE, RANGE_TYPE>>
472 */
473 template <typename CONTAINER_PAIR_RANGE_DOMAIN>
474 nonvirtual CONTAINER_PAIR_RANGE_DOMAIN As () const;
475
476 public:
477 /**
478 * Note - this computation MAYBE very expensive, and not optimized (maybe do better in a future release - see TODO).
479 *
480 * @todo - document computational complexity
481 *
482 * \note Not to be confused with EqualityComparerType and GetEqualsComparer () which compares ELEMENTS of Bijection<> for equality.
483 */
484 nonvirtual bool operator== (const Bijection& rhs) const;
485
486 public:
487 /**
488 * @aliases RemoveAll ().
489 *
490 * \note mutates container
491 */
492 nonvirtual void clear ();
493
494 public:
495 /**
496 * \brief STL-ish alias for Remove ().
497 *
498 * \note mutates container
499 */
500 nonvirtual Iterator<value_type> erase (const Iterator<value_type>& i);
501
502 public:
503 /**
504 *
505 * \note mutates container
506 */
507 template <IIterableOfTo<KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>> ITERABLE_OF_ADDABLE>
508 nonvirtual Bijection& operator+= (const ITERABLE_OF_ADDABLE& items);
509
510 public:
511 /**
512 *
513 * \note mutates container
514 */
515 template <IIterableOfTo<KeyValuePair<DOMAIN_TYPE, RANGE_TYPE>> ITERABLE_OF_ADDABLE>
516 nonvirtual Bijection& operator-= (const ITERABLE_OF_ADDABLE& items);
517
518 protected:
519 /**
520 * \brief Utility to get WRITABLE underlying shared_ptr (replacement for what we normally do - _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ())
521 * but where we also handle the cloning/patching of the associated iterator
522 *
523 * When you have a non-const operation (such as Remove) with an argument of an Iterator<>, then due to COW,
524 * you may end up cloning the container rep, and yet the Iterator<> contains a pointer to the earlier rep (and so maybe unusable).
525 *
526 * Prior to Stroika 2.1b14, this was handled elegantly, and automatically, by the iterator patching mechanism. But that was deprecated (due to cost, and
527 * rarity of use), in favor of this more restricted feature, where we just patch the iterators on an as-needed basis.
528 *
529 * \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)
530 */
532
533 protected:
534 /**
535 */
536 template <typename T2>
537 using _SafeReadRepAccessor = typename Iterable<value_type>::template _SafeReadRepAccessor<T2>;
538
539 protected:
540 /**
541 */
542 template <typename T2>
543 using _SafeReadWriteRepAccessor = typename inherited::template _SafeReadWriteRepAccessor<T2>;
544
545 protected:
546 nonvirtual void _AssertRepValidType () const;
547
548 public:
549 nonvirtual [[deprecated ("String Stroika v3.0d1, Name deprecated - use MapToRange")]] Iterable<RangeType> Map (const Iterable<DomainType>& values) const
550 {
551 return MapToRange (values);
552 }
553 nonvirtual [[deprecated ("String Stroika v3.0d1, Name deprecated - use MapToRange")]] Iterable<DomainType>
554 InverseMap (const Iterable<RangeType>& values) const
555 {
556 return MapToDomain (values);
557 }
558 };
559
560 /**
561 * \brief Implementation detail for Bijection<T> implementors.
562 *
563 * Protected abstract interface to support concrete implementations of
564 * the Bijection<T> container API.
565 */
566 template <typename DOMAIN_TYPE, typename RANGE_TYPE>
567 class Bijection<DOMAIN_TYPE, RANGE_TYPE>::_IRep : public Iterable<pair<DOMAIN_TYPE, RANGE_TYPE>>::_IRep {
568 private:
569 using inherited = typename Iterable<value_type>::_IRep;
570
571 protected:
572 _IRep () = default;
573
574 public:
575 virtual ~_IRep () = default;
576
577 public:
578 virtual shared_ptr<_IRep> CloneEmpty () const = 0;
579 virtual shared_ptr<_IRep> CloneAndPatchIterator (Iterator<value_type>* i) const = 0;
580 virtual bool Equals (const _IRep& rhs) const = 0;
581 virtual DomainEqualsCompareFunctionType GetDomainEqualsComparer () const = 0;
582 virtual RangeEqualsCompareFunctionType GetRangeEqualsComparer () const = 0;
583 // always clear/set item, and ensure return value == item->IsValidItem());
584 // 'item' arg CAN be nullptr
585 virtual bool Lookup (ArgByValueType<DOMAIN_TYPE> key, optional<RangeType>* item) const = 0;
586 virtual bool InverseLookup (ArgByValueType<RANGE_TYPE> key, optional<DomainType>* item) const = 0;
587 virtual void Add (ArgByValueType<DOMAIN_TYPE> key, ArgByValueType<RANGE_TYPE> newElt) = 0;
588 virtual void RemoveDomainElement (ArgByValueType<DOMAIN_TYPE> d) = 0;
589 virtual void RemoveRangeElement (ArgByValueType<RANGE_TYPE> r) = 0;
590 virtual void Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI) = 0;
591
592 /*
593 * Reference Implementations (often not used except for ensure's, but can be used for
594 * quickie backends).
595 *
596 * Importantly, these are all non-virtual so not actually pulled in or even compiled unless
597 * the sucblass refers to the method in a subclass virtual override.
598 */
599 protected:
600 nonvirtual bool _Equals_Reference_Implementation (const _IRep& rhs) const;
601 };
602
603}
604
605/*
606 ********************************************************************************
607 ******************************* Implementation Details *************************
608 ********************************************************************************
609 */
610#include "Bijection.inl"
611
612#endif /*_Stroika_Foundation_Containers_Bijection_h_ */
Implementation detail for Bijection<T> implementors.
Definition Bijection.h:567
Bijection allows for the bijective (1-1) association of two elements.
Definition Bijection.h:103
nonvirtual void RemoveDomainElement(ArgByValueType< DomainType > d)
Common::ComparisonRelationDeclaration< Common::ComparisonRelationType::eEquals, function< bool(ArgByValueType< DomainType >, ArgByValueType< DomainType >)> > DomainEqualsCompareFunctionType
Definition Bijection.h:138
nonvirtual void RemoveAll()
RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items...
nonvirtual Iterable< DomainType > MapToDomain(const Iterable< RangeType > &values) const
nonvirtual Iterator< value_type > erase(const Iterator< value_type > &i)
STL-ish alias for Remove ().
nonvirtual void RemoveRangeElement(ArgByValueType< RangeType > r)
nonvirtual Bijection WhereDomainIntersects(const Iterable< DomainType > &domainValues) const
nonvirtual void Remove(const Iterator< value_type > &i, Iterator< value_type > *nextI=nullptr)
Common::ComparisonRelationDeclaration< Common::ComparisonRelationType::eEquals, function< bool(RangeType, RangeType)> > RangeEqualsCompareFunctionType
Definition Bijection.h:147
nonvirtual Bijection WhereRangeIntersects(const Iterable< RangeType > &rangeValues) const
nonvirtual CONTAINER_PAIR_RANGE_DOMAIN As() const
nonvirtual Iterable< DomainType > Preimage() const
nonvirtual void Add(ArgByValueType< DomainType > key, ArgByValueType< RangeType > newElt)
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
Like Iterable<T>::Where, but returning a bijection - subset of this bijection where includeIfTrue is ...
nonvirtual optional< DomainType > InverseLookup(ArgByValueType< RangeType > key) const
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
'override' Iterable<>::Map () function so RESULT_CONTAINER defaults to Bijection, and improve that ca...
typename inherited::value_type value_type
Definition Bijection.h:120
nonvirtual Iterable< RangeType > MapToRange(const Iterable< DomainType > &values) const
nonvirtual DomainType InverseLookupValue(ArgByValueType< RangeType > key, ArgByValueType< DomainType > defaultValue=DomainType()) const
nonvirtual optional< RangeType > Lookup(ArgByValueType< DomainType > key) const
nonvirtual bool ContainsRangeElement(ArgByValueType< RangeType > v) const
nonvirtual Iterable< RangeType > Image() const
nonvirtual RangeType LookupValue(ArgByValueType< DomainType > key, ArgByValueType< RangeType > defaultValue=RangeType()) const
nonvirtual bool ContainsDomainElement(ArgByValueType< DomainType > key) const
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 void AddAll(const CONTAINER_OF_KEYVALUE &items)
Implementation detail for iterator implementors.
Definition Iterable.h:1576
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:250
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: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