/* date = April 20th 2023 9:43 pm */

#ifndef BASE_MEMORY_H
#define BASE_MEMORY_H

#if !defined(ARENA_COMMIT_GRANULARITY)
#define ARENA_COMMIT_GRANULARITY Kilobytes(4)
#endif

#if !defined(ARENA_DECOMMIT_THRESHOLD)
#define ARENA_DECOMMIT_THRESHOLD Megabytes(64)
#endif

#if !defined(M_DEFAULT_RESERVE_SIZE)
#define M_DEFAULT_RESERVE_SIZE Megabytes(512)
#endif

#if !defined(M_COMMIT_BLOCK_SIZE)
#define M_COMMIT_BLOCK_SIZE Megabytes(64)
#endif

// We store this information in the header of the allocated memory for the arena!!!
typedef struct Arena Arena;
struct Arena {
  U64 pos;
  U64 commit_pos;
  U64 capacity;
  U64 align;
};

typedef struct ArenaTemp ArenaTemp;
struct ArenaTemp {
  Arena *arena;
  U64 pos;
};

root_function void m_change_memory_noop(void *ptr, U64 size);

root_function Arena* m_make_arena_reserve(U64 reserve_size);
root_function Arena* m_make_arena();

root_function void m_arena_release(Arena *arena);
root_function void* m_arena_push(Arena *arena, U64 size);
root_function void m_arena_pop_to(Arena *arena, U64 pos);
root_function void m_arena_pop(Arena* arena, U64 size);
root_function void m_arena_align(Arena *arena, U64 pow2_alignment);
root_function void* m_arena_push_zero(Arena *arena, U64 size);
root_function void m_arena_clear(Arena *arena);

#define PushArrayNoZero(arena, type, count) (type *)m_arena_push((arena), sizeof(type)*(count))
#define PushArray(arena, type, count) (type *)m_arena_push_zero((arena), sizeof(type)*(count))
//~ temp arena

root_function ArenaTemp m_arena_temp_begin(Arena *arena);
root_function void m_arena_temp_end(ArenaTemp temp);

// TODO(anton): Not sure when I should use this?
#define ArenaTempBlock(arena, name) ArenaTemp name = { 0 }; DeferLoop(name = m_arena_temp_begin(arena), m_arena_temp_end(name))

#endif //BASE_MEMORY_H
