1/*
2 * Copyright 2010 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#include "GrAllocPool.h"
9
10#include "GrTypes.h"
11
12#define GrAllocPool_MIN_BLOCK_SIZE      ((size_t)128)
13
14struct GrAllocPool::Block {
15    Block*  fNext;
16    char*   fPtr;
17    size_t  fBytesFree;
18    size_t  fBytesTotal;
19
20    static Block* Create(size_t size, Block* next) {
21        SkASSERT(size >= GrAllocPool_MIN_BLOCK_SIZE);
22
23        Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
24        block->fNext = next;
25        block->fPtr = (char*)block + sizeof(Block);
26        block->fBytesFree = size;
27        block->fBytesTotal = size;
28        return block;
29    }
30
31    bool canAlloc(size_t bytes) const {
32        return bytes <= fBytesFree;
33    }
34
35    void* alloc(size_t bytes) {
36        SkASSERT(bytes <= fBytesFree);
37        fBytesFree -= bytes;
38        void* ptr = fPtr;
39        fPtr += bytes;
40        return ptr;
41    }
42
43    size_t release(size_t bytes) {
44        SkASSERT(bytes > 0);
45        size_t free = SkTMin(bytes, fBytesTotal - fBytesFree);
46        fBytesFree += free;
47        fPtr -= free;
48        return bytes - free;
49    }
50
51    bool empty() const { return fBytesTotal == fBytesFree; }
52};
53
54///////////////////////////////////////////////////////////////////////////////
55
56GrAllocPool::GrAllocPool(size_t blockSize) {
57    fBlock = NULL;
58    fMinBlockSize = SkTMax(blockSize, GrAllocPool_MIN_BLOCK_SIZE);
59    SkDEBUGCODE(fBlocksAllocated = 0;)
60}
61
62GrAllocPool::~GrAllocPool() {
63    this->reset();
64}
65
66void GrAllocPool::reset() {
67    this->validate();
68
69    Block* block = fBlock;
70    while (block) {
71        Block* next = block->fNext;
72        sk_free(block);
73        block = next;
74    }
75    fBlock = NULL;
76    SkDEBUGCODE(fBlocksAllocated = 0;)
77}
78
79void* GrAllocPool::alloc(size_t size) {
80    this->validate();
81
82    if (!fBlock || !fBlock->canAlloc(size)) {
83        size_t blockSize = SkTMax(fMinBlockSize, size);
84        fBlock = Block::Create(blockSize, fBlock);
85        SkDEBUGCODE(fBlocksAllocated += 1;)
86    }
87    return fBlock->alloc(size);
88}
89
90void GrAllocPool::release(size_t bytes) {
91    this->validate();
92
93    while (bytes && NULL != fBlock) {
94        bytes = fBlock->release(bytes);
95        if (fBlock->empty()) {
96            Block* next = fBlock->fNext;
97            sk_free(fBlock);
98            fBlock = next;
99            SkDEBUGCODE(fBlocksAllocated -= 1;)
100        }
101    }
102}
103
104#ifdef SK_DEBUG
105
106void GrAllocPool::validate() const {
107    Block* block = fBlock;
108    int count = 0;
109    while (block) {
110        count += 1;
111        block = block->fNext;
112    }
113    SkASSERT(fBlocksAllocated == count);
114}
115
116#endif
117