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