ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
monoallocator.t.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This "template-definition-header" file is part of module \alib_monomem of the \aliblong.
4/// It may be used to instantiate custom versions of \alib{monomem;TPoolAllocator}, working with
5/// a different \ref alib_contmono_chaining "chained" allocator.
6/// @see Manual section \ref alib_manual_appendix_t_inl_files about the nature of ".t.inl"-files.
7///
8/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
9/// Published under \ref mainpage_license "Boost Software License".
10//==================================================================================================
11namespace alib { namespace monomem {
12
13#if !DOXYGEN
15template<typename TAllocator>
17 TAllocator& pAllocator,
18 size_t initialBufferSizeInKB,
19 unsigned int pBufferGrowthInPercent )
20{
22 ALIB_ASSERT_ERROR( initialBufferSizeInKB, "MONOMEM", "Initial buffer of 0kb requested." )
23
24 auto size= initialBufferSizeInKB * 1024;
25 auto* mem= pAllocator.allocate( size, alignof(detail::Buffer) );
26 auto* firstBuffer= new (mem) detail::Buffer( initialBufferSizeInKB * 1024 );
27
28 auto* result = reinterpret_cast<TMA*>( firstBuffer->allocate( sizeof(TMA), alignof(TMA) ) );
29 return new (result) TMA( ALIB_DBG(pDbgName,) pAllocator, firstBuffer,
30 initialBufferSizeInKB, pBufferGrowthInPercent );
31}
32#include "ALib.Lang.CIMethods.H"
33#endif
34
35template<typename TAllocator>
37{
38 #if ALIB_DEBUG_CRITICAL_SECTIONS
39 DbgCriticalSectionsPH.Destruct();
40 #endif
41
42 #if ALIB_DEBUG_MEMORY
43 integer cntBuffers = 0;
44 #endif
45
46 // first delete recyclable buffers
47 auto* cnk= recyclables;
48 while( cnk )
49 {
50 #if ALIB_DEBUG_MEMORY
51 ++cntBuffers;
52 #endif
53
54 auto* next= cnk->previous;
55 allocMember::GetAllocator().free( cnk, cnk->Size() );
56 cnk= next;
57 }
58
59 // then the active ones
60 cnk= buffer;
61 while( cnk )
62 {
63 auto* next= cnk->previous;
64 allocMember::GetAllocator().free( cnk, cnk->Size() );
65
66 #if ALIB_DEBUG_MEMORY
67 ++cntBuffers;
68 #endif
69 cnk= next;
70 }
71
72 #if ALIB_DEBUG_MEMORY
73 ALIB_ASSERT_WARNING( cntBuffers <= 15, "MONOMEM",
74 "ALIB_DEBUG_MEMORY Warning: More than 15 buffers allocated. "
75 "Buffer size might be increased? #Buffers: ", cntBuffers )
76 #endif
77 //ALIB_DCS_RELEASE
78
79}
80
81template<typename TAllocator>
84
85 #if ALIB_DEBUG
86 // check if a (forbidden!) full reset is requested on a self-contained instance
87 if( snapshot.buffer == nullptr )
88 {
89 detail::Buffer* firstBuffer= buffer;
90 while( firstBuffer->previous )
91 firstBuffer= firstBuffer->previous;
92
93 ALIB_ASSERT_ERROR( !( this >= reinterpret_cast<TMonoAllocator*>(firstBuffer )
94 && this < reinterpret_cast<TMonoAllocator*>(firstBuffer->end ) )
95 || snapshot.actFill == reinterpret_cast<char*>(1),
96 "MONOMEM",
97 "A full MonoAllocator::Reset() was requested for a self-contained monotonic "
98 "allocator created with MonoAllocator::Create()." )
99 }
100 #endif
101
102
103 #if ALIB_DEBUG_MEMORY
104 Statistics stats;
105 #if ALIB_DEBUG_CRITICAL_SECTIONS
106 DbgCriticalSectionsPH.Get()->Release(ALIB_CALLER);
107 #endif
108 GetStatistics(stats);
109 #if ALIB_DEBUG_CRITICAL_SECTIONS
110 DbgCriticalSectionsPH.Get()->Acquire(ALIB_CALLER);
111 #endif
112 dbgStats.QtyAllocationsInclResets += dbgStats.QtyAllocations;
113 dbgStats.QtyTrivialAllocationsInclResets+= dbgStats.QtyTrivialAllocations;
114 dbgStats.AllocSizeInclResets += (stats.AllocSize - dbgStats.AlignmentWaste);
115 ++dbgStats.QtyResets;
116 dbgStats.QtyAllocations = 0;
117 dbgStats.QtyTrivialAllocations = 0;
118 dbgStats.AlignmentWaste = 0;
119 dbgStats.QtyBufferSizeExceeds = 0;
120 #endif
121
122 // recycle buffers until snapshot buffer or end is found
124 while( it != snapshot.buffer )
125 {
126 #if !ALIB_DEBUG_ALLOCATIONS
127 it->reset();
128 #else
129 // In debug mode, we must not reset the buffer if this is a self-contained instance and
130 // this is the first buffer, because this would overwrite the self-contained content
131 if ( it->previous != nullptr || snapshot.actFill != reinterpret_cast<char*>(1) )
132 it->reset();
133 else
134 // do a 'manual' reset of the buffer, without overwriting its contents.
135 buffer->act= reinterpret_cast<char*>( buffer + 1 );
136 #endif
137
138
139 detail::Buffer* next= it->previous;
140 if ( next == nullptr )
141 {
142 #if ALIB_DEBUG_ALLOCATIONS
143 if ( snapshot.actFill != reinterpret_cast<char*>(1) )
144 memset( buffer->act, 0xD2, size_t(buffer->end - buffer->act) );
145 #endif
146 buffer= it;
147 return;
148 }
149
151 recyclables= it;
152 it= next;
153 }
154
155 // snapshot buffer?
156 ALIB_ASSERT( snapshot.buffer, "MONOMEM" )
157 ALIB_ASSERT( snapshot.buffer == it, "MONOMEM" )
158 buffer= it;
159 buffer->act= snapshot.actFill;
160
161 #if ALIB_DEBUG_ALLOCATIONS
162 memset( buffer->act, 0xD2, size_t(buffer->end - buffer->act) );
163 #endif
164}
165
166template<typename TAllocator>
169
170 // search the pointer that has no previous and clear that pointer
171 detail::Buffer** it= &buffer;
172 while( (*it)->previous )
173 it= &(*it)->previous;
174 *it= nullptr;
175
176 // note: we do not need to check the recycling list, because this first buffer will
177 // never be recycled.
178}
179
180
181//==================================================================================================
182// TMonoAllocator::get/Free
183//==================================================================================================
184template<typename TAllocator>
185char* TMonoAllocator<TAllocator>::nextBuffer(size_t size, size_t alignment)
186{
187 // we always have a buffer in place, and this method is called from the inlined allocation
188 // function when the current buffer does not fit.
189
190 // special treatment if size exceeds buffer size: create an own buffer and keep using current
191 auto nextBUS= nextBuffersUsableSize;
192 if( lang::DbgAlloc::extSize( size )
194 {
195 // adjust the next buffer size to the exceeding size
196 nextBUS= lang::DbgAlloc::extSize(size)
197 + detail::Buffer::firstOffset(sizeof(detail::Buffer), alignment)
198 + alignment;
199 #if ALIB_DEBUG_MEMORY
200 ++dbgStats.QtyBufferSizeExceeds;
201 #endif
202 ALIB_WARNING( "MONOMEM",
203 "MonoAllocator: Allocation size exceeds the next buffers' size.\n"
204 "The allocator's buffer size should be increased.\n"
205 "Requested size: ", size )
206 }
207
208 // search a recycle buffer (usually the first fits)
209 detail::Buffer** previousPointer= &recyclables;
210 detail::Buffer* recyclable = recyclables;
211 while( recyclable )
212 { DBG_ALIGNMENT_INIT( recyclable )
213 char* mem= recyclable->allocate( size, alignment ); DBG_ALIGNMENT_MEASURE( recyclable )
214 if( mem )
215 {
216 *previousPointer= recyclable->previous;
217 recyclable->previous= buffer;
218 buffer= recyclable;
219 return mem;
220 }
221
222 // this should almost never happen (only if requesting oversized objects after a reset)
223 previousPointer= &recyclable->previous;
224 recyclable = recyclable->previous;
225 }
226
227 // create new buffer
228 detail::Buffer* previousBuffer= buffer;
229 buffer= new (allocMember::GetAllocator().allocate(nextBUS, alignof(void*))) detail::Buffer( nextBUS );
230 if ( nextBUS == nextBuffersUsableSize)
232 buffer->previous = previousBuffer; DBG_ALIGNMENT_INIT( buffer )
233
234 char* mem= buffer->allocate( size, alignment ); DBG_ALIGNMENT_MEASURE( buffer )
235 return mem;
236}
237
238//==================================================================================================
239// Statistics
240//==================================================================================================
241template<typename TAllocator>
244
245 result= Statistics();
247
248
249 // walk recyclable buffers
251 result.CurrentBufferSize= buffer->Size();
252 result.CurrentBufferFree= size_t(buffer->end - buffer->act);
253
254 while( it != nullptr )
255 {
256 result.QtyBuffers++;
257 result.HeapSize+= it->Size();
258 result.AllocSize+= it->Size() - size_t(it->end - it->act) - sizeof(detail::Buffer);
259 if ( it != buffer )
260 result.BufferWaste+= size_t(it->end - it->act);
261
262 it= it->previous;
263 }
264
265 it= recyclables;
266 while( it != nullptr )
267 {
268 result.QtyRecyclables++;
269 result.HeapSizeRecycled+= it->Size();
270 it= it->previous;
271 }
272}
273
274}} // namespace [alib::monomem]
275
char * actFill
Pointer to the first free byte in the current buffer.
detail::Buffer * buffer
The current buffer.
TMonoAllocator(const char *dbgName, std::nullptr_t) noexcept
ALIB_DLL ~TMonoAllocator()
Destructor. Disposes all memory allocated with ChainedAllocator.
detail::Buffer * buffer
The actual buffer. Contains a link to previously allocated buffers.
lang::Placeholder< lang::DbgCriticalSections > DbgCriticalSectionsPH
detail::Buffer * recyclables
The list of buffers that are to be recycled.
static ALIB_DLL TMonoAllocator * Create(const char *dbgName, TAllocator &pAllocator, size_t initialBufferSizeInKB, unsigned int bufferGrowthInPercent=200)
ALIB_DLL char * nextBuffer(size_t size, size_t alignment)
ALIB_DLL void GetStatistics(Statistics &result)
ALIB_DLL void Reset(Snapshot snapshot=Snapshot())
#define ALIB_CALLER
Definition alib.inl:1001
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1048
#define ALIB_WARNING(domain,...)
Definition alib.inl:1046
#define ALIB_ASSERT_WARNING(cond, domain,...)
Definition alib.inl:1050
#define ALIB_DCS_WITH(CS)
Definition alib.inl:1377
#define ALIB_DBG(...)
Definition alib.inl:836
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
Details of namespace alib::monomem.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
TAllocator & GetAllocator() const noexcept
static constexpr size_t extSize(TIntegral size)
size_t CurrentBufferSize
The size of the current buffer.
size_t HeapSizeRecycled
The number of bytes allocated at the heap.
size_t NextBufferSize
The planned size of the next buffer (that is not an oversize-allocation).
size_t CurrentBufferFree
The free space in the current buffer.
unsigned int QtyBuffers
The number of created buffers.
unsigned int QtyRecyclables
The number of created buffers.
static constexpr size_t firstOffset(size_t firstObject, size_t alignment)
char * end
Pointer to the first byte behind the buffer.
char * act
Pointer to the next free space in the buffer.
Buffer * previous
the previously allocated buffer.
char * allocate(size_t size, size_t alignment)