Stroika Library 3.0d24
 
Loading...
Searching...
No Matches
IteratorImplHelper.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_Private_IteratorImplHelper_h_
5#define _Stroika_Foundation_Containers_Private_IteratorImplHelper_h_
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/Common.h"
10#include "Stroika/Foundation/Containers/Common.h"
14
15/**
16 * Private utility to support building of Traversal::Iterator<> objects for concrete Containers.
17 *
18 * TODO:
19 * @todo Crazy temphack cuz current code assumes you must call++ before starting iteration! Crazy!
20 * Issue is way we implemented the 'CURRENT' stuff with iterators - filling in after the first
21 * More()...
22 *
23 * At this point - this appears to be restricted to ALL BACKEND support Iterator (ForwardIterator) classes.
24 * The Stroika Iterator API doesn't appear to have this quirk.
25 *
26 *
27 * Notes:
28 *
29 */
30
32
33 /**
34 */
35 struct ContainerDebugChangeCounts_ {
36 using ChangeCountType = unsigned int;
37#if qStroika_Foundation_Debug_AssertionsChecked
38 static ChangeCountType mkInitial_ ();
39#endif
40
41 ContainerDebugChangeCounts_ ();
42 ContainerDebugChangeCounts_ (const ContainerDebugChangeCounts_& src);
43 ~ContainerDebugChangeCounts_ ();
44
45#if qStroika_Foundation_Debug_AssertionsChecked
46 // NOTE - might want to use weakly_shared_ptr (weakref) as safer 'debugging' check than this, but only
47 // for debug checking, so not strictly needed (and might cost too much). CONSIDER going forward just
48 // for DEBUG mode -- LGP 2021-11-11
49 bool fDeleted{false};
50 atomic<ChangeCountType> fChangeCount{0}; // overwritten with random# in CTOR
51#endif
52
53 /**
54 */
55 nonvirtual void PerformedChange ();
56 };
57
58 template <typename T, typename DATASTRUCTURE_CONTAINER>
59 struct IteratorImplHelper_DefaultTraits {
60 static_assert (not is_reference_v<T>);
61 static_assert (not is_reference_v<DATASTRUCTURE_CONTAINER>);
62 using DataStructureT = DATASTRUCTURE_CONTAINER;
63 using DataStructureIteratorT = typename DATASTRUCTURE_CONTAINER::ForwardIterator;
64 using DataStructureContainerValueT = typename DATASTRUCTURE_CONTAINER::value_type; // I THINK WE CAN LOSE THIS DEFINE
65 // static constexpr bool kConvertDataStructureIterationResult2ContainerIteratorResult = false;
66 // see if can use auto in place of explict XX
67 //template <typename XX>
68 static constexpr T ConvertDataStructureIterationResult2ContainerIteratorResult (const DataStructureContainerValueT& t)
69 //requires (Common::explicitly_convertible_to<DataStructureContainerValueT, T>)
70 {
71 static_assert (Common::explicitly_convertible_to<DataStructureContainerValueT, T>,
72 "dont use the default traits, but provide your own - see KeyedCollection_HashTable as example");
73 return static_cast<T> (t);
74 }
75 };
76
77 /**
78 * \brief helper to wrap a low level 'DataStructure Container Iterator' into a 'Stroika' Iterator::IRep iterator.
79 *
80 * There is no requirement that Stroika concrete containers use this class. However, it
81 * so far has appeared a handy code sharing utility.
82 *
83 * Plus, its details are intimately tied to how the Stroika containers manage lifetime, so
84 * its not likely well suited for use elsewhere.
85 *
86 * \note BASE_IREP defaults to Iterator<T>::IRep, but can be overridden (see BidirectionalIteratorImplHelper_/
87 * RandomAccessIteratorImplHelper_ below) to derive from BidirectionalIterator<T>::IRep or
88 * RandomAccessIterator<T>::IRep instead, so that subclass can legally override AtStart ()/Back ()/
89 * Advance ()/Difference ()/PeekAtElement () (else there's nothing for those overrides to override).
90 *
91 * \todo This class is a bit kludgy/fragile. (e.g. the cases where you have to override More needing to also override Clone). Maybe use CRTP? And not
92 * good compiler error messages - maybe use more/better concepts usage; low priority since private impl helper method;
93 * -- LGP 2024-09-05
94 */
95 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS = IteratorImplHelper_DefaultTraits<T, DATASTRUCTURE_CONTAINER>,
96 typename BASE_IREP = typename Iterator<T>::IRep>
97 class IteratorImplHelper_ : public BASE_IREP,
98 public Memory::UseBlockAllocationIfAppropriate<IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP>> {
99 private:
100 using inherited = BASE_IREP;
101
102 //backward compat names
103 private:
104 using DATASTRUCTURE_CONTAINER_ITERATOR = typename TRAITS::DataStructureIteratorT;
105 using DATASTRUCTURE_CONTAINER_VALUE = typename TRAITS::DataStructureContainerValueT;
106
107 public:
108 using DataStructureImplValueType_ = DATASTRUCTURE_CONTAINER_VALUE;
109
110 public:
111 IteratorImplHelper_ () = delete;
112 IteratorImplHelper_ (IteratorImplHelper_&&) noexcept = default;
113 IteratorImplHelper_ (const IteratorImplHelper_&) = default;
114 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
115 explicit IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data, const ContainerDebugChangeCounts_* changeCounter = nullptr,
116 ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
117 requires (constructible_from<DATASTRUCTURE_CONTAINER_ITERATOR, const DATASTRUCTURE_CONTAINER*, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS...>);
118 template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
119 explicit IteratorImplHelper_ (const ContainerDebugChangeCounts_* changeCounter = nullptr, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
120 requires (constructible_from<DATASTRUCTURE_CONTAINER_ITERATOR, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS...>);
121
122 public:
123 virtual ~IteratorImplHelper_ () = default;
124
125 // Iterator<T>::IRep
126 public:
127 virtual unique_ptr<typename Iterator<T>::IRep> Clone () const override;
128 virtual bool AtEnd () const override;
129 virtual optional<T> Current () const override;
130 virtual optional<T> More () override;
131 virtual bool Equals (const typename Iterator<T>::IRep* rhs) const override;
132#if qStroika_Foundation_Debug_AssertionsChecked
133 /**
134 */
135 virtual void Invariant () const noexcept override;
136#endif
137
138 public:
139 /**
140 * rarely used but in special cases when returning new derived/pathed iterator*
141 */
142 nonvirtual void UpdateChangeCount ();
143
144 public:
145 /**
146 * This is used internally by Stroika to assure iterators are not used after the container they iterate over
147 * has been changed.
148 */
149 nonvirtual void ValidateChangeCount () const;
150
151 public:
152 mutable DATASTRUCTURE_CONTAINER_ITERATOR fIterator{};
153#if qStroika_Foundation_Debug_AssertionsChecked
154 const ContainerDebugChangeCounts_* fChangeCounter{nullptr};
155 ContainerDebugChangeCounts_::ChangeCountType fLastCapturedChangeCount{};
156#endif
157 };
158
159 /**
160 * \brief like IteratorImplHelper_ but for bidirectional iterators.
161 *
162 * \note BASE_IREP defaults to BidirectionalIterator<T>::IRep, but RandomAccessIteratorImplHelper_ (below)
163 * overrides it to RandomAccessIterator<T>::IRep, so it can inherit AtStart ()/Back () from here
164 * while still ultimately deriving from RandomAccessIterator<T>::IRep (needed so its own overrides
165 * of Advance ()/Difference ()/PeekAtElement () have something to override).
166 */
167 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS = IteratorImplHelper_DefaultTraits<T, DATASTRUCTURE_CONTAINER>,
168 typename BASE_IREP = typename Traversal::BidirectionalIterator<T>::IRep>
169 class BidirectionalIteratorImplHelper_ : public IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, BASE_IREP> {
170 private:
172
173 public:
174 using inherited::inherited;
175
176 // Iterator<T>::IRep
177 public:
178 // NOTE: must override Clone () again here (even though inherited::Clone () already 'works') because
179 // inherited::Clone () constructs an instance of 'inherited' (IteratorImplHelper_) - which is abstract
180 // once you factor in the AtStart ()/Back () pure virtuals added here - so Clone () must be re-overridden
181 // at each level that adds new pure virtual overrides, to construct the right (most-derived) type.
182 virtual unique_ptr<typename Iterator<T>::IRep> Clone () const override;
183
184 public:
185 virtual bool AtStart () const override;
186 virtual T Back () override;
187 };
188
189 /**
190 * \brief like IteratorImplHelper_ but for random access iterators.
191 */
192 template <typename T, typename DATASTRUCTURE_CONTAINER, typename TRAITS = IteratorImplHelper_DefaultTraits<T, DATASTRUCTURE_CONTAINER>>
194 : public BidirectionalIteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, TRAITS, typename Traversal::RandomAccessIterator<T>::IRep> {
195 private:
197
198 public:
200
201 // Iterator<T>::IRep
202 public:
203 // see NOTE on BidirectionalIteratorImplHelper_::Clone () above - same reasoning applies here.
204 virtual unique_ptr<typename Iterator<T>::IRep> Clone () const override;
205
206 public:
207 virtual void Advance (ptrdiff_t i) override;
208 virtual ptrdiff_t Difference (const typename Traversal::RandomAccessIterator<T>::IRep* rhs) const override;
209 virtual const T* PeekAtElement (ptrdiff_t i) const override;
210 };
211
212}
213
214/*
215 ********************************************************************************
216 ***************************** Implementation Details ***************************
217 ********************************************************************************
218 */
219#include "IteratorImplHelper.inl"
220
221#endif /*_Stroika_Foundation_Containers_Private_IteratorImplHelper_h_ */
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
like IteratorImplHelper_ but for bidirectional iterators.
helper to wrap a low level 'DataStructure Container Iterator' into a 'Stroika' Iterator::IRep iterato...
like IteratorImplHelper_ but for random access iterators.
Implementation detail for iterator implementors.
Definition Iterator.h:616
The interface for the internal representation of a RandomAccessIterator.