1 /* 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 8 #ifndef SkTInternalLList_DEFINED 9 #define SkTInternalLList_DEFINED 10 11 #include "../private/SkNoncopyable.h" 12 #include "SkTypes.h" 13 14 /** 15 * Helper class to automatically initialize the doubly linked list created pointers. 16 */ 17 template <typename T> class SkPtrWrapper { 18 public: SkPtrWrapper()19 SkPtrWrapper() : fPtr(nullptr) {} 20 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 /** 29 * 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. 31 */ 32 #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 38 39 /** 40 * This class implements a templated internal doubly linked list data structure. 41 */ 42 template <class T> class SkTInternalLList : SkNoncopyable { 43 public: SkTInternalLList()44 SkTInternalLList() 45 : fHead(nullptr) 46 , fTail(nullptr) { 47 } 48 reset()49 void reset() { 50 fHead = nullptr; 51 fTail = nullptr; 52 } 53 remove(T * entry)54 void remove(T* entry) { 55 SkASSERT(fHead && fTail); 56 SkASSERT(this->isInList(entry)); 57 58 T* prev = entry->fPrev; 59 T* next = entry->fNext; 60 61 if (prev) { 62 prev->fNext = next; 63 } else { 64 fHead = next; 65 } 66 if (next) { 67 next->fPrev = prev; 68 } else { 69 fTail = prev; 70 } 71 72 entry->fPrev = nullptr; 73 entry->fNext = nullptr; 74 75 #ifdef SK_DEBUG 76 entry->fList = nullptr; 77 #endif 78 } 79 addToHead(T * entry)80 void addToHead(T* entry) { 81 SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext); 82 SkASSERT(nullptr == entry->fList); 83 84 entry->fPrev = nullptr; 85 entry->fNext = fHead; 86 if (fHead) { 87 fHead->fPrev = entry; 88 } 89 fHead = entry; 90 if (nullptr == fTail) { 91 fTail = entry; 92 } 93 94 #ifdef SK_DEBUG 95 entry->fList = this; 96 #endif 97 } 98 addToTail(T * entry)99 void addToTail(T* entry) { 100 SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext); 101 SkASSERT(nullptr == entry->fList); 102 103 entry->fPrev = fTail; 104 entry->fNext = nullptr; 105 if (fTail) { 106 fTail->fNext = entry; 107 } 108 fTail = entry; 109 if (nullptr == fHead) { 110 fHead = entry; 111 } 112 113 #ifdef SK_DEBUG 114 entry->fList = this; 115 #endif 116 } 117 118 /** 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 */ addBefore(T * newEntry,T * existingEntry)123 void addBefore(T* newEntry, T* existingEntry) { 124 SkASSERT(newEntry); 125 126 if (nullptr == existingEntry) { 127 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; 136 if (nullptr == prev) { 137 SkASSERT(fHead == existingEntry); 138 fHead = newEntry; 139 } else { 140 prev->fNext = newEntry; 141 } 142 #ifdef SK_DEBUG 143 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 */ addAfter(T * newEntry,T * existingEntry)152 void addAfter(T* newEntry, T* existingEntry) { 153 SkASSERT(newEntry); 154 155 if (nullptr == existingEntry) { 156 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; 165 if (nullptr == next) { 166 SkASSERT(fTail == existingEntry); 167 fTail = newEntry; 168 } else { 169 next->fPrev = newEntry; 170 } 171 #ifdef SK_DEBUG 172 newEntry->fList = this; 173 #endif 174 } 175 concat(SkTInternalLList && list)176 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 isEmpty()201 bool isEmpty() const { 202 SkASSERT(SkToBool(fHead) == SkToBool(fTail)); 203 return !fHead; 204 } 205 head()206 T* head() { return fHead; } tail()207 T* tail() { return fTail; } 208 209 class Iter { 210 public: 211 enum IterStart { 212 kHead_IterStart, 213 kTail_IterStart 214 }; 215 Iter()216 Iter() : fCurr(nullptr) {} Iter(const Iter & iter)217 Iter(const Iter& iter) : fCurr(iter.fCurr) {} 218 Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; } 219 init(const SkTInternalLList & list,IterStart startLoc)220 T* init(const SkTInternalLList& list, IterStart startLoc) { 221 if (kHead_IterStart == startLoc) { 222 fCurr = list.fHead; 223 } else { 224 SkASSERT(kTail_IterStart == startLoc); 225 fCurr = list.fTail; 226 } 227 228 return fCurr; 229 } 230 get()231 T* get() { return fCurr; } 232 233 /** 234 * Return the next/previous element in the list or NULL if at the end. 235 */ next()236 T* next() { 237 if (nullptr == fCurr) { 238 return nullptr; 239 } 240 241 fCurr = fCurr->fNext; 242 return fCurr; 243 } 244 prev()245 T* prev() { 246 if (nullptr == fCurr) { 247 return nullptr; 248 } 249 250 fCurr = fCurr->fPrev; 251 return fCurr; 252 } 253 254 /** 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 261 private: 262 T* fCurr; 263 }; 264 begin()265 Iter begin() const { 266 Iter iter; 267 iter.init(*this, Iter::kHead_IterStart); 268 return iter; 269 } 270 end()271 Iter end() const { return Iter(); } 272 273 #ifdef SK_DEBUG validate()274 void validate() const { 275 SkASSERT(!fHead == !fTail); 276 Iter iter; 277 for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) { 278 SkASSERT(this->isInList(item)); 279 if (nullptr == item->fPrev) { 280 SkASSERT(fHead == item); 281 } else { 282 SkASSERT(item->fPrev->fNext == item); 283 } 284 if (nullptr == item->fNext) { 285 SkASSERT(fTail == item); 286 } else { 287 SkASSERT(item->fNext->fPrev == item); 288 } 289 } 290 } 291 292 /** 293 * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this' 294 * list. 295 */ isInList(const T * entry)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 */ countEntries()303 int countEntries() const { 304 int count = 0; 305 for (T* entry = fHead; entry; entry = entry->fNext) { 306 ++count; 307 } 308 return count; 309 } 310 #endif // SK_DEBUG 311 312 private: 313 T* fHead; 314 T* fTail; 315 316 typedef SkNoncopyable INHERITED; 317 }; 318 319 #endif 320