Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrTRecorder.h
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #ifndef GrTRecorder_DEFINED
9 #define GrTRecorder_DEFINED
10
11 #include "SkTemplates.h"
12 #include "SkTypes.h"
13
14 template<typename TBase, typename TAlign> class GrTRecorder;
15 template<typename TItem> struct GrTRecorderAllocWrapper;
16
17 /**
18  * Records a list of items with a common base type, optional associated data, and
19  * permanent memory addresses.
20  *
21  * This class preallocates its own chunks of memory for hosting objects, so new items can
22  * be created without excessive calls to malloc().
23  *
24  * To create a new item and append it to the back of the list, use the following macros:
25  *
26  *     GrNEW_APPEND_TO_RECORDER(recorder, SubclassName, (args))
27  *     GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, SubclassName, (args), sizeOfData)
28  *
29  * Upon reset or delete, the items are destructed in the same order they were received,
30  * not reverse (stack) order.
31  *
32  * @param TBase   Common base type of items in the list. If TBase is not a class with a
33  *                virtual destructor, the client is responsible for invoking any necessary
34  *                destructors.
35  *
36  *                For now, any subclass used in the list must have the same start address
37  *                as TBase (or in other words, the types must be convertible via
38  *                reinterpret_cast<>). Classes with multiple inheritance (or any subclass
39  *                on an obscure compiler) may not be compatible. This is runtime asserted
40  *                in debug builds.
41  *
42  * @param TAlign  A type whose size is the desired memory alignment for object allocations.
43  *                This should be the largest known alignment requirement for all objects
44  *                that may be stored in the list.
45  */
46 template<typename TBase, typename TAlign> class GrTRecorder : SkNoncopyable {
47 public:
48     class Iter;
49
50     /**
51      * Create a recorder.
52      *
53      * @param initialSizeInBytes  The amount of memory reserved by the recorder initially,
54                                   and after calls to reset().
55      */
56     GrTRecorder(int initialSizeInBytes)
57         : fHeadBlock(MemBlock::Alloc(LengthOf(initialSizeInBytes))),
58           fTailBlock(fHeadBlock),
59           fLastItem(NULL) {}
60
61     ~GrTRecorder() {
62         this->reset();
63         MemBlock::Free(fHeadBlock);
64     }
65
66     bool empty() { return !fLastItem; }
67
68     TBase& back() {
69         SkASSERT(!this->empty());
70         return *fLastItem;
71     }
72
73     /**
74      * Destruct all items in the list and reset to empty.
75      */
76     void reset();
77
78     /**
79      * Retrieve the extra data associated with an item that was allocated using
80      * GrNEW_APPEND_WITH_DATA_TO_RECORDER().
81      *
82      * @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.
84      *
85      * @return The item's associated data.
86      */
87     template<typename TItem> static const void* GetDataForItem(const TItem* item) {
88         const TAlign* ptr = reinterpret_cast<const TAlign*>(item);
89         return &ptr[length_of<TItem>::kValue];
90     }
91     template<typename TItem> static void* GetDataForItem(TItem* item) {
92         TAlign* ptr = reinterpret_cast<TAlign*>(item);
93         return &ptr[length_of<TItem>::kValue];
94     }
95
96 private:
97     template<typename TItem> struct length_of {
98         enum { kValue = (sizeof(TItem) + sizeof(TAlign) - 1) / sizeof(TAlign) };
99     };
100     static int LengthOf(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeof(TAlign); }
101
102     struct Header {
103         int fTotalLength;
104     };
105     template<typename TItem> TItem* alloc_back(int dataLength);
106
107     struct MemBlock : SkNoncopyable {
108         static MemBlock* Alloc(int length) {
109             MemBlock* block = reinterpret_cast<MemBlock*>(
110                 sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue + length)));
111             block->fLength = length;
112             block->fBack = 0;
113             block->fNext = NULL;
114             return block;
115         }
116
117         static void Free(MemBlock* block) {
118             if (!block) {
119                 return;
120             }
121             Free(block->fNext);
122             sk_free(block);
123         }
124
125         TAlign& operator [](int i) {
126             return reinterpret_cast<TAlign*>(this)[length_of<MemBlock>::kValue + i];
127         }
128
129         int       fLength;
130         int       fBack;
131         MemBlock* fNext;
132     };
133     MemBlock* const fHeadBlock;
134     MemBlock* fTailBlock;
135
136     TBase*    fLastItem;
137
138     template<typename TItem> friend struct GrTRecorderAllocWrapper;
139
140     template <typename UBase, typename UAlign, typename UItem>
141     friend void* operator new(size_t, GrTRecorder<UBase, UAlign>&,
142                               const GrTRecorderAllocWrapper<UItem>&);
143
144     friend class Iter;
145 };
146
147 ////////////////////////////////////////////////////////////////////////////////
148
149 template<typename TBase, typename TAlign>
150 template<typename TItem>
151 TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) {
152     const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue + dataLength;
153
154     if (fTailBlock->fBack + totalLength > fTailBlock->fLength) {
155         SkASSERT(!fTailBlock->fNext);
156         fTailBlock->fNext = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLength));
157         fTailBlock = fTailBlock->fNext;
158     }
159
160     Header* header = reinterpret_cast<Header*>(&(*fTailBlock)[fTailBlock->fBack]);
161     TItem* rawPtr = reinterpret_cast<TItem*>(
162                         &(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kValue]);
163
164     header->fTotalLength = totalLength;
165     fLastItem = rawPtr;
166     fTailBlock->fBack += totalLength;
167
168     // FIXME: We currently require that the base and subclass share the same start address.
169     // This is not required by the C++ spec, and is likely to not be true in the case of
170     // multiple inheritance or a base class that doesn't have virtual methods (when the
171     // subclass does). It would be ideal to find a more robust solution that comes at no
172     // extra cost to performance or code generality.
173     SkDEBUGCODE(void* baseAddr = fLastItem;
174                 void* subclassAddr = rawPtr);
175     SkASSERT(baseAddr == subclassAddr);
176
177     return rawPtr;
178 }
179
180 template<typename TBase, typename TAlign>
181 class GrTRecorder<TBase, TAlign>::Iter {
182 public:
183     Iter(GrTRecorder& recorder) : fBlock(recorder.fHeadBlock), fPosition(0), fItem(NULL) {}
184
185     bool next() {
186         if (fPosition >= fBlock->fBack) {
187             SkASSERT(fPosition == fBlock->fBack);
188             if (!fBlock->fNext) {
189                 return false;
190             }
191             SkASSERT(0 != fBlock->fNext->fBack);
192             fBlock = fBlock->fNext;
193             fPosition = 0;
194         }
195
196         Header* header = reinterpret_cast<Header*>(&(*fBlock)[fPosition]);
197         fItem = reinterpret_cast<TBase*>(&(*fBlock)[fPosition + length_of<Header>::kValue]);
198         fPosition += header->fTotalLength;
199         return true;
200     }
201
202     TBase* get() const {
203         SkASSERT(fItem);
204         return fItem;
205     }
206
207     TBase* operator->() const { return this->get(); }
208
209 private:
210     MemBlock* fBlock;
211     int       fPosition;
212     TBase*    fItem;
213 };
214
215 template<typename TBase, typename TAlign>
216 void GrTRecorder<TBase, TAlign>::reset() {
217     Iter iter(*this);
218     while (iter.next()) {
219         iter->~TBase();
220     }
221     fHeadBlock->fBack = 0;
222     MemBlock::Free(fHeadBlock->fNext);
223     fHeadBlock->fNext = NULL;
224     fTailBlock = fHeadBlock;
225     fLastItem = NULL;
226 }
227
228 ////////////////////////////////////////////////////////////////////////////////
229
230 template<typename TItem> struct GrTRecorderAllocWrapper {
231     GrTRecorderAllocWrapper() : fDataLength(0) {}
232
233     template <typename TBase, typename TAlign>
234     GrTRecorderAllocWrapper(const GrTRecorder<TBase, TAlign>&, int sizeOfData)
235         : fDataLength(GrTRecorder<TBase, TAlign>::LengthOf(sizeOfData)) {}
236
237     const int fDataLength;
238 };
239
240 template <typename TBase, typename TAlign, typename TItem>
241 void* operator new(size_t size, GrTRecorder<TBase, TAlign>& recorder,
242                    const GrTRecorderAllocWrapper<TItem>& wrapper) {
243     SkASSERT(size == sizeof(TItem));
244     return recorder.template alloc_back<TItem>(wrapper.fDataLength);
245 }
246
247 template <typename TBase, typename TAlign, typename TItem>
248 void operator delete(void*, GrTRecorder<TBase, TAlign>&, const GrTRecorderAllocWrapper<TItem>&) {
249     // We only provide an operator delete to work around compiler warnings that can come
250     // up for an unmatched operator new when compiling with exceptions.
251     SK_CRASH();
252 }
253
254 #define GrNEW_APPEND_TO_RECORDER(recorder, type_name, args) \
255     (new (recorder, GrTRecorderAllocWrapper<type_name>()) type_name args)
256
257 #define GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, type_name, args, size_of_data) \
258     (new (recorder, GrTRecorderAllocWrapper<type_name>(recorder, size_of_data)) type_name args)
259
260 #endif