Implement simple array
This commit is contained in:
parent
d8cb10b432
commit
ed2020edf1
@ -6,7 +6,7 @@ set build_dir=%script_dir%\Build
|
|||||||
set code_dir=%script_dir%
|
set code_dir=%script_dir%
|
||||||
if not exist %build_dir% mkdir %build_dir%
|
if not exist %build_dir% mkdir %build_dir%
|
||||||
|
|
||||||
set compile_flags=%code_dir%\rfleury_arena.cpp /W4 /Z7 /MD /EHsc /nologo
|
set compile_flags=%code_dir%\rfleury_arena.cpp /W4 /Z7 /MD /EHsc /nologo /fsanitize=address
|
||||||
set link_flags=/link /incremental:no
|
set link_flags=/link /incremental:no
|
||||||
|
|
||||||
set msvc_cmd=cl %compile_flags% /Forfleury_arena /Ferfleury_arena %link_flags%
|
set msvc_cmd=cl %compile_flags% /Forfleury_arena /Ferfleury_arena %link_flags%
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
// NOTE: Types =====================================================================================
|
// NOTE: Types =====================================================================================
|
||||||
typedef uint16_t U16;
|
typedef uint16_t U16;
|
||||||
@ -16,8 +17,8 @@ typedef uint64_t U64;
|
|||||||
|
|
||||||
struct OS
|
struct OS
|
||||||
{
|
{
|
||||||
U16 page_size;
|
U32 page_size;
|
||||||
U16 alloc_granularity;
|
U32 alloc_granularity;
|
||||||
};
|
};
|
||||||
OS g_os;
|
OS g_os;
|
||||||
|
|
||||||
@ -54,17 +55,55 @@ U64 ArenaPos(Arena *arena);
|
|||||||
#define ArenaPushN(arena, T, size) (T *)ArenaPush(arena, sizeof(T) * size, alignof(T))
|
#define ArenaPushN(arena, T, size) (T *)ArenaPush(arena, sizeof(T) * size, alignof(T))
|
||||||
void *ArenaPushNoZero(Arena *arena, U64 size, U64 alignment);
|
void *ArenaPushNoZero(Arena *arena, U64 size, U64 alignment);
|
||||||
void *ArenaPush(Arena *arena, U64 size, U64 alignment);
|
void *ArenaPush(Arena *arena, U64 size, U64 alignment);
|
||||||
|
void ArenaPushAlignment(Arena *arena, U64 alignment);
|
||||||
|
|
||||||
void ArenaPopTo(Arena *arena, U64 pos);
|
void ArenaPopTo(Arena *arena, U64 pos);
|
||||||
void ArenaPop(Arena *arena, U64 size);
|
void ArenaPop(Arena *arena, U64 size);
|
||||||
void ArenaClear(Arena *arena);
|
void ArenaClear(Arena *arena);
|
||||||
|
|
||||||
#define ArenaRealCommitPointer(block) (char *)block + block->commit +
|
#define IsPowerOfTwo(value, pot) ((((uintptr_t)value) & ((uintptr_t)pot - 1)) == 0)
|
||||||
#define ArenaRealCommitSize(block) arena->commit + sizeof(Arena) + sizeof(ArenaBlock)
|
#define AlignUpPowerOfTwo(value, pot) (((uintptr_t)(value) + ((uintptr_t)(pot) - 1)) & ~((uintptr_t)(pot) - 1))
|
||||||
|
#define AlignDownPowerOfTwo(value, pot) (((uintptr_t)value) & (~((uintptr_t)pot - 1)))
|
||||||
|
#define ArenaBlockMetadataSize(block) sizeof(ArenaBlock) + (block->next == block->prev ? sizeof(Arena) : 0)
|
||||||
|
|
||||||
#define IsPowerOfTwo(value, pot) ((((uintptr_t)value) & (pot - 1)) == 0)
|
template <typename T>
|
||||||
#define AlignUpPowerOfTwo(value, pot) (((uintptr_t)value) + ((pot) - (((uintptr_t)value) & ((pot) - 1))))
|
struct Array
|
||||||
#define AlignDownPowerOfTwo(value, pot) (((uintptr_t)value) & (~(pot - 1)))
|
{
|
||||||
|
T *data;
|
||||||
|
size_t size;
|
||||||
|
size_t cap;
|
||||||
|
Arena *arena;
|
||||||
|
|
||||||
|
static Array Init(U64 capacity);
|
||||||
|
|
||||||
|
T *begin() { return data; }
|
||||||
|
T *end() { return data + size; }
|
||||||
|
T const *begin() const { return data; }
|
||||||
|
T const *end() const { return data + size; }
|
||||||
|
|
||||||
|
T *PushBack(const T& item);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Array<T> Array<T>::Init(U64 capacity)
|
||||||
|
{
|
||||||
|
Array<T> result = {};
|
||||||
|
result.arena = ArenaAlloc(capacity * sizeof(T), ArenaFlag_ReserveCommit);
|
||||||
|
result.cap = capacity;
|
||||||
|
result.data = (T *)ArenaPush(result.arena, 0 /*size*/, alignof(T));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T *Array<T>::PushBack(const T& item)
|
||||||
|
{
|
||||||
|
T* result = ArenaPushN(arena, T, 1);
|
||||||
|
if (result) {
|
||||||
|
size++;
|
||||||
|
*result = item;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Implementation ============================================================================
|
// NOTE: Implementation ============================================================================
|
||||||
Arena *ArenaAlloc(U64 initial_cap, U32 flags)
|
Arena *ArenaAlloc(U64 initial_cap, U32 flags)
|
||||||
@ -88,6 +127,7 @@ Arena *ArenaAlloc(U64 initial_cap, U32 flags)
|
|||||||
|
|
||||||
// NOTE: Create arena and block
|
// NOTE: Create arena and block
|
||||||
Arena *result = (Arena *)ptr;
|
Arena *result = (Arena *)ptr;
|
||||||
|
result->flags = flags;
|
||||||
ptr += sizeof(*result);
|
ptr += sizeof(*result);
|
||||||
ArenaBlock *block = (ArenaBlock *)ptr;
|
ArenaBlock *block = (ArenaBlock *)ptr;
|
||||||
ptr += sizeof(*block);
|
ptr += sizeof(*block);
|
||||||
@ -124,7 +164,12 @@ void *ArenaPushNoZero(Arena *arena, U64 size, U64 alignment)
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
assert(IsPowerOfTwo(alignment, alignment)); // Enforce PoT
|
assert(IsPowerOfTwo(alignment, alignment)); // Enforce PoT
|
||||||
while ((arena->last->pos + size) > arena->last->cap) {
|
U64 new_block_pos = 0;
|
||||||
|
for (;;) {
|
||||||
|
new_block_pos = AlignUpPowerOfTwo(arena->last->pos, alignment) + size;
|
||||||
|
if (new_block_pos <= arena->last->cap)
|
||||||
|
break;
|
||||||
|
|
||||||
if ((arena->flags & ArenaFlag_Chain) == 0)
|
if ((arena->flags & ArenaFlag_Chain) == 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@ -139,24 +184,22 @@ void *ArenaPushNoZero(Arena *arena, U64 size, U64 alignment)
|
|||||||
block->next = arena->last->next;
|
block->next = arena->last->next;
|
||||||
block->prev->next = block;
|
block->prev->next = block;
|
||||||
block->next->prev = block;
|
block->next->prev = block;
|
||||||
|
arena->last = block;
|
||||||
block->commit = block->cap;
|
block->commit = block->cap;
|
||||||
assert(((uintptr_t)block & alignof(ArenaBlock) - 1) == 0); // Enforce alignment of block
|
assert(((uintptr_t)block & alignof(ArenaBlock) - 1) == 0); // Enforce alignment of block
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Align PoT & divvy out the pointer
|
// NOTE: Align PoT & divvy out the pointer
|
||||||
ArenaBlock *block = arena->last;
|
ArenaBlock *block = arena->last;
|
||||||
block->pos = AlignUpPowerOfTwo(block->pos, alignment) + size;
|
block->pos = new_block_pos;
|
||||||
result = (char *)block->data + (block->pos - size);
|
result = (char *)block->data + (block->pos - size);
|
||||||
|
|
||||||
// NOTE: Commit pages
|
// NOTE: Commit pages
|
||||||
if (block->commit <= block->pos) {
|
if (block->commit <= block->pos) {
|
||||||
assert(arena->flags & ArenaFlag_ReserveCommit);
|
|
||||||
void *commit_ptr = (char *)block->data + block->commit;
|
|
||||||
U64 commit_size = AlignUpPowerOfTwo(block->pos - block->commit, g_os.page_size);
|
U64 commit_size = AlignUpPowerOfTwo(block->pos - block->commit, g_os.page_size);
|
||||||
assert(IsPowerOfTwo(commit_ptr, g_os.page_size));
|
void *commit_ptr = (void *)AlignUpPowerOfTwo((char *)block->data + block->commit, g_os.page_size);
|
||||||
VirtualAlloc(commit_ptr, commit_size, MEM_COMMIT, PAGE_READWRITE);
|
VirtualAlloc(commit_ptr, commit_size, MEM_COMMIT, PAGE_READWRITE);
|
||||||
block->commit += commit_size;
|
block->commit += commit_size;
|
||||||
assert(IsPowerOfTwo(block->commit, g_os.page_size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(IsPowerOfTwo(result, alignment));
|
assert(IsPowerOfTwo(result, alignment));
|
||||||
@ -198,11 +241,35 @@ int main(int, char**)
|
|||||||
{
|
{
|
||||||
SYSTEM_INFO info = {};
|
SYSTEM_INFO info = {};
|
||||||
GetSystemInfo(&info);
|
GetSystemInfo(&info);
|
||||||
g_os.page_size = (U16)info.dwPageSize;
|
g_os.page_size = info.dwPageSize;
|
||||||
g_os.alloc_granularity = (U16)info.dwAllocationGranularity;
|
g_os.alloc_granularity = info.dwAllocationGranularity;
|
||||||
|
printf("Page Size: %u bytes\n", g_os.page_size);
|
||||||
|
printf("Allocation Granularity: %u bytes\n", g_os.alloc_granularity);
|
||||||
|
|
||||||
Arena *arena = ArenaAlloc(GIGABYTES(1), ArenaFlag_ChainReserveCommit);
|
Arena *arena = ArenaAlloc(g_os.page_size - 8, ArenaFlag_ChainReserveCommit);
|
||||||
U64 *array = ArenaPushN(arena, U64, 1'000);
|
{
|
||||||
assert(array);
|
U64 u64s_in_a_page = g_os.page_size / sizeof(U64);
|
||||||
|
U64 *u64s_array = ArenaPushN(arena, U64, u64s_in_a_page);
|
||||||
|
assert(u64s_array);
|
||||||
|
memset(u64s_array, 0xFA, u64s_in_a_page * sizeof(U64));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
U64 u64s_in_straddled_page = (g_os.page_size / sizeof(U64)) + 1;
|
||||||
|
U64 *u64s_array = ArenaPushN(arena, U64, u64s_in_straddled_page);
|
||||||
|
assert(u64s_array);
|
||||||
|
memset(u64s_array, 0xFB, u64s_in_straddled_page * sizeof(U64));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Array<U64> array = Array<U64>::Init(TERABYTES(1) / sizeof(U64));
|
||||||
|
for (size_t index = 0; index < 100'000; index++)
|
||||||
|
array.PushBack(1ULL);
|
||||||
|
assert(array.size == 100'000);
|
||||||
|
assert(array.cap == TERABYTES(1) / sizeof(U64));
|
||||||
|
memset(array.data, 0xFC, array.size * sizeof(*array.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArenaPopTo(arena, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user