Stroika Library 3.0d18
 
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 * \note for push_front(span) - this puts the span elements in front in the same order in
120 * which they appears in the span
121 */
122 nonvirtual void push_front (ArgByValueType<T> item);
123 template <Memory::ISpanOfT<T> SPAN_T>
124 nonvirtual void push_front (const SPAN_T& copyFrom);
125
126 public:
127 /**
128 * Complexity:
129 * Always: constant
130 */
131 nonvirtual void RemoveFirst ();
132
133 public:
134 /**
135 * \note Runtime performance/complexity:
136 * Always: O(N)
137 */
138 template <invocable<T> FUNCTION>
139 nonvirtual void Apply (FUNCTION&& doToElement) const;
140
141 public:
142 /**
143 * \note Runtime performance/complexity:
144 * Worst Case: O(N)
145 * Typical: O(N), but can be less if systematically finding entries near start of container
146 *
147 * * Complexity EQUALS_COMPARER OVERLOAD:
148 * Worst Case: O(N)
149 * Average Case: O(N)
150 *
151 * EQUALS_COMPARER OVERLOAD : Returns pointer to T (or nullptr if not found). Lifetime of T* only til next call on this.
152 *
153 * \alias Lookup, First, Contains (sort of)
154 */
155 template <predicate<T> FUNCTION>
156 nonvirtual UnderlyingIteratorRep Find (FUNCTION&& firstThat) const;
157 template <typename EQUALS_COMPARER = equal_to<T>>
158 nonvirtual const T* Find (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer = {}) const;
159 template <typename EQUALS_COMPARER = equal_to<T>>
160 nonvirtual T* Find (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer = {});
161
162 public:
163 /**
164 * Complexity:
165 * Always: constant
166 *
167 * \note lifetime of returned pointer only extends til the start of the next non-const call to this LinkedList object
168 */
169 nonvirtual T* PeekAt (const ForwardIterator& i);
170
171 public:
172 /**
173 * Complexity:
174 * Always: constant
175 */
176 nonvirtual void SetAt (const ForwardIterator& i, ArgByValueType<T> newValue);
177
178 public:
179 /**
180 * Complexity:
181 * Always: constant
182 *
183 * NB: Can be called if done
184 */
185 nonvirtual void AddBefore (const ForwardIterator& i, ArgByValueType<T> item);
186 nonvirtual void AddBefore (const ForwardIterator& i, ArgByValueType<T> item, ForwardIterator* newLinkCreatedAt);
187
188 public:
189 /**
190 * Complexity:
191 * Always: constant
192 */
193 nonvirtual void AddAfter (const ForwardIterator& i, ArgByValueType<T> item);
194
195 public:
196 /**
197 * EQUALS_COMPARER overload: Note - does nothing if item not found.
198 *
199 * Complexity (ForwardIterator overload):
200 * Always: constant
201 */
202 template <typename EQUALS_COMPARER>
203 nonvirtual void Remove (ArgByValueType<T> item, const EQUALS_COMPARER& equalsComparer);
204 nonvirtual void Remove (const ForwardIterator& i);
205
206 public:
207 /**
208 * Complexity:
209 * Always: constant
210 *
211 * Returns iterator pointing at next item.
212 */
213 nonvirtual ForwardIterator erase (const ForwardIterator& i);
214
215 public:
216 /**
217 * Complexity:
218 * Always: O(N) - but generally quite quick cuz uses block (de-)allocation
219 */
220 nonvirtual void clear ();
221
222 public:
223 /**
224 * @aliases Append
225 *
226 * Complexity:
227 * Always: O(N)
228 *
229 * Not a lot of point in having this method, as is terribly slow, but the could be convenient.
230 *
231 * \note for push_back(span) - this puts the span elements in back in the same order in
232 * which they appears in the span.
233 *
234 * \see push_front
235 */
236 nonvirtual void push_back (ArgByValueType<T> item);
237 template <Memory::ISpanOfT<T> SPAN_T>
238 nonvirtual void push_back (const SPAN_T& copyFrom);
239
240 public:
241 /**
242 * Complexity:
243 * Always: O(N)
244 *
245 * Not a lot of point in having this method, as is terribly slow, but the could be convenient.
246 */
247 nonvirtual T GetAt (size_t i) const;
248
249 public:
250 /**
251 * Complexity:
252 * Always: O(i)
253 *
254 * Not a lot of point in having this method, as is terribly slow, but the could be convenient.
255 */
256 nonvirtual void SetAt (T item, size_t i);
257
258 public:
259 /**
260 */
261 nonvirtual void Invariant () const noexcept;
262
263 private:
264 Link_* fHead_{nullptr};
265
266#if qStroika_Foundation_Debug_AssertionsChecked
267 private:
268 virtual void Invariant_ () const noexcept;
269#endif
270
271 private:
272 friend class ForwardIterator;
273 };
274
275 /**
276 * dont use block allocation for link sizes too large
277 */
278 template <typename T>
279 class LinkedList<T>::Link_ : public Memory::UseBlockAllocationIfAppropriate<Link_, sizeof (T) <= 256> {
280 public:
281 Link_ () = delete;
282 constexpr Link_ (ArgByValueType<T> item, Link_* next);
283 Link_ (const Link_&) = delete;
284
285 public:
286 T fItem;
287 Link_* fNext{nullptr};
288 };
289
290 /*
291 * ForwardIterator allows you to iterate over a LinkedList<T>. It is not safe to use a ForwardIterator after any
292 * update to the LinkedList.
293 */
294 template <typename T>
295 class LinkedList<T>::ForwardIterator {
296 public:
297 // stuff STL requires you to set to look like an iterator
298 using iterator_category = forward_iterator_tag;
299 using value_type = LinkedList::value_type;
300 using difference_type = ptrdiff_t;
301 using pointer = const value_type*;
302 using reference = const value_type&;
303
304 public:
305 /**
306 * /0 overload: sets iterator to 'end' - sentinel
307 * /1 (data) overload: sets iterator to begin
308 * /2 (data,startAt) overload: sets iterator to startAt
309 */
310 constexpr ForwardIterator () noexcept = default;
311 explicit constexpr ForwardIterator (const LinkedList* data) noexcept;
312 explicit constexpr ForwardIterator (const LinkedList* data, UnderlyingIteratorRep startAt) noexcept;
313 constexpr ForwardIterator (const ForwardIterator&) noexcept = default;
314 constexpr ForwardIterator (ForwardIterator&&) noexcept = default;
315
316 public:
317 nonvirtual ForwardIterator& operator= (const ForwardIterator&) = default;
318 nonvirtual ForwardIterator& operator= (ForwardIterator&&) noexcept = default;
319
320 public:
321 /**
322 * return true if iterator not Done
323 */
324 explicit operator bool () const;
325
326 public:
327 nonvirtual bool Done () const noexcept;
328
329 public:
330 nonvirtual ForwardIterator& operator++ () noexcept;
331 nonvirtual ForwardIterator operator++ (int) noexcept;
332
333 public:
334 nonvirtual T operator* () const;
335
336 public:
337 nonvirtual const T* operator->() const;
338
339 public:
340 /**
341 * \note Runtime performance/complexity:
342 * Average/WorseCase: O(N) - super slow cuz have to traverse on average half the list
343 *
344 * \pre data == fData_ argument constructed with (or as adjusted by Move...); api takes extra param so release builds need not store fData_
345 */
346 nonvirtual size_t CurrentIndex (const LinkedList* data) const;
347
348 public:
349 nonvirtual UnderlyingIteratorRep GetUnderlyingIteratorRep () const;
350
351 public:
352 nonvirtual void SetUnderlyingIteratorRep (const UnderlyingIteratorRep l);
353
354 public:
355 /**
356 * For debugging, assert the iterator data matches argument data
357 */
358 constexpr void AssertDataMatches (const LinkedList* data) const;
359
360 public:
361 nonvirtual bool operator== (const ForwardIterator& rhs) const;
362
363 public:
364 nonvirtual void Invariant () const noexcept;
365
366 private:
367 const Link_* fCurrent_{nullptr};
368#if qStroika_Foundation_Debug_AssertionsChecked
369 const LinkedList* fData_{nullptr};
370#endif
371
372#if qStroika_Foundation_Debug_AssertionsChecked
373 private:
374 nonvirtual void Invariant_ () const noexcept;
375#endif
376
377 private:
378 friend class LinkedList;
379 };
380
381 static_assert (ranges::input_range<LinkedList<int>>); // smoke test - make sure basic iteration etc should work (allows formattable to work)
382
383}
384
385/*
386 ********************************************************************************
387 ***************************** Implementation Details ***************************
388 ********************************************************************************
389 */
390#include "LinkedList.inl"
391
392#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 MoveIteratorHereAfterClone(ForwardIterator *pi, const LinkedList *movedFrom) const
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