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 {
    allocator: MyAllocator;
    allocator.handler = auto &my_allocator_handler;
    allocator.buffer = buffer;
    allocator.used_bytes = 0;
    return allocator;
}

my_allocator_handler :: fn (
    allocator: *MyAllocator,
    // Operation specify whether we do allocation or free.
    operation: AllocOp,
    // This is pointer to allocation to be freed, this value is set only when
    // operation is free.
    old_ptr: *u8,
    // Size of previous allocation (used for realloc).
    old_size: usize,
    // Count of bytes to be allocated, this value is set only when operation
    // is allocation.
    new_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   {
            return allocate(allocator, new_size, alignment);
        }
        REALLOCATE {
            mem, err :: allocate(allocator, new_size, alignment);
            if err { return mem, err; }
            if !old_ptr { return mem, OK; }
            memcpy(mem, old_ptr, old_size);
            return mem, OK;
        }
        FREE; // Nothing here
    }
    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.
    size += alignment - 1;
    // Calculate total size needed.
    needed_size :: allocator.used_bytes + 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 += size;
    // Align memory pointer.
    mem = auto ((cast(usize) mem) + alignment - 1 & mask);
    return mem, OK;
}

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

    str :: std.str_new("abc", &allocator);
    defer std.str_delete(&str);

    loop i := 0; i < 100; i += 1 {
        std.str_append(&str, i);
    }

    return 0;
}