ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
allocation.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of the \aliblong. It does not belong to an \alibmod and is
4/// included in any \alibdist.
5///
6/// \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
7/// Published under \ref mainpage_license "Boost Software License".
8//==================================================================================================
9#ifndef HPP_ALIB_LANG_ALLOCATION
10#define HPP_ALIB_LANG_ALLOCATION 1
11#pragma once
12#include "alib/lang/tmp.hpp"
14#include <cstddef>
15#include <cstdlib>
16#include <cstring>
17#include <utility>
18
19namespace alib { namespace lang {
20
21
22/// Provides debugging utility methods used by allocator types \alib{lang;HeapAllocator},
23/// \alib{monomem;TMonoAllocator}, and \alib{monomem;TPoolAllocator}.
24/// Each method is empty and thus optimized out in case compiler symbol
25/// \ref ALIB_DEBUG_ALLOCATIONS is not set.
26/// @see Chapter \ref alib_contmono_further_debug of the Programmer's Manual.
28{
29 /// Adds needed space for \b 4 magic bytes plus the <c>size_t</c> value that is stored.
30 /// @tparam TIntegral The type of given \p{size}.
31 /// (Deduced by the compiler, templated for convenience.)
32 /// @param size The given size or the extended size.
33 /// @return The truly allocated size.
34 template<class TIntegral>
35 static constexpr size_t extSize (TIntegral size)
36 {
37 #if !ALIB_DEBUG_ALLOCATIONS
38 return size_t(size);
39 #else
40 return size_t(size) + 4 + sizeof(size_t);
41 #endif
42 }
43
44 /// Writes magic bytes and size-information behind the given memory.
45 /// @tparam T The type of the given pointer \p{mem}.
46 /// (Deduced by the compiler, templated for convenience.)
47 /// @param mem The pointer to the allocated object.
48 /// @param size The originally requested size.
49 /// @param magic The magic byte to write after the element.
50 template<class T>
51 static constexpr void annotate(T* mem, size_t size, unsigned char magic)
52 {
53 #if ALIB_DEBUG_ALLOCATIONS
55 auto* cMem= reinterpret_cast<unsigned char*>(mem);
56 size_t idx= size;
57 for( ; idx< size + 4; ++idx)
58 cMem[idx] = magic;
59 for( size_t i= 0; i< sizeof(size_t); ++i)
60 {
61 cMem[idx++]= static_cast<unsigned char>( size & 0xFF );
62 size>>=8;
63 }
65 #else
66 (void) mem; (void) size; (void) magic;
67 #endif
68 }
69
70 /// The given character \p{c} is written into the allocated memory (including its extended
71 /// size).
72 /// @tparam T The type of the given pointer \p{mem}. (Deduced by the compiler.)
73 /// @param mem The pointer to the allocated object.
74 /// @param size The allocated size from the user's perspective (not the real size)
75 /// @param magic The magic byte to overwrite the freed memory with.
76 template<class T>
77 static constexpr void clearMem(T* mem, size_t size, unsigned char magic)
78 {
79 #if ALIB_DEBUG_ALLOCATIONS
80 memset( reinterpret_cast<char*>(mem), magic, extSize(size) );
81 #else
82 (void) mem; (void) size; (void) magic;
83 #endif
84 }
85
87 /// Raises an \alib assertion if the piece of allocated memory is corrupted or its allocation
88 /// size is not rightfully given by the using code.
89 ///
90 /// @tparam TSize The type of parameter \p{size}. (Deduced by the compiler.)
91 /// @param mem The address of the allocated object.
92 /// @param size The requested allocation size of the object.
93 /// @param magic The value of the magic bytes that had been written with #annotate.
94 /// @param name The type of the allocator.
95 /// In case of type \b MonoAllocator, the debug-name of the instance.
96 template<typename TSize>
97 static
98 void checkMem( void* mem, const TSize size, unsigned char magic, const char* name )
99 {
100 #if ALIB_DEBUG_ALLOCATIONS
102 auto* cMem= reinterpret_cast<unsigned char*>(mem);
103 size_t idx= size;
104 while ( idx< size + 4)
105 if( cMem[idx++] != magic )
106 ALIB_ERROR( "MONOMEM", "Corrupt memory with allocator ", name )
107
108 size_t storedSize= 0;
109 idx+= sizeof(size_t);
110 do
111 {
112 storedSize<<= 8;
113 storedSize|= cMem[--idx];
114 }
115 while( idx > size + 4);
116
117 if( storedSize != size )
118 ALIB_ERROR( "MONOMEM", "Given size does not match the allocated size "
119 "(or corrupt memory). Allocator: ", name )
121 #else
122 (void) mem; (void) size; (void) magic; (void) name;
123 #endif
124 }
126
127}; // struct DbgAlloc
128
129#if DOXYGEN
130// =================================================================================================
131/// This is class does not exist but is just exposed in the documentation of \alib.
132/// Its purpose is to precisely define what an \alib "Allocator" needs to offer as an interface
133/// to be usable with \alib template types that expect an allocator.
134///
135/// Implementations of this interface exist with \alib.:
136/// - \alib{lang;HeapAllocator},
137/// - \alib{monomem;TMonoAllocator}, its derivate
138/// - \alib{monomem;TLocalAllocator}, and
139/// - \alib{monomem;TPoolAllocator}.
140///
141/// The first is just using \c std::malloc and \c std::free, hence it does just the same
142/// allocation that C++ keywords <c>new</c> and <c>delete</c> do. The others are introduced and
143/// discussed by module \alib_monomem.
144///
145/// As an exception to the \ref alib_manual_appendix_naming "naming conventions used by ALib",
146/// the members of this type start with a non-capital letter, although they are declared \c public.
147/// This was done to emphasize that an indirect use of this type through type
148/// \alib{lang;AllocatorInterface} is available with #operator()(), and such usage is preferred.
149// =================================================================================================
151{
152 /// The type of the allocator that this allocator uses underneath for its allocations.
153 /// In case of \alib{lang;HeapAllocator}, this type is defined as <c>void</c>.<br>
154 /// Allocators provided by \alib allow to access the instance with publicly inherited methods
155 /// \alib{lang::AllocatorMember;GetAllocator} and \alib{lang::AllocatorMember;AI}.
156 using ChainedAllocator = TAllocator;
157
158 /// The minimum alignment an allocator supports, respectively uses even if lower values
159 /// are requested.
160 /// @see Chapter \ref alib_contmono_further_alignment of the Programmer's Manual of module
161 /// \alib_monomem.
162 static constexpr size_t MIN_ALIGNMENT;
163
164 /// The maximum alignment an allocator supports.
165 /// @see Chapter \ref alib_contmono_further_alignment of the Programmer's Manual of module
166 /// \alib_monomem.
167 static constexpr size_t MAX_ALIGNMENT;
168
169 /// Allocate memory using the allocator.<br>
170 /// Note, that parameter \p{size} is provided as a reference. If an allocator implementation
171 /// allocates bigger pieces than requested (which is true for
172 /// \alib{monomem;TPoolAllocator;PoolAllocator}), then this parameter is modified to this higher
173 /// value.
174 /// @param[in,out] size The size of memory the block to allocate in bytes. This is an input and
175 /// output parameter. Might be increased to the truly allocated size.
176 /// In case it was increased, the new value does not need to be passed
177 /// back to #reallocate or #free. Allocators are agnostic which of the
178 /// sizes are passed back, the requested, or the true size of the block.
179 /// @param alignment The (minimum) alignment of the memory block to allocate in bytes.
180 /// @return Pointer to the allocated memory.
181 void* allocate( size_t& size, size_t alignment );
182
183 /// Shrinks or grows a piece of memory. If a new allocation was performed the existing
184 /// data is copied.
185 /// Note, that parameter \p{newSize} is provided as a reference. If an allocator implementation
186 /// allocates bigger pieces than requested (which is true for
187 /// \alib{monomem;TPoolAllocator;PoolAllocator}), then this parameter is modified to this higher
188 /// value.
189 /// @param mem The memory to reallocate.
190 /// @param oldSize The current size of \p{mem}.
191 /// @param[in,out] newSize The new size of memory requested to allocate in bytes. This is an
192 /// input and output parameter. It might be increased to the truly
193 /// allocated size.
194 /// @param alignment The (minimum) alignment of the memory block to allocate in bytes.
195 /// @return Pointer to the re-allocated memory.
196 void* reallocate( void* mem, size_t oldSize, size_t& newSize, size_t alignment );
197
198 /// Frees memory that was previously allocated with the same allocator.
199 ///
200 /// @param mem The memory to dispose.
201 /// @param size The size of the given \p{mem}.
202 void free(void* mem, size_t size);
203
204 /// Returns a temporary object (which is usually optimized out together with a call to this
205 /// operator) providing high-level convenience methods for allocation.
206 /// @see Class \alib{lang::AllocatorInterface}
207 /// @return A temporary high-level interface into the allocator.
209
210 /// This is a constexpr static method that determines if a type allows splitting memory
211 /// and later passing the pieces back to free.<br>
212 /// Of the allocators exposed by module \alib_monomem, only \alib{monomem;TMonoAllocator}
213 /// returns \c true. This is because this allocator has an empty \b free method and thus
214 /// is agnostic about the memory freed.
215 /// If compiler symbol \ref ALIB_DEBUG_ALLOCATIONS is set, then also this allocator returns
216 /// \c false.
217 ///
218 /// @return \c true if this allocator is agnostic against freeing of objects which have not
219 /// been allocated as given.
220 static constexpr bool allowsMemSplit() noexcept;
221
222 /// Allocator name. This is a pure debug-field that helps to identify leaks and other issues
223 /// with allocators. The field is public an may be changed as wanted by a user of the library.
224 ///
225 /// Class \alib{monomem;TMonoAllocator;MonoAllocator} requires a name as the first parameter
226 /// with every overloaded constructor. Consequently, this argument has to be passed enclosed
227 /// in macro \ref ALIB_DBG (with a trailing comma) to have it pruned with release-builds.
228 ///
229 /// Class \alib{monomem;TMonoAllocator;PoolAllocator} grabs this name from its chained
230 /// allocator, which most often is an already named \b MonoAllocator. Thus, no constructor
231 /// argument is available. Its name may be changed after construction as appropriate.
232 const char* DbgName;
233
234 /// This method has to be called to set the correct object size in the case that:
235 /// a) An allocation method returned a higher allocation size (as of the current \alib release,
236 /// this only happens with the use of class \alib{monomem;TPoolAllocator;PoolAllocator}, and
237 /// b) this higher size is not ignored by the using code and,
238 /// c) this higher size is reported to one of the <em>free</em>-methods on object destruction.
239 ///
240 /// Within \alib a sample of such a type is class \alib{strings;TAString;AString}: this type
241 /// requests a string buffer as needed but acknowledges if the returned buffer is lager.
242 /// With destruction, this higher capacity is passed when the buffer is deleted.
243 /// Thus, this type invokes this method after performing allocations.
244 ///
245 /// Note that this method is empty and optimized out, when compiler symbol
246 /// \ref ALIB_DEBUG_ALLOCATIONS is not set. If set, an \alib assertion is raised if either the
247 /// magic bytes around the memory are not found, or the given \p{allocSize} does not
248 ///
249 /// @see Chapter \ref alib_contmono_further_debug of the Programmer's Manual.
250 ///
251 /// @tparam TSize The type of parameter \p{allocSize}. (Deduced by the compiler.)
252 /// @param mem The address of the allocated object.
253 /// @param allocSize The true allocation size returned by the method #allocate .
254 template<typename TSize>
255 void dbgAcknowledgeIncreasedAllocSize( void* mem, TSize allocSize ) const;
256
257 /// If the compiler symbol \ref ALIB_DEBUG_ALLOCATIONS is not set, this method is empty and will
258 /// be optimized out. Otherwise, this will raise an \alib assertion if the piece of allocated
259 /// memory is corrupted or its allocation size is not rightfully given by the using code.
260 /// @see Chapter \ref alib_contmono_further_debug of the Programmer's Manual.
261 ///
262 /// @tparam TSize The type of parameter \p{size}. (Deduced by the compiler.)
263 /// @param mem The address of the allocated object.
264 /// @param size The requested allocation size of the object.
265 template<typename TSize>
266 void dbgCheckMemory( void* mem, TSize size ) const;
267
268}; // struct Allocator
269#endif // Doxygen
270
271
272// =================================================================================================
273/// This type offers high-level convenience methods for \alib allocators.<br>
274/// An \alib allocator (a type that offers an interface as specified with prototype
275/// \alib{lang;Allocator}) has to provide only three <b>low-level (!)</b> allocation methods.
276/// Those are:
277/// - \alib{lang::Allocator;allocate(size_t& size, size_t alignment)},
278/// - \alib{lang::Allocator;reallocate(void* mem, size_t oldSize, size_t& newSize, size_t alignment)},
279/// - \alib{lang::Allocator;free(void* disposable, size_t size)}, and
280///
281/// Besides these, the C++ function call operator \alib{lang::Allocator;operator()()} has to be
282/// implemented to return a temporary instance of this type.
283/// Note that the compiler will optimize the function call and the temporary instance out.
284/// With this setup, each allocator offers the <b>high-level</b> allocation methods provided
285/// with this class.
286///
287/// The naming scheme of the convenience methods found with this type, is along the standards:
288/// - Methods containing the words <c>"Alloc"</c> or <c>"Free"</c> allocate, respectively free
289/// memory without construction, respectively destruction of type instances.
290/// - Methods containing the word <c>"New"</c> and <c>"Delete"</c> allocate, respectively free
291/// memory and in addition invoke constructors, respectively destructors of type instances.
292///
293/// In contrast to the low-level interface methods \alib{lang;Allocator::allocate} and
294/// \alib{lang;Allocator::reallocate}, information about a piece of memory returned that is larger
295/// than requested is not retrievable with the methods provided here. In case this can be of
296/// value, the low-level interface of an allocator has to be used.
297///
298/// The following quick sample illustrates the use of this class in combination with a
299/// \alib{monomem;TMonoAllocator}:
300///
301/// \snippet "ut_monomem.cpp" DOX_MONOMEM_ALLOCATOR_INTERFACE_TYPE
302/// \snippet "ut_monomem.cpp" DOX_MONOMEM_ALLOCATOR_INTERFACE
303///
304/// \note
305/// In this sample, the destructor is of class \c MyType is emtpy, and furthermore method
306/// \b free of class \b MonoAllocator is empty. Thus, the whole call to #Delete will be optimized
307/// out. With other allocators this is different. It is recommended to still include
308/// such calls to avoid memory leaks at the moment either the allocator is changed, an allocated
309/// type gets equipped with a destructor, etc.
310///
311/// @see
312/// - The \ref alib_mods_contmono "Programmer's Manual" of module \alib_monomem_nl.
313/// - Allocator types \alib{monomem;TMonoAllocator} and \alib{monomem;TPoolAllocator}
314/// found in module \alib_monomem_nl.
315/// - Class \alib{lang;HeapAllocator}, which is useful for templated types which are agnostic
316/// to underlying allocation strategies.
317/// - To allocate and create a copy of a character string, method \alib{strings;TString::Allocate}
318/// or constructor \alib{strings;TString;TString(TAllocator& allocator, const TString<TChar>&)}
319/// may be used. Freeing is then to be performed by using \alib{strings;TString::Free}.
320// =================================================================================================
321template<typename TAllocator>
323{
324 /// The allocator type to use.
325 TAllocator& allocator;
326
327 /// Constructor. Usually construction is performed by the function operator of the
328 /// an \b %Allocator, which then passes itself as parameter \p{pAllocator}.
329 /// @param pAllocator The allocator.
330 AllocatorInterface(TAllocator& pAllocator) : allocator(pAllocator) {}
331
332 /// Allocates memory of the requested \p{size} and \p{alignment}.
333 /// @tparam TSize The type of parameter \p{size}. Deduced by the compiler.
334 /// (Must be integral.)
335 /// @tparam TAlignment The type of parameter \p{alignment}. Deduced by the compiler.
336 /// (Must be integral.)
337 /// @param size The allocation size requested.
338 /// @param alignment The required alignment.
339 /// @return A pointer to the allocated memory.
340 template<typename TSize, typename TAlignment>
341 void* Alloc( TSize size, TAlignment alignment)
342 {
343 size_t s= size_t(size);
344 return allocator.allocate( s, size_t(alignment) );
345 }
346
347 /// Allocates memory of <c>sizeof(T)</c> and <c>alignof(T)</c>.
348 /// @tparam T The type of object to allocate memory for.
349 /// @return A pointer to the allocated memory.
350 template<typename T>
351 T* Alloc()
352 {
353 auto size= sizeof(T);
354 return reinterpret_cast<T*>( allocator.allocate(size, alignof(T) ) );
355 }
356
357 /// Allocates aligned memory for an array of objects of type \p{T} of size \p{length}
358 /// leaving the memory uninitialized.
359 /// @tparam T The array element type.
360 /// @tparam TLength The type of parameter \p{length}. Has to be integral.
361 /// Deduced by the compiler.
362 /// @param length The capacity of the requested array.
363 /// @return A pointer to the first element of the allocated array.
364 template<typename T, typename TLength>
365 T* AllocArray( TLength length )
366 {
367 auto size= sizeof(T[1]) * size_t(length);
368 return reinterpret_cast<T*>( allocator.allocate( size, alignof(T[]) ) );
369 }
370
371 /// Allocates memory of size- and alignment-suitable for type \p{T} and performs a
372 /// C++ "placement-new", passing the given variadic arguments to the type's constructor.
373 /// @tparam T Type of the object to allocate and construct.
374 /// @tparam TArgs Types of variadic parameters given with parameter \p{args}.
375 /// @param args Variadic parameters to be forwarded to the constructor of type \p{T}.
376 /// @return A pointer to the initialized array.
377 template<typename T, typename... TArgs>
379 T* New( TArgs&& ... args )
380 { return new (Alloc<T>()) T( std::forward<TArgs>( args )... ); }
381
382 /// Allocates aligned memory for an array of objects of type \p{T} of size \p{length}.
383 /// All array elements are initialized using a "placement-new", passing the given \p{args} to
384 /// each element's constructor.
385 /// @tparam T Element type of the array to allocate and construct.
386 /// @tparam TArgs Types of variadic parameters given with parameter \p{args}.
387 /// @tparam TSize The type of parameter \p{length}. Deduced by the compiler.
388 /// (Must be integral.)
389 /// @param length The capacity of the requested array.
390 /// @param args Variadic parameters to be forwarded to the constructor of each array element
391 /// of type \p{T}.
392 /// @return A pointer to the first element of the allocated array.
393 template<typename T,typename TSize, typename... TArgs>
394 T* NewArray(TSize length, TArgs&& ... args )
395 {
397 T* mem= AllocArray<T, TSize>( length );
398 for( TSize i= 0 ; i < length ; ++i )
399 new (mem + i) T(std::forward<TArgs>( args )...);
401 return mem;
402 }
403
404 /// Calls the destructor of the given \p{object} of type \p{T} and then frees the memory
405 /// with the associated allocator.
406 /// \attention
407 /// In the context of single inheritance, this convenience function supports deleting pointers
408 /// to objects of base types, also when they were previously allocated using a derived type,
409 /// provided that virtual destructors are in place. Virtual destructors ensure that the
410 /// appropriate destructor is called, preventing resource leaks.
411 ///
412 /// \attention
413 /// However, in cases of multiple inheritance, passing pointers to base types for deletion
414 /// might lead to undefined behavior. The underlying challenge here is that safely converting
415 /// a base type pointer back to the originally allocated derived type pointer (as required
416 /// for correct memory deallocation) is not feasible with standard C++ mechanisms.
417 /// While the C++ `delete` operator is equipped to handle such scenarios - thanks to internal
418 /// compiler implementations that track the original pointer - standard C++ does not expose
419 /// a portable way to replicate this functionality.
420 /// Consequently, objects utilizing multiple inheritance have to be deleted using the same
421 /// derived type pointer that was used for allocation.
422 ///
423 /// @tparam T The type that parameter \p{object} points to.
424 /// @param object The object to delete.
425 template<typename T>
426 inline void Delete(T* object)
427 {
428 object->~T();
429 allocator.free(object, sizeof(*object));
430 }
431
432 /// Destructs all array elements and frees the array's memory.
433 /// @tparam T The pointer type of parameter \p{array}.
434 /// @tparam TIntegral Integral type of parameter \p{size}. Deduced by the compiler.
435 /// @param array Pointer to the first array element.
436 /// @param length The size of the given \p{mem}.
437 template<typename T, typename TIntegral>
438 inline
439 void DeleteArray(T* array, TIntegral length)
440 {
442 for( TIntegral i= 0 ; i < length ; ++i )
443 (array + i)->~T();
444 allocator.free(array, sizeof(T[1]) * size_t(length) );
446 }
447
448
449 /// Frees memory of size <c>sizeof(T)</c> pointed to by \p{mem}.
450 /// This method does \b not call a destructor. To dispose custom types with due destruction,
451 /// use method #Delete<T>(T*).
452 ///
453 /// @tparam T The pointer type of the given \p{mem} to free.
454 /// @param mem The memory to free.
455 template<typename T>
456 inline
457 void Free(T* mem)
458 {
459 allocator.free(static_cast<void*>(const_cast<ATMP_RC(T)*>(mem)), sizeof(T) );
460 }
461
462 /// Frees memory of given \p{size} pointed to by \p{mem}.
463 /// This method does \b not call a destructor. To dispose custom types with due destruction,
464 /// use method #Delete<T>(T*).
465 ///
466 /// @tparam T The pointer type of the given \p{mem} to free.
467 /// @tparam TIntegral The type that parameter \p{size} is provided with.
468 /// Deduced by the compiler. (Has to be integral.)
469 /// @param mem The memory to free.
470 /// @param size The size of the given \p{mem}.
471 template<typename T, typename TIntegral>
472 inline
473 void Free(T* mem, TIntegral size)
474 {
475 allocator.free(static_cast<void*>(const_cast<ATMP_RC(T)*>(mem)), size_t(size) );
476 }
477
478 /// Frees memory of an array of objects.
479 /// This method does \b not call a destructor. To also destruct the elements of an array,
480 /// use method #DeleteArray<T>(T*, TIntegral).
481 /// @tparam T The pointer type of parameter \p{array}.
482 /// @tparam TIntegral Integral type of parameter \p{size}. Deduced by the compiler.
483 /// @param array Pointer to the first array element.
484 /// @param length The size of the given \p{mem}.
485 template<typename T, typename TIntegral>
486 inline
487 void FreeArray(T* array, TIntegral length)
488 {
489 allocator.free( static_cast<void*>(const_cast<ATMP_RC(T)*>(array)),
490 sizeof(T[1]) * size_t(length) );
491 }
492
493}; // struct AllocatorInterface
494
495// =================================================================================================
496/// Implementation of (prototype-) class \alib{lang;Allocator} which performs standard heap
497/// allocation by using <c>std::malloc</c>, <c>std::realloc</c>, and <c>std::free</c>
498///
499/// This class may be passed as the template parameter \p{TAllocator} with \alib- or custom types
500/// that expect an allocator.
501/// For example, the type definition \ref alib::AString uses this type and thus implements a common
502/// heap-allocated string buffer.
503///
504/// In contrast to other allocator types, this type is stateless and default-constructible, and
505/// temporary instances can be used and disposed of right away with no effort.
506/// Therefore, all types across \alib that are templated over an allocator type, provide two
507/// versions of each constructor, one that expects an allocator and one that does not expect an
508/// external instance. If this type \b %HeapAllocator is used, the constructors that do not
509/// expect an allocator become effective.
510///
511/// @see
512/// - Struct \alib{lang;AllocatorMember}, which should be used as a base class to inherit from
513/// if an arbitrary allocator is to be stored. A specialization for this \b %HeapAllocator
514/// is given, which does not contain a member and hence avoids increasing the footprint
515/// of derived types.
516/// - Types \alib{monomem;TMonoAllocator}, \alib{monomem;TLocalAllocator}, and
517/// \alib{monomem;TPoolAllocator} introduced with module \alib_monomem.
518// =================================================================================================
520{
521 /// A magic byte, used with compiler-symbol \ref ALIB_DEBUG_ALLOCATIONS to mark
522 /// memory and detect out-of-bounds writes.
523 /// @see Method \alib{lang;Allocator::dbgCheckMemory}.
524 static constexpr unsigned char MAGIC= 0xA1;
525
526 /// A magic byte written when memory is freed.
527 /// @see Field #CLEAR.
528 static constexpr unsigned char CLEAR= 0xF1;
529
530 /// Evaluates to <c>alignof(std::max_align_t)</c>.
531 /// @see Field \alib{lang;Allocator::MIN_ALIGNMENT}.
532 static constexpr size_t MIN_ALIGNMENT = alignof(std::max_align_t);
533
534 /// Evaluates to <c>alignof(std::max_align_t)</c>.
535 /// @see Field \alib{lang;Allocator::MAX_ALIGNMENT}.
536 static constexpr size_t MAX_ALIGNMENT = alignof(std::max_align_t);
537
538 /// The type of the allocator that this allocator uses underneath.
539 /// In this case, no chaining is available, hence this evaluates to <c>void</c>.
540 using ChainedAllocator = void;
541
542 /// Allocate memory using <c>std::malloc</c>.
543 /// @param size The size of memory the block to allocate in bytes. With this allocator
544 /// this is not an input/output parameter.
545 /// @param alignment This type ignores the alignment parameter, because <c>std::malloc</c>
546 /// always uses <c>alignof(std::max_align_t)</c>.
547 /// @return Pointer to the allocated memory block.
548 inline void* allocate( size_t size, size_t alignment ) const
549 {
550 ALIB_ASSERT_ERROR( alignment <= alignof(std::max_align_t), "ALIB",
551 "The HeapAllocator is not designed to provide alignments greater "
552 "than alignof(std::max_align_t). ")
553 (void) alignment;
554
555 void* mem= std::malloc(lang::DbgAlloc::extSize(size));
556 DbgAlloc::annotate(mem, size, MAGIC);
557 return mem;
558 }
559
560 /// Shrinks or grows a piece of memory.
561 /// If a new allocation was performed, the existing data is copied.
562 /// Note that unlike specified by the prototype, parameter \p{newSize} is not provided as a
563 /// reference. This allocator will not allocate bigger objects.
564 /// @param mem The memory to reallocate.
565 /// @param oldSize The current size of \p{mem}.
566 /// @param newSize The now required size of \p{mem} in bytes.
567 /// With this allocator this is not an input/output parameter.
568 /// @return Pointer to the re-allocated memory.
569 inline void* reallocate(void* mem, size_t oldSize, size_t newSize, size_t )
570 {
571 DbgAlloc::checkMem( mem, oldSize, MAGIC, "HeapAllocator" );
572 void* newMem= std::realloc(mem, lang::DbgAlloc::extSize(newSize));
573 DbgAlloc::annotate(newMem, newSize, MAGIC);
574 return newMem;
575 }
576
577 /// Frees memory by invoking <c>std::free</c>.
578 /// @param mem The memory to dispose.
579 /// @param size The size of the given \p{mem}.
580 inline void free(void* mem, size_t size) const
581 {
582 DbgAlloc::checkMem( mem, size, MAGIC, "HeapAllocator" );
583 DbgAlloc::clearMem(mem, size, CLEAR);
584 std::free(mem);
585 }
586
587 /// This is an empty implementation of the prototyped method.
588 /// It is empty because this allocator never returns a higher allocation size than requested.
589 /// \alib{lang;Allocator::dbgAcknowledgeIncreasedAllocSize}.
590 /// @tparam TSize The type of parameter \p{allocSize}. (Deduced by the compiler.)
591 template<typename TSize>
592 void dbgAcknowledgeIncreasedAllocSize( void*, TSize ) const {}
593
594 /// Returns a temporary object (which is usually optimized out together with a call to this
595 /// operator) providing high-level convenience methods for allocation.
596 /// @see Class \alib{lang::AllocatorInterface}
597 /// @return A temporary high-level interface into the allocator.
600
601 /// This is a constexpr static method that determines if a type allows splitting memory
602 /// and later passing the pieces back to free.<br>
603 /// @return \c false.
604 static constexpr bool allowsMemSplit() { return false; }
605
606 #if ALIB_DEBUG
607 /// With this allocator, the debug-name is \c constexpr "HeapAllocator".
608 static constexpr const char* DbgName = "HeapAllocator";
609 #endif
610
611 /// If the compiler symbol \ref ALIB_DEBUG_ALLOCATIONS is not set, this method is empty and will
612 /// be optimized out. Otherwise, this will raise an \alib assertion if the piece of allocated
613 /// memory is corrupted or its allocation size is not rightfully given by the using code.
614 /// @see Chapter \ref alib_contmono_further_debug of the Programmer's Manual.
615 ///
616 /// @tparam TSize The type of parameter \p{size}. (Deduced by the compiler.)
617 /// @param mem The address of the allocated object.
618 /// @param size The requested allocation size of the object.
619 template<typename TSize>
620 void dbgCheckMemory( void* mem, TSize size )
621 { DbgAlloc::checkMem( mem, size, MAGIC, "HeapAllocator" ); }
622
623}; // struct HeapAllocator
624
625
626//==================================================================================================
627/// This templated class is used to inherit an allocation member. The rationale for choosing
628/// inheritance instead of just having types defining a member for an allocator, lies in the
629/// C++ standard's concept of \https{Empty Base Optimization,en.cppreference.com/w/cpp/language/ebo}.
630///
631/// The class has a specialization with \ref lang::AllocatorMember<HeapAllocator>, which does
632/// not define a member and thus does not increase the footprint of a type that inherits it.
633/// With the standard implementation, a reference to the allocator specified with template
634/// parameter \p{TAllocator} is defined.
635///
636/// Consequently, this type is used to implement templated types that are allocation agnostic.
637/// Across \alib, a template parameter specifying an allocator is always named \p{TAllocator}.
638/// Types with this template parameter, in parallel inherit this type.
639/// A prominent example is the string buffer type of module \alib_strings, which usually is known
640/// through it's alias name \ref alib::AString, which performs classic heap allocation.
641/// Its alias type definition, is given as:
642/// \snippet "alib/strings/fwds.hpp" DOX_MONOMEM_ALLOCMEMBER
643/// Obviously the original type \b TString has two template parameters, one specifying the
644/// character type, the other specifying the allocator. Now looking at the
645/// \alib{strings;TAString;reference documentation of type TAString}, it can be seen that this type
646/// \b AllocatorMember is a protected base class and template parameter \p{TAllocator} is forwarded
647/// to this base.
648///
649/// \note As explained, this type is useful if allocation agnostic types are needed. This is true
650/// for types in this library. However, in many end-user cases, the allocation strategy will
651/// be fixed to a certain allocator, and therefore in this case, neither a templated approach,
652/// nor the helper-struct is needed.
653///
654/// @tparam TAllocator The allocator type of the inherited member, as prototyped with
655/// \alib{lang;Allocator}.
656//==================================================================================================
657template<typename TAllocator>
659{
660 protected:
661 TAllocator& allocator; ///< A reference to the allocator.
662
663 public:
664 /// Exposes the allocator type.
665 using AllocatorType = TAllocator;
666
667 /// Deleted default constructor. (The allocator has to be given with construction)
668 AllocatorMember() = delete;
669
670 /// Constructor.
671 /// @param pAllocator A reference to the allocator to store in member #allocator.
672 AllocatorMember( TAllocator& pAllocator ) noexcept
673 : allocator(pAllocator) {}
674
675 /// Returns the reference to the allocator.
676 /// @return The allocator given with construction.
677 TAllocator& GetAllocator() const noexcept { return allocator; }
678
679 /// This is a convenience operator that returns the \alib{lang;AllocatorInterface} for the
680 /// stored allocator (by calling \alib{lang;Allocator::operator()()}).
681 /// @return The allocator interface of the stored allocator.
682 AllocatorInterface<TAllocator> AI() const noexcept { return allocator(); }
683};
684
685/// Specialization of this helper-struct for type \alib{lang;HeapAllocator}. Does not define a
686/// member and thus does not increase the footprint of a type that inherits this specialization.
687template<>
689{
690 /// This is an empty instance of the empty heap allocation type..
691 /// It is used to receive a non-const reference with method #GetAllocator.
692 static constexpr HeapAllocator HEAP_ALLOCATOR_INSTANCE {};
693
694 /// Default Constructor.
695 AllocatorMember() = default;
696
697 /// Constructor.
698 /// @param heapAllocator This parameter is ignored, as always #HEAP_ALLOCATOR_INSTANCE is used.
699 AllocatorMember(const HeapAllocator& heapAllocator) noexcept { (void) heapAllocator; }
700
701 /// Static implementation of interface function. (Optimized out.)
702 /// @return A reference to the 'fake' object defined with# HEAP_ALLOCATOR_INSTANCE.
703 HeapAllocator& GetAllocator() const noexcept
704 { return const_cast<HeapAllocator&>(HEAP_ALLOCATOR_INSTANCE); }
705
706 /// This is a convenience operator which returns the \alib{lang;AllocatorInterface} for the
707 /// stored allocator (by calling \alib{lang;Allocator::operator()()}).
708 /// @return The allocator interface of the stored allocator.
709 AllocatorInterface<HeapAllocator> AI() const noexcept { return HEAP_ALLOCATOR_INSTANCE(); }
710};
711
712
713//==================================================================================================
714/// This static inline namespace function calls the destructor <b>~T()</b>of given \p{object}.
715/// The use of this method is recommended instead of calling the destructor directly,
716/// to increase readability of the code.
717///
718/// \attention
719/// Pointers have to be dereferenced when passed as arguments.
720/// Otherwise, this method does nothing, as the "destructor of a pointer" is called.<br>
721/// Because, for example, container types would pass a pointer here, in case their
722/// (custom) stored type is a pointer type, no static assertion can be made here.
723///
724/// @tparam T The object type. Deduced by the compiler and not need to be given.
725/// @param object The object to destruct.
726//==================================================================================================
727template<typename T>
729void Destruct(T& object) { object.~T(); }
730
731} // namespace alib[::lang]
732
733/// Type alias in namespace \b alib.
735
736} // namespace [alib]
737
738#endif // HPP_ALIB_LANG_ALLOCATION
739
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ALIB_FORCE_INLINE
Definition alib.hpp:650
#define ALIB_ERROR(...)
Definition alib.hpp:1267
#define ATMP_RC( T)
Definition tmp.hpp:31
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:760
Definition alib.cpp:69
@ Destruct
The main phase of termination that destructs everything.
TAllocator & allocator
The allocator type to use.
ALIB_FORCE_INLINE T * New(TArgs &&... args)
AllocatorInterface(TAllocator &pAllocator)
void FreeArray(T *array, TIntegral length)
void * Alloc(TSize size, TAlignment alignment)
void DeleteArray(T *array, TIntegral length)
T * AllocArray(TLength length)
T * NewArray(TSize length, TArgs &&... args)
void Free(T *mem, TIntegral size)
AllocatorMember()=default
Default Constructor.
AllocatorInterface< HeapAllocator > AI() const noexcept
HeapAllocator & GetAllocator() const noexcept
AllocatorMember(const HeapAllocator &heapAllocator) noexcept
TAllocator AllocatorType
Exposes the allocator type.
AllocatorInterface< TAllocator > AI() const noexcept
AllocatorMember()=delete
Deleted default constructor. (The allocator has to be given with construction)
AllocatorMember(TAllocator &pAllocator) noexcept
TAllocator & GetAllocator() const noexcept
TAllocator & allocator
A reference to the allocator.
void dbgCheckMemory(void *mem, TSize size) const
AllocatorInterface< Allocator > operator()()
void dbgAcknowledgeIncreasedAllocSize(void *mem, TSize allocSize) const
static constexpr size_t MIN_ALIGNMENT
TAllocator ChainedAllocator
void * reallocate(void *mem, size_t oldSize, size_t &newSize, size_t alignment)
static constexpr bool allowsMemSplit() noexcept
void free(void *mem, size_t size)
static constexpr size_t MAX_ALIGNMENT
void * allocate(size_t &size, size_t alignment)
static void checkMem(void *mem, const TSize size, unsigned char magic, const char *name)
static constexpr void clearMem(T *mem, size_t size, unsigned char magic)
static constexpr void annotate(T *mem, size_t size, unsigned char magic)
static constexpr size_t extSize(TIntegral size)
void * allocate(size_t size, size_t alignment) const
void * reallocate(void *mem, size_t oldSize, size_t newSize, size_t)
AllocatorInterface< HeapAllocator > operator()() const noexcept
static constexpr bool allowsMemSplit()
void free(void *mem, size_t size) const
void dbgAcknowledgeIncreasedAllocSize(void *, TSize) const
void dbgCheckMemory(void *mem, TSize size)