ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
monoallocator.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_monomem of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8#if ALIB_DEBUG_ALLOCATIONS && !ALIB_STRINGS
9# error "Module ALib Strings needed in the ALib Build if Monomem is included and ALIB_DEBUG_ALLOCATIONS is set."
10#endif
11
12ALIB_EXPORT namespace alib { namespace monomem {
13
14// forward declaration
15template<typename TAllocator> class TMonoAllocator;
16
17/// Details of namespace #"alib::monomem;2"
18namespace detail {
19
20//==================================================================================================
21/// Internal type defining a memory buffer.
22/// The allocation space is found behind this object itself as it is placed at the start
23/// of each allocated buffer.
24//==================================================================================================
25struct Buffer
26{
27 /// A magic byte, used with the configuration macro #"ALIB_DEBUG_ALLOCATIONS" to mark
28 /// memory and detect out-of-bounds writes.
29 /// @see Method #"Allocator::dbgCheckMemory;*".
30 static constexpr unsigned char MAGIC= 0xA1;
31
32 /// A magic byte written when memory is freed.
33 /// @see Field #".CLEAR".
34 static constexpr unsigned char CLEAR= 0xF1;
35
36 char* act; ///< Pointer to the next free space in the buffer.
37 char* end; ///< Pointer to the first byte behind the buffer.
38 Buffer* previous; ///< the previously allocated buffer.
39
40 /// Returns the first offset of an object with given \p{alignment} behind an object with.
41 /// smaller alignment.
42 /// @param firstObject The allocation size of the first object allocated in a buffer.
43 /// @param alignment The allocation alignment of the first object allocated in a buffer.
44 /// @return The value to add to the allocation size to ensure that an object with a certain
45 /// alignment fits after placing \p{firstObject} at the start..
46 static constexpr size_t firstOffset(size_t firstObject, size_t alignment)
47 { return ((firstObject + alignment - 1) / alignment) * alignment; }
48
49 /// Initializes the members of this buffer to reflect the given \p{size}.
50 /// @param size The size of the given \p{mem}.
51 Buffer( size_t size )
52 {
53 act = reinterpret_cast<char*>( this + 1 );
54 end = reinterpret_cast<char*>( this ) + size;
55 }
56
57 /// Defaulted default constructor
58 Buffer() =default;
59
60 /// @return The size of this buffer.
61 size_t Size() { return size_t(end - reinterpret_cast<char*>(this)) ; }
62
63 /// "Frees" all allocated memory by simply resetting the fill marker of this buffer to the
64 /// first usable byte of the allocated buffer.
65 void reset() {
66 act= reinterpret_cast<char*>( this + 1 );
67 #if ALIB_DEBUG_ALLOCATIONS
68 memset( act, 0xD2, size_t(end - act));
69 #endif
70 }
71
72 /// Returns a pointer to an aligned piece of memory of the requested size inside this
73 /// buffer. If there is not enough space left, \c nullptr is returned.
74 ///
75 /// @param size The size to allocate.
76 /// @param alignment The necessary alignment.
77 /// @return \c nullptr on failure, otherwise pointer to the requested memory.
78 char* allocate( size_t size, size_t alignment ) {
79 ALIB_ASSERT_ERROR( lang::BitCount(alignment) == 1, "MONOMEM",
80 "Requested alignment is not a power of 2:", alignment )
81
82 size_t dbgSize= lang::DbgAlloc::extSize(size);
83
84 // Calc aligned start. Fits to this buffer? If not, just return nullptr
85 char* aligned = reinterpret_cast<char*>( (size_t(act) + alignment - 1) & ~(alignment -1) );
86 if( size_t(end - aligned) < dbgSize )
87 return nullptr;
88 act= aligned + dbgSize;
89
90 lang::DbgAlloc::annotate(aligned, size, MAGIC);
91 return aligned;
92 }
93
94}; // struct Buffer
95
96
97} // namespace alib::momomem[::detail]
98
99//==================================================================================================
100/// Stores the actual state of outer class \b %MonoAllocator.
101/// Retrieved method #"TMonoAllocator::TakeSnapshot;*" and #"TMonoAllocator::Reset(Snapshot);*".
102//==================================================================================================
104{
105 protected:
106 #if !DOXYGEN
107 template<typename TAllocator> friend class TMonoAllocator;
108 #endif
109
110 detail::Buffer* buffer; ///< The current buffer.
111 char* actFill; ///< Pointer to the first free byte in the current buffer.
112
113 /// Internal constructor.
114 /// @param pBuffer The current buffer.
115 /// @param pFill The current fill of \p{buffer}.
116 constexpr Snapshot( detail:: Buffer* pBuffer, char* pFill) noexcept
117 : buffer (pBuffer)
118 , actFill(pFill ) {}
119
120 public:
121 /// Default constructor.
122 /// \note
123 /// Default-constructed snapshots passed to method
124 /// #"TMonoAllocator::Reset(Snapshot);*" do reset the monotonic allocator to its
125 /// initial state after construction. All monotonically allocated memory is considered
126 /// 'freed' then.
127 constexpr Snapshot() noexcept
128 : buffer (nullptr)
129 , actFill(nullptr) {}
130
131 /// Returns \c false if this snapshot was never initialized properly (default
132 /// constructed and not copied over).
133 /// @return \c true if this is not a valid snapshot, \c false otherwise.
134 constexpr bool IsValid() noexcept { return buffer != nullptr; }
135
136}; // class Snapshot
137
138/// Statistics for type #"TMonoAllocator", receivable with method
139/// #"TMonoAllocator::GetStatistics".
140/// @see Struct #"DbgStatistics" and corresponding method
141/// #"TMonoAllocator::DbgGetStatistics".
143{
144 /// The number of created buffers.
145 unsigned QtyBuffers =0;
146
147 /// The number of created buffers.
148 unsigned QtyRecyclables =0;
149
150 /// The number of bytes allocated at the heap.
152
153 /// The number of bytes allocated at the heap from buffers currently used.
154 /// Note: To get the total size, add #"HeapSizeRecycled".
155 size_t HeapSize =0;
156
157 /// The overall number of bytes requested. Note that this value includes the
158 /// losses due to alignment. To get the exact value, method
159 /// #"TMonoAllocator::DbgGetStatistics" needs to be used and its
160 /// information about the alignment waste has to be subtracted.
161 size_t AllocSize =0;
162
163 /// The number of bytes remaining in buffers, because a next object did not fit. This
164 /// does not include the remaining bytes in the current buffer.
165 size_t BufferWaste =0;
166
167 /// The free space in the current buffer.
169
170 /// The size of the current buffer.
172
173 /// The planned size of the next buffer (that is not an oversize-allocation).
174 size_t NextBufferSize =0;
175
176}; // struct Statistics
177
178#if ALIB_DEBUG_MEMORY
179 /// Debug statistics for type #"TMonoAllocator", receivable with method
180 /// #"TMonoAllocator::DbgGetStatistics".
181 /// Availability depends on configuration macro #"ALIB_DEBUG_MEMORY".
183 {
184 /// The number of allocations performed.
185 size_t QtyAllocations = 0;
186
187 /// The number of allocations performed, cumulated over resets.
189
190 /// The number of allocations that did not create a new buffer .
192
193 /// The number of allocations that did not create a new buffer, cumulated over resets.
195
196 /// The number of allocated space, cumulated over resets.
198
199 /// The number of bytes lost for alignment.
200 size_t AlignmentWaste = 0;
201
202 /// The number of allocations that have been larger than the buffer size.
204
205 /// The number of resets performed.
206 size_t QtyResets = 0;
207 }; // struct DbgStatistics
208#endif
209
210
211//==================================================================================================
212/// \par Important Note
213/// Please consult the #"alib_contmono_intro;Programmer's Manual" of \alib module
214/// \alib_monomem_nl for an introduction into the rather complex topic of monotonous allocation
215/// and how to use this class.
216///
217/// \par General Behavior
218/// Implements a monotonic allocator. Allocates a series of bigger memory buffers and offers
219/// sequential allocation of portions of those.<br>
220/// With construction, an initial memory buffer is received from the
221/// #"alib_contmono_chaining;chained allocator".
222/// The size of this buffer is defined with the constructor parameter \p{initialBufferSizeInKB}.
223/// With each necessary allocation of a next buffer, this value can be increased, according
224/// to the optional parameter \p{bufferGrowthInPercent}, which defaults to \c 200, resulting in
225/// doubling the size of each next buffer.
226///
227/// If an invocation of one of the allocation methods requests memory bigger than the
228/// remaining space in the actual (last) buffer, then a new buffer is created and made the actual
229/// buffer. The remaining space of the former actual buffer will not be used for future allocations
230/// and is wasted in this respect.
231///
232/// \par Oversized Allocations
233/// If a requested allocation size exceeds what would be the size of the next buffer, then a new
234/// buffer of the extended size is created. The next allocation will then create a new buffer
235/// which continues the originally defined buffer growth path. In other words:
236/// - Oversized allocations are allowed, and
237/// - the next buffer's size after an oversized allocation will use the size of the
238/// last non-oversized buffer as the base value for calculating the next size.
239///
240/// \note While accepted, oversized allocations should still be avoided, because the current
241/// buffer will not be used for further allocations.
242/// This is a design decision, allowing a more efficient implementation of this class.
243/// Former implementations kept the current buffer as the actual buffer, when an oversized
244/// allocation occured, but this feature was dropped.
245///
246/// \par Resetting
247/// The allocator can be reset to a certain state (see #"TakeSnapshot" and #"Reset(Snapshot)"),
248/// which disposes all memory behind the snapshot.
249/// Disposed complete buffers will not be freed, but "recycled" with future allocations.<br>
250/// If #"alib_contmono_class_monoalloc_snapshot;nested snapshots" are used in the right
251/// places, further gains in execution performance can be achieved.
252///
253/// \par External Allocation of the First Buffer
254/// Special constructors of this type allow to pass an existing first buffer for usage.
255/// This allows two fundamental concepts:
256/// - The first buffer might be stack-memory, which can lead to further (sometimes dramatical)
257/// performance improvements.<br>
258/// This feature is leveraged by type #"TLocalAllocator".
259/// - The first buffer might contain not only already emplaced objects, but even the
260/// \b %TMonoAllocator itself. We name this a <em>"self-contained monotonic allocator"</em>.<br>
261/// This feature is leveraged by type #"TSharedMonoVal".
262///
263/// \par Debug Features
264/// Depending on the configuration macro #"ALIB_DEBUG_MEMORY", some metrics on instances of this
265/// class become available.
266/// Those might, for example, be helpful to find a reasonable value for constructor parameters
267/// \p{initialBufferSize} and \p{bufferGrowthInPercent}.
268///
269/// \par See also
270/// - The #"alib_contmono_intro;Programmer's Manual" of module \alib_monomem_nl.
271/// - The "standard" type definition of this template type #"MonoAllocator", which uses
272/// an #"HeapAllocator" as the #"alib_contmono_chaining;chained allocator".
273///
274/// @tparam TAllocator The underlying allocator to use.<br>
275/// With type definition #"MonoAllocator", this is bound to type
276/// #"HeapAllocator".<br>
277/// For general information see chapter #"alib_contmono_chaining"
278/// of the Programmer's Manual.
279//==================================================================================================
280template<typename TAllocator>
281class TMonoAllocator : public lang::AllocatorMember<TAllocator>
282{
283 protected:
284 /// The type of the base class that stores the chained allocator.
286
287 /// The actual buffer. Contains a link to previously allocated buffers.
289
290 /// The list of buffers that are to be recycled.
292
293 /// The initial allocation size given in the constructor, multiplied with #"bufferGrowthInPercent"
294 /// with each new buffer created. Allocated buffers may be bigger in the case that a single
295 /// allocation is larger than this value.
297
298 /// Growth factor of subsequently allocated buffers.
299 /// Given by a construction parameter, which in most cases defaults to \c 200,
300 /// doubling the buffer size with each next buffer allocation.
302
303 #if ALIB_DEBUG
304 public:
305 /// A name for this object.
306 /// With debug-compilations, this name has to be given with construction.
307 const char* DbgName;
308
309 protected:
310 /// This flag to mark this allocator to not accept allocations.
311 /// @see Method #"DbgLock" and chapter #"alib_contmono_further_debug" of the
312 /// Programmer's Manual of this \alibmod_nl.
313 bool dbgLock =false;
314 #endif
315
316 #if ALIB_DEBUG_MEMORY
317 /// Debug statistics measured on the whole run-time of this object.<br>
318 /// Availability depends on configuration macro #"ALIB_DEBUG_MEMORY".
320 #endif
321
322 public:
323 #if ALIB_DEBUG_CRITICAL_SECTIONS
324 /// Due to the possibility of being self-contained, this type needs special treatment
325 /// in respect to the member of type #"lang::DbgCriticalSections". It must be neither derived
326 /// nor being a member. Instead, destruction has to be controlled.
327 /// Furthermore, the \ref alib_macros_mod_threads "ALib Module Threads Macros"
328 /// cannot be used.
330 #endif
331
332 protected:
333
334 /// This internal allocation method is called by the allocation interface methods, in case
335 /// the current request cannot be trivially satisfied.
336 ///
337 /// Implements the overall strategy of this class in respect to oversized blocks,
338 /// recycling of blocks, etc.
339 ///
340 /// @param size The size of the first object to allocate in the buffer.
341 /// @param alignment The allocation alignment of the first object to allocate.
342 /// @return A pointer to the memory allocated for the object.
343 ALIB_DLL char* nextBuffer(size_t size, size_t alignment);
344
345 public:
346 /// The type of the allocator that this allocator uses underneath to allocate the buffers,
347 /// given with template parameter \p{TAllocator}.<br>
348 /// The instance can be accessed with inherited methods
349 /// #"AllocatorMember::GetAllocator" and #"AllocatorMember::AI".
350 using ChainedAllocator = TAllocator;
351
352 /// Evaluates to \b 1.
353 /// @see Field #"Allocator::MIN_ALIGNMENT;*".
354 static constexpr size_t MIN_ALIGNMENT = 1;
355
356 /// Evaluates to <c>std::numeric_limits<size_t>::max()</c>.
357 /// @see Field #"Allocator::MAX_ALIGNMENT;*".
358 static constexpr size_t MAX_ALIGNMENT = (std::numeric_limits<size_t>::max)();
359
360 //################################################################################################
361 // ##### Constructors/Destructor
362 //################################################################################################
363 public:
364 #if DOXYGEN
365 /// Special constructor that is not initializing this type.
366 /// This can be used if a value of this type is required, but only later it becomes known
367 /// what the initial buffer size and growth factor is to be.
368 ///
369 /// The method #"TMonoAllocator;IsInitialized" can be used to determine if an allocator was
370 /// initialized on construction. If not, a placement-new calling a decent constructor is to be
371 /// performed before construction.
372 ///
373 /// @see Chapter #"alib_contmono_globalinstance_initialsize" of the Programmer's Manual
374 /// of module \alib_monomem.
375 ///
376 /// @param dbgName Has to be specified with debug-compilations only.
377 /// Use the macro #"ALIB_DBG" to pass a constant.
378 /// @tparam TRequires Defaulted template parameter. Must not be specified.
379 template<typename TRequires= lang::AllocatorMember<TAllocator>>
380 requires std::default_initializable<TRequires>
381 TMonoAllocator(const char* dbgName, std::nullptr_t) noexcept;
382 #else
383 template<typename TRequires= lang::AllocatorMember<TAllocator>>
384 requires std::default_initializable<TRequires>
385 TMonoAllocator(ALIB_DBG(const char* dbgName,) std::nullptr_t) noexcept
386 : allocMember(TAllocator())
387 , buffer (nullptr)
388 , recyclables(nullptr)
389ALIB_DBG(,DbgName(dbgName)) {}
390 #endif
391
392 #if DOXYGEN
393 /// Constructor that accepts an external first buffer. If this constructor is used, and the
394 /// given \p{initialBuffer} must not be freed to the heap, method #"destructWithExternalBuffer"
395 /// has to be called right before the allocator is destructed.
396 ///
397 /// \note
398 /// This constructor, together with the method #"destructWithExternalBuffer" enables the
399 /// efficient implementation of derived class #"TLocalAllocator", as well as
400 /// class #"TSharedMonoVal".
401 ///
402 /// @param dbgName Has to be specified with debug-compilations only.
403 /// Use the macro #"ALIB_DBG" to pass a constant.
404 /// @param pInitialBuffer The initial buffer to use. Has to be aligned with at least
405 /// <c>alignof(void*)</c>.
406 /// @param pInitialBufferSizeInKB The size in kB (1024 bytes) of the given \p{initialBuffer}.
407 /// @param pBufferGrowthInPercent Optional growth factor in percent, applied to each allocation
408 /// of a next buffer size in respect to its previous size.
409 /// Defaults to \c 200, which doubles buffer size with each
410 /// next internal buffer allocation.
411 /// @tparam TRequires Defaulted template parameter. Must not be specified.
412 template<typename TRequires= lang::AllocatorMember<TAllocator>>
413 requires std::default_initializable<TRequires>
414 TMonoAllocator( const char* dbgName,
415 detail::Buffer* pInitialBuffer,
416 size_t pInitialBufferSizeInKB,
417 unsigned pBufferGrowthInPercent= 200 );
418 #else
419 template<typename TRequires= lang::AllocatorMember<TAllocator>>
420 requires std::default_initializable<TRequires>
421 TMonoAllocator( ALIB_DBG(const char* dbgName,)
422 detail::Buffer* pInitialBuffer,
423 size_t pInitialBufferSizeInKB,
424 unsigned pBufferGrowthInPercent= 200 )
425 : buffer ( pInitialBuffer )
426 , recyclables ( nullptr )
427 , nextBuffersUsableSize( (pInitialBufferSizeInKB * 1024 * pBufferGrowthInPercent) / 100 )
428 , bufferGrowthInPercent( pBufferGrowthInPercent )
429ALIB_DBG(,DbgName (dbgName)) {
430 // assert alignment
431 ALIB_ASSERT_ERROR( (size_t(pInitialBuffer) & (alignof(void*)-1) )== 0, "MONOMEM",
432 "The given initial buffer is not aligned to at least 'alignof(void*)'." )
433
434 #if ALIB_DEBUG_CRITICAL_SECTIONS
435 DbgCriticalSectionsPH.Construct("MonoAllocator");
436 #endif
437 buffer->previous= nullptr;
438 }
439 #endif
440
441
442 #if DOXYGEN
443 /// Alternative constructor version that in addition expects an allocator.
444 ///
445 /// @param dbgName Has to be specified with debug-compilations only.
446 /// Use the macro #"ALIB_DBG" to pass a constant.
447 /// @param pAllocator The allocator to use for allocation of buffers.
448 /// @param pInitialBuffer The initial buffer to use. Has to be aligned with at least
449 /// <c>alignof(void*)</c>.
450 /// @param pInitialBufferSizeInKB The size in kB (1024 bytes) of the given \p{initialBuffer}.
451 /// @param pBufferGrowthInPercent Optional growth factor in percent, applied to each allocation
452 /// of a next buffer size in respect to its previous size.
453 /// Defaults to \c 200, which doubles buffer size with each
454 /// next internal buffer allocation.
455 TMonoAllocator( const char* dbgName,
456 TAllocator& pAllocator,
457 detail::Buffer* pInitialBuffer,
458 size_t pInitialBufferSizeInKB,
459 unsigned pBufferGrowthInPercent= 200 );
460 #else
461 TMonoAllocator( ALIB_DBG(const char* dbgName,)
462 TAllocator& pAllocator,
463 detail::Buffer* pInitialBuffer,
464 size_t pInitialBufferSizeInKB,
465 unsigned pBufferGrowthInPercent= 200 )
466 : allocMember ( pAllocator )
467 , buffer ( pInitialBuffer )
468 , recyclables ( nullptr )
469 , nextBuffersUsableSize( (pInitialBufferSizeInKB * 1024 * pBufferGrowthInPercent) / 100 )
470 , bufferGrowthInPercent( pBufferGrowthInPercent )
471 ALIB_DBG(,DbgName (dbgName)) {
472 // assert alignment
473 ALIB_ASSERT_ERROR( (size_t(pInitialBuffer) & (alignof(void*)-1) )== 0, "MONOMEM",
474 "The given initial buffer is not aligned to at least 'alignof(void*)'." )
475
476 #if ALIB_DEBUG_CRITICAL_SECTIONS
477 DbgCriticalSectionsPH.Construct("MonoAllocator");
478 #endif
479 buffer->previous= nullptr;
480 }
481 #endif
482
483 public:
484 #if DOXYGEN
485 //==============================================================================================
486 /// Constructor.
487 /// A first memory buffer is allocated from #ChainedAllocator.
488 ///
489 /// Parameter \p{bufferGrowthInPercent} determines the growth of memory buffers. The size of a
490 /// next buffer is calculated as:
491 /// newSize= (previousSize * bufferGrowthInPercent) / 100
492 ///
493 /// @param dbgName Has to be specified with debug-compilations only.
494 /// Use the macro #"ALIB_DBG" to pass a constant.
495 /// @param pInitialBufferSizeInKB The size in kB (1024 bytes) of the first memory buffer used
496 /// for the allocator itself as well as for the first allocations.
497 /// @param pBufferGrowthInPercent Optional growth factor in percent, applied to each allocation
498 /// of a next buffer size in respect to its previous size.
499 /// Defaults to \c 200, which doubles the buffer size with each
500 /// next internal buffer allocation.
501 /// @tparam TRequires Defaulted template parameter. Must not be specified.
502 //==============================================================================================
503 template<typename TRequires= lang::AllocatorMember<TAllocator>>
504 requires std::default_initializable<TRequires>
505 TMonoAllocator( const char* dbgName,
506 size_t pInitialBufferSizeInKB,
507 unsigned pBufferGrowthInPercent= 200 );
508 #else
509 template<typename TRequires= lang::AllocatorMember<TAllocator>>
510 requires std::default_initializable<TRequires>
511 TMonoAllocator( ALIB_DBG(const char* dbgName,)
512 size_t pInitialBufferSizeInKB,
513 unsigned pBufferGrowthInPercent= 200 )
514 : recyclables ( nullptr )
515 , nextBuffersUsableSize( (pInitialBufferSizeInKB * 1024 * pBufferGrowthInPercent) / 100 )
516 , bufferGrowthInPercent( pBufferGrowthInPercent )
517ALIB_DBG(,DbgName(dbgName)) {
518 #if ALIB_DEBUG && !ALIB_DEBUG_ASSERTION_PRINTABLES
519 ALIB_ASSERT_ERROR( pInitialBufferSizeInKB, "MONOMEM", "Initial buffer of 0kb requested." )
520 #endif
521 size_t initialBufferSize= pInitialBufferSizeInKB * 1024;
522 buffer= new (TAllocator().allocate(initialBufferSize, alignof(detail::Buffer)))
523 detail::Buffer( initialBufferSize );
524 #if ALIB_DEBUG_CRITICAL_SECTIONS
525 DbgCriticalSectionsPH.Construct("MonoAllocator");
526 #endif
527 buffer->previous= nullptr;
528 }
529 #endif
530
531 #if DOXYGEN
532 //==============================================================================================
533 /// Alternative constructor accepting an allocator instance.
534 /// To be used if template parameter \p{TAllocator} does not equal #"HeapAllocator"
535 /// or any (custom) default-constructible allocator type.
536 /// @param dbgName Has to be specified with debug-compilations only.
537 /// Use the macro #"ALIB_DBG" to pass a constant.
538 /// @param pAllocator The allocator to use for allocation of buffers.
539 /// @param pInitialBufferSizeInKB The size in kB (1024 bytes) of the first memory buffer used
540 /// for the allocator itself as well as for the first allocations.
541 /// @param pBufferGrowthInPercent Optional growth factor in percent, applied to each allocation
542 /// of a next buffer size in respect to its previous size.
543 /// Defaults to \c 200, which doubles the buffer size with each
544 /// next internal buffer allocation.
545 //==============================================================================================
547 TMonoAllocator( const char* dbgName, TAllocator& pAllocator,
548 size_t pInitialBufferSizeInKB, unsigned pBufferGrowthInPercent= 200 );
549 #else
551 TMonoAllocator( ALIB_DBG(const char* dbgName,) TAllocator& pAllocator,
552 size_t pInitialBufferSizeInKB, unsigned pBufferGrowthInPercent= 200 )
553 : allocMember ( pAllocator )
554 , recyclables ( nullptr )
555 , nextBuffersUsableSize( (pInitialBufferSizeInKB * 1024 * pBufferGrowthInPercent) / 100 )
556 , bufferGrowthInPercent( pBufferGrowthInPercent )
557ALIB_DBG(,DbgName(dbgName)) {
558 ALIB_ASSERT_ERROR( pInitialBufferSizeInKB, "MONOMEM", "Initial buffer of 0kb requested." )
559 size_t initialBufferSize= pInitialBufferSizeInKB * 1024;
560 buffer= new (TAllocator().allocate(initialBufferSize, alignof(detail::Buffer)))
561 detail::Buffer( initialBufferSize );
562 #if ALIB_DEBUG_CRITICAL_SECTIONS
563 DbgCriticalSectionsPH.Construct("MonoAllocator");
564 #endif
565 buffer->previous= nullptr;
566 }
567 #endif
568
569 /// Not copyable.
571
572 /// Not movable.
574
575 /// Destructor. Disposes all memory allocated with #ChainedAllocator.
578
579
580 //##############################################################################################
581 // Self-Contained Creation
582 //##############################################################################################
583
584 #if DOXYGEN
585 //==============================================================================================
586 /// This static method creates an object of this type inside "itself", aka inside its first
587 /// allocated buffer.
588 /// Instances created with this method have to be deleted by only invoking the destructor,
589 /// e.g., using #"lang::Destruct;*".
590 ///
591 /// Method #Reset must not be called using its default parameter when an instance of this type
592 /// was created by this method. Instead, if reset operations are desired, a snapshot has to be
593 /// taken (see method #TakeSnapshot) right after the invocation of this method and maybe
594 /// other initial members that should survive a reset, which then has to be passed to method
595 /// \b Reset.<br>
596 /// Alternatively, if only the monotonic allocator should survive the reset, overloaded method
597 /// #Reset(size_t, size_t) might be used, passing <c>sizeof(TMonoAllocator<T>)</c> and
598 /// <c>alignof(TMonoAllocator<T>)</c> as parameters.
599 ///
600 /// @param dbgName Has to be specified with debug-compilations only.
601 /// Use the macro #"ALIB_DBG" to pass a constant.
602 /// @param pAllocator The allocator used for creating the first buffer.
603 /// @param initialBufferSizeInKB The size of memory the buffers allocated in kilobytes.
604 /// @param bufferGrowthInPercent Optional growth factor in percent, applied to the buffer size
605 /// with each next buffer allocation.
606 /// Values provided should be greater than 100.<br>
607 /// Defaults to \c 200, which doubles buffer size with each
608 /// next internal buffer allocation.
609 /// @return A pointer to an instance of this type \b MonoAllocator residing in its first
610 /// created buffer.
611 //==============================================================================================
613 static TMonoAllocator* Create( const char* dbgName,
614 TAllocator& pAllocator,
615 size_t initialBufferSizeInKB,
616 unsigned bufferGrowthInPercent= 200 );
617 #else
619 static TMonoAllocator* Create( ALIB_DBG(const char* dbgName,)
620 TAllocator& pAllocator,
621 size_t initialBufferSizeInKB,
622 unsigned bufferGrowthInPercent= 200 );
623 #endif
624
625 #if DOXYGEN
626 //==============================================================================================
627 /// Same as #Create(const char*, TAllocator&, size_t, unsigned), but misses the allocator
628 /// parameter.
629 /// Used with chained allocators that are default-constructible (e.g., \b HeapAllocator):
630 ///
631 /// @param dbgName Has to be specified with debug-compilations only.
632 /// Use the macro #"ALIB_DBG" to pass a constant.
633 /// @param initialBufferSizeInKB The size of memory the buffers allocated in kilobytes.
634 /// @param bufferGrowthInPercent Optional growth factor in percent, applied to the buffer size
635 /// with each next buffer allocation.
636 /// Values provided should be greater than 100.<br>
637 /// Defaults to \c 200, which doubles buffer size with each
638 /// next internal buffer allocation.
639 /// @tparam TRequires Defaulted template parameter. Must not be specified.
640 /// @return A pointer to an instance of this type \b MonoAllocator residing in its first
641 /// created buffer.
642 //==============================================================================================
643 template<typename TRequires= lang::AllocatorMember<TAllocator>>
644 requires std::default_initializable<TRequires>
645 static TMonoAllocator* Create( const char* dbgName,
646 size_t initialBufferSizeInKB,
647 unsigned bufferGrowthInPercent= 200 );
648 #else
649 template<typename TRequires= lang::AllocatorMember<TAllocator>>
650 requires std::default_initializable<TRequires>
651 static TMonoAllocator* Create( ALIB_DBG( const char* dbgName, )
652 size_t initialBufferSizeInKB,
653 unsigned bufferGrowthInPercent= 200 )
654 {
655 TAllocator a;
656 return Create( ALIB_DBG(dbgName,) a, initialBufferSizeInKB, bufferGrowthInPercent );
657 }
658 #endif
659
660
661 /// This method has to be called before destruction of an instance, in the case that
662 /// instance was allocated using a special version of the constructors that accept an external
663 /// #"detail::Buffer".
664 /// This will remove the initially given buffer from the list of buffers, and thus this buffer
665 /// not be deleted. Only if the memory was simply heap-allocated using <c>std::malloc</c>,
666 /// <c>C++ new operator</c>, or #"HeapAllocator", and if the memory is intended to be
667 /// freed, this method may not be called. As a sample, class #"TLocalAllocator",
668 /// which uses stack-memory for the first buffer, will call this method in its destructor.
669 ///
670 /// \attention
671 /// 1. If this method is not called when needed, this leads to undefined behavior.
672 /// 2. If this method is called without the provision of an external buffer on construction,
673 /// a memory leak occurs. (The first buffer this allocator allocated, will not be freed.)
674 /// 3. After this method has been invoked, the instance becomes unusable and is to be
675 /// destructed in a next step.
676 ///
677 /// Note that as an exception to the rule, this method's name starts with a lowercase
678 /// letter as if it was protected, while it has to be public.
681
682
683 /// Tests if the non-initializing constructor #TMonoAllocator(const char*, std::nullptr_t) was
684 /// used.
685 /// @return \c false if this allocator needs to be initialized by performing a placement-new on
686 /// <c>this</c>.
687 bool IsInitialized() const noexcept { return buffer != nullptr; }
688
689
690 //##############################################################################################
691 // lang::Allocator Implementation
692 //##############################################################################################
693
694 /// Allocate memory from the internal buffer. If the buffer's size is exceeded, a next buffer
695 /// is allocated and used.
696 /// @param size The size of memory the block to allocate in bytes.
697 /// With this allocator this is not an input/output parameter.
698 /// @param alignment The (minimum) alignment of the memory block to allocate in bytes.
699 /// See Chapter #"alib_contmono_further_alignment" of the Programmer's
700 /// Manual of this module.
701 /// @return Pointer to the allocated memory.
702 inline void* allocate( size_t size, size_t alignment ) {
703 #if ALIB_DEBUG_CRITICAL_SECTIONS
704 DbgCriticalSectionsPH.Get()->Acquire(ALIB_CALLER);
705 #endif
707
708 ALIB_ASSERT_ERROR( buffer , "MONOMEM",
709 "This MonoAllocator was constructed passing 'nullptr' and is not usable.")
710 ALIB_ASSERT_ERROR( !dbgLock, "MONOMEM", "This MonoAllocator is locked.")
711 ALIB_ASSERT_ERROR(lang::BitCount(alignment) == 1, "MONOMEM",
712 "The requested alignment has to be a power of 2. Requested is: ", int(alignment) )
713
714 #if ALIB_DEBUG_MEMORY
715 ++dbgStats.QtyAllocations;
716 DBG_ALIGNMENT_INIT( buffer )
717 #endif
718
719 #if ALIB_DEBUG_MEMORY
720 if( lang::DbgAlloc::extSize( size ) > size_t(buffer->end - reinterpret_cast<char*>(buffer)) / 2 )
721 ALIB_WARNING( "MONOMEM",
722 "MonoAllocator: Allocation size exceeds 1/2 of the current buffer size.\n"
723 "The allocator's buffer size should be increased.\n"
724 "Requested size: ", size )
725 #endif
726
727
728 char* mem= buffer->allocate(size, alignment);
729 if ( mem ) {
730 #if ALIB_DEBUG_MEMORY
731 DBG_ALIGNMENT_MEASURE(buffer)
732 #endif
733 #if ALIB_DEBUG_CRITICAL_SECTIONS
734 DbgCriticalSectionsPH.Get()->Release(ALIB_CALLER);
735 #endif
736 return mem;
737 }
738
739 mem= nextBuffer( size, alignment );
740 #if ALIB_DEBUG_CRITICAL_SECTIONS
741 DbgCriticalSectionsPH.Get()->Release(ALIB_CALLER);
742 #endif
743 return mem;
744 }
745
746 /// Grows a piece of memory.
747 /// If a new allocation had to be performed, the existing data is copied.
748 /// Note that this allocator implementation never shrinks memory, thus
749 /// if \p{oldSize} is greater than \p{newSize}, the original memory is returned.<br>
750 /// @param mem The memory to reallocate.
751 /// @param oldSize The current size of \p{mem}.
752 /// @param newSize The now required size of \p{mem} in bytes.
753 /// With this allocator this is not an input/output parameter.
754 /// @param alignment The (minimum) alignment of the memory block to allocate in bytes.
755 /// (Has to be the same as before, but this is not tested here).
756 /// See Chapter #"alib_contmono_further_alignment" of the Programmer's
757 /// Manual of this module.
758 /// @return Pointer to the re-allocated memory block.
759 inline void* reallocate( void* mem, size_t oldSize, size_t newSize, size_t alignment ) {
760 ALIB_ASSERT_ERROR( !dbgLock, "MONOMEM", "This MonoAllocator is locked.")
762 ALIB_ASSERT_ERROR(lang::BitCount(alignment) == 1, "MONOMEM",
763 "The requested alignment has to be a power of 2. Requested is: ", alignment )
764
766 if( oldSize >= newSize )
767 return mem;
768
769 if( buffer->act - lang::DbgAlloc::extSize(oldSize) == mem )
770 buffer->act-= lang::DbgAlloc::extSize(oldSize);
771
772 auto* newMem= allocate( newSize, alignment );
773 if( newMem != mem )
774 std::memcpy( newMem, mem, oldSize );
775
776 #if ALIB_DEBUG_MEMORY
777 else
778 --dbgStats.QtyAllocations;
779 #endif
781 return newMem;
782 }
783
784 /// This method is empty for this allocator and optimized out. Only if the configuration macro
785 /// #"ALIB_DEBUG_ALLOCATIONS" is set, the method will overwrite the freed memory with
786 /// character <c>0xD2</c>. This is why method #allowsMemSplit returns \c false if that
787 /// symbol is set and some few optimizations will not be performed in that mode, for example,
788 /// the reuse of bucket arrays as recycled node objects when resizing hashtables.
789 ///
790 /// @param mem The memory to free.
791 /// @param size The allocated size.
792 inline void free( void* mem, size_t size) const {
793 ALIB_ASSERT_ERROR( !dbgLock, "MONOMEM", "This MonoAllocator is locked.")
796 }
797
798 /// This is an empty implementation of the prototyped method.
799 /// It is empty because this allocator never returns a higher allocation size than requested.
800 /// #"Allocator::dbgAcknowledgeIncreasedAllocSize;*".
801 /// @tparam TSize The type of parameter \p{allocSize}. (Deduced by the compiler.)
802 template<typename TSize>
803 void dbgAcknowledgeIncreasedAllocSize( void*, TSize ) const {}
804
805 /// Returns a temporary object (which is usually optimized out together with a call to this
806 /// operator) providing high-level convenience methods for allocation.
807 /// @see Class #"AllocatorInterface"
808 /// @return A temporary high-level interface into the allocator.
811
812 #if DOXYGEN
813 /// See the description of this method with prototype
814 /// #"Allocator::allowsMemSplit;*".<br> (Note: This method is static. For technical
815 /// reasons this cannot be reflected in this documentation)
816 /// @return \c true, except if the configuration macro #"ALIB_DEBUG_ALLOCATIONS" is given.
817 constexpr bool allowsMemSplit() noexcept;
818 #else
819 static inline constexpr bool allowsMemSplit() noexcept {
820 #if !ALIB_DEBUG_ALLOCATIONS
821 return true;
822 #else
823 return false;
824 #endif
825 }
826 #endif
827
828 //##############################################################################################
829 // Snapshots and Reset
830 //##############################################################################################
831
832 /// Saves the current state of the allocator and returns this information as a \b Snapshot
833 /// value. Such snapshots may be passed to method #Reset(Snapshot).
834 ///
835 /// Note that the actual memory is \b not copied and restored. In this respect the word
836 /// "Snapshot" is overstating. What is stored are the current use of memory, but not it's
837 /// contents.
838 ///
839 /// @return A (lightweight) snapshot value object.
841
842 /// Resets this allocator to the given #"Snapshot".
843 /// Parameter \p{snapshot} is defaulted with a default-constructed \b Snapshot, which
844 /// completely resets the allocator.
845 ///
846 /// With a reset, the memory buffers which had been allocated after taking the given
847 /// \p{snapshot}, are not released back to the operating system, but re-used with future
848 /// monotonic allocations.
849 ///
850 /// This method is useful in cases where some permanent objects which are allocated first
851 /// have to be preserved with resets.
852 ///
853 /// Note that snapshots taken after the given one become invalid. This is because
854 /// class \b Snapshot is only a simple lightweight class that marks the currently
855 /// used buffer and its fill level.
856 ///
857 /// @param snapshot The snapshot to reset to.
859 void Reset( Snapshot snapshot= Snapshot() );
860
861 /// Special version of #Reset(Snapshot) which resets this allocator to the first buffer
862 /// and within that, behind the first object of the given size.<br>
863 /// This method is used by class #"TSharedMonoVal" to avoid the need of storing
864 /// a snapshot behind itself.
865 ///
866 /// If the configuration macro #"ALIB_DEBUG_ALLOCATIONS" is set, then all freed memory is
867 /// overwritten with <c>0xD2</c>. This helps to identify invalid reset operations.
868 /// @param firstObjectSize The size of the first emplaced object.
869 /// @param firstObjectAlignment The alignment of the first emplaced object.
870 void Reset( size_t firstObjectSize, size_t firstObjectAlignment )
871 {
872 Reset( ALIB_DBG( Snapshot(nullptr, reinterpret_cast<char*>(1)) ) );
873 buffer->allocate( firstObjectSize, firstObjectAlignment );
874 }
875
876 //##############################################################################################
877 // Statistics and Debug-Interface
878 //##############################################################################################
879
880 /// Fills the given \p{result} record with statistical information about this allocator.
881 /// @see Method #DbgGetStatistics, which delivers further information but is only available
882 /// with configuration macro #"ALIB_DEBUG_MEMORY" set.
883 /// @param result The object to write the result into. (Will be reset before use.)
885 void GetStatistics( Statistics& result );
886
887 /// Lock or unlock this allocator.
888 /// If locked, an ALib assertion is raised if allocations are performed.
889 /// This can be quite useful to detect allocations with an allocator that is shared
890 /// between different code entities and to enforce certain allocation contracts.
891 ///
892 /// With release-compilations, this method is empty and optimized out.
893 /// @see Chapter #"alib_contmono_further_debug" of the Programmer's Manual of this
894 /// \alibmod_nl.
895 /// @param onOff The state to set.
896 void DbgLock(bool onOff) noexcept { ALIB_DBG( dbgLock= onOff;) (void) onOff; }
897
898 /// Allows access to the internal buffer.
899 /// For example, this is used with function #"DbgDumpStatistics".
900 /// With release-compilations, this method is empty and not useable.
901 /// @return A pointer to the internal buffer.
902 detail::Buffer* DbgGetBuffer() noexcept { ALIB_REL_DBG( return nullptr;, return buffer;) }
903
904 /// Allows access to the internal buffer (const overload).
905 /// For example, this is used with function #"DbgDumpStatistics".
906 /// With release-compilations, this method is empty and not useable.
907 /// @return A pointer to the internal buffer.
908 const detail::Buffer* DbgGetBuffer() const noexcept {
909 ALIB_REL_DBG( return nullptr; ,
910 return buffer; )
911 }
912
913 /// If the configuration macro #"ALIB_DEBUG_ALLOCATIONS" is not set, this method is empty and will
914 /// be optimized out. Otherwise, this will raise an \alib_assertion if the piece of allocated
915 /// memory is corrupted or its allocation size is not rightfully given by the using code.
916 /// @see Chapter #"alib_contmono_further_debug" of the Programmer's Manual.
917 ///
918 /// @tparam TSize The type of parameter \p{size}. (Deduced by the compiler.)
919 /// @param mem The address of the allocated object.
920 /// @param size The requested allocation size of the object.
921 template<typename TSize>
922 void dbgCheckMemory( void* mem, TSize size )
924
925 #if ALIB_DEBUG_MEMORY
926 //==========================================================================================
927 /// Returns allocation statistics for manual performance optimization.
928 /// \par Availability
929 /// This method is included only if the configuration macro #"ALIB_DEBUG_MEMORY" is set.
930 ///
931 /// @return The internal statistics struct.
932 //==========================================================================================
933 const DbgStatistics& DbgGetStatistics() const { return dbgStats; }
934 #endif
935
936
937 /// This is a simple helper-type following the
938 /// \https{RAII idiom,https://en.cppreference.com/w/cpp/language/raii}.
939 /// On construction a snapshot of the given mono allocator is taken and the allocator
940 /// is reset to the state on destruction.
941 struct Resetter {
942 TMonoAllocator& MA; ///< The mono allocator to reset on destruction.
943 Snapshot snapshot; ///< The snapshot taken on construction.
944
945 /// Constructor.
946 /// @param ma The mono allocator to reset on destruction.
948
949 /// Destructor. Resets the mono allocator given with construciton.
950 ~Resetter() { MA.Reset(snapshot); }
951 };
952
953
954}; // class TMonoAllocator
955
956
957//################################ Template instantiation declaration ##############################
958#if !DOXYGEN
959extern template ALIB_DLL class TMonoAllocator<lang::HeapAllocator>;
960#endif
961
962//######################################### Global Allocator #######################################
963
964/// This is the global monotonic allocator singleton instance.
965/// It's initial size defaults to \ 128 kilobytes. This can be tweaked by performing a
966/// placement-new on this instance before #"alib_mod_bs;bootstrapping ALib".
967///
968/// \see
969/// - Chapter #"alib_contmono_globalinstance" of the Programmer's Manual of this \alibmod_nl.
970/// - \b Lock instance #"GLOBAL_ALLOCATOR_LOCK"
971extern ALIB_DLL TMonoAllocator<lang::HeapAllocator> GLOBAL_ALLOCATOR;
972
973#if !ALIB_SINGLE_THREADED
974/// This <em>mutex</em> is used to protect the #"GLOBAL_ALLOCATOR" from racing
975/// conditions in multithreaded software.<br>
976/// If the configuration macro #"ALIB_DEBUG_CRITICAL_SECTIONS" is set, this lock will be attached
977/// to the #"lang::DbgCriticalSections" instance in #GLOBAL_ALLOCATOR during bootstrap.
978/// Thus, an assertion will be raised if the #"GLOBAL_ALLOCATOR" is used without
979/// locking this mutex.<br>
980/// This is a recursive lock.
981/// This allows using the #"AllocatorInterface;high-level allocation interface" with
982/// allocations, which constructs objects.
983/// These objects might recursively use the global allocator for their members.
985#endif
986
987} // namespace alib[::monomem]
988
989/// Type alias in namespace \b alib.
990/// This alias fixes template parameter \p{TAllocator} (which defines the
991/// #"alib_contmono_chaining;chained allocator") to type #"HeapAllocator".
993
994/// Type alias in namespace \b alib to denote the use of a #"MonoAllocator"
995/// with the type #"StdAllocator".
996template<typename T>
998
999
1000
1001} // namespace [alib]
#define ALIB_DLL
Definition alib.inl:573
#define ALIB_CALLER
Definition alib.inl:1096
#define ALIB_WARNING(domain,...)
Definition alib.inl:1141
#define ALIB_EXPORT
Definition alib.inl:562
#define ALIB_DBG(...)
Definition alib.inl:931
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
#define ALIB_REL_DBG(releaseCode,...)
Definition alib.inl:933
constexpr Snapshot(detail::Buffer *pBuffer, char *pFill) noexcept
char * actFill
Pointer to the first free byte in the current buffer.
constexpr Snapshot() noexcept
detail::Buffer * buffer
The current buffer.
constexpr bool IsValid() noexcept
const DbgStatistics & DbgGetStatistics() const
~TMonoAllocator()
Destructor. Disposes all memory allocated with ChainedAllocator.
void DbgLock(bool onOff) noexcept
TMonoAllocator(const char *dbgName, detail::Buffer *pInitialBuffer, size_t pInitialBufferSizeInKB, unsigned pBufferGrowthInPercent=200)
lang::Placeholder< lang::DbgCriticalSections > DbgCriticalSectionsPH
void free(void *mem, size_t size) const
constexpr bool allowsMemSplit() noexcept
lang::AllocatorMember< TAllocator > allocMember
The type of the base class that stores the chained allocator.
void dbgCheckMemory(void *mem, TSize size)
detail::Buffer * DbgGetBuffer() noexcept
TMonoAllocator(const TMonoAllocator &)=delete
Not copyable.
TMonoAllocator(const char *dbgName, TAllocator &pAllocator, detail::Buffer *pInitialBuffer, size_t pInitialBufferSizeInKB, unsigned pBufferGrowthInPercent=200)
static TMonoAllocator * Create(const char *dbgName, TAllocator &pAllocator, size_t initialBufferSizeInKB, unsigned bufferGrowthInPercent=200)
TMonoAllocator(const char *dbgName, TAllocator &pAllocator, size_t pInitialBufferSizeInKB, unsigned pBufferGrowthInPercent=200)
void dbgAcknowledgeIncreasedAllocSize(void *, TSize) const
lang::AllocatorInterface< TMonoAllocator > operator()()
void * allocate(size_t size, size_t alignment)
static TMonoAllocator * Create(const char *dbgName, size_t initialBufferSizeInKB, unsigned bufferGrowthInPercent=200)
void * reallocate(void *mem, size_t oldSize, size_t newSize, size_t alignment)
char * nextBuffer(size_t size, size_t alignment)
TMonoAllocator(TMonoAllocator &&)=delete
Not movable.
bool IsInitialized() const noexcept
void GetStatistics(Statistics &result)
void Reset(size_t firstObjectSize, size_t firstObjectAlignment)
void Reset(Snapshot snapshot=Snapshot())
TMonoAllocator(const char *dbgName, std::nullptr_t) noexcept
const detail::Buffer * DbgGetBuffer() const noexcept
TMonoAllocator(const char *dbgName, size_t pInitialBufferSizeInKB, unsigned pBufferGrowthInPercent=200)
void SingleThreaded()
Definition assert.cpp:140
constexpr int BitCount(TIntegral value)
Definition bits.inl:210
Details of namespace #"alib::monomem;2".
RecursiveLock GLOBAL_ALLOCATOR_LOCK
TMonoAllocator< lang::HeapAllocator > GLOBAL_ALLOCATOR
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
lang::StdAllocator< T, MonoAllocator > StdMA
threads::RecursiveLock RecursiveLock
Type alias in namespace alib.
static constexpr void clearMem(T *mem, size_t size, unsigned char magic)
static constexpr void annotate(T *mem, size_t size, unsigned char magic)
static constexpr size_t extSize(TIntegral size)
static void checkMem(void *mem, const TSize size, unsigned char magic, const char *name)
size_t QtyAllocationsInclResets
The number of allocations performed, cumulated over resets.
size_t QtyTrivialAllocationsInclResets
The number of allocations that did not create a new buffer, cumulated over resets.
size_t AlignmentWaste
The number of bytes lost for alignment.
size_t QtyBufferSizeExceeds
The number of allocations that have been larger than the buffer size.
size_t QtyAllocations
The number of allocations performed.
size_t AllocSizeInclResets
The number of allocated space, cumulated over resets.
size_t QtyTrivialAllocations
The number of allocations that did not create a new buffer .
size_t QtyResets
The number of resets performed.
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.
~Resetter()
Destructor. Resets the mono allocator given with construciton.
TMonoAllocator & MA
The mono allocator to reset on destruction.
Snapshot snapshot
The snapshot taken on construction.
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.
Buffer()=default
Defaulted default constructor.
static constexpr unsigned char CLEAR
static constexpr unsigned char MAGIC
char * allocate(size_t size, size_t alignment)