aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
fixedAllocator.cpp
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 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-2026 *
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
41
50// ============================================================================
52// ============================================================================
53
54#ifdef GUM_NO_INLINE
56#endif
57
58namespace gum {
59 void FixedAllocator::_Chunk_::_init_(const std::size_t& blockSize,
60 const unsigned char& numBlocks) {
61 // Chunk memory space allocation. A chunk allocates a memory of blockSize *
62 // numBlocks size.
63 // The chunk will then give us numBlocks distinct blocks of blockSize from
64 // that space.
65 _pData_ = new unsigned char[blockSize * numBlocks];
66
67 // The first available block of memory is logically at the beginning.
69
70 // The number of block still available is all the blocks at the beginning.
71 _blocksAvailable_ = numBlocks;
72
73 // For each unallocated block, the first byte contains a number.
74 // That number is the index of the next available block
75 // Since we're at the beginning, next free block is the next one simply.
76 // Following code initiate those number for each block
77 unsigned char* p = _pData_;
78 for (unsigned char indexBlock = 0; indexBlock != numBlocks; p += blockSize) {
79 *p = ++indexBlock;
80 }
81 }
82
83 void* FixedAllocator::_Chunk_::_allocate_(const std::size_t& blockSize) {
84 if (!_blocksAvailable_) {
85 // If no block is available return nullptr
86 return nullptr;
87 }
88
89 // _pData_ points to the beginning of allocated space.
90 // _firstAvailableBlock_ gives us how many block to pass before getting
91 // the good one. We have to multiply by blockSize to get the good memory
92 // emplacement
93 unsigned char* pResult = _pData_ + (_firstAvailableBlock_ * blockSize);
94
95 // Remember that the first byte of each block gives us the index of next
96 // available slot.
97 // The new first available block will be at the index indicating in this
98 // block.
99 _firstAvailableBlock_ = *pResult;
100
101 // We lose one block
103
104 return pResult;
105 }
106
107 void FixedAllocator::_Chunk_::_deallocat_(void* pDeallocatedBlock, const std::size_t& blockSize) {
108 // first, ensure that deallocated is in this chunk
109 GUM_ASSERT(pDeallocatedBlock >= _pData_);
110
111 // Conversion pf pointer for handling
112 unsigned char* toRelease = static_cast< unsigned char* >(pDeallocatedBlock);
113
114 // Alignement check
115 GUM_ASSERT((toRelease - _pData_) % blockSize == 0);
116
117 // First byte of toRelease has now to give the index of current first
118 // available block
119 *toRelease = _firstAvailableBlock_;
120
121 // So that first available block points to it
122 _firstAvailableBlock_ = static_cast< unsigned char >((toRelease - _pData_) / blockSize);
123
124 // Truncation check
125 GUM_ASSERT(_firstAvailableBlock_ == (toRelease - _pData_) / blockSize);
126
127 // We gain one block, yeah
129 }
130
132 if (_chunks_.empty() || _allocChunk_->_blocksAvailable_ == 0) {
133 // no available memory in this chunk
134 // Try to find one with memory available
135 for (_Chunks_::iterator chunksIter = _chunks_.begin();; ++chunksIter) {
136 if (chunksIter == _chunks_.end()) {
137 // All chunks are filled up. Adding a new one
138 _chunks_.reserve(_chunks_.size() + 1);
139 _Chunk_ newChunk;
140 newChunk._init_(_blockSize_, _numBlocks_);
141 _chunks_.push_back(newChunk);
142 _allocChunk_ = _chunks_.end();
143 --_allocChunk_;
145 break;
146 }
147 if (chunksIter->_blocksAvailable_ > 0) {
148 // Found a chunk
149 _allocChunk_ = chunksIter;
150 break;
151 }
152 }
153 }
154 return _allocChunk_->_allocate_(_blockSize_);
155 }
156
157 void FixedAllocator::deallocate(void* pDeallocatedBlock) {
158 bool chunk_found = true;
159 if (_deallocChunk_->_pData_ > pDeallocatedBlock
160 || pDeallocatedBlock > (_deallocChunk_->_pData_ + (_numBlocks_ * _blockSize_))) {
161 // If not things get ugly
162 // We have to find where the Chunk containing this pointer is
163 std::ptrdiff_t offset = 0;
164
165 // We perform a bidirectional search from _deallocChunk_
166 bool iter_ok = true;
167 while (iter_ok) {
168 iter_ok = false;
169 ++offset;
170 // First we look for the one going to the end of the vector
171 if ((_deallocChunk_ + offset) < _chunks_.end()) {
172 iter_ok = true;
173 if ((_deallocChunk_ + offset)->_pData_ <= pDeallocatedBlock
174 && pDeallocatedBlock
175 < ((_deallocChunk_ + offset)->_pData_ + (_numBlocks_ * _blockSize_))) {
176 // If pointed chunk contains this pointer, deallocation find the
177 // place
178 _deallocChunk_ = (_deallocChunk_ + offset);
179 chunk_found = true;
180 break;
181 }
182 }
183
184 // Then we look for the one going to the beginning of the vector
185 if ((_deallocChunk_ - offset) >= _chunks_.begin()) {
186 iter_ok = true;
187 if ((_deallocChunk_ - offset)->_pData_ <= pDeallocatedBlock
188 && pDeallocatedBlock
189 < ((_deallocChunk_ - offset)->_pData_ + (_numBlocks_ * _blockSize_))) {
190 // If pointed chunk contains this pointer, deallocation find the
191 // place
192 _deallocChunk_ = (_deallocChunk_ - offset);
193 chunk_found = true;
194 break;
195 }
196 }
197 }
198 }
199
200 if (chunk_found) { _deallocChunk_->_deallocat_(pDeallocatedBlock, _blockSize_); }
201 }
202
203} // namespace gum
_Chunks_::iterator _deallocChunk_
Last Chunk used for a deallocation.
void deallocate(void *pDeallocatedBlock)
Deallocates a block.
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.
Inlines of gum::FixedAllocator.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
Allocates objects of one given size.
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 * _allocate_(const std::size_t &blockSize)
Allocates a block of memory.
void _init_(const std::size_t &blockSize, const unsigned char &numBlocks)
Initializes a Chunk object.
unsigned char _blocksAvailable_
Number of blocks available in this chunck.