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 |
11 #include "SkTInternalLList.h" | 11 #include "SkTInternalLList.h" |
12 #include "SkTypes.h" | 12 #include "SkTypes.h" |
13 #include <utility> | 13 #include <utility> |
14 | 14 |
15 template <typename T> class SkTLList; | |
16 template <typename T> | |
17 inline void* operator new(size_t, SkTLList<T>* list, | |
18 typename SkTLList<T>::Placement placement, | |
19 const typename SkTLList<T>::Iter& location); | |
20 | |
21 /** Doubly-linked list of objects. The objects' lifetimes are controlled by the
list. I.e. the | 15 /** Doubly-linked list of objects. The objects' lifetimes are controlled by the
list. I.e. the |
22 the list creates the objects and they are deleted upon removal. This class b
lock-allocates | 16 the list creates the objects and they are deleted upon removal. This class b
lock-allocates |
23 space for entries based on a param passed to the constructor. | 17 space for entries based on a param passed to the constructor. |
24 | 18 |
25 Elements of the list can be constructed in place using the following macros: | 19 Elements of the list can be constructed in place using the following macros: |
26 SkNEW_INSERT_IN_LLIST_BEFORE(list, location, type_name, args) | 20 SkNEW_INSERT_IN_LLIST_BEFORE(list, location, type_name, args) |
27 SkNEW_INSERT_IN_LLIST_AFTER(list, location, type_name, args) | 21 SkNEW_INSERT_IN_LLIST_AFTER(list, location, type_name, args) |
28 where list is a SkTLList<type_name>*, location is an iterator, and args is t
he paren-surrounded | 22 where list is a SkTLList<type_name>*, location is an iterator, and args is t
he paren-surrounded |
29 constructor arguments for type_name. These macros behave like addBefore() an
d addAfter(). | 23 constructor arguments for type_name. These macros behave like addBefore() an
d addAfter(). |
| 24 |
| 25 allocCnt is the number of objects to allocate as a group. In the worst case
fragmentation |
| 26 each object is using the space required for allocCnt unfragmented objects. |
30 */ | 27 */ |
31 template <typename T> | 28 template <typename T, unsigned int N> class SkTLList : SkNoncopyable { |
32 class SkTLList : SkNoncopyable { | |
33 private: | 29 private: |
34 struct Block; | 30 struct Block; |
35 struct Node { | 31 struct Node { |
36 char fObj[sizeof(T)]; | 32 char fObj[sizeof(T)]; |
37 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Node); | 33 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Node); |
38 Block* fBlock; // owning block. | 34 Block* fBlock; // owning block. |
39 }; | 35 }; |
40 typedef SkTInternalLList<Node> NodeList; | 36 typedef SkTInternalLList<Node> NodeList; |
41 | 37 |
42 public: | 38 public: |
43 | |
44 class Iter; | 39 class Iter; |
45 | 40 |
46 /** allocCnt is the number of objects to allocate as a group. In the worst c
ase fragmentation | 41 SkTLList() : fCount(0) { |
47 each object is using the space required for allocCnt unfragmented object
s. */ | |
48 SkTLList(int allocCnt = 1) : fCount(0), fAllocCnt(allocCnt) { | |
49 SkASSERT(allocCnt > 0); | |
50 this->validate(); | 42 this->validate(); |
51 } | 43 } |
52 | 44 |
53 ~SkTLList() { | 45 ~SkTLList() { |
54 this->validate(); | 46 this->validate(); |
55 typename NodeList::Iter iter; | 47 typename NodeList::Iter iter; |
56 Node* node = iter.init(fList, Iter::kHead_IterStart); | 48 Node* node = iter.init(fList, Iter::kHead_IterStart); |
57 while (node) { | 49 while (node) { |
58 SkTCast<T*>(node->fObj)->~T(); | 50 SkTCast<T*>(node->fObj)->~T(); |
59 Block* block = node->fBlock; | 51 Block* block = node->fBlock; |
60 node = iter.next(); | 52 node = iter.next(); |
61 if (0 == --block->fNodesInUse) { | 53 if (0 == --block->fNodesInUse) { |
62 for (int i = 0; i < fAllocCnt; ++i) { | 54 for (unsigned int i = 0; i < N; ++i) { |
63 block->fNodes[i].~Node(); | 55 block->fNodes[i].~Node(); |
64 } | 56 } |
65 sk_free(block); | 57 sk_free(block); |
66 } | 58 } |
67 } | 59 } |
68 } | 60 } |
69 | 61 |
70 /** Adds a new element to the list at the head. */ | 62 /** Adds a new element to the list at the head. */ |
71 template <typename... Args> T* addToHead(Args&&... args) { | 63 template <typename... Args> T* addToHead(Args&&... args) { |
72 this->validate(); | 64 this->validate(); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 return reinterpret_cast<T*>(node->fObj); | 206 return reinterpret_cast<T*>(node->fObj); |
215 } else { | 207 } else { |
216 return nullptr; | 208 return nullptr; |
217 } | 209 } |
218 } | 210 } |
219 }; | 211 }; |
220 | 212 |
221 private: | 213 private: |
222 struct Block { | 214 struct Block { |
223 int fNodesInUse; | 215 int fNodesInUse; |
224 Node fNodes[1]; | 216 Node fNodes[N]; |
225 }; | 217 }; |
226 | 218 |
227 size_t blockSize() const { return sizeof(Block) + sizeof(Node) * (fAllocCnt-
1); } | |
228 | |
229 Node* createNode() { | 219 Node* createNode() { |
230 Node* node = fFreeList.head(); | 220 Node* node = fFreeList.head(); |
231 if (node) { | 221 if (node) { |
232 fFreeList.remove(node); | 222 fFreeList.remove(node); |
233 ++node->fBlock->fNodesInUse; | 223 ++node->fBlock->fNodesInUse; |
234 } else { | 224 } else { |
235 Block* block = reinterpret_cast<Block*>(sk_malloc_throw(this->blockS
ize())); | 225 Block* block = reinterpret_cast<Block*>(sk_malloc_throw(sizeof(Block
))); |
236 node = &block->fNodes[0]; | 226 node = &block->fNodes[0]; |
237 new (node) Node; | 227 new (node) Node; |
238 node->fBlock = block; | 228 node->fBlock = block; |
239 block->fNodesInUse = 1; | 229 block->fNodesInUse = 1; |
240 for (int i = 1; i < fAllocCnt; ++i) { | 230 for (unsigned int i = 1; i < N; ++i) { |
241 new (block->fNodes + i) Node; | 231 new (block->fNodes + i) Node; |
242 fFreeList.addToHead(block->fNodes + i); | 232 fFreeList.addToHead(block->fNodes + i); |
243 block->fNodes[i].fBlock = block; | 233 block->fNodes[i].fBlock = block; |
244 } | 234 } |
245 } | 235 } |
246 ++fCount; | 236 ++fCount; |
247 return node; | 237 return node; |
248 } | 238 } |
249 | 239 |
250 void removeNode(Node* node) { | 240 void removeNode(Node* node) { |
251 SkASSERT(node); | 241 SkASSERT(node); |
252 fList.remove(node); | 242 fList.remove(node); |
253 SkTCast<T*>(node->fObj)->~T(); | 243 SkTCast<T*>(node->fObj)->~T(); |
254 if (0 == --node->fBlock->fNodesInUse) { | 244 if (0 == --node->fBlock->fNodesInUse) { |
255 Block* block = node->fBlock; | 245 Block* block = node->fBlock; |
256 for (int i = 0; i < fAllocCnt; ++i) { | 246 for (unsigned int i = 0; i < N; ++i) { |
257 if (block->fNodes + i != node) { | 247 if (block->fNodes + i != node) { |
258 fFreeList.remove(block->fNodes + i); | 248 fFreeList.remove(block->fNodes + i); |
259 } | 249 } |
260 block->fNodes[i].~Node(); | 250 block->fNodes[i].~Node(); |
261 } | 251 } |
262 sk_free(block); | 252 sk_free(block); |
263 } else { | 253 } else { |
264 fFreeList.addToHead(node); | 254 fFreeList.addToHead(node); |
265 } | 255 } |
266 --fCount; | 256 --fCount; |
267 this->validate(); | 257 this->validate(); |
268 } | 258 } |
269 | 259 |
270 void validate() const { | 260 void validate() const { |
271 #ifdef SK_DEBUG | 261 #ifdef SK_DEBUG |
272 SkASSERT((0 == fCount) == fList.isEmpty()); | 262 SkASSERT((0 == fCount) == fList.isEmpty()); |
273 SkASSERT((0 != fCount) || fFreeList.isEmpty()); | 263 SkASSERT((0 != fCount) || fFreeList.isEmpty()); |
274 | 264 |
275 fList.validate(); | 265 fList.validate(); |
276 fFreeList.validate(); | 266 fFreeList.validate(); |
277 typename NodeList::Iter iter; | 267 typename NodeList::Iter iter; |
278 Node* freeNode = iter.init(fFreeList, Iter::kHead_IterStart); | 268 Node* freeNode = iter.init(fFreeList, Iter::kHead_IterStart); |
279 while (freeNode) { | 269 while (freeNode) { |
280 SkASSERT(fFreeList.isInList(freeNode)); | 270 SkASSERT(fFreeList.isInList(freeNode)); |
281 Block* block = freeNode->fBlock; | 271 Block* block = freeNode->fBlock; |
282 SkASSERT(block->fNodesInUse > 0 && block->fNodesInUse < fAllocCnt); | 272 SkASSERT(block->fNodesInUse > 0 && (unsigned)block->fNodesInUse < N)
; |
283 | 273 |
284 int activeCnt = 0; | 274 int activeCnt = 0; |
285 int freeCnt = 0; | 275 int freeCnt = 0; |
286 for (int i = 0; i < fAllocCnt; ++i) { | 276 for (unsigned int i = 0; i < N; ++i) { |
287 bool free = fFreeList.isInList(block->fNodes + i); | 277 bool free = fFreeList.isInList(block->fNodes + i); |
288 bool active = fList.isInList(block->fNodes + i); | 278 bool active = fList.isInList(block->fNodes + i); |
289 SkASSERT(free != active); | 279 SkASSERT(free != active); |
290 activeCnt += active; | 280 activeCnt += active; |
291 freeCnt += free; | 281 freeCnt += free; |
292 } | 282 } |
293 SkASSERT(activeCnt == block->fNodesInUse); | 283 SkASSERT(activeCnt == block->fNodesInUse); |
294 freeNode = iter.next(); | 284 freeNode = iter.next(); |
295 } | 285 } |
296 | 286 |
297 int count = 0; | 287 int count = 0; |
298 Node* activeNode = iter.init(fList, Iter::kHead_IterStart); | 288 Node* activeNode = iter.init(fList, Iter::kHead_IterStart); |
299 while (activeNode) { | 289 while (activeNode) { |
300 ++count; | 290 ++count; |
301 SkASSERT(fList.isInList(activeNode)); | 291 SkASSERT(fList.isInList(activeNode)); |
302 Block* block = activeNode->fBlock; | 292 Block* block = activeNode->fBlock; |
303 SkASSERT(block->fNodesInUse > 0 && block->fNodesInUse <= fAllocCnt); | 293 SkASSERT(block->fNodesInUse > 0 && (unsigned)block->fNodesInUse <= N
); |
304 | 294 |
305 int activeCnt = 0; | 295 int activeCnt = 0; |
306 int freeCnt = 0; | 296 int freeCnt = 0; |
307 for (int i = 0; i < fAllocCnt; ++i) { | 297 for (unsigned int i = 0; i < N; ++i) { |
308 bool free = fFreeList.isInList(block->fNodes + i); | 298 bool free = fFreeList.isInList(block->fNodes + i); |
309 bool active = fList.isInList(block->fNodes + i); | 299 bool active = fList.isInList(block->fNodes + i); |
310 SkASSERT(free != active); | 300 SkASSERT(free != active); |
311 activeCnt += active; | 301 activeCnt += active; |
312 freeCnt += free; | 302 freeCnt += free; |
313 } | 303 } |
314 SkASSERT(activeCnt == block->fNodesInUse); | 304 SkASSERT(activeCnt == block->fNodesInUse); |
315 activeNode = iter.next(); | 305 activeNode = iter.next(); |
316 } | 306 } |
317 SkASSERT(count == fCount); | 307 SkASSERT(count == fCount); |
318 #endif | 308 #endif |
319 } | 309 } |
320 | 310 |
321 NodeList fList; | 311 NodeList fList; |
322 NodeList fFreeList; | 312 NodeList fFreeList; |
323 int fCount; | 313 int fCount; |
324 int fAllocCnt; | |
325 | |
326 }; | 314 }; |
327 | 315 |
328 #endif | 316 #endif |
OLD | NEW |