| OLD | NEW |
| (Empty) |
| 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 point
ers. | |
| 15 */ | |
| 16 template <typename T> class SkPtrWrapper { | |
| 17 public: | |
| 18 SkPtrWrapper() : fPtr(NULL) {} | |
| 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 clas
s. It should be | |
| 29 * placed in the private section of any class that will be stored in a double li
nked 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: | |
| 43 SkTInternalLList() | |
| 44 : fHead(NULL) | |
| 45 , fTail(NULL) { | |
| 46 } | |
| 47 | |
| 48 void remove(T* entry) { | |
| 49 SkASSERT(fHead && fTail); | |
| 50 SkASSERT(this->isInList(entry)); | |
| 51 | |
| 52 T* prev = entry->fPrev; | |
| 53 T* next = entry->fNext; | |
| 54 | |
| 55 if (prev) { | |
| 56 prev->fNext = next; | |
| 57 } else { | |
| 58 fHead = next; | |
| 59 } | |
| 60 if (next) { | |
| 61 next->fPrev = prev; | |
| 62 } else { | |
| 63 fTail = prev; | |
| 64 } | |
| 65 | |
| 66 entry->fPrev = NULL; | |
| 67 entry->fNext = NULL; | |
| 68 | |
| 69 #ifdef SK_DEBUG | |
| 70 entry->fList = NULL; | |
| 71 #endif | |
| 72 } | |
| 73 | |
| 74 void addToHead(T* entry) { | |
| 75 SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); | |
| 76 SkASSERT(NULL == entry->fList); | |
| 77 | |
| 78 entry->fPrev = NULL; | |
| 79 entry->fNext = fHead; | |
| 80 if (fHead) { | |
| 81 fHead->fPrev = entry; | |
| 82 } | |
| 83 fHead = entry; | |
| 84 if (NULL == fTail) { | |
| 85 fTail = entry; | |
| 86 } | |
| 87 | |
| 88 #ifdef SK_DEBUG | |
| 89 entry->fList = this; | |
| 90 #endif | |
| 91 } | |
| 92 | |
| 93 void addToTail(T* entry) { | |
| 94 SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); | |
| 95 SkASSERT(NULL == entry->fList); | |
| 96 | |
| 97 entry->fPrev = fTail; | |
| 98 entry->fNext = NULL; | |
| 99 if (fTail) { | |
| 100 fTail->fNext = entry; | |
| 101 } | |
| 102 fTail = entry; | |
| 103 if (NULL == fHead) { | |
| 104 fHead = entry; | |
| 105 } | |
| 106 | |
| 107 #ifdef SK_DEBUG | |
| 108 entry->fList = this; | |
| 109 #endif | |
| 110 } | |
| 111 | |
| 112 /** | |
| 113 * Inserts a new list entry before an existing list entry. The new entry mus
t not already be | |
| 114 * a member of this or any other list. If existingEntry is NULL then the new
entry is added | |
| 115 * at the tail. | |
| 116 */ | |
| 117 void addBefore(T* newEntry, T* existingEntry) { | |
| 118 SkASSERT(newEntry); | |
| 119 | |
| 120 if (NULL == existingEntry) { | |
| 121 this->addToTail(newEntry); | |
| 122 return; | |
| 123 } | |
| 124 | |
| 125 SkASSERT(this->isInList(existingEntry)); | |
| 126 newEntry->fNext = existingEntry; | |
| 127 T* prev = existingEntry->fPrev; | |
| 128 existingEntry->fPrev = newEntry; | |
| 129 newEntry->fPrev = prev; | |
| 130 if (NULL == prev) { | |
| 131 SkASSERT(fHead == existingEntry); | |
| 132 fHead = newEntry; | |
| 133 } else { | |
| 134 prev->fNext = newEntry; | |
| 135 } | |
| 136 #ifdef SK_DEBUG | |
| 137 newEntry->fList = this; | |
| 138 #endif | |
| 139 } | |
| 140 | |
| 141 /** | |
| 142 * Inserts a new list entry after an existing list entry. The new entry must
not already be | |
| 143 * a member of this or any other list. If existingEntry is NULL then the new
entry is added | |
| 144 * at the head. | |
| 145 */ | |
| 146 void addAfter(T* newEntry, T* existingEntry) { | |
| 147 SkASSERT(newEntry); | |
| 148 | |
| 149 if (NULL == existingEntry) { | |
| 150 this->addToHead(newEntry); | |
| 151 return; | |
| 152 } | |
| 153 | |
| 154 SkASSERT(this->isInList(existingEntry)); | |
| 155 newEntry->fPrev = existingEntry; | |
| 156 T* next = existingEntry->fNext; | |
| 157 existingEntry->fNext = newEntry; | |
| 158 newEntry->fNext = next; | |
| 159 if (NULL == next) { | |
| 160 SkASSERT(fTail == existingEntry); | |
| 161 fTail = newEntry; | |
| 162 } else { | |
| 163 next->fPrev = newEntry; | |
| 164 } | |
| 165 #ifdef SK_DEBUG | |
| 166 newEntry->fList = this; | |
| 167 #endif | |
| 168 } | |
| 169 | |
| 170 bool isEmpty() const { | |
| 171 return NULL == fHead && NULL == fTail; | |
| 172 } | |
| 173 | |
| 174 T* head() { return fHead; } | |
| 175 T* tail() { return fTail; } | |
| 176 | |
| 177 class Iter { | |
| 178 public: | |
| 179 enum IterStart { | |
| 180 kHead_IterStart, | |
| 181 kTail_IterStart | |
| 182 }; | |
| 183 | |
| 184 Iter() : fCurr(NULL) {} | |
| 185 Iter(const Iter& iter) : fCurr(iter.fCurr) {} | |
| 186 Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; } | |
| 187 | |
| 188 T* init(const SkTInternalLList& list, IterStart startLoc) { | |
| 189 if (kHead_IterStart == startLoc) { | |
| 190 fCurr = list.fHead; | |
| 191 } else { | |
| 192 SkASSERT(kTail_IterStart == startLoc); | |
| 193 fCurr = list.fTail; | |
| 194 } | |
| 195 | |
| 196 return fCurr; | |
| 197 } | |
| 198 | |
| 199 T* get() { return fCurr; } | |
| 200 | |
| 201 /** | |
| 202 * Return the next/previous element in the list or NULL if at the end. | |
| 203 */ | |
| 204 T* next() { | |
| 205 if (NULL == fCurr) { | |
| 206 return NULL; | |
| 207 } | |
| 208 | |
| 209 fCurr = fCurr->fNext; | |
| 210 return fCurr; | |
| 211 } | |
| 212 | |
| 213 T* prev() { | |
| 214 if (NULL == fCurr) { | |
| 215 return NULL; | |
| 216 } | |
| 217 | |
| 218 fCurr = fCurr->fPrev; | |
| 219 return fCurr; | |
| 220 } | |
| 221 | |
| 222 private: | |
| 223 T* fCurr; | |
| 224 }; | |
| 225 | |
| 226 #ifdef SK_DEBUG | |
| 227 void validate() const { | |
| 228 SkASSERT(!fHead == !fTail); | |
| 229 Iter iter; | |
| 230 for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = ite
r.next()) { | |
| 231 SkASSERT(this->isInList(item)); | |
| 232 if (NULL == item->fPrev) { | |
| 233 SkASSERT(fHead == item); | |
| 234 } else { | |
| 235 SkASSERT(item->fPrev->fNext == item); | |
| 236 } | |
| 237 if (NULL == item->fNext) { | |
| 238 SkASSERT(fTail == item); | |
| 239 } else { | |
| 240 SkASSERT(item->fNext->fPrev == item); | |
| 241 } | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 /** | |
| 246 * Debugging-only method that uses the list back pointer to check if 'entry'
is indeed in 'this' | |
| 247 * list. | |
| 248 */ | |
| 249 bool isInList(const T* entry) const { | |
| 250 return entry->fList == this; | |
| 251 } | |
| 252 | |
| 253 /** | |
| 254 * Debugging-only method that laboriously counts the list entries. | |
| 255 */ | |
| 256 int countEntries() const { | |
| 257 int count = 0; | |
| 258 for (T* entry = fHead; entry; entry = entry->fNext) { | |
| 259 ++count; | |
| 260 } | |
| 261 return count; | |
| 262 } | |
| 263 #endif // SK_DEBUG | |
| 264 | |
| 265 private: | |
| 266 T* fHead; | |
| 267 T* fTail; | |
| 268 | |
| 269 typedef SkNoncopyable INHERITED; | |
| 270 }; | |
| 271 | |
| 272 #endif | |
| OLD | NEW |