/* * This software is licensed under the terms of the MIT License. * See COPYING for further information. * --- * Copyright (c) 2011-2024, Lukas Weber . * Copyright (c) 2012-2024, Andrei Alexeyev . */ #pragma once #include "taisei.h" #include "list.h" typedef struct MemArena MemArena; typedef struct MemArenaPage MemArenaPage; typedef struct MemArenaSnapshot MemArenaSnapshot; struct MemArena { LIST_ANCHOR(MemArenaPage) pages; size_t page_offset; size_t total_used; size_t total_allocated; }; struct MemArenaPage { LIST_INTERFACE(MemArenaPage); MemArena *arena; size_t size; alignas(alignof(max_align_t)) char data[]; }; typedef struct MemArenaSnapshot { MemArenaPage *page; size_t page_offset; } MemArenaSnapshot; void marena_init(MemArena *arena, size_t min_size) attr_nonnull_all; void marena_deinit(MemArena *arena) attr_nonnull_all; void marena_reset(MemArena *arena) attr_nonnull_all; void *marena_alloc(MemArena *arena, size_t size) attr_alloc_size(2) attr_malloc attr_returns_allocated attr_nonnull_all; void *marena_alloc_array(MemArena *arena, size_t num_members, size_t size) attr_alloc_size(2, 3) attr_malloc attr_returns_allocated attr_nonnull_all; void *marena_alloc_array_aligned(MemArena *arena, size_t num_members, size_t size, size_t align) attr_alloc_size(2, 3) attr_alloc_align(4) attr_malloc attr_returns_allocated attr_nonnull_all; void *marena_alloc_aligned(MemArena *arena, size_t size, size_t alignment) attr_alloc_size(2) attr_alloc_align(3) attr_malloc attr_returns_allocated attr_nonnull_all; bool marena_free(MemArena *restrict arena, void *restrict p, size_t old_size); #define marena_assert_free(arena, p, old_size) ({ \ bool _freed = marena_free(arena, p, old_size); \ assert(_freed); \ (void)0; \ }) void *marena_realloc(MemArena *restrict arena, void *restrict p, size_t old_size, size_t new_size) attr_alloc_size(4) attr_nonnull(1) attr_returns_allocated; void *marena_realloc_aligned(MemArena *restrict arena, void *restrict p, size_t old_size, size_t new_size, size_t align) attr_alloc_size(4) attr_alloc_align(5) attr_nonnull(1) attr_returns_allocated; MemArenaSnapshot marena_snapshot(MemArena *arena) attr_nonnull_all; bool marena_rollback(MemArena *restrict arena, const MemArenaSnapshot *restrict snapshot) attr_nonnull_all; INLINE void *marena_memdup(MemArena *arena, const void *buf, size_t size) { return memcpy(marena_alloc(arena, size), buf, size); } INLINE char *marena_strdup(MemArena *arena, const char *src) { return marena_memdup(arena, src, strlen(src) + 1); } /* * These are similar to the macros in memory.h, except they also take an Arena pointer as the * first argument. */ #define ARENA_ALLOC(_arena, _type, ...)\ MACROHAX_OVERLOAD_HASARGS(ARENA_ALLOC_, __VA_ARGS__)(_arena, _type, ##__VA_ARGS__) #define ARENA_ALLOC_0(_arena, _type) \ (_type *)__builtin_choose_expr( \ alignof(_type) > alignof(max_align_t), \ marena_alloc_aligned(_arena, sizeof(_type), alignof(_type)), \ marena_alloc(_arena, sizeof(_type))) #define ARENA_ALLOC_1(_arena, _type, ...) ({ \ auto _alloc_ptr = ARENA_ALLOC_0(_arena, _type); \ *_alloc_ptr = (_type) __VA_ARGS__; \ _alloc_ptr; \ }) #define ARENA_ALLOC_ARRAY(_arena, _nmemb, _type) \ (_type *)__builtin_choose_expr( \ alignof(_type) > alignof(max_align_t), \ marena_alloc_array_aligned(_arena, _nmemb, sizeof(_type), alignof(_type)), \ marena_alloc_array(_arena, _nmemb, sizeof(_type))) #define ARENA_ALLOC_FLEX(_arena, _type, _extra_size) \ (_type *)__builtin_choose_expr( \ alignof(_type) > alignof(max_align_t), \ marena_alloc_aligned(_arena, sizeof(_type) + (_extra_size), alignof(_type)), \ marena_alloc(_arena, sizeof(_type) + (_extra_size)))