1#ifndef SEAD_TLIST_H_
2#define SEAD_TLIST_H_
3
4#include <container/seadListImpl.h>
5
6namespace sead
7{
8template <typename T>
9class TListNode;
10
11template <typename T>
12class TList : public ListImpl
13{
14public:
15 using CompareCallback = int (*)(const T*, const T*);
16
17 TList() : ListImpl() {}
18
19 void pushBack(TListNode<T>* item)
20 {
21 item->erase();
22 item->mList = this;
23 ListImpl::pushBack(item);
24 }
25
26 void pushFront(TListNode<T>* item)
27 {
28 item->erase();
29 item->mList = this;
30 ListImpl::pushFront(item);
31 }
32
33 TListNode<T>* popBack() { return static_cast<TListNode<T>*>(ListImpl::popBack()); }
34 TListNode<T>* popFront() { return static_cast<TListNode<T>*>(ListImpl::popFront()); }
35
36 void insertBefore(TListNode<T>* node, TListNode<T>* node_to_insert)
37 {
38 node_to_insert->erase();
39 node_to_insert->mList = this;
40 ListImpl::insertBefore(node, node_to_insert);
41 }
42
43 void insertAfter(TListNode<T>* node, TListNode<T>* node_to_insert)
44 {
45 node_to_insert->erase();
46 node_to_insert->mList = this;
47 ListImpl::insertAfter(node, node_to_insert);
48 }
49
50 void erase(TListNode<T>* item)
51 {
52 if (!item->mList)
53 return;
54 item->mList = nullptr;
55 ListImpl::erase(item);
56 }
57
58 TListNode<T>* front() const { return static_cast<TListNode<T>*>(ListImpl::front()); }
59 TListNode<T>* back() const { return static_cast<TListNode<T>*>(ListImpl::back()); }
60 TListNode<T>* nth(int n) const { return static_cast<TListNode<T>*>(ListImpl::nth(n)); }
61 s32 indexOf(const TListNode<T>* node) const { return ListImpl::indexOf(node); }
62
63 void swap(TListNode<T>* n1, TListNode<T>* n2) { ListImpl::swap(n1, n2); }
64 void moveAfter(TListNode<T>* basis, TListNode<T>* n) { ListImpl::moveAfter(basis, n); }
65 void moveBefore(TListNode<T>* basis, TListNode<T>* n) { ListImpl::moveBefore(basis, n); }
66
67 void sort(s32 offset, CompareCallback cmp) { ListImpl::sort<T>(offset, cmp); }
68 void mergeSort(s32 offset, CompareCallback cmp) { ListImpl::mergeSort<T>(offset, cmp); }
69
70 TListNode<T>* find(const void* ptr, s32 offset, CompareCallback cmp) const
71 {
72 return static_cast<TListNode<T>*>(ListImpl::find(ptr, offset, cmp));
73 }
74 void uniq(s32 offset, CompareCallback cmp) { ListImpl::uniq(offset, cmp); }
75 void clear() { ListImpl::clear(); }
76
77 TListNode<T>* prev(const TListNode<T>* node) const
78 {
79 auto prev_node = static_cast<TListNode<T>*>(node->prev());
80 if (prev_node == &mStartEnd)
81 return nullptr;
82 return prev_node;
83 }
84
85 TListNode<T>* next(const TListNode<T>* node) const
86 {
87 auto next_node = static_cast<TListNode<T>*>(node->next());
88 if (next_node == &mStartEnd)
89 return nullptr;
90 return next_node;
91 }
92
93 class iterator
94 {
95 public:
96 iterator(TListNode<T>* ptr) : mPtr(ptr) {}
97
98 iterator& operator++()
99 {
100 mPtr = static_cast<TListNode<T>*>(mPtr->next());
101 return *this;
102 }
103
104 iterator& operator--()
105 {
106 mPtr = static_cast<TListNode<T>*>(mPtr->prev());
107 return *this;
108 }
109
110 T& operator*() const { return mPtr->mData; }
111 T* operator->() const { return &mPtr->mData; }
112
113 friend bool operator==(iterator it1, iterator it2) { return it1.mPtr == it2.mPtr; }
114 friend bool operator!=(iterator it1, iterator it2) { return !(it1 == it2); }
115
116 private:
117 TListNode<T>* mPtr;
118 };
119
120 iterator begin() const { return iterator(static_cast<TListNode<T>*>(mStartEnd.next())); }
121
122 iterator end() const
123 {
124 return iterator(static_cast<TListNode<T>*>(const_cast<ListNode*>(&mStartEnd)));
125 }
126
127 /// An iterator that is safe to use even if the list is mutated during iteration.
128 /// Unlike the regular iterator class, this exposes ListNode<T> rather than T
129 /// to make it easier to modify the list.
130 class robustIterator
131 {
132 public:
133 explicit robustIterator(TListNode<T>* ptr) : mPtr(ptr)
134 {
135 mPtrNext = static_cast<TListNode<T>*>(mPtr->next());
136 }
137
138 robustIterator& operator++()
139 {
140 mPtr = mPtrNext;
141 mPtrNext = static_cast<TListNode<T>*>(mPtrNext->next());
142 return *this;
143 }
144
145 robustIterator operator++(int)
146 {
147 robustIterator copy = *this;
148 mPtr = mPtrNext;
149 mPtrNext = static_cast<TListNode<T>*>(mPtr->next());
150 return copy;
151 }
152
153 TListNode<T>& operator*() const { return *mPtr; }
154 TListNode<T>* operator->() const { return mPtr; }
155
156 friend bool operator==(robustIterator it1, robustIterator it2)
157 {
158 return it1.mPtr == it2.mPtr;
159 }
160 friend bool operator!=(robustIterator it1, robustIterator it2) { return !(it1 == it2); }
161
162 private:
163 TListNode<T>* mPtr;
164 TListNode<T>* mPtrNext;
165 };
166
167 robustIterator robustBegin() const
168 {
169 return robustIterator(static_cast<TListNode<T>*>(mStartEnd.next()));
170 }
171
172 robustIterator robustEnd() const
173 {
174 return robustIterator(static_cast<TListNode<T>*>(const_cast<ListNode*>(&mStartEnd)));
175 }
176
177 struct RobustRange
178 {
179 auto begin() const { return mList.robustBegin(); }
180 auto end() const { return mList.robustEnd(); }
181 const TList& mList;
182 };
183 RobustRange robustRange() const { return {*this}; }
184
185private:
186 static int compareT(const T* a, const T* b)
187 {
188 if (*a < *b)
189 return -1;
190 if (*a > *b)
191 return 1;
192 return 0;
193 }
194};
195
196template <typename T>
197class TListNode : public ListNode
198{
199public:
200 TListNode() : ListNode()
201 {
202 mData = nullptr;
203 mList = NULL;
204 }
205
206 TListNode(T data) : ListNode(), mData(data), mList(nullptr) {}
207
208 void erase()
209 {
210 TList<T>* list = mList;
211 if (list != NULL)
212 list->erase(this);
213 }
214
215 T mData;
216 TList<T>* mList;
217};
218
219} // namespace sead
220
221#endif // SEAD_TLIST_H_
222