1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
#include "memstack.h"
#include <cassert.h>
#include <stdlib.h>
#include <string.h>
static bool is_pow2_or_0(size_t x) { return (x & (x - 1)) == 0; }
/// Align the given address to the next address that is a multiple of the
/// alignment. If the given address is already aligned, return the address.
static uint8_t* align(uint8_t* address, size_t alignment) {
assert(is_pow2_or_0(alignment));
const size_t mask = alignment - 1;
return (uint8_t*)(((uintptr_t)address + mask) & ~mask);
}
bool memstack_make(memstack* stack, size_t capacity, void* memory) {
assert(stack);
assert(capacity >= 1);
// Allocate memory if not user-provided.
uint8_t* stack_memory = memory;
if (!stack_memory) {
stack_memory = calloc(1, capacity);
if (stack_memory == nullptr) {
return false;
}
}
assert(stack_memory);
stack->capacity = capacity;
stack->base = stack_memory;
stack->watermark = stack_memory;
stack->owned = (stack_memory != memory);
stack->trap = true;
return true;
}
void memstack_del(memstack* stack) {
assert(stack);
if (stack->owned && (stack->base != nullptr)) {
free(stack->base);
stack->base = nullptr;
stack->owned = false;
}
stack->capacity = 0;
stack->watermark = stack->base;
}
void memstack_clear(memstack* stack) {
assert(stack);
stack->watermark = stack->base;
memset(stack->base, 0, stack->capacity);
}
void* memstack_alloc(memstack* stack, size_t bytes) {
assert(stack);
if ((memstack_size(stack) + bytes) > stack->capacity) {
if (stack->trap) {
FAIL("memstack allocation failed, increase the stack's capacity.");
}
return nullptr; // Block does not fit in remaining memory.
}
// Allocate the block.
uint8_t* const block = stack->watermark;
stack->watermark += bytes;
assert(memstack_size(stack) <= stack->capacity);
return block;
}
void* memstack_alloc_aligned(memstack* stack, size_t bytes, size_t alignment) {
assert(stack);
uint8_t* const new_watermark = align(stack->watermark, alignment);
assert(new_watermark >= stack->watermark);
assert((size_t)(new_watermark - stack->base) <= stack->capacity);
stack->watermark = new_watermark;
return memstack_alloc(stack, bytes);
}
size_t memstack_size(const memstack* stack) {
assert(stack);
return stack->watermark - stack->base;
}
size_t memstack_capacity(const memstack* stack) {
assert(stack);
return stack->capacity;
}
void memstack_enable_traps(memstack* stack, bool enable) {
assert(stack);
stack->trap = enable;
}
|