From 6b99bb6f7f63e8417042220a6c02eb43d48803d5 Mon Sep 17 00:00:00 2001
From: Talha Qamar <qamartalha@proton.me>
Date: Fri, 31 Jan 2025 21:17:28 +0500
Subject: [PATCH] Added Arena Allocator (crime against humanity)

---
 src/lily/alloc/arena.hb | 62 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 src/lily/alloc/arena.hb

diff --git a/src/lily/alloc/arena.hb b/src/lily/alloc/arena.hb
new file mode 100644
index 0000000..908a059
--- /dev/null
+++ b/src/lily/alloc/arena.hb
@@ -0,0 +1,62 @@
+.{Config, Target, Type, log, collections: .{Vec}} := @use("../lib.hb");
+
+Allocation := struct {
+	ptr: ^u8,
+	len: uint,
+}
+
+ArenaAllocator := struct {
+	ptr: ^u8,
+	size: uint,
+	allocated: uint,
+
+	$new := fn(size: uint): Self {
+		allocated := idk
+		if size == 0 {
+			allocated = Target.page_size()
+		} else {
+			allocated = size
+		}
+		ptr := Target.alloc_zeroed(size)
+		return .(ptr, size, 0)
+	}
+	deinit := fn(self: ^Self): void {
+		match Target.current() {
+			.LibC => Target.dealloc(self.ptr),
+			.AbleOS => Target.dealloc(self.ptr, self.size),
+		}
+		log.debug("deinit: allocator")
+	}
+	alloc := fn(self: ^Self, $T: type, count: uint): ?^T {
+		if count * @sizeof(T) + self.allocated > self.size {
+			log.error("You allocated more memory on the arena than the arena had.");
+			die
+		}
+		allocation := self.ptr + self.allocated
+		self.allocated = self.allocated + count * @sizeof(T)
+		log.debug("allocated")
+		return @bitcast(allocation)
+	}
+	alloc_zeroed := fn(self: ^Self, $T: type, count: uint): ?^T {
+		return self.alloc(T, count)
+	}
+	realloc := fn(self: ^Self, $T: type, ptr: ^T, count: uint): ?^T {
+		log.error("Don't call realloc on the arena allocator");
+		die
+	}
+	dealloc := fn(self: ^Self, $T: type, ptr: ^T): void {
+		log.debug("freed")
+	}
+	_find_and_remove := fn(self: ^Self, ptr: ^u8): ?Allocation {
+		i := 0
+		loop if i == self.allocations.len() break else {
+			defer i += 1
+			alloced := self.allocations.get_unchecked(i)
+			if alloced.ptr == ptr {
+				_ = self.allocations.swap_remove(i)
+				return alloced
+			}
+		}
+		return null
+	}
+}