Home | History | Annotate | Download | only in core
      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:
     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:
     43     SkTInternalLList()
     44         : fHead(nullptr)
     45         , fTail(nullptr) {
     46     }
     47 
     48     void reset() {
     49         fHead = nullptr;
     50         fTail = nullptr;
     51     }
     52 
     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 
     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 
     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      */
    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      */
    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 
    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 
    200     bool isEmpty() const {
    201         SkASSERT(SkToBool(fHead) == SkToBool(fTail));
    202         return !fHead;
    203     }
    204 
    205     T* head() { return fHead; }
    206     T* tail() { return fTail; }
    207 
    208     class Iter {
    209     public:
    210         enum IterStart {
    211             kHead_IterStart,
    212             kTail_IterStart
    213         };
    214 
    215         Iter() : fCurr(nullptr) {}
    216         Iter(const Iter& iter) : fCurr(iter.fCurr) {}
    217         Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; }
    218 
    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 
    230         T* get() { return fCurr; }
    231 
    232         /**
    233          * Return the next/previous element in the list or NULL if at the end.
    234          */
    235         T* next() {
    236             if (nullptr == fCurr) {
    237                 return nullptr;
    238             }
    239 
    240             fCurr = fCurr->fNext;
    241             return fCurr;
    242         }
    243 
    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
    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      */
    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      */
    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