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 "SkTypes.h" 12 13 /** 14 * Helper class to automatically initialize the doubly linked list created pointers. 15 */ 16 template <typename T> class SkPtrWrapper { 17 public: SkPtrWrapper()18 SkPtrWrapper() : fPtr(nullptr) {} 19 SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; } 20 operator T*() const { return fPtr; } 21 T* operator->() { return fPtr; } 22 private: 23 T* fPtr; 24 }; 25 26 27 /** 28 * This macro creates the member variables required by the SkTInternalLList class. It should be 29 * placed in the private section of any class that will be stored in a double linked list. 30 */ 31 #define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \ 32 friend class SkTInternalLList<ClassName>; \ 33 /* back pointer to the owning list - for debugging */ \ 34 SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;) \ 35 SkPtrWrapper<ClassName> fPrev; \ 36 SkPtrWrapper<ClassName> fNext 37 38 /** 39 * This class implements a templated internal doubly linked list data structure. 40 */ 41 template <class T> class SkTInternalLList : SkNoncopyable { 42 public: SkTInternalLList()43 SkTInternalLList() 44 : fHead(nullptr) 45 , fTail(nullptr) { 46 } 47 reset()48 void reset() { 49 fHead = nullptr; 50 fTail = nullptr; 51 } 52 remove(T * entry)53 void remove(T* entry) { 54 SkASSERT(fHead && fTail); 55 SkASSERT(this->isInList(entry)); 56 57 T* prev = entry->fPrev; 58 T* next = entry->fNext; 59 60 if (prev) { 61 prev->fNext = next; 62 } else { 63 fHead = next; 64 } 65 if (next) { 66 next->fPrev = prev; 67 } else { 68 fTail = prev; 69 } 70 71 entry->fPrev = nullptr; 72 entry->fNext = nullptr; 73 74 #ifdef SK_DEBUG 75 entry->fList = nullptr; 76 #endif 77 } 78 addToHead(T * entry)79 void addToHead(T* entry) { 80 SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext); 81 SkASSERT(nullptr == entry->fList); 82 83 entry->fPrev = nullptr; 84 entry->fNext = fHead; 85 if (fHead) { 86 fHead->fPrev = entry; 87 } 88 fHead = entry; 89 if (nullptr == fTail) { 90 fTail = entry; 91 } 92 93 #ifdef SK_DEBUG 94 entry->fList = this; 95 #endif 96 } 97 addToTail(T * entry)98 void addToTail(T* entry) { 99 SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext); 100 SkASSERT(nullptr == entry->fList); 101 102 entry->fPrev = fTail; 103 entry->fNext = nullptr; 104 if (fTail) { 105 fTail->fNext = entry; 106 } 107 fTail = entry; 108 if (nullptr == fHead) { 109 fHead = entry; 110 } 111 112 #ifdef SK_DEBUG 113 entry->fList = this; 114 #endif 115 } 116 117 /** 118 * Inserts a new list entry before an existing list entry. The new entry must not already be 119 * a member of this or any other list. If existingEntry is NULL then the new entry is added 120 * at the tail. 121 */ addBefore(T * newEntry,T * existingEntry)122 void addBefore(T* newEntry, T* existingEntry) { 123 SkASSERT(newEntry); 124 125 if (nullptr == existingEntry) { 126 this->addToTail(newEntry); 127 return; 128 } 129 130 SkASSERT(this->isInList(existingEntry)); 131 newEntry->fNext = existingEntry; 132 T* prev = existingEntry->fPrev; 133 existingEntry->fPrev = newEntry; 134 newEntry->fPrev = prev; 135 if (nullptr == prev) { 136 SkASSERT(fHead == existingEntry); 137 fHead = newEntry; 138 } else { 139 prev->fNext = newEntry; 140 } 141 #ifdef SK_DEBUG 142 newEntry->fList = this; 143 #endif 144 } 145 146 /** 147 * Inserts a new list entry after an existing list entry. The new entry must not already be 148 * a member of this or any other list. If existingEntry is NULL then the new entry is added 149 * at the head. 150 */ addAfter(T * newEntry,T * existingEntry)151 void addAfter(T* newEntry, T* existingEntry) { 152 SkASSERT(newEntry); 153 154 if (nullptr == existingEntry) { 155 this->addToHead(newEntry); 156 return; 157 } 158 159 SkASSERT(this->isInList(existingEntry)); 160 newEntry->fPrev = existingEntry; 161 T* next = existingEntry->fNext; 162 existingEntry->fNext = newEntry; 163 newEntry->fNext = next; 164 if (nullptr == next) { 165 SkASSERT(fTail == existingEntry); 166 fTail = newEntry; 167 } else { 168 next->fPrev = newEntry; 169 } 170 #ifdef SK_DEBUG 171 newEntry->fList = this; 172 #endif 173 } 174 concat(SkTInternalLList && list)175 void concat(SkTInternalLList&& list) { 176 if (list.isEmpty()) { 177 return; 178 } 179 180 list.fHead->fPrev = fTail; 181 if (!fHead) { 182 SkASSERT(!list.fHead->fPrev); 183 fHead = list.fHead; 184 } else { 185 SkASSERT(fTail); 186 fTail->fNext = list.fHead; 187 } 188 fTail = list.fTail; 189 190 #ifdef SK_DEBUG 191 for (T* node = list.fHead; node; node = node->fNext) { 192 SkASSERT(node->fList == &list); 193 node->fList = this; 194 } 195 #endif 196 197 list.fHead = list.fTail = nullptr; 198 } 199 isEmpty()200 bool isEmpty() const { 201 SkASSERT(SkToBool(fHead) == SkToBool(fTail)); 202 return !fHead; 203 } 204 head()205 T* head() { return fHead; } tail()206 T* tail() { return fTail; } 207 208 class Iter { 209 public: 210 enum IterStart { 211 kHead_IterStart, 212 kTail_IterStart 213 }; 214 Iter()215 Iter() : fCurr(nullptr) {} Iter(const Iter & iter)216 Iter(const Iter& iter) : fCurr(iter.fCurr) {} 217 Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; } 218 init(const SkTInternalLList & list,IterStart startLoc)219 T* init(const SkTInternalLList& list, IterStart startLoc) { 220 if (kHead_IterStart == startLoc) { 221 fCurr = list.fHead; 222 } else { 223 SkASSERT(kTail_IterStart == startLoc); 224 fCurr = list.fTail; 225 } 226 227 return fCurr; 228 } 229 get()230 T* get() { return fCurr; } 231 232 /** 233 * Return the next/previous element in the list or NULL if at the end. 234 */ next()235 T* next() { 236 if (nullptr == fCurr) { 237 return nullptr; 238 } 239 240 fCurr = fCurr->fNext; 241 return fCurr; 242 } 243 prev()244 T* prev() { 245 if (nullptr == fCurr) { 246 return nullptr; 247 } 248 249 fCurr = fCurr->fPrev; 250 return fCurr; 251 } 252 253 private: 254 T* fCurr; 255 }; 256 257 #ifdef SK_DEBUG validate()258 void validate() const { 259 SkASSERT(!fHead == !fTail); 260 Iter iter; 261 for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) { 262 SkASSERT(this->isInList(item)); 263 if (nullptr == item->fPrev) { 264 SkASSERT(fHead == item); 265 } else { 266 SkASSERT(item->fPrev->fNext == item); 267 } 268 if (nullptr == item->fNext) { 269 SkASSERT(fTail == item); 270 } else { 271 SkASSERT(item->fNext->fPrev == item); 272 } 273 } 274 } 275 276 /** 277 * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this' 278 * list. 279 */ isInList(const T * entry)280 bool isInList(const T* entry) const { 281 return entry->fList == this; 282 } 283 284 /** 285 * Debugging-only method that laboriously counts the list entries. 286 */ countEntries()287 int countEntries() const { 288 int count = 0; 289 for (T* entry = fHead; entry; entry = entry->fNext) { 290 ++count; 291 } 292 return count; 293 } 294 #endif // SK_DEBUG 295 296 private: 297 T* fHead; 298 T* fTail; 299 300 typedef SkNoncopyable INHERITED; 301 }; 302 303 #endif 304