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