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 };
53
SkChunkAlloc(size_t minSize)54 SkChunkAlloc::SkChunkAlloc(size_t minSize)
55 : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0)
56 {
57 }
58
~SkChunkAlloc()59 SkChunkAlloc::~SkChunkAlloc() {
60 this->reset();
61 }
62
reset()63 void SkChunkAlloc::reset() {
64 fBlock->freeChain();
65 fBlock = NULL;
66 fPool->freeChain();
67 fPool = NULL;
68 fTotalCapacity = 0;
69 }
70
reuse()71 void SkChunkAlloc::reuse() {
72 if (fPool && fBlock) {
73 fPool->tail()->fNext = fBlock;
74 }
75 fPool = fBlock;
76 fBlock = NULL;
77 fTotalCapacity = 0;
78 }
79
newBlock(size_t bytes,AllocFailType ftype)80 SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
81 Block* block = fPool;
82
83 if (block && bytes <= block->fFreeSize) {
84 fPool = block->fNext;
85 return block;
86 }
87
88 size_t size = SkMax32((int32_t)bytes, (int32_t)fMinSize);
89
90 block = (Block*)sk_malloc_flags(sizeof(Block) + size,
91 ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
92
93 if (block) {
94 // block->fNext = fBlock;
95 block->fFreeSize = size;
96 block->fFreePtr = block->startOfData();
97
98 fTotalCapacity += size;
99 }
100 return block;
101 }
102
alloc(size_t bytes,AllocFailType ftype)103 void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
104 bytes = SkAlign4(bytes);
105
106 Block* block = fBlock;
107
108 if (block == NULL || bytes > block->fFreeSize) {
109 block = this->newBlock(bytes, ftype);
110 if (NULL == block) {
111 return NULL;
112 }
113 block->fNext = fBlock;
114 fBlock = block;
115 }
116
117 SkASSERT(block && bytes <= block->fFreeSize);
118 void* ptr = block->fFreePtr;
119
120 block->fFreeSize -= bytes;
121 block->fFreePtr += bytes;
122 return ptr;
123 }
124
unalloc(void * ptr)125 size_t SkChunkAlloc::unalloc(void* ptr) {
126 size_t bytes = 0;
127 Block* block = fBlock;
128 if (block) {
129 char* cPtr = reinterpret_cast<char*>(ptr);
130 char* start = block->startOfData();
131 if (start <= cPtr && cPtr < block->fFreePtr) {
132 bytes = block->fFreePtr - cPtr;
133 block->fFreeSize += bytes;
134 block->fFreePtr = cPtr;
135 }
136 }
137 return bytes;
138 }
139
140