]> git.bts.cx Git - benzene.git/blob - src/bz/memory/arena.c
Sprites
[benzene.git] / src / bz / memory / arena.c
1 #include <bz/memory/arena_internal.h>
2
3 #include <bz/memory/allocator.h>
4 #include <bz/types/identifier_internal.h>
5 #include <stdalign.h>
6 #include <stddef.h>
7 #include <string.h> // memset... :rolleyes:
8
9 /*struct BZExpandedPointer {
10 BZMemoryArenaID arena;
11 uint8_t data[];
12 };
13 typedef struct BZExpandedPointer BZExpandedPointer;*/
14
15 //const size_t kMaxUserArenas = 32;
16 #define kMaxUserArenas 32 // FIXME
17 static BZMemoryArena userArenas[kMaxUserArenas];
18 static size_t nextUserArena = 0;
19
20 BZMemoryArenaID kBZSystemMemoryArena = &userArenas[0];
21
22 static size_t allocateSize(size_t size) {
23 size_t alignment = alignof(max_align_t); // FIXME, check this alignment stuff...
24 size_t alignmentPadding = (alignment - (size % alignment)) % alignment;
25 size_t fullSize = size + alignmentPadding;// + sizeof(BZExpandedPointer);
26 return fullSize;
27 }
28
29 BZMemoryArenaID bzMemoryArenaCreate(BZMemoryArenaID hostArena, size_t size, const char *nameFmt, ...) {
30 bzAssert(size == allocateSize(size));
31 if (nextUserArena < kMaxUserArenas) {
32 BZMemoryArenaID arena = bzMemoryArenaAllocate(&userArenas[++nextUserArena], hostArena, size);
33 bzInsertIdentifier(((char *)arena->identifier), nameFmt);
34 return arena;
35 } else {
36 bzError("Too many arenas");
37 return NULL;
38 }
39 }
40
41 void bzMemoryArenaReset(BZMemoryArenaID arena) {
42 bzMemoryArenaSetup(arena, arena->memory, arena->maxSize, arena->zeroOut);
43 }
44
45 void bzMemoryArenaResetTmp(BZMemoryArenaID arena) {
46 if (arena->zeroOut) {
47 memset(&arena->memory[arena->maxSize - arena->allocationOffsetTop], 0, arena->allocationOffsetTop);
48 }
49 arena->allocationOffsetTop = 0;
50 }
51
52 BZMemoryArenaID bzMemoryArenaSetup(BZMemoryArena *arenaOut, void *memory, size_t size, bool zeroOut) {
53 arenaOut->maxSize = size;
54 arenaOut->memory = memory;
55 arenaOut->numWatermarks = 0;
56 arenaOut->zeroOut = zeroOut;
57
58 arenaOut->allocationOffsetBottom = 0;
59 arenaOut->allocationOffsetTop = 0;
60
61 if (arenaOut->zeroOut) {
62 // We're gonna interop with C++, so we really need to do this.
63 memset(memory, 0, size);
64 }
65
66 return arenaOut;
67 }
68
69 BZMemoryArenaID bzMemoryArenaAllocate(BZMemoryArena *arenaOut, BZMemoryArenaID arenaFrom, size_t size) {
70 void *memory = bzMemoryAlloc(arenaFrom, size);
71 return bzMemoryArenaSetup(arenaOut, memory, size, true);
72 }
73
74 void bzMemoryArenaPushWatermark(BZMemoryArenaID arena) {
75 if (arena->numWatermarks < MAX_WATERMARKS) {
76 arena->watermarks[arena->numWatermarks++] = arena->allocationOffsetBottom;
77 } else {
78 bzError("Watermarked too many times!!");
79 }
80 }
81
82 void bzMemoryArenaPopWatermark(BZMemoryArenaID arena) {
83 if (arena->numWatermarks > 0) {
84 size_t lastAllocation = arena->allocationOffsetBottom;
85 arena->allocationOffsetBottom = arena->watermarks[--arena->numWatermarks];
86
87 if (arena->zeroOut) {
88 // We're gonna interop with C++, so we really need to do this.
89 // Zero out anything that got used.
90 memset(&arena->memory[arena->allocationOffsetBottom], 0, lastAllocation - arena->allocationOffsetBottom);
91 }
92 } else {
93 bzError("Watermarked too many times!!");
94 }
95 }
96
97 void *_bzMemoryAlloc(BZMemoryArenaID arena, size_t size, const char *filename, size_t lineNumber) {
98 bzAssertMessage(arena != NULL, "No memory arena");
99
100 size_t fullSize = allocateSize(size);
101
102 void *ptr = NULL;
103 if (arena == kBZSystemMemoryArena) {
104 ptr = bzSystemAllocate(fullSize);
105 // if (arena->zeroOut) {
106 memset(ptr, 0, fullSize); // Just do this one...
107 // }
108 } else if (arena->allocationOffsetBottom + fullSize <= arena->maxSize - arena->allocationOffsetTop) {
109 ptr = &arena->memory[arena->allocationOffsetBottom];
110 arena->allocationOffsetBottom += fullSize;
111 }
112
113 bzAssertMessage(ptr != NULL, "Arena '%s' is out of memory, failed %s:%d", arena->identifier, filename, lineNumber);
114
115 return ptr;
116 }
117
118 void *_bzMemoryAllocTmp(BZMemoryArenaID arena, size_t size, const char *filename, size_t lineNumber) {
119 bzAssertMessage(arena != NULL, "No memory arena");
120
121 size_t fullSize = allocateSize(size);
122
123 void *ptr = NULL;
124 if (arena == kBZSystemMemoryArena) {
125 ptr = bzSystemAllocateStack(fullSize);
126 } else if (arena->maxSize - arena->allocationOffsetTop - fullSize >= arena->allocationOffsetBottom) {
127 arena->allocationOffsetTop += fullSize;
128 ptr = &arena->memory[arena->maxSize - arena->allocationOffsetTop];
129 }
130
131 bzAssertMessage(ptr != NULL, "Arena is out of memory, failed %s:%d", filename, lineNumber);
132
133 return ptr;
134 } // FIXME, this won't work if you pass arena to other places, need more watermarking??....
135
136
137 //void bzMemoryFree(void *p) {
138 // void *ptr = p;
139 // ptr -= sizeof(BZExpandedPointer);
140
141 // if (*(BZMemoryArenaID *)ptr == kBZSystemMemoryArena) {
142 // free(ptr);
143 // } else {
144 // bzLog("Asked to free arena memory that cannot be");
145 // }
146 //}