Stroika Library 3.0d24
 
Loading...
Searching...
No Matches
IteratorImplHelper.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. 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, TRAITS, BASE_IREP> ******
55 ********************************************************************************
56 */
57 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
58 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
59 inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data,
60 [[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 TRAITS, typename BASE_IREP>
72 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
73 inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::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 TRAITS, typename BASE_IREP>
84 auto IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::Clone () const -> unique_ptr<typename Iterator<T>::IRep>
85 {
86 ValidateChangeCount ();
87 // NOTE: guarded with if constexpr because when BASE_IREP != Iterator<T>::IRep (i.e. this class is being used
88 // as the base of BidirectionalIteratorImplHelper_/RandomAccessIteratorImplHelper_, which add further pure
89 // virtuals of their own), THIS particular instantiation of IteratorImplHelper_ is abstract, and the derived
90 // class re-overrides Clone () to construct itself instead - so this branch must never actually be instantiated
91 // for that case (virtual member functions of class templates are instantiated regardless of whether called).
92 if constexpr (is_same_v<BASE_IREP, typename Iterator<T>::IRep>) {
93 return make_unique<IteratorImplHelper_> (*this);
94 }
95 else {
97 return nullptr;
98 }
99 }
100 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
101 auto IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::AtEnd () const -> bool
102 {
103 return fIterator.AtEnd ();
104 }
105 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
106 optional<T> IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::Current () const
107 {
108 if (fIterator.AtEnd ()) {
109 return nullopt;
110 }
111 else {
112 return TRAITS::ConvertDataStructureIterationResult2ContainerIteratorResult (*fIterator);
113 }
114 }
115 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
116 optional<T> IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::More ()
117 {
118 Require (not fIterator.AtEnd ());
119 ValidateChangeCount ();
120 ++fIterator;
121 if (fIterator.AtEnd ()) [[unlikely]] {
122 return nullopt;
123 }
124 else {
125 return TRAITS::ConvertDataStructureIterationResult2ContainerIteratorResult (*fIterator);
126 }
127 }
128 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
129 bool IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::Equals (const typename Iterator<T>::IRep* rhs) const
130 {
131 RequireNotNull (rhs);
132 using ActualIterImplType_ = IteratorImplHelper_;
133 const ActualIterImplType_* rrhs = Debug::UncheckedDynamicCast<const ActualIterImplType_*> (rhs);
134 return fIterator == rrhs->fIterator;
135 }
136#if qStroika_Foundation_Debug_AssertionsChecked
137 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
138 void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::Invariant () const noexcept
139 {
140 ValidateChangeCount ();
141 }
142#endif
143 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
145 {
146#if qStroika_Foundation_Debug_AssertionsChecked
147 if (fChangeCounter != nullptr) {
148 fLastCapturedChangeCount = fChangeCounter->fChangeCount;
150#endif
151 }
152 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
154 {
155#if qStroika_Foundation_Debug_AssertionsChecked
156 if (fChangeCounter != nullptr) {
157 Require (not fChangeCounter->fDeleted); // if this is triggered, it means the container changed so drastically that its rep was deleted
158 Require (fChangeCounter->fChangeCount == fLastCapturedChangeCount); // if this fails, it almost certainly means you are using a stale iterator
159 }
160#endif
161 }
162
163 /*
164 ********************************************************************************
165 * BidirectionalIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP> *
166 ********************************************************************************
167 */
168 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
170 {
171 this->ValidateChangeCount ();
172 // see NOTE on IteratorImplHelper_::Clone () above - same reasoning: only valid to self-construct when
173 // BASE_IREP is exactly BidirectionalIterator<T>::IRep (this class's own default/standalone use); when
174 // used as the base of RandomAccessIteratorImplHelper_, that class re-overrides Clone () instead.
175 if constexpr (is_same_v<BASE_IREP, typename Traversal::BidirectionalIterator<T>::IRep>) {
176 return make_unique<BidirectionalIteratorImplHelper_> (*this);
177 }
178 else {
180 return nullptr;
181 }
182 }
183 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
184 bool BidirectionalIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::AtStart () const
185 {
186 return this->fIterator.AtStart ();
187 }
188 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS, typename BASE_IREP>
189 T BidirectionalIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>::Back ()
190 {
191 Require (not this->fIterator.AtStart ());
192 this->ValidateChangeCount ();
193 --this->fIterator;
194 return *this->fIterator;
195 }
196
197 /*
198 ********************************************************************************
199 ***** RandomAccessIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS> ******
200 ********************************************************************************
201 */
202 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS>
203 auto RandomAccessIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS>::Clone () const -> unique_ptr<typename Iterator<T>::IRep>
204 {
205 this->ValidateChangeCount ();
206 return make_unique<RandomAccessIteratorImplHelper_> (*this);
207 }
208 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS>
209 void RandomAccessIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS>::Advance (ptrdiff_t i)
210 {
211 this->ValidateChangeCount ();
212 this->fIterator += i;
213 }
214 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS>
215 ptrdiff_t RandomAccessIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS>::Difference (const typename Traversal::RandomAccessIterator<T>::IRep* rhs) const
216 {
217 this->ValidateChangeCount ();
218 if (rhs == nullptr) {
219 // nullptr means 'end' - the backend iterator's own operator- knows how to handle a default-constructed
220 // (sentinel/end) instance of itself on either side (see e.g. Array<T>::ForwardIterator).
221 return this->fIterator - typename TRAITS::DataStructureIteratorT{};
222 }
223 using ActualIterImplType_ = RandomAccessIteratorImplHelper_;
224 const ActualIterImplType_* rrhs = Debug::UncheckedDynamicCast<const ActualIterImplType_*> (rhs);
225 return this->fIterator - rrhs->fIterator;
226 }
227 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS>
228 const T* RandomAccessIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS>::PeekAtElement (ptrdiff_t i) const
229 {
230 this->ValidateChangeCount ();
231 return &this->fIterator[i];
232 }
233
234}
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:49
#define RequireNotNull(p)
Definition Assertions.h:348
#define AssertNotReached()
Definition Assertions.h:356
like IteratorImplHelper_ but for bidirectional iterators.
An Iterator<T> is a copyable object which allows traversing the contents of some container.
Definition Iterator.h:253