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 |