aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
fixedAllocator_inl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40#pragma once
41
42
51// ============================================================================
53
54// ============================================================================
55
56namespace gum {
57
58 // ============================================================================
59 // Initializes a Chunk object
60 // ============================================================================
61 INLINE void FixedAllocator::_Chunk_::_init_(const std::size_t& blockSize,
62 const unsigned char& numBlocks) {
63 // Chunk memory space allocation. A chunk allocates a memory of blockSize *
64 // numBlocks size.
65 // The chunk will then give us numBlocks distinct blocks of blockSize from
66 // that space.
67 _pData_ = new unsigned char[blockSize * numBlocks];
68
69 // The first available block of memory is logically at the beginning.
71
72 // The number of block still available is all the blocks at the beginning.
73 _blocksAvailable_ = numBlocks;
74
75 // For each unallocated block, the first byte contains a number.
76 // That number is the index of the next available block
77 // Since we're at the beginning, next free block is the next one simply.
78 // Following code initiate those number for each block
79 unsigned char* p = _pData_;
80 for (unsigned char indexBlock = 0; indexBlock != numBlocks; p += blockSize)
81 *p = ++indexBlock;
82 }
83
84 // ============================================================================
85 // Allocates a block of memory
86 // ============================================================================
87 INLINE void* FixedAllocator::_Chunk_::_allocate_(const std::size_t& blockSize) {
89 // If no block is available return nullptr
90 return NULL;
91
92 // _pData_ points to the beginning of allocated space.
93 // _firstAvailableBlock_ gives us how many block to pass before getting
94 // the good one. We have to multiply by blockSize to get the good memory
95 // emplacement
96 unsigned char* pResult = _pData_ + (_firstAvailableBlock_ * blockSize);
97
98 // Remember that the first byte of each block gives us the index of next
99 // available slot.
100 // The new first availble block will be at the index indicating in this
101 // block.
102 _firstAvailableBlock_ = *pResult;
103
104 // We lose one block
106
107 return pResult;
108 }
109
110 // ============================================================================
111 // Deallocates a block of memory
112 // ============================================================================
113 INLINE void FixedAllocator::_Chunk_::_deallocat_(void* pDeallocatedBlock,
114 const std::size_t& blockSize) {
115 // first, ensure that deallocated is in this chunk
116 GUM_ASSERT(pDeallocatedBlock >= _pData_);
117
118 // Conversion pf pointer for handling
119 unsigned char* toRelease = static_cast< unsigned char* >(pDeallocatedBlock);
120
121 // Alignement check
122 GUM_ASSERT((toRelease - _pData_) % blockSize == 0);
123
124 // First byte of toRelease has now to give the index of current first
125 // available block
126 *toRelease = _firstAvailableBlock_;
127
128 // So that first available block points to it
129 _firstAvailableBlock_ = static_cast< unsigned char >((toRelease - _pData_) / blockSize);
130
131 // Truncation check
132 GUM_ASSERT(_firstAvailableBlock_ == (toRelease - _pData_) / blockSize);
133
134 // We gain one block, yeah
136 }
137
138 // ============================================================================
139 // Releases the allocated memory
140 // ============================================================================
141 INLINE void FixedAllocator::_Chunk_::_release_() { delete[] _pData_; }
142
143 // ############################################################################
144 // @name Constructors / Destructors
145 // ############################################################################
146
147 // ============================================================================
148 // Constructor.
149 // ============================================================================
150 INLINE FixedAllocator::FixedAllocator(const std::size_t& blockSize,
151 const unsigned char& numBlocks) {
152 // GUM_CONSTRUCTOR(FixedAllocator);
153 _blockSize_ = blockSize;
154 _numBlocks_ = numBlocks;
155 _allocChunk_ = _chunks_.begin();
156 _deallocChunk_ = _chunks_.begin();
157 }
158
159 // ============================================================================
160 // Destructor.
161 // ============================================================================
163 for (_Chunks_::iterator chunkIter = _chunks_.begin(); chunkIter != _chunks_.end(); ++chunkIter)
164 chunkIter->_release_();
165 // GUM_DESTRUCTOR(FixedAllocator);
166 }
167
168 // ############################################################################
169 // @name Allocator / Deallocator
170 // ############################################################################
171
172 // ============================================================================
173 // Allocates a block
174 // ============================================================================
176 if (_chunks_.empty() || _allocChunk_->_blocksAvailable_ == 0) {
177 // no available memory in this chunk
178 // Try to find one with memory available
179 for (_Chunks_::iterator chunksIter = _chunks_.begin();; ++chunksIter) {
180 if (chunksIter == _chunks_.end()) {
181 // All chunks are filled up. Adding a new one
182 _chunks_.reserve(_chunks_.size() + 1);
183 _Chunk_ newChunk;
184 newChunk._init_(_blockSize_, _numBlocks_);
185 _chunks_.push_back(newChunk);
186 _allocChunk_ = _chunks_.end();
187 --_allocChunk_;
189 break;
190 }
191 if (chunksIter->_blocksAvailable_ > 0) {
192 // Found a chunk
193 _allocChunk_ = chunksIter;
194 break;
195 }
196 }
197 }
198 return _allocChunk_->_allocate_(_blockSize_);
199 }
200
201 // ============================================================================
202 // Deallocates a block
203 // ============================================================================
204 INLINE void FixedAllocator::deallocate(void* pDeallocatedBlock) {
205 if (_deallocChunk_->_pData_ > pDeallocatedBlock
206 || pDeallocatedBlock > (_deallocChunk_->_pData_ + (_numBlocks_ * _blockSize_))) {
207 // If not things get ugly
208 // We have to find where the Chunk containing this pointer is
209 std::ptrdiff_t offset = 0;
210
211 // We perform a bidirectionnal search from _deallocChunk_
212 while (true) {
213 ++offset;
214 // First we look for the one going to the end of the vector
215 if ((_deallocChunk_ + offset) < _chunks_.end()) {
216 if ((_deallocChunk_ + offset)->_pData_ <= pDeallocatedBlock
217 && pDeallocatedBlock
218 < ((_deallocChunk_ + offset)->_pData_ + (_numBlocks_ * _blockSize_))) {
219 // If pointed chunk contains this pointer, deallocation find the
220 // place
221 _deallocChunk_ = (_deallocChunk_ + offset);
222 break;
223 }
224 }
225
226 // Then we look for the one going to the beginning of the vector
227 if ((_deallocChunk_ - offset) >= _chunks_.begin()) {
228 if ((_deallocChunk_ - offset)->_pData_ <= pDeallocatedBlock
229 && pDeallocatedBlock
230 < ((_deallocChunk_ - offset)->_pData_ + (_numBlocks_ * _blockSize_))) {
231 // If pointed chunk contains this pointer, deallocation find the
232 // place
233 _deallocChunk_ = (_deallocChunk_ - offset);
234 break;
235 }
236 }
237 }
238 }
239 _deallocChunk_->_deallocat_(pDeallocatedBlock, _blockSize_);
240 }
241
242} // namespace gum
void deallocate(void *pDeallocatedBlock)
Deallocates a block.
FixedAllocator(const std::size_t &blockSize, const unsigned char &numBlocks=UCHAR_MAX)
Constructor.
_Chunks_::iterator _deallocChunk_
Last Chunk used for a deallocation.
unsigned char _numBlocks_
The maximum number of blocks a chunk can allocate.
std::size_t _blockSize_
Size of a memory block allocated.
_Chunks_::iterator _allocChunk_
Last Chunk used for an allocation.
void * allocate()
Allocates a block.
Headers of gum::FixedAllocator.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
Allocates objects of one given size.
void * _allocate_(const std::size_t &blockSize)
Allocates a block of memory.
unsigned char _firstAvailableBlock_
Holds the index of the first block available in this chunck.
void _deallocat_(void *p, const std::size_t &blockSize)
Deallocates a block of memory.
unsigned char * _pData_
Pointer to the managed memory itself.
void _init_(const std::size_t &blockSize, const unsigned char &numBlocks)
Initializes a Chunk object.
void _release_()
Releases the allocated memory.
unsigned char _blocksAvailable_
Number of blocks available in this chunck.