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