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