Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Mapping.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4
5/*
6 ********************************************************************************
7 ***************************** Implementation Details ***************************
8 ********************************************************************************
9 */
14
16
17 /*
18 ********************************************************************************
19 ******************** Mapping<KEY_TYPE, MAPPED_VALUE_TYPE> **********************
20 ********************************************************************************
21 */
22 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
24 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>)
25 : Mapping{equal_to<KEY_TYPE>{}}
26 {
27 _AssertRepValidType ();
28 }
29 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
30 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER>
31 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer)
32 : inherited{Factory::Mapping_Factory<KEY_TYPE, MAPPED_VALUE_TYPE, remove_cvref_t<KEY_EQUALS_COMPARER>>::Default () (
33 forward<KEY_EQUALS_COMPARER> (keyEqualsComparer))}
34 {
35 _AssertRepValidType ();
36 }
37 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
38 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (const initializer_list<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& src)
39 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>)
40 : Mapping{}
41 {
42 AddAll (src);
43 _AssertRepValidType ();
44 }
45 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
46 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER>
47 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer,
48 const initializer_list<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& src)
49 : Mapping{forward<KEY_EQUALS_COMPARER> (keyEqualsComparer)}
50 {
51 AddAll (src);
52 _AssertRepValidType ();
53 }
54#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
55 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
56 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
57 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (ITERABLE_OF_ADDABLE&& src)
58 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE> and
59 not derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>>)
60 : Mapping{}
61 {
62 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
63 _AssertRepValidType ();
64 }
65#endif
66 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
67 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER, IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
68 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer, ITERABLE_OF_ADDABLE&& src)
69 : Mapping{forward<KEY_EQUALS_COMPARER> (keyEqualsComparer)}
70 {
72 _AssertRepValidType ();
73 }
74 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
75 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
76 Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
77 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>)
78 : Mapping{}
79 {
80 AddAll (forward<ITERATOR_OF_ADDABLE> (start), forward<ITERATOR_OF_ADDABLE2> (end));
81 _AssertRepValidType ();
82 }
83 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
84 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER, IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE,
85 sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
86 Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer, ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
87 : Mapping{forward<KEY_EQUALS_COMPARER> (keyEqualsComparer)}
88 {
90 _AssertRepValidType ();
91 }
92 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
93 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (const shared_ptr<_IRep>& rep) noexcept
94 : inherited{rep}
95 {
96 RequireNotNull (rep);
97 _AssertRepValidType ();
98 }
99 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
100 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (shared_ptr<_IRep>&& rep) noexcept
101 : inherited{(RequireExpression (rep != nullptr), move (rep))}
102 {
103 _AssertRepValidType ();
104 }
105 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
106 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::GetKeyEqualsComparer () const -> KeyEqualsCompareFunctionType
107 {
108 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().GetKeyEqualsComparer ();
109 }
110 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
112 {
113 return this->template Map<Iterable<KEY_TYPE>> ([] (const KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>& kvp) { return kvp.fKey; });
114 }
115 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
117 {
118 return this->template Map<Iterable<MAPPED_VALUE_TYPE>> (
119 [] (const KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>& kvp) { return kvp.fValue; });
120 }
121 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
122 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key, mapped_type* item) const
123 {
124 if (item == nullptr) {
125 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, nullptr);
126 }
127 else {
128 optional<mapped_type> tmp;
129 if (_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, &tmp)) {
130 *item = *tmp;
131 return true;
132 }
133 return false;
134 }
135 }
136 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
137 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key, optional<mapped_type>* item) const
138 {
139 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, item);
140 }
141 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
142 inline optional<MAPPED_VALUE_TYPE> Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key) const
143 {
144 optional<MAPPED_VALUE_TYPE> r;
145 [[maybe_unused]] bool result = _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, &r);
146 Ensure (result == r.has_value ());
147 return r;
148 }
149 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
150 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key, nullptr_t) const
151 {
152 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, nullptr);
153 }
154 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
155 template <typename THROW_IF_MISSING>
156 inline MAPPED_VALUE_TYPE Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::LookupChecked (ArgByValueType<key_type> key, const THROW_IF_MISSING& throwIfMissing) const
157 {
158 if (optional<MAPPED_VALUE_TYPE> r{Lookup (key)}) [[likely]] {
159 return *r;
160 }
161 Execution::Throw (throwIfMissing);
162 }
163 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
164 inline MAPPED_VALUE_TYPE Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::LookupValue (ArgByValueType<key_type> key, ArgByValueType<mapped_type> defaultValue) const
165 {
166 optional<MAPPED_VALUE_TYPE> r{Lookup (key)};
167 return r.has_value () ? *r : defaultValue;
168 }
169 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
170 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::operator[] (ArgByValueType<key_type> key) const -> add_const_t<mapped_type>
171 {
172 return *Lookup (key);
173 }
174 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
175 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::ContainsKey (ArgByValueType<key_type> key) const
176 {
177 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, nullptr);
178 }
179 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
180 template <typename VALUE_EQUALS_COMPARER>
181 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::ContainsMappedValue (ArgByValueType<mapped_type> v, VALUE_EQUALS_COMPARER&& valueEqualsComparer) const
182 {
183 return this->Find ([&valueEqualsComparer, &v] (const auto& t) { return valueEqualsComparer (t.fValue, v); }) != nullptr;
184 }
185 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
186 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Add (ArgByValueType<key_type> key, ArgByValueType<mapped_type> newElt, AddReplaceMode addReplaceMode)
187 {
188 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (key, newElt, addReplaceMode);
189 }
190 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
191 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Add (ArgByValueType<value_type> p, AddReplaceMode addReplaceMode)
192 {
193 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (p.fKey, p.fValue, addReplaceMode);
195 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
196 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
197 unsigned int Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::AddAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end, AddReplaceMode addReplaceMode)
198 {
199 unsigned int cntAdded{};
200 for (auto i = forward<ITERATOR_OF_ADDABLE> (start); i != forward<ITERATOR_OF_ADDABLE2> (end); ++i) {
201 if (Add (*i, addReplaceMode)) {
202 ++cntAdded;
203 }
204 }
205 return cntAdded;
206 }
207 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
208 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
209 inline unsigned int Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::AddAll (ITERABLE_OF_ADDABLE&& items, AddReplaceMode addReplaceMode)
210 {
211 if constexpr (std::is_convertible_v<remove_cvref_t<ITERABLE_OF_ADDABLE>*, Iterable<value_type>*>) {
212 // very rare corner case
213 if (static_cast<const Iterable<value_type>*> (this) == static_cast<const Iterable<value_type>*> (&items)) [[unlikely]] {
214 vector<value_type> copy{std::begin (items), Iterator<value_type>{std::end (items)}}; // because you can not iterate over a container while modifying it
215 return AddAll (std::begin (copy), std::end (copy), addReplaceMode);
216 }
217 }
218 return AddAll (std::begin (items), std::end (items), addReplaceMode);
219 }
220 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
221 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Remove (ArgByValueType<key_type> key)
222 {
223 Verify (_SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (key)); // use RemoveIf () if key may not exist
224 }
225 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
227 {
228 Require (not i.AtEnd ());
229 auto [writerRep, patchedIterator] = _GetWritableRepAndPatchAssociatedIterator (i);
230 writerRep->Remove (patchedIterator, nextI);
231 }
232 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
233 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveIf (ArgByValueType<key_type> key)
234 {
235 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (key);
236 }
237 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
239 {
240 _SafeReadRepAccessor<_IRep> accessor{this}; // important to use READ not WRITE accessor, because write accessor would have already cloned the data
241 if (not accessor._ConstGetRep ().empty ()) {
242 this->_fRep = accessor._ConstGetRep ().CloneEmpty ();
243 }
244 }
245 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
246 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
247 size_t Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveAll (const ITERABLE_OF_KEY_OR_ADDABLE& items)
248 requires (IIterableOfTo<ITERABLE_OF_KEY_OR_ADDABLE, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> or
249 IIterableOfTo<ITERABLE_OF_KEY_OR_ADDABLE, pair<KEY_TYPE, MAPPED_VALUE_TYPE>> or IIterableOfTo<ITERABLE_OF_KEY_OR_ADDABLE, KEY_TYPE>)
250 {
251 using ITEM_T = ranges::range_value_t<ITERABLE_OF_KEY_OR_ADDABLE>;
252 static_assert (is_convertible_v<ITEM_T, key_type> or is_convertible_v<ITEM_T, pair<key_type, mapped_type>> or
253 is_convertible_v<ITEM_T, KeyValuePair<key_type, mapped_type>>);
254 if constexpr (convertible_to<const Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>*, const ITERABLE_OF_KEY_OR_ADDABLE*>) {
255 if (this == &items) { // avoid modifying container while iterating over it
256 size_t result = this->size ();
257 RemoveAll ();
258 return result;
259 }
260 }
261 return this->RemoveAll (begin (items), end (items));
262 }
263 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
264 template <typename ITERATOR_OF_KEY_OR_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_KEY_OR_ADDABLE>> ITERATOR_OF_KEY_OR_ADDABLE2>
265 inline size_t Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveAll (ITERATOR_OF_KEY_OR_ADDABLE&& start, ITERATOR_OF_KEY_OR_ADDABLE2&& end)
266 {
267 using ITEM_T = iter_value_t<ITERATOR_OF_KEY_OR_ADDABLE>;
268 static_assert (is_convertible_v<ITEM_T, key_type> or is_convertible_v<ITEM_T, pair<key_type, mapped_type>> or
269 is_convertible_v<ITEM_T, KeyValuePair<key_type, mapped_type>>);
270 size_t cnt{};
271 for (auto i = start; i != end; ++i) {
272 if constexpr (is_convertible_v<ITEM_T, key_type>) {
273 if (RemoveIf (*i)) {
274 ++cnt;
275 }
276 }
277 else if constexpr (is_convertible_v<ITEM_T, pair<key_type, mapped_type>>) {
278 if (RemoveIf (i->first)) {
279 ++cnt;
280 }
281 }
282 else if constexpr (is_convertible_v<ITEM_T, KeyValuePair<key_type, mapped_type>>) {
283 if (RemoveIf (i->fKey)) {
284 ++cnt;
285 }
286 }
287 else {
289 }
290 }
291 return cnt;
292 }
293 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
294 template <predicate<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> PREDICATE>
296 {
297 size_t nRemoved{};
298 for (Iterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> i = this->begin (); i != this->end ();) {
299 if (p (*i)) {
300 Remove (i, &i);
301 ++nRemoved;
302 }
303 else {
304 ++i;
305 }
306 }
307 return nRemoved;
308 }
309 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
310 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Update (const Iterator<value_type>& i, ArgByValueType<mapped_type> newValue,
312 {
313 Require (not i.AtEnd ());
314 auto [writerRep, patchedIterator] = _GetWritableRepAndPatchAssociatedIterator (i);
315 writerRep->Update (patchedIterator, newValue, nextI);
317 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
318 template <IIterableOfTo<KEY_TYPE> ITERABLE_OF_KEY_TYPE>
319 void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RetainAll (const ITERABLE_OF_KEY_TYPE& items)
320 {
321 /*
322 * If items is smaller than this->size(), probably best to just remove one or two things from this
323 * (small number of lookups, and maybe no changes).
324 *
325 * If items is large, probably best to just create the entire mapping anew (cuz probably
326 * producing much smaller map).
327 *
328 * And both approaches avoid needing to quickly search through items repeatedly (except
329 * when we know items is small so no cost).
330 *
331 * NOT too worried about optimizing this code - but really quite unsure about this analysis of which way is faster.
332 * --LGP 2025-04-01
333 */
334 size_t thisSize = this->size ();
335
336 // Small case - just remove a few items
337 bool fewerLookupsThanAdds = items.size () <= 2;
338 if (fewerLookupsThanAdds) {
339 // Algorithm COMP COMPLEXITY VERY ROUHLTY apx= (O(Items-N) * O(THIS_LEN-N)) bad estimate cuz ignores cost of erases
340 auto keyEqualsComparer = this->GetKeyEqualsComparer ();
341 using ITEMS_ITER_TYPE = decltype (items.begin ()); // because of new ranges (c++20) code - sentinel but find_if only templated on one iter parameter
342 for (Iterator<value_type> i = this->begin (); i != this->end ();) {
343 if (find_if<ITEMS_ITER_TYPE> (items.begin (), items.end (),
344 [&] (const KEY_TYPE& k) { return keyEqualsComparer (i->fKey, k); }) == items.end ()) {
345#if qStroika_Foundation_Debug_AssertionsChecked
346 [[maybe_unused]] size_t sz = this->size ();
347#endif
348 i = this->erase (i);
349#if qStroika_Foundation_Debug_AssertionsChecked
350 Assert (this->size () == sz - 1u);
351#endif
352 }
353 else {
354 ++i;
355 }
357 }
358 else {
359 // Algorithm COMP COMPLEXITY apx= O(Items-N) * O(LOG(THIS_LEN-N)) - assuming tree style org for map, or O(1) if hashtable - bad estimate ignores cost of adds
360 // Fall thru, and just recreate the mapping
361 Mapping result = Mapping{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()};
362 size_t nAdds{0};
363 for (auto key2Keep : items) {
364 if (auto l = this->Lookup (key2Keep)) {
365 result.Add (key2Keep, *l);
366 ++nAdds;
367 }
368 }
369 // if nothing changed, we can just make no changes
370 if (thisSize != nAdds) {
371 *this = result;
372 }
373 else {
374 if constexpr (equality_comparable<MAPPED_VALUE_TYPE>) {
375 Assert (*this == result); // so why assign?
376 }
377 else {
378 // @todo assert keys equal...
379 }
380 }
381 }
382 }
383 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
384 template <typename RESULT_CONTAINER, invocable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ELEMENT_MAPPER>
385 RESULT_CONTAINER Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Map (ELEMENT_MAPPER&& elementMapper) const
386 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, typename RESULT_CONTAINER::value_type> or
387 convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, optional<typename RESULT_CONTAINER::value_type>>)
388 {
389 if constexpr (same_as<RESULT_CONTAINER, Mapping>) {
390 // clone the rep so we retain any ordering function/etc, rep type
391 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper),
392 RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
393 }
394 else {
395 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper)); // default Iterable<> implementation then...
396 }
397 }
398 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
399 template <derived_from<Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>> RESULT_CONTAINER, typename INCLUDE_PREDICATE>
400 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Where (INCLUDE_PREDICATE&& includeIfTrue) const -> RESULT_CONTAINER
401 requires (predicate<INCLUDE_PREDICATE, KEY_TYPE> or predicate<INCLUDE_PREDICATE, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>)
402 {
403 if constexpr (predicate<INCLUDE_PREDICATE, KEY_TYPE>) {
404 // recurse once with a KVP predicate
405 return Where<RESULT_CONTAINER> (
406 [=] (const ArgByValueType<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& kvp) { return includeIfTrue (kvp.fKey); });
407 }
408 else {
409 if constexpr (same_as<RESULT_CONTAINER, Mapping>) {
410 // clone the rep so we retain any ordering function/etc, rep type
411 return inherited::template Where<RESULT_CONTAINER> (
412 forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
413 }
414 else {
415 return inherited::template Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue)); // default Iterable<> implementation then...
416 }
417 }
418 }
419 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
420 template <typename CONTAINER_OF_KEYS>
421 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::WithKeys (const CONTAINER_OF_KEYS& includeKeys) const -> ArchetypeContainerType
422 {
423 return Where ([=] (const key_type& key) -> bool { return includeKeys.Contains (key); });
424 }
425 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
426 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::WithKeys (const initializer_list<key_type>& includeKeys) const -> ArchetypeContainerType
427 {
428 Iterable<key_type> ik{includeKeys};
429 return inherited::Where ([=] (const ArgByValueType<value_type>& kvp) { return ik.Contains (kvp.fKey); }, ArchetypeContainerType{});
430 }
431 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
432 template <typename CONTAINER_OF_Key_T>
433 inline CONTAINER_OF_Key_T Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::As () const
434 {
435 return As_<CONTAINER_OF_Key_T> ();
436 }
437 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
438 template <typename CONTAINER_OF_Key_T>
439 CONTAINER_OF_Key_T Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::As_ () const
440 {
441 CONTAINER_OF_Key_T result;
442 for (const auto& i : *this) {
443 // the reason we use the overload with an extra result.end () here is so it will work with std::map<> or std::vector<>
444 if constexpr (is_convertible_v<typename CONTAINER_OF_Key_T::value_type, pair<KEY_TYPE, MAPPED_VALUE_TYPE>>) {
445 result.insert (result.end (), pair<KEY_TYPE, MAPPED_VALUE_TYPE>{i.fKey, i.fValue});
446 }
447 else {
448 result.insert (result.end (), value_type{i.fKey, i.fValue});
449 }
450 }
451 return result;
452 }
453 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
454 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Accumulate (ArgByValueType<key_type> key, ArgByValueType<mapped_type> newValue,
455 const function<mapped_type (ArgByValueType<mapped_type>, ArgByValueType<mapped_type>)>& f,
456 mapped_type initialValue)
457 {
458 Add (key, f (LookupValue (key, initialValue), newValue));
459 }
460 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
461 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::insert (ArgByValueType<value_type> kvp)
462 {
463 Add (kvp.fKey, kvp.fValue);
464 }
465 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
466 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::erase (ArgByValueType<key_type> key)
467 {
468 Remove (key);
469 }
470 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
472 {
473 Iterator<value_type> nextI{nullptr};
474 Remove (i, &nextI);
475 return nextI;
476 }
477 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
479 {
480 RemoveAll ();
481 }
482 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
483 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
485 {
487 result.AddAll (items);
488 return result;
489 }
490 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
491 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
492 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>& Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::operator+= (const ITERABLE_OF_ADDABLE& items)
493 {
494 AddAll (items);
495 return *this;
496 }
497 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
498 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
499 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>& Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::operator-= (const ITERABLE_OF_KEY_OR_ADDABLE& items)
500 {
501 RemoveAll (items);
502 return *this;
503 }
504 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
506 -> tuple<_IRep*, Iterator<value_type>>
507 {
508 Require (not i.AtEnd ());
509 using element_type = typename inherited::_SharedByValueRepType::element_type;
510 Iterator<value_type> patchedIterator = i;
511 element_type* writableRep = this->_fRep.rwget ([&] (const element_type& prevRepPtr) -> typename inherited::_SharedByValueRepType::shared_ptr_type {
512 return Debug::UncheckedDynamicCast<const _IRep&> (prevRepPtr).CloneAndPatchIterator (&patchedIterator);
513 });
514 AssertNotNull (writableRep);
515 return make_tuple (Debug::UncheckedDynamicCast<_IRep*> (writableRep), move (patchedIterator));
516 }
517 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
519 {
521 [[maybe_unused]] _SafeReadRepAccessor<_IRep> ignored{this};
522 }
523 }
524 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
526 requires (equality_comparable<MAPPED_VALUE_TYPE>)
527 {
528 return EqualsComparer<>{}(*this, rhs);
529 }
530
531 /*
532 ********************************************************************************
533 ************ Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer **************
534 ********************************************************************************
535 */
536 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
537 template <typename VALUE_EQUALS_COMPARER>
538 constexpr Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer<VALUE_EQUALS_COMPARER>::EqualsComparer (const VALUE_EQUALS_COMPARER& valueEqualsComparer)
539 : fValueEqualsComparer{valueEqualsComparer}
540 {
541 }
542 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
543 template <typename VALUE_EQUALS_COMPARER>
544 bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer<VALUE_EQUALS_COMPARER>::operator() (const Mapping& lhs, const Mapping& rhs) const
545 {
546 /*
547 * @todo THIS CODE IS TOO COMPLICATED, and COULD USE CLEANUP/CODE REVIEW - LGP 2014-06-11
548 */
549 _SafeReadRepAccessor<_IRep> lhsR{&lhs};
550 _SafeReadRepAccessor<_IRep> rhsR{&rhs};
551 if (&lhsR._ConstGetRep () == &rhsR._ConstGetRep ()) [[unlikely]] {
552 // not such an unlikely test result since we use lazy copy, but this test is only an optimization and not logically required
553 return true;
554 }
555 // Check length, so we don't need to check both iterators for end/done
556 if (lhsR._ConstGetRep ().size () != rhsR._ConstGetRep ().size ()) [[likely]] {
557 return false;
558 }
559 /*
560 * Two Mappings compare equal, if they have the same domain, and map each element of that domain to the same range.
561 * They need not be in the same order to compare equals. Still - they often are, and if they are, this algorithm is faster.
562 * If they miss, we need to fall back to a slower strategy.
563 */
564 auto li = lhsR._ConstGetRep ().MakeIterator ();
565 auto ri = rhs.MakeIterator ();
566 auto keyEqualsComparer = lhs.GetKeyEqualsComparer (); // arbitrarily select left side key equals comparer
567 while (not li.AtEnd ()) {
568 Assert (not ri.AtEnd ()); // cuz move at same time and same size
569 bool keysEqual = keyEqualsComparer (li->fKey, ri->fKey);
570 Require (keysEqual == rhs.GetKeyEqualsComparer () (li->fKey, ri->fKey)); // if fails, cuz rhs/lhs keys equals comparers disagree
571 if (keysEqual) {
572 // then we are doing in same order so can do quick impl
573 if (not fValueEqualsComparer (li->fValue, ri->fValue)) {
574 return false;
575 }
576 }
577 else {
578 // check if li maps to right value in rhs
579 auto o = rhs.Lookup (li->fKey);
580 if (not o.has_value () or not fValueEqualsComparer (*o, li->fValue)) {
581 return false;
582 }
583 // if the keys were different, we must check the reverse direction too
584 if (not lhsR._ConstGetRep ().Lookup (ri->fKey, &o) or not fValueEqualsComparer (*o, ri->fValue)) {
585 return false;
586 }
587 }
588 // if we got this far, all compared OK so far, so keep going
589 ++li;
590 ++ri;
592 Assert (ri.AtEnd ()); // cuz LHS done and both sides iterate at same pace, and we checked both same size
593 return true;
594 }
595
596}
#define AssertNotNull(p)
Definition Assertions.h:336
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:49
#define RequireNotNull(p)
Definition Assertions.h:350
#define RequireExpression(c)
Definition Assertions.h:270
#define AssertNotReached()
Definition Assertions.h:358
#define Verify(c)
Definition Assertions.h:422
A Mapping uniquely associates two elements: a key and a value (use Assocation to allow multiple value...
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:186
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...
Definition Mapping.inl:505
nonvirtual Iterable< mapped_type > MappedValues() const
Definition Mapping.inl:116
nonvirtual void erase(ArgByValueType< key_type > key)
Definition Mapping.inl:466
nonvirtual bool ContainsKey(ArgByValueType< key_type > key) const
Definition Mapping.inl:175
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
Definition Mapping.inl:142
nonvirtual mapped_type LookupChecked(ArgByValueType< key_type > key, const THROW_IF_MISSING &throwIfMissing) const
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
nonvirtual add_const_t< mapped_type > operator[](ArgByValueType< key_type > key) const
Definition Mapping.inl:170
nonvirtual unsigned int AddAll(ITERABLE_OF_ADDABLE &&items, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual bool operator==(const Mapping &rhs) const
compares if the two mappings have the same keys, and corresponding values (doesn't check ordering sam...
Definition Mapping.inl:525
nonvirtual void insert(ArgByValueType< value_type > kvp)
Definition Mapping.inl:461
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:310
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:233
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
'override' Iterable<>::Map () function so container template defaults to Mapping, and improve that ca...
nonvirtual void RemoveAll()
RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items...
Definition Mapping.inl:238
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.
Definition Mapping.inl:454
nonvirtual void Remove(ArgByValueType< key_type > key)
Remove the given item (which must exist).
Definition Mapping.inl:221
nonvirtual mapped_type LookupValue(ArgByValueType< key_type > key, ArgByValueType< mapped_type > defaultValue=mapped_type{}) const
Definition Mapping.inl:164
nonvirtual Iterable< key_type > Keys() const
Definition Mapping.inl:111
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:234
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
nonvirtual bool AtEnd() const
AtEnd () means there is nothing left in this iterator (a synonym for (it == container....
Definition Iterator.inl:143
AddReplaceMode
Mode flag to say if Adding to a container replaces, or if the first addition wins.
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...
Definition Throw.inl:54
Compare Mappings<>s for equality. Note this can be costly, as the Mappings are not necessarily in the...