Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkChunkAlloc.h"
      9 
     10 // Don't malloc any chunks smaller than this
     11 #define MIN_CHUNKALLOC_BLOCK_SIZE   1024
     12 
     13 // Return the new min blocksize given the current value
     14 static size_t increase_next_size(size_t size) {
     15     return size + (size >> 1);
     16 }
     17 
     18 ///////////////////////////////////////////////////////////////////////////////
     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     static void FreeChain(Block* block) {
     31         while (block) {
     32             Block* next = block->fNext;
     33             sk_free(block);
     34             block = next;
     35         }
     36     };
     37 
     38     bool contains(const void* addr) const {
     39         const char* ptr = reinterpret_cast<const char*>(addr);
     40         return ptr >= (const char*)(this + 1) && ptr < fFreePtr;
     41     }
     42 };
     43 
     44 ///////////////////////////////////////////////////////////////////////////////
     45 
     46 SkChunkAlloc::SkChunkAlloc(size_t minSize) {
     47     if (minSize < MIN_CHUNKALLOC_BLOCK_SIZE) {
     48         minSize = MIN_CHUNKALLOC_BLOCK_SIZE;
     49     }
     50 
     51     fBlock = NULL;
     52     fMinSize = minSize;
     53     fChunkSize = fMinSize;
     54     fTotalCapacity = 0;
     55     fBlockCount = 0;
     56 }
     57 
     58 SkChunkAlloc::~SkChunkAlloc() {
     59     this->reset();
     60 }
     61 
     62 void SkChunkAlloc::reset() {
     63     Block::FreeChain(fBlock);
     64     fBlock = NULL;
     65     fChunkSize = fMinSize;  // reset to our initial minSize
     66     fTotalCapacity = 0;
     67     fBlockCount = 0;
     68 }
     69 
     70 SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
     71     size_t size = bytes;
     72     if (size < fChunkSize) {
     73         size = fChunkSize;
     74     }
     75 
     76     Block* block = (Block*)sk_malloc_flags(sizeof(Block) + size,
     77                         ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
     78 
     79     if (block) {
     80         //    block->fNext = fBlock;
     81         block->fFreeSize = size;
     82         block->fFreePtr = block->startOfData();
     83 
     84         fTotalCapacity += size;
     85         fBlockCount += 1;
     86 
     87         fChunkSize = increase_next_size(fChunkSize);
     88     }
     89     return block;
     90 }
     91 
     92 void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
     93     bytes = SkAlign4(bytes);
     94 
     95     Block* block = fBlock;
     96 
     97     if (block == NULL || bytes > block->fFreeSize) {
     98         block = this->newBlock(bytes, ftype);
     99         if (NULL == block) {
    100             return NULL;
    101         }
    102         block->fNext = fBlock;
    103         fBlock = block;
    104     }
    105 
    106     SkASSERT(block && bytes <= block->fFreeSize);
    107     char* ptr = block->fFreePtr;
    108 
    109     block->fFreeSize -= bytes;
    110     block->fFreePtr = ptr + bytes;
    111     return ptr;
    112 }
    113 
    114 size_t SkChunkAlloc::unalloc(void* ptr) {
    115     size_t bytes = 0;
    116     Block* block = fBlock;
    117     if (block) {
    118         char* cPtr = reinterpret_cast<char*>(ptr);
    119         char* start = block->startOfData();
    120         if (start <= cPtr && cPtr < block->fFreePtr) {
    121             bytes = block->fFreePtr - cPtr;
    122             block->fFreeSize += bytes;
    123             block->fFreePtr = cPtr;
    124         }
    125     }
    126     return bytes;
    127 }
    128 
    129 bool SkChunkAlloc::contains(const void* addr) const {
    130     const Block* block = fBlock;
    131     while (block) {
    132         if (block->contains(addr)) {
    133             return true;
    134         }
    135         block = block->fNext;
    136     }
    137     return false;
    138 }
    139