1 | // tList.h  |
2 | //  |
3 | // Linked list implementations. There are two implementations in this module. tList is intrusive, tItList (i for  |
4 | // iterator) is non-intrusive. Use the intrusive one for performance and fewer fragmentation issues if possible.  |
5 | //  |
6 | // tList advantages: Faster and less memory fragmentation (one new per object).  |
7 | // tList disadvantages: An object can only be on one list at a time. You must derive from tLink.  |
8 | //  |
9 | // tItList advantages: The same item only in one list at a time. No change in memory image for the objects. Cleaner  |
10 | // iterator syntax similar to the STL containers. Supports the new C++11 range-based for loop syntax.  |
11 | // tItList disadvantages: More memory allocs. Not quite as fast.  |
12 | //  |
13 | // Copyright (c) 2004-2006, 2015, 2017, 2020 Tristan Grimmer.  |
14 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
15 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
16 | //  |
17 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
19 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
20 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
21 | // PERFORMANCE OF THIS SOFTWARE.  |
22 |   |
23 | #pragma once  |
24 | #include "Foundation/tAssert.h"  |
25 | #include "Foundation/tPlatform.h"  |
26 |   |
27 |   |
28 | enum class tListSortAlgorithm  |
29 | {  |
30 | Merge, // Guaranteed O(n ln(n)) even in worst case.  |
31 | Bubble // As bad as O(n^2) on unsorted data. Only O(n) on sorted.  |
32 | };  |
33 |   |
34 |   |
35 | // You need to derive your object from this if you want to put them on a tList.  |
36 | template<typename T> class tLink  |
37 | {  |
38 | public:  |
39 | tLink() : NextItem(nullptr), PrevItem(nullptr) { }  |
40 | tLink(const tLink&) : NextItem(nullptr), PrevItem(nullptr) { }  |
41 | T* Next() const { return NextItem; }  |
42 | T* Prev() const { return PrevItem; }  |
43 |   |
44 | private:  |
45 | template<typename U> friend class tList;  |
46 | T* NextItem;  |
47 | T* PrevItem;  |
48 | };  |
49 |   |
50 |   |
51 | enum class tListMode  |
52 | {  |
53 | StaticZero, Static = StaticZero, // Default. Must be 0.  |
54 | External, UserOwns = External,  |
55 | Internal, ListOwns = Internal  |
56 | };  |
57 |   |
58 |   |
59 | // A tList is an intrusive list implementation. Less mem fragmentation but objects can only be on one list at a time.  |
60 | // A tList may be used in the cdata (global) memory section where zero-initialization is guaranteed. In this mode it  |
61 | // does NOT delete its items on destruction to avoid both the init and de-init fiasco. tLists may also be used on the  |
62 | // stack or heap, in which case it is optional construct with the ListOwns flag. It is vital that for zero-init you  |
63 | // call the constructor with mode as StaticZero IF you intend to have it populated by other statically initialized  |
64 | // objects before main() is entered. This is because we don't know what items will have already been put on the list  |
65 | // before the constructor is called (the C++ init fiasco). The constructor in StaticZero mode does NOT clear the state  |
66 | // variables so it doesn't matter when.  |
67 | //  |
68 | // Note: In static mode, the list does not consider itself to own the things on the list. It is safe to add 'this'  |
69 | // pointers to globally constructed objects for instance. If however you do want the list to delete the items, tList  |
70 | // will allow you to call Empty on a static-zero list. You can also call Reset (no deletes). Clear will be the same  |
71 | // as Reset for static-zero lists.  |
72 | template<typename T> class tList  |
73 | {  |
74 | public:  |
75 | // The default constructor has the list owning the items.  |
76 | tList() : Mode(tListMode::ListOwns), HeadItem(nullptr), TailItem(nullptr), ItemCount(0) { }  |
77 |   |
78 | // If mode is external the objects will not be deleted when the list is destroyed. You manage item lifetime.  |
79 | tList(tListMode mode) : Mode(mode) { if (mode != tListMode::StaticZero) { HeadItem = nullptr; TailItem = nullptr; ItemCount = 0; } }  |
80 |   |
81 | virtual ~tList() { if (Owns()) Empty(); }  |
82 |   |
83 | T* Insert(T* item); // Insert item at head. Returns item.  |
84 | T* Insert(T* item, T* here); // Insert item before here. Returns item.  |
85 | T* Append(T* item); // Append item at tail. Returns item.  |
86 | T* Append(T* item, T* here); // Append item after here. Returns item.  |
87 | T* Remove(T* item); // Removes and returns item.  |
88 | T* Remove(); // Removes and returns head item.  |
89 | T* Drop(); // Removes and returns tail item.  |
90 |   |
91 | void Clear() /* Clears the list. Deletes items if list owns them. */ { if (Owns()) Empty(); else Reset(); }  |
92 | void Reset() /* Resets the list. Never deletes the objects. */ { HeadItem = nullptr; TailItem = nullptr; ItemCount = 0; }  |
93 | void Empty() /* Empties the list. Always deletes the objects. */ { tAssert(Owns() || (Mode == tListMode::StaticZero)); while (!IsEmpty()) delete Remove(); }  |
94 |   |
95 | T* Head() const { return HeadItem; }  |
96 | T* Tail() const { return TailItem; }  |
97 | T* First() const { return HeadItem; }  |
98 | T* Last() const { return TailItem; }  |
99 |   |
100 | T* NextCirc(const T* here) const /* Circular. Gets item after here. */ { return here->NextItem ? here->NextItem : HeadItem; }  |
101 | T* PrevCirc(const T* here) const /* Circular. Gets item before here. */ { return here->PrevItem ? here->PrevItem : TailItem; }  |
102 |   |
103 | int GetNumItems() const { return ItemCount; }  |
104 | int NumItems() const { return ItemCount; }  |
105 | int Count() const { return ItemCount; }  |
106 | bool Owns() const { return (Mode == tListMode::Internal); }  |
107 | bool IsEmpty() const { return !HeadItem; }  |
108 | bool Contains(const T& item) const /* To use this there must be an operator== for type T. */ { for (const T* n = First(); n; n = n->Next()) if (*n == item) return true; return false; }  |
109 |   |
110 | // Sorts the list using the algorithm specified. The supplied compare function should never return true on equal.  |
111 | // To sort ascending return the truth of a < b. Return a > b to sort in descending order. Returns the number of  |
112 | // compares performed. The compare function usually implements bool CompareFunc(const T& a, const T& b)  |
113 | template<typename CompareFunc> int Sort(CompareFunc, tListSortAlgorithm alg = tListSortAlgorithm::Merge);  |
114 |   |
115 | // Inserts item in a sorted list. It will remain sorted.  |
116 | template<typename CompareFunc> T* Insert(T* item, CompareFunc);  |
117 |   |
118 | // This does an O(n) single pass of a bubble sort iteration. Allows the cost of sorting to be distributed over time  |
119 | // for objects that do not change their order very often. Do the expensive merge sort when the list is initially  |
120 | // populated, then use this to keep it approximately correct.  |
121 | //  |
122 | // The direction is important when doing this type of partial sort. A forward bubble will result in the last object  |
123 | // in the list being correct after one pass, last two for two passes etc. If getting the front of the list correct  |
124 | // sooner is more important you'll want to bubble backwards. This is true regardless of whether the compare  |
125 | // function implements an ascending or descending sort.  |
126 | //  |
127 | // maxCompares sets how far into the list to perform possible swaps. If maxCompares == -1 it means go all the way.  |
128 | // That is, GetNumItems() - 1. Returns number of swaps performed.  |
129 | template<typename CompareFunc> int Bubble(CompareFunc compare, bool backwards = false, int maxCompares = -1) { if (backwards) return BubbleBackward(compare, maxCompares); else return BubbleForward(compare, maxCompares); }  |
130 |   |
131 | private:  |
132 | // These return the number of swaps performed. If 0 is returned, the items considered were already in the correct  |
133 | // order. The maxCompares allows you to limit how many compares are performed. -1 means numItems-1 compares will be  |
134 | // made (a full sweep). The variable gets clamped to [0, numItems) otherwise.  |
135 | template<typename CompareFunc> int BubbleForward(CompareFunc, int maxCompares = -1);  |
136 | template<typename CompareFunc> int BubbleBackward(CompareFunc, int maxCompares = -1);  |
137 |   |
138 | // These return the number of compares performed.  |
139 | template<typename CompareFunc> int SortMerge(CompareFunc);  |
140 | template<typename CompareFunc> int SortBubble(CompareFunc);  |
141 |   |
142 | // Since tList supports static zero-initialization, all defaults for all member vars should be 0.  |
143 | tListMode Mode;  |
144 | T* HeadItem;  |
145 | T* TailItem;  |
146 | int ItemCount;  |
147 | };  |
148 |   |
149 |   |
150 | // The tItList implements a doubly linked non-intrusive iterator-based list. This list class is implemented by using a  |
151 | // tList of structs that point to the objects in the list.  |
152 | template<typename T> class tItList  |
153 | {  |
154 | public:  |
155 | tItList() : Mode(tListMode::ListOwns), Nodes(tListMode::ListOwns) { }  |
156 | tItList(tListMode mode) : Mode(mode), Nodes(tListMode::ListOwns) { }  |
157 | virtual ~tItList() { if (Owns()) Empty(); else Clear(); }  |
158 |   |
159 | private:  |
160 | // This internal datatype is declared early on to make inlining a bit easier.  |
161 | struct IterNode : public tLink<IterNode>  |
162 | {  |
163 | IterNode(const T* obj) : tLink<IterNode>(), Object(obj) { }  |
164 | const T* Get() const { return Object; }  |
165 | const T* Object;  |
166 | };  |
167 |   |
168 | public:  |
169 | // The tItList iterator class for external use.  |
170 | class Iter  |
171 | {  |
172 | public:  |
173 | Iter() : Node(nullptr), List(nullptr) { }  |
174 | Iter(const Iter& src) : Node(src.Node), List(src.List) { }  |
175 |   |
176 | // Iterators may be dereferenced to get to the object.  |
177 | T& operator*() const { return *((T*)Node->Object); }  |
178 | T* operator->() const { return (T*)Node->Object; }  |
179 | operator bool() const { return Node ? true : false; }  |
180 |   |
181 | // Iterators may be treated as pointers to the object.  |
182 | operator T*() { return GetObject(); }  |
183 | operator const T*() const { return GetObject(); }  |
184 | Iter& operator=(const Iter& i) { if (this != &i) { Node = i.Node; List = i.List; } return *this; }  |
185 |   |
186 | // Use ++iter instead of iter++ when possible.  |
187 | const Iter operator++(int) { Iter curr(*this); Next(); return curr; }  |
188 | const Iter operator--(int) { Iter curr(*this); Prev(); return curr; }  |
189 | const Iter operator++() { Next(); return *this; }  |
190 | const Iter operator--() { Prev(); return *this; }  |
191 | const Iter operator+(int offset) const { tAssert(offset >= 0); Iter i = *this; while (offset--) i.Next(); return i; }  |
192 | const Iter operator-(int offset) const { tAssert(offset >= 0); Iter i = *this; while (offset--) i.Prev(); return i; }  |
193 | Iter& operator+=(int offset) { tAssert(offset >= 0); while (offset--) Next(); return *this; }  |
194 | Iter& operator-=(int offset) { tAssert(offset >= 0); while (offset--) Prev(); return *this; }  |
195 | bool operator==(const Iter& i) const { return (Node == i.Node) && (List == i.List); }  |
196 | bool operator!=(const Iter& i) const { return (Node != i.Node) || (List != i.List); }  |
197 |   |
198 | bool IsValid() const { return Node ? true : false; }  |
199 | void Clear() { Node = nullptr; List = nullptr; }  |
200 | void Next() { if (Node) Node = Node->Next(); }  |
201 | void Prev() { if (Node) Node = Node->Prev(); }  |
202 |   |
203 | // Accessors that allow the list to be treated as circular.  |
204 | void NextCirc() { if (Node) Node = Node->Next(); if (!Node) Node = List->Nodes.Head(); }  |
205 | void PrevCirc() { if (Node) Node = Node->Prev(); if (!Node) Node = List->Nodes.Tail(); }  |
206 | T* GetObject() const { return (T*)(Node ? Node->Object : nullptr); }  |
207 |   |
208 | private:  |
209 | friend class tItList<T>;  |
210 | Iter(IterNode* listNode, const tItList<T>* list) : Node(listNode), List(list) { }  |
211 | IterNode* Node;  |
212 | const tItList<T>* List;  |
213 | };  |
214 |   |
215 | // Insert before head and append after tail.  |
216 | T* Insert(const T* obj) { tAssert(obj); Nodes.Insert(new IterNode(obj)); return obj; }  |
217 | T* Insert(const T* obj, const Iter& here) { tAssert(obj); tAssert(this == here.List); Nodes.Insert(new IterNode(obj), here.Node); return obj; }  |
218 | T* Append(T* obj) { tAssert(obj); Nodes.Append(new IterNode(obj)); return obj; }  |
219 | T* Append(const T* obj, const Iter& here) { tAssert(obj); tAssert(this == here.List); Nodes.Append(new IterNode(obj), here.Node); return obj; }  |
220 |   |
221 | T* Remove() /* Removes and returns head. */ { Iter head = Head(); return Remove(head); }  |
222 | T* Remove(Iter&); // Removed object referred to by Iter. Invalidates Iter.  |
223 | T* Drop() /* Drops and returns tail. */ { Iter tail = Tail(); return Drop(tail); }  |
224 | T* Drop(Iter& iter) /* Same a Remove. */ { return Remove(iter); }  |
225 |   |
226 | void Clear() /* Clears the list. Deletes items if ownership flag set. */ { if (Owns()) Empty(); else Reset(); }  |
227 | void Reset() /* Resets the list. Never deletes the objects. */ { while (!IsEmpty()) Remove(); }  |
228 | void Empty() /* Empties the list. Always deletes the objects. */ { while (!IsEmpty()) delete Remove(); }  |
229 |   |
230 | Iter Head() const { return Iter(Nodes.Head(), this); }  |
231 | Iter Tail() const { return Iter(Nodes.Tail(), this); }  |
232 | Iter First() const { return Iter(Nodes.Head(), this); }  |
233 | Iter Last() const { return Iter(Nodes.Tail(), this); }  |
234 |   |
235 | // Searches list forward for a particular item. Returns its iterator or an invalid one if it wasn't found.  |
236 | Iter Find(const T* item) const { for (IterNode* n = Nodes.First(); n; n = n->Next()) if (n->Object == item) return Iter(n, this); return Iter(); }  |
237 |   |
238 | int GetNumItems() const { return Nodes.GetNumItems(); }  |
239 | int NumItems() const { return Nodes.NumItems(); }  |
240 | int Count() const { return Nodes.Count(); }  |
241 | bool IsEmpty() const { return Nodes.IsEmpty(); }  |
242 | bool Owns() const { return (Mode == tListMode::ListOwns); }  |
243 |   |
244 | // For range-based iteration supported in C++11. It worth noting that ++Iter must return a value that matches  |
245 | // whatever end() returns here. That is != must return false when comparing the final ++Iter next call with  |
246 | // what is returned by end(). That is why we return an Iter with a null Node but a _valid_ List pointer.  |
247 | Iter begin() const { return Head(); }  |
248 | Iter end() const { return Iter(nullptr, this); }  |
249 |   |
250 | const T& operator[](const Iter& iter) const { tAssert(iter.IsValid() && (iter.List == this)); return *iter.Node->Object; }  |
251 | T& operator[](const Iter& iter) { tAssert(iter.IsValid() && (iter.List == this)); return *((T*)iter.Node->Object); }  |
252 |   |
253 | // Sorts the list using the algorithm specified. The supplied compare function should never return true on equal.  |
254 | // To sort ascending return the truth of a < b. Return a > b to sort in descending order. Returns the number of  |
255 | // compares performed. The compare function should implement bool CompareFunc(const T& a, const T& b)  |
256 | template<typename CompareFunc> int Sort(CompareFunc compare, tListSortAlgorithm algo = tListSortAlgorithm::Merge) { auto cmp = [&compare](const IterNode& a, const IterNode& b) { return compare(*a.Get(), *b.Get()); }; return Nodes.Sort(cmp, algo); }  |
257 |   |
258 | // Inserts item in a sorted list. It will remain sorted.  |
259 | template<typename CompareFunc> T* Insert(const T* item, CompareFunc compare) { auto cmp = [&compare](IterNode& a, IterNode& b) { return compare(*a.Get(), *b.Get()); }; return Nodes.Insert(item, cmp); }  |
260 |   |
261 | // This does an O(n) single pass of a bubble sort iteration. Allows the cost of sorting to be distributed over time  |
262 | // for objects that do not change their order very often. Do the expensive merge sort when the list is initially  |
263 | // populated, then use this to keep it approximately correct.  |
264 | //  |
265 | // The direction is important when doing this type of partial sort. A forward bubble will result in the last object  |
266 | // in the list being correct after one pass, last two for two passes etc. If getting the front of the list correct  |
267 | // sooner is more important you'll want to bubble backwards. This is true regardless of whether the compare  |
268 | // function implements an ascending or descending sort.  |
269 | //  |
270 | // maxCompares sets how far into the list to perform possible swaps. If maxCompares == -1 it means go all the way.  |
271 | // That is, GetNumItems() - 1. Returns number of swaps performed.  |
272 | //  |
273 | // Note that any iterators that you are maintaining should remain valid.  |
274 | template<typename CompareFunc> int Bubble(CompareFunc compare, bool backwards = false, int maxCompares = -1) { return Nodes.Bubble(compare, backwards, maxCompares); }  |
275 |   |
276 | private:  |
277 | // tItList is implemented using a tList of Nodes that point to the objects.  |
278 | tListMode Mode;  |
279 | tList<IterNode> Nodes;  |
280 | };  |
281 |   |
282 |   |
283 | // Implementation below this line.  |
284 |   |
285 |   |
286 | template<typename T> inline T* tList<T>::Insert(T* item)  |
287 | {  |
288 | if (HeadItem)  |
289 | HeadItem->PrevItem = item;  |
290 |   |
291 | item->NextItem = HeadItem;  |
292 | item->PrevItem = nullptr;  |
293 | HeadItem = item;  |
294 | if (!TailItem)  |
295 | TailItem = item;  |
296 |   |
297 | ItemCount++;  |
298 | return item;  |
299 | }  |
300 |   |
301 |   |
302 | template<typename T> inline T* tList<T>::Append(T* item)  |
303 | {  |
304 | if (TailItem)  |
305 | TailItem->NextItem = item;  |
306 |   |
307 | item->PrevItem = TailItem;  |
308 | item->NextItem = nullptr;  |
309 | TailItem = item;  |
310 | if (!HeadItem)  |
311 | HeadItem = (T*)item;  |
312 |   |
313 | ItemCount++;  |
314 | return item;  |
315 | }  |
316 |   |
317 |   |
318 | template<typename T> template<typename CompareFunc> inline T* tList<T>::Insert(T* item, CompareFunc compare)  |
319 | {  |
320 | // Find the first item (starting from the smallest/head) that our item is less than.  |
321 | for (T* contender = Head(); contender; contender = contender->Next())  |
322 | if (compare(*item, *contender))  |
323 | return Insert(item, contender);  |
324 |   |
325 | return Append(item);   |
326 | }  |
327 |   |
328 |   |
329 | template<typename T> inline T* tList<T>::Insert(T* item, T* where)  |
330 | {  |
331 | tAssert(item);  |
332 | if (!where)  |
333 | return Insert(item);  |
334 |   |
335 | item->NextItem = where;  |
336 | item->PrevItem = where->PrevItem;  |
337 | where->PrevItem = item;  |
338 |   |
339 | if (item->PrevItem)  |
340 | item->PrevItem->NextItem = item;  |
341 | else  |
342 | HeadItem = item;  |
343 |   |
344 | ItemCount++;  |
345 | return item;  |
346 | }  |
347 |   |
348 |   |
349 | template<typename T> inline T* tList<T>::Append(T* item, T* where)  |
350 | {  |
351 | tAssert(item);  |
352 | if (!where)  |
353 | return Append(item);  |
354 |   |
355 | item->PrevItem = where;  |
356 | item->NextItem = where->NextItem;  |
357 | where->NextItem = item;  |
358 |   |
359 | if (item->NextItem)  |
360 | item->NextItem->PrevItem = item;  |
361 | else  |
362 | TailItem = item;  |
363 |   |
364 | ItemCount++;  |
365 | return (T*)item;  |
366 | }  |
367 |   |
368 |   |
369 | template<typename T> inline T* tList<T>::Remove()  |
370 | {  |
371 | // It's OK to try to remove from an empty list.  |
372 | if (!HeadItem)  |
373 | return nullptr;  |
374 |   |
375 | T* removed = HeadItem;  |
376 | HeadItem = (T*)HeadItem->NextItem;  |
377 | if (!HeadItem)  |
378 | TailItem = nullptr;  |
379 | else  |
380 | HeadItem->PrevItem = nullptr;  |
381 |   |
382 | ItemCount--;  |
383 | return removed;  |
384 | }  |
385 |   |
386 |   |
387 | template<typename T> inline T* tList<T>::Drop()  |
388 | {  |
389 | // It's OK to try to lose something from an empty list.  |
390 | if (!TailItem)  |
391 | return nullptr;  |
392 |   |
393 | T* dropped = TailItem;  |
394 | TailItem = (T*)TailItem->PrevItem;  |
395 | if (!TailItem)  |
396 | HeadItem = nullptr;  |
397 | else  |
398 | TailItem->NextItem = nullptr;  |
399 |   |
400 | ItemCount--;  |
401 | return dropped;  |
402 | }  |
403 |   |
404 |   |
405 | template<typename T> inline T* tList<T>::Remove(T* item)  |
406 | {  |
407 | if (item->PrevItem)  |
408 | item->PrevItem->NextItem = item->NextItem;  |
409 | else  |
410 | HeadItem = item->NextItem;  |
411 |   |
412 | if (item->NextItem)  |
413 | item->NextItem->PrevItem = item->PrevItem;  |
414 | else  |
415 | TailItem = item->PrevItem;  |
416 |   |
417 | ItemCount--;  |
418 | return item;  |
419 | }  |
420 |   |
421 |   |
422 | template<typename T> template<typename CompareFunc> inline int tList<T>::Sort(CompareFunc compare, tListSortAlgorithm algorithm)  |
423 | {  |
424 | switch (algorithm)  |
425 | {  |
426 | case tListSortAlgorithm::Bubble:  |
427 | return SortBubble(compare);  |
428 | break;  |
429 |   |
430 | case tListSortAlgorithm::Merge:  |
431 | default:  |
432 | return SortMerge(compare);  |
433 | break;  |
434 | }  |
435 |   |
436 | return 0;  |
437 | }  |
438 |   |
439 |   |
440 | template<typename T> template<typename CompareFunc> inline int tList<T>::SortMerge(CompareFunc compare)  |
441 | {  |
442 | if (!HeadItem)  |
443 | return 0;  |
444 |   |
445 | // Treat every node as a separate list, completely sorted, starting with 1 element each.  |
446 | int numNodesPerList = 1;  |
447 | int numCompares = 0;  |
448 |   |
449 | while (1)  |
450 | {  |
451 | T* p = HeadItem;  |
452 | HeadItem = nullptr;  |
453 | TailItem = nullptr;  |
454 |   |
455 | // Num merges in this loop.  |
456 | int numMerges = 0;   |
457 |   |
458 | while (p)  |
459 | {  |
460 | numMerges++;  |
461 | T* q = p;  |
462 | int numPNodes = 0;  |
463 | for (int i = 0; i < numNodesPerList; i++)  |
464 | {  |
465 | numPNodes++;  |
466 | q = q->Next();  |
467 | if (!q)  |
468 | break;  |
469 | }  |
470 |   |
471 | int numQNodes = numNodesPerList;  |
472 |   |
473 | // Merge the two lists.  |
474 | while (numPNodes > 0 || (numQNodes > 0 && q))  |
475 | {  |
476 | // Decide whether next tBaseLink of merge comes from p or q.  |
477 | T* e;  |
478 |   |
479 | if (numPNodes == 0)  |
480 | {  |
481 | // p is empty; e must come from q.  |
482 | e = q;  |
483 | q = q->Next();  |
484 |   |
485 | numQNodes--;  |
486 | }  |
487 | else if (numQNodes == 0 || !q)  |
488 | {  |
489 | // q is empty; e must come from p.  |
490 | e = p;  |
491 | p = p->Next();  |
492 |   |
493 | numPNodes--;  |
494 | }  |
495 | else if (++numCompares && !compare(*q, *p))  |
496 | {  |
497 | // p is lower so e must come from p.  |
498 | e = p;  |
499 | p = p->Next();  |
500 |   |
501 | numPNodes--;  |
502 | }  |
503 | else  |
504 | {  |
505 | // First gBaseNode of q is bigger or equal; e must come from q.  |
506 | e = q;  |
507 | q = q->Next();  |
508 |   |
509 | numQNodes--;  |
510 | }  |
511 |   |
512 | // add the next gBaseNode to the merged list.  |
513 | if (TailItem)  |
514 | TailItem->NextItem = e;  |
515 | else  |
516 | HeadItem = e;  |
517 |   |
518 | e->PrevItem = TailItem;  |
519 | TailItem = e;  |
520 | }  |
521 |   |
522 | // P and Q have moved numNodesPerList places along.  |
523 | p = q;  |
524 | }  |
525 | TailItem->NextItem = nullptr;  |
526 |   |
527 | // If we have done only one merge, we're all sorted.  |
528 | if (numMerges <= 1)  |
529 | return numCompares;  |
530 |   |
531 | // Otherwise repeat, merging lists twice the size.  |
532 | numNodesPerList *= 2;  |
533 | }  |
534 |   |
535 | return numCompares;  |
536 | }  |
537 |   |
538 |   |
539 | template<typename T> template<typename CompareFunc> inline int tList<T>::SortBubble(CompareFunc compare)  |
540 | {  |
541 | // Performs a full bubble sort.  |
542 | int numCompares = 0;  |
543 | for (int maxCompares = ItemCount - 1; maxCompares >= 1; maxCompares--)  |
544 | {  |
545 | int numSwaps = BubbleForward(compare, maxCompares);  |
546 | numCompares += maxCompares;  |
547 |   |
548 | // Early exit detection. If any bubble pass resulted in no swaps, we're done!  |
549 | if (!numSwaps)  |
550 | return numCompares;  |
551 | }  |
552 |   |
553 | return numCompares;  |
554 | }  |
555 |   |
556 |   |
557 | template<typename T> template<typename CompareFunc> inline int tList<T>::BubbleForward(CompareFunc compare, int maxCompares)  |
558 | {  |
559 | // @todo Can -1 ever happen?  |
560 | if (maxCompares == -1)  |
561 | maxCompares = ItemCount-1;  |
562 | else if (maxCompares > ItemCount-1)  |
563 | maxCompares = ItemCount-1;  |
564 |   |
565 | // If there are no items, only a single item, or no compares are requested, we're done.  |
566 | if ((ItemCount < 2) || (maxCompares == 0))  |
567 | return 0;  |
568 |   |
569 | T* a = HeadItem;  |
570 | int numSwaps = 0;  |
571 | int numCompares = 0;  |
572 |   |
573 | while ((a != TailItem) && (numCompares < maxCompares))  |
574 | {  |
575 | T* b = a->NextItem;  |
576 |   |
577 | // We're sorting from lowest to biggest, so if b < a we need to swap them.  |
578 | if (compare(*b, *a))  |
579 | {  |
580 | // Swap.  |
581 | if (a->PrevItem)  |
582 | a->PrevItem->NextItem = b;  |
583 |   |
584 | if (b->NextItem)  |
585 | b->NextItem->PrevItem = a;  |
586 |   |
587 | a->NextItem = b->NextItem;  |
588 | b->PrevItem = a->PrevItem;  |
589 |   |
590 | a->PrevItem = b;  |
591 | b->NextItem = a;  |
592 |   |
593 | // Fix head and tail if they were involved in the swap.  |
594 | if (HeadItem == a)  |
595 | HeadItem = b;  |
596 |   |
597 | if (TailItem == b)  |
598 | TailItem = a;  |
599 |   |
600 | // Since we swapped, a is now correctly ready for the next loop.  |
601 | numSwaps++;  |
602 | }  |
603 | else  |
604 | {  |
605 | a = a->NextItem;  |
606 | }  |
607 | numCompares++;  |
608 | }  |
609 |   |
610 | return numSwaps;  |
611 | }  |
612 |   |
613 |   |
614 | template<typename T> template<typename CompareFunc> inline int tList<T>::BubbleBackward(CompareFunc compare, int maxCompares)  |
615 | {  |
616 | if (maxCompares == -1)  |
617 | maxCompares = ItemCount-1;  |
618 | else if (maxCompares > ItemCount-1)  |
619 | maxCompares = ItemCount-1;  |
620 |   |
621 | // If there are no items, or only a single one, we're done.  |
622 | if ((ItemCount < 2) || (maxCompares == 0))  |
623 | return 0;  |
624 |   |
625 | T* a = TailItem;  |
626 | int numSwaps = 0;  |
627 | int numCompares = 0;  |
628 |   |
629 | while ((a != HeadItem) && (numCompares < maxCompares))  |
630 | {  |
631 | T* b = a->PrevItem;  |
632 |   |
633 | // We're sorting from lowest to biggest, so if a < b we need to swap them.  |
634 | if (compare(*a, *b))  |
635 | {  |
636 | // Swap.  |
637 | if (a->NextItem)  |
638 | a->NextItem->PrevItem = b;  |
639 |   |
640 | if (b->PrevItem)  |
641 | b->PrevItem->NextItem = a;  |
642 |   |
643 | a->PrevItem = b->PrevItem;  |
644 | b->NextItem = a->NextItem;  |
645 |   |
646 | a->NextItem = b;  |
647 | b->PrevItem = a;  |
648 |   |
649 | // Fix head and tail if they were involved in the swap.  |
650 | if (HeadItem == b)  |
651 | HeadItem = a;  |
652 |   |
653 | if (TailItem == a)  |
654 | TailItem = b;  |
655 |   |
656 | // Since we swapped, a is now correctly ready for the next loop.  |
657 | numSwaps++;  |
658 | }  |
659 | else  |
660 | {  |
661 | a = a->PrevItem;  |
662 | }  |
663 | numCompares++;  |
664 | }  |
665 |   |
666 | return numSwaps;  |
667 | }  |
668 |   |
669 |   |
670 | template<typename T> inline T* tItList<T>::Remove(Iter& iter)  |
671 | {  |
672 | // It is perfectly valid to try to remove an object referenced by an invalid iterator.  |
673 | if (!iter.IsValid() || (this != iter.List))  |
674 | return nullptr;  |
675 |   |
676 | IterNode* node = Nodes.Remove(iter.Node);  |
677 | T* obj = (T*)node->Object;  |
678 |   |
679 | delete node;  |
680 | iter.Node = 0;  |
681 |   |
682 | return obj;  |
683 | }  |
684 | |