blob: 41f0c0b4af4fd00049882e38937c58e773c80e27 [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
11/** Doubly-linked list of objects. The objects' lifetimes are controlled by the list. I.e. the
12 the list creates the objects and they are deleted upon removal. This class block-allocates
13 space for entries based on a param passed to the constructor. */
14template <typename T>
15class SkTLList : public SkNoncopyable {
16private:
17 struct Block;
18 struct Node {
19 char fObj[sizeof(T)];
20 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Node);
21 Block* fBlock; // owning block.
22 };
23 typedef SkTInternalLList<Node> NodeList;
24
25public:
26 /** allocCnt is the number of objects to allocate as a group. In the worst case fragmentation
27 each object is using the space required for allocCnt unfragmented objects. */
28 SkTLList(int allocCnt = 1) : fCount(0), fAllocCnt(allocCnt) {
29 SkASSERT(allocCnt > 0);
30 this->validate();
31 }
32
33 ~SkTLList() {
34 this->validate();
35 typename NodeList::Iter iter;
36 Node* node = iter.init(fList, Iter::kHead_IterStart);
37 while (NULL != node) {
38 reinterpret_cast<T*>(node->fObj)->~T();
39 Block* block = node->fBlock;
40 node = iter.next();
41 if (0 == --block->fNodesInUse) {
42 for (int i = 0; i < fAllocCnt; ++i) {
43 block->fNodes[i].~Node();
44 }
45 sk_free(block);
46 }
47 }
48 }
49
50 void addToHead(const T& t) {
51 this->validate();
52 Node* node = this->createNode();
53 fList.addToHead(node);
54 SkNEW_PLACEMENT_ARGS(node->fObj, T, (t));
55 this->validate();
56 }
57
58 void addToTail(const T& t) {
59 this->validate();
60 Node* node = this->createNode();
61 fList.addToTail(node);
62 SkNEW_PLACEMENT_ARGS(node->fObj, T, (t));
63 this->validate();
64 }
65
66 void popHead() {
67 this->validate();
68 Node* node = fList.head();
69 if (NULL != node) {
70 this->removeNode(node);
71 }
72 this->validate();
73 }
74
75 void popTail() {
76 this->validate();
77 Node* node = fList.head();
78 if (NULL != node) {
79 this->removeNode(node);
80 }
81 this->validate();
82 }
83
84 void remove(T* t) {
85 this->validate();
86 Node* node = reinterpret_cast<Node*>(t);
87 SkASSERT(reinterpret_cast<T*>(node->fObj) == t);
88 this->removeNode(node);
89 this->validate();
90 }
91
92 void reset() {
93 this->validate();
94 Iter iter(*this, Iter::kHead_IterStart);
95 while (iter.get()) {
96 Iter next = iter;
97 next.next();
98 this->remove(iter.get());
99 iter = next;
100 }
101 SkASSERT(0 == fCount);
102 this->validate();
103 }
104
105 int count() const { return fCount; }
106 bool isEmpty() const { this->validate(); return 0 == fCount; }
107
108 bool operator== (const SkTLList& list) const {
109 if (this == &list) {
110 return true;
111 }
112 if (fCount != list.fCount) {
113 return false;
114 }
115 for (Iter a(*this, Iter::kHead_IterStart), b(list, Iter::kHead_IterStart);
116 a.get();
117 a.next(), b.next()) {
118 SkASSERT(NULL != b.get()); // already checked that counts match.
119 if (!(*a.get() == *b.get())) {
120 return false;
121 }
122 }
123 return true;
124 }
125 bool operator!= (const SkTLList& list) const { return !(*this == list); }
126
127 /** The iterator becomes invalid if the element it refers to is removed from the list. */
128 class Iter : private NodeList::Iter {
129 private:
130 typedef typename NodeList::Iter INHERITED;
131
132 public:
133 typedef typename INHERITED::IterStart IterStart;
134 //!< Start the iterator at the head of the list.
135 static const IterStart kHead_IterStart = INHERITED::kHead_IterStart;
136 //!< Start the iterator at the tail of the list.
137 static const IterStart kTail_IterStart = INHERITED::kTail_IterStart;
138
139 Iter() {}
140
141 Iter(const SkTLList& list, IterStart start) {
142 INHERITED::init(list.fList, start);
143 }
144
145 T* init(const SkTLList& list, IterStart start) {
146 return this->nodeToObj(INHERITED::init(list.fList, start));
147 }
148
149 T* get() { return this->nodeToObj(INHERITED::get()); }
150
151 T* next() { return this->nodeToObj(INHERITED::next()); }
152
153 T* prev() { return this->nodeToObj(INHERITED::prev()); }
154
155 Iter& operator= (const Iter& iter) { INHERITED::operator=(iter); return *this; }
156
157 private:
158 T* nodeToObj(Node* node) {
159 if (NULL != node) {
160 return reinterpret_cast<T*>(node->fObj);
161 } else {
162 return NULL;
163 }
164 }
165 };
166
167private:
168 struct Block {
169 int fNodesInUse;
170 Node fNodes[1];
171 };
172
173 size_t blockSize() const { return sizeof(Block) + sizeof(Node) * (fAllocCnt-1); }
174
175 Node* createNode() {
176 Node* node = fFreeList.head();
177 if (NULL != node) {
178 fFreeList.remove(node);
179 ++node->fBlock->fNodesInUse;
180 } else {
181 Block* block = reinterpret_cast<Block*>(sk_malloc_flags(this->blockSize(), 0));
182 node = &block->fNodes[0];
183 SkNEW_PLACEMENT(node, Node);
184 node->fBlock = block;
185 block->fNodesInUse = 1;
186 for (int i = 1; i < fAllocCnt; ++i) {
187 SkNEW_PLACEMENT(block->fNodes + i, Node);
188 fFreeList.addToHead(block->fNodes + i);
189 block->fNodes[i].fBlock = block;
190 }
191 }
192 ++fCount;
193 return node;
194 }
195
196 void removeNode(Node* node) {
197 SkASSERT(NULL != node);
198 fList.remove(node);
199 reinterpret_cast<T*>(node->fObj)->~T();
200 if (0 == --node->fBlock->fNodesInUse) {
201 // Delete a block when it no longer has any nodes in use to reduce memory consumption.
202 Block* block = node->fBlock;
203 for (int i = 0; i < fAllocCnt; ++i) {
204 if (block->fNodes + i != node) {
205 fFreeList.remove(block->fNodes + i);
206 }
207 block->fNodes[i].~Node();
208 }
209 sk_free(block);
210 } else {
211 fFreeList.addToHead(node);
212 }
213 --fCount;
214 this->validate();
215 }
216
217 void validate() const {
218#ifdef SK_DEBUG
219 SkASSERT((0 == fCount) == fList.isEmpty());
220 SkASSERT((0 != fCount) || fFreeList.isEmpty());
221
222 fList.validate();
223 fFreeList.validate();
224 typename NodeList::Iter iter;
225 Node* freeNode = iter.init(fFreeList, Iter::kHead_IterStart);
226 while (freeNode) {
227 SkASSERT(fFreeList.isInList(freeNode));
228 Block* block = freeNode->fBlock;
229 SkASSERT(block->fNodesInUse > 0 && block->fNodesInUse < fAllocCnt);
230
231 int activeCnt = 0;
232 int freeCnt = 0;
233 for (int i = 0; i < fAllocCnt; ++i) {
234 bool free = fFreeList.isInList(block->fNodes + i);
235 bool active = fList.isInList(block->fNodes + i);
236 SkASSERT(free != active);
237 activeCnt += active;
238 freeCnt += free;
239 }
240 SkASSERT(activeCnt == block->fNodesInUse);
241 freeNode = iter.next();
242 }
243
244 int count = 0;
245 Node* activeNode = iter.init(fList, Iter::kHead_IterStart);
246 while (activeNode) {
247 ++count;
248 SkASSERT(fList.isInList(activeNode));
249 Block* block = activeNode->fBlock;
250 SkASSERT(block->fNodesInUse > 0 && block->fNodesInUse <= fAllocCnt);
251
252 int activeCnt = 0;
253 int freeCnt = 0;
254 for (int i = 0; i < fAllocCnt; ++i) {
255 bool free = fFreeList.isInList(block->fNodes + i);
256 bool active = fList.isInList(block->fNodes + i);
257 SkASSERT(free != active);
258 activeCnt += active;
259 freeCnt += free;
260 }
261 SkASSERT(activeCnt == block->fNodesInUse);
262 activeNode = iter.next();
263 }
264 SkASSERT(count == fCount);
265#endif
266 }
267
268 NodeList fList;
269 NodeList fFreeList;
270 int fCount;
271 int fAllocCnt;
272};