21 template<
typename TIntegral>
22 static constexpr size_t extSize (TIntegral size) {
23 #if !ALIB_DEBUG_ALLOCATIONS
26 return size_t(size) + 4 +
sizeof(size_t);
37 static constexpr void annotate(T* mem,
size_t size,
unsigned char magic) {
38 #if ALIB_DEBUG_ALLOCATIONS
39 auto* cMem=
reinterpret_cast<unsigned char*
>(mem);
41 for( ; idx< size + 4; ++idx)
43 for(
size_t i= 0; i<
sizeof(size_t); ++i) {
44 cMem[idx++]=
static_cast<unsigned char>( size & 0xFF );
48 (void) mem; (void) size; (void) magic;
59 static constexpr void clearMem(T* mem,
size_t size,
unsigned char magic) {
60 #if ALIB_DEBUG_ALLOCATIONS
61 memset(
reinterpret_cast<char*
>(mem), magic,
extSize(size) );
63 (void) mem; (void) size; (void) magic;
77 template<
typename TSize>
79 void checkMem(
void* mem,
const TSize size,
unsigned char magic,
const char* name ) {
80 #if ALIB_DEBUG_ALLOCATIONS
81 auto* cMem=
static_cast<unsigned char*
>(mem);
83 while ( idx< size + 4)
84 if( cMem[idx++] != magic )
85 ALIB_ERROR(
"MONOMEM",
"Corrupt memory with allocator ", name )
92 storedSize|= cMem[--idx];
94 while( idx > size + 4);
96 if( storedSize != size )
97 ALIB_ERROR(
"MONOMEM",
"Given size does not match the allocated size "
98 "(or corrupt memory). Allocator: ", name )
100 (void) mem; (void) size; (void) magic; (void) name;
179 void*
reallocate(
void* mem,
size_t oldSize,
size_t& newSize,
size_t alignment );
185 void free(
void* mem,
size_t size);
237 template<typename TSize>
248 template<typename TSize>
303template<
typename TAllocator>
321 template<
typename TSize,
typename TAlignment>
322 void*
Alloc( TSize size, TAlignment alignment)
324 size_t s= size_t(size);
325 return allocator.allocate( s,
size_t(alignment) );
334 auto size=
sizeof(T);
335 return static_cast<T*
>(
allocator.allocate(size,
alignof(T) ) );
345 template<
typename T,
typename TLength>
348 auto size=
sizeof(T[1]) *
size_t(length);
349 return static_cast<T*
>(
allocator.allocate( size,
alignof(T[]) ) );
358 template<
typename T,
typename... TArgs>
359 T*
New( TArgs&& ... args )
360 {
return new (
Alloc<T>()) T( std::forward<TArgs>( args )... ); }
373 template<
typename T,
typename TSize,
typename... TArgs>
376 for( TSize i= 0 ; i < length ; ++i )
377 new (mem + i) T(std::forward<TArgs>( args )...);
403 inline void Delete(T*
object) {
object->~T();
allocator.free(
object,
sizeof(*
object)); }
410 template<
typename T,
typename TIntegral>
413 for( TIntegral i= 0 ; i < length ; ++i )
415 allocator.free(array,
sizeof(T[1]) *
size_t(length) );
427 {
allocator.free(
static_cast<void*
>(
const_cast<std::remove_const_t<T>*
>(mem)),
sizeof(T) ); }
438 template<
typename T,
typename TIntegral>
439 void Free(T* mem, TIntegral size)
440 {
allocator.free(
static_cast<void*
>(
const_cast<std::remove_const_t<T>*
>(mem)),
size_t(size) ); }
449 template<
typename T,
typename TIntegral>
453 allocator.free(
static_cast<void*
>(
const_cast<std::remove_const_t<T>*
>(array)),
454 sizeof(T[1]) *
size_t(length) );
468 requires(T obj,
size_t& size,
size_t alignment,
size_t oldSize,
void* mem) {
469 typename T::ChainedAllocator;
470 { T::MIN_ALIGNMENT } -> std::convertible_to<size_t>;
471 { T::MAX_ALIGNMENT } -> std::convertible_to<size_t>;
472 { obj.allocate (size, alignment) } -> std::same_as<void*>;
473 { obj.reallocate( mem, oldSize, size, alignment ) } -> std::same_as<void*>;
474 { obj.free (mem, size) } -> std::same_as<void>;
475 { obj.operator()() } -> std::same_as<AllocatorInterface<T>>;
476 { obj.allowsMemSplit() } -> std::convertible_to<bool>;
479 { obj.DbgName } -> std::convertible_to<const char*>;
480 { obj.dbgAcknowledgeIncreasedAllocSize(mem, size) } -> std::same_as<void>;
481 { obj.dbgCheckMemory(mem, size) } -> std::same_as<void>;
515 static constexpr unsigned char MAGIC= 0xA1;
519 static constexpr unsigned char CLEAR= 0xF1;
539 inline void*
allocate(
size_t size,
size_t alignment )
const {
541 "The HeapAllocator is not designed to provide alignments greater "
542 "than alignof(std::max_align_t): {} > {}. ", alignment,
alignof(std::max_align_t) )
558 inline void*
reallocate(
void* mem,
size_t oldSize,
size_t newSize,
size_t ) {
568 inline void free(
void* mem,
size_t size)
const {
578 template<
typename TSize>
595 static constexpr const char*
DbgName =
"HeapAllocator";
606 template<
typename TSize>
644template<
typename TAllocator>
656 template<
typename TIf= TAllocator>
657 requires std::is_default_constructible_v<TIf>
753template<
typename T,
typename TAllocator>
784 template<typename TSibling>
793 template<
typename TSibling>
807 [[nodiscard]] constexpr
810 #if defined(__cpp_lib_allocate_at_least) || DOXYGEN
816 [[nodiscard]]
constexpr
817 std::allocation_result<T*, std::size_t>
819 std::allocation_result<T*, std::size_t> result;
820 result.count= n *
sizeof(T);
822 result.count/=
sizeof(T);
843template<
typename TLhs,
typename TRhs,
typename TAllocator >
846 return &lhs.GetAllocator() == &rhs.GetAllocator();
878template<
typename TAllocator>
949 void*
Get(
size_t size,
size_t alignment,
const type_info& dbgTypeInfo);
951 void*
Get(
size_t size,
size_t alignment
ALIB_DBG(,
const std::type_info& dbgTypeInfo) ) {
960 ALIB_MESSAGE(
"RTTRA",
"Object type detected : ", &dbgTypeInfo )
962 "Struct RTTRAllocator cannot be used to recycle types with an alignment "
963 "smaller than {}. Requested: {}",
alignof(
Node), alignment )
966 if( (size == detectedObjectSize) && (detectedObjectAlignment== alignment) ) {
968 #if ALIB_DEBUG_MEMORY
969 ALIB_MESSAGE(
"RTTRA",
"Recycling object. Type: ", &dbgTypeInfo )
971 return reinterpret_cast<char*
>( stack.
popFront() );
975 if(dbgWarnDifferentObjectTypeAlloc) {
977 "A different object was requested for allocation!\n"
978 " Previous type : <{}>\n"
979 " Requested type: <{}>\n"
980 "Note: This allocator may not be efficient when used.\n"
981 " If this is a use case using a 'std' library container, this message indicates\n"
982 " that a RTTRAllocator was shared between different container instantiations.\n"
983 " If this is not the case, than an 'unusual' implementation of such C++ library may\n"
984 " prevent this concept from working. See ALib manual for further information.",
985 dbgDetectedObjectTypeInfo, &dbgTypeInfo )
988 dbgWarnDifferentObjectTypeAlloc=
false;
990 ALIB_MESSAGE(
"RTTRA",
"Allocating a different object type \"{}\"\n"
991 " Note: This object cannot be recycled.", &dbgTypeInfo )
992 return allocBase::AIF().Alloc( size, alignment );
996 #if ALIB_DEBUG_MEMORY
997 ALIB_MESSAGE(
"RTTRA",
"Allocating object. Type: \"{}\"", &dbgTypeInfo )
1000 return allocBase::AIF().Alloc( size, alignment );
1019 ALIB_MESSAGE(
"RTTRA",
"Allocating other. Type: <{}>", &dbgTypeInfo )
1045 void Recycle(
void* mem,
size_t size,
size_t alignment,
const type_info& dbgTypeInfo );
1047 void Recycle(
void* mem,
size_t size,
size_t alignment
1048 ALIB_DBG(,
const std::type_info& dbgTypeInfo) ) {
1052 stack.pushFront(
static_cast<Node*
>( mem ) );
1053 #if ALIB_DEBUG_MEMORY
1054 ALIB_MESSAGE(
"RTTRA",
"Stacking object. Type: ", &dbgTypeInfo )
1057 allocBase::GetAllocator().free(mem, size);
1059 if( detectedObjectSize == 0 ) {
1060 if( dbgWarnDeallocationPriorToAllocation) {
1062 "Deallocation before a first object allocation needed to detect recyclable type!\n"
1063 " De-allocated object type: <{}>\n"
1064 "Note: This allocator may not be efficient when used.\n"
1065 " If this is a use case using a 'std' library container, this message indicates\n"
1066 " an 'unusual' implementation of such C++ standard library."
1069 dbgWarnDeallocationPriorToAllocation=
false;
1071 if( dbgWarnDifferentObjectTypeDealloc ) {
1073 "A different object for was requested for de-allocoation!\n"
1074 " Previous type : <{}>\n"
1075 " Requested type: <{}>\n"
1076 "Note: This allocator may not be efficient when used.\n"
1077 " If this is a use case using a 'std' library container, this message indicates\n"
1078 " that a RTTRAllocator was shared between different container instantiations.\n"
1079 " If this is not the case, than an 'unusual' implementation of such C++ library may\n"
1080 " prevent this concept from working. See ALib manual for further information"
1081 , dbgDetectedObjectTypeInfo, &dbgTypeInfo )
1082 dbgWarnDifferentObjectTypeDealloc=
false;
1107 ALIB_DBG(,
const std::type_info& dbgTypeInfo) ) {
1110 if( !TAllocator::allowsMemSplit() ) {
1117 if( detectedObjectSize == 0) {
1119 if( dbgWarnRecycleChunkPriorToAllocation ) {
1121 "Deallocation before a first object allocation needed to detect recyclable type!\n"
1122 " De-allocated object type: <{}>.\n"
1123 "Note: If this recycler is used with a 'std' library container, this either\n"
1124 " indicates an 'unusual' implementation of such C++ standard library,\n"
1125 " or a manual shrink of the capacity without any prior object insertion.\n",
1127 dbgWarnRecycleChunkPriorToAllocation = false ;
1135 char* mem =
reinterpret_cast<char*
>( (size_t(memUnaligned) + detectedObjectAlignment - 1)
1136 & ~(detectedObjectAlignment -1) );
1137 size-= size_t(mem -
reinterpret_cast<char*
>(memUnaligned));
1140 ALIB_DBG(
size_t cntStackedObjects= 0; )
1141 while(size > detectedObjectSize) {
1142 stack.
pushFront(
reinterpret_cast<Node*
>( mem ) );
1143 mem =
static_cast<char*
>(mem) + detectedObjectSize;
1144 size -= detectedObjectSize;
1149 if( cntStackedObjects > 0 ) {
1151 "De-allocated chunk's size is smaller than detected object size.\n"
1152 " Deallocated object: Type: <{}>\n"
1154 " Detected object: Type: <{}>\n"
1155 " Size: {} bytes, alignment: {}\n"
1156 "Note: If this recycler is used with a <std::unordered_map> or <std::unordered_set>,\n"
1157 " this message may be eliminated by reserving a reasonable initial bucket size.",
1158 &dbgTypeInfo, origSize, dbgDetectedObjectTypeInfo,
1159 detectedObjectSize, detectedObjectAlignment )
1163 #if ALIB_DEBUG_MEMORY
1165 "Stacking {} objects from de-allocated memory of size {} (lost {} bytes).\n"
1166 "Deallocated type: {}", cntStackedObjects, origSize,
1167 origSize - cntStackedObjects * detectedObjectSize, &dbgTypeInfo )
1196template<
typename T,
typename TAllocator>
1227 template<typename TSibling>
1243 template<
typename U >
1245 {
return recycler == rhs.recycler; }
1251 template<
typename U >
1253 {
return recycler != rhs.recycler; }
1268 return static_cast<T*
>(
recycler.Get(
sizeof(T),
alignof(T)
1271 return static_cast<T*
>(
recycler.AllocUnrelated(
sizeof(T) * n,
alignof(T)
1284 if( n == 1 )
recycler.Recycle( p,
sizeof(T) ,
alignof(T)
ALIB_DBG(,
typeid(T) ) );
#define ALIB_MESSAGE(domain,...)
#define ALIB_DEBUG_MEMORY
#define ALIB_WARNING(domain,...)
#define ALIB_ERROR(domain,...)
#define ALIB_POP_ALLOWANCE
#define ALIB_ASSERT_ERROR(cond, domain,...)
constexpr bool operator==(const StdAllocator< TLhs, TAllocator > &lhs, const StdAllocator< TRhs, TAllocator > &rhs) noexcept
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
AllocatorInterface< HeapAllocator > AIF() const noexcept
HeapAllocator & GetAllocator() const noexcept
AllocatorMember()=default
Default Constructor.
AllocatorMember(const HeapAllocator &heapAllocator) noexcept
TAllocator * allocator
The allocator stored.
TAllocator & GetAllocator() const noexcept
AllocatorMember(TAllocator &pAllocator) noexcept
AllocatorInterface< TAllocator > AIF() const noexcept
TAllocator AllocatorType
Exposes the allocator type.
void dbgAcknowledgeIncreasedAllocSize(void *mem, TSize allocSize) const
TAllocator ChainedAllocator
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".
void * AllocUnrelated(size_t size, size_t alignment, const type_info &dbgTypeInfo)
bool dbgWarnDeallocationPriorToAllocation
void * Get(size_t size, size_t alignment, const type_info &dbgTypeInfo)
size_t detectedObjectSize
The object size of recyclables. Will be detected with the first invocation of #".Get".
void RecycleChunk(void *mem, size_t size, const type_info &dbgTypeInfo)
RTTRAllocator(TAllocator &pAllocator) noexcept
void Recycle(void *mem, size_t size, size_t alignment, const type_info &dbgTypeInfo)
SidiListHook< Node > stack
List of destructed objects available for recycling.
bool dbgWarnRecycleChunkPriorToAllocation
AllocatorMember< TAllocator > allocBase
The type of the base class that stores the allocator.
size_t detectedObjectAlignment
The required object alignment. Will be detected with the first invocation of #".Get".
bool dbgWarnDifferentObjectTypeDealloc
const std::type_info * dbgDetectedObjectTypeInfo
bool dbgWarnDifferentObjectTypeAlloc
void pushFront(TElement *elem) noexcept
TElement * popFront() noexcept
bool isEmpty() const noexcept
SidiNodeBase() noexcept=default
constexpr ~StdAllocator() noexcept=default
Parameterless destructor used with heap allocation.
constexpr T * allocate(size_t n)
std::false_type propagate_on_container_move_assignment
Type definition as required by C++ library standards.
constexpr void deallocate(T *p, std::size_t n)
TAllocator AllocatorType
Exposes template parameter TAllocator.
constexpr StdAllocator(StdAllocator &&) noexcept=default
Defaulted move constructor.
constexpr std::allocation_result< T *, std::size_t > allocate_at_least(std::size_t n)
constexpr StdAllocator(const StdAllocator &) noexcept=default
Defaulted copy constructor.
StdAllocator(const StdAllocator< TSibling, TAllocator > &origin)
constexpr StdAllocator() noexcept=default
Parameterless constructor used with heap allocation.
std::size_t size_type
Type definition as required by C++ library standards.
T value_type
Type definition as required by C++ library standards.
AllocatorMember< TAllocator > allocBase
The type of the base class that stores the allocator.
std::ptrdiff_t difference_type
Type definition as required by C++ library standards.
T & reference
Type definition as required by C++ library standards.
void deallocate(T *p, std::size_t n)
constexpr StdRecyclingAllocator(RTTRAllocator< TAllocator > &pRecycler)
TAllocator AllocatorType
Exposes template parameter TAllocator.
bool operator!=(const StdRecyclingAllocator< U, TAllocator > &rhs) const noexcept
const T & const_reference
Type definition as required by C++ library standards.
bool operator==(const StdRecyclingAllocator< U, TAllocator > &rhs) const noexcept
constexpr StdRecyclingAllocator(const StdRecyclingAllocator &) noexcept=default
Defaulted copy constructor.
RTTRAllocator< TAllocator > & recycler
The only member of this allocator type used to perform all duties.
ptrdiff_t difference_type
Type definition as required by C++ library standards.
std::false_type is_always_equal
Type definition as required by C++ library standards.
constexpr StdRecyclingAllocator(StdRecyclingAllocator &&) noexcept=default
Defaulted move constructor.
size_t size_type
Type definition as required by C++ library standards.
T value_type
Type definition as required by C++ library standards.