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