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