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 systemchunks
A list ofoc_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 arenareserve
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 tooc_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
Anoc_arena_scope
object that was created by a call tooc_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()
.