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 0 : char* startOfData() {
19 0 : return reinterpret_cast<char*>(this + 1);
20 : }
21 :
22 0 : void freeChain() { // this can be null
23 0 : Block* block = this;
24 0 : while (block) {
25 0 : Block* next = block->fNext;
26 0 : sk_free(block);
27 0 : block = next;
28 : }
29 0 : };
30 :
31 0 : Block* tail() {
32 0 : Block* block = this;
33 0 : if (block) {
34 0 : for (;;) {
35 0 : Block* next = block->fNext;
36 0 : if (NULL == next) {
37 : break;
38 : }
39 0 : block = next;
40 : }
41 : }
42 0 : return block;
43 : }
44 :
45 0 : bool contains(const void* addr) const {
46 0 : const char* ptr = reinterpret_cast<const char*>(addr);
47 0 : return ptr >= (const char*)(this + 1) && ptr < fFreePtr;
48 : }
49 : };
50 :
51 0 : SkChunkAlloc::SkChunkAlloc(size_t minSize)
52 0 : : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0)
53 : {
54 0 : }
55 :
56 0 : SkChunkAlloc::~SkChunkAlloc() {
57 0 : this->reset();
58 0 : }
59 :
60 0 : void SkChunkAlloc::reset() {
61 0 : fBlock->freeChain();
62 0 : fBlock = NULL;
63 0 : fPool->freeChain();
64 0 : fPool = NULL;
65 0 : fTotalCapacity = 0;
66 0 : }
67 :
68 0 : void SkChunkAlloc::reuse() {
69 0 : if (fPool && fBlock) {
70 0 : fPool->tail()->fNext = fBlock;
71 : }
72 0 : fPool = fBlock;
73 0 : fBlock = NULL;
74 0 : fTotalCapacity = 0;
75 0 : }
76 :
77 0 : SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
78 0 : Block* block = fPool;
79 :
80 0 : if (block && bytes <= block->fFreeSize) {
81 0 : fPool = block->fNext;
82 0 : return block;
83 : }
84 :
85 0 : size_t size = bytes;
86 0 : if (size < fMinSize)
87 0 : size = fMinSize;
88 :
89 : block = (Block*)sk_malloc_flags(sizeof(Block) + size,
90 0 : ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
91 :
92 0 : if (block) {
93 : // block->fNext = fBlock;
94 0 : block->fFreeSize = size;
95 0 : block->fFreePtr = block->startOfData();
96 :
97 0 : fTotalCapacity += size;
98 : }
99 0 : return block;
100 : }
101 :
102 0 : void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
103 0 : bytes = SkAlign4(bytes);
104 :
105 0 : Block* block = fBlock;
106 :
107 0 : if (block == NULL || bytes > block->fFreeSize) {
108 0 : block = this->newBlock(bytes, ftype);
109 0 : if (NULL == block) {
110 0 : return NULL;
111 : }
112 0 : block->fNext = fBlock;
113 0 : fBlock = block;
114 : }
115 :
116 0 : SkASSERT(block && bytes <= block->fFreeSize);
117 0 : void* ptr = block->fFreePtr;
118 :
119 0 : block->fFreeSize -= bytes;
120 0 : block->fFreePtr += bytes;
121 0 : return ptr;
122 : }
123 :
124 0 : size_t SkChunkAlloc::unalloc(void* ptr) {
125 0 : size_t bytes = 0;
126 0 : Block* block = fBlock;
127 0 : if (block) {
128 0 : char* cPtr = reinterpret_cast<char*>(ptr);
129 0 : char* start = block->startOfData();
130 0 : if (start <= cPtr && cPtr < block->fFreePtr) {
131 0 : bytes = block->fFreePtr - cPtr;
132 0 : block->fFreeSize += bytes;
133 0 : block->fFreePtr = cPtr;
134 : }
135 : }
136 0 : return bytes;
137 : }
138 :
139 0 : bool SkChunkAlloc::contains(const void* addr) const {
140 0 : const Block* block = fBlock;
141 0 : while (block) {
142 0 : if (block->contains(addr)) {
143 0 : return true;
144 : }
145 0 : block = block->fNext;
146 : }
147 0 : return false;
148 : }
149 :
|