1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com */
7ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
8ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#ifndef GrAllocator_DEFINED
9ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#define GrAllocator_DEFINED
10ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
11ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#include "GrConfig.h"
12a0b40280a49a8a43af7929ead3b3489951c58501commit-bot@chromium.org#include "GrTypes.h"
1349313f6b4391d0f74ab1964c295634e8830680f6bsalomon@google.com#include "SkTArray.h"
14a0b40280a49a8a43af7929ead3b3489951c58501commit-bot@chromium.org#include "SkTypes.h"
15ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
16e3beb6bd7de7fa211681abbb0be58e80b19885e0commit-bot@chromium.orgclass GrAllocator : SkNoncopyable {
17ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.compublic:
18bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    ~GrAllocator() { this->reset(); }
19ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
20ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
21ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * Create an allocator
22ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     *
23ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * @param   itemSize        the size of each item to allocate
24ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * @param   itemsPerBlock   the number of items to allocate at once
25ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * @param   initialBlock    optional memory to use for the first block.
26ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     *                          Must be at least itemSize*itemsPerBlock sized.
27ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     *                          Caller is responsible for freeing this memory.
28ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
29bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock)
30bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        : fItemSize(itemSize)
31bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        , fItemsPerBlock(itemsPerBlock)
32bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        , fOwnFirstBlock(NULL == initialBlock)
33bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        , fCount(0)
34bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        , fInsertionIndexInBlock(0) {
35f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(itemsPerBlock > 0);
36ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fBlockSize = fItemSize * fItemsPerBlock;
37bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        if (fOwnFirstBlock) {
38bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            // This force us to allocate a new block on push_back().
39bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fInsertionIndexInBlock = fItemsPerBlock;
40bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        } else {
41bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fBlocks.push_back() = initialBlock;
42bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fInsertionIndexInBlock = 0;
43bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        }
44845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org    }
45845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org
46ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
47ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * Adds an item and returns pointer to it.
48ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     *
49ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * @return pointer to the added item.
50ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
514fa6694c587b3830932429766c99d08c8dd9b723bsalomon@google.com    void* push_back() {
52ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        // we always have at least one block
53bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        if (fItemsPerBlock == fInsertionIndexInBlock) {
54bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fBlocks.push_back() = sk_malloc_throw(fBlockSize);
55bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fInsertionIndexInBlock = 0;
56d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
57bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        void* ret = (char*)fBlocks.back() + fItemSize * fInsertionIndexInBlock;
58ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        ++fCount;
59bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        ++fInsertionIndexInBlock;
60ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return ret;
61ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
62ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
63ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
64a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon     * Remove the last item, only call if count() != 0
65a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon     */
66a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon    void pop_back() {
67a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon        SkASSERT(fCount);
68a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon        SkASSERT(fInsertionIndexInBlock > 0);
69a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon        --fInsertionIndexInBlock;
70a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon        --fCount;
71a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon        if (0 == fInsertionIndexInBlock) {
72a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon            // Never delete the first block
73a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon            if (fBlocks.count() > 1) {
74a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon                sk_free(fBlocks.back());
75a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon                fBlocks.pop_back();
76a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon                fInsertionIndexInBlock = fItemsPerBlock;
77a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon            }
78a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon        }
79a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon    }
80a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon
81a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon    /**
82bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Removes all added items.
83ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
84d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    void reset() {
85bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        int firstBlockToFree = fOwnFirstBlock ? 0 : 1;
86bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        for (int i = firstBlockToFree; i < fBlocks.count(); ++i) {
87939ca7ce860c5e80a4fdccc0dba5f7bfa29fef22reed@google.com            sk_free(fBlocks[i]);
88ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        }
89ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        if (fOwnFirstBlock) {
90bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fBlocks.reset();
91bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            // This force us to allocate a new block on push_back().
92bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fInsertionIndexInBlock = fItemsPerBlock;
93bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        } else {
94bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fBlocks.pop_back_n(fBlocks.count() - 1);
95bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            fInsertionIndexInBlock = 0;
96ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        }
97ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fCount = 0;
98ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
99ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
100ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
101bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Returns the item count.
102ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
1036a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com    int count() const {
104ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return fCount;
105ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
106d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
107ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
108bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Is the count 0?
109ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
110bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    bool empty() const { return 0 == fCount; }
111d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
112ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
113bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Access last item, only call if count() != 0
114ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
115ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    void* back() {
116f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(fCount);
117bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        SkASSERT(fInsertionIndexInBlock > 0);
118bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        return (char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
119ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
120d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
121ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
122bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Access last item, only call if count() != 0
123ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
124ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    const void* back() const {
125f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(fCount);
126bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        SkASSERT(fInsertionIndexInBlock > 0);
127bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        return (const char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
128ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
129d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
130bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    /**
131bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Iterates through the allocator. This is faster than using operator[] when walking linearly
132bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * through the allocator.
133bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     */
134bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    class Iter {
135bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    public:
136bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        /**
137bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * Initializes the iterator. next() must be called before get().
138bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         */
139bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        Iter(const GrAllocator* allocator)
140bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            : fAllocator(allocator)
141bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            , fBlockIndex(-1)
142bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            , fIndexInBlock(allocator->fItemsPerBlock - 1)
143bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            , fItemIndex(-1) {}
144bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
145bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        /**
146bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * Advances the iterator. Iteration is finished when next() returns false.
147bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         */
148bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        bool next() {
149bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            ++fIndexInBlock;
150bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            ++fItemIndex;
151bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            if (fIndexInBlock == fAllocator->fItemsPerBlock) {
152bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon                ++fBlockIndex;
153bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon                fIndexInBlock = 0;
154bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            }
155bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            return fItemIndex < fAllocator->fCount;
156bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        }
157bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
158bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        /**
159bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * Gets the current iterator value. Call next() at least once before calling. Don't call
160bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * after next() returns false.
161bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         */
162e1bc1c6958de768521323075b659d6ec6ad442fcbsalomon        void* get() const {
163bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            SkASSERT(fItemIndex >= 0 && fItemIndex < fAllocator->fCount);
164bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon            return (char*) fAllocator->fBlocks[fBlockIndex] + fIndexInBlock * fAllocator->fItemSize;
165bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        }
166bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
167bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    private:
168bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        const GrAllocator* fAllocator;
169bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        int                fBlockIndex;
170bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        int                fIndexInBlock;
171bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        int                fItemIndex;
172bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    };
173bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
174ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
175bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Access item by index.
176d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com     */
1776a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com    void* operator[] (int i) {
178f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(i >= 0 && i < fCount);
179d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        return (char*)fBlocks[i / fItemsPerBlock] +
180ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com               fItemSize * (i % fItemsPerBlock);
181ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
182ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
183ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
184bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Access item by index.
185d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com     */
1866a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com    const void* operator[] (int i) const {
187f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(i >= 0 && i < fCount);
188d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        return (const char*)fBlocks[i / fItemsPerBlock] +
189ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com               fItemSize * (i % fItemsPerBlock);
190ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
191ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
192bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomonprotected:
193bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    /**
194bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Set first block of memory to write into.  Must be called before any other methods.
195bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * This requires that you have passed NULL in the constructor.
196bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     *
197bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * @param   initialBlock    optional memory to use for the first block.
198bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     *                          Must be at least itemSize*itemsPerBlock sized.
199bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     *                          Caller is responsible for freeing this memory.
200bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     */
201bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    void setInitialBlock(void* initialBlock) {
202bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        SkASSERT(0 == fCount);
203bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        SkASSERT(0 == fBlocks.count());
204bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        SkASSERT(fItemsPerBlock == fInsertionIndexInBlock);
205bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        fOwnFirstBlock = false;
206bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        fBlocks.push_back() = initialBlock;
207bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        fInsertionIndexInBlock = 0;
208bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    }
209bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
210bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    // For access to above function.
211bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    template <typename T> friend class GrTAllocator;
212bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
213ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comprivate:
2146a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com    static const int NUM_INIT_BLOCK_PTRS = 8;
215d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
216bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    SkSTArray<NUM_INIT_BLOCK_PTRS, void*, true>   fBlocks;
217bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    size_t                                        fBlockSize;
218bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    size_t                                        fItemSize;
219bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    int                                           fItemsPerBlock;
220bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    bool                                          fOwnFirstBlock;
221bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    int                                           fCount;
222bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    int                                           fInsertionIndexInBlock;
2234b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com
224a0b40280a49a8a43af7929ead3b3489951c58501commit-bot@chromium.org    typedef SkNoncopyable INHERITED;
225ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com};
226ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
227b3e3a955b6628acc540ef14854b57abb089e62dfbsalomontemplate <typename T> class GrTAllocator;
228b3e3a955b6628acc540ef14854b57abb089e62dfbsalomontemplate <typename T> void* operator new(size_t, GrTAllocator<T>*);
229b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon
230b3e3a955b6628acc540ef14854b57abb089e62dfbsalomontemplate <typename T> class GrTAllocator : SkNoncopyable {
231ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.compublic:
23213788bfbedc2528fbfa71162c888908c88f03ac2bsalomon@google.com    virtual ~GrTAllocator() { this->reset(); };
233a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
234ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
235ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * Create an allocator
236ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     *
237ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * @param   itemsPerBlock   the number of items to allocate at once
238ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
2394b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com    explicit GrTAllocator(int itemsPerBlock)
2404b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com        : fAllocator(sizeof(T), itemsPerBlock, NULL) {}
241a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com
242a55847ba22ae4a673af022e7d88404e080195464bsalomon@google.com    /**
243ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * Adds an item and returns it.
244ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     *
245ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     * @return the added item.
246ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
247ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    T& push_back() {
248ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        void* item = fAllocator.push_back();
24949f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(item);
250c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com        SkNEW_PLACEMENT(item, T);
251ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return *(T*)item;
252ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
2534fa6694c587b3830932429766c99d08c8dd9b723bsalomon@google.com
2544fa6694c587b3830932429766c99d08c8dd9b723bsalomon@google.com    T& push_back(const T& t) {
2554fa6694c587b3830932429766c99d08c8dd9b723bsalomon@google.com        void* item = fAllocator.push_back();
25649f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(item);
257c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com        SkNEW_PLACEMENT_ARGS(item, T, (t));
2584fa6694c587b3830932429766c99d08c8dd9b723bsalomon@google.com        return *(T*)item;
2594fa6694c587b3830932429766c99d08c8dd9b723bsalomon@google.com    }
2604fa6694c587b3830932429766c99d08c8dd9b723bsalomon@google.com
261ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
262a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon     * Remove the last item, only call if count() != 0
263a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon     */
264a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon    void pop_back() {
265a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon        this->back().~T();
266a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon        fAllocator.pop_back();
267a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon    }
268a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon
269a1ae66d252edf6da932caed1fe43d11216e56c0ebsalomon    /**
270bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Removes all added items.
271ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
272ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    void reset() {
2736a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com        int c = fAllocator.count();
2746a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com        for (int i = 0; i < c; ++i) {
275ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com            ((T*)fAllocator[i])->~T();
276ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        }
277ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fAllocator.reset();
278ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
279d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
280ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
281bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Returns the item count.
282ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
2836a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com    int count() const {
284ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return fAllocator.count();
285ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
286d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
287ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
288bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Is the count 0?
289ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
290ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    bool empty() const { return fAllocator.empty(); }
291d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
292ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
293bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Access last item, only call if count() != 0
294ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
295ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    T& back() {
296ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return *(T*)fAllocator.back();
297ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
298ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
299ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
300bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Access last item, only call if count() != 0
301ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
302ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    const T& back() const {
303ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return *(const T*)fAllocator.back();
304ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
305ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
306ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
307bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Iterates through the allocator. This is faster than using operator[] when walking linearly
308bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * through the allocator.
309bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     */
310bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    class Iter {
311bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    public:
312bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        /**
313bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * Initializes the iterator. next() must be called before get() or ops * and ->.
314bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         */
315bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        Iter(const GrTAllocator* allocator) : fImpl(&allocator->fAllocator) {}
316bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
317bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        /**
318bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * Advances the iterator. Iteration is finished when next() returns false.
319bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         */
320bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        bool next() { return fImpl.next(); }
321bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
322bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        /**
323bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * Gets the current iterator value. Call next() at least once before calling. Don't call
324bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * after next() returns false.
325bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         */
326e1bc1c6958de768521323075b659d6ec6ad442fcbsalomon        T* get() const { return (T*) fImpl.get(); }
327bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
328bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        /**
329bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         * Convenience operators. Same rules for calling apply as get().
330bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon         */
331e1bc1c6958de768521323075b659d6ec6ad442fcbsalomon        T& operator*() const { return *this->get(); }
332e1bc1c6958de768521323075b659d6ec6ad442fcbsalomon        T* operator->() const { return this->get(); }
333bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
334bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    private:
335bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon        GrAllocator::Iter fImpl;
336bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    };
337bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon
338bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon    /**
339bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Access item by index.
340d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com     */
3416a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com    T& operator[] (int i) {
342ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return *(T*)(fAllocator[i]);
343ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
344d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
345ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
346bce3d6dbb91c3e67f1010556c2b8aaf6d7a49267bsalomon     * Access item by index.
347ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
3486a77cc5dde4bc01a0a9ba9ac32140146247d113fbsalomon@google.com    const T& operator[] (int i) const {
349ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return *(const T*)(fAllocator[i]);
3504b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com    }
3514b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com
3524b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.comprotected:
353845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org    /*
354845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org     * Set first block of memory to write into.  Must be called before any other methods.
355845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org     *
356845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org     * @param   initialBlock    optional memory to use for the first block.
357845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org     *                          Must be at least size(T)*itemsPerBlock sized.
358845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org     *                          Caller is responsible for freeing this memory.
359845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org     */
360845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org    void setInitialBlock(void* initialBlock) {
361845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org        fAllocator.setInitialBlock(initialBlock);
3624b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com    }
3634b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com
3644b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.comprivate:
365b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon    friend void* operator new<T>(size_t, GrTAllocator*);
366b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon
3674b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com    GrAllocator fAllocator;
368a0b40280a49a8a43af7929ead3b3489951c58501commit-bot@chromium.org    typedef SkNoncopyable INHERITED;
3694b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com};
3704b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com
3714b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.comtemplate <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
3724b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.comprivate:
3734b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com    typedef GrTAllocator<T> INHERITED;
3744b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com
3754b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.compublic:
376845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org    GrSTAllocator() : INHERITED(N) {
377845da77bc04de38e3c410ee1e26d9df70ab7d0eecommit-bot@chromium.org        this->setInitialBlock(fStorage.get());
3784b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com    }
3794b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com
3804b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.comprivate:
3814b90c62dfcda5866808ceedee46358b3d9792c93bsalomon@google.com    SkAlignedSTStorage<N, T> fStorage;
382ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com};
383ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
384b3e3a955b6628acc540ef14854b57abb089e62dfbsalomontemplate <typename T> void* operator new(size_t size, GrTAllocator<T>* allocator) {
385b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon    return allocator->fAllocator.push_back();
386b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon}
387b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon
388b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon// Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete
389b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon// to match the op new silences warnings about missing op delete when a constructor throws an
390b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon// exception.
391b3e3a955b6628acc540ef14854b57abb089e62dfbsalomontemplate <typename T> void operator delete(void*, GrTAllocator<T>*) {
392b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon    SK_CRASH();
393b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon}
394b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon
395b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon#define GrNEW_APPEND_TO_ALLOCATOR(allocator_ptr, type_name, args) \
396b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon    new (allocator_ptr) type_name args
397b3e3a955b6628acc540ef14854b57abb089e62dfbsalomon
398ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
399