Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "SkChunkAlloc.h"
     11 
     12 struct SkChunkAlloc::Block {
     13     Block*  fNext;
     14     size_t  fFreeSize;
     15     char*   fFreePtr;
     16     // data[] follows
     17 
     18     char* startOfData() {
     19         return reinterpret_cast<char*>(this + 1);
     20     }
     21 
     22     void freeChain() {    // this can be null
     23         Block* block = this;
     24         while (block) {
     25             Block* next = block->fNext;
     26             sk_free(block);
     27             block = next;
     28         }
     29     };
     30 
     31     Block* tail() {
     32         Block* block = this;
     33         if (block) {
     34             for (;;) {
     35                 Block* next = block->fNext;
     36                 if (NULL == next) {
     37                     break;
     38                 }
     39                 block = next;
     40             }
     41         }
     42         return block;
     43     }
     44 
     45     bool contains(const void* addr) const {
     46         const char* ptr = reinterpret_cast<const char*>(addr);
     47         return ptr >= (const char*)(this + 1) && ptr < fFreePtr;
     48     }
     49 };
     50 
     51 SkChunkAlloc::SkChunkAlloc(size_t minSize)
     52     : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0)
     53 {
     54 }
     55 
     56 SkChunkAlloc::~SkChunkAlloc() {
     57     this->reset();
     58 }
     59 
     60 void SkChunkAlloc::reset() {
     61     fBlock->freeChain();
     62     fBlock = NULL;
     63     fPool->freeChain();
     64     fPool = NULL;
     65     fTotalCapacity = 0;
     66 }
     67 
     68 void SkChunkAlloc::reuse() {
     69     if (fPool && fBlock) {
     70         fPool->tail()->fNext = fBlock;
     71     }
     72     fPool = fBlock;
     73     fBlock = NULL;
     74     fTotalCapacity = 0;
     75 }
     76 
     77 SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
     78     Block* block = fPool;
     79 
     80     if (block && bytes <= block->fFreeSize) {
     81         fPool = block->fNext;
     82         return block;
     83     }
     84 
     85     size_t size = bytes;
     86     if (size < fMinSize)
     87         size = fMinSize;
     88 
     89     block = (Block*)sk_malloc_flags(sizeof(Block) + size,
     90                         ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
     91 
     92     if (block) {
     93         //    block->fNext = fBlock;
     94         block->fFreeSize = size;
     95         block->fFreePtr = block->startOfData();
     96 
     97         fTotalCapacity += size;
     98     }
     99     return block;
    100 }
    101 
    102 void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
    103     bytes = SkAlign4(bytes);
    104 
    105     Block* block = fBlock;
    106 
    107     if (block == NULL || bytes > block->fFreeSize) {
    108         block = this->newBlock(bytes, ftype);
    109         if (NULL == block) {
    110             return NULL;
    111         }
    112         block->fNext = fBlock;
    113         fBlock = block;
    114     }
    115 
    116     SkASSERT(block && bytes <= block->fFreeSize);
    117     void* ptr = block->fFreePtr;
    118 
    119     block->fFreeSize -= bytes;
    120     block->fFreePtr += bytes;
    121     return ptr;
    122 }
    123 
    124 size_t SkChunkAlloc::unalloc(void* ptr) {
    125     size_t bytes = 0;
    126     Block* block = fBlock;
    127     if (block) {
    128         char* cPtr = reinterpret_cast<char*>(ptr);
    129         char* start = block->startOfData();
    130         if (start <= cPtr && cPtr < block->fFreePtr) {
    131             bytes = block->fFreePtr - cPtr;
    132             block->fFreeSize += bytes;
    133             block->fFreePtr = cPtr;
    134         }
    135     }
    136     return bytes;
    137 }
    138 
    139 bool SkChunkAlloc::contains(const void* addr) const {
    140     const Block* block = fBlock;
    141     while (block) {
    142         if (block->contains(addr)) {
    143             return true;
    144         }
    145         block = block->fNext;
    146     }
    147     return false;
    148 }
    149 
    150