annotate thread/BlockAllocator.h @ 378:f5b5f64835b9

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