Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #ifndef SkTInternalLList_DEFINED | 8 #ifndef SkTInternalLList_DEFINED |
| 9 #define SkTInternalLList_DEFINED | 9 #define SkTInternalLList_DEFINED |
| 10 | 10 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 private: | 22 private: |
| 23 T* fPtr; | 23 T* fPtr; |
| 24 }; | 24 }; |
| 25 | 25 |
| 26 | 26 |
| 27 /** | 27 /** |
| 28 * This macro creates the member variables required by the SkTInternalLList clas s. It should be | 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. | 29 * placed in the private section of any class that will be stored in a double li nked list. |
| 30 */ | 30 */ |
| 31 #define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \ | 31 #define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \ |
| 32 friend class SkTInternalLList<ClassName>; \ | 32 friend class SkTInternalLListDefaultExtractor<ClassName>; \ |
|
mtklein
2013/12/03 19:02:02
I'm somewhat worried about the general design of G
| |
| 33 /* back pointer to the owning list - for debugging */ \ | 33 /* back pointer to the owning list - for debugging */ \ |
| 34 SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;) \ | 34 SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;) \ |
| 35 SkPtrWrapper<ClassName> fPrev; \ | 35 SkPtrWrapper<ClassName> fPrev; \ |
| 36 SkPtrWrapper<ClassName> fNext | 36 SkPtrWrapper<ClassName> fNext; |
| 37 | |
| 38 /** | |
| 39 * This macro creates the members for storing the instance to a specific, named linked list. It | |
| 40 * should be placed in the public section of any class that will be stored in a double linked | |
| 41 * list. Classes that use this macro need to use corresponding _DATA macro below . | |
| 42 */ | |
| 43 #define SK_DECLARE_NAMED_INTERNAL_LLIST_INTERFACE(T, Name) \ | |
| 44 struct InternalLListExtractor##Name { \ | |
| 45 typedef SkTInternalLList<T, InternalLListExtractor##Name > ListType; \ | |
| 46 static SkPtrWrapper<T>& Prev(T* o) { return o->fPrev##Name; } \ | |
| 47 static SkPtrWrapper<T>& Next(T* o) { return o->fNext##Name; } \ | |
| 48 SkDEBUGCODE(static SkPtrWrapper<ListType>& List(T* o) { return o->fList# #Name; }) \ | |
| 49 SkDEBUGCODE(static const ListType* List(const T* o) { return o->fList##N ame; }) \ | |
| 50 }; \ | |
| 51 friend class InternalLListExtractor##Name; | |
| 52 | |
| 53 /** | |
| 54 * This macro creates the member variables for storing the instance to a specifi c, named linked | |
| 55 * list. It should be placed in the private section of the class. | |
| 56 */ | |
| 57 #define SK_DECLARE_NAMED_INTERNAL_LLIST_INTERFACE_DATA(T, Name) \ | |
| 58 SkPtrWrapper<T> fPrev##Name; \ | |
| 59 SkPtrWrapper<T> fNext##Name; \ | |
| 60 SkDEBUGCODE(SkPtrWrapper<InternalLListExtractor##Name::ListType> fList##Name ;) | |
| 61 | |
| 62 /** | |
| 63 * This macro creates the member variable and short-cut typedefs for a specific, named linked list. | |
| 64 * This should be placed in the class declaration or code that creates the named linked list. | |
| 65 */ | |
| 66 #define SK_DECLARE_NAMED_INTERNAL_LLIST(T, Name, VarName) \ | |
| 67 typedef SkTInternalLList<T, T::InternalLListExtractor##Name> Name##InternalL ListType; \ | |
| 68 Name##InternalLListType VarName; | |
| 69 | |
| 70 template <class T, class E> class SkTInternalLList; | |
| 71 | |
| 72 template<typename T> | |
| 73 struct SkTInternalLListDefaultExtractor { | |
| 74 typedef SkTInternalLList<T, SkTInternalLListDefaultExtractor<T> > ListType; | |
| 75 static SkPtrWrapper<T>& Prev(T* o) { return o->fPrev; } | |
| 76 static SkPtrWrapper<T>& Next(T* o) { return o->fNext; } | |
| 77 SkDEBUGCODE(static SkPtrWrapper<ListType>& List(T* o) { return o->fList; }) | |
| 78 SkDEBUGCODE(static const ListType* List(const T* o) { return o->fList; }) | |
| 79 }; | |
| 37 | 80 |
| 38 /** | 81 /** |
| 39 * This class implements a templated internal doubly linked list data structure. | 82 * This class implements a templated internal doubly linked list data structure. |
| 40 */ | 83 */ |
| 41 template <class T> class SkTInternalLList : public SkNoncopyable { | 84 template <class T, class E = SkTInternalLListDefaultExtractor<T> > |
| 85 class SkTInternalLList : public SkNoncopyable { | |
| 42 public: | 86 public: |
| 43 SkTInternalLList() | 87 SkTInternalLList() |
| 44 : fHead(NULL) | 88 : fHead(NULL) |
| 45 , fTail(NULL) { | 89 , fTail(NULL) { |
| 46 } | 90 } |
| 47 | 91 |
| 48 void remove(T* entry) { | 92 void remove(T* entry) { |
| 49 SkASSERT(NULL != fHead && NULL != fTail); | 93 SkASSERT(NULL != fHead && NULL != fTail); |
| 50 SkASSERT(this->isInList(entry)); | 94 SkASSERT(this->isInList(entry)); |
| 51 | 95 |
| 52 T* prev = entry->fPrev; | 96 T* prev = E::Prev(entry); |
| 53 T* next = entry->fNext; | 97 T* next = E::Next(entry); |
| 54 | 98 |
| 55 if (NULL != prev) { | 99 if (NULL != prev) { |
| 56 prev->fNext = next; | 100 E::Next(prev) = next; |
| 57 } else { | 101 } else { |
| 58 fHead = next; | 102 fHead = next; |
| 59 } | 103 } |
| 60 if (NULL != next) { | 104 if (NULL != next) { |
| 61 next->fPrev = prev; | 105 E::Prev(next) = prev; |
| 62 } else { | 106 } else { |
| 63 fTail = prev; | 107 fTail = prev; |
| 64 } | 108 } |
| 65 | 109 |
| 66 entry->fPrev = NULL; | 110 E::Prev(entry) = NULL; |
| 67 entry->fNext = NULL; | 111 E::Next(entry) = NULL; |
| 68 | 112 |
| 69 #ifdef SK_DEBUG | 113 #ifdef SK_DEBUG |
| 70 entry->fList = NULL; | 114 E::List(entry) = NULL; |
| 71 #endif | 115 #endif |
| 72 } | 116 } |
| 73 | 117 |
| 74 void addToHead(T* entry) { | 118 void addToHead(T* entry) { |
| 75 SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); | 119 SkASSERT(NULL == E::Prev(entry) && NULL == E::Next(entry)); |
| 76 SkASSERT(NULL == entry->fList); | 120 SkASSERT(NULL == E::List(entry)); |
| 77 | 121 |
| 78 entry->fPrev = NULL; | 122 E::Prev(entry) = NULL; |
| 79 entry->fNext = fHead; | 123 E::Next(entry) = fHead; |
| 80 if (NULL != fHead) { | 124 if (NULL != fHead) { |
| 81 fHead->fPrev = entry; | 125 E::Prev(fHead) = entry; |
| 82 } | 126 } |
| 83 fHead = entry; | 127 fHead = entry; |
| 84 if (NULL == fTail) { | 128 if (NULL == fTail) { |
| 85 fTail = entry; | 129 fTail = entry; |
| 86 } | 130 } |
| 87 | 131 |
| 88 #ifdef SK_DEBUG | 132 #ifdef SK_DEBUG |
| 89 entry->fList = this; | 133 E::List(entry) = this; |
| 90 #endif | 134 #endif |
| 91 } | 135 } |
| 92 | 136 |
| 93 void addToTail(T* entry) { | 137 void addToTail(T* entry) { |
| 94 SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); | 138 SkASSERT(NULL == E::Prev(entry) && NULL == E::Next(entry)); |
| 95 SkASSERT(NULL == entry->fList); | 139 SkASSERT(NULL == E::List(entry)); |
| 96 | 140 |
| 97 entry->fPrev = fTail; | 141 E::Prev(entry) = fTail; |
| 98 entry->fNext = NULL; | 142 E::Next(entry) = NULL; |
| 99 if (NULL != fTail) { | 143 if (NULL != fTail) { |
| 100 fTail->fNext = entry; | 144 E::Next(fTail) = entry; |
| 101 } | 145 } |
| 102 fTail = entry; | 146 fTail = entry; |
| 103 if (NULL == fHead) { | 147 if (NULL == fHead) { |
| 104 fHead = entry; | 148 fHead = entry; |
| 105 } | 149 } |
| 106 | 150 |
| 107 #ifdef SK_DEBUG | 151 #ifdef SK_DEBUG |
| 108 entry->fList = this; | 152 E::List(entry) = this; |
| 109 #endif | 153 #endif |
| 110 } | 154 } |
| 111 | 155 |
| 112 /** | 156 /** |
| 113 * Inserts a new list entry before an existing list entry. The new entry mus t not already be | 157 * 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 | 158 * a member of this or any other list. If existingEntry is NULL then the new entry is added |
| 115 * at the tail. | 159 * at the tail. |
| 116 */ | 160 */ |
| 117 void addBefore(T* newEntry, T* existingEntry) { | 161 void addBefore(T* newEntry, T* existingEntry) { |
| 118 SkASSERT(NULL != newEntry); | 162 SkASSERT(NULL != newEntry); |
| 119 | 163 |
| 120 if (NULL == existingEntry) { | 164 if (NULL == existingEntry) { |
| 121 this->addToTail(newEntry); | 165 this->addToTail(newEntry); |
| 122 return; | 166 return; |
| 123 } | 167 } |
| 124 | 168 |
| 125 SkASSERT(this->isInList(existingEntry)); | 169 SkASSERT(this->isInList(existingEntry)); |
| 126 newEntry->fNext = existingEntry; | 170 E::Next(newEntry) = existingEntry; |
| 127 T* prev = existingEntry->fPrev; | 171 T* prev = E::Prev(existingEntry); |
| 128 existingEntry->fPrev = newEntry; | 172 E::Prev(existingEntry) = newEntry; |
| 129 newEntry->fPrev = prev; | 173 E::Prev(newEntry) = prev; |
| 130 if (NULL == prev) { | 174 if (NULL == prev) { |
| 131 SkASSERT(fHead == existingEntry); | 175 SkASSERT(fHead == existingEntry); |
| 132 fHead = newEntry; | 176 fHead = newEntry; |
| 133 } else { | 177 } else { |
| 134 prev->fNext = newEntry; | 178 E::Next(prev) = newEntry; |
| 135 } | 179 } |
| 136 #ifdef SK_DEBUG | 180 #ifdef SK_DEBUG |
| 137 newEntry->fList = this; | 181 E::List(newEntry) = this; |
| 138 #endif | 182 #endif |
| 139 } | 183 } |
| 140 | 184 |
| 141 /** | 185 /** |
| 142 * Inserts a new list entry after an existing list entry. The new entry must not already be | 186 * 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 | 187 * a member of this or any other list. If existingEntry is NULL then the new entry is added |
| 144 * at the head. | 188 * at the head. |
| 145 */ | 189 */ |
| 146 void addAfter(T* newEntry, T* existingEntry) { | 190 void addAfter(T* newEntry, T* existingEntry) { |
| 147 SkASSERT(NULL != newEntry); | 191 SkASSERT(NULL != newEntry); |
| 148 | 192 |
| 149 if (NULL == existingEntry) { | 193 if (NULL == existingEntry) { |
| 150 this->addToHead(newEntry); | 194 this->addToHead(newEntry); |
| 151 return; | 195 return; |
| 152 } | 196 } |
| 153 | 197 |
| 154 SkASSERT(this->isInList(existingEntry)); | 198 SkASSERT(this->isInList(existingEntry)); |
| 155 newEntry->fPrev = existingEntry; | 199 E::Prev(newEntry) = existingEntry; |
| 156 T* next = existingEntry->fNext; | 200 T* next = E::Next(existingEntry); |
| 157 existingEntry->fNext = newEntry; | 201 E::Next(existingEntry) = newEntry; |
| 158 newEntry->fNext = next; | 202 E::Next(newEntry) = next; |
| 159 if (NULL == next) { | 203 if (NULL == next) { |
| 160 SkASSERT(fTail == existingEntry); | 204 SkASSERT(fTail == existingEntry); |
| 161 fTail = newEntry; | 205 fTail = newEntry; |
| 162 } else { | 206 } else { |
| 163 next->fPrev = newEntry; | 207 E::Prev(next) = newEntry; |
| 164 } | 208 } |
| 165 #ifdef SK_DEBUG | 209 #ifdef SK_DEBUG |
| 166 newEntry->fList = this; | 210 E::List(newEntry) = this; |
| 167 #endif | 211 #endif |
| 168 } | 212 } |
| 169 | 213 |
| 170 bool isEmpty() const { | 214 bool isEmpty() const { |
| 171 return NULL == fHead && NULL == fTail; | 215 return NULL == fHead && NULL == fTail; |
| 172 } | 216 } |
| 173 | 217 |
| 174 T* head() { return fHead; } | 218 T* head() { return fHead; } |
| 175 T* tail() { return fTail; } | 219 T* tail() { return fTail; } |
| 176 | 220 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 199 T* get() { return fCurr; } | 243 T* get() { return fCurr; } |
| 200 | 244 |
| 201 /** | 245 /** |
| 202 * Return the next/previous element in the list or NULL if at the end. | 246 * Return the next/previous element in the list or NULL if at the end. |
| 203 */ | 247 */ |
| 204 T* next() { | 248 T* next() { |
| 205 if (NULL == fCurr) { | 249 if (NULL == fCurr) { |
| 206 return NULL; | 250 return NULL; |
| 207 } | 251 } |
| 208 | 252 |
| 209 fCurr = fCurr->fNext; | 253 fCurr = E::Next(fCurr); |
| 210 return fCurr; | 254 return fCurr; |
| 211 } | 255 } |
| 212 | 256 |
| 213 T* prev() { | 257 T* prev() { |
| 214 if (NULL == fCurr) { | 258 if (NULL == fCurr) { |
| 215 return NULL; | 259 return NULL; |
| 216 } | 260 } |
| 217 | 261 |
| 218 fCurr = fCurr->fPrev; | 262 fCurr = E::Prev(fCurr); |
| 219 return fCurr; | 263 return fCurr; |
| 220 } | 264 } |
| 221 | 265 |
| 222 private: | 266 private: |
| 223 T* fCurr; | 267 T* fCurr; |
| 224 }; | 268 }; |
| 225 | 269 |
| 270 template <typename PredicateFunctor> | |
| 271 T* find(const PredicateFunctor& f) { | |
|
mtklein
2013/12/03 19:02:02
I'm still skeptical of adding a method like this.
| |
| 272 Iter iter; | |
| 273 for (T* item = iter.init(*this, Iter::kHead_IterStart); NULL != item; it em = iter.next()) { | |
| 274 if (f(item)) { | |
| 275 return item; | |
| 276 } | |
| 277 } | |
| 278 return NULL; | |
| 279 } | |
| 280 | |
| 226 #ifdef SK_DEBUG | 281 #ifdef SK_DEBUG |
| 227 void validate() const { | 282 void validate() const { |
| 228 SkASSERT(!fHead == !fTail); | 283 SkASSERT(!fHead == !fTail); |
| 229 Iter iter; | 284 Iter iter; |
| 230 for (T* item = iter.init(*this, Iter::kHead_IterStart); NULL != (item = iter.next()); ) { | 285 for (T* item = iter.init(*this, Iter::kHead_IterStart); NULL != item; i tem = iter.next()) { |
| 231 SkASSERT(this->isInList(item)); | 286 SkASSERT(this->isInList(item)); |
| 232 if (NULL == item->fPrev) { | 287 if (NULL == E::Prev(item)) { |
| 233 SkASSERT(fHead == item); | 288 SkASSERT(fHead == item); |
| 234 } else { | 289 } else { |
| 235 SkASSERT(item->fPrev->fNext == item); | 290 SkASSERT(E::Next(E::Prev(item)) == item); |
| 236 } | 291 } |
| 237 if (NULL == item->fNext) { | 292 if (NULL == E::Next(item)) { |
| 238 SkASSERT(fTail == item); | 293 SkASSERT(fTail == item); |
| 239 } else { | 294 } else { |
| 240 SkASSERT(item->fNext->fPrev == item); | 295 SkASSERT(E::Prev(E::Next(item)) == item); |
| 241 } | 296 } |
| 242 } | 297 } |
| 243 } | 298 } |
| 244 | 299 |
| 245 /** | 300 /** |
| 246 * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this' | 301 * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this' |
| 247 * list. | 302 * list. |
| 248 */ | 303 */ |
| 249 bool isInList(const T* entry) const { | 304 bool isInList(const T* entry) const { |
| 250 return entry->fList == this; | 305 return E::List(entry) == this; |
| 251 } | 306 } |
| 252 | 307 |
| 253 /** | 308 /** |
| 254 * Debugging-only method that laboriously counts the list entries. | 309 * Debugging-only method that laboriously counts the list entries. |
| 255 */ | 310 */ |
| 256 int countEntries() const { | 311 int countEntries() const { |
| 257 int count = 0; | 312 int count = 0; |
| 258 for (T* entry = fHead; NULL != entry; entry = entry->fNext) { | 313 for (T* entry = fHead; NULL != entry; entry = E::Next(entry)) { |
| 259 ++count; | 314 ++count; |
| 260 } | 315 } |
| 261 return count; | 316 return count; |
| 262 } | 317 } |
| 263 #endif // SK_DEBUG | 318 #endif // SK_DEBUG |
| 264 | 319 |
| 265 private: | 320 private: |
| 266 T* fHead; | 321 T* fHead; |
| 267 T* fTail; | 322 T* fTail; |
| 268 | 323 |
| 269 typedef SkNoncopyable INHERITED; | 324 typedef SkNoncopyable INHERITED; |
| 270 }; | 325 }; |
| 271 | 326 |
| 272 #endif | 327 #endif |
| OLD | NEW |