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. |
(...skipping 10 matching lines...) Expand all Loading... | |
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; |
110 int fPrevLength; | |
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 static MemBlock* Alloc(int length, MemBlock* prev) { |
egdaniel
2014/11/21 19:09:46
Add comment on what length means when we alloc Mem
| |
109 MemBlock* block = reinterpret_cast<MemBlock*>( | 116 MemBlock* block = reinterpret_cast<MemBlock*>( |
110 sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue + length))); | 117 sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue + length))); |
111 block->fLength = length; | 118 block->fLength = length; |
112 block->fBack = 0; | 119 block->fBack = 0; |
113 block->fNext = NULL; | 120 block->fNext = NULL; |
121 block->fPrev = prev; | |
122 if (prev) { | |
123 SkASSERT(NULL == prev->fNext); | |
124 prev->fNext = block; | |
125 } | |
114 return block; | 126 return block; |
115 } | 127 } |
116 | 128 |
129 // Frees from this block forward. Also adjusts prev block's next ptr. | |
117 static void Free(MemBlock* block) { | 130 static void Free(MemBlock* block) { |
118 if (!block) { | 131 if (block && block->fPrev) { |
119 return; | 132 SkASSERT(block->fPrev->fNext == block); |
133 block->fPrev->fNext = NULL; | |
120 } | 134 } |
121 Free(block->fNext); | 135 while (block) { |
122 sk_free(block); | 136 MemBlock* next = block->fNext; |
137 sk_free(block); | |
138 block = next; | |
139 } | |
123 } | 140 } |
124 | 141 |
125 TAlign& operator [](int i) { | 142 TAlign& operator [](int i) { |
126 return reinterpret_cast<TAlign*>(this)[length_of<MemBlock>::kValue + i]; | 143 return reinterpret_cast<TAlign*>(this)[length_of<MemBlock>::kValue + i]; |
127 } | 144 } |
128 | 145 |
129 int fLength; | 146 int fLength; |
130 int fBack; | 147 int fBack; |
egdaniel
2014/11/21 19:09:47
comment about what this is
| |
131 MemBlock* fNext; | 148 MemBlock* fNext; |
149 MemBlock* fPrev; | |
132 }; | 150 }; |
133 MemBlock* const fHeadBlock; | 151 MemBlock* const fHeadBlock; |
134 MemBlock* fTailBlock; | 152 MemBlock* fTailBlock; |
135 | 153 |
136 TBase* fLastItem; | 154 TBase* fLastItem; |
137 | 155 |
138 template<typename TItem> friend struct GrTRecorderAllocWrapper; | 156 template<typename TItem> friend struct GrTRecorderAllocWrapper; |
139 | 157 |
140 template <typename UBase, typename UAlign, typename UItem> | 158 template <typename UBase, typename UAlign, typename UItem> |
141 friend void* operator new(size_t, GrTRecorder<UBase, UAlign>&, | 159 friend void* operator new(size_t, GrTRecorder<UBase, UAlign>&, |
142 const GrTRecorderAllocWrapper<UItem>&); | 160 const GrTRecorderAllocWrapper<UItem>&); |
143 | 161 |
144 friend class Iter; | 162 friend class Iter; |
145 }; | 163 }; |
146 | 164 |
147 //////////////////////////////////////////////////////////////////////////////// | 165 //////////////////////////////////////////////////////////////////////////////// |
148 | 166 |
149 template<typename TBase, typename TAlign> | 167 template<typename TBase, typename TAlign> |
168 void GrTRecorder<TBase, TAlign>::pop_back() { | |
169 SkASSERT(fLastItem); | |
170 Header* header = reinterpret_cast<Header*>( | |
171 reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue); | |
172 fTailBlock->fBack -= header->fTotalLength; | |
173 fLastItem->~TBase(); | |
174 | |
175 int lastItemLength = header->fPrevLength; | |
176 | |
177 if (!header->fPrevLength) { | |
egdaniel
2014/11/21 19:09:46
comment about what this if tells about the state w
| |
178 SkASSERT(0 == fTailBlock->fBack); | |
179 fLastItem = NULL; | |
180 return; | |
181 } | |
182 if (!fTailBlock->fBack) { | |
egdaniel
2014/11/21 19:09:47
comment about what this if tells about the state w
| |
183 MemBlock* prev = fTailBlock->fPrev; | |
184 SkASSERT(prev); | |
185 MemBlock::Free(fTailBlock); | |
186 fTailBlock = prev; | |
187 SkASSERT(NULL == fTailBlock->fNext); | |
188 } | |
189 fLastItem = reinterpret_cast<TBase*>( | |
190 &(*fTailBlock)[fTailBlock->fBack - lastItemLength + length_of<Header>::k Value]); | |
191 } | |
192 | |
193 template<typename TBase, typename TAlign> | |
150 template<typename TItem> | 194 template<typename TItem> |
151 TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) { | 195 TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) { |
196 int prevLength = 0; | |
197 if (fLastItem) { | |
198 Header* lastHeader = reinterpret_cast<Header*>( | |
199 reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue); | |
200 prevLength = lastHeader->fTotalLength; | |
201 } | |
202 | |
152 const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue + dataLength; | 203 const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue + dataLength; |
153 | 204 |
154 while (fTailBlock->fBack + totalLength > fTailBlock->fLength) { | 205 while (fTailBlock->fBack + totalLength > fTailBlock->fLength) { |
155 if (!fTailBlock->fNext) { | 206 if (!fTailBlock->fNext) { |
156 fTailBlock->fNext = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLength)); | 207 fTailBlock = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLe ngth), fTailBlock); |
208 } else { | |
209 fTailBlock = fTailBlock->fNext; | |
157 } | 210 } |
158 fTailBlock = fTailBlock->fNext; | |
159 SkASSERT(0 == fTailBlock->fBack); | 211 SkASSERT(0 == fTailBlock->fBack); |
160 } | 212 } |
161 | 213 |
162 Header* header = reinterpret_cast<Header*>(&(*fTailBlock)[fTailBlock->fBack] ); | 214 Header* header = reinterpret_cast<Header*>(&(*fTailBlock)[fTailBlock->fBack] ); |
163 TItem* rawPtr = reinterpret_cast<TItem*>( | 215 TItem* rawPtr = reinterpret_cast<TItem*>( |
164 &(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kV alue]); | 216 &(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kV alue]); |
165 | 217 |
166 header->fTotalLength = totalLength; | 218 header->fTotalLength = totalLength; |
219 header->fPrevLength = prevLength; | |
167 fLastItem = rawPtr; | 220 fLastItem = rawPtr; |
168 fTailBlock->fBack += totalLength; | 221 fTailBlock->fBack += totalLength; |
169 | 222 |
170 // FIXME: We currently require that the base and subclass share the same sta rt address. | 223 // 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 | 224 // 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 | 225 // 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 | 226 // 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. | 227 // extra cost to performance or code generality. |
175 SkDEBUGCODE(void* baseAddr = fLastItem; | 228 SkDEBUGCODE(void* baseAddr = fLastItem; |
176 void* subclassAddr = rawPtr); | 229 void* subclassAddr = rawPtr); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
218 Iter iter(*this); | 271 Iter iter(*this); |
219 while (iter.next()) { | 272 while (iter.next()) { |
220 iter->~TBase(); | 273 iter->~TBase(); |
221 } | 274 } |
222 | 275 |
223 // Assume the next time this recorder fills up it will use approximately the same | 276 // 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 | 277 // amount of space as last time. Leave enough space for up to ~50% growth; f ree |
225 // everything else. | 278 // everything else. |
226 if (fTailBlock->fBack <= fTailBlock->fLength / 2) { | 279 if (fTailBlock->fBack <= fTailBlock->fLength / 2) { |
227 MemBlock::Free(fTailBlock->fNext); | 280 MemBlock::Free(fTailBlock->fNext); |
228 fTailBlock->fNext = NULL; | |
229 } else if (fTailBlock->fNext) { | 281 } else if (fTailBlock->fNext) { |
230 MemBlock::Free(fTailBlock->fNext->fNext); | 282 MemBlock::Free(fTailBlock->fNext->fNext); |
231 fTailBlock->fNext->fNext = NULL; | 283 fTailBlock->fNext->fNext = NULL; |
232 } | 284 } |
233 | 285 |
234 for (MemBlock* block = fHeadBlock; block; block = block->fNext) { | 286 for (MemBlock* block = fHeadBlock; block; block = block->fNext) { |
235 block->fBack = 0; | 287 block->fBack = 0; |
236 } | 288 } |
237 | 289 |
238 fTailBlock = fHeadBlock; | 290 fTailBlock = fHeadBlock; |
(...skipping 26 matching lines...) Expand all Loading... | |
265 SK_CRASH(); | 317 SK_CRASH(); |
266 } | 318 } |
267 | 319 |
268 #define GrNEW_APPEND_TO_RECORDER(recorder, type_name, args) \ | 320 #define GrNEW_APPEND_TO_RECORDER(recorder, type_name, args) \ |
269 (new (recorder, GrTRecorderAllocWrapper<type_name>()) type_name args) | 321 (new (recorder, GrTRecorderAllocWrapper<type_name>()) type_name args) |
270 | 322 |
271 #define GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, type_name, args, size_of_da ta) \ | 323 #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) | 324 (new (recorder, GrTRecorderAllocWrapper<type_name>(recorder, size_of_data)) type_name args) |
273 | 325 |
274 #endif | 326 #endif |
OLD | NEW |