Derive-C
Loading...
Searching...
No Matches
template.h File Reference

Go to the source code of this file.

Data Structures

struct  SELF
 An allocator that prints to stdout when it allocates or frees memory. More...

Macros

#define CAPACITY   1024
 A very simple bump allocator making use of a provided fixed size buffer (e.g. statically allocated).
#define USED   uint8_t

Typedefs

typedef char buffer[CAPACITY]

Functions

static SELF new (buffer *buffer)
static void clear (SELF *self)
 Clear the allocator, note that all data should be freed before this occurs.
static USED get_used (SELF const *self)
static void * malloc (SELF *self, size_t size)
static void free (SELF *self, void *ptr)
static void * realloc (SELF *self, void *ptr, size_t new_size)
static void * calloc (SELF *self, size_t count, size_t size)
static void debug (SELF const *self, dc_debug_fmt fmt, FILE *stream)
 DC_TRAIT_ALLOC (SELF)

Variables

static size_t metadata_size = sizeof(USED)

Macro Definition Documentation

◆ CAPACITY

#define CAPACITY   1024

A very simple bump allocator making use of a provided fixed size buffer (e.g. statically allocated).

  • Useful when an upper bound for allocation size is known at compile time
  • Can be used when no global allocator is available (e.g. embedded systems, kernel dev)

Definition at line 17 of file template.h.

◆ USED

#define USED   uint8_t

Definition at line 25 of file template.h.

Typedef Documentation

◆ buffer

typedef char buffer[CAPACITY]

Definition at line 34 of file template.h.

Function Documentation

◆ calloc()

void * calloc ( SELF * self,
size_t count,
size_t size )
static

Definition at line 192 of file template.h.

192 {
193 // JUSTIFY:
194 // - We already zeroed the buffer in `new()`
195 return NS(SELF, malloc)(self, count * size);
196}
static void * malloc(SELF *self, size_t size)
Definition template.h:23
static INDEX_TYPE size(SELF const *self)
Definition template.h:252
#define NS(pre, post)
Definition namespace.h:4
#define SELF
Definition def.h:52

◆ clear()

void clear ( SELF * self)
static

Clear the allocator, note that all data should be freed before this occurs.

Definition at line 64 of file template.h.

64 {
65 DC_ASSUME(self);
66
67#if !defined NDEBUG
68 // JUSTIFY: Allocations & sizes zeroed on free in debug, we check all data has been freed.
70 (*self->buffer), self->used);
71 for (size_t i = 0; i < self->used; i++) {
72 if ((*self->buffer)[i] != 0) {
73 DC_PANIC("Data not freed before clearing the static bump allocator");
74 }
75 }
76#endif
78 self->used);
79 memset((*self->buffer), 0, self->used);
81 CAPACITY);
82 self->used = 0;
83}
#define CAPACITY
A very simple bump allocator making use of a provided fixed size buffer (e.g. statically allocated).
Definition template.h:17
static void dc_memory_tracker_set(dc_memory_tracker_level level, dc_memory_tracker_capability cap, const volatile void *addr, size_t size)
@ DC_MEMORY_TRACKER_LVL_ALLOC
@ DC_MEMORY_TRACKER_CAP_WRITE
@ DC_MEMORY_TRACKER_CAP_NONE
@ DC_MEMORY_TRACKER_CAP_READ_WRITE
#define DC_PANIC(...)
Definition panic.h:28
#define DC_ASSUME(expr,...)
Definition panic.h:56
size_t used
Definition template.h:37
buffer * buffer
Definition template.h:38

◆ DC_TRAIT_ALLOC()

DC_TRAIT_ALLOC ( SELF )

◆ debug()

void debug ( SELF const * self,
dc_debug_fmt fmt,
FILE * stream )
static

Definition at line 198 of file template.h.

198 {
199 fprintf(stream, STRINGIFY(SELF) "@%p {\n", self);
200 fmt = dc_debug_fmt_scope_begin(fmt);
201 dc_debug_fmt_print(fmt, stream, "capacity: %lu,\n", CAPACITY);
202 dc_debug_fmt_print(fmt, stream, "used: %lu,\n", self->used);
203 dc_debug_fmt_print(fmt, stream, "buffer: %p,\n", self->buffer);
204 fmt = dc_debug_fmt_scope_end(fmt);
205 dc_debug_fmt_print(fmt, stream, "}");
206}
dc_debug_fmt dc_debug_fmt_scope_end(dc_debug_fmt fmt)
Definition fmt.h:39
dc_debug_fmt dc_debug_fmt_scope_begin(dc_debug_fmt fmt)
Definition fmt.h:33
static void dc_debug_fmt_print(dc_debug_fmt fmt, FILE *stream, const char *format,...)
Definition fmt.h:22
#define STRINGIFY(MACRO)
Definition namespace.h:7
static FILE * stream(SELF *self)
Opens a file for.
Definition template.h:107

