Stroika Library 3.0d20
 
Loading...
Searching...
No Matches
DoublyLinkedList.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
5
7
8// Would like to leave on by default but we just added and cannot afford to have debug builds get that slow
9#ifndef qStroika_Foundation_Containers_DataStructures_DoublyLinkedList_IncludeSlowDebugChecks_
10#define qStroika_Foundation_Containers_DataStructures_DoublyLinkedList_IncludeSlowDebugChecks_ 0
11#endif
12
13 /*
14 ********************************************************************************
15 ***************************** DoublyLinkedList<T>::Link_ ***********************
16 ********************************************************************************
17 */
18 template <typename T>
19 constexpr DoublyLinkedList<T>::Link_::Link_ (ArgByValueType<T> item, Link_* prev, Link_* next)
20 : fItem{item}
21 , fPrev{prev}
22 , fNext{next}
23 {
24 }
25
26 /*
27 ********************************************************************************
28 ******************************* DoublyLinkedList<T> ****************************
29 ********************************************************************************
30 */
31 template <typename T>
32 inline DoublyLinkedList<T>::DoublyLinkedList ()
33 {
34 Invariant ();
35 }
36 template <typename T>
37 DoublyLinkedList<T>::DoublyLinkedList (const DoublyLinkedList& src)
38 {
39 for (const Link_* cur = src.fHead_; cur != nullptr; cur = cur->fNext) {
40 push_back (cur->fItem);
41 }
42 Invariant ();
43 }
44 template <typename T>
45 DoublyLinkedList<T>::DoublyLinkedList (DoublyLinkedList&& src) noexcept
46 : fHead_{src.fHead_}
47 , fTail_{src.fTail_}
48 {
49 Invariant ();
50 src.fHead_ = nullptr;
51 src.fTail_ = nullptr;
52 src.Invariant ();
53 }
54 template <typename T>
55 inline DoublyLinkedList<T>::~DoublyLinkedList ()
56 {
57 /*
58 * This could be a little cheaper - we could avoid setting fHead_ pointer,
59 * but we must worry more about codeSize/re-use.
60 * That would involve a new function that COULD NOT BE INLINED.
61 *
62 * < I guess I could add a hack method - unadvertised - but has to be
63 * at least protected - and call it here to do what I've mentioned above >
64 */
65 Invariant ();
66 clear ();
67 Invariant ();
68 Ensure (size () == 0);
69 Ensure (fHead_ == nullptr);
70 Ensure (fTail_ == nullptr);
71 }
72 template <typename T>
73 inline void DoublyLinkedList<T>::Invariant () const noexcept
74 {
75#if qStroika_Foundation_Debug_AssertionsChecked
76 Invariant_ ();
77#endif
78 }
79 template <typename T>
80 inline bool DoublyLinkedList<T>::empty () const
81 {
82 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
83 return fHead_ == nullptr;
84 }
85 template <typename T>
86 inline size_t DoublyLinkedList<T>::size () const
87 {
88 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
89 size_t n = 0;
90 for (const Link_* i = fHead_; i != nullptr; i = i->fNext) {
91 ++n;
92 }
93 return n;
94 }
95 template <typename T>
96 inline optional<T> DoublyLinkedList<T>::GetFirst () const
97 {
98 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
99 return fHead_ == nullptr ? optional<T>{} : fHead_->fItem;
100 }
101 template <typename T>
102 inline optional<T> DoublyLinkedList<T>::GetLast () const
103 {
104 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
105 return fTail_ == nullptr ? optional<T>{} : fTail_->fItem;
106 }
107 template <typename T>
108 inline void DoublyLinkedList<T>::push_front (ArgByValueType<T> item)
111 Invariant ();
112 fHead_ = new Link_{item, nullptr, fHead_};
113 if (fHead_->fNext != nullptr) [[likely]] {
114 // backlink second item to first
115 fHead_->fNext->fPrev = fHead_;
116 }
117 if (fTail_ == nullptr) [[unlikely]] {
118 // if last is null, list was empty, so first==last now
119 fTail_ = fHead_;
120 }
121 Invariant ();
122 }
123 template <typename T>
124 template <Memory::ISpanOfT<T> SPAN_T>
125 void DoublyLinkedList<T>::push_front (const SPAN_T& copyFrom)
126 {
127 // @todo note could optimize this - slightly, setting tail and calling invariant etc at the end...
128 // push_front in reverse order cuz push_front reverses traversal order, and two wrongs make a right
129 for (auto ri = copyFrom.rbegin (); ri != copyFrom.rend (); ++ri) {
130 push_front (*ri);
131 }
132 }
133 template <typename T>
134 inline void DoublyLinkedList<T>::push_back (ArgByValueType<T> item)
135 {
137 Invariant ();
138 fTail_ = new Link_{item, fTail_, nullptr};
139 if (fTail_->fPrev != nullptr) [[likely]] {
140 // forward link second to last item to its prev
141 fTail_->fPrev->fNext = fTail_;
142 }
143 if (fHead_ == nullptr) [[unlikely]] {
144 // if head is null, list was empty, so first==last now
145 fHead_ = fTail_;
146 }
147 Invariant ();
148 }
149 template <typename T>
150 template <Memory::ISpanOfT<T> SPAN_T>
151 void DoublyLinkedList<T>::push_back (const SPAN_T& copyFrom)
152 {
153 // @todo note could optimize this - slightly, setting tail and calling invariant etc at the end...
154 for (auto i : copyFrom) {
155 push_back (i);
156 }
157 }
158 template <typename T>
160 {
162 RequireNotNull (fHead_);
163 Invariant ();
164 Link_* victim = fHead_;
165 Assert (victim->fPrev == nullptr); // cuz it was first..
166 /*
167 * Before:
168 * | | | | | |
169 * | V | | B | | C |
170 * | <-prev | | <-prev | | <-prev | ...
171 * | next-> | | next-> | | next-> |
172 * | | | | | |
173 *
174 * After:
175 * | | | |
176 * | B | | C |
177 * | <-prev | | <-prev | ...
178 * | next-> | | next-> |
179 * | | | |
180 */
181 fHead_ = victim->fNext; // First points to B
182 if (fHead_ == nullptr) {
183 Assert (victim == fTail_);
184 fTail_ = nullptr;
185 }
186 else {
187 Assert (fHead_->fPrev == victim);
188 fHead_->fPrev = nullptr; // B's prev is Nil since it is new first
189 }
190 delete victim;
191 Invariant ();
192 }
193 template <typename T>
195 {
197 RequireNotNull (fHead_);
198 Invariant ();
199 Link_* victim = fTail_;
200 Assert (victim->fNext == nullptr); // cuz it was last..
201 /*
202 * Before:
203 * | | | | | |
204 * | A | | B | | V |
205 * ... | <-prev | | <-prev | | <-prev |
206 * | next-> | | next-> | | next-> |
207 * | | | | | |
208 *
209 * After:
210 * | | | |
211 * | A | | B |
212 * ... | <-prev | | <-prev |
213 * | next-> | | next-> |
214 * | | | |
215 */
216 fTail_ = victim->fPrev; // new last item
217 if (fTail_ == nullptr) {
218 Assert (fHead_ == victim);
219 fHead_ = nullptr;
220 }
221 else {
222 Assert (fTail_->fNext == victim);
223 fTail_->fNext = nullptr; // B's fNext is Nil since it is new last
224 }
225 delete victim;
226 Invariant ();
227 }
228 template <typename T>
229 auto DoublyLinkedList<T>::operator= (const DoublyLinkedList& rhs) -> DoublyLinkedList&
230 {
232 Invariant ();
233 clear ();
234 /*
235 * Copy the linked list by keeping a point to the new current and new
236 * previous, and sliding them along in parallel as we construct the
237 * new list. Only do this if we have at least one element - then we
238 * don't have to worry about the head of the list, or nullptr ptrs, etc - that
239 * case is handled outside, before the loop.
240 */
241 if (rhs.fHead_ != nullptr) {
242 fHead_ = new Link_{rhs.fHead_->fItem, nullptr};
243 Link_* newCur = fHead_;
244 for (const Link_* cur = rhs.fHead_->fNext; cur != nullptr; cur = cur->fNext) {
245 Link_* newPrev = newCur;
246 newCur = new Link_{cur->fItem, nullptr};
247 newPrev->fNext = newCur;
248 }
249 }
250 Invariant ();
251 return *this;
252 }
253 template <typename T>
254 template <typename EQUALS_COMPARER>
255 void DoublyLinkedList<T>::Remove (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer)
256 {
258 Invariant ();
259 if (equalsComparer (item, fHead_->fItem)) {
260 RemoveFirst ();
261 }
262 else {
263 Link_* prev = nullptr;
264 for (Link_* link = fHead_; link != nullptr; prev = link, link = link->fNext) {
265 if (equalsComparer (link->fItem, item)) {
266 AssertNotNull (prev); // cuz otherwise we would have hit it in first case!
267 prev->fNext = link->fNext;
268 delete (link);
269 break;
270 }
271 }
272 }
273 Invariant ();
274 }
275 template <typename T>
276 template <typename EQUALS_COMPARER>
277 bool DoublyLinkedList<T>::Contains (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer) const
278 {
279 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
280 for (const Link_* current = fHead_; current != nullptr; current = current->fNext) {
281 if (forward<EQUALS_COMPARER> (equalsComparer) (current->fItem, item)) {
282 return true;
283 }
284 }
285 return false;
286 }
287 template <typename T>
288 template <invocable<T> FUNCTION>
289 inline void DoublyLinkedList<T>::Apply (FUNCTION&& doToElement) const
290 {
291 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
292 for (const Link_* i = fHead_; i != nullptr; i = i->fNext) {
293 forward<FUNCTION> (doToElement) (i->fItem);
294 }
295 }
296 template <typename T>
297 template <typename FUNCTION>
298 inline auto DoublyLinkedList<T>::Find (FUNCTION&& firstThat) const -> UnderlyingIteratorRep
299 {
300 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
301 for (Link_* i = fHead_; i != nullptr; i = i->fNext) {
302 if (forward<FUNCTION> (firstThat) (i->fItem)) {
303 return i;
304 }
305 }
306 return nullptr;
307 }
308 template <typename T>
310 {
312 for (Link_* i = fHead_; i != nullptr;) {
313 Link_* deleteMe = i;
314 i = i->fNext;
315 delete deleteMe;
316 }
317 fHead_ = nullptr;
318 fTail_ = nullptr;
319 }
320 template <typename T>
321 T DoublyLinkedList<T>::GetAt (size_t i) const
322 {
323 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
324 Require (i >= 0);
325 Require (i < size ());
326 const Link_* cur = fHead_;
327 for (; i != 0; cur = cur->fNext, --i) {
328 AssertNotNull (cur); // cuz i <= fLength
329 }
330 AssertNotNull (cur); // cuz i <= fLength
331 return (cur->fItem);
332 }
333 template <typename T>
334 void DoublyLinkedList<T>::SetAt (size_t i, ArgByValueType<T> item)
335 {
337 Require (i >= 0);
338 Require (i < size ());
339 Link_* cur = fHead_;
340 for (; i != 0; cur = cur->fNext, --i) {
341 AssertNotNull (cur); // cuz i <= fLength
342 }
343 AssertNotNull (cur); // cuz i <= fLength
344 cur->fItem = item;
345 }
346 template <typename T>
347 inline void DoublyLinkedList<T>::MoveIteratorHereAfterClone (ForwardIterator* pi, const DoublyLinkedList<T>* movedFrom) const
348 {
349 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
350 // TRICKY TODO - BUT MUST DO - MUST MOVE FROM OLD ITER TO NEW
351 // only way
352 //
353 // For STL containers, not sure how to find an equiv new iterator for an old one, but my best guess is to iterate through
354 // old for old, and when I match, stop on new
355#if qStroika_Foundation_Debug_AssertionsChecked
356 Require (pi->fData_ == movedFrom);
357#endif
358 auto newI = this->fHead_;
359 [[maybe_unused]] auto newE = nullptr;
360 auto oldI = movedFrom->fHead_;
361 [[maybe_unused]] auto oldE = nullptr;
362 while (oldI != pi->fCurrent_) {
363 Assert (newI != newE);
364 Assert (oldI != oldE);
365 newI = newI->fNext;
366 oldI = oldI->fNext;
367 Assert (newI != newE);
368 Assert (oldI != oldE);
369 }
370 Assert (oldI == pi->fCurrent_);
371 pi->fCurrent_ = newI;
372#if qStroika_Foundation_Debug_AssertionsChecked
373 pi->fData_ = this;
374#endif
375 }
376 template <typename T>
377 inline auto DoublyLinkedList<T>::begin () const -> ForwardIterator
378 {
379 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
380 return ForwardIterator{this};
381 }
382 template <typename T>
383 constexpr auto DoublyLinkedList<T>::end () const noexcept -> ForwardIterator
384 {
385 return ForwardIterator{};
386 }
387 template <typename T>
388 auto DoublyLinkedList<T>::erase (const ForwardIterator& i) -> ForwardIterator
389 {
390 ForwardIterator next = i;
391 ++next;
392 Remove (i);
393 next.Invariant ();
394 return next;
395 }
396 template <typename T>
397 void DoublyLinkedList<T>::Remove (const ForwardIterator& i)
398 {
400 Require (not i.Done ());
401#if qStroika_Foundation_Debug_AssertionsChecked
402 Require (i.fData_ == this); // assure iterator not stale
403#endif
404 this->Invariant ();
405
406 const Link_* victim = i.fCurrent_;
407 AssertNotNull (victim); // cuz not done
408 /*
409 * Before:
410 * | | | | | |
411 * | A | | V | | C |
412 * ... | <-prev | | <-prev | | <-prev | ...
413 * | next-> | | next-> | | next-> |
414 * | | | | | |
415 *
416 * After:
417 * | | | |
418 * | A | | C |
419 * ... | <-prev | | <-prev | ...
420 * | next-> | | next-> |
421 * | | | |
422 */
423 if (victim->fPrev == nullptr) {
424 // In this case 'A' does not exist - it is Nil...
425 Assert (fHead_ == victim);
426 fHead_ = victim->fNext; // 'C' is now first
427 if (fHead_ == nullptr) {
428 fTail_ = nullptr;
429 }
430 else {
431 Assert (fHead_->fPrev == victim); // Victim used to be 'C's prev
432 fHead_->fPrev = nullptr; // Now Nil!
433 }
434 }
435 else {
436 Assert (victim->fPrev->fNext == victim); // In this case 'A' DOES exist
437 victim->fPrev->fNext = victim->fNext; // Make A point to C
438 // Now make 'C' point back to A (careful if 'C' is Nil)
439 if (victim->fNext == nullptr) {
440 // In this case 'C' does not exist - it is Nil...
441 Assert (victim == fTail_);
442 fTail_ = victim->fPrev; // 'A' is now last
443 }
444 else {
445 Assert (victim->fNext->fPrev == victim); // Victim used to be 'C's prev
446 victim->fNext->fPrev = victim->fPrev; // Now 'A' is
447 }
448 }
449 delete victim;
450 this->Invariant ();
451 }
452 template <typename T>
453 inline void DoublyLinkedList<T>::SetAt (const ForwardIterator& i, ArgByValueType<T> newValue)
454 {
456 Require (not i.Done ());
457#if qStroika_Foundation_Debug_AssertionsChecked
458 Require (i.fData_ == this); // assure iterator not stale
459#endif
460 this->Invariant ();
461 const_cast<Link_*> (i.fCurrent_)->fItem = newValue;
462 this->Invariant ();
463 }
464 template <typename T>
465 void DoublyLinkedList<T>::AddBefore (const ForwardIterator& i, ArgByValueType<T> newValue)
466 {
468#if qStroika_Foundation_Debug_AssertionsChecked
469 Require (i.fData_ == this); // assure iterator not stale
470#endif
471 /*
472 * NB: This code works fine, even if we are done!!!
473 */
474 this->Invariant ();
475 if (i.fCurrent_ == nullptr) {
476 /*
477 * NB: If I am past the last item on the list, AddBefore() is equivalent
478 * to Appending to the list.
479 */
480 Assert (i.Done ());
481 push_back (newValue);
482 Assert (i.Done ()); // what is done, cannot be undone!!!
483 }
484 else {
485 Link_* prev = i.fCurrent_->fPrev;
486 if (prev == nullptr) {
487 push_front (newValue);
488 }
489 else {
490 /*
491 * | | | | | |
492 * | PREV | | NEW | | CUR |
493 * ... | <-prev | | <-prev | | <-prev | ...
494 * | next-> | | next-> | | next-> |
495 * | | | | | |
496 */
497 Assert (prev->fNext == i.fCurrent_);
498 Link_* iteratorCurLink = const_cast<Link_*> (i.fCurrent_);
499 prev->fNext = new Link_{newValue, prev, iteratorCurLink};
500 // Since fCurrent != nullptr from above, we update its prev, and don't have
501 // to worry about fTail_.
502 iteratorCurLink->fPrev = prev->fNext;
503 Assert (i.fCurrent_->fPrev->fPrev == prev); // old prev is two back now...
504 }
505 }
506 this->Invariant ();
507 }
508 template <typename T>
509 inline void DoublyLinkedList<T>::AddAfter (const ForwardIterator& i, ArgByValueType<T> newValue)
510 {
512#if qStroika_Foundation_Debug_AssertionsChecked
513 Require (i.fData_ == this); // assure iterator not stale
514#endif
515 this->Invariant ();
516 Require (not i.Done ());
517 AssertNotNull (i.fCurrent_); // since not done...
518 Assert (fHead_ != nullptr);
519 /*
520 * | | | |
521 * | CUR | | NEW |
522 * ... | <-prev | | <-prev | ...
523 * | next-> | | next-> |
524 * | | | |
525 */
526 Link_* iteratorCurLink = const_cast<Link_*> (i.fCurrent_);
527 Link_* newLink = new Link_{newValue, iteratorCurLink, iteratorCurLink->fNext};
528 iteratorCurLink->fNext = newLink;
529 if (newLink->fNext != nullptr) {
530 newLink->fNext->fPrev = newLink;
531 }
532 if (newLink->fNext == nullptr) {
533 fTail_ = newLink;
534 }
535 else {
536 Assert (newLink->fNext->fPrev == newLink); // cuz of params to new Link_...
537 }
538 this->Invariant ();
539 }
540#if qStroika_Foundation_Debug_AssertionsChecked
541 template <typename T>
542 void DoublyLinkedList<T>::Invariant_ () const noexcept
543 {
544#if qStroika_Foundation_Containers_DataStructures_DoublyLinkedList_IncludeSlowDebugChecks_
545 AssertExternallySynchronizedMutex::ReadContext declareContext{*this};
546#endif
547 if (fHead_ != nullptr) {
548 Assert (fHead_->fPrev == nullptr);
549 if (fHead_->fNext == nullptr) {
550 Assert (fHead_ == fTail_);
551 }
552 else {
553 Assert (fHead_->fNext->fPrev == fHead_);
554 }
555 }
556 if (fTail_ != nullptr) {
557 Assert (fTail_->fNext == nullptr);
558 if (fTail_->fPrev == nullptr) {
559 Assert (fHead_ == fTail_);
560 }
561 else {
562 Assert (fTail_->fPrev->fNext == fTail_);
563 }
564 }
565 Assert (fHead_ == nullptr or fHead_->fPrev == nullptr);
566 Assert (fTail_ == nullptr or fTail_->fNext == nullptr);
567
568 /*
569 * Check we are properly linked together.
570 */
571 size_t forwardCounter = 0;
572 for (Link_* i = fHead_; i != nullptr; i = i->fNext) {
573 Assert (i->fNext == nullptr or i->fNext->fPrev == i); // adjacent nodes point at each other
574 ++forwardCounter;
575 }
576 size_t backwardCounter{};
577 for (Link_* i = fTail_; i != nullptr; i = i->fPrev) {
578 Assert (i->fPrev == nullptr or i->fPrev->fNext == i); // adjacent nodes point at each other
579 ++backwardCounter;
580 }
581 Assert (forwardCounter == backwardCounter);
582 }
583#endif
584
585 /*
586 ********************************************************************************
587 ********************** DoublyLinkedList<T>::ForwardIterator ********************
588 ********************************************************************************
589 */
590 template <typename T>
591 constexpr DoublyLinkedList<T>::ForwardIterator::ForwardIterator ([[maybe_unused]] const DoublyLinkedList* data, UnderlyingIteratorRep startAt) noexcept
592 : fCurrent_{startAt}
593#if qStroika_Foundation_Debug_AssertionsChecked
594 , fData_{data}
595#endif
596 {
597 }
598 template <typename T>
599 constexpr DoublyLinkedList<T>::ForwardIterator::ForwardIterator (const DoublyLinkedList* data) noexcept
600 : ForwardIterator{data, (RequireExpression (data != nullptr), data->fHead_)}
601 {
602 }
603 template <typename T>
604 inline void DoublyLinkedList<T>::ForwardIterator::Invariant () const noexcept
605 {
606#if qStroika_Foundation_Debug_AssertionsChecked
607 Invariant_ ();
608#endif
609 }
610 template <typename T>
611 inline DoublyLinkedList<T>::ForwardIterator::operator bool () const
612 {
613 return not Done ();
614 }
615 template <typename T>
616 inline bool DoublyLinkedList<T>::ForwardIterator::Done () const noexcept
617 {
618#if qStroika_Foundation_Debug_AssertionsChecked
619 if (fData_ != nullptr) {
620 AssertExternallySynchronizedMutex::ReadContext declareContext{*fData_};
621 Invariant ();
622 }
623#endif
624 return fCurrent_ == nullptr;
625 }
626 template <typename T>
627 inline auto DoublyLinkedList<T>::ForwardIterator::operator++ () noexcept -> ForwardIterator&
628 {
629 Require (not Done ());
630 Invariant ();
631 Assert (fCurrent_ != nullptr);
632 fCurrent_ = fCurrent_->fNext;
633 Invariant ();
634 return *this;
635 }
636 template <typename T>
637 inline auto DoublyLinkedList<T>::ForwardIterator::operator++ (int) noexcept -> ForwardIterator
638 {
639 ForwardIterator result = *this;
640 this->operator++ ();
641 return result;
642 }
643 template <typename T>
644 inline const T& DoublyLinkedList<T>::ForwardIterator::operator* () const
645 {
646#if qStroika_Foundation_Debug_AssertionsChecked
647 RequireNotNull (fData_);
648 AssertExternallySynchronizedMutex::ReadContext declareContext{*fData_};
649#endif
650 Require (not Done ());
651 Invariant ();
652 AssertNotNull (fCurrent_);
653 return fCurrent_->fItem;
654 }
655 template <typename T>
656 inline const T* DoublyLinkedList<T>::ForwardIterator::operator->() const
657 {
658#if qStroika_Foundation_Debug_AssertionsChecked
659 RequireNotNull (fData_);
660 AssertExternallySynchronizedMutex::ReadContext declareContext{*fData_};
661#endif
662 Require (not Done ());
663 Invariant ();
664 AssertNotNull (fCurrent_);
665 return &fCurrent_->fItem;
666 }
667 template <typename T>
668 size_t DoublyLinkedList<T>::ForwardIterator::CurrentIndex (const DoublyLinkedList* data) const
669 {
670 Require (not Done ());
671#if qStroika_Foundation_Debug_AssertionsChecked
672 Require (data == fData_);
673 RequireNotNull (fData_);
674#endif
675 RequireNotNull (this->fCurrent_);
676 size_t i = 0;
677 for (const Link_* l = data->fHead_;; l = l->fNext, ++i) {
678 AssertNotNull (l);
679 if (l == fCurrent_) [[unlikely]] {
680 return i;
681 }
682 }
684 return i;
685 }
686 template <typename T>
687 inline auto DoublyLinkedList<T>::ForwardIterator::GetUnderlyingIteratorRep () const -> UnderlyingIteratorRep
688 {
689 return fCurrent_;
690 }
691 template <typename T>
692 inline void DoublyLinkedList<T>::ForwardIterator::SetUnderlyingIteratorRep (UnderlyingIteratorRep l)
693 {
694#if qStroika_Foundation_Debug_AssertionsChecked
695 AssertExternallySynchronizedMutex::ReadContext declareContext{*fData_}; // read lock on data, though writing to this iterator
696#endif
697 // MUST COME FROM THIS LIST
698 // CAN be nullptr
699 fCurrent_ = l;
700 }
701 template <typename T>
702 constexpr void DoublyLinkedList<T>::ForwardIterator::AssertDataMatches ([[maybe_unused]] const DoublyLinkedList* data) const
703 {
704#if qStroika_Foundation_Debug_AssertionsChecked
705 Require (data == fData_);
706#endif
707 }
708 template <typename T>
709 inline bool DoublyLinkedList<T>::ForwardIterator::operator== (const ForwardIterator& rhs) const
710 {
711 return fCurrent_ == rhs.fCurrent_;
712 }
713#if qStroika_Foundation_Debug_AssertionsChecked
714 template <typename T>
715 void DoublyLinkedList<T>::ForwardIterator::Invariant_ () const noexcept
716 {
717 }
718#endif
719
720}
#define AssertNotNull(p)
Definition Assertions.h:333
#define RequireNotNull(p)
Definition Assertions.h:347
#define RequireExpression(c)
Definition Assertions.h:267
#define AssertNotReached()
Definition Assertions.h:355
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...