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