22 template<
typename TIntegral>
23 static constexpr size_t extSize (TIntegral size) {
24 #if !ALIB_DEBUG_ALLOCATIONS
27 return size_t(size) + 4 +
sizeof(size_t);
38 static constexpr void annotate(T* mem,
size_t size,
unsigned char magic) {
39 #if ALIB_DEBUG_ALLOCATIONS
40 auto* cMem=
reinterpret_cast<unsigned char*
>(mem);
42 for( ; idx< size + 4; ++idx)
44 for(
size_t i= 0; i<
sizeof(size_t); ++i) {
45 cMem[idx++]=
static_cast<unsigned char>( size & 0xFF );
49 (void) mem; (void) size; (void) magic;
60 static constexpr void clearMem(T* mem,
size_t size,
unsigned char magic) {
61 #if ALIB_DEBUG_ALLOCATIONS
62 memset(
reinterpret_cast<char*
>(mem), magic,
extSize(size) );
64 (void) mem; (void) size; (void) magic;
78 template<
typename TSize>
80 void checkMem(
void* mem,
const TSize size,
unsigned char magic,
const char* name ) {
81 #if ALIB_DEBUG_ALLOCATIONS
82 auto* cMem=
reinterpret_cast<unsigned char*
>(mem);
84 while ( idx< size + 4)
85 if( cMem[idx++] != magic )
86 ALIB_ERROR(
"MONOMEM",
"Corrupt memory with allocator ", name )
93 storedSize|= cMem[--idx];
95 while( idx > size + 4);
97 if( storedSize != size )
98 ALIB_ERROR(
"MONOMEM",
"Given size does not match the allocated size "
99 "(or corrupt memory). Allocator: ", name )
101 (void) mem; (void) size; (void) magic; (void) name;
180 void*
reallocate(
void* mem,
size_t oldSize,
size_t& newSize,
size_t alignment );
186 void free(
void* mem,
size_t size);
238 template<typename TSize>
249 template<typename TSize>
304template<
typename TAllocator>
323 template<
typename TSize,
typename TAlignment>
324 void*
Alloc( TSize size, TAlignment alignment)
326 size_t s= size_t(size);
327 return allocator.allocate( s,
size_t(alignment) );
336 auto size=
sizeof(T);
337 return reinterpret_cast<T*
>(
allocator.allocate(size,
alignof(T) ) );
347 template<
typename T,
typename TLength>
350 auto size=
sizeof(T[1]) *
size_t(length);
351 return reinterpret_cast<T*
>(
allocator.allocate( size,
alignof(T[]) ) );
360 template<
typename T,
typename... TArgs>
361 T*
New( TArgs&& ... args )
362 {
return new (
Alloc<T>()) T( std::forward<TArgs>( args )... ); }
375 template<
typename T,
typename TSize,
typename... TArgs>
378 for( TSize i= 0 ; i < length ; ++i )
379 new (mem + i) T(std::forward<TArgs>( args )...);
405 inline void Delete(T*
object) {
object->~T();
allocator.free(
object,
sizeof(*
object)); }
412 template<
typename T,
typename TIntegral>
415 for( TIntegral i= 0 ; i < length ; ++i )
417 allocator.free(array,
sizeof(T[1]) *
size_t(length) );
429 {
allocator.free(
static_cast<void*
>(
const_cast<std::remove_const_t<T>*
>(mem)),
sizeof(T) ); }
440 template<
typename T,
typename TIntegral>
441 void Free(T* mem, TIntegral size)
442 {
allocator.free(
static_cast<void*
>(
const_cast<std::remove_const_t<T>*
>(mem)),
size_t(size) ); }
451 template<
typename T,
typename TIntegral>
455 allocator.free(
static_cast<void*
>(
const_cast<std::remove_const_t<T>*
>(array)),
456 sizeof(T[1]) *
size_t(length) );
470 requires(T obj,
size_t& size,
size_t alignment,
size_t oldSize,
void* mem) {
471 typename T::ChainedAllocator;
472 { T::MIN_ALIGNMENT } -> std::convertible_to<size_t>;
473 { T::MAX_ALIGNMENT } -> std::convertible_to<size_t>;
474 { obj.allocate (size, alignment) } -> std::same_as<void*>;
475 { obj.reallocate( mem, oldSize, size, alignment ) } -> std::same_as<void*>;
476 { obj.free (mem, size) } -> std::same_as<void>;
477 { obj.operator()() } -> std::same_as<AllocatorInterface<T>>;
478 { obj.allowsMemSplit() } -> std::convertible_to<bool>;
481 { obj.DbgName } -> std::convertible_to<const char*>;
482 { obj.dbgAcknowledgeIncreasedAllocSize(mem, size) } -> std::same_as<void>;
483 { obj.dbgCheckMemory(mem, size) } -> std::same_as<void>;
518 static constexpr unsigned char MAGIC= 0xA1;
522 static constexpr unsigned char CLEAR= 0xF1;
542 inline void*
allocate(
size_t size,
size_t alignment )
const {
544 "The HeapAllocator is not designed to provide alignments greater "
545 "than alignof(std::max_align_t): {} > {}. ", alignment,
alignof(std::max_align_t) )
561 inline void*
reallocate(
void* mem,
size_t oldSize,
size_t newSize,
size_t ) {
571 inline void free(
void* mem,
size_t size)
const {
581 template<
typename TSize>
598 static constexpr const char*
DbgName =
"HeapAllocator";
609 template<
typename TSize>
647template<
typename TAllocator>
660 template<
typename TIf= TAllocator>
661 requires std::is_default_constructible_v<TIf>
757template<
typename T,
typename TAllocator>
789 template<typename TSibling>
798 template<
typename TSibling>
812 [[nodiscard]] constexpr
815 #if defined(__cpp_lib_allocate_at_least) || DOXYGEN
821 [[nodiscard]]
constexpr
822 std::allocation_result<T*, std::size_t>
824 std::allocation_result<T*, std::size_t> result;
825 result.count= n *
sizeof(T);
827 result.count/=
sizeof(T);
848template<
typename TLhs,
typename TRhs,
typename TAllocator >
851 return &lhs.GetAllocator() == &rhs.GetAllocator();
883template<
typename TAllocator>
955 void*
Get(
size_t size,
size_t alignment,
const type_info& dbgTypeInfo);
957 void*
Get(
size_t size,
size_t alignment
ALIB_DBG(,
const std::type_info& dbgTypeInfo) ) {
966 ALIB_MESSAGE(
"RTTRA",
"Object type detected : ", &dbgTypeInfo )
968 "Struct RTTRAllocator cannot be used to recycle types with an alignment "
969 "smaller than {}. Requested: {}",
alignof(
Node), alignment )
972 if( (size == detectedObjectSize) && (detectedObjectAlignment== alignment) ) {
974 #if ALIB_DEBUG_MEMORY
975 ALIB_MESSAGE(
"RTTRA",
"Recycling object. Type: ", &dbgTypeInfo )
977 return reinterpret_cast<char*
>( stack.
popFront() );
981 if(dbgWarnDifferentObjectTypeAlloc) {
983 "A different object was requested for allocation!\n"
984 " Previous type : <{}>\n"
985 " Requested type: <{}>\n"
986 "Note: This allocator may not be efficient when used.\n"
987 " If this is a use case using a 'std' library container, this message indicates\n"
988 " that a RTTRAllocator was shared between different container instantiations.\n"
989 " If this is not the case, than an 'unusual' implementation of such C++ library may\n"
990 " prevent this concept from working. See ALib manual for further information.",
991 dbgDetectedObjectTypeInfo, &dbgTypeInfo )
994 dbgWarnDifferentObjectTypeAlloc=
false;
996 ALIB_MESSAGE(
"RTTRA",
"Allocating a different object type \"{}\"\n"
997 " Note: This object cannot be recycled.", &dbgTypeInfo )
998 return allocBase::AI().Alloc( size, alignment );
1002 #if ALIB_DEBUG_MEMORY
1003 ALIB_MESSAGE(
"RTTRA",
"Allocating object. Type: \"{}\"", &dbgTypeInfo )
1006 return allocBase::AI().Alloc( size, alignment );
1025 ALIB_MESSAGE(
"RTTRA",
"Allocating other. Type: <{}>", &dbgTypeInfo )
1051 void Recycle(
void* mem,
size_t size,
size_t alignment,
const type_info& dbgTypeInfo );
1053 void Recycle(
void* mem,
size_t size,
size_t alignment
1054 ALIB_DBG(,
const std::type_info& dbgTypeInfo) ) {
1058 stack.pushFront(
reinterpret_cast<Node*
>( mem ) );
1059 #if ALIB_DEBUG_MEMORY
1060 ALIB_MESSAGE(
"RTTRA",
"Stacking object. Type: ", &dbgTypeInfo )
1063 allocBase::GetAllocator().free(mem, size);
1065 if( detectedObjectSize == 0 ) {
1066 if( dbgWarnDeallocationPriorToAllocation) {
1068 "Deallocation before a first object allocation needed to detect recyclable type!\n"
1069 " De-allocated object type: <{}>\n"
1070 "Note: This allocator may not be efficient when used.\n"
1071 " If this is a use case using a 'std' library container, this message indicates\n"
1072 " an 'unusual' implementation of such C++ standard library."
1075 dbgWarnDeallocationPriorToAllocation=
false;
1077 if( dbgWarnDifferentObjectTypeDealloc ) {
1079 "A different object for was requested for de-allocoation!\n"
1080 " Previous type : <{}>\n"
1081 " Requested type: <{}>\n"
1082 "Note: This allocator may not be efficient when used.\n"
1083 " If this is a use case using a 'std' library container, this message indicates\n"
1084 " that a RTTRAllocator was shared between different container instantiations.\n"
1085 " If this is not the case, than an 'unusual' implementation of such C++ library may\n"
1086 " prevent this concept from working. See ALib manual for further information"
1087 , dbgDetectedObjectTypeInfo, &dbgTypeInfo )
1088 dbgWarnDifferentObjectTypeDealloc=
false;
1113 ALIB_DBG(,
const std::type_info& dbgTypeInfo) ) {
1116 if( !TAllocator::allowsMemSplit() ) {
1123 if( detectedObjectSize == 0) {
1125 if( dbgWarnRecycleChunkPriorToAllocation ) {
1127 "Deallocation before a first object allocation needed to detect recyclable type!\n"
1128 " De-allocated object type: <{}>.\n"
1129 "Note: If this recycler is used with a 'std' library container, this either\n"
1130 " indicates an 'unusual' implementation of such C++ standard library,\n"
1131 " or a manual shrink of the capacity without any prior object insertion.\n",
1133 dbgWarnRecycleChunkPriorToAllocation = false ;
1141 char* mem =
reinterpret_cast<char*
>( (size_t(memUnaligned) + detectedObjectAlignment - 1) & ~(detectedObjectAlignment -1) );
1142 size-= size_t(mem -
reinterpret_cast<char*
>(memUnaligned));
1145 ALIB_DBG(
size_t cntStackedObjects= 0; )
1146 while(size > detectedObjectSize) {
1147 stack.
pushFront(
reinterpret_cast<Node*
>( mem ) );
1148 mem =
reinterpret_cast<char*
>(mem) + detectedObjectSize;
1149 size -= detectedObjectSize;
1154 if( cntStackedObjects > 0 ) {
1156 "De-allocated chunk's size is smaller than detected object size.\n"
1157 " Deallocated object: Type: <{}>\n"
1159 " Detected object: Type: <{}>\n"
1160 " Size: {} bytes, alignment: {}\n"
1161 "Note: If this recycler is used with a <std::unordered_map> or <std::unordered_set>,\n"
1162 " this message may be eliminated by reserving a reasonable initial bucket size.",
1163 &dbgTypeInfo, origSize, dbgDetectedObjectTypeInfo,
1164 detectedObjectSize, detectedObjectAlignment )
1168 #if ALIB_DEBUG_MEMORY
1170 "Stacking {} objects from de-allocated memory of size {} (lost {} bytes).\n"
1171 "Deallocated type: {}", cntStackedObjects, origSize,
1172 origSize - cntStackedObjects * detectedObjectSize, &dbgTypeInfo )
1201template<
typename T,
typename TAllocator>
1233 template<typename TSibling>
1249 template<
typename U >
1251 {
return recycler == rhs.recycler; }
1257 template<
typename U >
1259 {
return recycler != rhs.recycler; }
1274 return reinterpret_cast<T*
>(
recycler.Get(
sizeof(T),
1278 return reinterpret_cast<T*
>(
recycler.AllocUnrelated(
sizeof(T) * n,
1292 if( n == 1 )
recycler.Recycle( p,
sizeof(T) ,
alignof(T)
ALIB_DBG(,
typeid(T) ) );
#define ALIB_MESSAGE(domain,...)
#define ALIB_WARNINGS_RESTORE
#define ALIB_WARNING(domain,...)
#define ALIB_ERROR(domain,...)
#define ALIB_WARNINGS_IGNORE_DOCS
#define ALIB_ASSERT_ERROR(cond, domain,...)
#define ALIB_DEBUG_MEMORY
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
HeapAllocator & GetAllocator() const noexcept
AllocatorInterface< HeapAllocator > AI() const noexcept
AllocatorMember()=default
Default Constructor.
AllocatorMember(const HeapAllocator &heapAllocator) noexcept
TAllocator * allocator
The allocator stored.
AllocatorInterface< TAllocator > AI() const noexcept
TAllocator & GetAllocator() const noexcept
AllocatorMember(TAllocator &pAllocator) noexcept
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".
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
size_t detectedObjectAlignment
The required object alignment. Will be detected with the first invocation of Get.
bool dbgWarnDifferentObjectTypeDealloc
const std::type_info * dbgDetectedObjectTypeInfo
AllocatorMember< TAllocator > allocBase
The type of the base class that stores the allocator.
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)
AllocatorMember< TAllocator > allocBase
The type of the base class that stores the allocator.
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.
std::ptrdiff_t difference_type
Type definition as required by C++ library standards.
void deallocate(T *p, std::size_t n)
ptrdiff_t difference_type
Type definition as required by C++ library standards.
TAllocator AllocatorType
Exposes template parameter TAllocator.
const T & const_reference
Type definition as required by C++ library standards.
T value_type
Type definition as required by C++ library standards.
size_t size_type
Type definition as required by C++ library standards.
T & reference
Type definition as required by C++ library standards.
constexpr StdRecyclingAllocator(RTTRAllocator< TAllocator > &pRecycler)
bool operator!=(const StdRecyclingAllocator< U, TAllocator > &rhs) const noexcept
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.
std::false_type is_always_equal
Type definition as required by C++ library standards.
constexpr StdRecyclingAllocator(StdRecyclingAllocator &&) noexcept=default
Defaulted move constructor.