| 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 | 61 |
| 62 ~GrTRecorder() { | 62 ~GrTRecorder() { |
| 63 this->reset(); | 63 this->reset(); |
| 64 MemBlock::Free(fHeadBlock); | 64 MemBlock::Free(fHeadBlock); |
| 65 } | 65 } |
| 66 | 66 |
| 67 bool empty() { return !fLastItem; } | 67 bool empty() { return !fLastItem; } |
| 68 | 68 |
| 69 TBase& back() { | 69 TBase& back() { |
| 70 SkASSERT(!this->empty()); | 70 SkASSERT(!this->empty()); |
| 71 return *fLastItem; | 71 return *reinterpret_cast<TBase*>(fLastItem); |
| 72 } | 72 } |
| 73 | 73 |
| 74 /** | 74 /** |
| 75 * Removes and destroys the last block added to the recorder. It may not be
called when the | 75 * Removes and destroys the last block added to the recorder. It may not be
called when the |
| 76 * recorder is empty. | 76 * recorder is empty. |
| 77 */ | 77 */ |
| 78 void pop_back(); | 78 void pop_back(); |
| 79 | 79 |
| 80 /** | 80 /** |
| 81 * Destruct all items in the list and reset to empty. | 81 * Destruct all items in the list and reset to empty. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 103 private: | 103 private: |
| 104 template<typename TItem> struct length_of { | 104 template<typename TItem> struct length_of { |
| 105 enum { kValue = (sizeof(TItem) + sizeof(TAlign) - 1) / sizeof(TAlign) }; | 105 enum { kValue = (sizeof(TItem) + sizeof(TAlign) - 1) / sizeof(TAlign) }; |
| 106 }; | 106 }; |
| 107 static int LengthOf(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeo
f(TAlign); } | 107 static int LengthOf(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeo
f(TAlign); } |
| 108 | 108 |
| 109 struct Header { | 109 struct Header { |
| 110 int fTotalLength; // The length of an entry including header, item, and
data in TAligns. | 110 int fTotalLength; // The length of an entry including header, item, and
data in TAligns. |
| 111 int fPrevLength; // Same but for the previous entry. Used for iterating
backwards. | 111 int fPrevLength; // Same but for the previous entry. Used for iterating
backwards. |
| 112 }; | 112 }; |
| 113 template<typename TItem> TItem* alloc_back(int dataLength); | 113 template<typename TItem> void* alloc_back(int dataLength); |
| 114 | 114 |
| 115 struct MemBlock : SkNoncopyable { | 115 struct MemBlock : SkNoncopyable { |
| 116 /** Allocates a new block and appends it to prev if not NULL. The length
param is in units | 116 /** Allocates a new block and appends it to prev if not NULL. The length
param is in units |
| 117 of TAlign. */ | 117 of TAlign. */ |
| 118 static MemBlock* Alloc(int length, MemBlock* prev) { | 118 static MemBlock* Alloc(int length, MemBlock* prev) { |
| 119 MemBlock* block = reinterpret_cast<MemBlock*>( | 119 MemBlock* block = reinterpret_cast<MemBlock*>( |
| 120 sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue +
length))); | 120 sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue +
length))); |
| 121 block->fLength = length; | 121 block->fLength = length; |
| 122 block->fBack = 0; | 122 block->fBack = 0; |
| 123 block->fNext = NULL; | 123 block->fNext = NULL; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 147 } | 147 } |
| 148 | 148 |
| 149 int fLength; // Length in units of TAlign of the block. | 149 int fLength; // Length in units of TAlign of the block. |
| 150 int fBack; // Offset, in TAligns, to unused portion of the memor
y block. | 150 int fBack; // Offset, in TAligns, to unused portion of the memor
y block. |
| 151 MemBlock* fNext; | 151 MemBlock* fNext; |
| 152 MemBlock* fPrev; | 152 MemBlock* fPrev; |
| 153 }; | 153 }; |
| 154 MemBlock* const fHeadBlock; | 154 MemBlock* const fHeadBlock; |
| 155 MemBlock* fTailBlock; | 155 MemBlock* fTailBlock; |
| 156 | 156 |
| 157 TBase* fLastItem; | 157 void* fLastItem; // really a ptr to TBase |
| 158 | 158 |
| 159 template<typename TItem> friend struct GrTRecorderAllocWrapper; | 159 template<typename TItem> friend struct GrTRecorderAllocWrapper; |
| 160 | 160 |
| 161 template <typename UBase, typename UAlign, typename UItem> | 161 template <typename UBase, typename UAlign, typename UItem> |
| 162 friend void* operator new(size_t, GrTRecorder<UBase, UAlign>&, | 162 friend void* operator new(size_t, GrTRecorder<UBase, UAlign>&, |
| 163 const GrTRecorderAllocWrapper<UItem>&); | 163 const GrTRecorderAllocWrapper<UItem>&); |
| 164 | 164 |
| 165 friend class Iter; | 165 friend class Iter; |
| 166 friend class ReverseIter; | 166 friend class ReverseIter; |
| 167 }; | 167 }; |
| 168 | 168 |
| 169 //////////////////////////////////////////////////////////////////////////////// | 169 //////////////////////////////////////////////////////////////////////////////// |
| 170 | 170 |
| 171 template<typename TBase, typename TAlign> | 171 template<typename TBase, typename TAlign> |
| 172 void GrTRecorder<TBase, TAlign>::pop_back() { | 172 void GrTRecorder<TBase, TAlign>::pop_back() { |
| 173 SkASSERT(fLastItem); | 173 SkASSERT(fLastItem); |
| 174 Header* header = reinterpret_cast<Header*>( | 174 Header* header = reinterpret_cast<Header*>( |
| 175 reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue); | 175 reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue); |
| 176 fTailBlock->fBack -= header->fTotalLength; | 176 fTailBlock->fBack -= header->fTotalLength; |
| 177 fLastItem->~TBase(); | 177 reinterpret_cast<TBase*>(fLastItem)->~TBase(); |
| 178 | 178 |
| 179 int lastItemLength = header->fPrevLength; | 179 int lastItemLength = header->fPrevLength; |
| 180 | 180 |
| 181 if (!header->fPrevLength) { | 181 if (!header->fPrevLength) { |
| 182 // We popped the first entry in the recorder. | 182 // We popped the first entry in the recorder. |
| 183 SkASSERT(0 == fTailBlock->fBack); | 183 SkASSERT(0 == fTailBlock->fBack); |
| 184 fLastItem = NULL; | 184 fLastItem = NULL; |
| 185 return; | 185 return; |
| 186 } | 186 } |
| 187 while (!fTailBlock->fBack) { | 187 while (!fTailBlock->fBack) { |
| 188 // We popped the last entry in a block that isn't the head block. Move b
ack a block but | 188 // We popped the last entry in a block that isn't the head block. Move b
ack a block but |
| 189 // don't free it since we'll probably grow into it shortly. | 189 // don't free it since we'll probably grow into it shortly. |
| 190 fTailBlock = fTailBlock->fPrev; | 190 fTailBlock = fTailBlock->fPrev; |
| 191 SkASSERT(fTailBlock); | 191 SkASSERT(fTailBlock); |
| 192 } | 192 } |
| 193 fLastItem = reinterpret_cast<TBase*>( | 193 fLastItem = &(*fTailBlock)[fTailBlock->fBack - lastItemLength + length_of<He
ader>::kValue]; |
| 194 &(*fTailBlock)[fTailBlock->fBack - lastItemLength + length_of<Header>::k
Value]); | |
| 195 } | 194 } |
| 196 | 195 |
| 197 template<typename TBase, typename TAlign> | 196 template<typename TBase, typename TAlign> |
| 198 template<typename TItem> | 197 template<typename TItem> |
| 199 TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) { | 198 void* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) { |
| 200 // Find the header of the previous entry and get its length. We need to stor
e that in the new | 199 // Find the header of the previous entry and get its length. We need to stor
e that in the new |
| 201 // header for backwards iteration (pop_back()). | 200 // header for backwards iteration (pop_back()). |
| 202 int prevLength = 0; | 201 int prevLength = 0; |
| 203 if (fLastItem) { | 202 if (fLastItem) { |
| 204 Header* lastHeader = reinterpret_cast<Header*>( | 203 Header* lastHeader = reinterpret_cast<Header*>( |
| 205 reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue); | 204 reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue); |
| 206 prevLength = lastHeader->fTotalLength; | 205 prevLength = lastHeader->fTotalLength; |
| 207 } | 206 } |
| 208 | 207 |
| 209 const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue
+ dataLength; | 208 const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue
+ dataLength; |
| 210 | 209 |
| 211 // Check if there is room in the current block and if not walk to next (allo
cating if | 210 // Check if there is room in the current block and if not walk to next (allo
cating if |
| 212 // necessary). Note that pop_back() and reset() can leave the recorder in a
state where it | 211 // necessary). Note that pop_back() and reset() can leave the recorder in a
state where it |
| 213 // has preallocated blocks hanging off the tail that are currently unused. | 212 // has preallocated blocks hanging off the tail that are currently unused. |
| 214 while (fTailBlock->fBack + totalLength > fTailBlock->fLength) { | 213 while (fTailBlock->fBack + totalLength > fTailBlock->fLength) { |
| 215 if (!fTailBlock->fNext) { | 214 if (!fTailBlock->fNext) { |
| 216 fTailBlock = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLe
ngth), fTailBlock); | 215 fTailBlock = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLe
ngth), fTailBlock); |
| 217 } else { | 216 } else { |
| 218 fTailBlock = fTailBlock->fNext; | 217 fTailBlock = fTailBlock->fNext; |
| 219 } | 218 } |
| 220 SkASSERT(0 == fTailBlock->fBack); | 219 SkASSERT(0 == fTailBlock->fBack); |
| 221 } | 220 } |
| 222 | 221 |
| 223 Header* header = reinterpret_cast<Header*>(&(*fTailBlock)[fTailBlock->fBack]
); | 222 Header* header = reinterpret_cast<Header*>(&(*fTailBlock)[fTailBlock->fBack]
); |
| 224 TItem* rawPtr = reinterpret_cast<TItem*>( | 223 void* rawPtr = &(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kValue]
; |
| 225 &(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kV
alue]); | |
| 226 | 224 |
| 227 header->fTotalLength = totalLength; | 225 header->fTotalLength = totalLength; |
| 228 header->fPrevLength = prevLength; | 226 header->fPrevLength = prevLength; |
| 229 fLastItem = rawPtr; | 227 fLastItem = rawPtr; |
| 230 fTailBlock->fBack += totalLength; | 228 fTailBlock->fBack += totalLength; |
| 231 | 229 |
| 232 // 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. |
| 233 // 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 |
| 234 // 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 |
| 235 // 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 |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 SK_CRASH(); | 382 SK_CRASH(); |
| 385 } | 383 } |
| 386 | 384 |
| 387 #define GrNEW_APPEND_TO_RECORDER(recorder, type_name, args) \ | 385 #define GrNEW_APPEND_TO_RECORDER(recorder, type_name, args) \ |
| 388 (new (recorder, GrTRecorderAllocWrapper<type_name>()) type_name args) | 386 (new (recorder, GrTRecorderAllocWrapper<type_name>()) type_name args) |
| 389 | 387 |
| 390 #define GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, type_name, args, size_of_da
ta) \ | 388 #define GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, type_name, args, size_of_da
ta) \ |
| 391 (new (recorder, GrTRecorderAllocWrapper<type_name>(recorder, size_of_data))
type_name args) | 389 (new (recorder, GrTRecorderAllocWrapper<type_name>(recorder, size_of_data))
type_name args) |
| 392 | 390 |
| 393 #endif | 391 #endif |
| OLD | NEW |