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