summaryrefslogtreecommitdiff
path: root/source/base/base_stack.h
diff options
context:
space:
mode:
Diffstat (limited to 'source/base/base_stack.h')
-rwxr-xr-xsource/base/base_stack.h204
1 files changed, 197 insertions, 7 deletions
diff --git a/source/base/base_stack.h b/source/base/base_stack.h
index fc80b20..43a7230 100755
--- a/source/base/base_stack.h
+++ b/source/base/base_stack.h
@@ -1,20 +1,210 @@
1#ifndef STACK_H 1#ifndef STACK_H
2#define STACK_H 2#define STACK_H
3 3
4typedef struct mem_stack mem_stack;
5typedef struct mem_stack_header mem_stack_header; 4typedef struct mem_stack_header mem_stack_header;
5struct mem_stack_header
6{
7 u8 padding;
8 u8 previous_offset;
9};
10
6 11
12typedef struct mem_stack mem_stack;
7struct mem_stack 13struct mem_stack
8{ 14{
15 mem_stack_header *header;
16
17 u64 current_offset;
18 u64 capacity;
9 u8 *base_position; 19 u8 *base_position;
10 umm current_offset;
11 umm capacity;
12}; 20};
13 21
14struct mem_stack_header 22internal mem_stack *
23stack_create(u64 capacity)
15{ 24{
16 u8 padding; 25 mem_stack *stack = (mem_stack *)mmap(
17 u8 previous_offset; 26 0,
18}; 27 capacity + sizeof(mem_stack),
28 PROT_READ | PROT_WRITE,
29 MAP_SHARED | MAP_ANONYMOUS,
30 -1,
31 0);
32
33 if (stack == MAP_FAILED)
34 {
35 return NULL;
36 }
37
38 stack->capacity = capacity;
39 stack->base_position = (u8 *)stack + sizeof(mem_stack);
40 stack->current_offset = 0;
41
42 return stack;
43}
44
45internal u8
46calculate_padding(u64 pointer, u8 alignment, u64 header_size)
47{
48 u8 modulo, padding;
49
50 if (!is_pow(alignment))
51 {
52 return 0;
53 }
54
55 modulo = pointer & (u8)(alignment - 1);
56
57 padding = 0;
58
59 if (0 == modulo)
60 {
61 padding = alignment - modulo;
62 }
63
64 if (padding < header_size)
65 {
66 header_size -= padding;
67
68 if ((header_size & (alignment - 1)) != 0)
69 {
70 padding += alignment * (1 + (header_size / alignment));
71 }
72 else
73 {
74 padding += alignment * (header_size / alignment);
75 }
76 }
77
78 return padding;
79}
80
81internal mem_stack *
82stack_push_align(mem_stack *stack, u64 size, u8 alignment)
83{
84 u8 padding = 0;
85
86 if (!is_pow(alignment))
87 {
88 return (0);
89 }
90
91 if (alignment > 128)
92 {
93 alignment = 128;
94 }
95
96 u64 current_address = (u64)stack->base_position + stack->current_offset;
97 padding = calculate_padding(current_address, alignment, sizeof(mem_stack_header));
98
99 if (stack->current_offset + padding + size > stack->capacity)
100 {
101 return 0;
102 }
103
104 stack->current_offset += padding;
105
106 u64 next_address = current_address + (u64)padding;
107 mem_stack_header *header = (mem_stack_header *)(next_address - sizeof(mem_stack_header));
108 header->padding = padding;
109
110 stack->current_offset += size;
111
112 return MemSet((void *)next_address, size);
113}
114internal void *
115stack_push(mem_stack *stack, u64 size)
116{
117 return stack_push_align(stack, size, ARENA_ALIGN);
118}
119
120internal void
121stack_pop(mem_stack *stack, void *pointer)
122{
123 if (pointer != NULL)
124 {
125 u64 start, end, current_address;
126 mem_stack_header *header;
127 u64 prev_offset;
128
129 start = (u64)stack->base_position;
130 end = start + (u64)stack->capacity;
131 current_address = (u64)pointer;
132
133 if (!(start <= current_address && current_address < end))
134 {
135 if (0 && "Out of bounds memory address passed to stack allocator (free)")
136 {
137 return;
138 }
139 return;
140 }
141
142 if (current_address >= start + (u64)stack->base_position)
143 {
144 return;
145 }
146
147 header = (mem_stack_header *)(current_address - sizeof(mem_stack_header));
148 prev_offset = (size_t)(current_address - (u64)header->padding - start);
149 stack->current_offset = prev_offset;
150 }
151}
152
153internal mem_stack *
154stack_resize_align(mem_stack *stack, void *pointer, u64 old_size, u64 new_size, u8 alignment)
155{
156 if (pointer == NULL)
157 {
158 return stack_push_align(stack, new_size, alignment);
159 }
160 else if (new_size == 0)
161 {
162 stack_pop(stack, pointer);
163 return NULL;
164 }
165
166 u64 start, end, current_address;
167 u64 min_size = old_size < new_size ? old_size : new_size;
168 void *new_pointer;
169
170 start = (u64)stack->base_position;
171 end = start + (u64)stack->capacity;
172 current_address = (u64)pointer;
173 if (!(start <= current_address && current_address < end))
174 {
175 return NULL;
176 }
177
178 if (current_address >= start + (u64)stack->current_offset)
179 {
180 return NULL;
181 }
182
183 if (old_size == new_size)
184 {
185 return pointer;
186 }
187
188 new_pointer = stack_push_align(stack, new_size, alignment);
189 memmove(new_pointer, pointer, min_size);
190 return new_pointer;
191}
192
193internal void
194stack_pop_all(mem_stack *stack)
195{
196 stack->current_offset = 0;
197}
198
199internal void
200stack_destroy(mem_stack *stack)
201{
202 if (!stack)
203 {
204 return;
205 }
206
207 munmap(stack, stack->capacity + sizeof(mem_stack));
208}
19 209
20#endif 210#endif