Skip to content
Snippets Groups Projects
arena.c 2.66 KiB
Newer Older
  • Learn to ignore specific revisions
  • // Arena allocation
    // Michal Vlasák, FIT CTU, 2023
    
    
    Michal Vlasák's avatar
    Michal Vlasák committed
    #include "arena.h"
    #include "stdlib.h"
    #include "stdint.h"
    #include "string.h"
    
    static size_t
    align(size_t pos, size_t alignment)
    {
    	return (pos + (alignment - 1)) & ~(alignment - 1);
    }
    
    
    static ArenaChunk sentinel = {0};
    
    Michal Vlasák's avatar
    Michal Vlasák committed
    
    void
    arena_init(Arena *arena)
    {
    	ArenaChunk *chunk = &sentinel;
    	arena->current = chunk;
    	arena->prev_size_sum = 0;
    }
    
    void *
    arena_alloc(Arena *arena, size_t size)
    {
    	size_t pos = align(arena->current->pos, 8);
    	size_t current_size = arena->current->size;
    	if (pos + size > current_size) {
    		arena->prev_size_sum += current_size;
    		size_t new_size = size + (current_size ? current_size * 2 : 1024);
    		ArenaChunk *new = malloc(new_size);
    		new->size = new_size;
    		new->prev = arena->current;
    		arena->current = new;
    		pos = align(sizeof(ArenaChunk), 8);
    	}
    	arena->current->pos = pos + size;
    	return ((unsigned char *) arena->current) + pos;
    }
    
    size_t
    arena_save(Arena *arena)
    {
    	return arena->prev_size_sum + arena->current->pos;
    }
    
    void
    arena_restore(Arena *arena, size_t pos)
    {
    	ArenaChunk *chunk = arena->current;
    	while (pos < arena->prev_size_sum) {
    		ArenaChunk *prev = chunk->prev;
    		free(chunk);
    		chunk = prev;
    		arena->prev_size_sum -= chunk->size;
    	}
    	chunk->pos = pos - arena->prev_size_sum;
    	arena->current = chunk;
    }
    
    void
    arena_destroy(Arena *arena)
    {
    	arena_restore(arena, 0);
    	if (arena->current != &sentinel) {
    		free(arena->current);
    		arena->current = &sentinel;
    	}
    }
    
    
    
    
    void
    garena_init(GArena *arena)
    {
    	arena->mem = NULL;
    	arena->pos = 0;
    	arena->capacity = 0;
    }
    
    void
    garena_destroy(GArena *arena)
    {
    	free(arena->mem);
    }
    
    void *
    garena_alloc(GArena *arena, size_t size, size_t alignment)
    {
    	size_t pos = align(arena->pos, alignment);
    	if (pos + size > arena->capacity) {
    		arena->capacity = arena->capacity ? arena->capacity * 2 : size * 8;
    		arena->mem = realloc(arena->mem, arena->capacity);
    	}
    	arena->pos = pos + size;
    	return &arena->mem[pos];
    }
    
    size_t
    garena_save(GArena *arena)
    {
    	return arena->pos;
    }
    
    void *
    garena_restore(GArena *arena, size_t pos)
    {
    	arena->pos = pos;
    	return &arena->mem[pos];
    }
    
    void *
    garena_mem(GArena *arena)
    {
    	return arena->mem;
    }
    
    size_t
    garena_cnt_from_(GArena *arena, size_t start, size_t elem_size)
    {
    	return (arena->pos - start) / elem_size;
    }
    
    void *
    garena_from(GArena *arena, size_t start, size_t alignment)
    {
    	size_t pos = align(start, alignment);
    	return &arena->mem[pos];
    }
    
    void *
    move_to_arena_(Arena *arena, GArena *garena, size_t start, size_t alignment)
    {
    	size_t size = garena->pos - start;
    	if (size == 0) {
    		return NULL;
    	}
    	garena_restore(garena, start);
    	void *old = garena_from(garena, start, alignment);
    	return memcpy(arena_alloc(arena, size), old, size);
    }