Stroika Library 3.0d24
 
Loading...
Searching...
No Matches
Set.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4
6#include "Stroika/Foundation/Common/Concepts.h"
9
11
12 /*
13 ********************************************************************************
14 ************************************* Set<T> ***********************************
15 ********************************************************************************
16 */
17 template <typename T>
18 inline Set<T>::Set ()
19 requires (IEqualsComparer<equal_to<T>, T>)
20 : Set{equal_to<value_type>{}}
21 {
22 _AssertRepValidType ();
23 }
24 template <typename T>
25 template <IEqualsComparer<T> EQUALS_COMPARER>
26 inline Set<T>::Set (EQUALS_COMPARER&& equalsComparer)
27 : inherited{Factory::Set_Factory<T, remove_cvref_t<EQUALS_COMPARER>>::Default () (forward<EQUALS_COMPARER> (equalsComparer))}
28 {
29 _AssertRepValidType ();
30 }
31 template <typename T>
32 inline Set<T>::Set (const initializer_list<value_type>& src)
33 requires (IEqualsComparer<equal_to<T>, T>)
34 : Set{}
35 {
36 AddAll (src);
37 _AssertRepValidType ();
38 }
39 template <typename T>
40 template <IEqualsComparer<T> EQUALS_COMPARER>
41 inline Set<T>::Set (EQUALS_COMPARER&& equalsComparer, const initializer_list<value_type>& src)
42 : Set{forward<EQUALS_COMPARER> (equalsComparer)}
43 {
44 AddAll (src);
45 _AssertRepValidType ();
46 }
47#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
48 template <typename T>
49 template <IIterableOfTo<T> ITERABLE_OF_ADDABLE>
50 requires (not derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, Set<T>>)
51 inline Set<T>::Set (ITERABLE_OF_ADDABLE&& src)
52 : Set{}
53 {
54 AddAll (forward<ITERABLE_OF_ADDABLE> (src));
55 _AssertRepValidType ();
56 }
57#endif
58 template <typename T>
59 template <IEqualsComparer<T> EQUALS_COMPARER, IIterableOfTo<T> ITERABLE_OF_ADDABLE>
60 inline Set<T>::Set (EQUALS_COMPARER&& equalsComparer, ITERABLE_OF_ADDABLE&& src)
61 : Set{forward<EQUALS_COMPARER> (equalsComparer)}
62 {
64 _AssertRepValidType ();
65 }
66 template <typename T>
67 inline Set<T>::Set (const shared_ptr<_IRep>& src) noexcept
68 : inherited{src}
69 {
70 _AssertRepValidType ();
71 }
72 template <typename T>
73 inline Set<T>::Set (shared_ptr<_IRep>&& src) noexcept
74 : inherited{(RequireExpression (src != nullptr), move (src))}
75 {
76 _AssertRepValidType ();
77 }
78 template <typename T>
79 template <IInputIterator<T> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
80 inline Set<T>::Set (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
81 requires (IEqualsComparer<equal_to<T>, T>)
82 : Set{}
83 {
84 AddAll (forward<ITERATOR_OF_ADDABLE> (start), forward<ITERATOR_OF_ADDABLE2> (end));
85 _AssertRepValidType ();
86 }
87 template <typename T>
88 template <IEqualsComparer<T> EQUALS_COMPARER, IInputIterator<T> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
89 inline Set<T>::Set (EQUALS_COMPARER&& equalsComparer, ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
90 : Set{forward<EQUALS_COMPARER> (equalsComparer)}
91 {
93 _AssertRepValidType ();
94 }
95 template <typename T>
97 {
98 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().GetElementEqualsComparer ();
99 }
100 template <typename T>
101 inline bool Set<T>::Contains (ArgByValueType<value_type> item) const
102 {
103 return _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (item, nullptr, nullptr);
104 }
105 template <typename T>
106 inline bool Set<T>::contains (ArgByValueType<value_type> item) const
107 {
108 return Contains (item);
109 }
110 template <typename T>
112 {
113 return items.All ([&] (ArgByValueType<T> i) { return this->Contains (i); });
114 }
115 template <typename T>
117 {
118 return items.Any ([&] (ArgByValueType<T> i) { return this->Contains (i); });
119 }
120 template <typename T>
121 bool Set<T>::IsSubsetOf (const Set& superset) const
122 {
123 for (const auto& i : *this) {
124 if (not superset.Contains (i)) {
125 return false;
126 }
127 }
128 return true;
129 }
130 template <typename T>
131 inline auto Set<T>::Lookup (ArgByValueType<value_type> item) const -> optional<value_type>
132 {
133 optional<value_type> r;
134 _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (item, &r, nullptr);
135 return r; // don't move due to return value optimization
136 }
137 template <typename T>
138 inline void Set<T>::Add (ArgByValueType<value_type> item)
139 {
140 _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().Add (item);
141 }
142 template <typename T>
143 inline bool Set<T>::AddIf (ArgByValueType<value_type> item)
144 {
145 /*
146 * Note, this is an non-performance optimal implementation, but is not a race, because from the outside
147 * if someone calls AddIf() - they don't know/care if this call or another at the same time is doing the
148 * addition. Any 'race' would be in the logical of the calling code.
149 */
150 if (Contains (item)) {
151 return false;
152 }
153 else {
154 Add (item);
155 return true;
156 }
157 }
158 template <typename T>
159 template <IInputIterator<T> ITERATOR_OF_ADDABLE, sentinel_for<remove_cvref_t<ITERATOR_OF_ADDABLE>> ITERATOR_OF_ADDABLE2>
160 void Set<T>::AddAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE2&& end)
161 {
162 _SafeReadWriteRepAccessor<_IRep> tmp{this};
163 for (auto i = forward<ITERATOR_OF_ADDABLE> (start); i != forward<ITERATOR_OF_ADDABLE2> (end); ++i) {
164 tmp._GetWriteableRep ().Add (*i);
165 }
166 }
167 template <typename T>
168 template <IIterableOfTo<T> ITERABLE_OF_ADDABLE>
169 inline void Set<T>::AddAll (ITERABLE_OF_ADDABLE&& items)
170 {
171 if constexpr (std::is_convertible_v<remove_cvref_t<ITERABLE_OF_ADDABLE>*, const Iterable<value_type>*>) {
172 // very rare corner case
173 if (static_cast<const Iterable<value_type>*> (this) == static_cast<const Iterable<value_type>*> (&items)) [[unlikely]] {
174 vector<value_type> copy{std::begin (items), Iterator<value_type>{std::end (items)}}; // because you can not iterate over a container while modifying it
175 AddAll (std::begin (copy), std::end (copy));
176 return;
177 }
178 }
179 /*
180 * SOURCE-SIDE fast path only. Set<T>::_IRep::Add () takes ONE item (unlike Collection<T>::_IRep,
181 * whose Add () takes a span), so this cannot batch the DESTINATION without an incompatible change
182 * to that interface. It can, however, stop paying a virtual Iterator<T> advance per element, by
183 * walking the source's own buffer when the source is a Stroika container that has one - and that
184 * needs no rep-interface change whatsoever.
185 *
186 * So filling from a Stroika container costs two virtual calls per element (advance + Add) where
187 * filling from a vector costs one, and this removes the first. Measured (Tests/52 "Set<int>::AddAll
188 * (): vector source vs STROIKA source"): a Sequence<int> source cost 1.42x a vector<int> one, with
189 * the destination doing identical tree-insertion work on both sides - so that gap is exactly what
190 * this recovers.
191 *
192 * See Sequence<T>::InsertAll (i, ITERABLE_OF_ADDABLE) for why borrowing the source's buffer while
193 * writing our own rep is safe, and why the same-envelope case must be excluded.
194 */
195 if constexpr (derived_from<remove_cvref_t<ITERABLE_OF_ADDABLE>, Iterable<value_type>>) {
196 if (static_cast<const Iterable<value_type>*> (this) != static_cast<const Iterable<value_type>*> (&items)) [[likely]] {
197 bool handled = false;
198 {
199 _SafeReadWriteRepAccessor<_IRep> destAccessor{this};
200 _IRep& destRep = destAccessor._GetWriteableRep ();
201 _SafeReadRepAccessor<typename Iterable<value_type>::_IRep> srcAccessor{&items};
202 if (auto srcSpan = srcAccessor._ConstGetRep ().PeekContiguousStorage ()) {
203 for (const value_type& v : *srcSpan) {
204 destRep.Add (v);
205 }
206 handled = true;
207 }
208 }
209 if (handled) {
210 return;
211 }
212 }
213 }
214 AddAll (std::begin (items), std::end (items));
215 }
216 template <typename T>
217 inline void Set<T>::Remove (ArgByValueType<value_type> item)
218 {
219 Verify (_SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (item));
220 }
221 template <typename T>
222 inline void Set<T>::Remove (const Iterator<value_type>& i, Iterator<value_type>* nextI)
223 {
224 Require (not i.AtEnd ());
225 auto [writerRep, patchedIterator] = _GetWritableRepAndPatchAssociatedIterator (i);
226 writerRep->Remove (patchedIterator, nextI);
228 template <typename T>
229 inline bool Set<T>::RemoveIf (ArgByValueType<value_type> item)
230 {
231 return _SafeReadWriteRepAccessor<_IRep>{this}._GetWriteableRep ().RemoveIf (item);
232 }
233 template <typename T>
234 template <IInputIterator<T> ITERATOR_OF_ADDABLE>
235 inline size_t Set<T>::RemoveAll (ITERATOR_OF_ADDABLE&& start, ITERATOR_OF_ADDABLE&& end)
236 {
237 size_t cnt{};
238 for (auto i = forward<ITERATOR_OF_ADDABLE> (start); i != end; ++i) {
239 ++cnt;
240 Remove (*i);
241 }
242 return cnt;
243 }
244 template <typename T>
245 template <IIterableOfTo<T> ITERABLE_OF_ADDABLE>
246 inline size_t Set<T>::RemoveAll (const ITERABLE_OF_ADDABLE& s)
247 {
248 return RemoveAll (std::begin (s), std::end (s));
249 }
250 template <typename T>
251 inline void Set<T>::RemoveAll ()
252 {
253 _SafeReadRepAccessor<_IRep> tmp{this}; // important to use READ not WRITE accessor, because write accessor would have already cloned the data
254 if (not tmp._ConstGetRep ().empty ()) {
255 this->_fRep = tmp._ConstGetRep ().CloneEmpty ();
256 }
257 }
258 template <typename T>
259 template <predicate<T> PREDICATE>
260 size_t Set<T>::RemoveAll (PREDICATE&& p)
261 {
262 size_t nRemoved{};
263 for (Iterator<T> i = this->begin (); i != this->end ();) {
264 if (p (*i)) {
265 Remove (i, &i);
266 ++nRemoved;
267 }
268 else {
269 ++i;
270 }
272 return nRemoved;
273 }
274 template <typename T>
275 template <typename RESULT_CONTAINER, invocable<T> ELEMENT_MAPPER>
276 inline RESULT_CONTAINER Set<T>::Map (ELEMENT_MAPPER&& elementMapper) const
277 requires (convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, typename RESULT_CONTAINER::value_type> or
278 convertible_to<invoke_result_t<ELEMENT_MAPPER, T>, optional<typename RESULT_CONTAINER::value_type>>)
279 {
280 if constexpr (same_as<RESULT_CONTAINER, Set>) {
281 // clone the rep so we retain the ordering function, etc
282 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper),
283 RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
284 }
285 else {
286 return inherited::template Map<RESULT_CONTAINER> (forward<ELEMENT_MAPPER> (elementMapper)); // inherited impl fine for this case
287 }
289 template <typename T>
290 template <derived_from<Iterable<T>> RESULT_CONTAINER, predicate<T> INCLUDE_PREDICATE>
291 inline RESULT_CONTAINER Set<T>::Where (INCLUDE_PREDICATE&& includeIfTrue) const
292 {
293 if constexpr (same_as<RESULT_CONTAINER, Set>) {
294 // clone the rep so we retain the ordering function
295 return inherited::template Where<RESULT_CONTAINER> (
296 forward<INCLUDE_PREDICATE> (includeIfTrue), RESULT_CONTAINER{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()});
297 }
298 else {
299 return inherited::template Where<RESULT_CONTAINER> (forward<INCLUDE_PREDICATE> (includeIfTrue)); // default Iterable<> interpretation
300 }
301 }
302 template <typename T>
304 {
305 for (const auto& i : rhs) {
306 if (Contains (i)) {
307 return true;
308 }
309 }
310 return false;
311 }
312 template <typename T>
313 inline bool Set<T>::Intersects (const Set& lhs, const Iterable<value_type>& rhs)
314 {
315 return lhs.Intersects (rhs);
316 }
317 template <typename T>
318 inline bool Set<T>::Intersects (const Iterable<value_type>& lhs, const Set& rhs)
319 {
320 return rhs.Intersects (lhs);
321 }
322 template <typename T>
323 inline bool Set<T>::Intersects (const Set& lhs, const Set& rhs)
324 {
325 // intersection operation is commutative; and O(N) in side we iterate over, and < O(N) in side we do lookups
326 // on, so do iteration on shorter side
327 if (lhs.size () < rhs.size ()) {
328 return rhs.Intersects (static_cast<const Iterable<T>&> (lhs));
329 }
330 else {
331 return lhs.Intersects (static_cast<const Iterable<T>&> (rhs));
332 }
333 }
334 template <typename T>
335 Set<T> Set<T>::Intersection (const Iterable<value_type>& rhs) const
337 using namespace Stroika::Foundation::Common;
338 Set result{this->CloneEmpty ()};
339 /*
340 * note: TRIED using Apply() - and didn't seem to help performance --LGP 2021-11-08
341 */
342 for (const auto& i : rhs) {
343 if (Contains (i)) {
344 result.Add (i);
345 }
346 }
347 return result;
348 }
349 template <typename T>
350 inline Set<T> Set<T>::Intersection (const Set& lhs, const Iterable<value_type>& rhs)
351 {
352 return lhs.Intersection (rhs);
353 }
354 template <typename T>
355 inline Set<T> Set<T>::Intersection (const Iterable<T>& lhs, const Set& rhs)
356 {
357 return rhs.Intersection (lhs);
358 }
359 template <typename T>
360 inline Set<T> Set<T>::Intersection (const Set& lhs, const Set& rhs)
361 {
362 // Require (lhs.GetElementEqualsComparer () == rhs.GetElementEqualsComparer ()); Not LITERALLY required, but results undefined if these comparers produce different answers
363 // union operation is commutative; and O(N) in side we iterate over, and < O(N) in side we do lookups
364 // on, so do iteration on shorter side
365 if (lhs.size () < rhs.size ()) {
366 return rhs.Intersection (static_cast<const Iterable<T>&> (lhs));
367 }
368 else {
369 return lhs.Intersection (static_cast<const Iterable<T>&> (rhs));
370 }
371 }
372 template <typename T>
373 inline Set<T> Set<T>::Union (const Iterable<value_type>& rhs) const
374 {
375 Set r = *this;
376 r.AddAll (rhs);
377 return r;
378 }
379 template <typename T>
380 inline Set<T> Set<T>::Union (ArgByValueType<value_type> rhs) const
381 {
382 Set r = *this;
383 r.Add (rhs);
384 return r;
385 }
386 template <typename T>
387 inline Set<T> Set<T>::Union (const Set& lhs, const Iterable<value_type>& rhs)
388 {
389 return lhs.Union (rhs);
390 }
391 template <typename T>
392 inline Set<T> Set<T>::Union (const Iterable<value_type>& lhs, const Set& rhs)
393 {
394 // union operation is commutative
395 return rhs.Union (lhs);
397 template <typename T>
398 inline Set<T> Set<T>::Union (const Set& lhs, const Set& rhs)
399 {
400 // Require (lhs.GetElementEqualsComparer () == rhs.GetElementEqualsComparer ()); Not LITERALLY required, but results undefined if these comparers produce diffrent answers
401 // union operation is commutative; and O(N) in side we iterate over, and < O(N) in side we do lookups
402 // on, so do iteration on shorter side
403 if (lhs.size () < rhs.size ()) {
404 return rhs.Union (static_cast<const Iterable<T>&> (lhs));
406 else {
407 return lhs.Union (static_cast<const Iterable<T>&> (rhs));
408 }
409 }
410 template <typename T>
411 Set<T> Set<T>::Difference (const Set& rhs) const
412 {
413 using namespace Stroika::Foundation::Common;
414 Set result{this->CloneEmpty ()};
415 /*
416 * whether its better to incrementally create the result set, or better to incrementally remove
417 * from the result set (performance wise) (probably) depends on how close *this and rhs are to one another.
418 *
419 * note: TRIED using Apply() - and didn't seem to help performance --LGP 2021-11-08
420 */
421 for (const auto& i : *this) {
422 if (not rhs.Contains (i)) {
423 result.Add (i);
424 }
425 }
426 return result;
427 }
428 template <typename T>
429 Set<T> Set<T>::Difference (const Iterable<value_type>& rhs) const
430 {
431 /*
432 * We could iterate (doubly nested loop) over both *this and rhs, and that would avoid constructing
433 * an intermediate object. However, in the INNER loop, we would do an O(N) operation, and this way we
434 * probably have an (O(Log(N)) operation in the inner loop. At least for larger containers, that
435 * makes sense (except for requiring more memory temporarily). For smaller ones, it probably doesn't matter.
436 *
437 * OR - maybe better, could CLONE this, and iterate over rhs, and just remove els as needed. for special case where nothing removed
438 * that would be faster (because of COW), and maybe in general faster.
439 *
440 * OR return Difference (Set{this->GetElementEqualsComparer (), rhs});
441 *
442 * note: TRIED using Apply() - and didn't seem to help performance --LGP 2021-11-08
443 */
444 Set<T> result = *this;
445 for (const auto& i : rhs) {
446 result.RemoveIf (i);
447 }
448 return result;
449 }
450 template <typename T>
451 Set<T> Set<T>::Difference (ArgByValueType<value_type> rhs) const
452 {
453 /*
454 * Could implement as return Difference (Set{rhs});
455 * But due to COW in SharedByValue, this is better if 'rhs' not found in this.
456 */
457 Set<T> result = *this;
458 result.RemoveIf (rhs);
459 return result;
460 }
461 template <typename T>
463 {
464 Add (item);
465 return *this;
466 }
467 template <typename T>
469 {
470 AddAll (items);
471 return *this;
472 }
473 template <typename T>
475 {
476 RemoveIf (item);
477 return *this;
478 }
479 template <typename T>
481 {
482 RemoveAll (items);
483 return *this;
484 }
485 template <typename T>
487 {
488 *this = Intersection (items);
489 return *this;
491 template <typename T>
492 inline void Set<T>::clear ()
493 {
494 RemoveAll ();
495 }
496 template <typename T>
498 {
499 Iterator<value_type> r{nullptr};
500 _SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().Lookup (item, nullptr, &r);
501 return move (r);
503 template <typename T>
504 inline auto Set<T>::insert (ArgByValueType<value_type> item) -> pair<const_iterator, bool>
505 {
506 auto i = AddIf (item);
507 return make_pair (this->find (item), i);
508 }
509 template <typename T>
510 inline auto Set<T>::insert (const_iterator /*ignored*/, ArgByValueType<value_type> item) -> pair<const_iterator, bool>
511 {
512 return this->insert (item);
513 }
514 template <typename T>
515 template <class InputIt>
516 inline void Set<T>::insert (InputIt first, InputIt last)
517 {
518 AddAll (first, last);
519 }
520 template <typename T>
521 inline void Set<T>::insert (initializer_list<T> ilist)
522 {
523 AddAll (ilist);
525 template <typename T>
527 {
528 Remove (item);
529 }
530 template <typename T>
532 {
533 Iterator<T> nextI{nullptr};
534 this->Remove (i, &nextI);
535 return nextI;
536 }
537 template <typename T>
538 inline auto Set<T>::CloneEmpty () const -> Set
539 {
540 return Set{_SafeReadRepAccessor<_IRep>{this}._ConstGetRep ().CloneEmpty ()};
541 }
542 template <typename T>
543 auto Set<T>::_GetWritableRepAndPatchAssociatedIterator (const Iterator<value_type>& i) -> tuple<_IRep*, Iterator<value_type>>
544 {
545 Require (not i.AtEnd ());
546 using element_type = typename inherited::_SharedByValueRepType::element_type;
547 Iterator<value_type> patchedIterator = i;
548 element_type* writableRep = this->_fRep.rwget ([&] (const element_type& prevRepPtr) -> typename inherited::_SharedByValueRepType::shared_ptr_type {
549 return Debug::UncheckedDynamicCast<const _IRep&> (prevRepPtr).CloneAndPatchIterator (&patchedIterator);
550 });
551 AssertNotNull (writableRep);
552 return make_tuple (Debug::UncheckedDynamicCast<_IRep*> (writableRep), move (patchedIterator));
553 }
554 template <typename T>
555 inline void Set<T>::_AssertRepValidType () const
556 {
558 [[maybe_unused]] _SafeReadRepAccessor<_IRep> ignored{this};
559 }
560 }
561 template <typename T>
562 inline bool Set<T>::operator== (const Set& rhs) const
563 {
564 return EqualsComparer{}(*this, rhs);
565 }
566 template <typename T>
567 inline bool Set<T>::operator== (const Iterable<value_type>& rhs) const
568 {
569 return EqualsComparer{}(*this, rhs);
570 }
571
572 /*
573 ********************************************************************************
574 ******************************** Set<T>::_IRep *********************************
575 ********************************************************************************
576 */
577 template <typename T>
579 {
580 // for some reps, this is fast (vector, std::map), but others its quite slow, and not that great a test.
581 // so for now, just iterate to see
582 constexpr bool kCanUseGetLengthAsOptimizationCheck_ = false;
583 if (this == &rhs) {
584 return true;
585 }
587 if (this->size () != rhs.size ()) {
588 return false;
589 }
590 }
591 // Note - no need to iterate over rhs because we checked sizes the same
592 [[maybe_unused]] size_t rhsSize{};
593 for (auto i = rhs.MakeIterator (); not i.AtEnd (); ++i) {
594 if (not Lookup (*i, nullptr, nullptr)) {
595 return false;
596 }
597 ++rhsSize;
598 }
600 return rhsSize == this->size ();
601 }
602 return true;
603 }
604
605 /*
606 ********************************************************************************
607 ************************* Set<T>::EqualsComparer *******************************
608 ********************************************************************************
609 */
610 template <typename T>
611 inline bool Set<T>::EqualsComparer::operator() (const Set& lhs, const Set& rhs) const
612 {
613 bool result = _SafeReadRepAccessor<_IRep>{&lhs}._ConstGetRep ().Equals (_SafeReadRepAccessor<_IRep>{&rhs}._ConstGetRep ());
614 Ensure (result == _SafeReadRepAccessor<_IRep>{&rhs}._ConstGetRep ().Equals (_SafeReadRepAccessor<_IRep>{&lhs}._ConstGetRep ())); // if this fails caller probably provided incompatible LHS/RHS comparers
615 return result;
616 }
617 template <typename T>
618 inline bool Set<T>::EqualsComparer::operator() (const Set& lhs, const Iterable<value_type>& rhs) const
619 {
620 return _SafeReadRepAccessor<_IRep>{&lhs}._ConstGetRep ().Equals (_SafeReadRepAccessor<typename Iterable<T>::_IRep>{&rhs}._ConstGetRep ());
621 }
622 template <typename T>
623 inline bool Set<T>::EqualsComparer::operator() (const Iterable<value_type>& lhs, const Set& rhs) const
624 {
625 return _SafeReadRepAccessor<_IRep>{&rhs}._ConstGetRep ().Equals (_SafeReadRepAccessor<typename Iterable<T>::_IRep>{&lhs}._ConstGetRep ());
626 }
627
628 /*
629 ********************************************************************************
630 ******************************* Set<T> operators *******************************
631 ********************************************************************************
632 */
633 template <typename T>
634 inline Set<T> operator+ (const Set<T>& lhs, const Iterable<T>& rhs)
635 {
636 return lhs.Union (rhs);
637 }
638 template <typename T>
639 inline Set<T> operator+ (const Set<T>& lhs, const T& rhs)
640 {
641 return lhs.Union (rhs);
642 }
643 template <typename T>
644 inline Set<T> operator- (const Set<T>& lhs, const Iterable<T>& rhs)
645 {
646 return lhs.Difference (rhs);
647 }
648 template <typename T>
649 inline Set<T> operator- (const Set<T>& lhs, const T& rhs)
650 {
651 return lhs.Difference (rhs);
652 }
653 template <typename T>
654 inline Set<T> operator^ (const Set<T>& lhs, const Iterable<T>& rhs)
655 {
656 return lhs.Intersection (rhs);
657 }
658 template <typename T>
659 inline Set<T> operator^ (const Iterable<T>& lhs, const Set<T>& rhs)
660 {
661 return rhs.Intersection (lhs); // intersection is commutative
662 }
663 template <typename T>
664 inline Set<T> operator^ (const Set<T>& lhs, const Set<T>& rhs)
665 {
666 return lhs.Intersection (rhs);
667 }
668
669}
#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 bool _Equals_Reference_Implementation(const typename Iterable< value_type >::_IRep &rhs) const
Definition Set.inl:578
virtual bool Lookup(ArgByValueType< value_type > item, optional< value_type > *oResult, Iterator< value_type > *iResult) const =0
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
nonvirtual Set & operator^=(const Iterable< value_type > &items)
Definition Set.inl:486
nonvirtual bool contains(ArgByValueType< value_type > item) const
Definition Set.inl:106
nonvirtual bool ContainsAny(const Iterable< value_type > &items) const
Definition Set.inl:116
nonvirtual Iterator< value_type > find(ArgByValueType< value_type > item) const
Definition Set.inl:497
nonvirtual optional< value_type > Lookup(ArgByValueType< value_type > item) const
Definition Set.inl:131
nonvirtual ElementEqualityComparerType GetElementEqualsComparer() const
Definition Set.inl:96
nonvirtual bool AddIf(ArgByValueType< value_type > item)
Definition Set.inl:143
nonvirtual bool Intersects(const Iterable< value_type > &rhs) const
return true iff the Intersection () is non-empty
Definition Set.inl:303
nonvirtual bool IsSubsetOf(const Set &superset) const
Definition Set.inl:121
nonvirtual Set CloneEmpty() const
for return Set<T> { s->GetEqualsComparer(); } - except more efficient - clones settings/dynamic subty...
Definition Set.inl:538
nonvirtual void Remove(ArgByValueType< value_type > item)
Remove the item (given by value or iterator pointing to it) from the contain. The item MUST exist.
Definition Set.inl:217
nonvirtual RESULT_CONTAINER Map(ELEMENT_MAPPER &&elementMapper) const
'override' Iterable<>::Map () function so RESULT_CONTAINER defaults to Set, and improve that case to ...
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
nonvirtual Set & operator+=(ArgByValueType< value_type > item)
Definition Set.inl:462
nonvirtual bool operator==(const Set &rhs) const
Definition Set.inl:562
nonvirtual bool ContainsAll(const Iterable< value_type > &items) const
Definition Set.inl:111
nonvirtual bool RemoveIf(ArgByValueType< value_type > item)
Definition Set.inl:229
nonvirtual void erase(ArgByValueType< value_type > item)
STL-ish alias for Remove ().
Definition Set.inl:526
nonvirtual Set & operator-=(ArgByValueType< value_type > item)
Definition Set.inl:474
nonvirtual pair< const_iterator, bool > insert(ArgByValueType< value_type > item)
Definition Set.inl:504
nonvirtual void Add(ArgByValueType< value_type > item)
Definition Set.inl:138
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 Set.inl:543
nonvirtual void AddAll(ITERATOR_OF_ADDABLE &&start, ITERATOR_OF_ADDABLE2 &&end)
Implementation detail for iterator implementors.
Definition Iterable.h:1743
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:238
nonvirtual bool Any() const
Any() same as not empty (); Any (includeIfTrue) returns true iff includeIfTrue returns true on any va...
nonvirtual CONTAINER_OF_T As(CONTAINER_OF_T_CONSTRUCTOR_ARGS... args) const
nonvirtual bool All(const function< bool(ArgByValueType< T >)> &testEachElt) const
return true iff argument predicate returns true for each element of the iterable
nonvirtual size_t size() const
Returns the number of items contained.
Definition Iterable.inl:311
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
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
Definition TypeHints.h:36
Set< T > operator^(const Set< T > &lhs, const Iterable< T > &rhs)
Definition Set.inl:654
Collection< T > operator+(const Iterable< T > &lhs, const Collection< T > &rhs)
Set< T > operator-(const Set< T > &lhs, const Iterable< T > &rhs)
Definition Set.inl:644