Skip to content
/ larena Public

Yet another simple header only arena allocator for C11

License

Notifications You must be signed in to change notification settings

linkdd/larena

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Little Arena

tests license version

This project is a C11 header only library providing an Arena implementation.

Installation

Copy the larena.h file in your source tree, then in a single .c file:

#define LARENA_IMPLEMENTATION
#include "larena.h"

Usage

To create an arena, you first need an allocator:

lallocator myallocator = {0};
lallocator_init_stdlib(&myallocator);

This will initialize (on the stack) an allocator using stdlib.h's malloc, realloc and free functions.

To create a custom allocator:

void *myallocator_alloc(size_t sz, void *ctx) {
  // ...
}

void *myallocator_realloc(void *ptr, size_t oldsz, size_t newsz, void *ctx) {
  // ...
}

void myallocator_dealloc(void *ptr, size_t sz, void *ctx) {
  // ...
}
lallocator myallocator = {
  .alloc   = myallocator_alloc,
  .realloc = myallocator_realloc,
  .dealloc = myallocator_dealloc,
  .ctx     = NULL
};

Once your allocator is set-up, you will be able to create an arena:

larena myarena = {0};
larena_init(&myarena, &myallocator);

You can then allocate objects with your arena:

lobject myobj = {0};

if (larena_alloc(&myarena, sizeof(int), &myobj) != 0) {
  // allocation failed
}

The possible error codes are:

Code Description
0 The allocation was successful
EOVERFLOW The size of the allocation would produce an integer overflow
ENOMEM The heap allocation, to extend the arena, failed

NB: Error codes are found in the header errno.h

An object is a simple structure containing a reference to the arena used to allocate said object, and a pointer relative to the base of the arena.

If the arena does not have enough capacity, the allocator's realloc method will be called to increase the available memory. Because realloc can move the memory, old pointers would be invalidated. This is why we store in the object a relative pointer.

NB: The returned memory has been zero'd.

To access the allocated memory, we need to dereference the object:

int *mymem = lobject_deref(&myobj);

The absolute pointer will be resolved by summing the arena's base with the relative pointer contained in the object. This way, there is no pointer invalidation when realloc moves the memory.

The library also provide a calloc interface to allocate multiple chunks of contiguous memory at once:

lobject myobj = {0};

if (larena_calloc(&myarena, 5, sizeof(int), &myobj) != 0) {
  // allocation failed
}

int *array = lobject_deref(myobj);
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;

Once you're done with your arena, you can free all the memory at once:

larena_free(&myarena);
// all lobjects are now invalid

But if you wish to reuse the arena, for example each frame of a game loop, you can simply clear it instead:

larena_clear(&myarena);

The arena's offset is reset to 0, but the allocated memory has not been free'd. This is especially useful for loops so that the arena grows to its maximum capacity only once:

larena myarena = {0};
larena_init(&myarena);

while (true) {
  // do work, and some allocations

  larena_clear(&myarena);
}

larena_free(&myarena);

License

This library is distributed under the terms of the MIT License.