Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
LinkedList.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Containers_DataStructures_LinkedList_h_
5#define _Stroika_Foundation_Containers_DataStructures_LinkedList_h_
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <optional>
10
11#include "Stroika/Foundation/Common/Common.h"
14#include "Stroika/Foundation/Containers/Common.h"
17
18/**
19 * LinkedList<T,TRAITS> is a backend implementation. It is not intended to be directly
20 * used by programmers, except in implementing concrete container reps.
21 *
22 * TODO:
23 * @todo Include Performance numbers for each operation (done for many).
24 * @todo https://stroika.atlassian.net/browse/STK-1016 - ranges/sentinel support
25 *
26 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
27 *
28 */
29
31
33
34 /**
35 * LinkedList<T,TRAITS> is a generic link (non-intrusive) list implementation (similar to std::forward_list).
36 * We provide no public means to access the links themselves.
37 *
38 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
39 */
40 template <typename T>
42 public:
43 using value_type = T;
44
45 public:
46 /**
47 */
48 LinkedList ();
49 LinkedList (LinkedList&& src);
50 LinkedList (const LinkedList& src);
51 ~LinkedList ();
52
53 public:
54 nonvirtual LinkedList& operator= (const LinkedList& list);
55
56 public:
57 class ForwardIterator;
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 /*
70 * Support for COW (CopyOnWrite):
71 *
72 * Take iterator 'pi' which is originally a valid iterator from 'movedFrom' - and replace *pi with a valid
73 * iterator from 'this' - which points at the same logical position. This requires that this container
74 * was just 'copied' from 'movedFrom' - and is used to produce an equivalent iterator (since iterators are tied to
75 * the container they were iterating over).
76 */
77 nonvirtual void MoveIteratorHereAfterClone (ForwardIterator* pi, const LinkedList* movedFrom) const;
78
79 public:
80 /**
81 */
82 nonvirtual ForwardIterator begin () const;
83
84 public:
85 /**
86 */
87 constexpr ForwardIterator end () const noexcept;
88
89 public:
90 /**
91 * \note Runtime performance/complexity:
92 * Always: constant
93 */
94 nonvirtual bool empty () const;
95
96 public:
97 /**
98 * \note Runtime performance/complexity:
99 * Always: O(N)
100 */
101 nonvirtual size_t size () const;
102
103 public:
104 /**
105 * Complexity:
106 * Always: constant
107 */
108 nonvirtual optional<T> GetFirst () const;
109
110 public:
111 /**
112 * @aliases Prepend
113 *
114 * Complexity:
115 * Always: constant
116 *
117 * \see push_back
118 */
119 nonvirtual void push_front (ArgByValueType<T> item);
120
121 public:
122 /**
123 * Complexity:
124 * Always: constant
125 */
126 nonvirtual void RemoveFirst ();
127
128 public:
129 /**
130 * \note Runtime performance/complexity:
131 * Always: O(N)
132 * @todo add function concept
133 */
134 template <invocable<T> FUNCTION>
135 nonvirtual void Apply (FUNCTION&& doToElement) const;
136
137 public:
138 /**
139 * \note Runtime performance/complexity:
140 * Worst Case: O(N)
141 * Typical: O(N), but can be less if systematically finding entries near start of container
142 *
143 * @todo add predicate
144 *
145 * * Complexity EQUALS_COMPARER OVERLOAD:
146 * Worst Case: O(N)
147 * Average Case: O(N)
148 *
149 * EQUALS_COMPARER OVERLOAD : Returns pointer to T (or nullptr if not found). Lifetime of T* only til next call on this.
150 */
151 template <predicate<T> FUNCTION>
152 nonvirtual UnderlyingIteratorRep Find (FUNCTION&& firstThat) const;
153 template <typename EQUALS_COMPARER = equal_to<T>>
154 nonvirtual const T* Find (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer = {}) const;
155 template <typename EQUALS_COMPARER = equal_to<T>>
156 nonvirtual T* Find (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer = {});
157
158 public:
159 /**
160 * Complexity:
161 * Always: constant
162 *
163 * \note lifetime of returned pointer only extends til the start of the next non-const call to this LinkedList object
164 */
165 nonvirtual T* PeekAt (const ForwardIterator& i);
166
167 public:
168 /**
169 * Complexity:
170 * Always: constant
171 */
172 nonvirtual void SetAt (const ForwardIterator& i, ArgByValueType<T> newValue);
173
174 public:
175 /**
176 * Complexity:
177 * Always: constant
178 *
179 * NB: Can be called if done
180 */
181 nonvirtual void AddBefore (const ForwardIterator& i, ArgByValueType<T> item);
182 nonvirtual void AddBefore (const ForwardIterator& i, ArgByValueType<T> item, ForwardIterator* newLinkCreatedAt);
183
184 public:
185 /**
186 * Complexity:
187 * Always: constant
188 */
189 nonvirtual void AddAfter (const ForwardIterator& i, ArgByValueType<T> item);
190
191 public:
192 /**
193 * EQUALS_COMPARER overload: Note - does nothing if item not found.
194 *
195 * Complexity (ForwardIterator overload):
196 * Always: constant
197 */
198 template <typename EQUALS_COMPARER>
199 nonvirtual void Remove (ArgByValueType<T> item, const EQUALS_COMPARER& equalsComparer);
200 nonvirtual void Remove (const ForwardIterator& i);
201
202 public:
203 /**
204 * Complexity:
205 * Always: constant
206 *
207 * Returns iterator pointing at next item.
208 */
209 nonvirtual ForwardIterator erase (const ForwardIterator& i);
210
211 public:
212 /**
213 * Complexity:
214 * Always: O(N) - but generally quite quick cuz uses block (de-)allocation
215 *
216 */
217 nonvirtual void RemoveAll ();
218
219 public:
220 /**
221 * @aliases Append
222 *
223 * Complexity:
224 * Always: O(N)
225 *
226 * Not a lot of point in having this method, as is terribly slow, but the could be convenient.
227 *
228 * \see push_front
229 */
230 nonvirtual void push_back (ArgByValueType<T> item);
231
232 public:
233 /*
234 * Complexity:
235 * Always: O(N)
236 *
237 * Not a lot of point in having this method, as is terribly slow, but the could be convenient.
238 */
239 nonvirtual T GetAt (size_t i) const;
240
241 public:
242 /*
243 * Complexity:
244 * Always: O(i)
245 *
246 * Not a lot of point in having this method, as is terribly slow, but the could be convenient.
247 */
248 nonvirtual void SetAt (T item, size_t i);
249
250 public:
251 nonvirtual void Invariant () const noexcept;
252
253 private:
254 Link_* fHead_{nullptr};
255
256#if qStroika_Foundation_Debug_AssertionsChecked
257 private:
258 virtual void Invariant_ () const noexcept;
259#endif
260
261 private:
262 friend class ForwardIterator;
263 };
264
265 /**
266 * dont use block allocation for link sizes too large
267 */
268 template <typename T>
269 class LinkedList<T>::Link_ : public Memory::UseBlockAllocationIfAppropriate<Link_, sizeof (T) <= 256> {
270 public:
271 Link_ () = delete;
272 constexpr Link_ (ArgByValueType<T> item, Link_* next);
273 Link_ (const Link_&) = delete;
274
275 public:
276 T fItem;
277 Link_* fNext{nullptr};
278 };
279
280 /*
281 * ForwardIterator allows you to iterate over a LinkedList<T>. It is not safe to use a ForwardIterator after any
282 * update to the LinkedList.
283 */
284 template <typename T>
285 class LinkedList<T>::ForwardIterator {
286 public:
287 // stuff STL requires you to set to look like an iterator
288 using iterator_category = forward_iterator_tag;
289 using value_type = LinkedList::value_type;
290 using difference_type = ptrdiff_t;
291 using pointer = const value_type*;
292 using reference = const value_type&;
293
294 public:
295 /**
296 * /0 overload: sets iterator to 'end' - sentinel
297 * /1 (data) overload: sets iterator to begin
298 * /2 (data,startAt) overload: sets iterator to startAt
299 */
300 constexpr ForwardIterator () noexcept = default;
301 explicit constexpr ForwardIterator (const LinkedList* data) noexcept;
302 explicit constexpr ForwardIterator (const LinkedList* data, UnderlyingIteratorRep startAt) noexcept;
303 constexpr ForwardIterator (const ForwardIterator&) noexcept = default;
304 constexpr ForwardIterator (ForwardIterator&&) noexcept = default;
305
306 public:
307 nonvirtual ForwardIterator& operator= (const ForwardIterator&) = default;
308 nonvirtual ForwardIterator& operator= (ForwardIterator&&) noexcept = default;
309
310 public:
311 /**
312 * return true if iterator not Done
313 */
314 explicit operator bool () const;
315
316 public:
317 nonvirtual bool Done () const noexcept;
318
319 public:
320 nonvirtual ForwardIterator& operator++ () noexcept;
321 nonvirtual ForwardIterator operator++ (int) noexcept;
322
323 public:
324 nonvirtual T operator* () const;
325
326 public:
327 nonvirtual const T* operator->() const;
328
329 public:
330 /**
331 * \note Runtime performance/complexity:
332 * Average/WorseCase: O(N) - super slow cuz have to traverse on average half the list
333 *
334 * \pre data == fData_ argument constructed with (or as adjusted by Move...); api takes extra param so release builds need not store fData_
335 */
336 nonvirtual size_t CurrentIndex (const LinkedList* data) const;
337
338 public:
339 nonvirtual UnderlyingIteratorRep GetUnderlyingIteratorRep () const;
340
341 public:
342 nonvirtual void SetUnderlyingIteratorRep (const UnderlyingIteratorRep l);
343
344 public:
345 /**
346 * For debugging, assert the iterator data matches argument data
347 */
348 constexpr void AssertDataMatches (const LinkedList* data) const;
349
350 public:
351 nonvirtual bool operator== (const ForwardIterator& rhs) const;
352
353 public:
354 nonvirtual void Invariant () const noexcept;
355
356 private:
357 const Link_* fCurrent_{nullptr};
358#if qStroika_Foundation_Debug_AssertionsChecked
359 const LinkedList* fData_{nullptr};
360#endif
361
362#if qStroika_Foundation_Debug_AssertionsChecked
363 private:
364 nonvirtual void Invariant_ () const noexcept;
365#endif
366
367 private:
368 friend class LinkedList;
369 };
370
371 static_assert (ranges::input_range<LinkedList<int>>); // smoke test - make sure basic iteration etc should work (allows formattable to work)
372
373}
374
375/*
376 ********************************************************************************
377 ***************************** Implementation Details ***************************
378 ********************************************************************************
379 */
380#include "LinkedList.inl"
381
382#endif /*_Stroika_Foundation_Containers_DataStructures_LinkedList_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 Remove(ArgByValueType< T > item, const EQUALS_COMPARER &equalsComparer)
nonvirtual void AddBefore(const ForwardIterator &i, ArgByValueType< T > item)
nonvirtual void SetAt(const ForwardIterator &i, ArgByValueType< T > newValue)
nonvirtual void push_back(ArgByValueType< T > item)
nonvirtual void push_front(ArgByValueType< T > item)
nonvirtual T * PeekAt(const ForwardIterator &i)
nonvirtual UnderlyingIteratorRep Find(FUNCTION &&firstThat) const
nonvirtual ForwardIterator erase(const ForwardIterator &i)
nonvirtual void Apply(FUNCTION &&doToElement) 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