135 lines
3.7 KiB
C
135 lines
3.7 KiB
C
/*
|
|
* This software is licensed under the terms of the MIT License.
|
|
* See COPYING for further information.
|
|
* ---
|
|
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
|
|
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
|
|
*/
|
|
|
|
#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)))
|