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