Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
IteratorImplHelper.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <random>
5
8
10
11 /*
12 ********************************************************************************
13 *************************** ContainerDebugChangeCounts_ ************************
14 ********************************************************************************
15 */
16#if qStroika_Foundation_Debug_AssertionsChecked
17 inline ContainerDebugChangeCounts_::ChangeCountType ContainerDebugChangeCounts_::mkInitial_ ()
18 {
19 // use random number so when we assign new object we are more likely to detect bad iterators (dangling)
20 random_device rd;
21 mt19937 gen{rd ()};
22 uniform_int_distribution<ChangeCountType> distrib{1, 1000};
23 return distrib (gen);
24 }
25#endif
26 inline ContainerDebugChangeCounts_::ContainerDebugChangeCounts_ ()
27#if qStroika_Foundation_Debug_AssertionsChecked
28 : fChangeCount{mkInitial_ ()}
29#endif
30 {
31 }
32 inline ContainerDebugChangeCounts_::ContainerDebugChangeCounts_ ([[maybe_unused]] const ContainerDebugChangeCounts_& src)
33#if qStroika_Foundation_Debug_AssertionsChecked
34 : fDeleted{src.fDeleted}
35 , fChangeCount{src.fChangeCount.load ()}
36#endif
37 {
38 }
39 inline ContainerDebugChangeCounts_::~ContainerDebugChangeCounts_ ()
40 {
41#if qStroika_Foundation_Debug_AssertionsChecked
42 fDeleted = true;
43#endif
44 }
45 inline void ContainerDebugChangeCounts_::PerformedChange ()
46 {
47#if qStroika_Foundation_Debug_AssertionsChecked
48 ++fChangeCount;
49#endif
50 }
51
52 /*
53 ********************************************************************************
54 *IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR,DATASTRUCTURE_CONTAINER_VALUE> *
55 ********************************************************************************
56 */
57 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
58 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
59 inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::IteratorImplHelper_ (
60 const DATASTRUCTURE_CONTAINER* data, [[maybe_unused]] const ContainerDebugChangeCounts_* changeCounter,
61 ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
62 requires (constructible_from<DATASTRUCTURE_CONTAINER_ITERATOR, const DATASTRUCTURE_CONTAINER*, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS...>)
63 : fIterator{data, forward<ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS> (args)...}
65 , fChangeCounter{changeCounter}
66 , fLastCapturedChangeCount{(changeCounter == nullptr) ? 0 : changeCounter->fChangeCount.load ()}
67#endif
68 {
69 RequireNotNull (data);
70 }
71 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
72 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
73 inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::IteratorImplHelper_ (
74 [[maybe_unused]] const ContainerDebugChangeCounts_* changeCounter, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
75 requires (constructible_from<DATASTRUCTURE_CONTAINER_ITERATOR, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS...>)
76 : fIterator{forward<ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS> (args)...}
78 , fChangeCounter{changeCounter}
79 , fLastCapturedChangeCount{(changeCounter == nullptr) ? 0 : changeCounter->fChangeCount.load ()}
80#endif
81 {
82 }
83 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
85 -> unique_ptr<typename Iterator<T>::IRep>
86 {
87 ValidateChangeCount ();
88 return make_unique<IteratorImplHelper_> (*this);
89 }
90 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
92 {
93 if constexpr (convertible_to<decltype (*fIterator), T>) {
94 RequireNotNull (result); // API says result ptr required
95 ValidateChangeCount ();
96 // Typically calls have advance = true
97 if (advance) [[likely]] {
98 Require (not fIterator.Done ());
99 ++fIterator;
100 }
101 if (fIterator.Done ()) [[unlikely]] {
102 *result = nullopt;
103 }
104 else {
105 *result = *fIterator;
106 }
107 }
108 else {
109 RequireNotReached (); // "If this fails, you must override ::More, and provide it yourself"; and remember to override Clone() too!!!
110 }
111 }
112 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
113 bool IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::Equals (
114 const typename Iterator<T>::IRep* rhs) const
116 RequireNotNull (rhs);
118 const ActualIterImplType_* rrhs = Debug::UncheckedDynamicCast<const ActualIterImplType_*> (rhs);
119 return fIterator == rrhs->fIterator;
120 }
121#if qStroika_Foundation_Debug_AssertionsChecked
122 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
124 {
125 ValidateChangeCount ();
126 }
127#endif
128 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
130 {
131#if qStroika_Foundation_Debug_AssertionsChecked
132 if (fChangeCounter != nullptr) {
133 fLastCapturedChangeCount = fChangeCounter->fChangeCount;
134 }
135#endif
136 }
137 template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
139 {
140#if qStroika_Foundation_Debug_AssertionsChecked
141 if (fChangeCounter != nullptr) {
142 Require (not fChangeCounter->fDeleted); // if this is triggered, it means the container changed so drastically that its rep was deleted
143 Require (fChangeCounter->fChangeCount == fLastCapturedChangeCount); // if this fails, it almost certainly means you are using a stale iterator
144 }
145#endif
146 }
147
148}
#define RequireNotReached()
Definition Assertions.h:385
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:48
#define RequireNotNull(p)
Definition Assertions.h:347
helper to wrap a low level 'DataStructure Container Iterator' into a 'Stroika' Iterator::IRep iterato...
virtual void More(optional< T > *result, bool advance) override
virtual unique_ptr< typename Iterator< T >::IRep > Clone() const override
Implementation detail for iterator implementors.
Definition Iterator.h:599
An Iterator<T> is a copyable object which allows traversing the contents of some container....
Definition Iterator.h:225