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 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 54 SkChunkAlloc::SkChunkAlloc(size_t minSize) 55 : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0) 56 { 57 } 58 59 SkChunkAlloc::~SkChunkAlloc() { 60 this->reset(); 61 } 62 63 void SkChunkAlloc::reset() { 64 fBlock->freeChain(); 65 fBlock = NULL; 66 fPool->freeChain(); 67 fPool = NULL; 68 fTotalCapacity = 0; 69 } 70 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 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 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 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