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
12struct 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
51SkChunkAlloc::SkChunkAlloc(size_t minSize)
52    : fBlock(NULL), fMinSize(SkAlign4(minSize)), fPool(NULL), fTotalCapacity(0)
53{
54}
55
56SkChunkAlloc::~SkChunkAlloc() {
57    this->reset();
58}
59
60void SkChunkAlloc::reset() {
61    fBlock->freeChain();
62    fBlock = NULL;
63    fPool->freeChain();
64    fPool = NULL;
65    fTotalCapacity = 0;
66}
67
68void SkChunkAlloc::reuse() {
69    if (fPool && fBlock) {
70        fPool->tail()->fNext = fBlock;
71    }
72    fPool = fBlock;
73    fBlock = NULL;
74    fTotalCapacity = 0;
75}
76
77SkChunkAlloc::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
102void* 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
124size_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
139bool 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