#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 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, }; 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) struct Arena_Free_List { Mutex mutex; s32 in_flight_count[6]; Array free_table[6]; #if ARENA_DEBUG Array in_flight[6]; #endif b32 initialized; }; void initialize_arena_table (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)