Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
5#include <stdint.h>
6#include <string.h>
7
10
12
13#if !defined CAPACITY
14 #if !defined __clang_analyzer__
15 #error "The capacity of the static allocator must be defined"
16 #endif
17 #define CAPACITY 1024
18#endif
19
20#if CAPACITY > (1ULL << 30)
21 #error "CAPACITY must not exceed 1 GiB"
22#endif
23
24#if CAPACITY <= UINT8_MAX
25 #define USED uint8_t
26#elif CAPACITY <= UINT16_MAX
27 #define USED uint16_t
28#elif CAPACITY <= UINT32_MAX
29 #define USED uint32_t
30#else
31 #define USED uint64_t
32#endif
33
34typedef struct {
35 size_t used;
38} SELF;
39
40static size_t NS(SELF, metadata_size) = sizeof(USED);
41
42static SELF NS(SELF, new)() {
43 SELF self = {.used = 0, .derive_c_staticbumpalloc = {}};
44 // JUSTIFY: Zeroed buffer
45 // - For easier debugging & view in gdb.
46 // - Additionally allows for calloc to be malloc.
47 memset(self.buffer, 0, CAPACITY);
48 return self;
49}
50
52static void NS(SELF, clear)(SELF* self) {
53 DEBUG_ASSERT(self);
54
55#if !defined NDEBUG
56 // JUSTIFY: Allocations & sizes zeroed on free in debug, we check all data has been freed.
57 for (size_t i = 0; i < self->used; i++) {
58 if (self->buffer[i] != 0) {
59 PANIC("Data not freed before clearing the static bump allocator");
60 }
61 }
62#endif
63 memset(self->buffer, 0, self->used);
64 self->used = 0;
65}
66
67static USED NS(SELF, get_used)(SELF const* self) {
68 DEBUG_ASSERT(self);
69 return self->used;
70}
71
72static void* NS(SELF, malloc)(SELF* self, size_t size) {
73 DEBUG_ASSERT(self);
74 if (self->used + (size + sizeof(USED)) > CAPACITY) {
75 return NULL;
76 }
77 char* ptr = &self->buffer[self->used];
78 USED* used_ptr = (USED*)ptr;
79 *used_ptr = size;
80 self->used += size + sizeof(USED);
81 return ptr + sizeof(USED);
82}
83
84static void NS(SELF, free)(SELF* DEBUG_UNUSED(self), void* DEBUG_UNUSED(ptr)) {
85 DEBUG_ASSERT(self);
86 DEBUG_ASSERT(ptr);
87
88#if !defined NDEBUG
89 // JUSTIFY: Zero memory in debug.
90 // - Expensive for release, but helpful when debugging
91 // NOTE: This means that users should free, before they clear and reuse the buffer.
92 USED* used_ptr = (USED*)((char*)ptr - sizeof(USED));
93 memset(ptr, 0, *used_ptr);
94 *used_ptr = 0;
95#endif
96}
97
98static void* NS(SELF, realloc)(SELF* self, void* ptr, size_t new_size) {
99 DEBUG_ASSERT(self);
100
101 if (!ptr) {
102 return NS(SELF, malloc)(self, new_size);
103 }
104
105 char* byte_ptr = (char*)ptr;
106 USED* old_size = (USED*)(byte_ptr - sizeof(USED));
107 const bool was_last_alloc = (byte_ptr + *old_size == self->buffer + self->used);
108
109 if (was_last_alloc) {
110 if (self->used + (new_size - *old_size) > CAPACITY) {
111 return NULL;
112 }
113
114 self->used += (new_size - *old_size);
115 *old_size = new_size;
116 return ptr;
117 }
118
119 if (new_size < *old_size) {
120 // JUSTIFY: Shrinking an allocation
121 // - Can become a noop - as we cannot re-extend the allocation
122 // afterwards - no metadata for unused capacity not at end of buffer.
123 *old_size = new_size;
124 return ptr;
125 }
126
127 void* new_buff = NS(SELF, malloc)(self, new_size);
128 if (!new_buff) {
129 return NULL;
130 }
131
132 memcpy(new_buff, ptr, *old_size);
133
134 NS(SELF, free)(self, ptr);
135 return new_buff;
136}
137
138static void* NS(SELF, calloc)(SELF* self, size_t count, size_t size) {
139 // JUSTIFY:
140 // - We already zeroed the buffer in `new()`
141 return NS(SELF, malloc)(self, count * size);
142}
143
144#undef CAPACITY
145#undef USED
146
static void free(SELF *self, void *ptr)
Definition template.h:56
static void * realloc(SELF *self, void *ptr, size_t size)
Definition template.h:45
static void * malloc(SELF *self, size_t size)
Definition template.h:23
static void * calloc(SELF *self, size_t count, size_t size)
Definition template.h:34
static void clear(SELF *self)
Clear the allocator, note that all data should be freed before this occurs.
Definition template.h:52
static size_t metadata_size
Definition template.h:40
static USED get_used(SELF const *self)
Definition template.h:67
#define CAPACITY
A very simple bump allocator making use of a provided fixed size buffer (e.g. statically allocated).
Definition template.h:17
#define USED
Definition template.h:25
#define NS(pre, post)
Definition helpers.h:6
#define DEBUG_UNUSED(ident)
Definition helpers.h:11
#define DEBUG_ASSERT(expr)
Definition panic.h:34
#define PANIC(...)
Definition panic.h:7
#define SELF
Definition def.h:51
size_t used
Definition template.h:35
gdb_marker derive_c_staticbumpalloc
Definition template.h:37
char buffer[CAPACITY]
Definition template.h:36
static INDEX_TYPE size(SELF const *self)
Definition template.h:220