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 |