@ -1,3 +1,6 @@
const std = @import ( " std " ) ;
const Allocator = std . mem . Allocator ;
pub usingnamespace @import ( " ./component.zig " ) ;
pub usingnamespace @import ( " ./entity.zig " ) ;
pub usingnamespace @import ( " ./id.zig " ) ;
@ -28,7 +31,72 @@ pub fn Lookup(comptime ctx: anytype, comptime T: type) type {
} ;
}
pub var is_initialized = false ;
pub var allocator : Allocator = undefined ;
/ / / Ensures that some global settings are set up to interface with Flecs .
/ / / Must be called before creating a ` World ` . Subsequent calls are a no - op .
pub fn init ( alloc : Allocator ) void {
if ( is_initialized ) {
std . debug . assert ( allocator . ptr = = alloc . ptr ) ;
return ;
}
is_initialized = true ;
allocator = alloc ;
c . ecs_os_api . malloc_ = flecsMalloc ;
c . ecs_os_api . realloc_ = flecsRealloc ;
c . ecs_os_api . calloc_ = flecsCalloc ;
c . ecs_os_api . free_ = flecsFree ;
}
fn flecsMalloc ( size : i32 ) callconv ( . C ) ? * anyopaque {
return allocLengthEncodedSlice ( size , null ) . ptr ;
}
fn flecsRealloc ( ptr : ? * anyopaque , size : i32 ) callconv ( . C ) ? * anyopaque {
return allocLengthEncodedSlice ( size , sliceFromPtr ( ptr . ? ) ) . ptr ;
}
fn flecsCalloc ( size : i32 ) callconv ( . C ) ? * anyopaque {
var slice = allocLengthEncodedSlice ( size , null ) ;
@memset ( slice , 0 ) ;
return slice . ptr ;
}
fn flecsFree ( ptr : ? * anyopaque ) callconv ( . C ) void {
const slice = sliceFromPtr ( ptr . ? ) ;
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 : ? [ ] u8 ) [ ] u8 {
const slice_len = @as ( usize , @intCast ( size ) ) + @sizeOf ( i32 ) ;
const slice = if ( old_slice ) | old |
allocator . realloc ( old , slice_len ) catch @panic ( " OOM " )
else
allocator . allocWithOptions ( u8 , slice_len , @alignOf ( i32 ) , null ) catch @panic ( " OOM " ) ;
@as ( * i32 , @alignCast ( @ptrCast ( slice . ptr ) ) ) . * = 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 ) [ ] u8 {
const slice_ptr = @as ( [ * ] align ( @alignOf ( i32 ) ) u8 , @alignCast ( @ptrCast ( ptr ) ) ) - @sizeOf ( i32 ) ;
const slice_len : usize = @intCast ( @as ( * i32 , @ptrCast ( slice_ptr ) ) . * ) ;
return slice_ptr [ 0 . . ( slice_len + @sizeOf ( i32 ) ) ] ;
}
test {
const std = @import ( " std " ) ;
std . testing . refAllDecls ( @This ( ) ) ;
}