Home | History | Annotate | Download | only in core
      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 
     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     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 
     54 SkChunkAlloc::SkChunkAlloc(size_t minSize)
     55     : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0)
     56 {
     57 }
     58 
     59 SkChunkAlloc::~SkChunkAlloc() {
     60     this->reset();
     61 }
     62 
     63 void SkChunkAlloc::reset() {
     64     fBlock->freeChain();
     65     fBlock = NULL;
     66     fPool->freeChain();
     67     fPool = NULL;
     68     fTotalCapacity = 0;
     69 }
     70 
     71 void SkChunkAlloc::reuse() {
     72     if (fPool && fBlock) {
     73         fPool->tail()->fNext = fBlock;
     74     }
     75     fPool = fBlock;
     76     fBlock = NULL;
     77     fTotalCapacity = 0;
     78 }
     79 
     80 SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
     81     Block* block = fPool;
     82 
     83     if (block && bytes <= block->fFreeSize) {
     84         fPool = block->fNext;
     85         return block;
     86     }
     87 
     88     size_t  size = SkMax32((int32_t)bytes, (int32_t)fMinSize);
     89 
     90     block = (Block*)sk_malloc_flags(sizeof(Block) + size,
     91                         ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
     92 
     93     if (block) {
     94         //    block->fNext = fBlock;
     95         block->fFreeSize = size;
     96         block->fFreePtr = block->startOfData();
     97 
     98         fTotalCapacity += size;
     99     }
    100     return block;
    101 }
    102 
    103 void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
    104     bytes = SkAlign4(bytes);
    105 
    106     Block* block = fBlock;
    107 
    108     if (block == NULL || bytes > block->fFreeSize) {
    109         block = this->newBlock(bytes, ftype);
    110         if (NULL == block) {
    111             return NULL;
    112         }
    113         block->fNext = fBlock;
    114         fBlock = block;
    115     }
    116 
    117     SkASSERT(block && bytes <= block->fFreeSize);
    118     void* ptr = block->fFreePtr;
    119 
    120     block->fFreeSize -= bytes;
    121     block->fFreePtr += bytes;
    122     return ptr;
    123 }
    124 
    125 size_t SkChunkAlloc::unalloc(void* ptr) {
    126     size_t bytes = 0;
    127     Block* block = fBlock;
    128     if (block) {
    129         char* cPtr = reinterpret_cast<char*>(ptr);
    130         char* start = block->startOfData();
    131         if (start <= cPtr && cPtr < block->fFreePtr) {
    132             bytes = block->fFreePtr - cPtr;
    133             block->fFreeSize += bytes;
    134             block->fFreePtr = cPtr;
    135         }
    136     }
    137     return bytes;
    138 }
    139 
    140