Chromium Code Reviews| Index: include/core/SkTInternalLList.h |
| diff --git a/include/core/SkTInternalLList.h b/include/core/SkTInternalLList.h |
| index a6b6f153530796097c1f92a7294220f2209bd481..7a89dd63ce5d477b4329743f9a0d1257dfb5268e 100644 |
| --- a/include/core/SkTInternalLList.h |
| +++ b/include/core/SkTInternalLList.h |
| @@ -29,16 +29,60 @@ template <typename T> class SkPtrWrapper { |
| * placed in the private section of any class that will be stored in a double linked list. |
| */ |
| #define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \ |
| - friend class SkTInternalLList<ClassName>; \ |
| + friend class SkTInternalLListDefaultExtractor<ClassName>; \ |
|
mtklein
2013/12/03 19:02:02
I'm somewhat worried about the general design of G
|
| /* back pointer to the owning list - for debugging */ \ |
| SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;) \ |
| SkPtrWrapper<ClassName> fPrev; \ |
| - SkPtrWrapper<ClassName> fNext |
| + SkPtrWrapper<ClassName> fNext; |
| + |
| +/** |
| + * This macro creates the members for storing the instance to a specific, named linked list. It |
| + * should be placed in the public section of any class that will be stored in a double linked |
| + * list. Classes that use this macro need to use corresponding _DATA macro below. |
| + */ |
| +#define SK_DECLARE_NAMED_INTERNAL_LLIST_INTERFACE(T, Name) \ |
| + struct InternalLListExtractor##Name { \ |
| + typedef SkTInternalLList<T, InternalLListExtractor##Name > ListType; \ |
| + static SkPtrWrapper<T>& Prev(T* o) { return o->fPrev##Name; } \ |
| + static SkPtrWrapper<T>& Next(T* o) { return o->fNext##Name; } \ |
| + SkDEBUGCODE(static SkPtrWrapper<ListType>& List(T* o) { return o->fList##Name; }) \ |
| + SkDEBUGCODE(static const ListType* List(const T* o) { return o->fList##Name; }) \ |
| + }; \ |
| + friend class InternalLListExtractor##Name; |
| + |
| +/** |
| + * This macro creates the member variables for storing the instance to a specific, named linked |
| + * list. It should be placed in the private section of the class. |
| + */ |
| +#define SK_DECLARE_NAMED_INTERNAL_LLIST_INTERFACE_DATA(T, Name) \ |
| + SkPtrWrapper<T> fPrev##Name; \ |
| + SkPtrWrapper<T> fNext##Name; \ |
| + SkDEBUGCODE(SkPtrWrapper<InternalLListExtractor##Name::ListType> fList##Name;) |
| + |
| +/** |
| + * This macro creates the member variable and short-cut typedefs for a specific, named linked list. |
| + * This should be placed in the class declaration or code that creates the named linked list. |
| + */ |
| +#define SK_DECLARE_NAMED_INTERNAL_LLIST(T, Name, VarName) \ |
| + typedef SkTInternalLList<T, T::InternalLListExtractor##Name> Name##InternalLListType; \ |
| + Name##InternalLListType VarName; |
| + |
| +template <class T, class E> class SkTInternalLList; |
| + |
| +template<typename T> |
| +struct SkTInternalLListDefaultExtractor { |
| + typedef SkTInternalLList<T, SkTInternalLListDefaultExtractor<T> > ListType; |
| + static SkPtrWrapper<T>& Prev(T* o) { return o->fPrev; } |
| + static SkPtrWrapper<T>& Next(T* o) { return o->fNext; } |
| + SkDEBUGCODE(static SkPtrWrapper<ListType>& List(T* o) { return o->fList; }) |
| + SkDEBUGCODE(static const ListType* List(const T* o) { return o->fList; }) |
| +}; |
| /** |
| * This class implements a templated internal doubly linked list data structure. |
| */ |
| -template <class T> class SkTInternalLList : public SkNoncopyable { |
| +template <class T, class E = SkTInternalLListDefaultExtractor<T> > |
| +class SkTInternalLList : public SkNoncopyable { |
| public: |
| SkTInternalLList() |
| : fHead(NULL) |
| @@ -49,36 +93,36 @@ public: |
| SkASSERT(NULL != fHead && NULL != fTail); |
| SkASSERT(this->isInList(entry)); |
| - T* prev = entry->fPrev; |
| - T* next = entry->fNext; |
| + T* prev = E::Prev(entry); |
| + T* next = E::Next(entry); |
| if (NULL != prev) { |
| - prev->fNext = next; |
| + E::Next(prev) = next; |
| } else { |
| fHead = next; |
| } |
| if (NULL != next) { |
| - next->fPrev = prev; |
| + E::Prev(next) = prev; |
| } else { |
| fTail = prev; |
| } |
| - entry->fPrev = NULL; |
| - entry->fNext = NULL; |
| + E::Prev(entry) = NULL; |
| + E::Next(entry) = NULL; |
| #ifdef SK_DEBUG |
| - entry->fList = NULL; |
| + E::List(entry) = NULL; |
| #endif |
| } |
| void addToHead(T* entry) { |
| - SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); |
| - SkASSERT(NULL == entry->fList); |
| + SkASSERT(NULL == E::Prev(entry) && NULL == E::Next(entry)); |
| + SkASSERT(NULL == E::List(entry)); |
| - entry->fPrev = NULL; |
| - entry->fNext = fHead; |
| + E::Prev(entry) = NULL; |
| + E::Next(entry) = fHead; |
| if (NULL != fHead) { |
| - fHead->fPrev = entry; |
| + E::Prev(fHead) = entry; |
| } |
| fHead = entry; |
| if (NULL == fTail) { |
| @@ -86,18 +130,18 @@ public: |
| } |
| #ifdef SK_DEBUG |
| - entry->fList = this; |
| + E::List(entry) = this; |
| #endif |
| } |
| void addToTail(T* entry) { |
| - SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); |
| - SkASSERT(NULL == entry->fList); |
| + SkASSERT(NULL == E::Prev(entry) && NULL == E::Next(entry)); |
| + SkASSERT(NULL == E::List(entry)); |
| - entry->fPrev = fTail; |
| - entry->fNext = NULL; |
| + E::Prev(entry) = fTail; |
| + E::Next(entry) = NULL; |
| if (NULL != fTail) { |
| - fTail->fNext = entry; |
| + E::Next(fTail) = entry; |
| } |
| fTail = entry; |
| if (NULL == fHead) { |
| @@ -105,7 +149,7 @@ public: |
| } |
| #ifdef SK_DEBUG |
| - entry->fList = this; |
| + E::List(entry) = this; |
| #endif |
| } |
| @@ -123,18 +167,18 @@ public: |
| } |
| SkASSERT(this->isInList(existingEntry)); |
| - newEntry->fNext = existingEntry; |
| - T* prev = existingEntry->fPrev; |
| - existingEntry->fPrev = newEntry; |
| - newEntry->fPrev = prev; |
| + E::Next(newEntry) = existingEntry; |
| + T* prev = E::Prev(existingEntry); |
| + E::Prev(existingEntry) = newEntry; |
| + E::Prev(newEntry) = prev; |
| if (NULL == prev) { |
| SkASSERT(fHead == existingEntry); |
| fHead = newEntry; |
| } else { |
| - prev->fNext = newEntry; |
| + E::Next(prev) = newEntry; |
| } |
| #ifdef SK_DEBUG |
| - newEntry->fList = this; |
| + E::List(newEntry) = this; |
| #endif |
| } |
| @@ -152,18 +196,18 @@ public: |
| } |
| SkASSERT(this->isInList(existingEntry)); |
| - newEntry->fPrev = existingEntry; |
| - T* next = existingEntry->fNext; |
| - existingEntry->fNext = newEntry; |
| - newEntry->fNext = next; |
| + E::Prev(newEntry) = existingEntry; |
| + T* next = E::Next(existingEntry); |
| + E::Next(existingEntry) = newEntry; |
| + E::Next(newEntry) = next; |
| if (NULL == next) { |
| SkASSERT(fTail == existingEntry); |
| fTail = newEntry; |
| } else { |
| - next->fPrev = newEntry; |
| + E::Prev(next) = newEntry; |
| } |
| #ifdef SK_DEBUG |
| - newEntry->fList = this; |
| + E::List(newEntry) = this; |
| #endif |
| } |
| @@ -206,7 +250,7 @@ public: |
| return NULL; |
| } |
| - fCurr = fCurr->fNext; |
| + fCurr = E::Next(fCurr); |
| return fCurr; |
| } |
| @@ -215,7 +259,7 @@ public: |
| return NULL; |
| } |
| - fCurr = fCurr->fPrev; |
| + fCurr = E::Prev(fCurr); |
| return fCurr; |
| } |
| @@ -223,21 +267,32 @@ public: |
| T* fCurr; |
| }; |
| + template <typename PredicateFunctor> |
| + T* find(const PredicateFunctor& f) { |
|
mtklein
2013/12/03 19:02:02
I'm still skeptical of adding a method like this.
|
| + Iter iter; |
| + for (T* item = iter.init(*this, Iter::kHead_IterStart); NULL != item; item = iter.next()) { |
| + if (f(item)) { |
| + return item; |
| + } |
| + } |
| + return NULL; |
| + } |
| + |
| #ifdef SK_DEBUG |
| void validate() const { |
| SkASSERT(!fHead == !fTail); |
| Iter iter; |
| - for (T* item = iter.init(*this, Iter::kHead_IterStart); NULL != (item = iter.next()); ) { |
| + for (T* item = iter.init(*this, Iter::kHead_IterStart); NULL != item; item = iter.next()) { |
| SkASSERT(this->isInList(item)); |
| - if (NULL == item->fPrev) { |
| + if (NULL == E::Prev(item)) { |
| SkASSERT(fHead == item); |
| } else { |
| - SkASSERT(item->fPrev->fNext == item); |
| + SkASSERT(E::Next(E::Prev(item)) == item); |
| } |
| - if (NULL == item->fNext) { |
| + if (NULL == E::Next(item)) { |
| SkASSERT(fTail == item); |
| } else { |
| - SkASSERT(item->fNext->fPrev == item); |
| + SkASSERT(E::Prev(E::Next(item)) == item); |
| } |
| } |
| } |
| @@ -247,7 +302,7 @@ public: |
| * list. |
| */ |
| bool isInList(const T* entry) const { |
| - return entry->fList == this; |
| + return E::List(entry) == this; |
| } |
| /** |
| @@ -255,7 +310,7 @@ public: |
| */ |
| int countEntries() const { |
| int count = 0; |
| - for (T* entry = fHead; NULL != entry; entry = entry->fNext) { |
| + for (T* entry = fHead; NULL != entry; entry = E::Next(entry)) { |
| ++count; |
| } |
| return count; |