ALib C++ Library
Library Version: 2511 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 pBufferGrowthInPercent) {
21 ALIB_ASSERT_ERROR( initialBufferSizeInKB, "MONOMEM", "Initial buffer of 0kb requested." )
22
23 auto size= initialBufferSizeInKB * 1024;
24 auto* mem= pAllocator.allocate( size, alignof(detail::Buffer) );
25 auto* firstBuffer= new (mem) detail::Buffer( initialBufferSizeInKB * 1024 );
26
27 auto* result = reinterpret_cast<TMA*>( firstBuffer->allocate( sizeof(TMA), alignof(TMA) ) );
28 return new (result) TMA( ALIB_DBG(pDbgName,) pAllocator, firstBuffer,
29 initialBufferSizeInKB, pBufferGrowthInPercent );
30}
31#include "ALib.Lang.CIMethods.H"
32#endif
33
34template<typename TAllocator>
36 #if ALIB_DEBUG_CRITICAL_SECTIONS
37 DbgCriticalSectionsPH.Destruct();
38 #endif
39
40 #if ALIB_DEBUG_MEMORY
41 integer cntBuffers = 0;
42 #endif
43
44 // first delete recyclable buffers
45 auto* cnk= recyclables;
46 while( cnk ) {
47 #if ALIB_DEBUG_MEMORY
48 ++cntBuffers;
49 #endif
50
51 auto* next= cnk->previous;
52 allocMember::GetAllocator().free( cnk, cnk->Size() );
53 cnk= next;
54 }
55
56 // then the active ones
57 cnk= buffer;
58 while( cnk ) {
59 auto* next= cnk->previous;
60 allocMember::GetAllocator().free( cnk, cnk->Size() );
61
62 #if ALIB_DEBUG_MEMORY
63 ++cntBuffers;
64 #endif
65 cnk= next;
66 }
67
68 #if ALIB_DEBUG_MEMORY
69 ALIB_ASSERT_WARNING( cntBuffers <= 15, "MONOMEM",
70 "ALIB_DEBUG_MEMORY Warning: More than 15 buffers allocated. "
71 "Buffer size might be increased? #Buffers: ", cntBuffers )
72 #endif
73 //ALIB_DCS_RELEASE
74
75}
76
77template<typename TAllocator>
80
81 #if ALIB_DEBUG
82 // check if a (forbidden!) full reset is requested on a self-contained instance
83 if( snapshot.buffer == nullptr ) {
84 detail::Buffer* firstBuffer= buffer;
85 while( firstBuffer->previous )
86 firstBuffer= firstBuffer->previous;
87
88 ALIB_ASSERT_ERROR( !( this >= reinterpret_cast<TMonoAllocator*>(firstBuffer )
89 && this < reinterpret_cast<TMonoAllocator*>(firstBuffer->end ) )
90 || snapshot.actFill == reinterpret_cast<char*>(1),
91 "MONOMEM",
92 "A full MonoAllocator::Reset() was requested for a self-contained monotonic "
93 "allocator created with MonoAllocator::Create()." )
94 }
95 #endif
96
97
98 #if ALIB_DEBUG_MEMORY
99 Statistics stats;
100 #if ALIB_DEBUG_CRITICAL_SECTIONS
101 DbgCriticalSectionsPH.Get()->Release(ALIB_CALLER);
102 #endif
103 GetStatistics(stats);
104 #if ALIB_DEBUG_CRITICAL_SECTIONS
105 DbgCriticalSectionsPH.Get()->Acquire(ALIB_CALLER);
106 #endif
107 dbgStats.QtyAllocationsInclResets += dbgStats.QtyAllocations;
108 dbgStats.QtyTrivialAllocationsInclResets+= dbgStats.QtyTrivialAllocations;
109 dbgStats.AllocSizeInclResets += (stats.AllocSize - dbgStats.AlignmentWaste);
110 ++dbgStats.QtyResets;
111 dbgStats.QtyAllocations = 0;
112 dbgStats.QtyTrivialAllocations = 0;
113 dbgStats.AlignmentWaste = 0;
114 dbgStats.QtyBufferSizeExceeds = 0;
115 #endif
116
117 // recycle buffers until snapshot buffer or end is found
119 while( it != snapshot.buffer ) {
120 #if !ALIB_DEBUG_ALLOCATIONS
121 it->reset();
122 #else
123 // In debug mode, we must not reset the buffer if this is a self-contained instance and
124 // this is the first buffer, because this would overwrite the self-contained content
125 if ( it->previous != nullptr || snapshot.actFill != reinterpret_cast<char*>(1) )
126 it->reset();
127 else
128 // do a 'manual' reset of the buffer, without overwriting its contents.
129 buffer->act= reinterpret_cast<char*>( buffer + 1 );
130 #endif
131
132
133 detail::Buffer* next= it->previous;
134 if ( next == nullptr ) {
135 #if ALIB_DEBUG_ALLOCATIONS
136 if ( snapshot.actFill != reinterpret_cast<char*>(1) )
137 memset( buffer->act, 0xD2, size_t(buffer->end - buffer->act) );
138 #endif
139 buffer= it;
140 return;
141 }
142
144 recyclables= it;
145 it= next;
146 }
147
148 // snapshot buffer?
149 ALIB_ASSERT( snapshot.buffer, "MONOMEM" )
150 ALIB_ASSERT( snapshot.buffer == it, "MONOMEM" )
151 buffer= it;
152 buffer->act= snapshot.actFill;
153
154 #if ALIB_DEBUG_ALLOCATIONS
155 memset( buffer->act, 0xD2, size_t(buffer->end - buffer->act) );
156 #endif
157}
158
159template<typename TAllocator>
162
163 // search the pointer that has no previous and clear that pointer
164 detail::Buffer** it= &buffer;
165 while( (*it)->previous )
166 it= &(*it)->previous;
167 *it= nullptr;
168
169 // note: we do not need to check the recycling list, because this first buffer will
170 // never be recycled.
171}
172
173
174//==================================================================================================
175// TMonoAllocator::get/Free
176//==================================================================================================
177template<typename TAllocator>
178char* TMonoAllocator<TAllocator>::nextBuffer(size_t size, size_t alignment) {
179 // we always have a buffer in place, and this method is called from the inlined allocation
180 // function when the current buffer does not fit.
181
182 // special treatment if size exceeds buffer size: create an own buffer and keep using current
183 auto nextBUS= nextBuffersUsableSize;
184 if( lang::DbgAlloc::extSize( size )
186 {
187 // adjust the next buffer size to the exceeding size
188 nextBUS= lang::DbgAlloc::extSize(size)
189 + detail::Buffer::firstOffset(sizeof(detail::Buffer), alignment)
190 + alignment;
191 #if ALIB_DEBUG_MEMORY
192 ++dbgStats.QtyBufferSizeExceeds;
193 #endif
194 ALIB_WARNING( "MONOMEM",
195 "MonoAllocator: Allocation size exceeds the next buffers' size.\n"
196 "The allocator's buffer size should be increased.\n"
197 "Requested size: ", size )
198 }
199
200 // search a recycle buffer (usually the first fits)
201 detail::Buffer** previousPointer= &recyclables;
202 detail::Buffer* recyclable = recyclables;
203 while( recyclable )
204 { DBG_ALIGNMENT_INIT( recyclable )
205 char* mem= recyclable->allocate( size, alignment ); DBG_ALIGNMENT_MEASURE( recyclable )
206 if( mem ) {
207 *previousPointer= recyclable->previous;
208 recyclable->previous= buffer;
209 buffer= recyclable;
210 return mem;
211 }
212
213 // this should almost never happen (only if requesting oversized objects after a reset)
214 previousPointer= &recyclable->previous;
215 recyclable = recyclable->previous;
216 }
217
218 // create new buffer
219 detail::Buffer* previousBuffer= buffer;
220 buffer= new (allocMember::GetAllocator().allocate(nextBUS, alignof(void*))) detail::Buffer( nextBUS );
221 if ( nextBUS == nextBuffersUsableSize)
223 buffer->previous = previousBuffer; DBG_ALIGNMENT_INIT( buffer )
224
225 char* mem= buffer->allocate( size, alignment ); DBG_ALIGNMENT_MEASURE( buffer )
226 return mem;
227}
228
229//==================================================================================================
230// Statistics
231//==================================================================================================
232template<typename TAllocator>
235
236 result= Statistics();
238
239
240 // walk recyclable buffers
242 result.CurrentBufferSize= buffer->Size();
243 result.CurrentBufferFree= size_t(buffer->end - buffer->act);
244
245 while( it != nullptr ) {
246 result.QtyBuffers++;
247 result.HeapSize+= it->Size();
248 result.AllocSize+= it->Size() - size_t(it->end - it->act) - sizeof(detail::Buffer);
249 if ( it != buffer )
250 result.BufferWaste+= size_t(it->end - it->act);
251
252 it= it->previous;
253 }
254
255 it= recyclables;
256 while( it != nullptr ) {
257 result.QtyRecyclables++;
258 result.HeapSizeRecycled+= it->Size();
259 it= it->previous;
260} }
261
262}} // namespace [alib::monomem]
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 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:1018
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1065
#define ALIB_WARNING(domain,...)
Definition alib.inl:1063
#define ALIB_ASSERT_WARNING(cond, domain,...)
Definition alib.inl:1067
#define ALIB_DCS_WITH(CS)
Definition alib.inl:1394
#define ALIB_DBG(...)
Definition alib.inl:853
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
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.
unsigned QtyBuffers
The number of created buffers.
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 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)