| 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 |