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