Musa-Cpp-Lib-V2/lib/Base/Arena.h

141 lines
4.5 KiB
C++

#pragma once
struct ExpandableArena; // fwd declare #temp
#if OS_WINDOWS
constexpr u32 ARENA_DEFAULT_COMMIT_PAGE_COUNT = 16; // 16 * 4k page = 64kB
constexpr s64 ARENA_DEFAULT_COMMIT_SIZE_BYTES = 65536;
#endif
constexpr u16 ARENA_DEFAULT_ALIGNMENT = CPU_REGISTER_WIDTH_BYTES;
#define ARENA_DEBUG BUILD_DEBUG
constexpr s32 Arena_Reserve_Count = 7;
enum class Arena_Reserve: u8 {
Size_64K = 0, // these are used as indices in Arena_Free_List!
Size_2M = 1,
Size_64M = 2,
Size_2G = 3,
Size_64G = 4,
Size_2T = 5,
Size_64T = 6,
};
constexpr s64 Arena_Sizes[Arena_Reserve_Count] = {
64LL * 1024,
2LL * 1024 * 1024,
64LL * 1024 * 1024,
2LL * 1024 * 1024 * 1024,
64LL * 1024 * 1024 * 1024,
2LL * 1024 * 1024 * 1024 * 1024,
64LL * 1024 * 1024 * 1024 * 1024,
};
enum class Arena_Flags: u8 {
None = 0,
Chained = 0x01,
Is_Bootstrapped = 0x02,
Large_Pages = 0x40,
// Secure_Arena = 0xF0 // #NOTE: Secure Arenas are not implemented yet!
};
force_inline Arena_Flags operator | (Arena_Flags a, Arena_Flags b) {
return (Arena_Flags)(((u8)a) | ((u8)b));
}
force_inline Arena_Flags operator & (Arena_Flags a, Arena_Flags b) {
return (Arena_Flags)(((u8)a) & ((u8)b));
}
force_inline Arena_Flags& operator |= (Arena_Flags& a, Arena_Flags b) {
a = a | b;
return a;
}
force_inline Arena_Flags operator ~ (Arena_Flags a) {
return (Arena_Flags)(~((u8)a));
}
struct Arena {
u8* current_point = nullptr;
u8* memory_base = nullptr;
u8* first_uncommitted_page = nullptr;
u16 alignment = CPU_REGISTER_WIDTH_BYTES;
Arena_Reserve reserve_size = Arena_Reserve::Size_64K;
Arena_Flags flags = Arena_Flags::None;
u32 initial_commit_page_count = ARENA_DEFAULT_COMMIT_PAGE_COUNT;
};
typedef void* (*Memory_Wipe_Function)(void* memory, u64 byte_count);
void* arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
// Interface API for normal use (idk how to explain - see Arena_Free_List.cpp)
void initialize_arena_free_list (Allocator allocator);
Arena* next_arena (Arena_Reserve reserve_size);
void release_arena (Arena* arena, bool delete_extra_pages=true);
// Main API
Arena* bootstrap_arena (Arena_Reserve new_reserve, s32 default_commit_page_count);
void arena_init (Arena* arena, Arena_Reserve new_reserve, s32 default_commit_page_count=16); // For when we're *not* bootstrapping arenas: (I'm debating if we should keep this..)
bool arena_commit_first_pages (Arena* arena, s64 commit_size, s64 start_offset=0); // This is useful for initializing arenas (arena_init), and for starting Arena-backed arrays.
void arena_clear_flags (Arena* arena);
void arena_set_bootstrap_flag (Arena* arena);
void arena_set_secure_flag (Arena* arena);
bool arena_is_bootstrapped (Arena* arena);
void arena_reset_keeping_memory (Arena* arena); // just sets current point to arena_start
void arena_reset (Arena* arena); // frees excess pages
void arena_reset_overwriting_memory (Arena* arena, Memory_Wipe_Function wipe_function);
// Internal API (should not be called directly by program)
void* arena_alloc (Arena* arena, s64 byte_count);
// Utilties
u8* arena_start (Arena* arena);
u8* arena_address_limit (Arena* arena);
s64 arena_usage_bytes (Arena* arena);
s64 arena_usage_committed_bytes (Arena* arena);
// arena_details (requires print)
s64 reserve_size (Arena* arena);
s64 reserve_size (Arena_Reserve ar);
bool is_valid (Arena* arena);
Allocator allocator (Arena* arena);
// Platform-Specific Implementations (forward-declared)
void platform_init (Arena* arena, s64 new_reserve);
void extend_committed_pages (Arena* arena, u8* end);
void free_pages_down_to (Arena* arena, s64 pages_to_keep);
void arena_delete (Arena* arena);
Arena_Reserve next_reserve_size (s64 size);
struct Push_Alignment { // #rename to Arena_Push_Alignment?
Arena* arena;
u16 original_alignment;
Push_Alignment(Arena* arena, u16 alignment) {
Assert(is_valid(arena));
this->arena = arena;
this->original_alignment = arena->alignment;
this->arena->alignment = alignment;
}
Push_Alignment(ExpandableArena* arena_ex, u16 alignment) {
Push_Alignment((Arena*)arena_ex, alignment);
}
~Push_Alignment() {
arena->alignment = original_alignment;
}
};
// Do this later:
// arena_lock_pages :: (using arena: *Arena, start_address: *u8, byte_count: s64)
// arena_unlock_pages :: (using arena: *Arena, start_address: *u8, byte_count: s64)