OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkTLList_DEFINED | 8 #ifndef SkTLList_DEFINED |
9 #define SkTLList_DEFINED | 9 #define SkTLList_DEFINED |
10 | 10 |
(...skipping 20 matching lines...) Expand all Loading... |
31 struct Node { | 31 struct Node { |
32 char fObj[sizeof(T)]; | 32 char fObj[sizeof(T)]; |
33 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Node); | 33 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Node); |
34 Block* fBlock; // owning block. | 34 Block* fBlock; // owning block. |
35 }; | 35 }; |
36 typedef SkTInternalLList<Node> NodeList; | 36 typedef SkTInternalLList<Node> NodeList; |
37 | 37 |
38 public: | 38 public: |
39 class Iter; | 39 class Iter; |
40 | 40 |
41 SkTLList() : fCount(0) { | 41 // Having fCount initialized to -1 indicates that the first time we attempt
to grab a free node |
42 fFirstBlock.fNodesInUse = 0; | 42 // all the nodes in the pre-allocated first block need to be inserted into t
he free list. This |
43 for (unsigned int i = 0; i < N; ++i) { | 43 // allows us to skip that loop in instances when the list is never populated
. |
44 fFreeList.addToHead(fFirstBlock.fNodes + i); | 44 SkTLList() : fCount(-1) {} |
45 fFirstBlock.fNodes[i].fBlock = &fFirstBlock; | |
46 } | |
47 this->validate(); | |
48 } | |
49 | 45 |
50 ~SkTLList() { | 46 ~SkTLList() { |
51 this->validate(); | 47 this->validate(); |
52 typename NodeList::Iter iter; | 48 typename NodeList::Iter iter; |
53 Node* node = iter.init(fList, Iter::kHead_IterStart); | 49 Node* node = iter.init(fList, Iter::kHead_IterStart); |
54 while (node) { | 50 while (node) { |
55 SkTCast<T*>(node->fObj)->~T(); | 51 SkTCast<T*>(node->fObj)->~T(); |
56 Block* block = node->fBlock; | 52 Block* block = node->fBlock; |
57 node = iter.next(); | 53 node = iter.next(); |
58 if (0 == --block->fNodesInUse) { | 54 if (0 == --block->fNodesInUse) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 | 137 |
142 void reset() { | 138 void reset() { |
143 this->validate(); | 139 this->validate(); |
144 Iter iter(*this, Iter::kHead_IterStart); | 140 Iter iter(*this, Iter::kHead_IterStart); |
145 while (iter.get()) { | 141 while (iter.get()) { |
146 Iter next = iter; | 142 Iter next = iter; |
147 next.next(); | 143 next.next(); |
148 this->remove(iter.get()); | 144 this->remove(iter.get()); |
149 iter = next; | 145 iter = next; |
150 } | 146 } |
151 SkASSERT(0 == fCount); | 147 SkASSERT(0 == fCount || -1 == fCount); |
152 this->validate(); | 148 this->validate(); |
153 } | 149 } |
154 | 150 |
155 int count() const { return fCount; } | 151 int count() const { return SkTMax(fCount ,0); } |
156 bool isEmpty() const { this->validate(); return 0 == fCount; } | 152 bool isEmpty() const { this->validate(); return 0 == fCount || -1 == fCount;
} |
157 | 153 |
158 bool operator== (const SkTLList& list) const { | 154 bool operator== (const SkTLList& list) const { |
159 if (this == &list) { | 155 if (this == &list) { |
160 return true; | 156 return true; |
161 } | 157 } |
162 if (fCount != list.fCount) { | 158 // Call count() rather than use fCount because an empty list may have fC
ount = 0 or -1. |
| 159 if (this->count() != list.count()) { |
163 return false; | 160 return false; |
164 } | 161 } |
165 for (Iter a(*this, Iter::kHead_IterStart), b(list, Iter::kHead_IterStart
); | 162 for (Iter a(*this, Iter::kHead_IterStart), b(list, Iter::kHead_IterStart
); |
166 a.get(); | 163 a.get(); |
167 a.next(), b.next()) { | 164 a.next(), b.next()) { |
168 SkASSERT(b.get()); // already checked that counts match. | 165 SkASSERT(b.get()); // already checked that counts match. |
169 if (!(*a.get() == *b.get())) { | 166 if (!(*a.get() == *b.get())) { |
170 return false; | 167 return false; |
171 } | 168 } |
172 } | 169 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 } | 213 } |
217 } | 214 } |
218 }; | 215 }; |
219 | 216 |
220 private: | 217 private: |
221 struct Block { | 218 struct Block { |
222 int fNodesInUse; | 219 int fNodesInUse; |
223 Node fNodes[N]; | 220 Node fNodes[N]; |
224 }; | 221 }; |
225 | 222 |
| 223 void delayedInit() { |
| 224 SkASSERT(-1 == fCount); |
| 225 fFirstBlock.fNodesInUse = 0; |
| 226 for (unsigned int i = 0; i < N; ++i) { |
| 227 fFreeList.addToHead(fFirstBlock.fNodes + i); |
| 228 fFirstBlock.fNodes[i].fBlock = &fFirstBlock; |
| 229 } |
| 230 fCount = 0; |
| 231 this->validate(); |
| 232 } |
| 233 |
226 Node* createNode() { | 234 Node* createNode() { |
| 235 if (-1 == fCount) { |
| 236 this->delayedInit(); |
| 237 } |
227 Node* node = fFreeList.head(); | 238 Node* node = fFreeList.head(); |
228 if (node) { | 239 if (node) { |
229 fFreeList.remove(node); | 240 fFreeList.remove(node); |
230 ++node->fBlock->fNodesInUse; | 241 ++node->fBlock->fNodesInUse; |
231 } else { | 242 } else { |
232 // Should not get here when count == 0 because we always have the pr
eallocated first | 243 // Should not get here when count == 0 because we always have the pr
eallocated first |
233 // block. | 244 // block. |
234 SkASSERT(fCount > 0); | 245 SkASSERT(fCount > 0); |
235 Block* block = reinterpret_cast<Block*>(sk_malloc_throw(sizeof(Block
))); | 246 Block* block = reinterpret_cast<Block*>(sk_malloc_throw(sizeof(Block
))); |
236 node = &block->fNodes[0]; | 247 node = &block->fNodes[0]; |
(...skipping 26 matching lines...) Expand all Loading... |
263 sk_free(block); | 274 sk_free(block); |
264 } else { | 275 } else { |
265 fFreeList.addToHead(node); | 276 fFreeList.addToHead(node); |
266 } | 277 } |
267 --fCount; | 278 --fCount; |
268 this->validate(); | 279 this->validate(); |
269 } | 280 } |
270 | 281 |
271 void validate() const { | 282 void validate() const { |
272 #ifdef SK_DEBUG | 283 #ifdef SK_DEBUG |
273 SkASSERT((0 == fCount) == fList.isEmpty()); | 284 bool isEmpty = false; |
274 if (0 == fCount) { | 285 if (-1 == fCount) { |
| 286 // We should not yet have initialized the free list. |
| 287 SkASSERT(fFreeList.isEmpty()); |
| 288 isEmpty = true; |
| 289 } else if (0 == fCount) { |
275 // Should only have the nodes from the first block in the free list. | 290 // Should only have the nodes from the first block in the free list. |
276 SkASSERT(fFreeList.countEntries() == N); | 291 SkASSERT(fFreeList.countEntries() == N); |
| 292 isEmpty = true; |
277 } | 293 } |
| 294 SkASSERT(isEmpty == fList.isEmpty()); |
278 fList.validate(); | 295 fList.validate(); |
279 fFreeList.validate(); | 296 fFreeList.validate(); |
280 typename NodeList::Iter iter; | 297 typename NodeList::Iter iter; |
281 Node* freeNode = iter.init(fFreeList, Iter::kHead_IterStart); | 298 Node* freeNode = iter.init(fFreeList, Iter::kHead_IterStart); |
282 while (freeNode) { | 299 while (freeNode) { |
283 SkASSERT(fFreeList.isInList(freeNode)); | 300 SkASSERT(fFreeList.isInList(freeNode)); |
284 Block* block = freeNode->fBlock; | 301 Block* block = freeNode->fBlock; |
285 // Only the first block is allowed to have all its nodes in the free
list. | 302 // Only the first block is allowed to have all its nodes in the free
list. |
286 SkASSERT(block->fNodesInUse > 0 || block == &fFirstBlock); | 303 SkASSERT(block->fNodesInUse > 0 || block == &fFirstBlock); |
287 SkASSERT((unsigned)block->fNodesInUse < N); | 304 SkASSERT((unsigned)block->fNodesInUse < N); |
(...skipping 23 matching lines...) Expand all Loading... |
311 for (unsigned int i = 0; i < N; ++i) { | 328 for (unsigned int i = 0; i < N; ++i) { |
312 bool free = fFreeList.isInList(block->fNodes + i); | 329 bool free = fFreeList.isInList(block->fNodes + i); |
313 bool active = fList.isInList(block->fNodes + i); | 330 bool active = fList.isInList(block->fNodes + i); |
314 SkASSERT(free != active); | 331 SkASSERT(free != active); |
315 activeCnt += active; | 332 activeCnt += active; |
316 freeCnt += free; | 333 freeCnt += free; |
317 } | 334 } |
318 SkASSERT(activeCnt == block->fNodesInUse); | 335 SkASSERT(activeCnt == block->fNodesInUse); |
319 activeNode = iter.next(); | 336 activeNode = iter.next(); |
320 } | 337 } |
321 SkASSERT(count == fCount); | 338 SkASSERT(count == fCount || (0 == count && -1 == fCount)); |
322 #endif | 339 #endif |
323 } | 340 } |
324 | 341 |
325 NodeList fList; | 342 NodeList fList; |
326 NodeList fFreeList; | 343 NodeList fFreeList; |
327 Block fFirstBlock; | 344 Block fFirstBlock; |
328 int fCount; | 345 int fCount; |
329 }; | 346 }; |
330 | 347 |
331 #endif | 348 #endif |
OLD | NEW |