Stroika Library 3.0d23
 
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 {
71 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
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 {
89 AddAll (forward<ITERATOR_OF_ADDABLE> (start), forward<ITERATOR_OF_ADDABLE2> (end));
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 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wmaybe-uninitialized\""); // warned by g++ on ubuntu 21.10 - obviously wrong cuz optional initializes
148 return r;
149 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"");
150 }
151 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
152 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key, nullptr_t) const
153 {
154 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, nullptr);
155 }
156 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
157 template <typename THROW_IF_MISSING>
158 inline MAPPED_VALUE_TYPE Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::LookupChecked (ArgByValueType<key_type> key, const THROW_IF_MISSING& throwIfMissing) const
159 {
160 if (optional<MAPPED_VALUE_TYPE> r{Lookup (key)}) [[likely]] {
161 return *r;
162 }
163 Execution::Throw (throwIfMissing);
164 }
165 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
166 inline MAPPED_VALUE_TYPE Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::LookupValue (ArgByValueType<key_type> key, ArgByValueType<mapped_type> defaultValue) const
167 {
168 optional<MAPPED_VALUE_TYPE> r{Lookup (key)};
169 return r.has_value () ? *r : defaultValue;
170 }
171 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
172 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::operator[] (ArgByValueType<key_type> key) const -> add_const_t<mapped_type>
173 {
174 return *Lookup (key);
175 }
176 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
177 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::ContainsKey (ArgByValueType<key_type> key) const
178 {
179 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, nullptr);
180 }
181 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
182 template <typename VALUE_EQUALS_COMPARER>
183 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::ContainsMappedValue (ArgByValueType<mapped_type> v, VALUE_EQUALS_COMPARER&& valueEqualsComparer) const
184 {
185 return this->Find ([&valueEqualsComparer, &v] (const auto& t) { return valueEqualsComparer (t.fValue, v); }) != nullptr;
186 }
187 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
188 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Add (ArgByValueType<key_type> key, ArgByValueType<mapped_type> newElt, AddReplaceMode addReplaceMode)
189 {
190 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (key, newElt, addReplaceMode);
192 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
193 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Add (ArgByValueType<value_type> p, AddReplaceMode addReplaceMode)
194 {
195 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (p.fKey, p.fValue, addReplaceMode);
196 }
197 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
198 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
199 unsigned int Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::AddAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end, AddReplaceMode addReplaceMode)
200 {
201 unsigned int cntAdded{};
202 for (auto i = forward<ITERATOR_OF_ADDABLE> (start); i != forward<ITERATOR_OF_ADDABLE2> (end); ++i) {
203 if (Add (*i, addReplaceMode)) {
204 ++cntAdded;
205 }
206 }
207 return cntAdded;
208 }
209 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
210 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
211 inline unsigned int Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::AddAll (ITERABLE_OF_ADDABLE&& items, AddReplaceMode addReplaceMode)
212 {
213 if constexpr (std::is_convertible_v<remove_cvref_t<ITERABLE_OF_ADDABLE>*, Iterable<value_type>*>) {
214 // very rare corner case
215 if (static_cast<const Iterable<value_type>*> (this) == static_cast<const Iterable<value_type>*> (&items)) [[unlikely]] {
216 vector<value_type> copy{std::begin (items), Iterator<value_type>{std::end (items)}}; // because you can not iterate over a container while modifying it
217 return AddAll (std::begin (copy), std::end (copy), addReplaceMode);
218 }
219 }
220 return AddAll (std::begin (items), std::end (items), addReplaceMode);
221 }
222 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
223 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Remove (ArgByValueType<key_type> key)
224 {
225 Verify (_SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (key)); // use RemoveIf () if key may not exist
226 }
227 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
229 {
230 Require (not i.Done ());
231 auto [writerRep, patchedIterator] = _GetWritableRepAndPatchAssociatedIterator (i);
232 writerRep->Remove (patchedIterator, nextI);
233 }
234 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
235 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveIf (ArgByValueType<key_type> key)
236 {
237 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (key);
238 }
239 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
241 {
242 _SafeReadRepAccessor<_IRep> accessor{this}; // important to use READ not WRITE accessor, because write accessor would have already cloned the data
243 if (not accessor._ConstGetRep ().empty ()) {
244 this->_fRep = accessor._ConstGetRep ().CloneEmpty ();
245 }
246 }
247 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
248 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
249 size_t Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveAll (const ITERABLE_OF_KEY_OR_ADDABLE& items)
250 requires (IIterableOfTo<ITERABLE_OF_KEY_OR_ADDABLE, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> or
251 IIterableOfTo<ITERABLE_OF_KEY_OR_ADDABLE, pair<KEY_TYPE, MAPPED_VALUE_TYPE>> or IIterableOfTo<ITERABLE_OF_KEY_OR_ADDABLE, KEY_TYPE>)
252 {
253 using ITEM_T = ranges::range_value_t<ITERABLE_OF_KEY_OR_ADDABLE>;
254 static_assert (is_convertible_v<ITEM_T, key_type> or is_convertible_v<ITEM_T, pair<key_type, mapped_type>> or
255 is_convertible_v<ITEM_T, KeyValuePair<key_type, mapped_type>>);
256 if constexpr (convertible_to<const Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>*, const ITERABLE_OF_KEY_OR_ADDABLE*>) {
257 if (this == &items) { // avoid modifying container while iterating over it
258 size_t result = this->size ();
259 RemoveAll ();
260 return result;
261 }
262 }
263 return this->RemoveAll (begin (items), end (items));
264 }
265 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
266 template <typename ITERATOR_OF_KEY_OR_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_KEY_OR_ADDABLE>> ITERATOR_OF_KEY_OR_ADDABLE2>
267 inline size_t Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveAll (ITERATOR_OF_KEY_OR_ADDABLE&& start, ITERATOR_OF_KEY_OR_ADDABLE2&& end)
268 {
269 using ITEM_T = iter_value_t<ITERATOR_OF_KEY_OR_ADDABLE>;
270 static_assert (is_convertible_v<ITEM_T, key_type> or is_convertible_v<ITEM_T, pair<key_type, mapped_type>> or
271 is_convertible_v<ITEM_T, KeyValuePair<key_type, mapped_type>>);
272 size_t cnt{};
273 for (auto i = start; i != end; ++i) {
274 if constexpr (is_convertible_v<ITEM_T, key_type>) {
275 if (RemoveIf (*i)) {
276 ++cnt;
277 }
278 }
279 else if constexpr (is_convertible_v<ITEM_T, pair<key_type, mapped_type>>) {
280 if (RemoveIf (i->first)) {
281 ++cnt;
282 }
283 }
284 else if constexpr (is_convertible_v<ITEM_T, KeyValuePair<key_type, mapped_type>>) {
285 if (RemoveIf (i->fKey)) {
286 ++cnt;
287 }
288 }
289 else {
291 }
292 }
293 return cnt;
294 }
295 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
296 template <predicate<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> PREDICATE>
298 {
299 size_t nRemoved{};
300 for (Iterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> i = this->begin (); i != this->end ();) {
301 if (p (*i)) {
302 Remove (i, &i);
303 ++nRemoved;
304 }
305 else {
306 ++i;
307 }
308 }
309 return nRemoved;
310 }
311 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
312 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Update (const Iterator<value_type>& i, ArgByValueType<mapped_type> newValue,
314 {
315 Require (not i.Done ());
316 auto [writerRep, patchedIterator] = _GetWritableRepAndPatchAssociatedIterator (i);
317 writerRep->Update (patchedIterator, newValue, nextI);
318 }
319 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
320 template <IIterableOfTo<KEY_TYPE> ITERABLE_OF_KEY_TYPE>
321 void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RetainAll (const ITERABLE_OF_KEY_TYPE& items)
322 {
323 /*
324 * If items is smaller than this->size(), probably best to just remove one or two things from this
325 * (small number of lookups, and maybe no changes).
326 *
327 * If items is large, probably best to just create the entire mapping anew (cuz probably
328 * producing much smaller map).
329 *
330 * And both approaches avoid needing to quickly search through items repeatedly (except
331 * when we know items is small so no cost).
332 *
333 * NOT too worried about optimizing this code - but really quite unsure about this analysis of which way is faster.
334 * --LGP 2025-04-01
335 */
336 size_t thisSize = this->size ();
337
338 // Small case - just remove a few items
339 bool fewerLookupsThanAdds = items.size () <= 2;
340 if (fewerLookupsThanAdds) {
341 // Algorithm COMP COMPLEXITY VERY ROUHLTY apx= (O(Items-N) * O(THIS_LEN-N)) bad estimate cuz ignores cost of erases
342 auto keyEqualsComparer = this->GetKeyEqualsComparer ();
343 using ITEMS_ITER_TYPE = decltype (items.begin ()); // because of new ranges (c++20) code - sentinel but find_if only templated on one iter parameter
344 for (Iterator<value_type> i = this->begin (); i != this->end ();) {
345 if (find_if<ITEMS_ITER_TYPE> (items.begin (), items.end (),
346 [&] (const KEY_TYPE& k) { return keyEqualsComparer (i->fKey, k); }) == items.end ()) {
347#if qStroika_Foundation_Debug_AssertionsChecked
348 [[maybe_unused]] size_t sz = this->size ();
349#endif
350 i = this->erase (i);
351#if qStroika_Foundation_Debug_AssertionsChecked
352 Assert (this->size () == sz - 1u);
353#endif
354 }
355 else {
356 ++i;
357 }
358 }
360 else {
361 // 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
362 // Fall thru, and just recreate the mapping
363 Mapping result = Mapping{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()};
364 size_t nAdds{0};
365 for (auto key2Keep : items) {
366 if (auto l = this->Lookup (key2Keep)) {
367 result.Add (key2Keep, *l);
368 ++nAdds;
369 }
370 }
371 // if nothing changed, we can just make no changes
372 if (thisSize != nAdds) {
373 *this = result;
374 }
375 else {
376 if constexpr (equality_comparable<MAPPED_VALUE_TYPE>) {
377 Assert (*this == result); // so why assign?
378 }
379 else {
380 // @todo assert keys equal...
381 }
382 }
383 }
384 }
385 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
386 template <typename RESULT_CONTAINER, invocable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ELEMENT_MAPPER>
387 RESULT_CONTAINER Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Map (ELEMENT_MAPPER&& elementMapper) const
388 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, typename RESULT_CONTAINER::value_type> or
389 convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, optional<typename RESULT_CONTAINER::value_type>>)
390 {
391 if constexpr (same_as<RESULT_CONTAINER, Mapping>) {
392 // clone the rep so we retain any ordering function/etc, rep type
393 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper),
394 RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
395 }
396 else {
397 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper)); // default Iterable<> implementation then...
398 }
399 }
400 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
401 template <derived_from<Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>> RESULT_CONTAINER, typename INCLUDE_PREDICATE>
402 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Where (INCLUDE_PREDICATE&& includeIfTrue) const -> RESULT_CONTAINER
403 requires (predicate<INCLUDE_PREDICATE, KEY_TYPE> or predicate<INCLUDE_PREDICATE, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>)
404 {
405 if constexpr (predicate<INCLUDE_PREDICATE, KEY_TYPE>) {
406 // recurse once with a KVP predicate
407 return Where<RESULT_CONTAINER> (
408 [=] (const ArgByValueType<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& kvp) { return includeIfTrue (kvp.fKey); });
409 }
410 else {
411 if constexpr (same_as<RESULT_CONTAINER, Mapping>) {
412 // clone the rep so we retain any ordering function/etc, rep type
413 return inherited::template Where<RESULT_CONTAINER> (
414 forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
415 }
416 else {
417 return inherited::template Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue)); // default Iterable<> implementation then...
418 }
419 }
420 }
421 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
422 template <typename CONTAINER_OF_KEYS>
423 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::WithKeys (const CONTAINER_OF_KEYS& includeKeys) const -> ArchetypeContainerType
424 {
425 return Where ([=] (const key_type& key) -> bool { return includeKeys.Contains (key); });
426 }
427 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
428 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::WithKeys (const initializer_list<key_type>& includeKeys) const -> ArchetypeContainerType
429 {
430 Iterable<key_type> ik{includeKeys};
431 return inherited::Where ([=] (const ArgByValueType<value_type>& kvp) { return ik.Contains (kvp.fKey); }, ArchetypeContainerType{});
433 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
434 template <typename CONTAINER_OF_Key_T>
435 inline CONTAINER_OF_Key_T Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::As () const
436 {
437 return As_<CONTAINER_OF_Key_T> ();
438 }
439 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
440 template <typename CONTAINER_OF_Key_T>
441 CONTAINER_OF_Key_T Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::As_ () const
442 {
443 CONTAINER_OF_Key_T result;
444 for (const auto& i : *this) {
445 // the reason we use the overload with an extra result.end () here is so it will work with std::map<> or std::vector<>
446 if constexpr (is_convertible_v<typename CONTAINER_OF_Key_T::value_type, pair<KEY_TYPE, MAPPED_VALUE_TYPE>>) {
447 result.insert (result.end (), pair<KEY_TYPE, MAPPED_VALUE_TYPE>{i.fKey, i.fValue});
448 }
449 else {
450 result.insert (result.end (), value_type{i.fKey, i.fValue});
451 }
452 }
453 return result;
454 }
455 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
456 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Accumulate (ArgByValueType<key_type> key, ArgByValueType<mapped_type> newValue,
457 const function<mapped_type (ArgByValueType<mapped_type>, ArgByValueType<mapped_type>)>& f,
458 mapped_type initialValue)
459 {
460 Add (key, f (LookupValue (key, initialValue), newValue));
461 }
462 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
463 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::insert (ArgByValueType<value_type> kvp)
464 {
465 Add (kvp.fKey, kvp.fValue);
466 }
467 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
468 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::erase (ArgByValueType<key_type> key)
469 {
470 Remove (key);
471 }
472 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
474 {
475 Iterator<value_type> nextI{nullptr};
476 Remove (i, &nextI);
477 return nextI;
478 }
479 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
481 {
482 RemoveAll ();
483 }
484 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
485 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
487 {
489 result.AddAll (items);
490 return result;
491 }
492 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
493 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
494 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>& Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::operator+= (const ITERABLE_OF_ADDABLE& items)
495 {
496 AddAll (items);
497 return *this;
498 }
499 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
500 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
501 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>& Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::operator-= (const ITERABLE_OF_KEY_OR_ADDABLE& items)
502 {
503 RemoveAll (items);
504 return *this;
505 }
506 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
508 -> tuple<_IRep*, Iterator<value_type>>
509 {
510 Require (not i.Done ());
511 using element_type = typename inherited::_SharedByValueRepType::element_type;
512 Iterator<value_type> patchedIterator = i;
513 element_type* writableRep = this->_fRep.rwget ([&] (const element_type& prevRepPtr) -> typename inherited::_SharedByValueRepType::shared_ptr_type {
514 return Debug::UncheckedDynamicCast<const _IRep&> (prevRepPtr).CloneAndPatchIterator (&patchedIterator);
515 });
516 AssertNotNull (writableRep);
517 return make_tuple (Debug::UncheckedDynamicCast<_IRep*> (writableRep), move (patchedIterator));
518 }
519 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
521 {
523 [[maybe_unused]] _SafeReadRepAccessor<_IRep> ignored{this};
524 }
525 }
526 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
528 requires (equality_comparable<MAPPED_VALUE_TYPE>)
529 {
530 return EqualsComparer<>{}(*this, rhs);
531 }
532
533 /*
534 ********************************************************************************
535 ************ Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer **************
536 ********************************************************************************
537 */
538 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
539 template <typename VALUE_EQUALS_COMPARER>
540 constexpr Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer<VALUE_EQUALS_COMPARER>::EqualsComparer (const VALUE_EQUALS_COMPARER& valueEqualsComparer)
541 : fValueEqualsComparer{valueEqualsComparer}
542 {
543 }
544 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
545 template <typename VALUE_EQUALS_COMPARER>
546 bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer<VALUE_EQUALS_COMPARER>::operator() (const Mapping& lhs, const Mapping& rhs) const
547 {
548 /*
549 * @todo THIS CODE IS TOO COMPLICATED, and COULD USE CLEANUP/CODE REVIEW - LGP 2014-06-11
550 */
551 _SafeReadRepAccessor<_IRep> lhsR{&lhs};
552 _SafeReadRepAccessor<_IRep> rhsR{&rhs};
553 if (&lhsR._ConstGetRep () == &rhsR._ConstGetRep ()) [[unlikely]] {
554 // not such an unlikely test result since we use lazy copy, but this test is only an optimization and not logically required
555 return true;
556 }
557 // Check length, so we don't need to check both iterators for end/done
558 if (lhsR._ConstGetRep ().size () != rhsR._ConstGetRep ().size ()) [[likely]] {
559 return false;
560 }
561 /*
562 * Two Mappings compare equal, if they have the same domain, and map each element of that domain to the same range.
563 * They need not be in the same order to compare equals. Still - they often are, and if they are, this algorithm is faster.
564 * If they miss, we need to fall back to a slower strategy.
565 */
566 auto li = lhsR._ConstGetRep ().MakeIterator ();
567 auto ri = rhs.MakeIterator ();
568 auto keyEqualsComparer = lhs.GetKeyEqualsComparer (); // arbitrarily select left side key equals comparer
569 while (not li.Done ()) {
570 Assert (not ri.Done ()); // cuz move at same time and same size
571 bool keysEqual = keyEqualsComparer (li->fKey, ri->fKey);
572 Require (keysEqual == rhs.GetKeyEqualsComparer () (li->fKey, ri->fKey)); // if fails, cuz rhs/lhs keys equals comparers disagree
573 if (keysEqual) {
574 // then we are doing in same order so can do quick impl
575 if (not fValueEqualsComparer (li->fValue, ri->fValue)) {
576 return false;
577 }
578 }
579 else {
580 // check if li maps to right value in rhs
581 auto o = rhs.Lookup (li->fKey);
582 if (not o.has_value () or not fValueEqualsComparer (*o, li->fValue)) {
583 return false;
584 }
585 // if the keys were different, we must check the reverse direction too
586 if (not lhsR._ConstGetRep ().Lookup (ri->fKey, &o) or not fValueEqualsComparer (*o, ri->fValue)) {
587 return false;
589 }
590 // if we got this far, all compared OK so far, so keep going
591 ++li;
592 ++ri;
593 }
594 Assert (ri.Done ()); // cuz LHS done and both sides iterate at same pace, and we checked both same size
595 return true;
596 }
598}
#define AssertNotNull(p)
Definition Assertions.h:334
#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:348
#define RequireExpression(c)
Definition Assertions.h:268
#define AssertNotReached()
Definition Assertions.h:356
#define Verify(c)
Definition Assertions.h:420
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:188
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:507
nonvirtual Iterable< mapped_type > MappedValues() const
Definition Mapping.inl:116
nonvirtual void erase(ArgByValueType< key_type > key)
Definition Mapping.inl:468
nonvirtual bool ContainsKey(ArgByValueType< key_type > key) const
Definition Mapping.inl:177
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:172
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:527
nonvirtual void insert(ArgByValueType< value_type > kvp)
Definition Mapping.inl:463
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:235
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:240
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:456
nonvirtual void Remove(ArgByValueType< key_type > key)
Remove the given item (which must exist).
Definition Mapping.inl:223
nonvirtual mapped_type LookupValue(ArgByValueType< key_type > key, ArgByValueType< mapped_type > defaultValue=mapped_type{}) const
Definition Mapping.inl:166
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:237
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
nonvirtual bool Done() const
Done () means there is nothing left in this iterator (a synonym for (it == container....
Definition Iterator.inl:147
AddReplaceMode
Mode flag to say if Adding to a container replaces, or if the first addition wins.
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Definition Throw.inl:43
Compare Mappings<>s for equality. Note this can be costly, as the Mappings are not necessarily in the...