aboutsummaryrefslogtreecommitdiff
path: root/memstack/src
diff options
context:
space:
mode:
Diffstat (limited to 'memstack/src')
-rw-r--r--memstack/src/memstack.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/memstack/src/memstack.c b/memstack/src/memstack.c
new file mode 100644
index 0000000..84131ef
--- /dev/null
+++ b/memstack/src/memstack.c
@@ -0,0 +1,119 @@
1#include "memstack.h"
2
3#include <cassert.h>
4
5#include <stdlib.h>
6#include <string.h>
7
8static bool is_pow2_or_0(size_t x) { return (x & (x - 1)) == 0; }
9
10/// Align the given address to the next address that is a multiple of the
11/// alignment. If the given address is already aligned, return the address.
12static uint8_t* align(uint8_t* address, size_t alignment) {
13 assert(is_pow2_or_0(alignment));
14 const size_t mask = alignment - 1;
15 return (uint8_t*)(((uintptr_t)address + mask) & ~mask);
16}
17
18bool memstack_make(memstack* stack, size_t capacity, void* memory) {
19 assert(stack);
20 assert(capacity >= 1);
21
22 // Allocate memory if not user-provided.
23 uint8_t* stack_memory = memory;
24 if (!stack_memory) {
25 stack_memory = calloc(1, capacity);
26 if (stack_memory == nullptr) {
27 return false;
28 }
29 }
30 assert(stack_memory);
31
32 stack->capacity = capacity;
33 stack->base = stack_memory;
34 stack->watermark = stack_memory;
35 stack->owned = (stack_memory != memory);
36 stack->trap = true;
37
38 return true;
39}
40
41void memstack_del(memstack* stack) {
42 assert(stack);
43
44 if (stack->owned && (stack->base != nullptr)) {
45 free(stack->base);
46 stack->base = nullptr;
47 stack->owned = false;
48 }
49
50 stack->capacity = 0;
51 stack->watermark = stack->base;
52}
53
54void memstack_clear(memstack* stack) {
55 assert(stack);
56
57 stack->watermark = stack->base;
58 memset(stack->base, 0, stack->capacity);
59}
60
61size_t memstack_watermark(const memstack* stack) {
62 assert(stack);
63 return stack->watermark - stack->base;
64}
65
66void memstack_set_watermark(memstack* stack, size_t watermark) {
67 assert(stack);
68 const bool fits = (watermark < stack->capacity);
69 if (stack->trap && !fits) {
70 FAIL("memstack watermark update failed, bad watermark");
71 }
72 assert(fits);
73 stack->watermark = stack->base + watermark;
74}
75
76void* memstack_alloc(memstack* stack, size_t bytes) {
77 assert(stack);
78
79 if ((memstack_size(stack) + bytes) > stack->capacity) {
80 if (stack->trap) {
81 FAIL("memstack allocation failed, increase the stack's capacity.");
82 }
83 return nullptr; // Block does not fit in remaining memory.
84 }
85
86 // Allocate the block.
87 uint8_t* const block = stack->watermark;
88 stack->watermark += bytes;
89 assert(memstack_size(stack) <= stack->capacity);
90
91 return block;
92}
93
94void* memstack_alloc_aligned(memstack* stack, size_t bytes, size_t alignment) {
95 assert(stack);
96
97 uint8_t* const new_watermark = align(stack->watermark, alignment);
98 assert(new_watermark >= stack->watermark);
99 assert((size_t)(new_watermark - stack->base) <= stack->capacity);
100 stack->capacity -= (new_watermark - stack->watermark);
101 stack->watermark = new_watermark;
102
103 return memstack_alloc(stack, bytes);
104}
105
106size_t memstack_size(const memstack* stack) {
107 assert(stack);
108 return stack->watermark - stack->base;
109}
110
111size_t memstack_capacity(const memstack* stack) {
112 assert(stack);
113 return stack->capacity;
114}
115
116void memstack_enable_traps(memstack* stack, bool enable) {
117 assert(stack);
118 stack->trap = enable;
119}