Stroika Library 3.0d24
 
Loading...
Searching...
No Matches
STLContainerWrapper.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_DataStructures_STLContainerWrapper_h_
5#define _Stroika_Foundation_Containers_DataStructures_STLContainerWrapper_h_
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/Common.h"
10#include "Stroika/Foundation/Common/Concepts.h"
12#include "Stroika/Foundation/Containers/Common.h"
14
15/**
16 * \file
17 *
18 * Description:
19 * This module generically wraps STL containers (such as map, vector etc), and facilitates
20 * using them as backends for Stroika containers.
21 *
22 * TODO:
23 *
24 * @todo Add special subclass of ForwardIterator that tracks PREVPTR - and use to cleanup stuff
25 * that uses forward_list code...
26 *
27 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
28 */
29
31
32 namespace Private_ {
33 template <typename T>
34 using has_erase_t = decltype (declval<T&> ().erase (begin (declval<T&> ()), end (declval<T&> ())));
35 template <typename T>
36 constexpr inline bool has_erase_v = Common::is_detected_v<has_erase_t, T>;
37 }
38
39 /**
40 * Use this to wrap an underlying stl container (like std::vector or stl:list, etc) to adapt
41 * it for Stroika containers.
42 *
43 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
44 */
45 template <typename STL_CONTAINER_OF_T>
46 class STLContainerWrapper : public STL_CONTAINER_OF_T, public Debug::AssertExternallySynchronizedChecker {
47 private:
48 using inherited = STL_CONTAINER_OF_T;
49
50 public:
51 using value_type = typename STL_CONTAINER_OF_T::value_type;
52 using iterator = typename STL_CONTAINER_OF_T::iterator;
53 using const_iterator = typename STL_CONTAINER_OF_T::const_iterator;
54
55 public:
56 /**
57 * Basic (mostly internal) element used by ForwardIterator. Abstract name so can be referenced generically across 'DataStructure' objects
58 */
59 using UnderlyingIteratorRep = const_iterator;
60
61 public:
62 /**
63 * pass through CTOR args to underlying container
64 */
65 template <typename... EXTRA_ARGS>
66 STLContainerWrapper (EXTRA_ARGS&&... args);
67 constexpr STLContainerWrapper (const STLContainerWrapper&) = default;
68 constexpr STLContainerWrapper (STLContainerWrapper&&) noexcept = default;
69
70 public:
71 class ForwardIterator;
74
75 public:
76 /*
77 * Support for COW (CopyOnWrite):
78 *
79 * Take iterator 'pi' which is originally a valid iterator from 'movedFrom' - and replace *pi with a valid
80 * iterator from 'this' - which points at the same logical position. This requires that this container
81 * was just 'copied' from 'movedFrom' - and is used to produce an equivalent iterator (since iterators are tied to
82 * the container they were iterating over).
83 *
84 * // we iterate over old data structure, and new ones at the same time. return true
85 * // when the newI should be considered to 'match' the old I value. NOTE - the argument lambda MAY use other information, like
86 * // the passed in pi forward iterator
87 * bool pointToSameThingTester (oldI, newI)
88 * {
89 * return true if newI now matches oldI;
90 * }
91 *
92 * // For example, to move in an INDEX like situation, just count the number of times pointToSameThingTester called
93 * bool pointToSameThingTester (oldI, newI)
94 * {
95 * return oldI == origIterator->GetOSRep();
96 * }
97 * // For example, to move in an key equals situation
98 * bool pointToSameThingTester (oldI, newI)
99 * {
100 * return origIterator->GetOSRep()->fKey == newI->fKey;
101 * }
102 */
103 template <invocable<typename STL_CONTAINER_OF_T::const_iterator, typename STL_CONTAINER_OF_T::const_iterator> POINT_TO_SAME_THING>
104 nonvirtual void MoveIteratorHereAfterClone (ForwardIterator* pi, const STLContainerWrapper* movedFrom, POINT_TO_SAME_THING&& pointToSameThingTester) const
105 requires (convertible_to<invoke_result_t<POINT_TO_SAME_THING, typename STL_CONTAINER_OF_T::const_iterator, typename STL_CONTAINER_OF_T::const_iterator>, bool>)
106 ;
107
108 public:
109 nonvirtual bool contains (Common::ArgByValueType<value_type> item) const;
110
111 public:
112 /**
113 * \note Runtime performance/complexity:
114 * Always: O(N)
115 */
116 template <invocable<typename STL_CONTAINER_OF_T::value_type> FUNCTION>
117 nonvirtual void Apply (FUNCTION&& doToElement) const;
118
119 public:
120 /**
121 * \note Runtime performance/complexity:
122 * Worst Case: O(N)
123 * Typical: O(N), but can be less if systematically finding entries near start of container
124 */
125 template <predicate<typename STL_CONTAINER_OF_T::value_type> FUNCTION>
126 nonvirtual iterator Find (FUNCTION&& firstThat);
127 template <predicate<typename STL_CONTAINER_OF_T::value_type> FUNCTION>
128 nonvirtual const_iterator Find (FUNCTION&& firstThat) const;
129
130 public:
131 template <predicate<typename STL_CONTAINER_OF_T::value_type> PREDICATE>
132 nonvirtual bool FindIf (PREDICATE&& pred) const;
133
134 public:
135 nonvirtual void Invariant () const noexcept;
136
137 public:
138 nonvirtual iterator remove_constness (const_iterator it);
139 };
140
141 /**
142 * STLContainerWrapper::ForwardIterator is a private utility class designed
143 * to promote source code sharing among the patched iterator implementations.
144 *
145 * \note ForwardIterator takes a const-pointer the the container as argument since this
146 * iterator never MODIFIES the container.
147 *
148 * However, it does a const-cast to maintain a non-const pointer since that is needed to
149 * option a non-const iterator pointer, which is needed by some classes that use this, and
150 * there is no zero (or even low for forward_list) cost way to map from const to non const
151 * iterators (needed to perform the update).
152 *
153 * @see https://github.com/SophistSolutions/Stroika/issues/674 (STK-538)
154 */
155 template <typename STL_CONTAINER_OF_T>
156 class STLContainerWrapper<STL_CONTAINER_OF_T>::ForwardIterator {
157 public:
158 // stuff STL requires you to set to look like an iterator
159 using iterator_category = forward_iterator_tag;
160 using value_type = STLContainerWrapper::value_type;
161 using difference_type = ptrdiff_t;
162 using pointer = const value_type*;
163 using reference = const value_type&;
164
165 public:
166 /**
167 * /0 overload: sets iterator to 'end' - sentinel
168 * /1 (data) overload: sets iterator to begin
169 * /2 (data,startAt) overload: sets iterator to startAt
170 */
171 constexpr ForwardIterator () noexcept = default;
172 explicit constexpr ForwardIterator (const STLContainerWrapper* data) noexcept;
173 explicit constexpr ForwardIterator (const STLContainerWrapper* data, UnderlyingIteratorRep startAt) noexcept;
174 constexpr ForwardIterator (const ForwardIterator&) noexcept = default;
175 constexpr ForwardIterator (ForwardIterator&&) noexcept = default;
176
177 public:
178 nonvirtual ForwardIterator& operator= (const ForwardIterator&) = default;
179 nonvirtual ForwardIterator& operator= (ForwardIterator&&) noexcept = default;
180
181 public:
182 /**
183 * return true if iterator not AtEnd
184 */
185 explicit operator bool () const;
186
187 public:
188 nonvirtual bool AtEnd () const noexcept;
189
190 public:
191 nonvirtual ForwardIterator& operator++ () noexcept;
192 nonvirtual ForwardIterator operator++ (int) noexcept;
193
194 public:
195 nonvirtual const value_type& operator* () const;
196
197 public:
198 nonvirtual const value_type* operator->() const;
199
200 public:
201 /**
202 */
203 nonvirtual size_t CurrentIndex () const;
204
205 public:
206 nonvirtual UnderlyingIteratorRep GetUnderlyingIteratorRep () const;
207
208 public:
209 nonvirtual void SetUnderlyingIteratorRep (UnderlyingIteratorRep l);
210
211 public:
212 nonvirtual bool operator== (const ForwardIterator& rhs) const;
213
214 public:
215 /**
216 * For debugging, assert the iterator data matches argument data
217 */
218 constexpr void AssertDataMatches (const STLContainerWrapper* data) const;
219
220 protected:
221 const STLContainerWrapper* _fData{nullptr};
222 const_iterator _fStdIterator{};
223
224 private:
225 friend class STLContainerWrapper;
226 };
227
228 // see Satisfies Concepts
229 static_assert (forward_iterator<typename STLContainerWrapper<vector<int>>::ForwardIterator>);
230 static_assert (regular<typename STLContainerWrapper<vector<int>>::ForwardIterator>);
231
232 /**
233 * \brief like ForwardIterator, but adding the ability to reverse direction.
234 *
235 * \note only usable if the wrapped STL container's iterator itself supports operator-- (e.g. vector, set,
236 * multiset, multimap - but not forward_list).
237 *
238 * \note Satisfies Concepts:
239 * o regular<BidirectionalIterator>
240 * o bidirectional_iterator<BidirectionalIterator>
241 */
242 template <typename STL_CONTAINER_OF_T>
243 class STLContainerWrapper<STL_CONTAINER_OF_T>::BidirectionalIterator : public ForwardIterator {
244 private:
246
247 public:
248 using iterator_category = bidirectional_iterator_tag;
249 using value_type = typename inherited::value_type;
250 using difference_type = typename inherited::difference_type;
251 using pointer = typename inherited::pointer;
252 using reference = typename inherited::reference;
253
254 public:
255 using inherited::inherited;
256
257 public:
258 /**
259 * \brief same as inherited operator++ () - advances iterator - but returning the subclass iterator type.
260 */
261 nonvirtual BidirectionalIterator& operator++ () noexcept;
262 nonvirtual BidirectionalIterator operator++ (int) noexcept;
263
264 public:
265 nonvirtual bool AtStart () const noexcept;
266
267 public:
268 /**
269 * \pre not AtStart ()
270 */
271 nonvirtual BidirectionalIterator& operator-- () noexcept;
272 nonvirtual BidirectionalIterator operator-- (int) noexcept;
273 };
274
275 // see Satisfies Concepts
276 static_assert (bidirectional_iterator<typename STLContainerWrapper<vector<int>>::BidirectionalIterator>);
277 static_assert (regular<typename STLContainerWrapper<vector<int>>::BidirectionalIterator>);
278
279 /**
280 * \brief like BidirectionalIterator, but adding random access (operator+=, operator[], etc).
281 *
282 * \note only usable if the wrapped STL container's iterator itself is random-access (e.g. vector - but not
283 * set/multiset/multimap/forward_list).
284 *
285 * \note Satisfies Concepts:
286 * o regular<RandomAccessIterator>
287 * o random_access_iterator<RandomAccessIterator>
288 */
289 template <typename STL_CONTAINER_OF_T>
291 private:
293
294 public:
295 using iterator_category = random_access_iterator_tag;
296 using value_type = typename inherited::value_type;
297 using difference_type = ptrdiff_t;
298 using pointer = typename inherited::pointer;
299 using reference = typename inherited::reference;
300
301 public:
303
304 public:
305 /**
306 * \brief same as inherited operator++ ()/operator-- () - but returning the subclass iterator type.
307 */
308 nonvirtual RandomAccessIterator& operator++ () noexcept;
309 nonvirtual RandomAccessIterator operator++ (int) noexcept;
310 nonvirtual RandomAccessIterator& operator-- () noexcept;
311 nonvirtual RandomAccessIterator operator-- (int) noexcept;
312
313 public:
314 nonvirtual RandomAccessIterator operator+ (difference_type i) const;
315 nonvirtual RandomAccessIterator operator- (difference_type i) const;
316 nonvirtual RandomAccessIterator& operator+= (difference_type i);
317 nonvirtual RandomAccessIterator& operator-= (difference_type i);
318
319 public:
320 /**
321 * \brief access the element at the specified index, relative to the current position.
322 */
323 nonvirtual const value_type& operator[] (difference_type i) const;
324
325 public:
326 nonvirtual strong_ordering operator<=> (const RandomAccessIterator& rhs) const;
327
328 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wnon-template-friend\"");
329
330 public:
331 friend RandomAccessIterator operator+ (difference_type i, const RandomAccessIterator& it)
332 {
333 return it + i;
334 }
335
336 public:
337 /**
338 * \brief difference between two iterators - handling the 'sentinel' (default-constructed, _fData ==
339 * nullptr, meaning logically 'end') case on either side, same as
340 * Array<T>::ForwardIterator::operator- does.
341 */
342 friend difference_type operator- (const RandomAccessIterator& lhs, const RandomAccessIterator& rhs)
343 {
344 if (lhs._fData == nullptr) {
345 if (rhs._fData == nullptr) {
346 return 0;
347 }
348 return static_cast<difference_type> (rhs._fData->size ()) - static_cast<difference_type> (rhs.CurrentIndex ());
349 }
350 else if (rhs._fData == nullptr) {
351 return static_cast<difference_type> (lhs.CurrentIndex ()) - static_cast<difference_type> (lhs._fData->size ());
352 }
353 else {
354 return static_cast<difference_type> (lhs._fStdIterator - rhs._fStdIterator);
355 }
356 }
357 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wnon-template-friend\"");
358 };
359
360 // see Satisfies Concepts
361 static_assert (random_access_iterator<typename STLContainerWrapper<vector<int>>::RandomAccessIterator>);
362 static_assert (regular<typename STLContainerWrapper<vector<int>>::RandomAccessIterator>);
363
364 static_assert (ranges::input_range<STLContainerWrapper<vector<int>>>); // smoke test - make sure basic iteration etc should work (allows formattable to work)
365
366}
367
368/*
369 ********************************************************************************
370 ***************************** Implementation Details ***************************
371 ********************************************************************************
372 */
373#include "STLContainerWrapper.inl"
374
375#endif /*_Stroika_Foundation_Containers_DataStructures_STLContainerWrapper_h_ */
like BidirectionalIterator, but adding random access (operator+=, operator[], etc).
nonvirtual void Apply(FUNCTION &&doToElement) const
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
constexpr void AssertDataMatches(const DoublyLinkedList *data) const
nonvirtual ForwardIterator & operator++() noexcept
nonvirtual size_t CurrentIndex(const DoublyLinkedList *data) const