| 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 GrTRecorder_DEFINED | 8 #ifndef GrTRecorder_DEFINED |
| 9 #define GrTRecorder_DEFINED | 9 #define GrTRecorder_DEFINED |
| 10 | 10 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 public: | 47 public: |
| 48 class Iter; | 48 class Iter; |
| 49 | 49 |
| 50 /** | 50 /** |
| 51 * Create a recorder. | 51 * Create a recorder. |
| 52 * | 52 * |
| 53 * @param initialSizeInBytes The amount of memory reserved by the recorder
initially, | 53 * @param initialSizeInBytes The amount of memory reserved by the recorder
initially, |
| 54 and after calls to reset(). | 54 and after calls to reset(). |
| 55 */ | 55 */ |
| 56 GrTRecorder(int initialSizeInBytes) | 56 GrTRecorder(int initialSizeInBytes) |
| 57 : fHeadBlock(MemBlock::Alloc(LengthOf(initialSizeInBytes))), | 57 : fHeadBlock(MemBlock::Alloc(LengthOf(initialSizeInBytes), NULL)), |
| 58 fTailBlock(fHeadBlock), | 58 fTailBlock(fHeadBlock), |
| 59 fLastItem(NULL) {} | 59 fLastItem(NULL) {} |
| 60 | 60 |
| 61 ~GrTRecorder() { | 61 ~GrTRecorder() { |
| 62 this->reset(); | 62 this->reset(); |
| 63 MemBlock::Free(fHeadBlock); | 63 MemBlock::Free(fHeadBlock); |
| 64 } | 64 } |
| 65 | 65 |
| 66 bool empty() { return !fLastItem; } | 66 bool empty() { return !fLastItem; } |
| 67 | 67 |
| 68 TBase& back() { | 68 TBase& back() { |
| 69 SkASSERT(!this->empty()); | 69 SkASSERT(!this->empty()); |
| 70 return *fLastItem; | 70 return *fLastItem; |
| 71 } | 71 } |
| 72 | 72 |
| 73 /** | 73 /** |
| 74 * Removes and destroys the last block added to the recorder. It may not be
called when the |
| 75 * recorder is empty. |
| 76 */ |
| 77 void pop_back(); |
| 78 |
| 79 /** |
| 74 * Destruct all items in the list and reset to empty. | 80 * Destruct all items in the list and reset to empty. |
| 75 */ | 81 */ |
| 76 void reset(); | 82 void reset(); |
| 77 | 83 |
| 78 /** | 84 /** |
| 79 * Retrieve the extra data associated with an item that was allocated using | 85 * Retrieve the extra data associated with an item that was allocated using |
| 80 * GrNEW_APPEND_WITH_DATA_TO_RECORDER(). | 86 * GrNEW_APPEND_WITH_DATA_TO_RECORDER(). |
| 81 * | 87 * |
| 82 * @param item The item whose data to retrieve. The pointer must be of the
same type | 88 * @param item The item whose data to retrieve. The pointer must be of the
same type |
| 83 * that was allocated initally; it can't be a pointer to a base
class. | 89 * that was allocated initally; it can't be a pointer to a base
class. |
| 84 * | 90 * |
| 85 * @return The item's associated data. | 91 * @return The item's associated data. |
| 86 */ | 92 */ |
| 87 template<typename TItem> static const void* GetDataForItem(const TItem* item
) { | 93 template<typename TItem> static const void* GetDataForItem(const TItem* item
) { |
| 88 const TAlign* ptr = reinterpret_cast<const TAlign*>(item); | 94 const TAlign* ptr = reinterpret_cast<const TAlign*>(item); |
| 89 return &ptr[length_of<TItem>::kValue]; | 95 return &ptr[length_of<TItem>::kValue]; |
| 90 } | 96 } |
| 91 template<typename TItem> static void* GetDataForItem(TItem* item) { | 97 template<typename TItem> static void* GetDataForItem(TItem* item) { |
| 92 TAlign* ptr = reinterpret_cast<TAlign*>(item); | 98 TAlign* ptr = reinterpret_cast<TAlign*>(item); |
| 93 return &ptr[length_of<TItem>::kValue]; | 99 return &ptr[length_of<TItem>::kValue]; |
| 94 } | 100 } |
| 95 | 101 |
| 96 private: | 102 private: |
| 97 template<typename TItem> struct length_of { | 103 template<typename TItem> struct length_of { |
| 98 enum { kValue = (sizeof(TItem) + sizeof(TAlign) - 1) / sizeof(TAlign) }; | 104 enum { kValue = (sizeof(TItem) + sizeof(TAlign) - 1) / sizeof(TAlign) }; |
| 99 }; | 105 }; |
| 100 static int LengthOf(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeo
f(TAlign); } | 106 static int LengthOf(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeo
f(TAlign); } |
| 101 | 107 |
| 102 struct Header { | 108 struct Header { |
| 103 int fTotalLength; | 109 int fTotalLength; // The length of an entry including header, item, and
data in TAligns. |
| 110 int fPrevLength; // Same but for the previous entry. Used for iterating
backwards. |
| 104 }; | 111 }; |
| 105 template<typename TItem> TItem* alloc_back(int dataLength); | 112 template<typename TItem> TItem* alloc_back(int dataLength); |
| 106 | 113 |
| 107 struct MemBlock : SkNoncopyable { | 114 struct MemBlock : SkNoncopyable { |
| 108 static MemBlock* Alloc(int length) { | 115 /** Allocates a new block and appends it to prev if not NULL. The length
param is in units |
| 116 of TAlign. */ |
| 117 static MemBlock* Alloc(int length, MemBlock* prev) { |
| 109 MemBlock* block = reinterpret_cast<MemBlock*>( | 118 MemBlock* block = reinterpret_cast<MemBlock*>( |
| 110 sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue +
length))); | 119 sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue +
length))); |
| 111 block->fLength = length; | 120 block->fLength = length; |
| 112 block->fBack = 0; | 121 block->fBack = 0; |
| 113 block->fNext = NULL; | 122 block->fNext = NULL; |
| 123 block->fPrev = prev; |
| 124 if (prev) { |
| 125 SkASSERT(NULL == prev->fNext); |
| 126 prev->fNext = block; |
| 127 } |
| 114 return block; | 128 return block; |
| 115 } | 129 } |
| 116 | 130 |
| 131 // Frees from this block forward. Also adjusts prev block's next ptr. |
| 117 static void Free(MemBlock* block) { | 132 static void Free(MemBlock* block) { |
| 118 if (!block) { | 133 if (block && block->fPrev) { |
| 119 return; | 134 SkASSERT(block->fPrev->fNext == block); |
| 135 block->fPrev->fNext = NULL; |
| 120 } | 136 } |
| 121 Free(block->fNext); | 137 while (block) { |
| 122 sk_free(block); | 138 MemBlock* next = block->fNext; |
| 139 sk_free(block); |
| 140 block = next; |
| 141 } |
| 123 } | 142 } |
| 124 | 143 |
| 125 TAlign& operator [](int i) { | 144 TAlign& operator [](int i) { |
| 126 return reinterpret_cast<TAlign*>(this)[length_of<MemBlock>::kValue +
i]; | 145 return reinterpret_cast<TAlign*>(this)[length_of<MemBlock>::kValue +
i]; |
| 127 } | 146 } |
| 128 | 147 |
| 129 int fLength; | 148 int fLength; // Length in units of TAlign of the block. |
| 130 int fBack; | 149 int fBack; // Offset, in TAligns, to unused portion of the memor
y block. |
| 131 MemBlock* fNext; | 150 MemBlock* fNext; |
| 151 MemBlock* fPrev; |
| 132 }; | 152 }; |
| 133 MemBlock* const fHeadBlock; | 153 MemBlock* const fHeadBlock; |
| 134 MemBlock* fTailBlock; | 154 MemBlock* fTailBlock; |
| 135 | 155 |
| 136 TBase* fLastItem; | 156 TBase* fLastItem; |
| 137 | 157 |
| 138 template<typename TItem> friend struct GrTRecorderAllocWrapper; | 158 template<typename TItem> friend struct GrTRecorderAllocWrapper; |
| 139 | 159 |
| 140 template <typename UBase, typename UAlign, typename UItem> | 160 template <typename UBase, typename UAlign, typename UItem> |
| 141 friend void* operator new(size_t, GrTRecorder<UBase, UAlign>&, | 161 friend void* operator new(size_t, GrTRecorder<UBase, UAlign>&, |
| 142 const GrTRecorderAllocWrapper<UItem>&); | 162 const GrTRecorderAllocWrapper<UItem>&); |
| 143 | 163 |
| 144 friend class Iter; | 164 friend class Iter; |
| 145 }; | 165 }; |
| 146 | 166 |
| 147 //////////////////////////////////////////////////////////////////////////////// | 167 //////////////////////////////////////////////////////////////////////////////// |
| 148 | 168 |
| 149 template<typename TBase, typename TAlign> | 169 template<typename TBase, typename TAlign> |
| 170 void GrTRecorder<TBase, TAlign>::pop_back() { |
| 171 SkASSERT(fLastItem); |
| 172 Header* header = reinterpret_cast<Header*>( |
| 173 reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue); |
| 174 fTailBlock->fBack -= header->fTotalLength; |
| 175 fLastItem->~TBase(); |
| 176 |
| 177 int lastItemLength = header->fPrevLength; |
| 178 |
| 179 if (!header->fPrevLength) { |
| 180 // We popped the first entry in the recorder. |
| 181 SkASSERT(0 == fTailBlock->fBack); |
| 182 fLastItem = NULL; |
| 183 return; |
| 184 } |
| 185 if (!fTailBlock->fBack) { |
| 186 // We popped the last entry in a block that isn't the head block. Move b
ack a block but |
| 187 // don't free it since we'll probably grow into it shortly. |
| 188 fTailBlock = fTailBlock->fPrev; |
| 189 SkASSERT(fTailBlock); |
| 190 } |
| 191 fLastItem = reinterpret_cast<TBase*>( |
| 192 &(*fTailBlock)[fTailBlock->fBack - lastItemLength + length_of<Header>::k
Value]); |
| 193 } |
| 194 |
| 195 template<typename TBase, typename TAlign> |
| 150 template<typename TItem> | 196 template<typename TItem> |
| 151 TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) { | 197 TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) { |
| 198 // Find the header of the previous entry and get its length. We need to stor
e that in the new |
| 199 // header for backwards iteration (pop_back()). |
| 200 int prevLength = 0; |
| 201 if (fLastItem) { |
| 202 Header* lastHeader = reinterpret_cast<Header*>( |
| 203 reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue); |
| 204 prevLength = lastHeader->fTotalLength; |
| 205 } |
| 206 |
| 152 const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue
+ dataLength; | 207 const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue
+ dataLength; |
| 153 | 208 |
| 209 // Check if there is room in the current block and if not walk to next (allo
cating if |
| 210 // necessary). Note that pop_back() and reset() can leave the recorder in a
state where it |
| 211 // has preallocated blocks hanging off the tail that are currently unused. |
| 154 while (fTailBlock->fBack + totalLength > fTailBlock->fLength) { | 212 while (fTailBlock->fBack + totalLength > fTailBlock->fLength) { |
| 155 if (!fTailBlock->fNext) { | 213 if (!fTailBlock->fNext) { |
| 156 fTailBlock->fNext = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength,
totalLength)); | 214 fTailBlock = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLe
ngth), fTailBlock); |
| 215 } else { |
| 216 fTailBlock = fTailBlock->fNext; |
| 157 } | 217 } |
| 158 fTailBlock = fTailBlock->fNext; | |
| 159 SkASSERT(0 == fTailBlock->fBack); | 218 SkASSERT(0 == fTailBlock->fBack); |
| 160 } | 219 } |
| 161 | 220 |
| 162 Header* header = reinterpret_cast<Header*>(&(*fTailBlock)[fTailBlock->fBack]
); | 221 Header* header = reinterpret_cast<Header*>(&(*fTailBlock)[fTailBlock->fBack]
); |
| 163 TItem* rawPtr = reinterpret_cast<TItem*>( | 222 TItem* rawPtr = reinterpret_cast<TItem*>( |
| 164 &(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kV
alue]); | 223 &(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kV
alue]); |
| 165 | 224 |
| 166 header->fTotalLength = totalLength; | 225 header->fTotalLength = totalLength; |
| 226 header->fPrevLength = prevLength; |
| 167 fLastItem = rawPtr; | 227 fLastItem = rawPtr; |
| 168 fTailBlock->fBack += totalLength; | 228 fTailBlock->fBack += totalLength; |
| 169 | 229 |
| 170 // FIXME: We currently require that the base and subclass share the same sta
rt address. | 230 // FIXME: We currently require that the base and subclass share the same sta
rt address. |
| 171 // This is not required by the C++ spec, and is likely to not be true in the
case of | 231 // This is not required by the C++ spec, and is likely to not be true in the
case of |
| 172 // multiple inheritance or a base class that doesn't have virtual methods (w
hen the | 232 // multiple inheritance or a base class that doesn't have virtual methods (w
hen the |
| 173 // subclass does). It would be ideal to find a more robust solution that com
es at no | 233 // subclass does). It would be ideal to find a more robust solution that com
es at no |
| 174 // extra cost to performance or code generality. | 234 // extra cost to performance or code generality. |
| 175 SkDEBUGCODE(void* baseAddr = fLastItem; | 235 SkDEBUGCODE(void* baseAddr = fLastItem; |
| 176 void* subclassAddr = rawPtr); | 236 void* subclassAddr = rawPtr); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 Iter iter(*this); | 278 Iter iter(*this); |
| 219 while (iter.next()) { | 279 while (iter.next()) { |
| 220 iter->~TBase(); | 280 iter->~TBase(); |
| 221 } | 281 } |
| 222 | 282 |
| 223 // Assume the next time this recorder fills up it will use approximately the
same | 283 // Assume the next time this recorder fills up it will use approximately the
same |
| 224 // amount of space as last time. Leave enough space for up to ~50% growth; f
ree | 284 // amount of space as last time. Leave enough space for up to ~50% growth; f
ree |
| 225 // everything else. | 285 // everything else. |
| 226 if (fTailBlock->fBack <= fTailBlock->fLength / 2) { | 286 if (fTailBlock->fBack <= fTailBlock->fLength / 2) { |
| 227 MemBlock::Free(fTailBlock->fNext); | 287 MemBlock::Free(fTailBlock->fNext); |
| 228 fTailBlock->fNext = NULL; | |
| 229 } else if (fTailBlock->fNext) { | 288 } else if (fTailBlock->fNext) { |
| 230 MemBlock::Free(fTailBlock->fNext->fNext); | 289 MemBlock::Free(fTailBlock->fNext->fNext); |
| 231 fTailBlock->fNext->fNext = NULL; | 290 fTailBlock->fNext->fNext = NULL; |
| 232 } | 291 } |
| 233 | 292 |
| 234 for (MemBlock* block = fHeadBlock; block; block = block->fNext) { | 293 for (MemBlock* block = fHeadBlock; block; block = block->fNext) { |
| 235 block->fBack = 0; | 294 block->fBack = 0; |
| 236 } | 295 } |
| 237 | 296 |
| 238 fTailBlock = fHeadBlock; | 297 fTailBlock = fHeadBlock; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 265 SK_CRASH(); | 324 SK_CRASH(); |
| 266 } | 325 } |
| 267 | 326 |
| 268 #define GrNEW_APPEND_TO_RECORDER(recorder, type_name, args) \ | 327 #define GrNEW_APPEND_TO_RECORDER(recorder, type_name, args) \ |
| 269 (new (recorder, GrTRecorderAllocWrapper<type_name>()) type_name args) | 328 (new (recorder, GrTRecorderAllocWrapper<type_name>()) type_name args) |
| 270 | 329 |
| 271 #define GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, type_name, args, size_of_da
ta) \ | 330 #define GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, type_name, args, size_of_da
ta) \ |
| 272 (new (recorder, GrTRecorderAllocWrapper<type_name>(recorder, size_of_data))
type_name args) | 331 (new (recorder, GrTRecorderAllocWrapper<type_name>(recorder, size_of_data))
type_name args) |
| 273 | 332 |
| 274 #endif | 333 #endif |
| OLD | NEW |