1 /* 2 Copyright 2010 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 18 #ifndef GrAllocator_DEFINED 19 #define GrAllocator_DEFINED 20 21 #include "GrConfig.h" 22 #include "GrTArray.h" 23 24 class GrAllocator { 25 public: ~GrAllocator()26 virtual ~GrAllocator() { 27 reset(); 28 } 29 30 /** 31 * Create an allocator 32 * 33 * @param itemSize the size of each item to allocate 34 * @param itemsPerBlock the number of items to allocate at once 35 * @param initialBlock optional memory to use for the first block. 36 * Must be at least itemSize*itemsPerBlock sized. 37 * Caller is responsible for freeing this memory. 38 */ GrAllocator(size_t itemSize,int itemsPerBlock,void * initialBlock)39 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) : 40 fBlocks(fBlockInitialStorage, NUM_INIT_BLOCK_PTRS), 41 fItemSize(itemSize), 42 fItemsPerBlock(itemsPerBlock), 43 fOwnFirstBlock(NULL == initialBlock), 44 fCount(0) { 45 GrAssert(itemsPerBlock > 0); 46 fBlockSize = fItemSize * fItemsPerBlock; 47 fBlocks.push_back() = initialBlock; 48 GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} ); 49 } 50 51 /** 52 * Adds an item and returns pointer to it. 53 * 54 * @return pointer to the added item. 55 */ push_back()56 void* push_back() { 57 int indexInBlock = fCount % fItemsPerBlock; 58 // we always have at least one block 59 if (0 == indexInBlock) { 60 if (0 != fCount) { 61 fBlocks.push_back() = GrMalloc(fBlockSize); 62 } else if (fOwnFirstBlock) { 63 fBlocks[0] = GrMalloc(fBlockSize); 64 } 65 } 66 void* ret = (char*)fBlocks[fCount/fItemsPerBlock] + 67 fItemSize * indexInBlock; 68 ++fCount; 69 return ret; 70 } 71 72 /** 73 * removes all added items 74 */ reset()75 void reset() { 76 int blockCount = GrMax((unsigned)1, 77 GrUIDivRoundUp(fCount, fItemsPerBlock)); 78 for (int i = 1; i < blockCount; ++i) { 79 GrFree(fBlocks[i]); 80 } 81 if (fOwnFirstBlock) { 82 GrFree(fBlocks[0]); 83 fBlocks[0] = NULL; 84 } 85 fBlocks.pop_back_n(blockCount-1); 86 fCount = 0; 87 } 88 89 /** 90 * count of items 91 */ count()92 int count() const { 93 return fCount; 94 } 95 96 /** 97 * is the count 0 98 */ empty()99 bool empty() const { return fCount == 0; } 100 101 /** 102 * access last item, only call if count() != 0 103 */ back()104 void* back() { 105 GrAssert(fCount); 106 return (*this)[fCount-1]; 107 } 108 109 /** 110 * access last item, only call if count() != 0 111 */ back()112 const void* back() const { 113 GrAssert(fCount); 114 return (*this)[fCount-1]; 115 } 116 117 /** 118 * access item by index. 119 */ 120 void* operator[] (int i) { 121 GrAssert(i >= 0 && i < fCount); 122 return (char*)fBlocks[i / fItemsPerBlock] + 123 fItemSize * (i % fItemsPerBlock); 124 } 125 126 /** 127 * access item by index. 128 */ 129 const void* operator[] (int i) const { 130 GrAssert(i >= 0 && i < fCount); 131 return (const char*)fBlocks[i / fItemsPerBlock] + 132 fItemSize * (i % fItemsPerBlock); 133 } 134 135 private: 136 static const int NUM_INIT_BLOCK_PTRS = 8; 137 138 GrTArray<void*> fBlocks; 139 size_t fBlockSize; 140 char fBlockInitialStorage[NUM_INIT_BLOCK_PTRS*sizeof(void*)]; 141 size_t fItemSize; 142 int fItemsPerBlock; 143 bool fOwnFirstBlock; 144 int fCount; 145 }; 146 147 template <typename T> 148 class GrTAllocator { 149 private: 150 GrAllocator fAllocator; 151 152 public: ~GrTAllocator()153 virtual ~GrTAllocator() {}; 154 155 /** 156 * Create an allocator 157 * 158 * @param itemsPerBlock the number of items to allocate at once 159 * @param initialBlock optional memory to use for the first block. 160 * Must be at least size(T)*itemsPerBlock sized. 161 * Caller is responsible for freeing this memory. 162 */ GrTAllocator(int itemsPerBlock,void * initialBlock)163 GrTAllocator(int itemsPerBlock, void* initialBlock) 164 : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {} 165 166 /** 167 * Create an allocator using a GrAlignedTAlloc as the initial block. 168 * 169 * @param initialBlock specifies the storage for the initial block 170 * and the size of subsequent blocks. 171 */ 172 template <int N> GrTAllocator(GrAlignedSTStorage<N,T> * initialBlock)173 GrTAllocator(GrAlignedSTStorage<N,T>* initialBlock) 174 : fAllocator(sizeof(T), N, initialBlock->get()) {} 175 176 /** 177 * Adds an item and returns it. 178 * 179 * @return the added item. 180 */ push_back()181 T& push_back() { 182 void* item = fAllocator.push_back(); 183 GrAssert(NULL != item); 184 new (item) T; 185 return *(T*)item; 186 } 187 188 /** 189 * removes all added items 190 */ reset()191 void reset() { 192 int c = fAllocator.count(); 193 for (int i = 0; i < c; ++i) { 194 ((T*)fAllocator[i])->~T(); 195 } 196 fAllocator.reset(); 197 } 198 199 /** 200 * count of items 201 */ count()202 int count() const { 203 return fAllocator.count(); 204 } 205 206 /** 207 * is the count 0 208 */ empty()209 bool empty() const { return fAllocator.empty(); } 210 211 /** 212 * access last item, only call if count() != 0 213 */ back()214 T& back() { 215 return *(T*)fAllocator.back(); 216 } 217 218 /** 219 * access last item, only call if count() != 0 220 */ back()221 const T& back() const { 222 return *(const T*)fAllocator.back(); 223 } 224 225 /** 226 * access item by index. 227 */ 228 T& operator[] (int i) { 229 return *(T*)(fAllocator[i]); 230 } 231 232 /** 233 * access item by index. 234 */ 235 const T& operator[] (int i) const { 236 return *(const T*)(fAllocator[i]); 237 } 238 }; 239 240 #endif 241