Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
DoublyLinkedList.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_DataStructures_DoublyLinkedList_h_
5#define _Stroika_Foundation_Containers_DataStructures_DoublyLinkedList_h_
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/Common.h"
12#include "Stroika/Foundation/Containers/Common.h"
15
16/*
17 *
18 * Description:
19 *
20 * DoublyLinkedList<T> is a backend implementation. It is not intended to be directly
21 * used by programmers, except in implementing concrete container reps.
22 *
23 * TODO:
24 *
25 * Long-Term TODO:
26 * @todo Could add iterator subclass (or use traits to control) which tracks index internally, as with Stroika v1
27 * but this will do for and maybe best (depending on frequency of calls to CurrentIndex ()
28 *
29 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
30 *
31 */
32
34
36
37 /**
38 * DoublyLinkedList<T> is a generic link (non-intrusive) list implementation.
39 * We provide no public means to access the links themselves.
40 *
41 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
42 */
43 template <typename T>
45 public:
46 using value_type = T;
47
48 public:
49 /**
50 */
55
56 public:
57 nonvirtual DoublyLinkedList& operator= (const DoublyLinkedList& list);
58
59 private:
60 class Link_;
61
62 public:
63 /**
64 * Basic (mostly internal) element used by ForwardIterator. Abstract name so can be referenced generically across 'DataStructure' objects
65 */
66 using UnderlyingIteratorRep = const Link_*;
67
68 public:
69 class ForwardIterator;
70
71 public:
72 /**
73 * \note Runtime performance/complexity:
74 * Always: constant
75 */
76 nonvirtual bool empty () const;
77
78 public:
79 /**
80 * \note Runtime performance/complexity:
81 * Always: O(N)
82 */
83 nonvirtual size_t size () const;
84
85 public:
86 /**
87 * \note Runtime performance/complexity:
88 * Always: constant
89 */
90 nonvirtual optional<T> GetFirst () const;
91
92 public:
93 /**
94 * \note Runtime performance/complexity:
95 * Always: constant
96 */
97 nonvirtual optional<T> GetLast () const;
98
99 public:
100 /**
101 * @aliases Prepend
102 *
103 * \note Runtime performance/complexity:
104 * Always: constant
105 *
106 * \note for push_front(span) - this puts the span elements in front in the same order in
107 * which they appears in the span.
108 */
109 nonvirtual void push_front (ArgByValueType<T> item);
110 template <Memory::ISpanOfT<T> SPAN_T>
111 nonvirtual void push_front (const SPAN_T& copyFrom);
112
113 public:
114 /**
115 * @aliases Append
116 *
117 * \note Runtime performance/complexity:
118 * Always: constant
119 *
120 * \note for push_back(span) - this puts the span elements in back in the same order in
121 * which they appears in the span.
122 */
123 nonvirtual void push_back (ArgByValueType<T> item);
124 template <Memory::ISpanOfT<T> SPAN_T>
125 nonvirtual void push_back (const SPAN_T& copyFrom);
126
127 public:
128 /**
129 * \note Runtime performance/complexity:
130 * Always: constant
131 *
132 * \pre not empty ()
133 */
134 nonvirtual void RemoveFirst ();
135
136 public:
137 /**
138 * \note Runtime performance/complexity:
139 * Always: constant
140 *
141 * \pre not empty ()
142 */
143 nonvirtual void RemoveLast ();
144
145 public:
146 /*
147 * \note Runtime performance/complexity:
148 * Worst Case: O(N)
149 * Average Case: O(N)
150 *
151 * Utility to search the list for the given item using EQUALS_COMPARER
152 */
153 template <typename EQUALS_COMPARER = equal_to<T>>
154 nonvirtual bool Contains (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer = {}) const;
155
156 public:
157 /**
158 * \note Runtime performance/complexity:
159 * Always: O(N)
160 */
161 template <invocable<T> FUNCTION>
162 nonvirtual void Apply (FUNCTION&& doToElement) const;
163
164 public:
165 /**
166 * \note Runtime performance/complexity:
167 * Worst Case: O(N)
168 * Typical: O(N), but can be less if systematically finding entries near start of container
169 */
170 template <typename FUNCTION>
171 nonvirtual UnderlyingIteratorRep Find (FUNCTION&& firstThat) const;
172
173 public:
174 /**
175 * \note Runtime performance/complexity:
176 * Worst Case: O(N)
177 * Average Case: O(N)
178 *
179 * Note - does nothing if item not found.
180
181 ForwardIterator OVERLOAD:
182 * \note Runtime performance/complexity:
183 * Always: constant
184 *
185 * returns the next link
186 */
187 template <typename EQUALS_COMPARER = equal_to<T>>
188 nonvirtual void Remove (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer = {});
189 nonvirtual void Remove (const ForwardIterator& i);
190
191 public:
192 /**
193 * Complexity:
194 * Always: constant
195 *
196 * Returns iterator pointing at next item.
197 */
198 nonvirtual ForwardIterator erase (const ForwardIterator& i);
199
200 public:
201 /**
202 * \note Runtime performance/complexity:
203 * Worst Case: O(N)
204 * Average Case: O(N)
205 */
206 nonvirtual void clear ();
207
208 public:
209 /**
210 * \note Runtime performance/complexity:
211 * Worst Case: O(N)
212 * Average Case: O(N)
213 */
214 nonvirtual T GetAt (size_t i) const;
215
216 public:
217 /**
218 * \note Runtime performance/complexity:
219 * Worst Case: O(N)
220 * Average Case: O(N)
221 */
222 nonvirtual void SetAt (size_t i, ArgByValueType<T> item);
223
224 public:
225 /*
226 * Support for COW (CopyOnWrite):
227 *
228 * Take iterator 'pi' which is originally a valid iterator from 'movedFrom' - and replace *pi with a valid
229 * iterator from 'this' - which points at the same logical position. This requires that this container
230 * was just 'copied' from 'movedFrom' - and is used to produce an equivalent iterator (since iterators are tied to
231 * the container they were iterating over).
232 */
233 nonvirtual void MoveIteratorHereAfterClone (ForwardIterator* pi, const DoublyLinkedList<T>* movedFrom) const;
234
235 public:
236 /**
237 */
238 nonvirtual ForwardIterator begin () const;
239
240 public:
241 /**
242 */
243 constexpr ForwardIterator end () const noexcept;
244
245 public:
246 /**
247 * \note Runtime performance/complexity:
248 * Always: constant
249 */
250 nonvirtual void SetAt (const ForwardIterator& i, ArgByValueType<T> newValue);
251
252 public:
253 /**
254 * \note Runtime performance/complexity:
255 * Always: constant
256 *
257 * \pre not i.Done ()
258 */
259 nonvirtual void AddBefore (const ForwardIterator& i, ArgByValueType<T> item);
260
261 public:
262 /**
263 * \note Runtime performance/complexity:
264 * Always: constant
265 */
266 nonvirtual void AddAfter (const ForwardIterator& i, ArgByValueType<T> item);
267
268 public:
269 nonvirtual void Invariant () const noexcept;
270
271 private:
272 Link_* fHead_{};
273 Link_* fTail_{};
274
275#if qStroika_Foundation_Debug_AssertionsChecked
276 private:
277 virtual void Invariant_ () const noexcept;
278#endif
279
280 private:
281 friend class ForwardIterator;
282 };
283
284 /**
285 * Just an implementation detail. Don't use directly except in helper classes.
286 * dont use block allocation for link sizes too large
287 */
288 template <typename T>
289 class DoublyLinkedList<T>::Link_ : public Memory::UseBlockAllocationIfAppropriate<Link_, sizeof (T) <= 1024> {
290 public:
291 Link_ () = delete;
292 Link_ (const Link_&) = delete;
293 constexpr Link_ (ArgByValueType<T> item, Link_* prev, Link_* next);
294
295 public:
296 T fItem;
297 Link_* fPrev{nullptr};
298 Link_* fNext{nullptr};
299 };
300
301 /**
302 * ForwardIterator<T> allows you to iterate over a DoublyLinkedList<T>. Its API
303 * is designed to make easy implementations of subclasses of IteratorRep<T>.
304 * It is unpatched - use DoublyLinkedListIterator_Patch<T> or DoublyLinkedListIterator_Patch<T>
305 * for that.
306 */
307 template <typename T>
308 class DoublyLinkedList<T>::ForwardIterator {
309 public:
310 // stuff STL requires you to set to look like an iterator
311 using iterator_category = forward_iterator_tag;
312 using value_type = DoublyLinkedList::value_type;
313 using difference_type = ptrdiff_t;
314 using pointer = const value_type*;
315 using reference = const value_type&;
316
317 public:
318 /**
319 * /0 overload: sets iterator to 'end' - sentinel
320 * /1 (data) overload: sets iterator to begin
321 * /2 (data,startAt) overload: sets iterator to startAt
322 */
323 constexpr ForwardIterator () noexcept = default;
324 explicit constexpr ForwardIterator (const DoublyLinkedList* data) noexcept;
325 explicit constexpr ForwardIterator (const DoublyLinkedList* data, UnderlyingIteratorRep startAt) noexcept;
326 constexpr ForwardIterator (const ForwardIterator&) noexcept = default;
327 constexpr ForwardIterator (ForwardIterator&&) noexcept = default;
328
329 public:
330 nonvirtual ForwardIterator& operator= (const ForwardIterator&) = default;
331 nonvirtual ForwardIterator& operator= (ForwardIterator&&) noexcept = default;
332
333 public:
334 /**
335 * return true if iterator not Done
336 */
337 explicit operator bool () const;
338
339 public:
340 nonvirtual bool Done () const noexcept;
341
342 public:
343 nonvirtual const T& operator* () const;
344
345 public:
346 nonvirtual const T* operator->() const;
347
348 public:
349 nonvirtual ForwardIterator& operator++ () noexcept;
350 nonvirtual ForwardIterator operator++ (int) noexcept;
351
352 /**
353 * \note Runtime performance/complexity:
354 * Average/WorseCase: O(N) - super slow cuz have to traverse on average half the list
355 *
356 * \pre data == fData_ argument constructed with (or as adjusted by Move...); api takes extra param so release builds need not store fData_
357 */
358 nonvirtual size_t CurrentIndex (const DoublyLinkedList* data) const;
359
360 public:
361 nonvirtual UnderlyingIteratorRep GetUnderlyingIteratorRep () const;
362
363 public:
364 nonvirtual void SetUnderlyingIteratorRep (UnderlyingIteratorRep l);
365
366 public:
367 /**
368 * For debugging, assert the iterator data matches argument data
369 */
370 constexpr void AssertDataMatches (const DoublyLinkedList* data) const;
371
372 public:
373 nonvirtual bool operator== (const ForwardIterator& rhs) const;
374
375 public:
376 nonvirtual void Invariant () const noexcept;
377
378 private:
379 const Link_* fCurrent_{nullptr};
380#if qStroika_Foundation_Debug_AssertionsChecked
381 const DoublyLinkedList* fData_{nullptr};
382#endif
383
384#if qStroika_Foundation_Debug_AssertionsChecked
385 private:
386 nonvirtual void Invariant_ () const noexcept;
387#endif
388
389 private:
390 friend class DoublyLinkedList;
391 };
392
393 static_assert (ranges::input_range<DoublyLinkedList<int>>); // smoke test - make sure basic iteration etc should work (allows formattable to work)
394
395}
396
397/*
398 ********************************************************************************
399 ***************************** Implementation Details ***************************
400 ********************************************************************************
401 */
402#include "DoublyLinkedList.inl"
403
404#endif /*_Stroika_Foundation_Containers_DataStructures_DoublyLinkedList_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.
nonvirtual void AddBefore(const ForwardIterator &i, ArgByValueType< T > item)
nonvirtual ForwardIterator erase(const ForwardIterator &i)
nonvirtual void Remove(ArgByValueType< T > item, EQUALS_COMPARER &&equalsComparer={})
nonvirtual void Apply(FUNCTION &&doToElement) const
nonvirtual void SetAt(size_t i, ArgByValueType< T > item)
nonvirtual UnderlyingIteratorRep Find(FUNCTION &&firstThat) const
nonvirtual void AddAfter(const ForwardIterator &i, ArgByValueType< T > item)
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
Definition TypeHints.h:32
constexpr void AssertDataMatches(const DoublyLinkedList *data) const
nonvirtual size_t CurrentIndex(const DoublyLinkedList *data) const