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