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