Lumenarium/src_v2/lumenarium_memory.cpp

232 lines
5.7 KiB
C++

/////////////////////////////////////////
// Memory Functions
void
memory_zero_no_simd(u8* base, u64 size)
{
for (u64 i = 0; i < size; i++) base[i] = 0;
}
void
memory_copy_no_simd(u8* from, u8* to, u64 size)
{
for (u64 i = 0; i < size; i++) to[i] = from[i];
}
#if defined(PLATFORM_HAS_SIMD)
// TODO(PS):
// TODO(PS):
// TODO(PS):
void
memory_zero_simd(u8* base, u64 size)
{
memory_zero_no_simd(base, size);
}
void
memory_copy_simd(u8* from, u8* to, u64 size)
{
memory_copy_no_simd(from, to, size);
}
# define memory_zero(b,s) memory_zero_simd((b),(s))
# define memory_copy(f,t,s) memory_copy_simd((f),(t),(s))
#else
# define memory_zero(b,s) memory_zero_no_simd((b),(s))
# define memory_copy(f,t,s) memory_copy_no_simd((f),(t),(s))
#endif // defined(PLATFORM_HAS_SIMD)
#define zero_struct(s) memory_zero((u8*)(&s), sizeof(s))
u64
size_to_pages(u64 size)
{
u64 page_size = platform_page_size();
u64 rem = size % page_size;
if (rem != 0 || size < page_size)
{
u64 grow = page_size - rem;
size += grow;
}
return size;
}
/////////////////////////////////////////
// Allocator
//
// A generic interface for any memory-providing construct
//
// To implement a complete allocator, all that is really required
// is to create its Allocator_Alloc function
typedef struct Allocator Allocator;
typedef u8* Allocator_Alloc(Allocator* allocator, u64 size);
typedef void Allocator_Free(Allocator* allocator, u8* base, u64 size);
typedef u8* Allocator_Realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size);
typedef void Allocator_Clear(Allocator* allocator);
struct Allocator
{
Allocator_Alloc* alloc;
Allocator_Free* free;
Allocator_Realloc* realloc;
Allocator_Clear* clear;
Allocator* parent;
u8* allocator_data;
};
#define allocator_alloc(a,s) (a)->alloc((a),(s))
#define allocator_alloc_struct(a,t) (t*)(a)->alloc((a),sizeof(t))
#define allocator_alloc_array(a,t,c) (t*)(a)->alloc((a),sizeof(t)*(c))
#define allocator_free(a,b,s) (a)->free((a),(b),(s))
#define allocator_free_struct(a,b,t) (a)->free((a),(b),sizeof(t))
#define allocator_free_array(a,b,t,c) (a)->free((a),(b),sizeof(t)*(c))
#define allocator_realloc(a,b,os,ns) (a)->realloc((a),(b),(os),(ns))
#define allocator_realloc_array(a,b,t,oc,nc) (t*)(a)->realloc((a),(b),sizeof(t)*(oc),sizeof(t)*(nc))
#define allocator_clear(a) (a)->clear(a)
/////////////////////////////////////////
// Bump Allocator
struct Allocator_Bump
{
u8* base;
u64 at;
u64 size_committed;
u64 size_reserved;
};
internal u8*
bump_allocator_alloc(Allocator* allocator, u64 size)
{
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
u64 at_after = bump->at + size;
// TODO(PS): align up to 8 bytes
if (at_after >= bump->size_committed)
{
// determine new size of the arena
u64 new_size = bump->size_committed * 2;
if (new_size == 0) new_size = platform_page_size();
if (new_size < at_after) new_size = size_to_pages(at_after);
if (allocator->parent)
{
bump->base = allocator_realloc(
allocator->parent,
bump->base,
bump->size_committed,
new_size
);
if (bump->base != 0)
{
bump->size_reserved = new_size;
bump->size_committed = new_size;
}
}
else
{
if (new_size <= bump->size_reserved)
{
u64 next_page = size_to_pages(bump->at);
if (bump->at == 0 && bump->size_committed == 0) next_page = 0;
u64 commit_amt = new_size - next_page;
u8* new_page = platform_mem_commit(bump->base + next_page, commit_amt);
if (new_page != 0)
{
bump->size_committed = new_size;
}
}
else
{
invalid_code_path; // out of reserved memory
}
}
}
u8* result = bump->base + bump->at;
bump->at = at_after;
return result;
}
internal u8*
bump_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size)
{
u8* result = bump_allocator_alloc(allocator, new_size);
memory_copy(base, result, old_size);
return result;
}
internal void
bump_allocator_clear(Allocator* allocator)
{
if (!allocator->allocator_data) return;
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
bump->at = 0;
}
internal Allocator*
bump_allocator_create_()
{
u64 size_needed = sizeof(Allocator) + sizeof(Allocator_Bump);
u8* base = platform_mem_reserve(size_needed);
base = platform_mem_commit(base, size_needed);
Allocator* result = (Allocator*)base;
zero_struct(*result);
Allocator_Bump* bump = (Allocator_Bump*)base + sizeof(Allocator);
zero_struct(*bump);
result->alloc = bump_allocator_alloc;
result->realloc = bump_allocator_realloc;
result->clear = bump_allocator_clear;
result->allocator_data = (u8*)bump;
return result;
}
internal Allocator*
bump_allocator_create_reserve(u64 reserve_size)
{
Allocator* result = bump_allocator_create_();
Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data;
u64 reserve_pages = size_to_pages(reserve_size);
bump->base = platform_mem_reserve(reserve_pages);
if (bump->base != 0) bump->size_reserved = reserve_pages;
return result;
}
internal Allocator*
bump_allocator_create_child(Allocator* parent, u64 init_size)
{
Allocator* result = bump_allocator_create_();
result->parent = parent;
Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data;
bump->base = allocator_alloc(result->parent, init_size);
if (bump->base != 0)
{
bump->size_reserved = init_size;
bump->size_committed = init_size;
}
return result;
}