/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkChunkAlloc.h" // Don't malloc any chunks smaller than this #define MIN_CHUNKALLOC_BLOCK_SIZE 1024 // Return the new min blocksize given the current value static size_t increase_next_size(size_t size) { return size + (size >> 1); } /////////////////////////////////////////////////////////////////////////////// struct SkChunkAlloc::Block { Block* fNext; size_t fFreeSize; char* fFreePtr; // data[] follows char* startOfData() { return reinterpret_cast<char*>(this + 1); } static void FreeChain(Block* block) { while (block) { Block* next = block->fNext; sk_free(block); block = next; } }; bool contains(const void* addr) const { const char* ptr = reinterpret_cast<const char*>(addr); return ptr >= (const char*)(this + 1) && ptr < fFreePtr; } }; /////////////////////////////////////////////////////////////////////////////// SkChunkAlloc::SkChunkAlloc(size_t minSize) { if (minSize < MIN_CHUNKALLOC_BLOCK_SIZE) { minSize = MIN_CHUNKALLOC_BLOCK_SIZE; } fBlock = NULL; fMinSize = minSize; fChunkSize = fMinSize; fTotalCapacity = 0; fTotalUsed = 0; fBlockCount = 0; } SkChunkAlloc::~SkChunkAlloc() { this->reset(); } void SkChunkAlloc::reset() { Block::FreeChain(fBlock); fBlock = NULL; fChunkSize = fMinSize; // reset to our initial minSize fTotalCapacity = 0; fTotalUsed = 0; fBlockCount = 0; } SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { size_t size = bytes; if (size < fChunkSize) { size = fChunkSize; } Block* block = (Block*)sk_malloc_flags(sizeof(Block) + size, ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0); if (block) { // block->fNext = fBlock; block->fFreeSize = size; block->fFreePtr = block->startOfData(); fTotalCapacity += size; fBlockCount += 1; fChunkSize = increase_next_size(fChunkSize); } return block; } void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { fTotalUsed += bytes; bytes = SkAlign4(bytes); Block* block = fBlock; if (block == NULL || bytes > block->fFreeSize) { block = this->newBlock(bytes, ftype); if (NULL == block) { return NULL; } block->fNext = fBlock; fBlock = block; } SkASSERT(block && bytes <= block->fFreeSize); char* ptr = block->fFreePtr; block->fFreeSize -= bytes; block->fFreePtr = ptr + bytes; return ptr; } size_t SkChunkAlloc::unalloc(void* ptr) { size_t bytes = 0; Block* block = fBlock; if (block) { char* cPtr = reinterpret_cast<char*>(ptr); char* start = block->startOfData(); if (start <= cPtr && cPtr < block->fFreePtr) { bytes = block->fFreePtr - cPtr; block->fFreeSize += bytes; block->fFreePtr = cPtr; } } return bytes; } bool SkChunkAlloc::contains(const void* addr) const { const Block* block = fBlock; while (block) { if (block->contains(addr)) { return true; } block = block->fNext; } return false; }