| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google, Inc | 2 * Copyright 2014 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 SkSmallAllocator_DEFINED | 8 #ifndef SkSmallAllocator_DEFINED |
| 9 #define SkSmallAllocator_DEFINED | 9 #define SkSmallAllocator_DEFINED |
| 10 | 10 |
| 11 #include "SkTDArray.h" | 11 #include "SkTDArray.h" |
| 12 #include "SkTypes.h" | 12 #include "SkTypes.h" |
| 13 | 13 |
| 14 // Used by SkSmallAllocator to call the destructor for objects it has | 14 #include <new> |
| 15 // allocated. | |
| 16 template<typename T> void destroyT(void* ptr) { | |
| 17 static_cast<T*>(ptr)->~T(); | |
| 18 } | |
| 19 | 15 |
| 20 /* | 16 /* |
| 21 * Template class for allocating small objects without additional heap memory | 17 * Template class for allocating small objects without additional heap memory |
| 22 * allocations. kMaxObjects is a hard limit on the number of objects that can | 18 * allocations. kMaxObjects is a hard limit on the number of objects that can |
| 23 * be allocated using this class. After that, attempts to create more objects | 19 * be allocated using this class. After that, attempts to create more objects |
| 24 * with this class will assert and return nullptr. | 20 * with this class will assert and return nullptr. |
| 25 * kTotalBytes is the total number of bytes provided for storage for all | 21 * kTotalBytes is the total number of bytes provided for storage for all |
| 26 * objects created by this allocator. If an object to be created is larger | 22 * objects created by this allocator. If an object to be created is larger |
| 27 * than the storage (minus storage already used), it will be allocated on the | 23 * than the storage (minus storage already used), it will be allocated on the |
| 28 * heap. This class's destructor will handle calling the destructor for each | 24 * heap. This class's destructor will handle calling the destructor for each |
| (...skipping 16 matching lines...) Expand all Loading... |
| 45 rec->fKillProc(rec->fObj); | 41 rec->fKillProc(rec->fObj); |
| 46 // Safe to do if fObj is in fStorage, since fHeapStorage will | 42 // Safe to do if fObj is in fStorage, since fHeapStorage will |
| 47 // point to nullptr. | 43 // point to nullptr. |
| 48 sk_free(rec->fHeapStorage); | 44 sk_free(rec->fHeapStorage); |
| 49 } | 45 } |
| 50 } | 46 } |
| 51 | 47 |
| 52 /* | 48 /* |
| 53 * Create a new object of type T. Its lifetime will be handled by this | 49 * Create a new object of type T. Its lifetime will be handled by this |
| 54 * SkSmallAllocator. | 50 * SkSmallAllocator. |
| 55 * Each version behaves the same but takes a different number of | |
| 56 * arguments. | |
| 57 * Note: If kMaxObjects have been created by this SkSmallAllocator, nullptr | 51 * Note: If kMaxObjects have been created by this SkSmallAllocator, nullptr |
| 58 * will be returned. | 52 * will be returned. |
| 59 */ | 53 */ |
| 60 template<typename T> | 54 template<typename T, typename... Args> |
| 61 T* createT() { | 55 T* createT(const Args&... args) { |
| 62 void* buf = this->reserveT<T>(); | 56 void* buf = this->reserveT<T>(); |
| 63 if (nullptr == buf) { | 57 if (nullptr == buf) { |
| 64 return nullptr; | 58 return nullptr; |
| 65 } | 59 } |
| 66 new (buf) T; | 60 return new (buf) T(args...); |
| 67 return static_cast<T*>(buf); | |
| 68 } | |
| 69 | |
| 70 template<typename T, typename A1> T* createT(const A1& a1) { | |
| 71 void* buf = this->reserveT<T>(); | |
| 72 if (nullptr == buf) { | |
| 73 return nullptr; | |
| 74 } | |
| 75 new (buf) T(a1); | |
| 76 return static_cast<T*>(buf); | |
| 77 } | |
| 78 | |
| 79 template<typename T, typename A1, typename A2> | |
| 80 T* createT(const A1& a1, const A2& a2) { | |
| 81 void* buf = this->reserveT<T>(); | |
| 82 if (nullptr == buf) { | |
| 83 return nullptr; | |
| 84 } | |
| 85 new (buf) T(a1, a2); | |
| 86 return static_cast<T*>(buf); | |
| 87 } | |
| 88 | |
| 89 template<typename T, typename A1, typename A2, typename A3> | |
| 90 T* createT(const A1& a1, const A2& a2, const A3& a3) { | |
| 91 void* buf = this->reserveT<T>(); | |
| 92 if (nullptr == buf) { | |
| 93 return nullptr; | |
| 94 } | |
| 95 new (buf) T(a1, a2, a3); | |
| 96 return static_cast<T*>(buf); | |
| 97 } | |
| 98 | |
| 99 template<typename T, typename A1, typename A2, typename A3, typename A4> | |
| 100 T* createT(const A1& a1, const A2& a2, const A3& a3, const A4& a4) { | |
| 101 void* buf = this->reserveT<T>(); | |
| 102 if (nullptr == buf) { | |
| 103 return nullptr; | |
| 104 } | |
| 105 new (buf) T(a1, a2, a3, a4); | |
| 106 return static_cast<T*>(buf); | |
| 107 } | 61 } |
| 108 | 62 |
| 109 /* | 63 /* |
| 110 * Reserve a specified amount of space (must be enough space for one T). | 64 * Reserve a specified amount of space (must be enough space for one T). |
| 111 * The space will be in fStorage if there is room, or on the heap otherwise
. | 65 * The space will be in fStorage if there is room, or on the heap otherwise
. |
| 112 * Either way, this class will call ~T() in its destructor and free the hea
p | 66 * Either way, this class will call ~T() in its destructor and free the hea
p |
| 113 * allocation if necessary. | 67 * allocation if necessary. |
| 114 * Unlike createT(), this method will not call the constructor of T. | 68 * Unlike createT(), this method will not call the constructor of T. |
| 115 */ | 69 */ |
| 116 template<typename T> void* reserveT(size_t storageRequired = sizeof(T)) { | 70 template<typename T> void* reserveT(size_t storageRequired = sizeof(T)) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 131 rec->fHeapStorage = sk_malloc_throw(storageRequired); | 85 rec->fHeapStorage = sk_malloc_throw(storageRequired); |
| 132 rec->fObj = static_cast<void*>(rec->fHeapStorage); | 86 rec->fObj = static_cast<void*>(rec->fHeapStorage); |
| 133 } else { | 87 } else { |
| 134 // There is space in fStorage. | 88 // There is space in fStorage. |
| 135 rec->fStorageSize = storageRequired; | 89 rec->fStorageSize = storageRequired; |
| 136 rec->fHeapStorage = nullptr; | 90 rec->fHeapStorage = nullptr; |
| 137 SkASSERT(SkIsAlign4(fStorageUsed)); | 91 SkASSERT(SkIsAlign4(fStorageUsed)); |
| 138 rec->fObj = static_cast<void*>(fStorage + (fStorageUsed / 4)); | 92 rec->fObj = static_cast<void*>(fStorage + (fStorageUsed / 4)); |
| 139 fStorageUsed += storageRequired; | 93 fStorageUsed += storageRequired; |
| 140 } | 94 } |
| 141 rec->fKillProc = destroyT<T>; | 95 rec->fKillProc = DestroyT<T>; |
| 142 fNumObjects++; | 96 fNumObjects++; |
| 143 return rec->fObj; | 97 return rec->fObj; |
| 144 } | 98 } |
| 145 | 99 |
| 146 /* | 100 /* |
| 147 * Free the memory reserved last without calling the destructor. | 101 * Free the memory reserved last without calling the destructor. |
| 148 * Can be used in a nested way, i.e. after reserving A and B, calling | 102 * Can be used in a nested way, i.e. after reserving A and B, calling |
| 149 * freeLast once will free B and calling it again will free A. | 103 * freeLast once will free B and calling it again will free A. |
| 150 */ | 104 */ |
| 151 void freeLast() { | 105 void freeLast() { |
| 152 SkASSERT(fNumObjects > 0); | 106 SkASSERT(fNumObjects > 0); |
| 153 Rec* rec = &fRecs[fNumObjects - 1]; | 107 Rec* rec = &fRecs[fNumObjects - 1]; |
| 154 sk_free(rec->fHeapStorage); | 108 sk_free(rec->fHeapStorage); |
| 155 fStorageUsed -= rec->fStorageSize; | 109 fStorageUsed -= rec->fStorageSize; |
| 156 | 110 |
| 157 fNumObjects--; | 111 fNumObjects--; |
| 158 } | 112 } |
| 159 | 113 |
| 160 private: | 114 private: |
| 161 struct Rec { | 115 struct Rec { |
| 162 size_t fStorageSize; // 0 if allocated on heap | 116 size_t fStorageSize; // 0 if allocated on heap |
| 163 void* fObj; | 117 void* fObj; |
| 164 void* fHeapStorage; | 118 void* fHeapStorage; |
| 165 void (*fKillProc)(void*); | 119 void (*fKillProc)(void*); |
| 166 }; | 120 }; |
| 167 | 121 |
| 122 // Used to call the destructor for allocated objects. |
| 123 template<typename T> |
| 124 static void DestroyT(void* ptr) { |
| 125 static_cast<T*>(ptr)->~T(); |
| 126 } |
| 127 |
| 168 // Number of bytes used so far. | 128 // Number of bytes used so far. |
| 169 size_t fStorageUsed; | 129 size_t fStorageUsed; |
| 170 // Pad the storage size to be 4-byte aligned. | 130 // Pad the storage size to be 4-byte aligned. |
| 171 uint32_t fStorage[SkAlign4(kTotalBytes) >> 2]; | 131 uint32_t fStorage[SkAlign4(kTotalBytes) >> 2]; |
| 172 uint32_t fNumObjects; | 132 uint32_t fNumObjects; |
| 173 Rec fRecs[kMaxObjects]; | 133 Rec fRecs[kMaxObjects]; |
| 174 }; | 134 }; |
| 175 | 135 |
| 176 #endif // SkSmallAllocator_DEFINED | 136 #endif // SkSmallAllocator_DEFINED |
| OLD | NEW |