Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Mapping.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4
5/*
6 ********************************************************************************
7 ***************************** Implementation Details ***************************
8 ********************************************************************************
9 */
10#include <set> // tmphack for sloppy RetainAll implementation
11
16
18
19 /*
20 ********************************************************************************
21 ******************** Mapping<KEY_TYPE, MAPPED_VALUE_TYPE> **********************
22 ********************************************************************************
23 */
24 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
26 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>)
27 : Mapping{equal_to<KEY_TYPE>{}}
28 {
29 _AssertRepValidType ();
30 }
31 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
32 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER>
33 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer)
34 : inherited{Factory::Mapping_Factory<KEY_TYPE, MAPPED_VALUE_TYPE, remove_cvref_t<KEY_EQUALS_COMPARER>>::Default () (
35 forward<KEY_EQUALS_COMPARER> (keyEqualsComparer))}
36 {
37 _AssertRepValidType ();
38 }
39 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
40 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (const initializer_list<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& src)
41 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>)
42 : Mapping{}
43 {
44 AddAll (src);
45 _AssertRepValidType ();
46 }
47 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
48 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER>
49 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer,
50 const initializer_list<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& src)
51 : Mapping{forward<KEY_EQUALS_COMPARER> (keyEqualsComparer)}
52 {
53 AddAll (src);
54 _AssertRepValidType ();
55 }
56#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
57 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
58 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
59 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (ITERABLE_OF_ADDABLE&& src)
60 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE> and
61 not derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>>)
62 : Mapping{}
63 {
64 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
65 _AssertRepValidType ();
66 }
67#endif
68 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
69 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER, IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
70 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer, ITERABLE_OF_ADDABLE&& src)
71 : Mapping{forward<KEY_EQUALS_COMPARER> (keyEqualsComparer)}
72 {
73 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
74 _AssertRepValidType ();
75 }
76 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
77 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
78 Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
79 requires (IEqualsComparer<equal_to<KEY_TYPE>, KEY_TYPE>)
80 : Mapping{}
81 {
82 AddAll (forward<ITERATOR_OF_ADDABLE> (start), forward<ITERATOR_OF_ADDABLE2> (end));
83 _AssertRepValidType ();
84 }
85 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
86 template <IEqualsComparer<KEY_TYPE> KEY_EQUALS_COMPARER, IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE,
87 sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
88 Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (KEY_EQUALS_COMPARER&& keyEqualsComparer, ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
89 : Mapping{forward<KEY_EQUALS_COMPARER> (keyEqualsComparer)}
90 {
91 AddAll (forward<ITERATOR_OF_ADDABLE> (start), forward<ITERATOR_OF_ADDABLE2> (end));
92 _AssertRepValidType ();
93 }
94 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
95 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (const shared_ptr<_IRep>& rep) noexcept
96 : inherited{rep}
97 {
98 RequireNotNull (rep);
99 _AssertRepValidType ();
100 }
101 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
102 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Mapping (shared_ptr<_IRep>&& rep) noexcept
103 : inherited{(RequireExpression (rep != nullptr), move (rep))}
104 {
105 _AssertRepValidType ();
106 }
107 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
108 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::GetKeyEqualsComparer () const -> KeyEqualsCompareFunctionType
109 {
110 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().GetKeyEqualsComparer ();
111 }
112 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
114 {
115 return this->template Map<Iterable<KEY_TYPE>> ([] (const KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>& kvp) { return kvp.fKey; });
116 }
117 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
119 {
120 return this->template Map<Iterable<MAPPED_VALUE_TYPE>> (
121 [] (const KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>& kvp) { return kvp.fValue; });
122 }
123 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
124 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key, mapped_type* item) const
125 {
126 if (item == nullptr) {
127 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, nullptr);
128 }
129 else {
130 optional<mapped_type> tmp;
131 if (_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, &tmp)) {
132 *item = *tmp;
133 return true;
134 }
135 return false;
136 }
137 }
138 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
139 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key, optional<mapped_type>* item) const
140 {
141 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, item);
142 }
143 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
144 inline optional<MAPPED_VALUE_TYPE> Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key) const
145 {
146 optional<MAPPED_VALUE_TYPE> r;
147 [[maybe_unused]] bool result = _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, &r);
148 Ensure (result == r.has_value ());
149 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wmaybe-uninitialized\""); // warned by g++ on ubuntu 21.10 - obviously wrong cuz optional initializes
150 return r;
151 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"");
152 }
153 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
154 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Lookup (ArgByValueType<key_type> key, nullptr_t) const
155 {
156 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, nullptr);
157 }
158 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
159 template <typename THROW_IF_MISSING>
160 inline MAPPED_VALUE_TYPE Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::LookupChecked (ArgByValueType<key_type> key, const THROW_IF_MISSING& throwIfMissing) const
161 {
162 if (optional<MAPPED_VALUE_TYPE> r{Lookup (key)}) [[likely]] {
163 return *r;
164 }
165 Execution::Throw (throwIfMissing);
166 }
167 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
168 inline MAPPED_VALUE_TYPE Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::LookupValue (ArgByValueType<key_type> key, ArgByValueType<mapped_type> defaultValue) const
169 {
170 optional<MAPPED_VALUE_TYPE> r{Lookup (key)};
171 return r.has_value () ? *r : defaultValue;
172 }
173 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
174 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::operator[] (ArgByValueType<key_type> key) const -> add_const_t<mapped_type>
175 {
176 return *Lookup (key);
177 }
178 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
179 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::ContainsKey (ArgByValueType<key_type> key) const
180 {
181 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (key, nullptr);
182 }
183 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
184 template <typename VALUE_EQUALS_COMPARER>
185 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::ContainsMappedValue (ArgByValueType<mapped_type> v, VALUE_EQUALS_COMPARER&& valueEqualsComparer) const
186 {
187 return this->Find ([&valueEqualsComparer, &v] (const auto& t) { return valueEqualsComparer (t.fValue, v); }) != nullptr;
188 }
189 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
190 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Add (ArgByValueType<key_type> key, ArgByValueType<mapped_type> newElt, AddReplaceMode addReplaceMode)
192 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (key, newElt, addReplaceMode);
193 }
194 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
195 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Add (ArgByValueType<value_type> p, AddReplaceMode addReplaceMode)
196 {
197 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (p.fKey, p.fValue, addReplaceMode);
198 }
199 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
200 template <IInputIterator<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
201 unsigned int Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::AddAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end, AddReplaceMode addReplaceMode)
202 {
203 unsigned int cntAdded{};
204 for (auto i = forward<ITERATOR_OF_ADDABLE> (start); i != forward<ITERATOR_OF_ADDABLE2> (end); ++i) {
205 if (Add (*i, addReplaceMode)) {
206 ++cntAdded;
207 }
208 }
209 return cntAdded;
210 }
211 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
212 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
213 inline unsigned int Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::AddAll (ITERABLE_OF_ADDABLE&& items, AddReplaceMode addReplaceMode)
214 {
215 if constexpr (std::is_convertible_v<remove_cvref_t<ITERABLE_OF_ADDABLE>*, Iterable<value_type>*>) {
216 // very rare corner case
217 if (static_cast<const Iterable<value_type>*> (this) == static_cast<const Iterable<value_type>*> (&items)) [[unlikely]] {
218 vector<value_type> copy{std::begin (items), Iterator<value_type>{std::end (items)}}; // because you can not iterate over a container while modifying it
219 return AddAll (std::begin (copy), std::end (copy), addReplaceMode);
220 }
221 }
222 return AddAll (std::begin (items), std::end (items), addReplaceMode);
223 }
224 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
225 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Remove (ArgByValueType<key_type> key)
226 {
227 Verify (_SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (key)); // use RemoveIf () if key may not exist
228 }
229 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
231 {
232 Require (not i.Done ());
233 auto [writerRep, patchedIterator] = _GetWritableRepAndPatchAssociatedIterator (i);
234 writerRep->Remove (patchedIterator, nextI);
235 }
236 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
237 inline bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveIf (ArgByValueType<key_type> key)
238 {
239 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (key);
240 }
241 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
243 {
244 _SafeReadRepAccessor<_IRep> accessor{this}; // important to use READ not WRITE accessor, because write accessor would have already cloned the data
245 if (not accessor._ConstGetRep ().empty ()) {
246 this->_fRep = accessor._ConstGetRep ().CloneEmpty ();
247 }
248 }
249 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
250 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
251 size_t Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveAll (const ITERABLE_OF_KEY_OR_ADDABLE& items)
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, Common::KeyValuePair<key_type, mapped_type>>);
256 if (this == &items) { // avoid modifying container while iterating over it
257 size_t result = this->size ();
258 RemoveAll ();
259 return result;
260 }
261 else {
262 return RemoveAll (begin (items), end (items));
263 }
264 }
265 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
266 template <typename ITERATOR_OF_KEY_OR_ADDABLE>
267 inline size_t Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::RemoveAll (ITERATOR_OF_KEY_OR_ADDABLE start, ITERATOR_OF_KEY_OR_ADDABLE end)
268 {
269 using ITEM_T = ranges::range_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, Common::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, Common::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 // @see http://stroika-bugs.sophists.com/browse/STK-539
324#if 0
325 Mapping<KEY_TYPE, MAPPED_VALUE_TYPE> result = Mapping<KEY_TYPE, MAPPED_VALUE_TYPE> { _SafeReadRepAccessor<_IRep> { this } ._ConstGetRep ().CloneEmpty () };
326 for (auto key2Keep : items) {
327 if (auto l = this->Lookup (key2Keep)) {
328 result.Add (key2Keep, *l);
329 }
330 }
331 *this = result;
332#else
333 // cannot easily use STL::less because our Mapping class only requires KeyEqualsCompareFunctionType - SO - should use Stroika Set<> But don't want cross-dependencies if not needed
334 using ITEMS_ITER_TYPE = decltype (items.begin ());
335 set<KEY_TYPE> tmp{items.begin (), ITEMS_ITER_TYPE{items.end ()}}; // @todo - weak implementation because of 'comparison' function, and performance (if items already a set)
336 for (Iterator<value_type> i = this->begin (); i != this->end ();) {
337 if (tmp.find (i->fKey) == tmp.end ()) {
338 [[maybe_unused]] size_t sz = this->size ();
339 i = this->erase (i);
340 Assert (this->size () == sz - 1u);
341 }
342 else {
343 ++i;
344 }
345 }
346#endif
347 }
348 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
349 template <typename RESULT_CONTAINER, invocable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ELEMENT_MAPPER>
350 RESULT_CONTAINER Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Map (ELEMENT_MAPPER&& elementMapper) const
351 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, typename RESULT_CONTAINER::value_type> or
352 convertible_to<invoke_result_t<ELEMENT_MAPPER, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>, optional<typename RESULT_CONTAINER::value_type>>)
354 if constexpr (same_as<RESULT_CONTAINER, Mapping>) {
355 // clone the rep so we retain any ordering function/etc, rep type
356 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper),
357 RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
358 }
359 else {
360 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper)); // default Iterable<> implementation then...
361 }
362 }
363 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
364 template <derived_from<Iterable<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>> RESULT_CONTAINER, typename INCLUDE_PREDICATE>
365 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Where (INCLUDE_PREDICATE&& includeIfTrue) const -> RESULT_CONTAINER
366 requires (predicate<INCLUDE_PREDICATE, KEY_TYPE> or predicate<INCLUDE_PREDICATE, KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>)
367 {
368 if constexpr (predicate<INCLUDE_PREDICATE, KEY_TYPE>) {
369 // recurse once with a KVP predicate
370 return Where<RESULT_CONTAINER> (
371 [=] (const ArgByValueType<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>>& kvp) { return includeIfTrue (kvp.fKey); });
372 }
373 else {
374 if constexpr (same_as<RESULT_CONTAINER, Mapping>) {
375 // clone the rep so we retain any ordering function/etc, rep type
376 return inherited::template Where<RESULT_CONTAINER> (
377 forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
378 }
379 else {
380 return inherited::template Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue)); // default Iterable<> implementation then...
381 }
382 }
383 }
384 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
385 template <typename CONTAINER_OF_KEYS>
386 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::WithKeys (const CONTAINER_OF_KEYS& includeKeys) const -> ArchetypeContainerType
387 {
388 return Where ([=] (const key_type& key) -> bool { return includeKeys.Contains (key); });
389 }
390 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
391 inline auto Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::WithKeys (const initializer_list<key_type>& includeKeys) const -> ArchetypeContainerType
392 {
393 Iterable<key_type> ik{includeKeys};
394 return inherited::Where ([=] (const ArgByValueType<value_type>& kvp) { return ik.Contains (kvp.fKey); }, ArchetypeContainerType{});
395 }
396 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
397 template <typename CONTAINER_OF_Key_T>
398 inline CONTAINER_OF_Key_T Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::As () const
399 {
400 return As_<CONTAINER_OF_Key_T> ();
401 }
402 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
403 template <typename CONTAINER_OF_Key_T>
404 CONTAINER_OF_Key_T Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::As_ () const
405 {
406 CONTAINER_OF_Key_T result;
407 for (const auto& i : *this) {
408 // the reason we use the overload with an extra result.end () here is so it will work with std::map<> or std::vector<>
409 if constexpr (is_convertible_v<typename CONTAINER_OF_Key_T::value_type, pair<KEY_TYPE, MAPPED_VALUE_TYPE>>) {
410 result.insert (result.end (), pair<KEY_TYPE, MAPPED_VALUE_TYPE>{i.fKey, i.fValue});
411 }
412 else {
413 result.insert (result.end (), value_type{i.fKey, i.fValue});
414 }
415 }
416 return result;
417 }
418 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
419 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::Accumulate (ArgByValueType<key_type> key, ArgByValueType<mapped_type> newValue,
420 const function<mapped_type (ArgByValueType<mapped_type>, ArgByValueType<mapped_type>)>& f,
421 mapped_type initialValue)
422 {
423 Add (key, f (LookupValue (key, initialValue), newValue));
424 }
425 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
426 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::insert (ArgByValueType<value_type> kvp)
427 {
428 Add (kvp.fKey, kvp.fValue);
429 }
430 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
431 inline void Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::erase (ArgByValueType<key_type> key)
433 Remove (key);
434 }
435 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
437 {
438 Iterator<value_type> nextI{nullptr};
439 Remove (i, &nextI);
440 return nextI;
441 }
442 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
444 {
446 }
447 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
448 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
450 {
452 result.AddAll (items);
453 return result;
454 }
455 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
456 template <IIterableOfTo<KeyValuePair<KEY_TYPE, MAPPED_VALUE_TYPE>> ITERABLE_OF_ADDABLE>
457 inline Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>& Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::operator+= (const ITERABLE_OF_ADDABLE& items)
458 {
459 AddAll (items);
460 return *this;
461 }
462 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
463 template <typename ITERABLE_OF_KEY_OR_ADDABLE>
465 {
466 RemoveAll (items);
467 return *this;
468 }
469 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
471 -> tuple<_IRep*, Iterator<value_type>>
472 {
473 Require (not i.Done ());
474 using element_type = typename inherited::_SharedByValueRepType::element_type;
475 Iterator<value_type> patchedIterator = i;
476 element_type* writableRep = this->_fRep.rwget ([&] (const element_type& prevRepPtr) -> typename inherited::_SharedByValueRepType::shared_ptr_type {
477 return Debug::UncheckedDynamicCast<const _IRep&> (prevRepPtr).CloneAndPatchIterator (&patchedIterator);
478 });
479 AssertNotNull (writableRep);
480 return make_tuple (Debug::UncheckedDynamicCast<_IRep*> (writableRep), move (patchedIterator));
481 }
482 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
484 {
486 [[maybe_unused]] _SafeReadRepAccessor<_IRep> ignored{this};
487 }
488 }
489 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
491 requires (equality_comparable<MAPPED_VALUE_TYPE>)
492 {
493 return EqualsComparer<>{}(*this, rhs);
494 }
495
496 /*
497 ********************************************************************************
498 ************ Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer **************
499 ********************************************************************************
500 */
501 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
502 template <typename VALUE_EQUALS_COMPARER>
503 constexpr Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer<VALUE_EQUALS_COMPARER>::EqualsComparer (const VALUE_EQUALS_COMPARER& valueEqualsComparer)
504 : fValueEqualsComparer{valueEqualsComparer}
505 {
506 }
507 template <typename KEY_TYPE, typename MAPPED_VALUE_TYPE>
508 template <typename VALUE_EQUALS_COMPARER>
509 bool Mapping<KEY_TYPE, MAPPED_VALUE_TYPE>::EqualsComparer<VALUE_EQUALS_COMPARER>::operator() (const Mapping& lhs, const Mapping& rhs) const
510 {
511 /*
512 * @todo THIS CODE IS TOO COMPLICATED, and COULD USE CLEANUP/CODE REVIEW - LGP 2014-06-11
513 */
514 _SafeReadRepAccessor<_IRep> lhsR{&lhs};
515 _SafeReadRepAccessor<_IRep> rhsR{&rhs};
516 if (&lhsR._ConstGetRep () == &rhsR._ConstGetRep ()) [[unlikely]] {
517 // not such an unlikely test result since we use lazy copy, but this test is only an optimization and not logically required
518 return true;
519 }
520 // Check length, so we don't need to check both iterators for end/done
521 if (lhsR._ConstGetRep ().size () != rhsR._ConstGetRep ().size ()) [[likely]] {
522 return false;
523 }
524 /*
525 * Two Mappings compare equal, if they have the same domain, and map each element of that domain to the same range.
526 * They need not be in the same order to compare equals. Still - they often are, and if they are, this algorithm is faster.
527 * If they miss, we need to fall back to a slower strategy.
528 */
529 auto li = lhsR._ConstGetRep ().MakeIterator ();
530 auto ri = rhs.MakeIterator ();
531 auto keyEqualsComparer = lhs.GetKeyEqualsComparer (); // arbitrarily select left side key equals comparer
532 while (not li.Done ()) {
533 Assert (not ri.Done ()); // cuz move at same time and same size
534 bool keysEqual = keyEqualsComparer (li->fKey, ri->fKey);
535 Require (keysEqual == rhs.GetKeyEqualsComparer () (li->fKey, ri->fKey)); // if fails, cuz rhs/lhs keys equals comparers disagree
536 if (keysEqual) {
537 // then we are doing in same order so can do quick impl
538 if (not fValueEqualsComparer (li->fValue, ri->fValue)) {
539 return false;
540 }
541 }
542 else {
543 // check if li maps to right value in rhs
544 auto o = rhs.Lookup (li->fKey);
545 if (not o.has_value () or not fValueEqualsComparer (*o, li->fValue)) {
546 return false;
547 }
548 // if the keys were different, we must check the reverse direction too
549 if (not lhsR._ConstGetRep ().Lookup (ri->fKey, &o) or not fValueEqualsComparer (*o, ri->fValue)) {
550 return false;
551 }
552 }
553 // if we got this far, all compared OK so far, so keep going
554 ++li;
555 ++ri;
556 }
557 Assert (ri.Done ()); // cuz LHS done and both sides iterate at same pace, and we checked both same size
558 return true;
559 }
560
561}
#define AssertNotNull(p)
Definition Assertions.h:333
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:48
#define RequireNotNull(p)
Definition Assertions.h:347
#define RequireExpression(c)
Definition Assertions.h:267
#define AssertNotReached()
Definition Assertions.h:355
#define Verify(c)
Definition Assertions.h:419
nonvirtual CONTAINER_OF_Key_T As() const
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
Definition Mapping.inl:190
nonvirtual 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:470
nonvirtual Iterable< mapped_type > MappedValues() const
Definition Mapping.inl:118
nonvirtual void erase(ArgByValueType< key_type > key)
Definition Mapping.inl:431
nonvirtual bool ContainsKey(ArgByValueType< key_type > key) const
Definition Mapping.inl:179
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
Definition Mapping.inl:144
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:174
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:490
nonvirtual void insert(ArgByValueType< value_type > kvp)
Definition Mapping.inl:426
nonvirtual bool ContainsMappedValue(ArgByValueType< mapped_type > v, VALUE_EQUALS_COMPARER &&valueEqualsComparer={}) const
nonvirtual void Update(const Iterator< value_type > &i, ArgByValueType< mapped_type > newValue, Iterator< value_type > *nextI=nullptr)
Definition Mapping.inl:312
nonvirtual ArchetypeContainerType WithKeys(const CONTAINER_OF_KEYS &includeKeys) const
nonvirtual bool RemoveIf(ArgByValueType< key_type > key)
Remove the given item, if it exists. Return true if found and removed.
Definition Mapping.inl:237
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
'override' Iterable<>::Map () function so container template defaults to Mapping, and improve that ca...
nonvirtual void RemoveAll()
RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items...
Definition Mapping.inl:242
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:419
nonvirtual void Remove(ArgByValueType< key_type > key)
Remove the given item (which must exist).
Definition Mapping.inl:225
nonvirtual mapped_type LookupValue(ArgByValueType< key_type > key, ArgByValueType< mapped_type > defaultValue=mapped_type{}) const
Definition Mapping.inl:168
nonvirtual Iterable< key_type > Keys() const
Definition Mapping.inl:113
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
nonvirtual Iterator< T > begin() const
Support for ranged for, and STL syntax in general.
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...
Definition Mapping.h:700