blob: 547befe6943e8b6034dc81bced8d2d1d24c047bb [file] [log] [blame]
robertphillips@google.com2ea0a232012-08-23 11:13:48 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
bsalomon@google.com42619d82012-12-03 14:54:59 +00008#ifndef SkTInternalLList_DEFINED
9#define SkTInternalLList_DEFINED
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000010
Ben Wagnerd5148e32018-07-16 17:44:06 -040011#include "../private/SkNoncopyable.h"
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000012#include "SkTypes.h"
13
rmistry@google.comfbfcd562012-08-23 18:09:54 +000014/**
bsalomon@google.com42619d82012-12-03 14:54:59 +000015 * Helper class to automatically initialize the doubly linked list created pointers.
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000016 */
17template <typename T> class SkPtrWrapper {
18 public:
Ben Wagnera93a14a2017-08-28 10:34:05 -040019 SkPtrWrapper() : fPtr(nullptr) {}
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000020 SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; }
21 operator T*() const { return fPtr; }
22 T* operator->() { return fPtr; }
23 private:
24 T* fPtr;
25};
26
27
28/**
bsalomon@google.com42619d82012-12-03 14:54:59 +000029 * This macro creates the member variables required by the SkTInternalLList class. It should be
30 * placed in the private section of any class that will be stored in a double linked list.
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000031 */
bsalomon@google.com42619d82012-12-03 14:54:59 +000032#define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \
33 friend class SkTInternalLList<ClassName>; \
34 /* back pointer to the owning list - for debugging */ \
35 SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;) \
36 SkPtrWrapper<ClassName> fPrev; \
37 SkPtrWrapper<ClassName> fNext
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000038
39/**
40 * This class implements a templated internal doubly linked list data structure.
41 */
commit-bot@chromium.orge3beb6b2014-04-07 19:34:38 +000042template <class T> class SkTInternalLList : SkNoncopyable {
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000043public:
bsalomon@google.com42619d82012-12-03 14:54:59 +000044 SkTInternalLList()
Ben Wagnera93a14a2017-08-28 10:34:05 -040045 : fHead(nullptr)
46 , fTail(nullptr) {
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000047 }
48
Jim Van Verth106b5c42017-09-26 12:45:29 -040049 void reset() {
50 fHead = nullptr;
51 fTail = nullptr;
52 }
53
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000054 void remove(T* entry) {
bsalomon49f085d2014-09-05 13:34:00 -070055 SkASSERT(fHead && fTail);
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000056 SkASSERT(this->isInList(entry));
57
58 T* prev = entry->fPrev;
59 T* next = entry->fNext;
60
bsalomon49f085d2014-09-05 13:34:00 -070061 if (prev) {
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000062 prev->fNext = next;
63 } else {
64 fHead = next;
65 }
bsalomon49f085d2014-09-05 13:34:00 -070066 if (next) {
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000067 next->fPrev = prev;
68 } else {
69 fTail = prev;
70 }
71
Ben Wagnera93a14a2017-08-28 10:34:05 -040072 entry->fPrev = nullptr;
73 entry->fNext = nullptr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000074
bsalomon@google.com39ac1ae2012-08-23 13:24:31 +000075#ifdef SK_DEBUG
Ben Wagnera93a14a2017-08-28 10:34:05 -040076 entry->fList = nullptr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000077#endif
78 }
79
80 void addToHead(T* entry) {
Ben Wagnera93a14a2017-08-28 10:34:05 -040081 SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext);
82 SkASSERT(nullptr == entry->fList);
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000083
Ben Wagnera93a14a2017-08-28 10:34:05 -040084 entry->fPrev = nullptr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000085 entry->fNext = fHead;
bsalomon49f085d2014-09-05 13:34:00 -070086 if (fHead) {
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000087 fHead->fPrev = entry;
88 }
89 fHead = entry;
Ben Wagnera93a14a2017-08-28 10:34:05 -040090 if (nullptr == fTail) {
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000091 fTail = entry;
92 }
93
bsalomon@google.com39ac1ae2012-08-23 13:24:31 +000094#ifdef SK_DEBUG
robertphillips@google.com2ea0a232012-08-23 11:13:48 +000095 entry->fList = this;
96#endif
97 }
98
bsalomon@google.com42619d82012-12-03 14:54:59 +000099 void addToTail(T* entry) {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400100 SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext);
101 SkASSERT(nullptr == entry->fList);
bsalomon@google.com42619d82012-12-03 14:54:59 +0000102
103 entry->fPrev = fTail;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400104 entry->fNext = nullptr;
bsalomon49f085d2014-09-05 13:34:00 -0700105 if (fTail) {
bsalomon@google.com42619d82012-12-03 14:54:59 +0000106 fTail->fNext = entry;
107 }
108 fTail = entry;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400109 if (nullptr == fHead) {
bsalomon@google.com42619d82012-12-03 14:54:59 +0000110 fHead = entry;
111 }
112
113#ifdef SK_DEBUG
114 entry->fList = this;
115#endif
116 }
117
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000118 /**
119 * Inserts a new list entry before an existing list entry. The new entry must not already be
120 * a member of this or any other list. If existingEntry is NULL then the new entry is added
121 * at the tail.
122 */
123 void addBefore(T* newEntry, T* existingEntry) {
bsalomon49f085d2014-09-05 13:34:00 -0700124 SkASSERT(newEntry);
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000125
Ben Wagnera93a14a2017-08-28 10:34:05 -0400126 if (nullptr == existingEntry) {
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000127 this->addToTail(newEntry);
128 return;
129 }
130
131 SkASSERT(this->isInList(existingEntry));
132 newEntry->fNext = existingEntry;
133 T* prev = existingEntry->fPrev;
134 existingEntry->fPrev = newEntry;
135 newEntry->fPrev = prev;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400136 if (nullptr == prev) {
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000137 SkASSERT(fHead == existingEntry);
138 fHead = newEntry;
139 } else {
140 prev->fNext = newEntry;
141 }
robertphillips@google.comb8b8ba02012-12-03 23:34:32 +0000142#ifdef SK_DEBUG
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000143 newEntry->fList = this;
144#endif
145 }
146
147 /**
148 * Inserts a new list entry after an existing list entry. The new entry must not already be
149 * a member of this or any other list. If existingEntry is NULL then the new entry is added
150 * at the head.
151 */
152 void addAfter(T* newEntry, T* existingEntry) {
bsalomon49f085d2014-09-05 13:34:00 -0700153 SkASSERT(newEntry);
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000154
Ben Wagnera93a14a2017-08-28 10:34:05 -0400155 if (nullptr == existingEntry) {
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000156 this->addToHead(newEntry);
157 return;
158 }
159
160 SkASSERT(this->isInList(existingEntry));
161 newEntry->fPrev = existingEntry;
162 T* next = existingEntry->fNext;
163 existingEntry->fNext = newEntry;
164 newEntry->fNext = next;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400165 if (nullptr == next) {
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000166 SkASSERT(fTail == existingEntry);
167 fTail = newEntry;
168 } else {
169 next->fPrev = newEntry;
170 }
robertphillips@google.comb8b8ba02012-12-03 23:34:32 +0000171#ifdef SK_DEBUG
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000172 newEntry->fList = this;
173#endif
174 }
175
Chris Dalton832bd2b2017-06-21 12:33:39 -0700176 void concat(SkTInternalLList&& list) {
177 if (list.isEmpty()) {
178 return;
179 }
180
181 list.fHead->fPrev = fTail;
182 if (!fHead) {
183 SkASSERT(!list.fHead->fPrev);
184 fHead = list.fHead;
185 } else {
186 SkASSERT(fTail);
187 fTail->fNext = list.fHead;
188 }
189 fTail = list.fTail;
190
191#ifdef SK_DEBUG
192 for (T* node = list.fHead; node; node = node->fNext) {
193 SkASSERT(node->fList == &list);
194 node->fList = this;
195 }
196#endif
197
198 list.fHead = list.fTail = nullptr;
199 }
200
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000201 bool isEmpty() const {
Chris Dalton832bd2b2017-06-21 12:33:39 -0700202 SkASSERT(SkToBool(fHead) == SkToBool(fTail));
203 return !fHead;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000204 }
205
bsalomon@google.coma2921122012-08-28 12:34:17 +0000206 T* head() { return fHead; }
207 T* tail() { return fTail; }
208
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000209 class Iter {
210 public:
211 enum IterStart {
212 kHead_IterStart,
213 kTail_IterStart
214 };
215
Ben Wagnera93a14a2017-08-28 10:34:05 -0400216 Iter() : fCurr(nullptr) {}
bsalomon@google.com42619d82012-12-03 14:54:59 +0000217 Iter(const Iter& iter) : fCurr(iter.fCurr) {}
218 Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; }
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000219
bsalomon@google.com42619d82012-12-03 14:54:59 +0000220 T* init(const SkTInternalLList& list, IterStart startLoc) {
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000221 if (kHead_IterStart == startLoc) {
bsalomon@google.com42619d82012-12-03 14:54:59 +0000222 fCurr = list.fHead;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000223 } else {
224 SkASSERT(kTail_IterStart == startLoc);
bsalomon@google.com42619d82012-12-03 14:54:59 +0000225 fCurr = list.fTail;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000226 }
227
bsalomon@google.com42619d82012-12-03 14:54:59 +0000228 return fCurr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000229 }
230
bsalomon@google.com42619d82012-12-03 14:54:59 +0000231 T* get() { return fCurr; }
232
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000233 /**
234 * Return the next/previous element in the list or NULL if at the end.
235 */
236 T* next() {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400237 if (nullptr == fCurr) {
238 return nullptr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000239 }
240
bsalomon@google.com42619d82012-12-03 14:54:59 +0000241 fCurr = fCurr->fNext;
242 return fCurr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000243 }
244
245 T* prev() {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400246 if (nullptr == fCurr) {
247 return nullptr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000248 }
249
bsalomon@google.com42619d82012-12-03 14:54:59 +0000250 fCurr = fCurr->fPrev;
251 return fCurr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000252 }
253
Chris Daltonf112ea22018-05-09 13:10:44 -0600254 /**
255 * C++11 range-for interface.
256 */
257 bool operator!=(const Iter& that) { return fCurr != that.fCurr; }
258 T* operator*() { return this->get(); }
259 void operator++() { this->next(); }
260
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000261 private:
bsalomon@google.com42619d82012-12-03 14:54:59 +0000262 T* fCurr;
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000263 };
264
Chris Daltonf112ea22018-05-09 13:10:44 -0600265 Iter begin() const {
266 Iter iter;
267 iter.init(*this, Iter::kHead_IterStart);
268 return iter;
269 }
270
271 Iter end() const { return Iter(); }
272
bsalomon@google.com39ac1ae2012-08-23 13:24:31 +0000273#ifdef SK_DEBUG
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000274 void validate() const {
bsalomon@google.com42619d82012-12-03 14:54:59 +0000275 SkASSERT(!fHead == !fTail);
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000276 Iter iter;
bsalomon49f085d2014-09-05 13:34:00 -0700277 for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) {
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000278 SkASSERT(this->isInList(item));
Ben Wagnera93a14a2017-08-28 10:34:05 -0400279 if (nullptr == item->fPrev) {
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000280 SkASSERT(fHead == item);
281 } else {
282 SkASSERT(item->fPrev->fNext == item);
283 }
Ben Wagnera93a14a2017-08-28 10:34:05 -0400284 if (nullptr == item->fNext) {
bsalomon@google.comdd3f7a92012-12-03 19:47:41 +0000285 SkASSERT(fTail == item);
286 } else {
287 SkASSERT(item->fNext->fPrev == item);
288 }
289 }
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000290 }
291
292 /**
bsalomon@google.com42619d82012-12-03 14:54:59 +0000293 * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this'
294 * list.
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000295 */
296 bool isInList(const T* entry) const {
297 return entry->fList == this;
298 }
299
300 /**
301 * Debugging-only method that laboriously counts the list entries.
302 */
303 int countEntries() const {
304 int count = 0;
bsalomon49f085d2014-09-05 13:34:00 -0700305 for (T* entry = fHead; entry; entry = entry->fNext) {
robertphillips@google.com2ea0a232012-08-23 11:13:48 +0000306 ++count;
307 }
308 return count;
309 }
310#endif // SK_DEBUG
311
312private:
313 T* fHead;
314 T* fTail;
315
316 typedef SkNoncopyable INHERITED;
317};
318
bsalomon@google.com42619d82012-12-03 14:54:59 +0000319#endif