1
2/*
3 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10
11#ifndef GrAllocator_DEFINED
12#define GrAllocator_DEFINED
13
14#include "GrConfig.h"
15#include "SkTArray.h"
16
17class GrAllocator : GrNoncopyable {
18public:
19    ~GrAllocator() {
20        reset();
21    }
22
23    /**
24     * Create an allocator
25     *
26     * @param   itemSize        the size of each item to allocate
27     * @param   itemsPerBlock   the number of items to allocate at once
28     * @param   initialBlock    optional memory to use for the first block.
29     *                          Must be at least itemSize*itemsPerBlock sized.
30     *                          Caller is responsible for freeing this memory.
31     */
32    GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) :
33            fItemSize(itemSize),
34            fItemsPerBlock(itemsPerBlock),
35            fOwnFirstBlock(NULL == initialBlock),
36            fCount(0) {
37        GrAssert(itemsPerBlock > 0);
38        fBlockSize = fItemSize * fItemsPerBlock;
39        fBlocks.push_back() = initialBlock;
40        GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
41    }
42
43    /**
44     * Adds an item and returns pointer to it.
45     *
46     * @return pointer to the added item.
47     */
48    void* push_back() {
49        int indexInBlock = fCount % fItemsPerBlock;
50        // we always have at least one block
51        if (0 == indexInBlock) {
52            if (0 != fCount) {
53                fBlocks.push_back() = GrMalloc(fBlockSize);
54            } else if (fOwnFirstBlock) {
55                fBlocks[0] = GrMalloc(fBlockSize);
56            }
57        }
58        void* ret = (char*)fBlocks[fCount/fItemsPerBlock] +
59                    fItemSize * indexInBlock;
60        ++fCount;
61        return ret;
62    }
63
64    /**
65     * removes all added items
66     */
67    void reset() {
68        int blockCount = GrMax((unsigned)1,
69                               GrUIDivRoundUp(fCount, fItemsPerBlock));
70        for (int i = 1; i < blockCount; ++i) {
71            GrFree(fBlocks[i]);
72        }
73        if (fOwnFirstBlock) {
74            GrFree(fBlocks[0]);
75            fBlocks[0] = NULL;
76        }
77        fBlocks.pop_back_n(blockCount-1);
78        fCount = 0;
79    }
80
81    /**
82     * count of items
83     */
84    int count() const {
85        return fCount;
86    }
87
88    /**
89     * is the count 0
90     */
91    bool empty() const { return fCount == 0; }
92
93    /**
94     * access last item, only call if count() != 0
95     */
96    void* back() {
97        GrAssert(fCount);
98        return (*this)[fCount-1];
99    }
100
101    /**
102     * access last item, only call if count() != 0
103     */
104    const void* back() const {
105        GrAssert(fCount);
106        return (*this)[fCount-1];
107    }
108
109    /**
110     * access item by index.
111     */
112    void* operator[] (int i) {
113        GrAssert(i >= 0 && i < fCount);
114        return (char*)fBlocks[i / fItemsPerBlock] +
115               fItemSize * (i % fItemsPerBlock);
116    }
117
118    /**
119     * access item by index.
120     */
121    const void* operator[] (int i) const {
122        GrAssert(i >= 0 && i < fCount);
123        return (const char*)fBlocks[i / fItemsPerBlock] +
124               fItemSize * (i % fItemsPerBlock);
125    }
126
127private:
128    static const int NUM_INIT_BLOCK_PTRS = 8;
129
130    SkSTArray<NUM_INIT_BLOCK_PTRS, void*>   fBlocks;
131    size_t                                  fBlockSize;
132    size_t                                  fItemSize;
133    int                                     fItemsPerBlock;
134    bool                                    fOwnFirstBlock;
135    int                                     fCount;
136
137    typedef GrNoncopyable INHERITED;
138};
139
140template <typename T>
141class GrTAllocator : GrNoncopyable {
142
143public:
144    virtual ~GrTAllocator() { this->reset(); };
145
146    /**
147     * Create an allocator
148     *
149     * @param   itemsPerBlock   the number of items to allocate at once
150     * @param   initialBlock    optional memory to use for the first block.
151     *                          Must be at least size(T)*itemsPerBlock sized.
152     *                          Caller is responsible for freeing this memory.
153     */
154    explicit GrTAllocator(int itemsPerBlock)
155        : fAllocator(sizeof(T), itemsPerBlock, NULL) {}
156
157    /**
158     * Adds an item and returns it.
159     *
160     * @return the added item.
161     */
162    T& push_back() {
163        void* item = fAllocator.push_back();
164        GrAssert(NULL != item);
165        new (item) T;
166        return *(T*)item;
167    }
168
169    T& push_back(const T& t) {
170        void* item = fAllocator.push_back();
171        GrAssert(NULL != item);
172        new (item) T(t);
173        return *(T*)item;
174    }
175
176    /**
177     * removes all added items
178     */
179    void reset() {
180        int c = fAllocator.count();
181        for (int i = 0; i < c; ++i) {
182            ((T*)fAllocator[i])->~T();
183        }
184        fAllocator.reset();
185    }
186
187    /**
188     * count of items
189     */
190    int count() const {
191        return fAllocator.count();
192    }
193
194    /**
195     * is the count 0
196     */
197    bool empty() const { return fAllocator.empty(); }
198
199    /**
200     * access last item, only call if count() != 0
201     */
202    T& back() {
203        return *(T*)fAllocator.back();
204    }
205
206    /**
207     * access last item, only call if count() != 0
208     */
209    const T& back() const {
210        return *(const T*)fAllocator.back();
211    }
212
213    /**
214     * access item by index.
215     */
216    T& operator[] (int i) {
217        return *(T*)(fAllocator[i]);
218    }
219
220    /**
221     * access item by index.
222     */
223    const T& operator[] (int i) const {
224        return *(const T*)(fAllocator[i]);
225    }
226
227protected:
228    GrTAllocator(int itemsPerBlock, void* initialBlock)
229        : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {
230    }
231
232private:
233    GrAllocator fAllocator;
234    typedef GrNoncopyable INHERITED;
235};
236
237template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
238private:
239    typedef GrTAllocator<T> INHERITED;
240
241public:
242    GrSTAllocator() : INHERITED(N, fStorage.get()) {
243    }
244
245private:
246    SkAlignedSTStorage<N, T> fStorage;
247};
248
249#endif
250