annotate thread/BlockAllocator.h @ 307:f26e2d35dde9

* Add new files
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 13 Jul 2010 11:35:13 +0000
parents b97f4f926f48
children 701233f8ed41
rev   line source
c@292 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@292 2
c@292 3 /*
c@292 4 QM DSP Library
c@292 5
c@292 6 Centre for Digital Music, Queen Mary, University of London.
c@292 7
c@292 8 This file is derived from the FSB Allocator by Juha Nieminen. The
c@292 9 underlying method is unchanged, but the class has been refactored
c@292 10 to permit multiple separate allocators (e.g. one per thread)
c@292 11 rather than use a single global one (and to fit house style).
c@292 12
c@292 13 Copyright (c) 2008 Juha Nieminen
c@292 14
c@292 15 Permission is hereby granted, free of charge, to any person obtaining a copy
c@292 16 of this software and associated documentation files (the "Software"), to deal
c@292 17 in the Software without restriction, including without limitation the rights
c@292 18 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
c@292 19 copies of the Software, and to permit persons to whom the Software is
c@292 20 furnished to do so, subject to the following conditions:
c@292 21
c@292 22 The above copyright notice and this permission notice shall be included in
c@292 23 all copies or substantial portions of the Software.
c@292 24
c@292 25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
c@292 26 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
c@292 27 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
c@292 28 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
c@292 29 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
c@292 30 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
c@292 31 THE SOFTWARE.
c@292 32 */
c@292 33
c@292 34 #ifndef _BLOCK_ALLOCATOR_H_
c@292 35 #define _BLOCK_ALLOCATOR_H_
c@292 36
c@292 37 #include <cstdlib>
c@292 38
c@292 39 /**
c@292 40 * BlockAllocator is a simple allocator for fixed-size (usually small)
c@292 41 * chunks of memory. The size of an element is specified in the
c@292 42 * BlockAllocator constructor, and the functions allocate() and
c@292 43 * deallocate() are used to obtain and release a single element at a
c@292 44 * time.
c@292 45 *
c@292 46 * BlockAllocator may be an appropriate class to use in situations
c@292 47 * involving a very large number of allocations and deallocations of
c@292 48 * simple, identical objects across multiple threads (a hard situation
c@292 49 * for a generic system malloc implementation to handle well). Retain
c@292 50 * one BlockAllocator per thread (the class itself is not
c@292 51 * thread-safe), and ensure that each thread uses its own allocator
c@292 52 * exclusively.
c@292 53 *
c@292 54 * BlockAllocator is based on Juha Nieminen's more general
c@292 55 * FSBAllocator.
c@292 56 */
c@292 57 class BlockAllocator
c@292 58 {
c@292 59 public:
c@292 60 typedef std::size_t data_t;
c@292 61
c@292 62 BlockAllocator(int elementSize) : m_sz(elementSize) { }
c@292 63
c@292 64 void *
c@292 65 allocate()
c@292 66 {
c@292 67 if (m_freelist.empty()) {
c@292 68 m_freelist.push_back(m_blocks.data.size());
c@292 69 m_blocks.data.push_back(Block(this));
c@292 70 }
c@292 71
c@292 72 const data_t index = m_freelist.back();
c@292 73 Block &block = m_blocks.data[index];
c@292 74 void *retval = block.allocate(index);
c@292 75 if (block.isFull()) m_freelist.pop_back();
c@292 76
c@292 77 return retval;
c@292 78 }
c@292 79
c@292 80 void
c@292 81 deallocate(void *ptr)
c@292 82 {
c@292 83 if (!ptr) return;
c@292 84
c@292 85 data_t *unitPtr = (data_t *)ptr;
c@292 86 const data_t blockIndex = unitPtr[elementSizeInDataUnits()];
c@292 87 Block& block = m_blocks.data[blockIndex];
c@292 88
c@292 89 if (block.isFull()) m_freelist.push_back(blockIndex);
c@292 90 block.deallocate(unitPtr);
c@292 91 }
c@292 92
c@292 93 private:
c@292 94 inline data_t elementsPerBlock() const {
c@292 95 return 512;
c@292 96 }
c@292 97 inline data_t dataSize() const {
c@292 98 return sizeof(data_t);
c@292 99 }
c@292 100 inline data_t elementSizeInDataUnits() const {
c@292 101 return (m_sz + (dataSize() - 1)) / dataSize();
c@292 102 }
c@292 103 inline data_t unitSizeInDataUnits() const {
c@292 104 return elementSizeInDataUnits() + 1;
c@292 105 }
c@292 106 inline data_t blockSizeInDataUnits() const {
c@292 107 return elementsPerBlock() * unitSizeInDataUnits();
c@292 108 }
c@292 109
c@292 110 class Block
c@292 111 {
c@292 112 public:
c@292 113 Block(BlockAllocator *a) :
c@292 114 m_a(a),
c@292 115 m_block(0),
c@292 116 m_firstFreeUnit(data_t(-1)),
c@292 117 m_allocated(0),
c@292 118 m_end(0)
c@292 119 {}
c@292 120
c@292 121 ~Block() {
c@292 122 delete[] m_block;
c@292 123 }
c@292 124
c@292 125 bool isFull() const {
c@292 126 return m_allocated == m_a->elementsPerBlock();
c@292 127 }
c@292 128
c@292 129 void clear() {
c@292 130 delete[] m_block;
c@292 131 m_block = 0;
c@292 132 m_firstFreeUnit = data_t(-1);
c@292 133 }
c@292 134
c@292 135 void *allocate(data_t index) {
c@292 136
c@292 137 if (m_firstFreeUnit == data_t(-1)) {
c@292 138
c@292 139 if (!m_block) {
c@292 140 m_block = new data_t[m_a->blockSizeInDataUnits()];
c@292 141 m_end = 0;
c@292 142 }
c@292 143
c@292 144 data_t *retval = m_block + m_end;
c@292 145 m_end += m_a->unitSizeInDataUnits();
c@292 146 retval[m_a->elementSizeInDataUnits()] = index;
c@292 147 ++m_allocated;
c@292 148 return retval;
c@292 149
c@292 150 } else {
c@292 151
c@292 152 data_t *retval = m_block + m_firstFreeUnit;
c@292 153 m_firstFreeUnit = *retval;
c@292 154 ++m_allocated;
c@292 155 return retval;
c@292 156 }
c@292 157 }
c@292 158
c@292 159 void deallocate(data_t *ptr) {
c@292 160
c@292 161 *ptr = m_firstFreeUnit;
c@292 162 m_firstFreeUnit = ptr - m_block;
c@292 163
c@292 164 if (--m_allocated == 0) clear();
c@292 165 }
c@292 166
c@292 167 private:
c@292 168 const BlockAllocator *m_a;
c@292 169 data_t *m_block;
c@292 170 data_t m_firstFreeUnit;
c@292 171 data_t m_allocated;
c@292 172 data_t m_end;
c@292 173 };
c@292 174
c@292 175 struct Blocks
c@292 176 {
c@292 177 std::vector<Block> data;
c@292 178
c@292 179 Blocks() {
c@292 180 data.reserve(1024);
c@292 181 }
c@292 182 };
c@292 183
c@292 184 const int m_sz;
c@292 185 Blocks m_blocks;
c@292 186 std::vector<data_t> m_freelist;
c@292 187 };
c@292 188
c@292 189 #endif