| /* | 
 |  * 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; | 
 | } |