annotate thread/BlockAllocator.h @ 189:e4a57215ddee

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