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 "../private/SkNoncopyable.h"
12 #include "SkTypes.h"
13 
14 /**
15  * Helper class to automatically initialize the doubly linked list created pointers.
16  */
17 template <typename T> class SkPtrWrapper {
18   public:
SkPtrWrapper()19       SkPtrWrapper() : fPtr(nullptr) {}
20       SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; }
21       operator T*() const { return fPtr; }
22       T* operator->() { return fPtr; }
23   private:
24       T* fPtr;
25 };
26 
27 
28 /**
29  * This macro creates the member variables required by the SkTInternalLList class. It should be
30  * placed in the private section of any class that will be stored in a double linked list.
31  */
32 #define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName)              \
33     friend class SkTInternalLList<ClassName>;                       \
34     /* back pointer to the owning list - for debugging */           \
35     SkDEBUGCODE(SkPtrWrapper<SkTInternalLList<ClassName> > fList;)  \
36     SkPtrWrapper<ClassName> fPrev;                                  \
37     SkPtrWrapper<ClassName> fNext
38 
39 /**
40  * This class implements a templated internal doubly linked list data structure.
41  */
42 template <class T> class SkTInternalLList : SkNoncopyable {
43 public:
SkTInternalLList()44     SkTInternalLList()
45         : fHead(nullptr)
46         , fTail(nullptr) {
47     }
48 
reset()49     void reset() {
50         fHead = nullptr;
51         fTail = nullptr;
52     }
53 
remove(T * entry)54     void remove(T* entry) {
55         SkASSERT(fHead && fTail);
56         SkASSERT(this->isInList(entry));
57 
58         T* prev = entry->fPrev;
59         T* next = entry->fNext;
60 
61         if (prev) {
62             prev->fNext = next;
63         } else {
64             fHead = next;
65         }
66         if (next) {
67             next->fPrev = prev;
68         } else {
69             fTail = prev;
70         }
71 
72         entry->fPrev = nullptr;
73         entry->fNext = nullptr;
74 
75 #ifdef SK_DEBUG
76         entry->fList = nullptr;
77 #endif
78     }
79 
addToHead(T * entry)80     void addToHead(T* entry) {
81         SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext);
82         SkASSERT(nullptr == entry->fList);
83 
84         entry->fPrev = nullptr;
85         entry->fNext = fHead;
86         if (fHead) {
87             fHead->fPrev = entry;
88         }
89         fHead = entry;
90         if (nullptr == fTail) {
91             fTail = entry;
92         }
93 
94 #ifdef SK_DEBUG
95         entry->fList = this;
96 #endif
97     }
98 
addToTail(T * entry)99     void addToTail(T* entry) {
100         SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext);
101         SkASSERT(nullptr == entry->fList);
102 
103         entry->fPrev = fTail;
104         entry->fNext = nullptr;
105         if (fTail) {
106             fTail->fNext = entry;
107         }
108         fTail = entry;
109         if (nullptr == fHead) {
110             fHead = entry;
111         }
112 
113 #ifdef SK_DEBUG
114         entry->fList = this;
115 #endif
116     }
117 
118     /**
119      * Inserts a new list entry before an existing list entry. The new entry must not already be
120      * a member of this or any other list. If existingEntry is NULL then the new entry is added
121      * at the tail.
122      */
addBefore(T * newEntry,T * existingEntry)123     void addBefore(T* newEntry, T* existingEntry) {
124         SkASSERT(newEntry);
125 
126         if (nullptr == existingEntry) {
127             this->addToTail(newEntry);
128             return;
129         }
130 
131         SkASSERT(this->isInList(existingEntry));
132         newEntry->fNext = existingEntry;
133         T* prev = existingEntry->fPrev;
134         existingEntry->fPrev = newEntry;
135         newEntry->fPrev = prev;
136         if (nullptr == prev) {
137             SkASSERT(fHead == existingEntry);
138             fHead = newEntry;
139         } else {
140             prev->fNext = newEntry;
141         }
142 #ifdef SK_DEBUG
143         newEntry->fList = this;
144 #endif
145     }
146 
147     /**
148      * Inserts a new list entry after an existing list entry. The new entry must not already be
149      * a member of this or any other list. If existingEntry is NULL then the new entry is added
150      * at the head.
151      */
addAfter(T * newEntry,T * existingEntry)152     void addAfter(T* newEntry, T* existingEntry) {
153         SkASSERT(newEntry);
154 
155         if (nullptr == existingEntry) {
156             this->addToHead(newEntry);
157             return;
158         }
159 
160         SkASSERT(this->isInList(existingEntry));
161         newEntry->fPrev = existingEntry;
162         T* next = existingEntry->fNext;
163         existingEntry->fNext = newEntry;
164         newEntry->fNext = next;
165         if (nullptr == next) {
166             SkASSERT(fTail == existingEntry);
167             fTail = newEntry;
168         } else {
169             next->fPrev = newEntry;
170         }
171 #ifdef SK_DEBUG
172         newEntry->fList = this;
173 #endif
174     }
175 
concat(SkTInternalLList && list)176     void concat(SkTInternalLList&& list) {
177         if (list.isEmpty()) {
178             return;
179         }
180 
181         list.fHead->fPrev = fTail;
182         if (!fHead) {
183             SkASSERT(!list.fHead->fPrev);
184             fHead = list.fHead;
185         } else {
186             SkASSERT(fTail);
187             fTail->fNext = list.fHead;
188         }
189         fTail = list.fTail;
190 
191 #ifdef SK_DEBUG
192         for (T* node = list.fHead; node; node = node->fNext) {
193             SkASSERT(node->fList == &list);
194             node->fList = this;
195         }
196 #endif
197 
198         list.fHead = list.fTail = nullptr;
199     }
200 
isEmpty()201     bool isEmpty() const {
202         SkASSERT(SkToBool(fHead) == SkToBool(fTail));
203         return !fHead;
204     }
205 
head()206     T* head() { return fHead; }
tail()207     T* tail() { return fTail; }
208 
209     class Iter {
210     public:
211         enum IterStart {
212             kHead_IterStart,
213             kTail_IterStart
214         };
215 
Iter()216         Iter() : fCurr(nullptr) {}
Iter(const Iter & iter)217         Iter(const Iter& iter) : fCurr(iter.fCurr) {}
218         Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; }
219 
init(const SkTInternalLList & list,IterStart startLoc)220         T* init(const SkTInternalLList& list, IterStart startLoc) {
221             if (kHead_IterStart == startLoc) {
222                 fCurr = list.fHead;
223             } else {
224                 SkASSERT(kTail_IterStart == startLoc);
225                 fCurr = list.fTail;
226             }
227 
228             return fCurr;
229         }
230 
get()231         T* get() { return fCurr; }
232 
233         /**
234          * Return the next/previous element in the list or NULL if at the end.
235          */
next()236         T* next() {
237             if (nullptr == fCurr) {
238                 return nullptr;
239             }
240 
241             fCurr = fCurr->fNext;
242             return fCurr;
243         }
244 
prev()245         T* prev() {
246             if (nullptr == fCurr) {
247                 return nullptr;
248             }
249 
250             fCurr = fCurr->fPrev;
251             return fCurr;
252         }
253 
254         /**
255          * C++11 range-for interface.
256          */
257         bool operator!=(const Iter& that) { return fCurr != that.fCurr; }
258         T* operator*() { return this->get(); }
259         void operator++() { this->next(); }
260 
261     private:
262         T* fCurr;
263     };
264 
begin()265     Iter begin() const {
266         Iter iter;
267         iter.init(*this, Iter::kHead_IterStart);
268         return iter;
269     }
270 
end()271     Iter end() const { return Iter(); }
272 
273 #ifdef SK_DEBUG
validate()274     void validate() const {
275         SkASSERT(!fHead == !fTail);
276         Iter iter;
277         for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) {
278             SkASSERT(this->isInList(item));
279             if (nullptr == item->fPrev) {
280                 SkASSERT(fHead == item);
281             } else {
282                 SkASSERT(item->fPrev->fNext == item);
283             }
284             if (nullptr == item->fNext) {
285                 SkASSERT(fTail == item);
286             } else {
287                 SkASSERT(item->fNext->fPrev == item);
288             }
289         }
290     }
291 
292     /**
293      * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this'
294      * list.
295      */
isInList(const T * entry)296     bool isInList(const T* entry) const {
297         return entry->fList == this;
298     }
299 
300     /**
301      * Debugging-only method that laboriously counts the list entries.
302      */
countEntries()303     int countEntries() const {
304         int count = 0;
305         for (T* entry = fHead; entry; entry = entry->fNext) {
306             ++count;
307         }
308         return count;
309     }
310 #endif // SK_DEBUG
311 
312 private:
313     T* fHead;
314     T* fTail;
315 
316     typedef SkNoncopyable INHERITED;
317 };
318 
319 #endif
320