Memory

Base allocator and memory arenas.

Types

oc_mem_reserve_proc

typedef void* (*oc_mem_reserve_proc)((oc_base_allocator* context, u64 size));

The prototype of a procedure to reserve memory from the system.


oc_mem_modify_proc

typedef void (*oc_mem_modify_proc)((oc_base_allocator* context, void* ptr, u64 size));

The prototype of a procedure to modify a memory reservation.


oc_base_allocator

typedef struct oc_base_allocator
{
    oc_mem_reserve_proc reserve;
    oc_mem_modify_proc commit;
    oc_mem_modify_proc decommit;
    oc_mem_modify_proc release;
} oc_base_allocator;

A structure that defines how to allocate memory from the system.

Fields

  • reserve A procedure to reserve memory from the system.
  • commit A procedure to commit memory from the system.
  • decommit A procedure to decommit memory from the system.
  • release A procedure to release memory previously reserved from the system.

oc_arena_chunk

typedef struct oc_arena_chunk
{
    oc_list_elt listElt;
    char* ptr;
    u64 offset;
    u64 committed;
    u64 cap;
} oc_arena_chunk;

A contiguous chunk of memory managed by a memory arena.


oc_arena

typedef struct oc_arena
{
    oc_base_allocator* base;
    oc_list chunks;
    oc_arena_chunk* currentChunk;
} oc_arena;

A memory arena, allowing to allocate memory in a linear or stack-like fashion.

Fields

  • base An allocator providing memory pages from the system
  • chunks A list of oc_arena_chunk chunks.
  • currentChunk The chunk new memory allocations are pulled from.

oc_arena_scope

typedef struct oc_arena_scope
{
    oc_arena* arena;
    oc_arena_chunk* chunk;
    u64 offset;
} oc_arena_scope;

This struct provides a way to store the current offset in a given arena, in order to reset the arena to that offset later. This allows using arenas in a stack-like fashion, e.g. to create temporary "scratch" allocations

Fields

  • arena The arena which offset is stored.
  • chunk The arena chunk to which the offset belongs.
  • offset The offset to rewind the arena to.

oc_arena_options

typedef struct oc_arena_options
{
    oc_base_allocator* base;
    u64 reserve;
} oc_arena_options;

Options for arena creation.

Fields

  • base The base allocator to use with this arena
  • reserve The amount of memory to reserve up-front when creating the arena.

Macros

oc_arena_push_type

#define oc_arena_push_type(arena, type)

Allocate a type from an arena. This macro takes care of the memory alignment and type cast.

Parameters

  • arena The arena to allocate from.
  • type The type of the object to allocate.

Return

A pointer to the allocated object.


oc_arena_push_array

#define oc_arena_push_array(arena, type, count)

Allocate an array from an arena. This macro takes care of the size calculation, memory alignment and type cast.

Parameters

  • arena The arena to allocate from.
  • type The type of the array's elements.
  • count The number of element in the array.

Return

A pointer to the allocated array.


oc_scratch_end

#define oc_scratch_end(scope)

End a scratch scope.

Parameters

  • scope A scope object created by a call to oc_scratch_begin() or similar functions.

Functions

oc_arena_init

void oc_arena_init(oc_arena* arena);

Initialize a memory arena.

Parameters

  • arena The arena to initialize.

oc_arena_init_with_options

void oc_arena_init_with_options(oc_arena* arena, oc_arena_options* options);

Initialize a memory arena with additional options.

Parameters

  • arena The arena to initialize.
  • options The options to use to initialize the arena.

oc_arena_cleanup

void oc_arena_cleanup(oc_arena* arena);

Release all resources allocated to a memory arena.

Parameters

  • arena The arena to cleanup.

oc_arena_push

void* oc_arena_push(oc_arena* arena, u64 size);

Allocate a block of memory from an arena.

Parameters

  • arena An arena to allocate memory from.
  • size The size of the memory to allocate, in bytes.

Return

A pointer to the allocated memory.


oc_arena_push_aligned

void* oc_arena_push_aligned(oc_arena* arena, u64 size, u32 alignment);

Allocate an aligned block of memory from an arena.

Parameters

  • arena An arena to allocate memory from.
  • size The size of the memory to allocate, in bytes.
  • alignment The desired alignment of the memory block, in bytes

Return

A pointer to the allocated memory


oc_arena_clear

void oc_arena_clear(oc_arena* arena);

Reset an arena. All memory that was previously allocated from this arena is released to the arena, and can be reallocated by later calls to oc_arena_push and similar functions. No memory is actually released to the system.

Parameters

  • arena The arena to clear.

oc_arena_scope_begin

oc_arena_scope oc_arena_scope_begin(oc_arena* arena);

Begin a memory scope. This creates an oc_arena_scope object that stores the current offset of the arena. The arena can later be reset to that offset by calling oc_arena_scope_end, releasing all memory that was allocated within the scope to the arena.

Parameters

  • arena The arena for which the scope is created.

Return

A oc_arena_scope object storing the current offset of the arena.


oc_arena_scope_end

void oc_arena_scope_end(oc_arena_scope scope);

End a memory scope. This resets an arena to the offset it had when the scope was created. All memory allocated within the scope is released back to the arena.

Parameters

  • scope An oc_arena_scope object that was created by a call to oc_arena_scope_begin().

oc_scratch_begin

oc_arena_scope oc_scratch_begin();

Begin a scratch scope. This creates a memory scope on a per-thread, global "scratch" arena. This allows easily creating temporary memory for scratch computations or intermediate results, in a stack-like fashion.

If you must return results in an arena passed by the caller, and you also use a scratch arena to do intermediate computations, beware that the results arena could itself be a scatch arena. In this case, you have to be careful not to intermingle your scratch computations with the final result, or clear your result entirely. You can either:

  • Allocate memory for the result upfront and call oc_scratch_begin afterwards, if possible.
  • Use oc_scratch_begin_next() and pass it the result arena, to get a scratch arena that does not conflict with it.

Return

A memory scope object. You can use the arena field of this object to allocate memory from the scratch scope. When you're done, pass the scope oject to oc_scratch_end().


oc_scratch_begin_next

oc_arena_scope oc_scratch_begin_next(oc_arena* used);

Begin a scratch scope that does not conflict with a given arena. See oc_scratch_begin() for more details about when to use this function.

Parameters

  • used A pointer to a memory arena that the scratch scope shouldn't interfere with.

Return

A memory scope object. You can use the arena field of this object to allocate memory from the scratch scope. When you're done, pass the scope oject to oc_scratch_end().