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