7#include "Stroika/Foundation/Execution/Exceptions.h"
13 static thread_local std::mt19937 sRng_{[] () {
14 auto seed = std::random_device{}();
15 return std::mt19937{seed};
23 inline void SetRandomNumberGenerator (
const std::mt19937& use)
27 inline size_t RandomSize_t (
size_t first,
size_t last)
29 Assert (sRng_.min () <= first);
31 std::uniform_int_distribution<size_t> unif{first, last};
32 size_t result = unif (sRng_);
33 Ensure (result >= first);
34 Ensure (result <= last);
45#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
46 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
47 template <
typename MAPPED_TYPE2>
48 constexpr SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::Link_::Link_ (ArgByValueType<key_type> key, ArgByValueType<MAPPED_TYPE2> val)
49 requires (not same_as<MAPPED_TYPE2, void>)
53 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
54 constexpr SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::Link_::Link_ (ArgByValueType<key_type> key)
55 requires (same_as<MAPPED_TYPE, void>)
60 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
61 constexpr SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::Link_::Link_ (ArgByValueType<value_type> v)
71 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
72 inline SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::SkipList (
const KeyComparerType& keyComparer)
73 : fKeyThreeWayComparer_{keyComparer}
75 GrowHeadLinksIfNeeded_ (1,
nullptr);
77 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
78 SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::SkipList (
const SkipList& src)
79 : fKeyThreeWayComparer_{src.fKeyThreeWayComparer_}
81 GrowHeadLinksIfNeeded_ (1,
nullptr);
82 Link_* prev =
nullptr;
83 Link_* n = src.fHead_[0];
84 while (n !=
nullptr) {
85 Link_* newLink =
new Link_{n->fEntry};
86 if (prev ==
nullptr) {
87 Assert (fHead_.size () == 1);
88 Assert (fHead_[0] ==
nullptr);
92 prev->fNext.push_back (newLink);
98 if (prev !=
nullptr) {
99 Assert (prev->fNext.size () == 0);
100 prev->fNext.push_back (
nullptr);
102 fLength_ = src.fLength_;
105 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
106 inline SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::SkipList (SkipList&& src) noexcept
107 : fKeyThreeWayComparer_{src.fKeyThreeWayComparer_}
108 , fHead_{move (src.fHead_)}
109 , fLength_{src.fLength_}
111 src.fHead_.resize (1);
115 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
116 SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>& SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::operator= (
const SkipList& t)
119 if (t.size () != 0) {
120 Link_* prev =
nullptr;
121 Link_* n = t.fHead_[0];
122 while (n !=
nullptr) {
123 Link_* newLink =
new Link_{n->fEntry};
124 if (prev ==
nullptr) {
125 Assert (fHead_.size () == 1);
126 Assert (fHead_[0] ==
nullptr);
130 prev->fNext.push_back (newLink);
136 Assert (prev->fNext.size () == 0);
137 prev->fNext.push_back (
nullptr);
138 fLength_ = t.fLength_;
143 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
144 inline SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::~SkipList ()
148 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
149 constexpr auto SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::key_comp () const -> KeyComparerType
151 return fKeyThreeWayComparer_;
153 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
158 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
163 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
166 AssertExternallySynchronizedChecker::ReadContext declareContext{*
this};
169 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
172 AssertExternallySynchronizedChecker::ReadContext declareContext{*
this};
173 return fLength_ == 0;
175 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
178 AssertExternallySynchronizedChecker::ReadContext declareContext{*
this};
179 return ForwardIterator{
this};
181 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
182 constexpr auto SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::end () const noexcept -> ForwardIterator
184 return ForwardIterator{};
186 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
192#if qStroika_Foundation_Debug_AssertionsChecked
193 Require (pi->fData_ == movedFrom);
200 Link_* newI = this->fHead_[0];
201 [[maybe_unused]] Link_* newE =
nullptr;
202 Link_* oldI = movedFrom->fHead_[0];
203 [[maybe_unused]] Link_* oldE =
nullptr;
204 while (oldI != pi->fCurrent_) {
205 Assert (newI != newE);
206 Assert (oldI != oldE);
207 newI = newI->fNext[0];
208 oldI = oldI->fNext[0];
209 Assert (newI != newE);
210 Assert (oldI != oldE);
212 Assert (oldI == pi->fCurrent_);
213 pi->fCurrent_ = newI;
214#if qStroika_Foundation_Debug_AssertionsChecked
218 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
219 template <Common::IAnyOf<KEY_TYPE,
typename TRAITS::AlternateFindType> KEYISH_T>
223 AssertExternallySynchronizedChecker::ReadContext declareContext{*
this};
224 Assert (fHead_.size () > 0);
225 LinkVector_
const* startV = &fHead_;
226 for (
size_t linkHeight = fHead_.size (); linkHeight > 0; --linkHeight) {
227 Link_* n = (*startV)[linkHeight - 1];
231 Link_* overShotLink = (startV->size () <= linkHeight) ?
nullptr : (*startV)[linkHeight];
232 while (n != overShotLink) {
233 if constexpr (same_as<Support::SkipList::Stats_Basic, StatsType>) {
236 switch (ToInt (fKeyThreeWayComparer_ (n->fEntry.fKey, key))) {
237 case ToInt (strong_ordering::equal):
239 case ToInt (strong_ordering::less):
241 n = n->fNext[linkHeight - 1];
243 case ToInt (strong_ordering::greater):
251 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
252 template <Common::IAnyOf<KEY_TYPE,
typename TRAITS::AlternateFindType> KEYISH_T>
253 auto SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::FindFirstLink_ (
const KEYISH_T& key)
const -> Link_*
255 AssertExternallySynchronizedChecker::ReadContext declareContext{*
this};
256 Assert (fHead_.size () > 0);
257 LinkVector_
const* startV = &fHead_;
258 Link_* candidate =
nullptr;
259 for (
size_t linkHeight = fHead_.size (); linkHeight > 0; --linkHeight) {
260 Link_* n = (*startV)[linkHeight - 1];
261 Link_* overShotLink = (startV->size () <= linkHeight) ?
nullptr : (*startV)[linkHeight];
266 while (n != overShotLink) {
267 if constexpr (same_as<Support::SkipList::Stats_Basic, StatsType>) {
270 if (fKeyThreeWayComparer_ (n->fEntry.fKey, key) != strong_ordering::less) {
274 n = n->fNext[linkHeight - 1];
278 return (candidate !=
nullptr and fKeyThreeWayComparer_ (candidate->fEntry.fKey, key) == strong_ordering::equal) ? candidate : nullptr;
280 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
285 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
290 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
291 template <
typename ARG_T>
293 requires (not same_as<typename TRAITS::AlternateFindType, void> and same_as<remove_cvref_t<ARG_T>,
typename TRAITS::AlternateFindType>)
295 return ForwardIterator{
this, FindLink_ (key)};
297#if !qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
298 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
299 template <predicate<typename SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::value_type> FUNCTION>
302 for (
auto i = begin (); i; ++i) {
303 if (firstThat (*i)) {
310 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
313 if (
auto o = FindLink_ (key)) {
314 return o->fEntry.fValue;
318 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
319 template <qCompilerAndStdLib_RequiresNotMatchXXXDefined_1_BWA (predicate<
typename SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::value_type>) FUNCTION>
322 for (
auto i : *this) {
323 if (firstThat (*i)) {
329 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
332 AssertExternallySynchronizedChecker::ReadContext declareContext{*
this};
333 return FindLink_ (key) !=
nullptr;
335 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
336#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
340 requires (same_as<mapped_type, void>)
343 AssertExternallySynchronizedChecker::WriteContext declareContext{*
this};
344 if constexpr (TRAITS::kCostlyInvariants) {
347 LinkAndInfoAboutBackPointers_ keyLinkInfo = FindNearest_ (key);
348 Link_* n = keyLinkInfo.fLink;
350 Link_* newLink =
new Link_{key};
351 AddLink_ (newLink, keyLinkInfo.fLinksPointingToReturnedLink);
352 if constexpr (TRAITS::kCostlyInvariants) {
355 if (oAddedI !=
nullptr) [[unlikely]] {
356 *oAddedI = ForwardIterator{
this, newLink};
361 switch (TRAITS::kAddOrExtendOrReplaceMode) {
362 case AddOrExtendOrReplaceMode::eAddIfMissing:
364 case AddOrExtendOrReplaceMode::eAddReplaces:
365 n->fEntry.fKey = key;
366 if constexpr (TRAITS::kCostlyInvariants) {
369 if (oAddedI !=
nullptr) [[unlikely]] {
370 *oAddedI = ForwardIterator{
this, n};
373 case AddOrExtendOrReplaceMode::eAddExtras: {
374 Link_* newLink =
new Link_{key};
375 AddLink_ (newLink, keyLinkInfo.fLinksPointingToReturnedLink);
376 if constexpr (TRAITS::kCostlyInvariants) {
379 if (oAddedI !=
nullptr) [[unlikely]] {
380 *oAddedI = ForwardIterator{
this, newLink};
384 case AddOrExtendOrReplaceMode::eDuplicatesRejected:
386 Execution::Throw (kExcept_);
392 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
393#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
394 template <
typename CHECK_T>
395 inline bool SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::Add2_ (ArgByValueType<key_type> key, ArgByValueType<CHECK_T> val, ForwardIterator* oAddedI)
397 template <
typename CHECK_T>
398 inline bool SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::Add (ArgByValueType<key_type> key, ArgByValueType<CHECK_T> val, ForwardIterator* oAddedI)
399 requires (not same_as<mapped_type, void>)
402 AssertExternallySynchronizedChecker::WriteContext declareContext{*
this};
403 if constexpr (TRAITS::kCostlyInvariants) {
406 LinkAndInfoAboutBackPointers_ keyLinkInfo = FindNearest_ (key);
407 Link_* n = keyLinkInfo.fLink;
408 if (keyLinkInfo.fLink ==
nullptr) {
409 Link_* newLink =
new Link_{key, val};
410 AddLink_ (newLink, keyLinkInfo.fLinksPointingToReturnedLink);
411 if constexpr (TRAITS::kCostlyInvariants) {
414 if (oAddedI !=
nullptr) [[unlikely]] {
415 *oAddedI = ForwardIterator{
this, newLink};
420 switch (TRAITS::kAddOrExtendOrReplaceMode) {
421 case AddOrExtendOrReplaceMode::eAddIfMissing:
423 case AddOrExtendOrReplaceMode::eAddReplaces:
424 n->fEntry.fKey = key;
425 n->fEntry.fValue = val;
426 if constexpr (TRAITS::kCostlyInvariants) {
429 if (oAddedI !=
nullptr) [[unlikely]] {
430 *oAddedI = ForwardIterator{
this, n};
433 case AddOrExtendOrReplaceMode::eAddExtras: {
435 Link_* newLink =
new Link_{key, val};
436 AddLink_ (newLink, keyLinkInfo.fLinksPointingToReturnedLink);
437 if constexpr (TRAITS::kCostlyInvariants) {
440 if (oAddedI !=
nullptr) [[unlikely]] {
441 *oAddedI = ForwardIterator{
this, newLink};
445 case AddOrExtendOrReplaceMode::eDuplicatesRejected:
447 Execution::Throw (kExcept_);
453 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
454 inline bool SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::Add (
const value_type& v, ForwardIterator* oAddedI)
456 return Add (v.fKey, v.fValue, oAddedI);
458 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
459 void SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::AddLink_ (Link_* link,
const LinkVector_& links)
461 AssertExternallySynchronizedChecker::WriteContext declareContext{*
this};
463 size_t newLinkHeight = DetermineLinkHeight_ ();
464 link->fNext.resize (newLinkHeight);
465 size_t linksToPatch = min (fHead_.size (), newLinkHeight);
466 for (
size_t i = 0; i < linksToPatch; ++i) {
467 Link_* nextL =
nullptr;
468 if (links[i] ==
nullptr) {
473 if constexpr (same_as<Support::SkipList::Stats_Basic, StatsType>) {
474 ++fStats_.fRotations;
476 Link_* oldLink = links[i];
478 nextL = oldLink->fNext[i];
479 oldLink->fNext[i] = link;
481 link->fNext[i] = nextL;
483 GrowHeadLinksIfNeeded_ (newLinkHeight, link);
486 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
491 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
495 LinkAndInfoAboutBackPointers_ keyLinkInfo = FindNearest_ (it);
497 RemoveLink_ (keyLinkInfo.fLink, keyLinkInfo.fLinksPointingToReturnedLink);
498 if constexpr (TRAITS::kCostlyInvariants) {
502 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
507 LinkAndInfoAboutBackPointers_ keyLinkInfo = FindNearest_ (i);
509 Link_* after = keyLinkInfo.fLink->fNext[0];
510 RemoveLink_ (keyLinkInfo.fLink, keyLinkInfo.fLinksPointingToReturnedLink);
511 if constexpr (TRAITS::kCostlyInvariants) {
516 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
519 AssertExternallySynchronizedChecker::WriteContext declareContext{*
this};
520 if constexpr (TRAITS::kCostlyInvariants) {
523 LinkAndInfoAboutBackPointers_ keyLinkInfo = FindNearest_ (key);
524 if (keyLinkInfo.fLink !=
nullptr) {
525 RemoveLink_ (keyLinkInfo.fLink, keyLinkInfo.fLinksPointingToReturnedLink);
526 if constexpr (TRAITS::kCostlyInvariants) {
535 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
538 AssertExternallySynchronizedChecker::WriteContext declareContext{*
this};
539 for (
auto it = links.begin (); it != links.end (); ++it) {
540 size_t index = it - links.begin ();
541 Link_** patchLink = (*it ==
nullptr) ? &fHead_[index] : &(*it)->fNext[index];
542 if (*patchLink == n) {
543 if constexpr (same_as<Support::SkipList::Stats_Basic, StatsType>) {
544 ++fStats_.fRotations;
546 *patchLink = n->fNext[index];
552 if (n->fNext.size () == fHead_.size ()) {
553 ShrinkHeadLinksIfNeeded_ ();
558 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
559 size_t SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::DetermineLinkHeight_ ()
const
561 constexpr size_t kMaxNewGrowth = 1;
562 size_t linkHeight = 1;
563 size_t maxHeight = min (fHead_.size () + kMaxNewGrowth, size_t (kMaxLinkHeight_));
564 while ((linkHeight < maxHeight) and (Private_::RandomSize_t (1, 100) <= GetLinkHeightProbability ())) {
569 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
570 void SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::GrowHeadLinksIfNeeded_ (
size_t newSize, Link_* linkToPointTo)
572 if (newSize > fHead_.size ()) {
573 fHead_.resize (newSize, linkToPointTo);
574 Assert (fHead_[newSize - 1] == linkToPointTo);
577 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
578 void SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::ShrinkHeadLinksIfNeeded_ ()
580 Require (fHead_.size () >= 1);
581 for (
size_t i = fHead_.size () - 1; i >= 1; --i) {
582 if (fHead_[i] ==
nullptr) {
586 Ensure (fHead_.size () >= 1);
588 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
591 AssertExternallySynchronizedChecker::WriteContext declareContext{*
this};
592 Link_* link = (fHead_.size () == 0) ?
nullptr : fHead_[0];
593 while (link !=
nullptr) {
594 Link_* nextLink = link->fNext[0];
601 Ensure (size () == 0);
603 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
606 LinkVector_ linksPointingToReturnedLink;
607 key_type key = std::get_if<key_type> (&keyOrI) ? std::get<key_type> (keyOrI) : get<ForwardIterator> (keyOrI).fCurrent_->fEntry.fKey;
609 Assert (fHead_.size () > 0);
610 linksPointingToReturnedLink = fHead_;
611 Link_* newOverShotLink =
nullptr;
612 Link_* foundLink =
nullptr;
613 Assert (not linksPointingToReturnedLink.empty ());
614 size_t linkIndex = linksPointingToReturnedLink.size () - 1;
616 Link_* n = linksPointingToReturnedLink[linkIndex];
620 Link_* overShotLink = newOverShotLink;
621 Assert (n ==
nullptr or overShotLink ==
nullptr or
622 (fKeyThreeWayComparer_ (n->fEntry.fKey, overShotLink->fEntry.fKey) != strong_ordering::greater));
624 linksPointingToReturnedLink[linkIndex] =
nullptr;
625 while (n != overShotLink) {
626 if constexpr (same_as<Support::SkipList::Stats_Basic, StatsType>) {
629 switch (ToInt (fKeyThreeWayComparer_ (n->fEntry.fKey, key))) {
630 case ToInt (strong_ordering::equal):
631 if (
std::get_if<key_type> (&keyOrI) or n == get<ForwardIterator> (keyOrI).fCurrent_) {
633 newOverShotLink = foundLink;
637 linksPointingToReturnedLink[linkIndex] = n;
638 n = n->fNext[linkIndex];
642 case ToInt (strong_ordering::less):
643 linksPointingToReturnedLink[linkIndex] = n;
644 n = n->fNext[linkIndex];
647 case ToInt (strong_ordering::greater):
658 if (linkIndex > 0 and linksPointingToReturnedLink[linkIndex] !=
nullptr) {
659 linksPointingToReturnedLink[linkIndex - 1] = linksPointingToReturnedLink[linkIndex];
661 }
while (linkIndex-- != 0);
663 Ensure (foundLink ==
nullptr or fKeyThreeWayComparer_ (foundLink->fEntry.fKey, key) == strong_ordering::equal);
668 return LinkAndInfoAboutBackPointers_{foundLink, move (linksPointingToReturnedLink)};
671 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
674 Require (fHead_.size () >= 1);
677 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
678 auto SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::GetLast_ () const -> Link_*
680 Require (fHead_.size () >= 1);
681 size_t linkIndex = fHead_.size () - 1;
682 Link_* n = fHead_[linkIndex];
686 while (n !=
nullptr) {
688 n = n->fNext[linkIndex];
691 if (linkIndex == 0) {
699 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
700 template <qCompilerAndStdLib_RequiresNotMatchXXXDefined_1_BWA (invocable<
typename SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::value_type>) FUNCTION>
701 inline void SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::Apply (FUNCTION&& doToElement)
const
704 std::for_each (begin (), end (), forward<FUNCTION> (doToElement));
706 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
709 LinkAndInfoAboutBackPointers_ keyLinkInfo = FindNearest_ (key);
710 if (keyLinkInfo.fLink !=
nullptr and keyLinkInfo.fLink->fNext.size () <= fHead_.size ()) {
711 if (keyLinkInfo.fLink->fNext.size () == fHead_.size ()) {
712 GrowHeadLinksIfNeeded_ (fHead_.size () + 1, keyLinkInfo.fLink);
713 keyLinkInfo.fLinksPointingToReturnedLink.resize (fHead_.size (), keyLinkInfo.fLink);
715 size_t oldLinkHeight = keyLinkInfo.fLink->fNext.size ();
716 keyLinkInfo.fLink->fNext.resize (fHead_.size (),
nullptr);
717 size_t newLinkHeight = keyLinkInfo.fLink->fNext.size ();
718 Assert (oldLinkHeight < newLinkHeight);
719 for (
size_t i = oldLinkHeight; i <= newLinkHeight - 1; ++i) {
720 if (keyLinkInfo.fLinksPointingToReturnedLink[i] ==
nullptr) {
721 fHead_[i] = keyLinkInfo.fLink;
723 else if (keyLinkInfo.fLinksPointingToReturnedLink[i] == keyLinkInfo.fLink) {
727 if constexpr (same_as<Support::SkipList::Stats_Basic, StatsType>) {
728 ++fStats_.fRotations;
730 Link_* oldLink = keyLinkInfo.fLinksPointingToReturnedLink[i];
732 Assert (oldLink->fNext.size () > i);
733 Link_* nextL = oldLink->fNext[i];
734 oldLink->fNext[i] = keyLinkInfo.fLink;
735 keyLinkInfo.fLink->fNext[i] = nextL;
740 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
741 template <
typename CHECKED_T>
743 requires (not same_as<MAPPED_TYPE, void>)
745 const_cast<ForwardIterator&
> (it).UpdateValue (newValue);
747 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
750 if (empty ()) [[unlikely]] {
756 double indexBase = (GetLinkHeightProbability () == 0) ? 0 : 1 / (GetLinkHeightProbability () / 100.0);
757 size_t height[kMaxLinkHeight_];
758 size_t lastValidHeight = 0;
759 for (
size_t i = 0; i <
sizeof (height) /
sizeof (
size_t); ++i) {
760 height[i] = size_t (pow (indexBase,
double (i)));
761 if (height[i] == 0 or height[i] > size ()) {
768 Link_* link = fHead_[0];
770 fHead_.resize (kMaxLinkHeight_);
772 Link_** patchLinks[kMaxLinkHeight_];
773 for (
size_t i = 0; i <
sizeof (patchLinks) /
sizeof (
size_t); ++i) {
774 patchLinks[i] = &fHead_[i];
778 while (link !=
nullptr) {
779 Link_* next = link->fNext[0];
780 link->fNext.clear ();
781#if qStroika_Foundation_Debug_AssertionsChecked
782 bool patched =
false;
784 for (
size_t hIndex = lastValidHeight + 1; hIndex-- > 0;) {
785 if (index >= height[hIndex] and (index % height[hIndex] == 0)) {
786 link->fNext.resize (hIndex + 1,
nullptr);
787 for (
size_t patchIndex = link->fNext.size (); patchIndex-- > 0;) {
788 *patchLinks[patchIndex] = link;
789 patchLinks[patchIndex] = &link->fNext[patchIndex];
791#if qStroika_Foundation_Debug_AssertionsChecked
797#if qStroika_Foundation_Debug_AssertionsChecked
804 Assert (index == size () + 1);
805 ShrinkHeadLinksIfNeeded_ ();
807 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
810 if (totalHeight !=
nullptr) {
812 size_t maxLinkHeight = 0;
813 Link_* n = fHead_[0];
814 while (n !=
nullptr) {
815 maxLinkHeight = max (maxLinkHeight, n->fNext.size ());
816 *totalHeight += n->fNext.size ();
819 Assert (maxLinkHeight == fHead_.size ());
821 return fHead_.size ();
823 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
826#if qStroika_Foundation_Debug_AssertionsChecked
830#if qStroika_Foundation_Debug_AssertionsChecked
831 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
832 void SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::Invariant_ () const noexcept
835 const Link_* n = fHead_[0];
836 while (n !=
nullptr) {
838 KEY_TYPE oldKey = n->fEntry.fKey;
839 for (
size_t i = 1; i < n->fNext.size (); ++i) {
840 const Link_* newN = n->fNext[i];
842 Assert (newN ==
nullptr);
846 Assert (newN ==
nullptr or fKeyThreeWayComparer_ (oldKey, newN->fEntry.fKey) != strong_ordering::greater);
849 Assert (not n->fNext.empty ());
851 Assert (n ==
nullptr or fKeyThreeWayComparer_ (n->fEntry.fKey, oldKey) != strong_ordering::less);
853 Assert (sz == this->fLength_);
862 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
863 constexpr SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::ForwardIterator::ForwardIterator (
const SkipList* data, UnderlyingIteratorRep startAt) noexcept
865#if qStroika_Foundation_Debug_AssertionsChecked
872 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
873 constexpr SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::ForwardIterator::ForwardIterator (
const SkipList* data) noexcept
877#if qStroika_Foundation_Debug_AssertionsChecked
878 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
879 SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::ForwardIterator::~ForwardIterator ()
884 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
889 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
892 return fCurrent_ ==
nullptr;
894 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
898 return fCurrent_->fEntry;
900 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
901 inline auto SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::ForwardIterator::operator->() const -> const value_type*
904 return &fCurrent_->fEntry;
906 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
909 Require (not AtEnd ());
910#if qStroika_Foundation_Debug_AssertionsChecked
912 Require (fData_ == data);
916 for (
const Link_* l = data->fHead_;; l = l->fNext[0], ++i) {
918 if (l == fCurrent_) [[unlikely]] {
925 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
928#if qStroika_Foundation_Debug_AssertionsChecked
929 Require (fData_ ==
nullptr or rhs.fData_ ==
nullptr or fData_ == rhs.fData_);
931 return fCurrent_ == rhs.fCurrent_;
933 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
938 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
943 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
946#if qStroika_Foundation_Debug_AssertionsChecked
947 Require (data == fData_);
950 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
953 fCurrent_ = fCurrent_->fNext[0];
956 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
959 ForwardIterator result = *
this;
963 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
964 template <
typename CHECKED_T>
965 void SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::ForwardIterator::UpdateValue (ArgByValueType<CHECKED_T> newValue)
966 requires (not same_as<MAPPED_TYPE, void>)
968 Link_* link2Update =
const_cast<Link_*
> (fCurrent_);
969 link2Update->fEntry.fValue = newValue;
971 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
972 constexpr void SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::ForwardIterator::Invariant () const noexcept
974#if qStroika_Foundation_Debug_AssertionsChecked
978#if qStroika_Foundation_Debug_AssertionsChecked
979 template <
typename KEY_TYPE,
typename MAPPED_TYPE, Support::SkipList::IVal
idTraits<KEY_TYPE> TRAITS>
980 void SkipList<KEY_TYPE, MAPPED_TYPE, TRAITS>::ForwardIterator::Invariant_ () const noexcept
983 Require (AtEnd () or fData_ !=
nullptr);
984 if (fData_ !=
nullptr) {
985 fData_->Invariant ();
#define RequireNotNull(p)
#define RequireExpression(c)
#define AssertNotReached()
Support::SkipList::StatsType< KEY_TYPE, TRAITS > StatsType
const Link_ * UnderlyingIteratorRep
shared_lock< const AssertExternallySynchronizedChecker > ReadContext
Instantiate AssertExternallySynchronizedChecker::ReadContext to designate an area of code where prote...