SkChunkAlloc.cpp revision f2b98d67dcb6fcb3120feede9c72016fc7b3ead8
1/* libs/corecg/SkChunkAlloc.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkChunkAlloc.h"
19
20struct SkChunkAlloc::Block {
21    Block*  fNext;
22    size_t  fFreeSize;
23    char*   fFreePtr;
24    // data[] follows
25
26    char* startOfData() {
27        return reinterpret_cast<char*>(this + 1);
28    }
29
30    void freeChain() {    // this can be null
31        Block* block = this;
32        while (block) {
33            Block* next = block->fNext;
34            sk_free(block);
35            block = next;
36        }
37    };
38
39    Block* tail() {
40        Block* block = this;
41        if (block) {
42            for (;;) {
43                Block* next = block->fNext;
44                if (NULL == next) {
45                    break;
46                }
47                block = next;
48            }
49        }
50        return block;
51    }
52
53    bool contains(const void* addr) const {
54        const char* ptr = reinterpret_cast<const char*>(addr);
55        return ptr >= (const char*)(this + 1) && ptr < fFreePtr;
56    }
57};
58
59SkChunkAlloc::SkChunkAlloc(size_t minSize)
60    : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0)
61{
62}
63
64SkChunkAlloc::~SkChunkAlloc() {
65    this->reset();
66}
67
68void SkChunkAlloc::reset() {
69    fBlock->freeChain();
70    fBlock = NULL;
71    fPool->freeChain();
72    fPool = NULL;
73    fTotalCapacity = 0;
74}
75
76void SkChunkAlloc::reuse() {
77    if (fPool && fBlock) {
78        fPool->tail()->fNext = fBlock;
79    }
80    fPool = fBlock;
81    fBlock = NULL;
82    fTotalCapacity = 0;
83}
84
85SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
86    Block* block = fPool;
87
88    if (block && bytes <= block->fFreeSize) {
89        fPool = block->fNext;
90        return block;
91    }
92
93    size_t size = bytes;
94    if (size < fMinSize)
95        size = fMinSize;
96
97    block = (Block*)sk_malloc_flags(sizeof(Block) + size,
98                        ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
99
100    if (block) {
101        //    block->fNext = fBlock;
102        block->fFreeSize = size;
103        block->fFreePtr = block->startOfData();
104
105        fTotalCapacity += size;
106    }
107    return block;
108}
109
110void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
111    bytes = SkAlign4(bytes);
112
113    Block* block = fBlock;
114
115    if (block == NULL || bytes > block->fFreeSize) {
116        block = this->newBlock(bytes, ftype);
117        if (NULL == block) {
118            return NULL;
119        }
120        block->fNext = fBlock;
121        fBlock = block;
122    }
123
124    SkASSERT(block && bytes <= block->fFreeSize);
125    void* ptr = block->fFreePtr;
126
127    block->fFreeSize -= bytes;
128    block->fFreePtr += bytes;
129    return ptr;
130}
131
132size_t SkChunkAlloc::unalloc(void* ptr) {
133    size_t bytes = 0;
134    Block* block = fBlock;
135    if (block) {
136        char* cPtr = reinterpret_cast<char*>(ptr);
137        char* start = block->startOfData();
138        if (start <= cPtr && cPtr < block->fFreePtr) {
139            bytes = block->fFreePtr - cPtr;
140            block->fFreeSize += bytes;
141            block->fFreePtr = cPtr;
142        }
143    }
144    return bytes;
145}
146
147bool SkChunkAlloc::contains(const void* addr) const {
148    const Block* block = fBlock;
149    while (block) {
150        if (block->contains(addr)) {
151            return true;
152        }
153        block = block->fNext;
154    }
155    return false;
156}
157
158