199 lines
4.8 KiB
Text
199 lines
4.8 KiB
Text
#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 := meta.type_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 !meta.type_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_file;
|
|
|
|
// @note(judah): this will cause a cyclic import cycle if we import meta's module.jai
|
|
// @todo(judah): switch to abslote imports everywhere (ie. "jc/meta")
|
|
meta :: #import,file "../meta/type_info.jai";
|
|
|
|
|
|
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);
|
|
});
|
|
}
|