parent
12280219cb
commit
dbfe13af58
4 changed files with 114 additions and 92 deletions
@ -0,0 +1,78 @@ |
|||||||
|
const std = @import("std"); |
||||||
|
const Allocator = std.mem.Allocator; |
||||||
|
|
||||||
|
const c = @import("./c.zig"); |
||||||
|
|
||||||
|
pub var is_setup = false; |
||||||
|
pub var allocator: Allocator = undefined; |
||||||
|
|
||||||
|
pub fn setup(allocator_: Allocator) void { |
||||||
|
if (is_setup) std.debug.panic("setup must only be called once", .{}); |
||||||
|
is_setup = true; |
||||||
|
allocator = allocator_; |
||||||
|
|
||||||
|
c.ecs_os_set_api_defaults(); |
||||||
|
var os_api = c.ecs_os_api; |
||||||
|
os_api.malloc_ = flecsMalloc; |
||||||
|
os_api.realloc_ = flecsRealloc; |
||||||
|
os_api.calloc_ = flecsCalloc; |
||||||
|
os_api.free_ = flecsFree; |
||||||
|
c.ecs_os_set_api(&os_api); |
||||||
|
_ = c.ecs_log_set_level(-1); // No tracing. |
||||||
|
} |
||||||
|
|
||||||
|
fn flecsMalloc(size: i32) callconv(.C) ?*anyopaque { |
||||||
|
if (size == 0) return null; |
||||||
|
return allocLengthEncodedSlice(size, null).ptr; |
||||||
|
} |
||||||
|
|
||||||
|
fn flecsRealloc(ptr: ?*anyopaque, size: i32) callconv(.C) ?*anyopaque { |
||||||
|
if (size == 0) { |
||||||
|
flecsFree(ptr); |
||||||
|
return null; |
||||||
|
} else { |
||||||
|
const old = if (ptr) |p| sliceFromPtr(p) else null; |
||||||
|
return allocLengthEncodedSlice(size, old).ptr; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn flecsCalloc(size: i32) callconv(.C) ?*anyopaque { |
||||||
|
if (size == 0) return null; |
||||||
|
const slice = allocLengthEncodedSlice(size, null); |
||||||
|
@memset(slice, 0); |
||||||
|
return slice.ptr; |
||||||
|
} |
||||||
|
|
||||||
|
fn flecsFree(ptr: ?*anyopaque) callconv(.C) void { |
||||||
|
if (ptr) |p| { |
||||||
|
const slice = sliceFromPtr(p); |
||||||
|
allocator.free(slice); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Reserves an additional `@sizeOf(i32)` bytes, which is used to store the |
||||||
|
/// length so we can use a simple pointer offset to "encode" the full slice |
||||||
|
/// information (including length) into just a single pointer. |
||||||
|
/// |
||||||
|
/// Optionally allows passing a slice to be reallocated into this new slice. |
||||||
|
/// The `old_slice` must be the full slice as returned by `sliceFromPtr(...)`. |
||||||
|
/// |
||||||
|
/// Returns the pointer from the offset where the actual data is stored. |
||||||
|
/// This allows manipulating the contents, such as zeroing it out. |
||||||
|
fn allocLengthEncodedSlice(size: i32, old_slice: ?[]align(@sizeOf(i32)) u8) []u8 { |
||||||
|
const slice_len = @sizeOf(i32) + @as(usize, @intCast(size)); |
||||||
|
const slice = if (old_slice) |old| |
||||||
|
allocator.realloc(old, slice_len) catch @panic("OOM") |
||||||
|
else |
||||||
|
allocator.allocWithOptions(u8, slice_len, @sizeOf(i32), null) catch @panic("OOM"); |
||||||
|
@as([*]i32, @ptrCast(slice.ptr))[0] = size; |
||||||
|
return slice[@sizeOf(i32)..]; |
||||||
|
} |
||||||
|
|
||||||
|
/// Recovers the original slice that was allocated by `allocSlice` to get the |
||||||
|
/// specified pointer. Returns the full slice including the "encoded" length. |
||||||
|
fn sliceFromPtr(ptr: *anyopaque) []align(@sizeOf(i32)) u8 { |
||||||
|
const slice_ptr = @as([*]align(@sizeOf(i32)) u8, @alignCast(@ptrCast(ptr))) - @sizeOf(i32); |
||||||
|
const slice_len = @as([*]i32, @ptrCast(slice_ptr))[0]; |
||||||
|
return slice_ptr[0..(@sizeOf(i32) + @as(usize, @intCast(slice_len)))]; |
||||||
|
} |
Loading…
Reference in new issue