◆ free()

void free ( SELF * self,
void * ptr )
static

Definition at line 112 of file template.h.

112 {
113 DC_ASSUME(self);
114 DC_ASSUME(ptr);
115
116#if !defined NDEBUG
117 // JUSTIFY: Zero memory in debug.
118 // - Expensive for release, but helpful when debugging
119 // NOTE: This means that users should free, before they clear and reuse the buffer.
120 USED* used_ptr = (USED*)((char*)ptr - sizeof(USED));
122 sizeof(USED));
123 memset(ptr, 0, *used_ptr);
125 *used_ptr = 0;
127 sizeof(USED));
128#endif
129}
#define USED
Definition template.h:25

◆ get_used()

USED get_used ( SELF const * self)
static

Definition at line 85 of file template.h.

85 {
86 DC_ASSUME(self);
87 return self->used;
88}

◆ malloc()

void * malloc ( SELF * self,
size_t size )
static

Definition at line 90 of file template.h.

90 {
91 DC_ASSUME(self);
92 if (self->used + (size + sizeof(USED)) > CAPACITY) {
93 return NULL;
94 }
95 char* ptr = &(*self->buffer)[self->used];
96 USED* used_ptr = (USED*)ptr;
97
99 sizeof(USED));
100 *used_ptr = size;
101 char* allocation_ptr = ptr + sizeof(USED);
103 sizeof(USED));
104
105 self->used += size + sizeof(USED);
107 size);
108
109 return allocation_ptr;
110}

◆ new()

SELF new ( buffer * buffer)
static

Definition at line 44 of file template.h.

44 {
45 SELF self = {
46 .used = 0,
47 .buffer = buffer,
48 .derive_c_staticbumpalloc = {},
49 };
50 // JUSTIFY: Zeroed buffer
51 // - For easier debugging & view in gdb.
52 // - Additionally allows for calloc to be malloc.
53 memset(*self.buffer, 0, CAPACITY);
54
55 // JUSTIFY: no capabilities on init
56 // - Protect access by users outside of malloc/calloc
58 CAPACITY);
59
60 return self;
61}
char buffer[CAPACITY]
Definition template.h:34

◆ realloc()

void * realloc ( SELF * self,
void * ptr,
size_t new_size )
static

Definition at line 131 of file template.h.

131 {
132 DC_ASSUME(self);
133
134 if (!ptr) {
135 return NS(SELF, malloc)(self, new_size);
136 }
137
138 char* byte_ptr = (char*)ptr;
139 USED* old_size = (USED*)(byte_ptr - sizeof(USED));
141 sizeof(USED));
142 const bool was_last_alloc = (byte_ptr + *old_size == &(*self->buffer)[self->used]);
143
144 if (was_last_alloc) {
145 if (new_size > *old_size) {
146 size_t increase = new_size - *old_size;
147 if (self->used + increase > CAPACITY) {
148 return NULL;
149 }
150 self->used += increase;
152 (char*)ptr + *old_size, increase);
153 } else if (new_size < *old_size) {
154 size_t decrease = *old_size - new_size;
155 self->used -= decrease;
156
157 // JUSTIFY: Zeroing the end of the old allocation
158 // - Future calls to calloc may reuse this memory
159 memset((char*)ptr + new_size, 0, decrease);
160
162 (char*)ptr + new_size, decrease);
163 }
164
165 *old_size = new_size;
167 sizeof(USED));
168 return ptr;
169 }
170
171 if (new_size < *old_size) {
172 // JUSTIFY: Shrinking an allocation
173 // - Can become a noop - as we cannot re-extend the allocation
174 // afterwards - no metadata for unused capacity not at end of buffer.
175 *old_size = new_size;
177 sizeof(USED));
178 return ptr;
179 }
180
181 void* new_buff = NS(SELF, malloc)(self, new_size);
182 if (!new_buff) {
183 return NULL;
184 }
185
186 memcpy(new_buff, ptr, *old_size);
187
188 NS(SELF, free)(self, ptr);
189 return new_buff;
190}
static void free(SELF *self, void *ptr)
Definition template.h:56

Variable Documentation

◆ metadata_size

size_t metadata_size = sizeof(USED)
static

Definition at line 42 of file template.h.