/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkTInternalLList_DEFINED #define SkTInternalLList_DEFINED #include "SkTypes.h" /** * Helper class to automatically initialize the doubly linked list created pointers. */ template class SkPtrWrapper { public: SkPtrWrapper() : fPtr(NULL) {} SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; } operator T*() const { return fPtr; } T* operator->() { return fPtr; } private: T* fPtr; }; /** * This macro creates the member variables required by the SkTInternalLList class. It should be * 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; \ /* back pointer to the owning list - for debugging */ \ SkDEBUGCODE(SkPtrWrapper > fList;) \ SkPtrWrapper fPrev; \ SkPtrWrapper fNext /** * This class implements a templated internal doubly linked list data structure. */ template class SkTInternalLList : public SkNoncopyable { public: SkTInternalLList() : fHead(NULL) , fTail(NULL) { } void remove(T* entry) { SkASSERT(NULL != fHead && NULL != fTail); SkASSERT(this->isInList(entry)); T* prev = entry->fPrev; T* next = entry->fNext; if (NULL != prev) { prev->fNext = next; } else { fHead = next; } if (NULL != next) { next->fPrev = prev; } else { fTail = prev; } entry->fPrev = NULL; entry->fNext = NULL; #ifdef SK_DEBUG entry->fList = NULL; #endif } void addToHead(T* entry) { SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); SkASSERT(NULL == entry->fList); entry->fPrev = NULL; entry->fNext = fHead; if (NULL != fHead) { fHead->fPrev = entry; } fHead = entry; if (NULL == fTail) { fTail = entry; } #ifdef SK_DEBUG entry->fList = this; #endif } void addToTail(T* entry) { SkASSERT(NULL == entry->fPrev && NULL == entry->fNext); SkASSERT(NULL == entry->fList); entry->fPrev = fTail; entry->fNext = NULL; if (NULL != fTail) { fTail->fNext = entry; } fTail = entry; if (NULL == fHead) { fHead = entry; } #ifdef SK_DEBUG entry->fList = this; #endif } bool isEmpty() const { return NULL == fHead && NULL == fTail; } T* head() { return fHead; } T* tail() { return fTail; } class Iter { public: enum IterStart { kHead_IterStart, kTail_IterStart }; Iter() : fCurr(NULL) {} Iter(const Iter& iter) : fCurr(iter.fCurr) {} Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; } T* init(const SkTInternalLList& list, IterStart startLoc) { if (kHead_IterStart == startLoc) { fCurr = list.fHead; } else { SkASSERT(kTail_IterStart == startLoc); fCurr = list.fTail; } return fCurr; } T* get() { return fCurr; } /** * Return the next/previous element in the list or NULL if at the end. */ T* next() { if (NULL == fCurr) { return NULL; } fCurr = fCurr->fNext; return fCurr; } T* prev() { if (NULL == fCurr) { return NULL; } fCurr = fCurr->fPrev; return fCurr; } private: T* fCurr; }; #ifdef SK_DEBUG void validate() const { SkASSERT(!fHead == !fTail); } /** * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this' * list. */ bool isInList(const T* entry) const { return entry->fList == this; } /** * Debugging-only method that laboriously counts the list entries. */ int countEntries() const { int count = 0; for (T* entry = fHead; NULL != entry; entry = entry->fNext) { ++count; } return count; } #endif // SK_DEBUG private: T* fHead; T* fTail; typedef SkNoncopyable INHERITED; }; #endif