1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2010 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifndef GrAllocator_DEFINED
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define GrAllocator_DEFINED
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrConfig.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrTypes.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTArray.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTypes.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrAllocator : SkNoncopyable {
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ~GrAllocator() { this->reset(); }
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Create an allocator
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * @param   itemSize        the size of each item to allocate
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * @param   itemsPerBlock   the number of items to allocate at once
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * @param   initialBlock    optional memory to use for the first block.
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *                          Must be at least itemSize*itemsPerBlock sized.
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *                          Caller is responsible for freeing this memory.
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock)
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        : fItemSize(itemSize)
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        , fItemsPerBlock(itemsPerBlock)
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        , fOwnFirstBlock(nullptr == initialBlock)
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        , fCount(0)
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        , fInsertionIndexInBlock(0) {
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(itemsPerBlock > 0);
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlockSize = fItemSize * fItemsPerBlock;
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fOwnFirstBlock) {
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // This force us to allocate a new block on push_back().
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fInsertionIndexInBlock = fItemsPerBlock;
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlocks.push_back() = initialBlock;
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fInsertionIndexInBlock = 0;
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Adds an item and returns pointer to it.
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * @return pointer to the added item.
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void* push_back() {
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // we always have at least one block
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fItemsPerBlock == fInsertionIndexInBlock) {
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlocks.push_back() = sk_malloc_throw(fBlockSize);
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fInsertionIndexInBlock = 0;
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void* ret = (char*)fBlocks.back() + fItemSize * fInsertionIndexInBlock;
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++fCount;
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++fInsertionIndexInBlock;
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return ret;
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Remove the last item, only call if count() != 0
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void pop_back() {
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fCount);
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fInsertionIndexInBlock > 0);
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        --fInsertionIndexInBlock;
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        --fCount;
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (0 == fInsertionIndexInBlock) {
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Never delete the first block
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (fBlocks.count() > 1) {
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                sk_free(fBlocks.back());
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fBlocks.pop_back();
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fInsertionIndexInBlock = fItemsPerBlock;
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Removes all added items.
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void reset() {
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int firstBlockToFree = fOwnFirstBlock ? 0 : 1;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = firstBlockToFree; i < fBlocks.count(); ++i) {
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            sk_free(fBlocks[i]);
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fOwnFirstBlock) {
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlocks.reset();
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // This force us to allocate a new block on push_back().
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fInsertionIndexInBlock = fItemsPerBlock;
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlocks.pop_back_n(fBlocks.count() - 1);
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fInsertionIndexInBlock = 0;
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCount = 0;
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Returns the item count.
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int count() const {
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fCount;
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Is the count 0?
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool empty() const { return 0 == fCount; }
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Access last item, only call if count() != 0
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void* back() {
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fCount);
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fInsertionIndexInBlock > 0);
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return (char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Access last item, only call if count() != 0
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const void* back() const {
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fCount);
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fInsertionIndexInBlock > 0);
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return (const char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Iterates through the allocator. This is faster than using operator[] when walking linearly
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * through the allocator.
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    class Iter {
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    public:
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /**
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * Initializes the iterator. next() must be called before get().
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         */
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        Iter(const GrAllocator* allocator)
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            : fAllocator(allocator)
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            , fBlockIndex(-1)
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            , fIndexInBlock(allocator->fItemsPerBlock - 1)
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            , fItemIndex(-1) {}
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /**
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * Advances the iterator. Iteration is finished when next() returns false.
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         */
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool next() {
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++fIndexInBlock;
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++fItemIndex;
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (fIndexInBlock == fAllocator->fItemsPerBlock) {
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ++fBlockIndex;
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fIndexInBlock = 0;
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return fItemIndex < fAllocator->fCount;
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /**
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * Gets the current iterator value. Call next() at least once before calling. Don't call
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * after next() returns false.
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         */
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void* get() const {
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(fItemIndex >= 0 && fItemIndex < fAllocator->fCount);
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return (char*) fAllocator->fBlocks[fBlockIndex] + fIndexInBlock * fAllocator->fItemSize;
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    private:
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const GrAllocator* fAllocator;
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int                fBlockIndex;
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int                fIndexInBlock;
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int                fItemIndex;
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Access item by index.
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void* operator[] (int i) {
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(i >= 0 && i < fCount);
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return (char*)fBlocks[i / fItemsPerBlock] +
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               fItemSize * (i % fItemsPerBlock);
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Access item by index.
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const void* operator[] (int i) const {
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(i >= 0 && i < fCount);
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return (const char*)fBlocks[i / fItemsPerBlock] +
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               fItemSize * (i % fItemsPerBlock);
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Set first block of memory to write into.  Must be called before any other methods.
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * This requires that you have passed nullptr in the constructor.
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * @param   initialBlock    optional memory to use for the first block.
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *                          Must be at least itemSize*itemsPerBlock sized.
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *                          Caller is responsible for freeing this memory.
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setInitialBlock(void* initialBlock) {
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(0 == fCount);
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(0 == fBlocks.count());
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fItemsPerBlock == fInsertionIndexInBlock);
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fOwnFirstBlock = false;
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlocks.push_back() = initialBlock;
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fInsertionIndexInBlock = 0;
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // For access to above function.
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    template <typename T> friend class GrTAllocator;
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static const int NUM_INIT_BLOCK_PTRS = 8;
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkSTArray<NUM_INIT_BLOCK_PTRS, void*, true>   fBlocks;
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t                                        fBlockSize;
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t                                        fItemSize;
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int                                           fItemsPerBlock;
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool                                          fOwnFirstBlock;
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int                                           fCount;
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int                                           fInsertionIndexInBlock;
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    typedef SkNoncopyable INHERITED;
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T> class GrTAllocator;
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T> void* operator new(size_t, GrTAllocator<T>*);
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T> class GrTAllocator : SkNoncopyable {
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    virtual ~GrTAllocator() { this->reset(); }
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Create an allocator
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * @param   itemsPerBlock   the number of items to allocate at once
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    explicit GrTAllocator(int itemsPerBlock)
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        : fAllocator(sizeof(T), itemsPerBlock, nullptr) {}
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Adds an item and returns it.
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * @return the added item.
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    T& push_back() {
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void* item = fAllocator.push_back();
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(item);
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        new (item) T;
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *(T*)item;
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    T& push_back(const T& t) {
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void* item = fAllocator.push_back();
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(item);
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        new (item) T(t);
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *(T*)item;
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    template <typename... Args> T& emplace_back(Args&&... args) {
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void* item = fAllocator.push_back();
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(item);
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        new (item) T(std::forward<Args>(args)...);
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *(T*)item;
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Remove the last item, only call if count() != 0
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void pop_back() {
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->back().~T();
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fAllocator.pop_back();
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Removes all added items.
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void reset() {
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int c = fAllocator.count();
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < c; ++i) {
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ((T*)fAllocator[i])->~T();
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fAllocator.reset();
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Returns the item count.
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int count() const {
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fAllocator.count();
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Is the count 0?
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool empty() const { return fAllocator.empty(); }
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Access last item, only call if count() != 0
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    T& back() {
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *(T*)fAllocator.back();
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Access last item, only call if count() != 0
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const T& back() const {
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *(const T*)fAllocator.back();
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Iterates through the allocator. This is faster than using operator[] when walking linearly
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * through the allocator.
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    class Iter {
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    public:
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /**
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * Initializes the iterator. next() must be called before get() or ops * and ->.
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         */
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        Iter(const GrTAllocator* allocator) : fImpl(&allocator->fAllocator) {}
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /**
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * Advances the iterator. Iteration is finished when next() returns false.
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         */
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool next() { return fImpl.next(); }
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /**
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * Gets the current iterator value. Call next() at least once before calling. Don't call
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * after next() returns false.
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         */
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        T* get() const { return (T*) fImpl.get(); }
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /**
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         * Convenience operators. Same rules for calling apply as get().
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         */
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        T& operator*() const { return *this->get(); }
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        T* operator->() const { return this->get(); }
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    private:
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrAllocator::Iter fImpl;
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Access item by index.
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    T& operator[] (int i) {
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *(T*)(fAllocator[i]);
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /**
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Access item by index.
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const T& operator[] (int i) const {
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *(const T*)(fAllocator[i]);
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /*
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * Set first block of memory to write into.  Must be called before any other methods.
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     * @param   initialBlock    optional memory to use for the first block.
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *                          Must be at least size(T)*itemsPerBlock sized.
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *                          Caller is responsible for freeing this memory.
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setInitialBlock(void* initialBlock) {
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fAllocator.setInitialBlock(initialBlock);
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    friend void* operator new<T>(size_t, GrTAllocator*);
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrAllocator fAllocator;
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    typedef SkNoncopyable INHERITED;
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    typedef GrTAllocator<T> INHERITED;
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrSTAllocator() : INHERITED(N) {
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->setInitialBlock(fStorage.get());
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkAlignedSTStorage<N, T> fStorage;
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T> void* operator new(size_t size, GrTAllocator<T>* allocator) {
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return allocator->fAllocator.push_back();
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// to match the op new silences warnings about missing op delete when a constructor throws an
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// exception.
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T> void operator delete(void*, GrTAllocator<T>*) {
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SK_ABORT("Invalid Operation");
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define GrNEW_APPEND_TO_ALLOCATOR(allocator_ptr, type_name, args) \
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    new (allocator_ptr) type_name args
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
406