Stroika Library 3.0d24
 
Loading...
Searching...
No Matches
MultiSet.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4
8
10
11 /*
12 ********************************************************************************
13 ************************* MultiSet<T, TRAITS>::_IRep ***************************
14 ********************************************************************************
15 */
16 template <typename T, typename TRAITS>
17 bool MultiSet<T, TRAITS>::_IRep::_Equals_Reference_Implementation (const _IRep& rhs) const
18 {
19 if (this == &rhs) {
20 return true;
21 }
22 if (this->size () != rhs.size ()) {
23 return false;
24 }
25 for (auto i = this->MakeIterator (); not i.AtEnd (); ++i) {
26 if (i->fCount != rhs.OccurrencesOf (i->fValue)) {
27 return false;
28 }
29 }
30 return true;
31 }
32
33 /*
34 ********************************************************************************
35 ***************************** MultiSet<T, TRAITS> ******************************
36 ********************************************************************************
37 */
38 template <typename T, typename TRAITS>
40 requires (IEqualsComparer<equal_to<T>, T>)
41 : MultiSet{equal_to<T>{}}
42 {
43 _AssertRepValidType ();
44 }
45 template <typename T, typename TRAITS>
46 template <IEqualsComparer<T> EQUALS_COMPARER>
47 inline MultiSet<T, TRAITS>::MultiSet (EQUALS_COMPARER&& equalsComparer)
48 : inherited{Factory::MultiSet_Factory<T, TRAITS, remove_cvref_t<EQUALS_COMPARER>>::Default () (forward<EQUALS_COMPARER> (equalsComparer))}
49 {
50 _AssertRepValidType ();
51 }
52#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
53 template <typename T, typename TRAITS>
54 template <IIterableOfTo<typename TRAITS::CountedValueType> ITERABLE_OF_ADDABLE>
55 inline MultiSet<T, TRAITS>::MultiSet (ITERABLE_OF_ADDABLE&& src)
56 requires (IEqualsComparer<equal_to<T>, T> and not derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, MultiSet<T, TRAITS>>)
57 : MultiSet{}
58 {
59 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
60 _AssertRepValidType ();
61 }
62#endif
63 template <typename T, typename TRAITS>
64 template <IEqualsComparer<T> EQUALS_COMPARER, IIterableOfTo<typename TRAITS::CountedValueType> ITERABLE_OF_ADDABLE>
65 inline MultiSet<T, TRAITS>::MultiSet (EQUALS_COMPARER&& equalsComparer, ITERABLE_OF_ADDABLE&& src)
66 : MultiSet{forward<EQUALS_COMPARER> (equalsComparer)}
67 {
69 _AssertRepValidType ();
70 }
71 template <typename T, typename TRAITS>
72 inline MultiSet<T, TRAITS>::MultiSet (const shared_ptr<_IRep>& rep) noexcept
73 : inherited{(RequireExpression (rep != nullptr), rep)}
74 {
75 _AssertRepValidType ();
76 }
77 template <typename T, typename TRAITS>
78 inline MultiSet<T, TRAITS>::MultiSet (shared_ptr<_IRep>&& rep) noexcept
79 : inherited{(RequireExpression (rep != nullptr), move (rep))}
80 {
81 _AssertRepValidType ();
82 }
83 template <typename T, typename TRAITS>
84 MultiSet<T, TRAITS>::MultiSet (const initializer_list<T>& src)
85 requires (IEqualsComparer<equal_to<T>, T>)
86 : MultiSet{}
87 {
88 AddAll (src);
89 _AssertRepValidType ();
90 }
91 template <typename T, typename TRAITS>
92 template <IEqualsComparer<T> EQUALS_COMPARER>
93 MultiSet<T, TRAITS>::MultiSet (EQUALS_COMPARER&& equalsComparer, const initializer_list<T>& src)
94 : MultiSet{forward<EQUALS_COMPARER> (equalsComparer)}
95 {
96 AddAll (src);
97 _AssertRepValidType ();
98 }
99 template <typename T, typename TRAITS>
100 MultiSet<T, TRAITS>::MultiSet (const initializer_list<value_type>& src)
101 : MultiSet{}
102 {
103 AddAll (src);
104 _AssertRepValidType ();
105 }
106 template <typename T, typename TRAITS>
107 template <IEqualsComparer<T> EQUALS_COMPARER>
108 MultiSet<T, TRAITS>::MultiSet (EQUALS_COMPARER&& equalsComparer, const initializer_list<value_type>& src)
109 : MultiSet{forward<EQUALS_COMPARER> (equalsComparer)}
110 {
111 AddAll (src);
112 _AssertRepValidType ();
113 }
114 template <typename T, typename TRAITS>
115 template <IInputIterator<typename TRAITS::CountedValueType> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
116 MultiSet<T, TRAITS>::MultiSet (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
117 requires (IEqualsComparer<equal_to<T>, T>)
118 : MultiSet{}
119 {
120 AddAll (forward<ITERATOR_OF_ADDABLE> (start), forward<ITERATOR_OF_ADDABLE2> (end));
121 _AssertRepValidType ();
122 }
123 template <typename T, typename TRAITS>
124 template <IEqualsComparer<T> EQUALS_COMPARER, IInputIterator<typename TRAITS::CountedValueType> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
125 MultiSet<T, TRAITS>::MultiSet (EQUALS_COMPARER&& equalsComparer, ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
126 : MultiSet{forward<EQUALS_COMPARER> (equalsComparer)}
127 {
129 _AssertRepValidType ();
130 }
131 template <typename T, typename TRAITS>
132 auto MultiSet<T, TRAITS>::TotalOccurrences () const -> CounterType
133 {
134 CounterType sum = 0;
135 for (value_type i : *this) {
136 sum += i.fCount;
137 }
138 return sum;
139 }
140 template <typename T, typename TRAITS>
142 {
143 Iterator<value_type> result{nullptr};
144 this->Remove (i, &result);
145 return result;
146 }
147 template <typename T, typename TRAITS>
149 {
150 RemoveAll ();
151 }
152 template <typename T, typename TRAITS>
154 {
155 // Need explicit struct because we need to re-create the iterator on copies
156 // Not just simple map cuz must pause and 'create' new extra elements
157 struct Context_ {
158 MultiSet<T, TRAITS> fOriginalMultiset;
159 Iterator<typename TRAITS::CountedValueType> fCurrentIteratorOverOrig;
160 size_t fIthAdvanceOfIterator{0}; // because not a random-accessor iterator so hard to compute without tracking
161 size_t fIthOfCurrentIterator{0};
162 Context_ (const Context_& rhs)
163 : fOriginalMultiset{rhs.fOriginalMultiset}
164 , fCurrentIteratorOverOrig{fOriginalMultiset.MakeIterator ()}
165 , fIthAdvanceOfIterator{rhs.fIthAdvanceOfIterator}
166 , fIthOfCurrentIterator{rhs.fIthOfCurrentIterator}
167 {
168 std::advance (fCurrentIteratorOverOrig, fIthAdvanceOfIterator);
169 }
170 Context_ (const MultiSet<T, TRAITS>& ms)
171 : fOriginalMultiset{ms}
172 , fCurrentIteratorOverOrig{fOriginalMultiset.MakeIterator ()}
173 {
174 }
175 Context_& operator= (Context_&) = delete; // could implement but I think no need
176 };
177 function<optional<T> ()> getNext = [context = Context_{*this}] () mutable -> optional<T> {
178 again:
179 if (context.fCurrentIteratorOverOrig) {
180 if (context.fIthOfCurrentIterator < context.fCurrentIteratorOverOrig->fCount) {
181 ++context.fIthOfCurrentIterator;
182 return context.fCurrentIteratorOverOrig->fValue;
183 }
184 else {
185 ++context.fCurrentIteratorOverOrig;
186 ++context.fIthAdvanceOfIterator;
187 context.fIthOfCurrentIterator = 0;
188 goto again;
189 }
190 }
191 return nullopt;
192 };
193 return Traversal::CreateGenerator (getNext);
194 }
195 template <typename T, typename TRAITS>
197 {
198 return this->template Map<Iterable<T>> ([] (const typename TRAITS::CountedValueType& cv) { return cv.fValue; });
199 }
200 template <typename T, typename TRAITS>
201 optional<typename TRAITS::CountedValueType> MultiSet<T, TRAITS>::Top () const
202 {
203 return this->inherited::Top ([] (const typename TRAITS::CountedValueType& lhs, const typename TRAITS::CountedValueType& rhs) {
204 return lhs.fCount > rhs.fCount;
205 });
206 }
207 template <typename T, typename TRAITS>
209 {
210 return this->inherited::Top (n, [] (const typename TRAITS::CountedValueType& lhs, const typename TRAITS::CountedValueType& rhs) {
211 return lhs.fCount > rhs.fCount;
212 });
213 }
214 template <typename T, typename TRAITS>
216 {
217 if (auto t = Top ()) {
218 return t->fValue;
219 }
220 return nullopt;
221 }
222 template <typename T, typename TRAITS>
224 {
225 return Top (n).template Map<Iterable<T>> ([] (const typename TRAITS::CountedValueType& cv) { return cv.fValue; });
226 }
227 template <typename T, typename TRAITS>
229 {
230 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().GetElementEqualsComparer ();
231 }
232 template <typename T, typename TRAITS>
233 inline bool MultiSet<T, TRAITS>::Contains (ArgByValueType<T> item) const
234 {
235 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Contains (item);
236 }
237 template <typename T, typename TRAITS>
239 {
240 _SafeReadRepAccessor<_IRep> tmp{this}; // important to use READ not WRITE accessor, because write accessor would have already cloned the data
241 if (not tmp._ConstGetRep ().empty ()) {
242 this->_fRep = tmp._ConstGetRep ().CloneEmpty ();
244 }
245 template <typename T, typename TRAITS>
246 inline size_t MultiSet<T, TRAITS>::RemoveAll (ArgByValueType<T> item)
247 {
248 return RemoveIf (item, OccurrencesOf (item));
249 }
250 template <typename T, typename TRAITS>
251 inline void MultiSet<T, TRAITS>::Add (ArgByValueType<T> item)
252 {
253 _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (item, 1);
254 }
255 template <typename T, typename TRAITS>
256 inline void MultiSet<T, TRAITS>::Add (ArgByValueType<T> item, CounterType count)
257 {
258 _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (item, count);
259 }
260 template <typename T, typename TRAITS>
261 inline void MultiSet<T, TRAITS>::Add (const value_type& item)
262 {
263 _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (item.fValue, item.fCount);
264 }
265 template <typename T, typename TRAITS>
266 template <IInputIterator<typename TRAITS::CountedValueType> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
267 void MultiSet<T, TRAITS>::AddAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
268 {
269 for (ITERATOR_OF_ADDABLE i = forward<ITERATOR_OF_ADDABLE> (start); i != forward<ITERATOR_OF_ADDABLE2> (end); ++i) {
270 Add (*i);
271 }
272 }
273 template <typename T, typename TRAITS>
274 template <IIterableOfTo<typename TRAITS::CountedValueType> ITERABLE_OF_ADDABLE>
275 void MultiSet<T, TRAITS>::AddAll (ITERABLE_OF_ADDABLE&& items)
276 {
277 // see https://github.com/SophistSolutions/Stroika/issues/781 (STK-645)
278 if constexpr (std::is_convertible_v<remove_cvref_t<ITERABLE_OF_ADDABLE>*, const MultiSet<T, TRAITS>*>) {
279 if (static_cast<const Iterable<value_type>*> (this) == static_cast<const Iterable<value_type>*> (&items)) [[unlikely]] {
280 // very rare corner case
281 using VEC_ELT_T = typename remove_cvref_t<ITERABLE_OF_ADDABLE>::value_type;
282 using ELTS_IT_T = decltype (items.begin ());
283 vector<VEC_ELT_T> copy{std::begin (items), ELTS_IT_T{std::end (items)}}; // because you can not iterate over a container while modifying it
284 for (const auto& i : copy) {
285 Add (i);
286 }
287 return;
288 }
289 }
290 /*
291 * \note NO source-side _IRep::PeekContiguousStorage () fast path here, unlike Set<T>::AddAll (),
292 * Collection<T>::AddAll () and KeyedCollection<T,KEY>::AddAll (). Tried and NOT viable -
293 * recorded so it is not re-attempted:
294 *
295 * Measured cost of not having it: ~1.10x versus filling from a vector (Tests/52
296 * "MultiSet<int>::AddAll (): vector source vs STROIKA source"), ie about 10%.
297 *
298 * Why it cannot be done the way the others do it: MultiSet<T> derives from
299 * Iterable<TRAITS::CountedValueType>, NOT from Iterable<T>. The common source is a bare-T
300 * container (a Sequence<T>), and reaching ITS storage means naming Iterable<T>::_IRep and
301 * constructing an Iterable<T>::_SafeReadRepAccessor - both PROTECTED members of a class
302 * this one does not derive from. The inherited accessor is the CountedValueType one, whose
303 * constructor will not take a const Iterable<T>*.
304 *
305 * A peek restricted to the counted-type source (ie another MultiSet) does compile, but
306 * that is the rare case and is not what the measurement above covers, so it would be an
307 * unmeasurable change.
308 *
309 * NOT actually blocked, to be clear - and no change to Iterable is needed: a small shim
310 * deriving from Iterable<T> purely to forward the protected accessor would reach it fine.
311 * It is just not worth the machinery for ~10% at this stage, where the interest is
312 * correctness and large wins --LGP 2026-08-22. Revisit only if this path shows up hot in a
313 * real profile.
314 */
315 for (const auto& i : items) {
316 Add (i);
317 }
318 }
319 template <typename T, typename TRAITS>
320 inline void MultiSet<T, TRAITS>::Remove (ArgByValueType<T> item, CounterType count)
322 Verify (_SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (item, count) == count);
323 }
324 template <typename T, typename TRAITS>
326 {
327 Require (not i.AtEnd ());
328 auto [writerRep, patchedIterator] = _GetWritableRepAndPatchAssociatedIterator (i);
329 writerRep->Remove (patchedIterator, nextI);
330 }
331 template <typename T, typename TRAITS>
332 inline size_t MultiSet<T, TRAITS>::RemoveIf (ArgByValueType<T> item, CounterType count)
333 {
334 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (item, count);
335 }
336 template <typename T, typename TRAITS>
337 inline void MultiSet<T, TRAITS>::UpdateCount (const Iterator<value_type>& i, CounterType newCount, Iterator<value_type>* nextI)
338 {
339 Require (not i.AtEnd ());
340 auto [writerRep, patchedIterator] = _GetWritableRepAndPatchAssociatedIterator (i);
341 writerRep->UpdateCount (patchedIterator, newCount, nextI);
343 template <typename T, typename TRAITS>
344 inline void MultiSet<T, TRAITS>::SetCount (ArgByValueType<T> i, CounterType newCount)
345 {
346 CounterType cnt = OccurrencesOf (i);
347 if (newCount > cnt) {
348 Add (i, newCount - cnt);
349 }
350 else if (newCount < cnt) {
351 Remove (i, cnt - newCount);
352 }
353 }
354 template <typename T, typename TRAITS>
355 inline auto MultiSet<T, TRAITS>::OccurrencesOf (ArgByValueType<T> item) const -> CounterType
356 {
357 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().OccurrencesOf (item);
358 }
359 template <typename T, typename TRAITS>
360 template <typename RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
361 inline RESULT_CONTAINER MultiSet<T, TRAITS>::Map (ELEMENT_MAPPER&& elementMapper) const
362 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, typename TRAITS::CountedValueType>, typename RESULT_CONTAINER::value_type> or
363 convertible_to<invoke_result_t<ELEMENT_MAPPER, typename TRAITS::CountedValueType>, optional<typename RESULT_CONTAINER::value_type>>)
364 {
365 if constexpr (same_as<RESULT_CONTAINER, MultiSet>) {
366 // clone the rep so we retain the ordering function
367 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper),
368 RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
369 }
370 else {
371 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper)); // default Iterable<> interpretation
372 }
373 }
374 template <typename T, typename TRAITS>
375 template <derived_from<Iterable<typename TRAITS::CountedValueType>> RESULT_CONTAINER, predicate<typename TRAITS::CountedValueType> INCLUDE_PREDICATE>
376 inline RESULT_CONTAINER MultiSet<T, TRAITS>::Where (INCLUDE_PREDICATE&& includeIfTrue) const
377 {
378 if constexpr (same_as<RESULT_CONTAINER, MultiSet>) {
379 // clone the rep so we retain the ordering function
380 return inherited::template Where<RESULT_CONTAINER> (
381 forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
382 }
383 else {
384 return inherited::template Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue)); // default Iterable<> interpretation
385 }
386 }
387 template <typename T, typename TRAITS>
389 {
390 _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (item, 1);
391 return *this;
392 }
393 template <typename T, typename TRAITS>
395 {
396 AddAll (items);
397 return *this;
398 }
399 template <typename T, typename TRAITS>
401 {
402 Require (not i.AtEnd ());
403 using element_type = typename inherited::_SharedByValueRepType::element_type;
404 Iterator<value_type> patchedIterator = i;
405 element_type* writableRep = this->_fRep.rwget ([&] (const element_type& prevRepPtr) -> typename inherited::_SharedByValueRepType::shared_ptr_type {
406 return Debug::UncheckedDynamicCast<const _IRep&> (prevRepPtr).CloneAndPatchIterator (&patchedIterator);
407 });
408 AssertNotNull (writableRep);
409 return make_tuple (Debug::UncheckedDynamicCast<_IRep*> (writableRep), move (patchedIterator));
410 }
411 template <typename T, typename TRAITS>
412 inline void MultiSet<T, TRAITS>::_AssertRepValidType () const
413 {
415 _SafeReadRepAccessor<_IRep>{this};
416 }
417 }
418 template <typename T, typename TRAITS>
419 inline bool MultiSet<T, TRAITS>::operator== (const MultiSet& rhs) const
420 {
421 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Equals (_SafeReadRepAccessor<_IRep>{&rhs}._ConstGetRep ());
422 }
423
424}
#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 RequireExpression(c)
Definition Assertions.h:268
#define Verify(c)
Definition Assertions.h:420
nonvirtual MultiSet & operator+=(ArgByValueType< T > item)
Definition MultiSet.inl:388
nonvirtual void AddAll(ITERATOR_OF_ADDABLE &&start, ITERATOR_OF_ADDABLE2 &&end)
nonvirtual CounterType TotalOccurrences() const
Definition MultiSet.inl:132
nonvirtual Iterator< value_type > erase(const Iterator< value_type > &i)
Definition MultiSet.inl:141
nonvirtual void Remove(ArgByValueType< T > item, CounterType count=1)
remove the argument data from the multiset. The data specified MUST exist (require) - else use Remove...
Definition MultiSet.inl:320
nonvirtual Iterable< T > Elements() const
Definition MultiSet.inl:153
nonvirtual void UpdateCount(const Iterator< value_type > &i, CounterType newCount, Iterator< value_type > *nextI=nullptr)
Definition MultiSet.inl:337
nonvirtual void Add(ArgByValueType< T > item)
Definition MultiSet.inl:251
nonvirtual ElementEqualityComparerType GetElementEqualsComparer() const
Definition MultiSet.inl:228
typename inherited::value_type value_type
Definition MultiSet.h:149
nonvirtual bool operator==(const MultiSet &rhs) const
Definition MultiSet.inl:419
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
'override' Iterable<>::Map () function so RESULT_CONTAINER defaults to MultiSet, and improve that cas...
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 MultiSet.inl:400
nonvirtual optional< typename TRAITS::CountedValueType > Top() const
Find the most commonly occurring element of the multiset - or the top n of them, ordered most to leas...
Definition MultiSet.inl:201
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
nonvirtual bool Contains(ArgByValueType< T > item) const
Definition MultiSet.inl:233
nonvirtual void RemoveAll()
RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items...
Definition MultiSet.inl:238
nonvirtual optional< T > TopElements() const
Same as Top (), but yielding just the element(s) - without the count.
Definition MultiSet.inl:215
nonvirtual CounterType OccurrencesOf(ArgByValueType< T > item) const
Definition MultiSet.inl:355
nonvirtual size_t RemoveIf(ArgByValueType< T > item, CounterType count=1)
remove the argument data from the multiset (can specify remove of more than are present) - returns nu...
Definition MultiSet.inl:332
nonvirtual void SetCount(ArgByValueType< T > i, CounterType newCount)
Definition MultiSet.inl:344
nonvirtual Iterable< T > UniqueElements() const
Definition MultiSet.inl:196
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:238
nonvirtual CONTAINER_OF_T As(CONTAINER_OF_T_CONSTRUCTOR_ARGS... args) const
static constexpr default_sentinel_t end() noexcept
Support for ranged for, and STL syntax in general.
nonvirtual Iterator< T > MakeIterator() const
Create an iterator object which can be used to traverse the 'Iterable'.
Definition Iterable.inl:305
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