#module_parameters(RUN_TESTS := false); Kilobyte :: 1024; Megabyte :: 1024 * Kilobyte; Gigabyte :: 1024 * Megabyte; Default_Align :: #run 2 * align_of(*void); align_of :: ($T: Type) -> u64 #expand { return #run -> u64 { info := type_info(struct{ p: u8; t: T; }); return info.members[1].offset_in_bytes.(u64); }; } default_of :: ($T: Type) -> T #expand { default: T; return default; } zero_of :: ($T: Type) -> T #expand { zero: T = ---; memset(*zero, 0, size_of(T)); return zero; } bitcast :: ($T: Type, expr: Code) -> T #expand { value := expr; return (*value).(*T).*; } power_of_two :: (x: u64) -> bool { if x == 0 return false; return x & (x - 1) == 0; } align_forward :: (ptr: u64, align: u64 = Default_Align) -> u64 { basic.assert(power_of_two(align), "alignment must be a power of two"); p := ptr; mod := p & (align - 1); if mod != 0 then p += align - mod; return p; } init_or_zero :: inline (ptr: *$T, custom_init: (*T) = null) { init :: initializer_of(T); if custom_init != null { custom_init(ptr); } #if init != null { inline init(ptr); } else { memset(ptr, 0, size_of(T)); } } make :: ($T: Type, reserved := 0, $init := true) -> [..]T #modify { ok, info := types.is_array(T); if ok && info.array_type == .RESIZABLE { T = compiler.get_type(info.element_type); return true; } return false; } { size := align_forward(size_of(T) * basic.max(reserved, 0).(u64)).(s64); data := basic.alloc(size); #if init if size != 0 { memset(data, 0, size); } arr: [..]T; arr.data = data; arr.count = 0; arr.allocated = size / size_of(T); arr.allocator = context.allocator; return arr; } make :: ($T: Type, $init := true) -> *T #modify { return !types.is_array(T); } { ptr := basic.alloc(size_of(T)).(*T); #if init init_or_zero(ptr); return ptr; } Crash_Allocator :: Allocator.{ proc = crash_allocator_proc }; crash_allocator_proc :: (mode: Allocator_Mode, size: s64, old_size: s64, old_memory: *void, allocator_data: *void) -> *void { message: string; if mode == { case .ALLOCATE; message = basic.tprint("Attempt to allocate % byte(s) using the crash allocator!", size); case .RESIZE; message = basic.tprint("Attempt to resize (from % to % byte(s)) using the crash allocator!", old_size, size); case .FREE; message = basic.tprint("Attempt to free % byte(s) using the crash allocator!", size); } basic.assert(false, message); debug_break(); return null; } Arena :: struct { memory: *void; memory_size: u64; offset: u64; } init_arena :: (a: *Arena, memory: *void, size: u64) { a.memory = memory; a.memory_size = size; a.offset = 0; } arena_allocator_proc :: (mode: Allocator_Mode, size: s64, old_size: s64, old_memory: *void, allocator_data: *void) -> *void { arena := allocator_data.(*Arena); if mode == { case .ALLOCATE; return arena_alloc(arena, size); case .RESIZE; if old_memory == null { return arena_alloc(arena, size); } if size == 0 { return null; } if size == old_size { return old_memory; } new_memory := arena_alloc(arena, size); memcpy(new_memory, old_memory, old_size); return new_memory; case; } return null; } arena_alloc :: (a: *Arena, count: int, alignment := Default_Align, loc := #caller_location) -> *void { basic.assert(a.memory != null, "arena: not initialized", loc = loc); basic.assert(power_of_two(alignment)); end := a.memory.(*u8) + a.offset; ptr := align_forward(end.(u64), alignment); total_size := (count + ptr.(*u8) - end.(*u8)).(u64); basic.assert(a.offset + total_size <= a.memory_size, "arena: out of memory", loc = loc); a.offset += total_size; return ptr.(*void); } #scope_module; types :: #import,file "../types/module.jai"; #scope_file; basic :: #import "Basic"; // @future compiler :: #import "Compiler"; // @future #if RUN_TESTS #run { test :: #import,file "../test/module.jai"; test.run("make:dynamic arrays", (t) => { a1 := make([..]int); test.expect(t, a1.count == 0); test.expect(t, a1.allocated == 0); basic.array_add(*a1, 10, 20, 30); test.expect(t, a1.count == 3); test.expect(t, a1.allocated != 0, "%", a1.allocated); a2 := make([..]int, 8); test.expect(t, a2.count == 0); test.expect(t, a2.allocated == 8); }); test.run("make:values", (t) => { v1 := make(int); test.expect(t, v1.* == 0); }); }