Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2014 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 #ifndef SkStackAllocator_DEFINED | |
| 9 #define SkStackAllocator_DEFINED | |
| 10 | |
| 11 #include "SkTDArray.h" | |
| 12 #include "SkTypes.h" | |
| 13 | |
| 14 /* | |
| 15 * Helper for using an SkStackAllocator to create a new object. | |
| 16 * @param ptr Raw pointer to typeName. It should be pointing to NULL, since | |
| 17 * its old value will be ignored. After this macro finishes, it will point | |
| 18 * to a new object of type typeName, allocated by the SkStackAllocator, | |
| 19 * which will handle deleting it. | |
| 20 * @param allocator Reference to an SkStackAllocator. Will be used to allocate | |
| 21 * an object of type typeName. It handles deleting the new object in its | |
| 22 * destructor. | |
| 23 * @param typeName type of the new object to create. | |
| 24 * @param args Arguments to pass to the constructor of the new object, in | |
| 25 * parentheses, or () for the default constructor. | |
| 26 * | |
| 27 * Sample usage: | |
| 28 * <code> | |
| 29 * SkStackAllocator<100> alloc; | |
| 30 * SkBlitter* blitter (NULL); | |
| 31 * SkSTACK_ALLOCATE(blitter, alloc, SkNullBlitter, ()); | |
| 32 * </code> | |
| 33 * | |
| 34 * After this line, blitter points to a new SkNullBlitter object, which will | |
| 35 * be destroyed when alloc goes out of scope. | |
| 36 */ | |
| 37 #define SkSTACK_ALLOCATE(ptr, allocator, typeName, args) \ | |
| 38 void* buf = allocator.reserveT<typeName>(); \ | |
| 39 SkNEW_PLACEMENT_ARGS(buf, typeName, args); \ | |
| 40 ptr = static_cast<typeName*>(buf) | |
| 41 | |
| 42 // Used by SkStackAllocator to call the destructor for objects it has | |
| 43 // allocated. | |
| 44 template<typename T> void destroyT(void* ptr) { | |
| 45 static_cast<T*>(ptr)->~T(); | |
| 46 } | |
| 47 | |
| 48 /* | |
| 49 * Template class for allocating small (as defined by kSize) objects on the | |
|
mtklein
2014/02/27 23:40:54
This sort of reads like we'll be able to allocate
scroggo
2014/03/05 20:25:52
Correct. I've updated the comment. Sound better?
| |
| 50 * stack. If an object is larger than kSize, it will be allocated on the | |
| 51 * heap, This class's destructor will handle calling the destructor for each | |
| 52 * object it allocated and freeing its memory. | |
| 53 */ | |
| 54 template<size_t kSize> class SkStackAllocator : public SkNoncopyable { | |
|
mtklein
2014/02/27 23:40:54
It looked like we're generally using this to alloc
scroggo
2014/03/05 20:25:52
Actually, no. The Sk3DBlitter will be allocated by
| |
| 55 public: | |
| 56 SkStackAllocator() | |
| 57 : fStorageUsed(0) | |
| 58 {} | |
| 59 | |
| 60 ~SkStackAllocator() { | |
| 61 // Destruct in reverse order, in case an earlier object points to a | |
| 62 // later object. | |
| 63 while (fObjects.count() > 0) { | |
| 64 Triple triple; | |
| 65 fObjects.pop(&triple); | |
| 66 triple.fKillProc(triple.fObj); | |
| 67 // Safe to do if fObj is in fStorage, since fHeapStorage will | |
| 68 // point to NULL. | |
| 69 sk_free(triple.fHeapStorage); | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 /* | |
| 74 * Create and return space for a T. The space will be on the stack if | |
| 75 * there is room, or on the heap otherwise. Either way, this class will | |
| 76 * call ~T() in its destructor and free the heap allocation if necessary. | |
| 77 * | |
| 78 * The caller MUST create a new T in the returned buffer (using | |
| 79 * SkNEW_PLACEMENT or SkNEW_PLACEMENT_ARGS), as this class will call ~T() | |
| 80 * in its destructor. (FIXME: Can we pass T's constructor's arguments to | |
| 81 * this function so we can create the object as well?) | |
|
bungeman-skia
2014/02/27 18:26:01
With perfect forwarding in c++11 you can. With c++
mtklein
2014/02/27 18:51:02
A good compromise is to make a few versions:
temp
scroggo
2014/03/05 20:25:52
Done.
| |
| 82 */ | |
| 83 template<typename T> void* reserveT() { | |
| 84 const size_t storageRemaining = SkAlign4(kSize) - fStorageUsed; | |
| 85 const size_t storageRequired = SkAlign4(sizeof(T)); | |
| 86 Triple triple; | |
| 87 if (storageRequired > storageRemaining) { | |
| 88 // Allocate on the heap | |
| 89 triple.fHeapStorage = sk_malloc_throw(storageRequired); | |
| 90 triple.fObj = static_cast<void*>(triple.fHeapStorage); | |
| 91 } else { | |
| 92 // There is space in fStorage. | |
| 93 triple.fHeapStorage = NULL; | |
| 94 SkASSERT(SkIsAlign4(fStorageUsed)); | |
| 95 triple.fObj = static_cast<void*>(fStorage + (fStorageUsed >> 2)); | |
| 96 fStorageUsed += storageRequired; | |
| 97 } | |
| 98 triple.fKillProc = destroyT<T>; | |
| 99 fObjects.push(triple); | |
| 100 return triple.fObj; | |
| 101 } | |
| 102 | |
| 103 private: | |
| 104 struct Triple { | |
| 105 void* fObj; | |
|
mtklein
2014/02/27 23:40:54
If you really want to keep things small, we might
scroggo
2014/03/05 20:25:52
Interesting idea! Are we guaranteed the bottom bit
| |
| 106 void* fHeapStorage; | |
| 107 void (*fKillProc)(void*); | |
| 108 | |
| 109 }; | |
| 110 | |
| 111 // Number of bytes used so far. | |
| 112 size_t fStorageUsed; | |
| 113 SkTDArray<Triple> fObjects; | |
| 114 // Pad the storage size to be 4-byte aligned. | |
| 115 uint32_t fStorage[SkAlign4(kSize) >> 2]; | |
|
mtklein
2014/02/27 23:40:54
Consider storing everything in fStorage? Does it
scroggo
2014/03/05 20:25:52
That's a very good point. I've removed the SkTDArr
| |
| 116 }; | |
| 117 // This class only makes sense on the stack. | |
|
mtklein
2014/02/27 23:40:54
This doesn't strictly have to be on the stack righ
scroggo
2014/03/05 20:25:52
Agreed. Renamed SkSmallAllocator.
And I've remove
| |
| 118 #define SkStackAllocator(...) SK_REQUIRE_LOCAL_VAR(SkStackAllocator) | |
| 119 | |
| 120 #endif // SkStackAllocator_DEFINED | |
| OLD | NEW |