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