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 SkTLList_DEFINED
9 #define SkTLList_DEFINED
10
11 #include "SkTInternalLList.h"
12 #include "SkTemplates.h"
13
14 template <typename T> class SkTLList;
15 template <typename T>
16 inline void* operator new(size_t, SkTLList<T>* list,
17 typename SkTLList<T>::Placement placement,
18 const typename SkTLList<T>::Iter& location);
19
20 /** Doubly-linked list of objects. The objects' lifetimes are controlled by the list. I.e. the
21 the list creates the objects and they are deleted upon removal. This class block-allocates
22 space for entries based on a param passed to the constructor.
23
24 Elements of the list can be constructed in place using the following macros:
25 SkNEW_INSERT_IN_LLIST_BEFORE(list, location, type_name, args)
26 SkNEW_INSERT_IN_LLIST_AFTER(list, location, type_name, args)
27 where list is a SkTLList<type_name>*, location is an iterator, and args is the paren-surrounded
28 constructor arguments for type_name. These macros behave like addBefore() and addAfter().
29 */
30 template <typename T>
31 class SkTLList : SkNoncopyable {
32 private:
33 struct Block;
34 struct Node {
35 char fObj[sizeof(T)];
36 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Node);
37 Block* fBlock; // owning block.
38 };
39 typedef SkTInternalLList<Node> NodeList;
40
41 public:
42
43 class Iter;
44
45 /** allocCnt is the number of objects to allocate as a group. In the worst case fragmentation
46 each object is using the space required for allocCnt unfragmented objects. */
47 SkTLList(int allocCnt = 1) : fCount(0), fAllocCnt(allocCnt) {
48 SkASSERT(allocCnt > 0);
49 this->validate();
50 }
51
~SkTLList()52 ~SkTLList() {
53 this->validate();
54 typename NodeList::Iter iter;
55 Node* node = iter.init(fList, Iter::kHead_IterStart);
56 while (node) {
57 SkTCast<T*>(node->fObj)->~T();
58 Block* block = node->fBlock;
59 node = iter.next();
60 if (0 == --block->fNodesInUse) {
61 for (int i = 0; i < fAllocCnt; ++i) {
62 block->fNodes[i].~Node();
63 }
64 sk_free(block);
65 }
66 }
67 }
68
addToHead(const T & t)69 T* addToHead(const T& t) {
70 this->validate();
71 Node* node = this->createNode();
72 fList.addToHead(node);
73 SkNEW_PLACEMENT_ARGS(node->fObj, T, (t));
74 this->validate();
75 return reinterpret_cast<T*>(node->fObj);
76 }
77
addToHead()78 T* addToHead() {
79 this->validate();
80 Node* node = this->createNode();
81 fList.addToHead(node);
82 SkNEW_PLACEMENT(node->fObj, T);
83 this->validate();
84 return reinterpret_cast<T*>(node->fObj);
85 }
86
addToTail(const T & t)87 T* addToTail(const T& t) {
88 this->validate();
89 Node* node = this->createNode();
90 fList.addToTail(node);
91 SkNEW_PLACEMENT_ARGS(node->fObj, T, (t));
92 this->validate();
93 return reinterpret_cast<T*>(node->fObj);
94 }
95
addToTail()96 T* addToTail() {
97 this->validate();
98 Node* node = this->createNode();
99 fList.addToTail(node);
100 SkNEW_PLACEMENT(node->fObj, T);
101 this->validate();
102 return reinterpret_cast<T*>(node->fObj);
103 }
104
105 /** Adds a new element to the list before the location indicated by the iterator. If the
106 iterator refers to a NULL location then the new element is added at the tail */
addBefore(const T & t,const Iter & location)107 T* addBefore(const T& t, const Iter& location) {
108 return SkNEW_PLACEMENT_ARGS(this->internalAddBefore(location), T, (t));
109 }
110
111 /** Adds a new element to the list after the location indicated by the iterator. If the
112 iterator refers to a NULL location then the new element is added at the head */
addAfter(const T & t,const Iter & location)113 T* addAfter(const T& t, const Iter& location) {
114 return SkNEW_PLACEMENT_ARGS(this->internalAddAfter(location), T, (t));
115 }
116
117 /** Convenience methods for getting an iterator initialized to the head/tail of the list. */
headIter()118 Iter headIter() const { return Iter(*this, Iter::kHead_IterStart); }
tailIter()119 Iter tailIter() const { return Iter(*this, Iter::kTail_IterStart); }
120
head()121 T* head() { return Iter(*this, Iter::kHead_IterStart).get(); }
tail()122 T* tail() { return Iter(*this, Iter::kTail_IterStart).get(); }
head()123 const T* head() const { return Iter(*this, Iter::kHead_IterStart).get(); }
tail()124 const T* tail() const { return Iter(*this, Iter::kTail_IterStart).get(); }
125
popHead()126 void popHead() {
127 this->validate();
128 Node* node = fList.head();
129 if (node) {
130 this->removeNode(node);
131 }
132 this->validate();
133 }
134
popTail()135 void popTail() {
136 this->validate();
137 Node* node = fList.head();
138 if (node) {
139 this->removeNode(node);
140 }
141 this->validate();
142 }
143
remove(T * t)144 void remove(T* t) {
145 this->validate();
146 Node* node = reinterpret_cast<Node*>(t);
147 SkASSERT(reinterpret_cast<T*>(node->fObj) == t);
148 this->removeNode(node);
149 this->validate();
150 }
151
reset()152 void reset() {
153 this->validate();
154 Iter iter(*this, Iter::kHead_IterStart);
155 while (iter.get()) {
156 Iter next = iter;
157 next.next();
158 this->remove(iter.get());
159 iter = next;
160 }
161 SkASSERT(0 == fCount);
162 this->validate();
163 }
164
count()165 int count() const { return fCount; }
isEmpty()166 bool isEmpty() const { this->validate(); return 0 == fCount; }
167
168 bool operator== (const SkTLList& list) const {
169 if (this == &list) {
170 return true;
171 }
172 if (fCount != list.fCount) {
173 return false;
174 }
175 for (Iter a(*this, Iter::kHead_IterStart), b(list, Iter::kHead_IterStart);
176 a.get();
177 a.next(), b.next()) {
178 SkASSERT(b.get()); // already checked that counts match.
179 if (!(*a.get() == *b.get())) {
180 return false;
181 }
182 }
183 return true;
184 }
185 bool operator!= (const SkTLList& list) const { return !(*this == list); }
186
187 /** The iterator becomes invalid if the element it refers to is removed from the list. */
188 class Iter : private NodeList::Iter {
189 private:
190 typedef typename NodeList::Iter INHERITED;
191
192 public:
193 typedef typename INHERITED::IterStart IterStart;
194 //!< Start the iterator at the head of the list.
195 static const IterStart kHead_IterStart = INHERITED::kHead_IterStart;
196 //!< Start the iterator at the tail of the list.
197 static const IterStart kTail_IterStart = INHERITED::kTail_IterStart;
198
Iter()199 Iter() {}
200
201 Iter(const SkTLList& list, IterStart start = kHead_IterStart) {
202 INHERITED::init(list.fList, start);
203 }
204
205 T* init(const SkTLList& list, IterStart start = kHead_IterStart) {
206 return this->nodeToObj(INHERITED::init(list.fList, start));
207 }
208
get()209 T* get() { return this->nodeToObj(INHERITED::get()); }
210
next()211 T* next() { return this->nodeToObj(INHERITED::next()); }
212
prev()213 T* prev() { return this->nodeToObj(INHERITED::prev()); }
214
215 Iter& operator= (const Iter& iter) { INHERITED::operator=(iter); return *this; }
216
217 private:
218 friend class SkTLList;
getNode()219 Node* getNode() { return INHERITED::get(); }
220
nodeToObj(Node * node)221 T* nodeToObj(Node* node) {
222 if (node) {
223 return reinterpret_cast<T*>(node->fObj);
224 } else {
225 return NULL;
226 }
227 }
228 };
229
230 // For use with operator new
231 enum Placement {
232 kBefore_Placement,
233 kAfter_Placement,
234 };
235
236 private:
237 struct Block {
238 int fNodesInUse;
239 Node fNodes[1];
240 };
241
blockSize()242 size_t blockSize() const { return sizeof(Block) + sizeof(Node) * (fAllocCnt-1); }
243
createNode()244 Node* createNode() {
245 Node* node = fFreeList.head();
246 if (node) {
247 fFreeList.remove(node);
248 ++node->fBlock->fNodesInUse;
249 } else {
250 Block* block = reinterpret_cast<Block*>(sk_malloc_flags(this->blockSize(), 0));
251 node = &block->fNodes[0];
252 SkNEW_PLACEMENT(node, Node);
253 node->fBlock = block;
254 block->fNodesInUse = 1;
255 for (int i = 1; i < fAllocCnt; ++i) {
256 SkNEW_PLACEMENT(block->fNodes + i, Node);
257 fFreeList.addToHead(block->fNodes + i);
258 block->fNodes[i].fBlock = block;
259 }
260 }
261 ++fCount;
262 return node;
263 }
264
removeNode(Node * node)265 void removeNode(Node* node) {
266 SkASSERT(node);
267 fList.remove(node);
268 SkTCast<T*>(node->fObj)->~T();
269 if (0 == --node->fBlock->fNodesInUse) {
270 Block* block = node->fBlock;
271 for (int i = 0; i < fAllocCnt; ++i) {
272 if (block->fNodes + i != node) {
273 fFreeList.remove(block->fNodes + i);
274 }
275 block->fNodes[i].~Node();
276 }
277 sk_free(block);
278 } else {
279 fFreeList.addToHead(node);
280 }
281 --fCount;
282 this->validate();
283 }
284
validate()285 void validate() const {
286 #ifdef SK_DEBUG
287 SkASSERT((0 == fCount) == fList.isEmpty());
288 SkASSERT((0 != fCount) || fFreeList.isEmpty());
289
290 fList.validate();
291 fFreeList.validate();
292 typename NodeList::Iter iter;
293 Node* freeNode = iter.init(fFreeList, Iter::kHead_IterStart);
294 while (freeNode) {
295 SkASSERT(fFreeList.isInList(freeNode));
296 Block* block = freeNode->fBlock;
297 SkASSERT(block->fNodesInUse > 0 && block->fNodesInUse < fAllocCnt);
298
299 int activeCnt = 0;
300 int freeCnt = 0;
301 for (int i = 0; i < fAllocCnt; ++i) {
302 bool free = fFreeList.isInList(block->fNodes + i);
303 bool active = fList.isInList(block->fNodes + i);
304 SkASSERT(free != active);
305 activeCnt += active;
306 freeCnt += free;
307 }
308 SkASSERT(activeCnt == block->fNodesInUse);
309 freeNode = iter.next();
310 }
311
312 int count = 0;
313 Node* activeNode = iter.init(fList, Iter::kHead_IterStart);
314 while (activeNode) {
315 ++count;
316 SkASSERT(fList.isInList(activeNode));
317 Block* block = activeNode->fBlock;
318 SkASSERT(block->fNodesInUse > 0 && block->fNodesInUse <= fAllocCnt);
319
320 int activeCnt = 0;
321 int freeCnt = 0;
322 for (int i = 0; i < fAllocCnt; ++i) {
323 bool free = fFreeList.isInList(block->fNodes + i);
324 bool active = fList.isInList(block->fNodes + i);
325 SkASSERT(free != active);
326 activeCnt += active;
327 freeCnt += free;
328 }
329 SkASSERT(activeCnt == block->fNodesInUse);
330 activeNode = iter.next();
331 }
332 SkASSERT(count == fCount);
333 #endif
334 }
335
336 // Support in-place initializing of objects inserted into the list via operator new.
337 friend void* operator new<T>(size_t,
338 SkTLList* list,
339 Placement placement,
340 const Iter& location);
341
342
343 // Helpers that insert the node and returns a pointer to where the new object should be init'ed.
internalAddBefore(Iter location)344 void* internalAddBefore(Iter location) {
345 this->validate();
346 Node* node = this->createNode();
347 fList.addBefore(node, location.getNode());
348 this->validate();
349 return node->fObj;
350 }
351
internalAddAfter(Iter location)352 void* internalAddAfter(Iter location) {
353 this->validate();
354 Node* node = this->createNode();
355 fList.addAfter(node, location.getNode());
356 this->validate();
357 return node->fObj;
358 }
359
360 NodeList fList;
361 NodeList fFreeList;
362 int fCount;
363 int fAllocCnt;
364
365 };
366
367 // Use the below macros rather than calling this directly
368 template <typename T>
new(size_t,SkTLList<T> * list,typename SkTLList<T>::Placement placement,const typename SkTLList<T>::Iter & location)369 void *operator new(size_t, SkTLList<T>* list,
370 typename SkTLList<T>::Placement placement,
371 const typename SkTLList<T>::Iter& location) {
372 SkASSERT(list);
373 if (SkTLList<T>::kBefore_Placement == placement) {
374 return list->internalAddBefore(location);
375 } else {
376 return list->internalAddAfter(location);
377 }
378 }
379
380 // Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete
381 // to match the op new silences warnings about missing op delete when a constructor throws an
382 // exception.
383 template <typename T>
delete(void *,SkTLList<T> *,typename SkTLList<T>::Placement,const typename SkTLList<T>::Iter &)384 void operator delete(void*,
385 SkTLList<T>*,
386 typename SkTLList<T>::Placement,
387 const typename SkTLList<T>::Iter&) {
388 SK_CRASH();
389 }
390
391 #define SkNEW_INSERT_IN_LLIST_BEFORE(list, location, type_name, args) \
392 (new ((list), SkTLList< type_name >::kBefore_Placement, (location)) type_name args)
393
394 #define SkNEW_INSERT_IN_LLIST_AFTER(list, location, type_name, args) \
395 (new ((list), SkTLList< type_name >::kAfter_Placement, (location)) type_name args)
396
397 #define SkNEW_INSERT_AT_LLIST_HEAD(list, type_name, args) \
398 SkNEW_INSERT_IN_LLIST_BEFORE((list), (list)->headIter(), type_name, args)
399
400 #define SkNEW_INSERT_AT_LLIST_TAIL(list, type_name, args) \
401 SkNEW_INSERT_IN_LLIST_AFTER((list), (list)->tailIter(), type_name, args)
402
403 #endif
404