simple_allocator.blΒΆ

// Simple static allocator and executable context

/*
   Memory management in BL programs is handled by alocator function set in
   global context. Every allocation and free via alloc or free function call 
   ends up in default or custom allocator provided by context, so we can change
   the way memory allocates for whole program even for standart API function.

   This can be helpful during development when we want to track down all
   allocations or basically when we want to optimize memory usage of program.

   Following example shows simple allocator using static buffer.
*/

// Preallocate memory on stack
_buffer: [4098]u8;
_bi: usize;
my_allocator :: fn (
    // Operation specify whether we do allocation or free
    operation: AllocOp, 
    // Count of bytes to be allocated, this value is set only when operation
    // is allocation.
    size: usize, 
    // This is pointer to allocation to be freed, this value is set only when
    // operation is free
    ptr: *u8 = null, 
    // Source file where allocator was called.
    file := string_empty, 
    // Line in source file where allocator was called.
    line := 0) *u8 
{
    switch operation {
        AllocOp.Allocate {
            // We get address of free memory by shifting buffer pointer.
            if _bi >= auto _buffer.len { panic(); }
            mem :: ptr_shift_bytes(_buffer.ptr, auto _bi);
            _bi += size;
            print_log("Allocate % bytes called from %:%.", size, file, line);
            return mem;
        }
        AllocOp.Free {
            // We do not handle memory free in this example, just print
            // out log message.
            print_log("Free called from %:%.", file, line);
        }
        AllocOp.Release;
        default { panic(); }
    }
    return null; 
}

main :: fn () s32 {
    // Store original allocator and set new one.
    orig_allocator :: _context.alloc_fn;
    _context.alloc_fn = &my_allocator;
    defer _context.alloc_fn = orig_allocator;

    // All following allocations will use our custom allocator.
    str :: string_new("abc");
    defer string_delete(str);
    loop i := 0; i < 100; i += 1 {
        string_append(&str, i);
    }
    return 0;
}