Simple Allocator

Compile using blc my-file-name.bl and run ./out.

MyAllocator :: struct #base Allocator {
	buffer: []u8;
	used_bytes: usize;
}

allocator_make :: fn (buffer: []u8) MyAllocator {
	return MyAllocator.{
		base = Allocator.{ auto &my_allocator_handler },
		buffer = buffer,
		used_bytes = 0,
	};
}

my_allocator_handler :: fn (
	allocator: *MyAllocator,
	// Operation specify whether we do allocation or free.
	operation: AllocOp,
	// Pointer to the previously allocated memory. 
	_: *u8,
	// Count of bytes to be allocated.
	size: usize,
	// Allocation allignment.
	alignment: usize,
	// Source file where allocator was called.
	file: string_view,
	// Line in source file where allocator was called.
	line: s32) (mem: *u8, err: Error)
{
	using AllocOp;
	switch operation {
		ALLOCATE   {
			print("Allocate %B called from %:%.", size, file, line);
			return allocate(allocator, size, alignment);
		}
		REALLOCATE {
			// To properly support reallocation, we have to store additional metadata
			// containing the size of the previous allocated memory associated with input
			// ptr pointer.
			// This is not implemented in this example to keep things simple.
			panic("Rellocation is not supported.");
		}
		FREE {
			print("Free called from %:%.", file, line);
		}
		RESET, RELEASE {
			panic("Unsupported operation: %.", operation);
		}

		default { panic("Unknown operation."); }
	}
	return null, OK;
}

allocate :: fn (allocator: *MyAllocator, size: usize, alignment: usize) (mem: *u8, err: Error) {
	// Alignment mask.
	mask :: ~(alignment - 1);
	// We need some additional space to properly align the allocation.
	adjusted_size :: size + alignment - 1;
	// Calculate total size needed.
	needed_size :: allocator.used_bytes + adjusted_size;
	// Check if there is space enough in out buffer.
	if needed_size > auto allocator.buffer.len {
		return null, error("The buffer is full! The buffer size is %B and required size is %B.", allocator.buffer.len, needed_size);
	}
	// Get free memory pointer.
	mem := &allocator.buffer[auto allocator.used_bytes];
	// Adjust used size.
	allocator.used_bytes += adjusted_size;
	// Align memory pointer.
	mem = auto ((cast(usize) mem) + alignment - 1 & mask);
	return mem, OK;
}

User :: struct {
	name: string_view;
	age: s32;
}

main :: fn () s32 {
	buffer: [2048]u8;
	allocator :: allocator_make(buffer);

	user :: new(User, true, &allocator);
	user.name = "Martin.";
	user.age = 32;

	print("User = %\n", @user);

	free(auto user, &allocator);
	return 0;
}