gencpp/project/Bloat.cpp

265 lines
6.4 KiB
C++

#define BLOAT_IMPL
#include "Bloat.hpp"
void* gen_Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
{
gen_Arena* arena = rcast(gen_Arena*, allocator_data);
void* ptr = NULL;
// unused( old_size );
switch ( type )
{
case EAllocation_ALLOC :
{
void* end = pointer_add( arena->PhysicalStart, arena->TotalUsed );
sw total_size = align_forward_i64( size, alignment );
// NOTE: Out of memory
if ( arena->TotalUsed + total_size > (sw) arena->TotalSize )
{
// zpl__printf_err("%s", "Arena out of memory\n");
return nullptr;
}
ptr = align_forward( end, alignment );
arena->TotalUsed += total_size;
if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO )
zero_size( ptr, size );
}
break;
case EAllocation_FREE :
// NOTE: Free all at once
// Use Temp_Arena_Memory if you want to free a block
break;
case EAllocation_FREE_ALL :
arena->TotalUsed = 0;
break;
case EAllocation_RESIZE :
{
// TODO : Check if ptr is on top of stack and just extend
AllocatorInfo a = arena->Backing;
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
}
break;
}
return ptr;
}
void* gen_Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
{
gen_Pool* pool = zpl_cast( gen_Pool* ) allocator_data;
void* ptr = NULL;
// unused( old_size );
switch ( type )
{
case EAllocation_ALLOC :
{
uptr next_free;
ZPL_ASSERT( size == pool->BlockSize );
ZPL_ASSERT( alignment == pool->BlockAlign );
ZPL_ASSERT( pool->FreeList != NULL );
next_free = *zpl_cast( uptr* ) pool->FreeList;
ptr = pool->FreeList;
pool->FreeList = zpl_cast( void* ) next_free;
pool->TotalSize += pool->BlockSize;
if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO )
zero_size( ptr, size );
}
break;
case EAllocation_FREE :
{
uptr* next;
if ( old_memory == NULL )
return NULL;
next = zpl_cast( uptr* ) old_memory;
*next = zpl_cast( uptr ) pool->FreeList;
pool->FreeList = old_memory;
pool->TotalSize -= pool->BlockSize;
}
break;
case EAllocation_FREE_ALL :
{
sw actual_block_size, block_index;
void* curr;
uptr* end;
actual_block_size = pool->BlockSize + pool->BlockAlign;
pool->TotalSize = 0;
// NOTE: Init intrusive freelist
curr = pool->PhysicalStart;
for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ )
{
uptr* next = zpl_cast( uptr* ) curr;
*next = zpl_cast( uptr ) curr + actual_block_size;
curr = pointer_add( curr, actual_block_size );
}
end = zpl_cast( uptr* ) curr;
*end = zpl_cast( uptr ) NULL;
pool->FreeList = pool->PhysicalStart;
}
break;
case EAllocation_RESIZE :
// NOTE: Cannot resize
ZPL_PANIC( "You cannot resize something allocated by with a pool." );
break;
}
return ptr;
}
gen_Pool gen_Pool::init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw block_align )
{
gen_Pool pool = {};
sw actual_block_size, pool_size, block_index;
void *data, *curr;
uptr* end;
pool.Backing = backing;
pool.BlockSize = block_size;
pool.BlockAlign = block_align;
pool.NumBlocks = num_blocks;
actual_block_size = block_size + block_align;
pool_size = num_blocks * actual_block_size;
data = alloc_align( backing, pool_size, block_align );
// NOTE: Init intrusive freelist
curr = data;
for ( block_index = 0; block_index < num_blocks - 1; block_index++ )
{
uptr* next = ( uptr* ) curr;
*next = ( uptr ) curr + actual_block_size;
curr = pointer_add( curr, actual_block_size );
}
end = ( uptr* ) curr;
*end = ( uptr ) 0;
pool.PhysicalStart = data;
pool.FreeList = data;
return pool;
}
namespace Memory
{
using namespace zpl;
global AllocatorInfo GlobalAllocator;
global Array(Arena) Global_AllocatorBuckets;
void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
{
Arena* last = & array_back( Global_AllocatorBuckets );
switch ( type )
{
case EAllocation_ALLOC:
{
if ( last->total_allocated + size > last->total_size )
{
Arena bucket;
arena_init_from_allocator( & bucket, heap(), BucketSize );
if ( bucket.physical_start == nullptr )
fatal( "Failed to create bucket for Global_AllocatorBuckets");
if ( ! array_append( Global_AllocatorBuckets, bucket ) )
fatal( "Failed to append bucket to Global_AllocatorBuckets");
last = & array_back( Global_AllocatorBuckets );
}
return alloc_align( arena_allocator( last), size, alignment );
}
case EAllocation_FREE:
{
// Doesn't recycle.
}
case EAllocation_FREE_ALL:
{
// Memory::cleanup instead.
}
case EAllocation_RESIZE:
{
if ( last->total_allocated + size > last->total_size )
{
Arena bucket;
arena_init_from_allocator( & bucket, heap(), BucketSize );
if ( bucket.physical_start == nullptr )
fatal( "Failed to create bucket for Global_AllocatorBuckets");
if ( ! array_append( Global_AllocatorBuckets, bucket ) )
fatal( "Failed to append bucket to Global_AllocatorBuckets");
last = & array_back( Global_AllocatorBuckets );
}
void* result = alloc_align( arena_allocator( last), size, alignment );
if ( result != nullptr && old_memory != nullptr )
{
mem_copy( result, old_memory, size );
}
return result;
}
}
return nullptr;
}
void setup()
{
GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr };
if ( ! array_init_reserve( Global_AllocatorBuckets, heap(), 128 ) )
fatal( "Failed to reserve memory for Global_AllocatorBuckets");
Arena bucket;
arena_init_from_allocator( & bucket, heap(), BucketSize );
if ( bucket.physical_start == nullptr )
fatal( "Failed to create first bucket for Global_AllocatorBuckets");
array_append( Global_AllocatorBuckets, bucket );
}
void cleanup()
{
s32 index = 0;
s32 left = array_count( Global_AllocatorBuckets );
do
{
Arena* bucket = & Global_AllocatorBuckets[ index ];
arena_free( bucket );
index++;
}
while ( left--, left );
array_free( Global_AllocatorBuckets );
}
}