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
20 struct SkChunkAlloc::Block {
21 Block* fNext;
22 size_t fFreeSize;
23 char* fFreePtr;
24 // data[] follows
25
startOfDataSkChunkAlloc::Block26 char* startOfData() {
27 return reinterpret_cast<char*>(this + 1);
28 }
29
freeChainSkChunkAlloc::Block30 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
tailSkChunkAlloc::Block39 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
containsSkChunkAlloc::Block53 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
SkChunkAlloc(size_t minSize)59 SkChunkAlloc::SkChunkAlloc(size_t minSize)
60 : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0)
61 {
62 }
63
~SkChunkAlloc()64 SkChunkAlloc::~SkChunkAlloc() {
65 this->reset();
66 }
67
reset()68 void SkChunkAlloc::reset() {
69 fBlock->freeChain();
70 fBlock = NULL;
71 fPool->freeChain();
72 fPool = NULL;
73 fTotalCapacity = 0;
74 }
75
reuse()76 void SkChunkAlloc::reuse() {
77 if (fPool && fBlock) {
78 fPool->tail()->fNext = fBlock;
79 }
80 fPool = fBlock;
81 fBlock = NULL;
82 fTotalCapacity = 0;
83 }
84
newBlock(size_t bytes,AllocFailType ftype)85 SkChunkAlloc::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
alloc(size_t bytes,AllocFailType ftype)110 void* 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
unalloc(void * ptr)132 size_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
contains(const void * addr) const147 bool 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