mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 20:00:09 +00:00
Remove unneeded semicolons from the core library
This commit is contained in:
+86
-86
@@ -35,7 +35,7 @@ Calling_Convention :: enum u8 {
|
||||
Naked = 7,
|
||||
}
|
||||
|
||||
Type_Info_Enum_Value :: distinct i64;
|
||||
Type_Info_Enum_Value :: distinct i64
|
||||
|
||||
Platform_Endianness :: enum u8 {
|
||||
Platform = 0,
|
||||
@@ -44,9 +44,9 @@ Platform_Endianness :: enum u8 {
|
||||
}
|
||||
|
||||
// Procedure type to test whether two values of the same type are equal
|
||||
Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool;
|
||||
Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool
|
||||
// Procedure type to hash a value, default seed value is 0
|
||||
Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr = 0) -> uintptr;
|
||||
Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr = 0) -> uintptr
|
||||
|
||||
Type_Info_Struct_Soa_Kind :: enum u8 {
|
||||
None = 0,
|
||||
@@ -61,33 +61,33 @@ Type_Info_Named :: struct {
|
||||
base: ^Type_Info,
|
||||
pkg: string,
|
||||
loc: Source_Code_Location,
|
||||
};
|
||||
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness};
|
||||
Type_Info_Rune :: struct {};
|
||||
Type_Info_Float :: struct {endianness: Platform_Endianness};
|
||||
Type_Info_Complex :: struct {};
|
||||
Type_Info_Quaternion :: struct {};
|
||||
Type_Info_String :: struct {is_cstring: bool};
|
||||
Type_Info_Boolean :: struct {};
|
||||
Type_Info_Any :: struct {};
|
||||
Type_Info_Type_Id :: struct {};
|
||||
}
|
||||
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness}
|
||||
Type_Info_Rune :: struct {}
|
||||
Type_Info_Float :: struct {endianness: Platform_Endianness}
|
||||
Type_Info_Complex :: struct {}
|
||||
Type_Info_Quaternion :: struct {}
|
||||
Type_Info_String :: struct {is_cstring: bool}
|
||||
Type_Info_Boolean :: struct {}
|
||||
Type_Info_Any :: struct {}
|
||||
Type_Info_Type_Id :: struct {}
|
||||
Type_Info_Pointer :: struct {
|
||||
elem: ^Type_Info, // nil -> rawptr
|
||||
};
|
||||
}
|
||||
Type_Info_Multi_Pointer :: struct {
|
||||
elem: ^Type_Info,
|
||||
};
|
||||
}
|
||||
Type_Info_Procedure :: struct {
|
||||
params: ^Type_Info, // Type_Info_Tuple
|
||||
results: ^Type_Info, // Type_Info_Tuple
|
||||
variadic: bool,
|
||||
convention: Calling_Convention,
|
||||
};
|
||||
}
|
||||
Type_Info_Array :: struct {
|
||||
elem: ^Type_Info,
|
||||
elem_size: int,
|
||||
count: int,
|
||||
};
|
||||
}
|
||||
Type_Info_Enumerated_Array :: struct {
|
||||
elem: ^Type_Info,
|
||||
index: ^Type_Info,
|
||||
@@ -95,13 +95,13 @@ Type_Info_Enumerated_Array :: struct {
|
||||
count: int,
|
||||
min_value: Type_Info_Enum_Value,
|
||||
max_value: Type_Info_Enum_Value,
|
||||
};
|
||||
Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int};
|
||||
Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int};
|
||||
}
|
||||
Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int}
|
||||
Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int}
|
||||
Type_Info_Tuple :: struct { // Only used for procedures parameters and results
|
||||
types: []^Type_Info,
|
||||
names: []string,
|
||||
};
|
||||
}
|
||||
|
||||
Type_Info_Struct :: struct {
|
||||
types: []^Type_Info,
|
||||
@@ -119,7 +119,7 @@ Type_Info_Struct :: struct {
|
||||
soa_kind: Type_Info_Struct_Soa_Kind,
|
||||
soa_base_type: ^Type_Info,
|
||||
soa_len: int,
|
||||
};
|
||||
}
|
||||
Type_Info_Union :: struct {
|
||||
variants: []^Type_Info,
|
||||
tag_offset: uintptr,
|
||||
@@ -130,44 +130,44 @@ Type_Info_Union :: struct {
|
||||
custom_align: bool,
|
||||
no_nil: bool,
|
||||
maybe: bool,
|
||||
};
|
||||
}
|
||||
Type_Info_Enum :: struct {
|
||||
base: ^Type_Info,
|
||||
names: []string,
|
||||
values: []Type_Info_Enum_Value,
|
||||
};
|
||||
}
|
||||
Type_Info_Map :: struct {
|
||||
key: ^Type_Info,
|
||||
value: ^Type_Info,
|
||||
generated_struct: ^Type_Info,
|
||||
key_equal: Equal_Proc,
|
||||
key_hasher: Hasher_Proc,
|
||||
};
|
||||
}
|
||||
Type_Info_Bit_Set :: struct {
|
||||
elem: ^Type_Info,
|
||||
underlying: ^Type_Info, // Possibly nil
|
||||
lower: i64,
|
||||
upper: i64,
|
||||
};
|
||||
}
|
||||
Type_Info_Simd_Vector :: struct {
|
||||
elem: ^Type_Info,
|
||||
elem_size: int,
|
||||
count: int,
|
||||
};
|
||||
}
|
||||
Type_Info_Relative_Pointer :: struct {
|
||||
pointer: ^Type_Info,
|
||||
base_integer: ^Type_Info,
|
||||
};
|
||||
}
|
||||
Type_Info_Relative_Slice :: struct {
|
||||
slice: ^Type_Info,
|
||||
base_integer: ^Type_Info,
|
||||
};
|
||||
}
|
||||
|
||||
Type_Info_Flag :: enum u8 {
|
||||
Comparable = 0,
|
||||
Simple_Compare = 1,
|
||||
};
|
||||
Type_Info_Flags :: distinct bit_set[Type_Info_Flag; u32];
|
||||
}
|
||||
Type_Info_Flags :: distinct bit_set[Type_Info_Flag; u32]
|
||||
|
||||
Type_Info :: struct {
|
||||
size: int,
|
||||
@@ -247,9 +247,9 @@ Typeid_Kind :: enum u8 {
|
||||
|
||||
// NOTE(bill): only the ones that are needed (not all types)
|
||||
// This will be set by the compiler
|
||||
type_table: []Type_Info;
|
||||
type_table: []Type_Info
|
||||
|
||||
args__: []cstring;
|
||||
args__: []cstring
|
||||
|
||||
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
|
||||
|
||||
@@ -260,7 +260,7 @@ Source_Code_Location :: struct {
|
||||
procedure: string,
|
||||
}
|
||||
|
||||
Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location) -> !;
|
||||
Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location) -> !
|
||||
|
||||
// Allocation Stuff
|
||||
Allocator_Mode :: enum byte {
|
||||
@@ -272,7 +272,7 @@ Allocator_Mode :: enum byte {
|
||||
Query_Info,
|
||||
}
|
||||
|
||||
Allocator_Mode_Set :: distinct bit_set[Allocator_Mode];
|
||||
Allocator_Mode_Set :: distinct bit_set[Allocator_Mode]
|
||||
|
||||
Allocator_Query_Info :: struct {
|
||||
pointer: rawptr,
|
||||
@@ -291,7 +291,7 @@ Allocator_Error :: enum byte {
|
||||
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int,
|
||||
location: Source_Code_Location = #caller_location) -> ([]byte, Allocator_Error);
|
||||
location: Source_Code_Location = #caller_location) -> ([]byte, Allocator_Error)
|
||||
Allocator :: struct {
|
||||
procedure: Allocator_Proc,
|
||||
data: rawptr,
|
||||
@@ -319,8 +319,8 @@ Logger_Option :: enum {
|
||||
Thread_Id,
|
||||
}
|
||||
|
||||
Logger_Options :: bit_set[Logger_Option];
|
||||
Logger_Proc :: #type proc(data: rawptr, level: Logger_Level, text: string, options: Logger_Options, location := #caller_location);
|
||||
Logger_Options :: bit_set[Logger_Option]
|
||||
Logger_Proc :: #type proc(data: rawptr, level: Logger_Level, text: string, options: Logger_Options, location := #caller_location)
|
||||
|
||||
Logger :: struct {
|
||||
procedure: Logger_Proc,
|
||||
@@ -386,63 +386,63 @@ foreign {
|
||||
|
||||
type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil {
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
base := info;
|
||||
base := info
|
||||
loop: for {
|
||||
#partial switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base;
|
||||
case: break loop;
|
||||
case Type_Info_Named: base = i.base
|
||||
case: break loop
|
||||
}
|
||||
}
|
||||
return base;
|
||||
return base
|
||||
}
|
||||
|
||||
|
||||
type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil {
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
base := info;
|
||||
base := info
|
||||
loop: for {
|
||||
#partial switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base;
|
||||
case Type_Info_Enum: base = i.base;
|
||||
case: break loop;
|
||||
case Type_Info_Named: base = i.base
|
||||
case Type_Info_Enum: base = i.base
|
||||
case: break loop
|
||||
}
|
||||
}
|
||||
return base;
|
||||
return base
|
||||
}
|
||||
type_info_base_without_enum :: type_info_core;
|
||||
type_info_base_without_enum :: type_info_core
|
||||
|
||||
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check {
|
||||
MASK :: 1<<(8*size_of(typeid) - 8) - 1;
|
||||
data := transmute(uintptr)id;
|
||||
n := int(data & MASK);
|
||||
MASK :: 1<<(8*size_of(typeid) - 8) - 1
|
||||
data := transmute(uintptr)id
|
||||
n := int(data & MASK)
|
||||
if n < 0 || n >= len(type_table) {
|
||||
n = 0;
|
||||
n = 0
|
||||
}
|
||||
return &type_table[n];
|
||||
return &type_table[n]
|
||||
}
|
||||
|
||||
typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_of(id);
|
||||
ti = type_info_base(ti);
|
||||
return ti.id;
|
||||
ti := type_info_of(id)
|
||||
ti = type_info_base(ti)
|
||||
return ti.id
|
||||
}
|
||||
typeid_core :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_core(type_info_of(id));
|
||||
return ti.id;
|
||||
ti := type_info_core(type_info_of(id))
|
||||
return ti.id
|
||||
}
|
||||
typeid_base_without_enum :: typeid_core;
|
||||
typeid_base_without_enum :: typeid_core
|
||||
|
||||
|
||||
|
||||
debug_trap :: intrinsics.debug_trap;
|
||||
trap :: intrinsics.trap;
|
||||
read_cycle_counter :: intrinsics.read_cycle_counter;
|
||||
debug_trap :: intrinsics.debug_trap
|
||||
trap :: intrinsics.trap
|
||||
read_cycle_counter :: intrinsics.read_cycle_counter
|
||||
|
||||
|
||||
|
||||
@@ -451,53 +451,53 @@ default_logger_proc :: proc(data: rawptr, level: Logger_Level, text: string, opt
|
||||
}
|
||||
|
||||
default_logger :: proc() -> Logger {
|
||||
return Logger{default_logger_proc, nil, Logger_Level.Debug, nil};
|
||||
return Logger{default_logger_proc, nil, Logger_Level.Debug, nil}
|
||||
}
|
||||
|
||||
|
||||
default_context :: proc "contextless" () -> Context {
|
||||
c: Context;
|
||||
__init_context(&c);
|
||||
return c;
|
||||
c: Context
|
||||
__init_context(&c)
|
||||
return c
|
||||
}
|
||||
|
||||
@private
|
||||
__init_context_from_ptr :: proc "contextless" (c: ^Context, other: ^Context) {
|
||||
if c == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
c^ = other^;
|
||||
__init_context(c);
|
||||
c^ = other^
|
||||
__init_context(c)
|
||||
}
|
||||
|
||||
@private
|
||||
__init_context :: proc "contextless" (c: ^Context) {
|
||||
if c == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// NOTE(bill): Do not initialize these procedures with a call as they are not defined with the "contexless" calling convention
|
||||
c.allocator.procedure = default_allocator_proc;
|
||||
c.allocator.data = nil;
|
||||
c.allocator.procedure = default_allocator_proc
|
||||
c.allocator.data = nil
|
||||
|
||||
c.temp_allocator.procedure = default_temp_allocator_proc;
|
||||
c.temp_allocator.data = &global_default_temp_allocator_data;
|
||||
c.temp_allocator.procedure = default_temp_allocator_proc
|
||||
c.temp_allocator.data = &global_default_temp_allocator_data
|
||||
|
||||
c.assertion_failure_proc = default_assertion_failure_proc;
|
||||
c.assertion_failure_proc = default_assertion_failure_proc
|
||||
|
||||
c.logger.procedure = default_logger_proc;
|
||||
c.logger.data = nil;
|
||||
c.logger.procedure = default_logger_proc
|
||||
c.logger.data = nil
|
||||
}
|
||||
|
||||
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
|
||||
print_caller_location(loc);
|
||||
print_string(" ");
|
||||
print_string(prefix);
|
||||
print_caller_location(loc)
|
||||
print_string(" ")
|
||||
print_string(prefix)
|
||||
if len(message) > 0 {
|
||||
print_string(": ");
|
||||
print_string(message);
|
||||
print_string(": ")
|
||||
print_string(message)
|
||||
}
|
||||
print_byte('\n');
|
||||
print_byte('\n')
|
||||
// intrinsics.debug_trap();
|
||||
intrinsics.trap();
|
||||
intrinsics.trap()
|
||||
}
|
||||
|
||||
+225
-225
@@ -3,156 +3,156 @@ package runtime
|
||||
import "core:intrinsics"
|
||||
|
||||
@builtin
|
||||
Maybe :: union($T: typeid) #maybe {T};
|
||||
Maybe :: union($T: typeid) #maybe {T}
|
||||
|
||||
@thread_local global_default_temp_allocator_data: Default_Temp_Allocator;
|
||||
@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
|
||||
|
||||
@builtin
|
||||
init_global_temporary_allocator :: proc(size: int, backup_allocator := context.allocator) {
|
||||
default_temp_allocator_init(&global_default_temp_allocator_data, size, backup_allocator);
|
||||
default_temp_allocator_init(&global_default_temp_allocator_data, size, backup_allocator)
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
n := max(0, min(len(dst), len(src)));
|
||||
n := max(0, min(len(dst), len(src)))
|
||||
if n > 0 {
|
||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(E));
|
||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(E))
|
||||
}
|
||||
return n;
|
||||
return n
|
||||
}
|
||||
@builtin
|
||||
copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
|
||||
n := max(0, min(len(dst), len(src)));
|
||||
n := max(0, min(len(dst), len(src)))
|
||||
if n > 0 {
|
||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n);
|
||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n)
|
||||
}
|
||||
return n;
|
||||
return n
|
||||
}
|
||||
@builtin
|
||||
copy :: proc{copy_slice, copy_from_string};
|
||||
copy :: proc{copy_slice, copy_from_string}
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
|
||||
bounds_check_error_loc(loc, index, len(array));
|
||||
n := len(array)-1;
|
||||
bounds_check_error_loc(loc, index, len(array))
|
||||
n := len(array)-1
|
||||
if index != n {
|
||||
array[index] = array[n];
|
||||
array[index] = array[n]
|
||||
}
|
||||
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
}
|
||||
|
||||
@builtin
|
||||
ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
|
||||
bounds_check_error_loc(loc, index, len(array));
|
||||
bounds_check_error_loc(loc, index, len(array))
|
||||
if index+1 < len(array) {
|
||||
copy(array[index:], array[index+1:]);
|
||||
copy(array[index:], array[index+1:])
|
||||
}
|
||||
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
}
|
||||
|
||||
@builtin
|
||||
remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_location) #no_bounds_check {
|
||||
slice_expr_error_lo_hi_loc(loc, lo, hi, len(array));
|
||||
n := max(hi-lo, 0);
|
||||
slice_expr_error_lo_hi_loc(loc, lo, hi, len(array))
|
||||
n := max(hi-lo, 0)
|
||||
if n > 0 {
|
||||
if hi != len(array) {
|
||||
copy(array[lo:], array[hi:]);
|
||||
copy(array[lo:], array[hi:])
|
||||
}
|
||||
(^Raw_Dynamic_Array)(array).len -= n;
|
||||
(^Raw_Dynamic_Array)(array).len -= n
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
|
||||
assert(len(array) > 0, "", loc);
|
||||
res = array[len(array)-1];
|
||||
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||
return res;
|
||||
assert(len(array) > 0, "", loc)
|
||||
res = array[len(array)-1]
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
|
||||
if len(array) == 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
res, ok = array[len(array)-1], true;
|
||||
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||
return;
|
||||
res, ok = array[len(array)-1], true
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
|
||||
assert(len(array) > 0, "", loc);
|
||||
res = array[0];
|
||||
assert(len(array) > 0, "", loc)
|
||||
res = array[0]
|
||||
if len(array) > 1 {
|
||||
copy(array[0:], array[1:]);
|
||||
copy(array[0:], array[1:])
|
||||
}
|
||||
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||
return res;
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
return res
|
||||
}
|
||||
|
||||
@builtin
|
||||
pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
|
||||
if len(array) == 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
res, ok = array[0], true;
|
||||
res, ok = array[0], true
|
||||
if len(array) > 1 {
|
||||
copy(array[0:], array[1:]);
|
||||
copy(array[0:], array[1:])
|
||||
}
|
||||
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||
return;
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
clear :: proc{clear_dynamic_array, clear_map};
|
||||
clear :: proc{clear_dynamic_array, clear_map}
|
||||
|
||||
@builtin
|
||||
reserve :: proc{reserve_dynamic_array, reserve_map};
|
||||
reserve :: proc{reserve_dynamic_array, reserve_map}
|
||||
|
||||
@builtin
|
||||
resize :: proc{resize_dynamic_array};
|
||||
resize :: proc{resize_dynamic_array}
|
||||
|
||||
|
||||
@builtin
|
||||
free :: proc{mem_free};
|
||||
free :: proc{mem_free}
|
||||
|
||||
@builtin
|
||||
free_all :: proc{mem_free_all};
|
||||
free_all :: proc{mem_free_all}
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free(raw_data(str), allocator, loc);
|
||||
return mem_free(raw_data(str), allocator, loc)
|
||||
}
|
||||
@builtin
|
||||
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free((^byte)(str), allocator, loc);
|
||||
return mem_free((^byte)(str), allocator, loc)
|
||||
}
|
||||
@builtin
|
||||
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free(raw_data(array), array.allocator, loc);
|
||||
return mem_free(raw_data(array), array.allocator, loc)
|
||||
}
|
||||
@builtin
|
||||
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free(raw_data(array), allocator, loc);
|
||||
return mem_free(raw_data(array), allocator, loc)
|
||||
}
|
||||
@builtin
|
||||
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
|
||||
raw := transmute(Raw_Map)m;
|
||||
err := delete_slice(raw.hashes, raw.entries.allocator, loc);
|
||||
err1 := mem_free(raw.entries.data, raw.entries.allocator, loc);
|
||||
raw := transmute(Raw_Map)m
|
||||
err := delete_slice(raw.hashes, raw.entries.allocator, loc)
|
||||
err1 := mem_free(raw.entries.data, raw.entries.allocator, loc)
|
||||
if err == nil {
|
||||
err = err1;
|
||||
err = err1
|
||||
}
|
||||
return err;
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -163,84 +163,84 @@ delete :: proc{
|
||||
delete_dynamic_array,
|
||||
delete_slice,
|
||||
delete_map,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// The new built-in procedure allocates memory. The first argument is a type, not a value, and the value
|
||||
// return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator
|
||||
@builtin
|
||||
new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_second {
|
||||
return new_aligned(T, align_of(T), allocator, loc);
|
||||
return new_aligned(T, align_of(T), allocator, loc)
|
||||
}
|
||||
new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
|
||||
data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return;
|
||||
t = (^T)(raw_data(data));
|
||||
return;
|
||||
data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return
|
||||
t = (^T)(raw_data(data))
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_second {
|
||||
t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return;
|
||||
t = (^T)(raw_data(t_data));
|
||||
t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
|
||||
t = (^T)(raw_data(t_data))
|
||||
if t != nil {
|
||||
t^ = data;
|
||||
t^ = data
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
DEFAULT_RESERVE_CAPACITY :: 16;
|
||||
DEFAULT_RESERVE_CAPACITY :: 16
|
||||
|
||||
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second {
|
||||
make_slice_error_loc(loc, len);
|
||||
data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc);
|
||||
make_slice_error_loc(loc, len)
|
||||
data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc)
|
||||
if data == nil && size_of(E) != 0 {
|
||||
return nil, err;
|
||||
return nil, err
|
||||
}
|
||||
s := Raw_Slice{raw_data(data), len};
|
||||
return transmute(T)s, err;
|
||||
s := Raw_Slice{raw_data(data), len}
|
||||
return transmute(T)s, err
|
||||
}
|
||||
|
||||
@(builtin)
|
||||
make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second {
|
||||
return make_aligned(T, len, align_of(E), allocator, loc);
|
||||
return make_aligned(T, len, align_of(E), allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second {
|
||||
return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc);
|
||||
return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second {
|
||||
return make_dynamic_array_len_cap(T, len, len, allocator, loc);
|
||||
return make_dynamic_array_len_cap(T, len, len, allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second {
|
||||
make_dynamic_array_error_loc(loc, len, cap);
|
||||
data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return;
|
||||
s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator};
|
||||
make_dynamic_array_error_loc(loc, len, cap)
|
||||
data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
|
||||
s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator}
|
||||
if data == nil && size_of(E) != 0 {
|
||||
s.len, s.cap = 0, 0;
|
||||
s.len, s.cap = 0, 0
|
||||
}
|
||||
array = transmute(T)s;
|
||||
return;
|
||||
array = transmute(T)s
|
||||
return
|
||||
}
|
||||
@(builtin)
|
||||
make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = DEFAULT_RESERVE_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T {
|
||||
make_map_expr_error_loc(loc, cap);
|
||||
context.allocator = allocator;
|
||||
make_map_expr_error_loc(loc, cap)
|
||||
context.allocator = allocator
|
||||
|
||||
m: T;
|
||||
reserve_map(&m, cap);
|
||||
return m;
|
||||
m: T
|
||||
reserve_map(&m, cap)
|
||||
return m
|
||||
}
|
||||
@(builtin)
|
||||
make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_second {
|
||||
make_slice_error_loc(loc, len);
|
||||
data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return;
|
||||
make_slice_error_loc(loc, len)
|
||||
data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
|
||||
if data == nil && size_of(E) != 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
mp = cast(T)raw_data(data);
|
||||
return;
|
||||
mp = cast(T)raw_data(data)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -256,27 +256,27 @@ make :: proc{
|
||||
make_dynamic_array_len_cap,
|
||||
make_map,
|
||||
make_multi_pointer,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
if m == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
raw_map := (^Raw_Map)(m);
|
||||
entries := (^Raw_Dynamic_Array)(&raw_map.entries);
|
||||
entries.len = 0;
|
||||
raw_map := (^Raw_Map)(m)
|
||||
entries := (^Raw_Dynamic_Array)(&raw_map.entries)
|
||||
entries.len = 0
|
||||
for _, i in raw_map.hashes {
|
||||
raw_map.hashes[i] = -1;
|
||||
raw_map.hashes[i] = -1
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) {
|
||||
if m != nil {
|
||||
__dynamic_map_reserve(__get_map_header(m), capacity);
|
||||
__dynamic_map_reserve(__get_map_header(m), capacity)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,20 +285,20 @@ reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) {
|
||||
@builtin
|
||||
delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: V) {
|
||||
if m != nil {
|
||||
key := key;
|
||||
h := __get_map_header(m);
|
||||
hash := __get_map_hash(&key);
|
||||
fr := __dynamic_map_find(h, hash);
|
||||
key := key
|
||||
h := __get_map_header(m)
|
||||
hash := __get_map_hash(&key)
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index);
|
||||
deleted_key = (^K)(uintptr(entry)+h.key_offset)^;
|
||||
deleted_value = (^V)(uintptr(entry)+h.value_offset)^;
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
deleted_key = (^K)(uintptr(entry)+h.key_offset)^
|
||||
deleted_value = (^V)(uintptr(entry)+h.value_offset)^
|
||||
|
||||
__dynamic_map_erase(h, fr);
|
||||
__dynamic_map_erase(h, fr)
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -306,57 +306,57 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
||||
@builtin
|
||||
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
||||
if array == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
if cap(array) < len(array)+1 {
|
||||
cap := 2 * cap(array) + max(8, 1);
|
||||
_ = reserve(array, cap, loc);
|
||||
cap := 2 * cap(array) + max(8, 1)
|
||||
_ = reserve(array, cap, loc)
|
||||
}
|
||||
if cap(array)-len(array) > 0 {
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
when size_of(E) != 0 {
|
||||
data := ([^]E)(a.data);
|
||||
assert(condition=data != nil, loc=loc);
|
||||
data[a.len] = arg;
|
||||
data := ([^]E)(a.data)
|
||||
assert(condition=data != nil, loc=loc)
|
||||
data[a.len] = arg
|
||||
}
|
||||
a.len += 1;
|
||||
a.len += 1
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) {
|
||||
if array == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
arg_len := len(args);
|
||||
arg_len := len(args)
|
||||
if arg_len <= 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if cap(array) < len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len);
|
||||
_ = reserve(array, cap, loc);
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
_ = reserve(array, cap, loc)
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
arg_len = min(cap(array)-len(array), arg_len)
|
||||
if arg_len > 0 {
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
when size_of(E) != 0 {
|
||||
data := ([^]E)(a.data);
|
||||
assert(condition=data != nil, loc=loc);
|
||||
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len);
|
||||
data := ([^]E)(a.data)
|
||||
assert(condition=data != nil, loc=loc)
|
||||
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
|
||||
}
|
||||
a.len += arg_len;
|
||||
a.len += arg_len
|
||||
}
|
||||
}
|
||||
|
||||
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
|
||||
@builtin
|
||||
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) {
|
||||
args := transmute([]E)arg;
|
||||
append_elems(array=array, args=args, loc=loc);
|
||||
args := transmute([]E)arg
|
||||
append_elems(array=array, args=args, loc=loc)
|
||||
}
|
||||
|
||||
|
||||
@@ -364,86 +364,86 @@ append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #ca
|
||||
@builtin
|
||||
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) {
|
||||
for arg in args {
|
||||
append(array = array, args = transmute([]E)(arg), loc = loc);
|
||||
append(array = array, args = transmute([]E)(arg), loc = loc)
|
||||
}
|
||||
}
|
||||
|
||||
// The append built-in procedure appends elements to the end of a dynamic array
|
||||
@builtin append :: proc{append_elem, append_elems, append_elem_string};
|
||||
@builtin append :: proc{append_elem, append_elems, append_elem_string}
|
||||
|
||||
|
||||
@builtin
|
||||
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) {
|
||||
if array == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
resize(array, len(array)+1);
|
||||
resize(array, len(array)+1)
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if array == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
n := len(array);
|
||||
m :: 1;
|
||||
resize(array, n+m, loc);
|
||||
n := len(array)
|
||||
m :: 1
|
||||
resize(array, n+m, loc)
|
||||
if n+m <= len(array) {
|
||||
when size_of(E) != 0 {
|
||||
copy(array[index+m:], array[index:]);
|
||||
array[index] = arg;
|
||||
copy(array[index+m:], array[index:])
|
||||
array[index] = arg
|
||||
}
|
||||
ok = true;
|
||||
ok = true
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if array == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if len(args) == 0 {
|
||||
ok = true;
|
||||
return;
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
n := len(array);
|
||||
m := len(args);
|
||||
resize(array, n+m, loc);
|
||||
n := len(array)
|
||||
m := len(args)
|
||||
resize(array, n+m, loc)
|
||||
if n+m <= len(array) {
|
||||
when size_of(E) != 0 {
|
||||
copy(array[index+m:], array[index:]);
|
||||
copy(array[index:], args);
|
||||
copy(array[index+m:], array[index:])
|
||||
copy(array[index:], args)
|
||||
}
|
||||
ok = true;
|
||||
ok = true
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
|
||||
if array == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if len(args) == 0 {
|
||||
ok = true;
|
||||
return;
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
n := len(array);
|
||||
m := len(args);
|
||||
resize(array, n+m, loc);
|
||||
n := len(array)
|
||||
m := len(args)
|
||||
resize(array, n+m, loc)
|
||||
if n+m <= len(array) {
|
||||
copy(array[index+m:], array[index:]);
|
||||
copy(array[index:], args);
|
||||
ok = true;
|
||||
copy(array[index+m:], array[index:])
|
||||
copy(array[index:], args)
|
||||
ok = true
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
@builtin insert_at :: proc{insert_at_elem, insert_at_elems, insert_at_elem_string};
|
||||
@builtin insert_at :: proc{insert_at_elem, insert_at_elems, insert_at_elem_string}
|
||||
|
||||
|
||||
|
||||
@@ -451,134 +451,134 @@ insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
|
||||
@builtin
|
||||
clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
|
||||
if array != nil {
|
||||
(^Raw_Dynamic_Array)(array).len = 0;
|
||||
(^Raw_Dynamic_Array)(array).len = 0
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||
if array == nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
|
||||
if capacity <= a.cap {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
if a.allocator.procedure == nil {
|
||||
a.allocator = context.allocator;
|
||||
a.allocator = context.allocator
|
||||
}
|
||||
assert(a.allocator.procedure != nil);
|
||||
assert(a.allocator.procedure != nil)
|
||||
|
||||
old_size := a.cap * size_of(E);
|
||||
new_size := capacity * size_of(E);
|
||||
allocator := a.allocator;
|
||||
old_size := a.cap * size_of(E)
|
||||
new_size := capacity * size_of(E)
|
||||
allocator := a.allocator
|
||||
|
||||
new_data, err := allocator.procedure(
|
||||
allocator.data, .Resize, new_size, align_of(E),
|
||||
a.data, old_size, loc,
|
||||
);
|
||||
)
|
||||
if new_data == nil || err != nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
a.data = raw_data(new_data);
|
||||
a.cap = capacity;
|
||||
return true;
|
||||
a.data = raw_data(new_data)
|
||||
a.cap = capacity
|
||||
return true
|
||||
}
|
||||
|
||||
@builtin
|
||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
||||
if array == nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array)
|
||||
|
||||
if length <= a.cap {
|
||||
a.len = max(length, 0);
|
||||
return true;
|
||||
a.len = max(length, 0)
|
||||
return true
|
||||
}
|
||||
|
||||
if a.allocator.procedure == nil {
|
||||
a.allocator = context.allocator;
|
||||
a.allocator = context.allocator
|
||||
}
|
||||
assert(a.allocator.procedure != nil);
|
||||
assert(a.allocator.procedure != nil)
|
||||
|
||||
old_size := a.cap * size_of(E);
|
||||
new_size := length * size_of(E);
|
||||
allocator := a.allocator;
|
||||
old_size := a.cap * size_of(E)
|
||||
new_size := length * size_of(E)
|
||||
allocator := a.allocator
|
||||
|
||||
new_data, err := allocator.procedure(
|
||||
allocator.data, .Resize, new_size, align_of(E),
|
||||
a.data, old_size, loc,
|
||||
);
|
||||
)
|
||||
if new_data == nil || err != nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
a.data = raw_data(new_data);
|
||||
a.len = length;
|
||||
a.cap = length;
|
||||
return true;
|
||||
a.data = raw_data(new_data)
|
||||
a.len = length
|
||||
a.cap = length
|
||||
return true
|
||||
}
|
||||
|
||||
@builtin
|
||||
map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
|
||||
key, value := key, value;
|
||||
h := __get_map_header(m);
|
||||
hash := __get_map_hash(&key);
|
||||
key, value := key, value
|
||||
h := __get_map_header(m)
|
||||
hash := __get_map_hash(&key)
|
||||
|
||||
data := uintptr(__dynamic_map_set(h, hash, &value, loc));
|
||||
return (^V)(data + h.value_offset);
|
||||
data := uintptr(__dynamic_map_set(h, hash, &value, loc))
|
||||
return (^V)(data + h.value_offset)
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
incl_elem :: proc(s: ^$S/bit_set[$E; $U], elem: E) {
|
||||
s^ |= {elem};
|
||||
s^ |= {elem}
|
||||
}
|
||||
@builtin
|
||||
incl_elems :: proc(s: ^$S/bit_set[$E; $U], elems: ..E) {
|
||||
for elem in elems {
|
||||
s^ |= {elem};
|
||||
s^ |= {elem}
|
||||
}
|
||||
}
|
||||
@builtin
|
||||
incl_bit_set :: proc(s: ^$S/bit_set[$E; $U], other: S) {
|
||||
s^ |= other;
|
||||
s^ |= other
|
||||
}
|
||||
@builtin
|
||||
excl_elem :: proc(s: ^$S/bit_set[$E; $U], elem: E) {
|
||||
s^ &~= {elem};
|
||||
s^ &~= {elem}
|
||||
}
|
||||
@builtin
|
||||
excl_elems :: proc(s: ^$S/bit_set[$E; $U], elems: ..E) {
|
||||
for elem in elems {
|
||||
s^ &~= {elem};
|
||||
s^ &~= {elem}
|
||||
}
|
||||
}
|
||||
@builtin
|
||||
excl_bit_set :: proc(s: ^$S/bit_set[$E; $U], other: S) {
|
||||
s^ &~= other;
|
||||
s^ &~= other
|
||||
}
|
||||
|
||||
@builtin incl :: proc{incl_elem, incl_elems, incl_bit_set};
|
||||
@builtin excl :: proc{excl_elem, excl_elems, excl_bit_set};
|
||||
@builtin incl :: proc{incl_elem, incl_elems, incl_bit_set}
|
||||
@builtin excl :: proc{excl_elem, excl_elems, excl_bit_set}
|
||||
|
||||
|
||||
@builtin
|
||||
card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
||||
when size_of(S) == 1 {
|
||||
return int(intrinsics.count_ones(transmute(u8)s));
|
||||
return int(intrinsics.count_ones(transmute(u8)s))
|
||||
} else when size_of(S) == 2 {
|
||||
return int(intrinsics.count_ones(transmute(u16)s));
|
||||
return int(intrinsics.count_ones(transmute(u16)s))
|
||||
} else when size_of(S) == 4 {
|
||||
return int(intrinsics.count_ones(transmute(u32)s));
|
||||
return int(intrinsics.count_ones(transmute(u32)s))
|
||||
} else when size_of(S) == 8 {
|
||||
return int(intrinsics.count_ones(transmute(u64)s));
|
||||
return int(intrinsics.count_ones(transmute(u64)s))
|
||||
} else when size_of(S) == 16 {
|
||||
return int(intrinsics.count_ones(transmute(u128)s));
|
||||
return int(intrinsics.count_ones(transmute(u128)s))
|
||||
} else {
|
||||
#panic("Unhandled card bit_set size");
|
||||
}
|
||||
@@ -588,25 +588,25 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
||||
|
||||
@builtin
|
||||
raw_array_data :: proc "contextless" (a: $P/^($T/[$N]$E)) -> ^E {
|
||||
return (^E)(a);
|
||||
return (^E)(a)
|
||||
}
|
||||
@builtin
|
||||
raw_slice_data :: proc "contextless" (s: $S/[]$E) -> ^E {
|
||||
ptr := (transmute(Raw_Slice)s).data;
|
||||
return (^E)(ptr);
|
||||
ptr := (transmute(Raw_Slice)s).data
|
||||
return (^E)(ptr)
|
||||
}
|
||||
@builtin
|
||||
raw_dynamic_array_data :: proc "contextless" (s: $S/[dynamic]$E) -> ^E {
|
||||
ptr := (transmute(Raw_Dynamic_Array)s).data;
|
||||
return (^E)(ptr);
|
||||
ptr := (transmute(Raw_Dynamic_Array)s).data
|
||||
return (^E)(ptr)
|
||||
}
|
||||
@builtin
|
||||
raw_string_data :: proc "contextless" (s: $S/string) -> ^u8 {
|
||||
return (transmute(Raw_String)s).data;
|
||||
return (transmute(Raw_String)s).data
|
||||
}
|
||||
|
||||
@builtin
|
||||
raw_data :: proc{raw_array_data, raw_slice_data, raw_dynamic_array_data, raw_string_data};
|
||||
raw_data :: proc{raw_array_data, raw_slice_data, raw_dynamic_array_data, raw_string_data}
|
||||
|
||||
|
||||
|
||||
@@ -615,45 +615,45 @@ raw_data :: proc{raw_array_data, raw_slice_data, raw_dynamic_array_data, raw_str
|
||||
assert :: proc(condition: bool, message := "", loc := #caller_location) {
|
||||
if !condition {
|
||||
proc(message: string, loc: Source_Code_Location) {
|
||||
p := context.assertion_failure_proc;
|
||||
p := context.assertion_failure_proc
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
p = default_assertion_failure_proc
|
||||
}
|
||||
p("runtime assertion", message, loc);
|
||||
}(message, loc);
|
||||
p("runtime assertion", message, loc)
|
||||
}(message, loc)
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
@(disabled=ODIN_DISABLE_ASSERT)
|
||||
panic :: proc(message: string, loc := #caller_location) -> ! {
|
||||
p := context.assertion_failure_proc;
|
||||
p := context.assertion_failure_proc
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
p = default_assertion_failure_proc
|
||||
}
|
||||
p("panic", message, loc);
|
||||
p("panic", message, loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
@(disabled=ODIN_DISABLE_ASSERT)
|
||||
unimplemented :: proc(message := "", loc := #caller_location) -> ! {
|
||||
p := context.assertion_failure_proc;
|
||||
p := context.assertion_failure_proc
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
p = default_assertion_failure_proc
|
||||
}
|
||||
p("not yet implemented", message, loc);
|
||||
p("not yet implemented", message, loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
@(disabled=ODIN_DISABLE_ASSERT)
|
||||
unreachable :: proc(message := "", loc := #caller_location) -> ! {
|
||||
p := context.assertion_failure_proc;
|
||||
p := context.assertion_failure_proc
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
p = default_assertion_failure_proc
|
||||
}
|
||||
if message != "" {
|
||||
p("internal error", message, loc);
|
||||
p("internal error", message, loc)
|
||||
} else {
|
||||
p("internal error", "entered unreachable code", loc);
|
||||
p("internal error", "entered unreachable code", loc)
|
||||
}
|
||||
}
|
||||
|
||||
+155
-155
@@ -1,7 +1,7 @@
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
_ :: intrinsics;
|
||||
_ :: intrinsics
|
||||
|
||||
/*
|
||||
|
||||
@@ -52,112 +52,112 @@ Raw_SOA_Footer_Dynamic_Array :: struct {
|
||||
|
||||
raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Slice) {
|
||||
if array == nil {
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E));
|
||||
footer = (^Raw_SOA_Footer_Slice)(uintptr(array) + field_count*size_of(rawptr));
|
||||
return;
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E))
|
||||
footer = (^Raw_SOA_Footer_Slice)(uintptr(array) + field_count*size_of(rawptr))
|
||||
return
|
||||
}
|
||||
raw_soa_footer_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) -> (footer: ^Raw_SOA_Footer_Dynamic_Array) {
|
||||
if array == nil {
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E));
|
||||
footer = (^Raw_SOA_Footer_Dynamic_Array)(uintptr(array) + field_count*size_of(rawptr));
|
||||
return;
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E))
|
||||
footer = (^Raw_SOA_Footer_Dynamic_Array)(uintptr(array) + field_count*size_of(rawptr))
|
||||
return
|
||||
}
|
||||
raw_soa_footer :: proc{
|
||||
raw_soa_footer_slice,
|
||||
raw_soa_footer_dynamic_array,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second {
|
||||
if length <= 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
footer := raw_soa_footer(&array);
|
||||
footer := raw_soa_footer(&array)
|
||||
if size_of(E) == 0 {
|
||||
footer.len = length;
|
||||
return;
|
||||
footer.len = length
|
||||
return
|
||||
}
|
||||
|
||||
max_align := max(alignment, align_of(E));
|
||||
max_align := max(alignment, align_of(E))
|
||||
|
||||
ti := type_info_of(typeid_of(T));
|
||||
ti = type_info_base(ti);
|
||||
si := &ti.variant.(Type_Info_Struct);
|
||||
ti := type_info_of(typeid_of(T))
|
||||
ti = type_info_base(ti)
|
||||
si := &ti.variant.(Type_Info_Struct)
|
||||
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E));
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E))
|
||||
|
||||
total_size := 0;
|
||||
total_size := 0
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||
total_size += type.size * length;
|
||||
total_size = align_forward_int(total_size, max_align);
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem
|
||||
total_size += type.size * length
|
||||
total_size = align_forward_int(total_size, max_align)
|
||||
}
|
||||
|
||||
allocator := allocator;
|
||||
allocator := allocator
|
||||
if allocator.procedure == nil {
|
||||
allocator = context.allocator;
|
||||
allocator = context.allocator
|
||||
}
|
||||
assert(allocator.procedure != nil);
|
||||
assert(allocator.procedure != nil)
|
||||
|
||||
new_bytes: []byte;
|
||||
new_bytes: []byte
|
||||
new_bytes, err = allocator.procedure(
|
||||
allocator.data, .Alloc, total_size, max_align,
|
||||
nil, 0, loc,
|
||||
);
|
||||
)
|
||||
if new_bytes == nil || err != nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
new_data := raw_data(new_bytes);
|
||||
new_data := raw_data(new_bytes)
|
||||
|
||||
data := uintptr(&array);
|
||||
offset := 0;
|
||||
data := uintptr(&array)
|
||||
offset := 0
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem
|
||||
|
||||
offset = align_forward_int(offset, max_align);
|
||||
offset = align_forward_int(offset, max_align)
|
||||
|
||||
(^uintptr)(data)^ = uintptr(new_data) + uintptr(offset);
|
||||
data += size_of(rawptr);
|
||||
offset += type.size * length;
|
||||
(^uintptr)(data)^ = uintptr(new_data) + uintptr(offset)
|
||||
data += size_of(rawptr)
|
||||
offset += type.size * length
|
||||
}
|
||||
footer.len = length;
|
||||
footer.len = length
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second {
|
||||
return make_soa_aligned(T, length, align_of(E), allocator, loc);
|
||||
return make_soa_aligned(T, length, align_of(E), allocator, loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
context.allocator = allocator;
|
||||
reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc);
|
||||
return;
|
||||
context.allocator = allocator
|
||||
reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc)
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, auto_cast length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
context.allocator = allocator;
|
||||
resize_soa(&array, length, loc);
|
||||
return;
|
||||
context.allocator = allocator
|
||||
resize_soa(&array, length, loc)
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, auto_cast length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
if reserve_soa(&array, capacity, loc) {
|
||||
resize_soa(&array, length, loc);
|
||||
resize_soa(&array, length, loc)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -167,206 +167,206 @@ make_soa :: proc{
|
||||
make_soa_dynamic_array,
|
||||
make_soa_dynamic_array_len,
|
||||
make_soa_dynamic_array_len_cap,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
||||
if array == nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
if !reserve_soa(array, length, loc) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
footer := raw_soa_footer(array);
|
||||
footer.len = length;
|
||||
return true;
|
||||
footer := raw_soa_footer(array)
|
||||
footer.len = length
|
||||
return true
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||
if array == nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
old_cap := cap(array);
|
||||
old_cap := cap(array)
|
||||
if capacity <= old_cap {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
if array.allocator.procedure == nil {
|
||||
array.allocator = context.allocator;
|
||||
array.allocator = context.allocator
|
||||
}
|
||||
assert(array.allocator.procedure != nil);
|
||||
assert(array.allocator.procedure != nil)
|
||||
|
||||
footer := raw_soa_footer(array);
|
||||
footer := raw_soa_footer(array)
|
||||
if size_of(E) == 0 {
|
||||
footer.cap = capacity;
|
||||
return true;
|
||||
footer.cap = capacity
|
||||
return true
|
||||
}
|
||||
|
||||
ti := type_info_of(typeid_of(T));
|
||||
ti = type_info_base(ti);
|
||||
si := &ti.variant.(Type_Info_Struct);
|
||||
ti := type_info_of(typeid_of(T))
|
||||
ti = type_info_base(ti)
|
||||
si := &ti.variant.(Type_Info_Struct)
|
||||
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E));
|
||||
assert(footer.cap == old_cap);
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E))
|
||||
assert(footer.cap == old_cap)
|
||||
|
||||
old_size := 0;
|
||||
new_size := 0;
|
||||
old_size := 0
|
||||
new_size := 0
|
||||
|
||||
max_align :: align_of(E);
|
||||
max_align :: align_of(E)
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem
|
||||
|
||||
old_size += type.size * old_cap;
|
||||
new_size += type.size * capacity;
|
||||
old_size += type.size * old_cap
|
||||
new_size += type.size * capacity
|
||||
|
||||
old_size = align_forward_int(old_size, max_align);
|
||||
new_size = align_forward_int(new_size, max_align);
|
||||
old_size = align_forward_int(old_size, max_align)
|
||||
new_size = align_forward_int(new_size, max_align)
|
||||
}
|
||||
|
||||
old_data := (^rawptr)(array)^;
|
||||
old_data := (^rawptr)(array)^
|
||||
|
||||
new_bytes, err := array.allocator.procedure(
|
||||
array.allocator.data, .Alloc, new_size, max_align,
|
||||
nil, old_size, loc,
|
||||
);
|
||||
)
|
||||
if new_bytes == nil || err != nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
new_data := raw_data(new_bytes);
|
||||
new_data := raw_data(new_bytes)
|
||||
|
||||
|
||||
footer.cap = capacity;
|
||||
footer.cap = capacity
|
||||
|
||||
old_offset := 0;
|
||||
new_offset := 0;
|
||||
old_offset := 0
|
||||
new_offset := 0
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem
|
||||
|
||||
old_offset = align_forward_int(old_offset, max_align);
|
||||
new_offset = align_forward_int(new_offset, max_align);
|
||||
old_offset = align_forward_int(old_offset, max_align)
|
||||
new_offset = align_forward_int(new_offset, max_align)
|
||||
|
||||
new_data_elem := rawptr(uintptr(new_data) + uintptr(new_offset));
|
||||
old_data_elem := rawptr(uintptr(old_data) + uintptr(old_offset));
|
||||
new_data_elem := rawptr(uintptr(new_data) + uintptr(new_offset))
|
||||
old_data_elem := rawptr(uintptr(old_data) + uintptr(old_offset))
|
||||
|
||||
mem_copy(new_data_elem, old_data_elem, type.size * old_cap);
|
||||
mem_copy(new_data_elem, old_data_elem, type.size * old_cap)
|
||||
|
||||
(^rawptr)(uintptr(array) + i*size_of(rawptr))^ = new_data_elem;
|
||||
(^rawptr)(uintptr(array) + i*size_of(rawptr))^ = new_data_elem
|
||||
|
||||
old_offset += type.size * old_cap;
|
||||
new_offset += type.size * capacity;
|
||||
old_offset += type.size * old_cap
|
||||
new_offset += type.size * capacity
|
||||
}
|
||||
|
||||
_, err = array.allocator.procedure(
|
||||
array.allocator.data, .Free, 0, max_align,
|
||||
old_data, old_size, loc,
|
||||
);
|
||||
)
|
||||
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
@builtin
|
||||
append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) {
|
||||
if array == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
arg_len := 1;
|
||||
arg_len := 1
|
||||
|
||||
if cap(array) <= len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len);
|
||||
_ = reserve_soa(array, cap, loc);
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
_ = reserve_soa(array, cap, loc)
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
arg_len = min(cap(array)-len(array), arg_len)
|
||||
|
||||
footer := raw_soa_footer(array);
|
||||
footer := raw_soa_footer(array)
|
||||
|
||||
if size_of(E) > 0 && arg_len > 0 {
|
||||
ti := type_info_of(typeid_of(T));
|
||||
ti = type_info_base(ti);
|
||||
si := &ti.variant.(Type_Info_Struct);
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E));
|
||||
ti := type_info_of(typeid_of(T))
|
||||
ti = type_info_base(ti)
|
||||
si := &ti.variant.(Type_Info_Struct)
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E))
|
||||
|
||||
data := (^rawptr)(array)^;
|
||||
data := (^rawptr)(array)^
|
||||
|
||||
soa_offset := 0;
|
||||
item_offset := 0;
|
||||
soa_offset := 0
|
||||
item_offset := 0
|
||||
|
||||
arg_copy := arg;
|
||||
arg_ptr := &arg_copy;
|
||||
arg_copy := arg
|
||||
arg_ptr := &arg_copy
|
||||
|
||||
max_align :: align_of(E);
|
||||
max_align :: align_of(E)
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem
|
||||
|
||||
soa_offset = align_forward_int(soa_offset, max_align);
|
||||
item_offset = align_forward_int(item_offset, type.align);
|
||||
soa_offset = align_forward_int(soa_offset, max_align)
|
||||
item_offset = align_forward_int(item_offset, type.align)
|
||||
|
||||
dst := rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * footer.len));
|
||||
src := rawptr(uintptr(arg_ptr) + uintptr(item_offset));
|
||||
mem_copy(dst, src, type.size);
|
||||
dst := rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * footer.len))
|
||||
src := rawptr(uintptr(arg_ptr) + uintptr(item_offset))
|
||||
mem_copy(dst, src, type.size)
|
||||
|
||||
soa_offset += type.size * cap(array);
|
||||
item_offset += type.size;
|
||||
soa_offset += type.size * cap(array)
|
||||
item_offset += type.size
|
||||
}
|
||||
}
|
||||
footer.len += arg_len;
|
||||
footer.len += arg_len
|
||||
}
|
||||
|
||||
@builtin
|
||||
append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) {
|
||||
if array == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
arg_len := len(args);
|
||||
arg_len := len(args)
|
||||
if arg_len == 0 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
if cap(array) <= len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len);
|
||||
_ = reserve_soa(array, cap, loc);
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
_ = reserve_soa(array, cap, loc)
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
arg_len = min(cap(array)-len(array), arg_len)
|
||||
|
||||
footer := raw_soa_footer(array);
|
||||
footer := raw_soa_footer(array)
|
||||
if size_of(E) > 0 && arg_len > 0 {
|
||||
ti := type_info_of(typeid_of(T));
|
||||
ti = type_info_base(ti);
|
||||
si := &ti.variant.(Type_Info_Struct);
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E));
|
||||
ti := type_info_of(typeid_of(T))
|
||||
ti = type_info_base(ti)
|
||||
si := &ti.variant.(Type_Info_Struct)
|
||||
field_count := uintptr(intrinsics.type_struct_field_count(E))
|
||||
|
||||
data := (^rawptr)(array)^;
|
||||
data := (^rawptr)(array)^
|
||||
|
||||
soa_offset := 0;
|
||||
item_offset := 0;
|
||||
soa_offset := 0
|
||||
item_offset := 0
|
||||
|
||||
args_ptr := &args[0];
|
||||
args_ptr := &args[0]
|
||||
|
||||
max_align :: align_of(E);
|
||||
max_align :: align_of(E)
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem;
|
||||
type := si.types[i].variant.(Type_Info_Pointer).elem
|
||||
|
||||
soa_offset = align_forward_int(soa_offset, max_align);
|
||||
item_offset = align_forward_int(item_offset, type.align);
|
||||
soa_offset = align_forward_int(soa_offset, max_align)
|
||||
item_offset = align_forward_int(item_offset, type.align)
|
||||
|
||||
dst := uintptr(data) + uintptr(soa_offset) + uintptr(type.size * footer.len);
|
||||
src := uintptr(args_ptr) + uintptr(item_offset);
|
||||
dst := uintptr(data) + uintptr(soa_offset) + uintptr(type.size * footer.len)
|
||||
src := uintptr(args_ptr) + uintptr(item_offset)
|
||||
for j in 0..<arg_len {
|
||||
d := rawptr(dst + uintptr(j*type.size));
|
||||
s := rawptr(src + uintptr(j*size_of(E)));
|
||||
mem_copy(d, s, type.size);
|
||||
d := rawptr(dst + uintptr(j*type.size))
|
||||
s := rawptr(src + uintptr(j*size_of(E)))
|
||||
mem_copy(d, s, type.size)
|
||||
}
|
||||
|
||||
soa_offset += type.size * cap(array);
|
||||
item_offset += type.size;
|
||||
soa_offset += type.size * cap(array)
|
||||
item_offset += type.size
|
||||
}
|
||||
}
|
||||
|
||||
footer.len += arg_len;
|
||||
footer.len += arg_len
|
||||
}
|
||||
|
||||
|
||||
@@ -375,23 +375,23 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
|
||||
append_soa :: proc{
|
||||
append_soa_elem,
|
||||
append_soa_elems,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) {
|
||||
when intrinsics.type_struct_field_count(E) != 0 {
|
||||
array := array;
|
||||
ptr := (^rawptr)(&array)^;
|
||||
free(ptr, allocator, loc);
|
||||
array := array
|
||||
ptr := (^rawptr)(&array)^
|
||||
free(ptr, allocator, loc)
|
||||
}
|
||||
}
|
||||
|
||||
delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) {
|
||||
when intrinsics.type_struct_field_count(E) != 0 {
|
||||
array := array;
|
||||
ptr := (^rawptr)(&array)^;
|
||||
footer := raw_soa_footer(&array);
|
||||
free(ptr, footer.allocator, loc);
|
||||
array := array
|
||||
ptr := (^rawptr)(&array)^
|
||||
footer := raw_soa_footer(&array)
|
||||
free(ptr, footer.allocator, loc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,4 +400,4 @@ delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_locat
|
||||
delete_soa :: proc{
|
||||
delete_soa_slice,
|
||||
delete_soa_dynamic_array,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,33 +6,33 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
switch mode {
|
||||
case .Alloc:
|
||||
data, err = _windows_default_alloc(size, alignment);
|
||||
data, err = _windows_default_alloc(size, alignment)
|
||||
|
||||
case .Free:
|
||||
_windows_default_free(old_memory);
|
||||
_windows_default_free(old_memory)
|
||||
|
||||
case .Free_All:
|
||||
// NOTE(tetra): Do nothing.
|
||||
|
||||
case .Resize:
|
||||
data, err = _windows_default_resize(old_memory, old_size, size, alignment);
|
||||
data, err = _windows_default_resize(old_memory, old_size, size, alignment)
|
||||
|
||||
case .Query_Features:
|
||||
set := (^Allocator_Mode_Set)(old_memory);
|
||||
set := (^Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Alloc, .Free, .Resize, .Query_Features};
|
||||
set^ = {.Alloc, .Free, .Resize, .Query_Features}
|
||||
}
|
||||
|
||||
case .Query_Info:
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
default_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = default_allocator_proc,
|
||||
data = nil,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package runtime
|
||||
|
||||
@(private)
|
||||
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte {
|
||||
return transmute([]u8)Raw_Slice{data=data, len=max(len, 0)};
|
||||
return transmute([]u8)Raw_Slice{data=data, len=max(len, 0)}
|
||||
}
|
||||
|
||||
|
||||
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22);
|
||||
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
|
||||
|
||||
|
||||
Default_Temp_Allocator :: struct {
|
||||
@@ -18,179 +18,179 @@ Default_Temp_Allocator :: struct {
|
||||
}
|
||||
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {
|
||||
s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator);
|
||||
s.curr_offset = 0;
|
||||
s.prev_allocation = nil;
|
||||
s.backup_allocator = backup_allocator;
|
||||
s.leaked_allocations.allocator = backup_allocator;
|
||||
s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator)
|
||||
s.curr_offset = 0
|
||||
s.prev_allocation = nil
|
||||
s.backup_allocator = backup_allocator
|
||||
s.leaked_allocations.allocator = backup_allocator
|
||||
}
|
||||
|
||||
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
|
||||
if s == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
for ptr in s.leaked_allocations {
|
||||
free(raw_data(ptr), s.backup_allocator);
|
||||
free(raw_data(ptr), s.backup_allocator)
|
||||
}
|
||||
delete(s.leaked_allocations);
|
||||
delete(s.data, s.backup_allocator);
|
||||
s^ = {};
|
||||
delete(s.leaked_allocations)
|
||||
delete(s.data, s.backup_allocator)
|
||||
s^ = {}
|
||||
}
|
||||
|
||||
@(private)
|
||||
default_temp_allocator_alloc :: proc(s: ^Default_Temp_Allocator, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
size := size;
|
||||
size = align_forward_int(size, alignment);
|
||||
size := size
|
||||
size = align_forward_int(size, alignment)
|
||||
|
||||
switch {
|
||||
case s.curr_offset+size <= len(s.data):
|
||||
start := uintptr(raw_data(s.data));
|
||||
ptr := start + uintptr(s.curr_offset);
|
||||
ptr = align_forward_uintptr(ptr, uintptr(alignment));
|
||||
mem_zero(rawptr(ptr), size);
|
||||
start := uintptr(raw_data(s.data))
|
||||
ptr := start + uintptr(s.curr_offset)
|
||||
ptr = align_forward_uintptr(ptr, uintptr(alignment))
|
||||
mem_zero(rawptr(ptr), size)
|
||||
|
||||
s.prev_allocation = rawptr(ptr);
|
||||
offset := int(ptr - start);
|
||||
s.curr_offset = offset + size;
|
||||
return byte_slice(rawptr(ptr), size), .None;
|
||||
s.prev_allocation = rawptr(ptr)
|
||||
offset := int(ptr - start)
|
||||
s.curr_offset = offset + size
|
||||
return byte_slice(rawptr(ptr), size), .None
|
||||
|
||||
case size <= len(s.data):
|
||||
start := uintptr(raw_data(s.data));
|
||||
ptr := align_forward_uintptr(start, uintptr(alignment));
|
||||
mem_zero(rawptr(ptr), size);
|
||||
start := uintptr(raw_data(s.data))
|
||||
ptr := align_forward_uintptr(start, uintptr(alignment))
|
||||
mem_zero(rawptr(ptr), size)
|
||||
|
||||
s.prev_allocation = rawptr(ptr);
|
||||
offset := int(ptr - start);
|
||||
s.curr_offset = offset + size;
|
||||
return byte_slice(rawptr(ptr), size), .None;
|
||||
s.prev_allocation = rawptr(ptr)
|
||||
offset := int(ptr - start)
|
||||
s.curr_offset = offset + size
|
||||
return byte_slice(rawptr(ptr), size), .None
|
||||
}
|
||||
a := s.backup_allocator;
|
||||
a := s.backup_allocator
|
||||
if a.procedure == nil {
|
||||
a = context.allocator;
|
||||
s.backup_allocator = a;
|
||||
a = context.allocator
|
||||
s.backup_allocator = a
|
||||
}
|
||||
|
||||
data, err := mem_alloc_bytes(size, alignment, a, loc);
|
||||
data, err := mem_alloc_bytes(size, alignment, a, loc)
|
||||
if err != nil {
|
||||
return data, err;
|
||||
return data, err
|
||||
}
|
||||
if s.leaked_allocations == nil {
|
||||
s.leaked_allocations = make([dynamic][]byte, a);
|
||||
s.leaked_allocations = make([dynamic][]byte, a)
|
||||
}
|
||||
append(&s.leaked_allocations, data);
|
||||
append(&s.leaked_allocations, data)
|
||||
|
||||
// TODO(bill): Should leaks be notified about?
|
||||
if logger := context.logger; logger.lowest_level <= .Warning {
|
||||
if logger.procedure != nil {
|
||||
logger.procedure(logger.data, .Warning, "default temp allocator resorted to backup_allocator" , logger.options, loc);
|
||||
logger.procedure(logger.data, .Warning, "default temp allocator resorted to backup_allocator" , logger.options, loc)
|
||||
}
|
||||
}
|
||||
|
||||
return data, .None;
|
||||
return data, .None
|
||||
}
|
||||
|
||||
@(private)
|
||||
default_temp_allocator_free :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, loc := #caller_location) -> Allocator_Error {
|
||||
if old_memory == nil {
|
||||
return .None;
|
||||
return .None
|
||||
}
|
||||
|
||||
start := uintptr(raw_data(s.data));
|
||||
end := start + uintptr(len(s.data));
|
||||
old_ptr := uintptr(old_memory);
|
||||
start := uintptr(raw_data(s.data))
|
||||
end := start + uintptr(len(s.data))
|
||||
old_ptr := uintptr(old_memory)
|
||||
|
||||
if s.prev_allocation == old_memory {
|
||||
s.curr_offset = int(uintptr(s.prev_allocation) - start);
|
||||
s.prev_allocation = nil;
|
||||
return .None;
|
||||
s.curr_offset = int(uintptr(s.prev_allocation) - start)
|
||||
s.prev_allocation = nil
|
||||
return .None
|
||||
}
|
||||
|
||||
if start <= old_ptr && old_ptr < end {
|
||||
// NOTE(bill): Cannot free this pointer but it is valid
|
||||
return .None;
|
||||
return .None
|
||||
}
|
||||
|
||||
if len(s.leaked_allocations) != 0 {
|
||||
for data, i in s.leaked_allocations {
|
||||
ptr := raw_data(data);
|
||||
ptr := raw_data(data)
|
||||
if ptr == old_memory {
|
||||
free(ptr, s.backup_allocator);
|
||||
ordered_remove(&s.leaked_allocations, i);
|
||||
return .None;
|
||||
free(ptr, s.backup_allocator)
|
||||
ordered_remove(&s.leaked_allocations, i)
|
||||
return .None
|
||||
}
|
||||
}
|
||||
}
|
||||
return .Invalid_Pointer;
|
||||
return .Invalid_Pointer
|
||||
// panic("invalid pointer passed to default_temp_allocator");
|
||||
}
|
||||
|
||||
@(private)
|
||||
default_temp_allocator_free_all :: proc(s: ^Default_Temp_Allocator, loc := #caller_location) {
|
||||
s.curr_offset = 0;
|
||||
s.prev_allocation = nil;
|
||||
s.curr_offset = 0
|
||||
s.prev_allocation = nil
|
||||
for data in s.leaked_allocations {
|
||||
free(raw_data(data), s.backup_allocator);
|
||||
free(raw_data(data), s.backup_allocator)
|
||||
}
|
||||
clear(&s.leaked_allocations);
|
||||
clear(&s.leaked_allocations)
|
||||
}
|
||||
|
||||
@(private)
|
||||
default_temp_allocator_resize :: proc(s: ^Default_Temp_Allocator, old_memory: rawptr, old_size, size, alignment: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
begin := uintptr(raw_data(s.data));
|
||||
end := begin + uintptr(len(s.data));
|
||||
old_ptr := uintptr(old_memory);
|
||||
begin := uintptr(raw_data(s.data))
|
||||
end := begin + uintptr(len(s.data))
|
||||
old_ptr := uintptr(old_memory)
|
||||
if old_memory == s.prev_allocation && old_ptr & uintptr(alignment)-1 == 0 {
|
||||
if old_ptr+uintptr(size) < end {
|
||||
s.curr_offset = int(old_ptr-begin)+size;
|
||||
return byte_slice(old_memory, size), .None;
|
||||
s.curr_offset = int(old_ptr-begin)+size
|
||||
return byte_slice(old_memory, size), .None
|
||||
}
|
||||
}
|
||||
data, err := default_temp_allocator_alloc(s, size, alignment, loc);
|
||||
data, err := default_temp_allocator_alloc(s, size, alignment, loc)
|
||||
if err == .None {
|
||||
copy(data, byte_slice(old_memory, old_size));
|
||||
err = default_temp_allocator_free(s, old_memory, loc);
|
||||
copy(data, byte_slice(old_memory, old_size))
|
||||
err = default_temp_allocator_free(s, old_memory, loc)
|
||||
}
|
||||
return data, err;
|
||||
return data, err
|
||||
}
|
||||
|
||||
default_temp_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
|
||||
s := (^Default_Temp_Allocator)(allocator_data);
|
||||
s := (^Default_Temp_Allocator)(allocator_data)
|
||||
|
||||
if s.data == nil {
|
||||
default_temp_allocator_init(s, DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, default_allocator());
|
||||
default_temp_allocator_init(s, DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, default_allocator())
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .Alloc:
|
||||
data, err = default_temp_allocator_alloc(s, size, alignment, loc);
|
||||
data, err = default_temp_allocator_alloc(s, size, alignment, loc)
|
||||
case .Free:
|
||||
err = default_temp_allocator_free(s, old_memory, loc);
|
||||
err = default_temp_allocator_free(s, old_memory, loc)
|
||||
|
||||
case .Free_All:
|
||||
default_temp_allocator_free_all(s, loc);
|
||||
default_temp_allocator_free_all(s, loc)
|
||||
|
||||
case .Resize:
|
||||
data, err = default_temp_allocator_resize(s, old_memory, old_size, size, alignment, loc);
|
||||
data, err = default_temp_allocator_resize(s, old_memory, old_size, size, alignment, loc)
|
||||
|
||||
case .Query_Features:
|
||||
set := (^Allocator_Mode_Set)(old_memory);
|
||||
set := (^Allocator_Mode_Set)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features};
|
||||
set^ = {.Alloc, .Free, .Free_All, .Resize, .Query_Features}
|
||||
}
|
||||
|
||||
case .Query_Info:
|
||||
// Nothing to give
|
||||
}
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = default_temp_allocator_proc,
|
||||
data = allocator,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +1,103 @@
|
||||
package runtime
|
||||
|
||||
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
array.allocator = context.allocator;
|
||||
assert(array.allocator.procedure != nil);
|
||||
array := (^Raw_Dynamic_Array)(array_)
|
||||
array.allocator = context.allocator
|
||||
assert(array.allocator.procedure != nil)
|
||||
|
||||
if cap > 0 {
|
||||
__dynamic_array_reserve(array_, elem_size, elem_align, cap, loc);
|
||||
array.len = len;
|
||||
__dynamic_array_reserve(array_, elem_size, elem_align, cap, loc)
|
||||
array.len = len
|
||||
}
|
||||
}
|
||||
|
||||
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_)
|
||||
|
||||
// NOTE(tetra, 2020-01-26): We set the allocator before earlying-out below, because user code is usually written
|
||||
// assuming that appending/reserving will set the allocator, if it is not already set.
|
||||
if array.allocator.procedure == nil {
|
||||
array.allocator = context.allocator;
|
||||
array.allocator = context.allocator
|
||||
}
|
||||
assert(array.allocator.procedure != nil);
|
||||
assert(array.allocator.procedure != nil)
|
||||
|
||||
if cap <= array.cap {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
old_size := array.cap * elem_size;
|
||||
new_size := cap * elem_size;
|
||||
allocator := array.allocator;
|
||||
old_size := array.cap * elem_size
|
||||
new_size := cap * elem_size
|
||||
allocator := array.allocator
|
||||
|
||||
new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc);
|
||||
new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc)
|
||||
if err != nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
if new_data != nil || elem_size == 0 {
|
||||
array.data = raw_data(new_data);
|
||||
array.cap = min(cap, len(new_data)/elem_size);
|
||||
return true;
|
||||
array.data = raw_data(new_data)
|
||||
array.cap = min(cap, len(new_data)/elem_size)
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_)
|
||||
|
||||
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
|
||||
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc)
|
||||
if ok {
|
||||
array.len = len;
|
||||
array.len = len
|
||||
}
|
||||
return ok;
|
||||
return ok
|
||||
}
|
||||
|
||||
|
||||
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
items: rawptr, item_count: int, loc := #caller_location) -> int {
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_)
|
||||
|
||||
if items == nil {
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
if item_count <= 0 {
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
ok := true;
|
||||
ok := true
|
||||
if array.cap <= array.len+item_count {
|
||||
cap := 2 * array.cap + max(8, item_count);
|
||||
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc);
|
||||
cap := 2 * array.cap + max(8, item_count)
|
||||
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc)
|
||||
}
|
||||
// TODO(bill): Better error handling for failed reservation
|
||||
if !ok {
|
||||
return array.len;
|
||||
return array.len
|
||||
}
|
||||
|
||||
assert(array.data != nil);
|
||||
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
||||
assert(array.data != nil)
|
||||
data := uintptr(array.data) + uintptr(elem_size*array.len)
|
||||
|
||||
mem_copy(rawptr(data), items, elem_size * item_count);
|
||||
array.len += item_count;
|
||||
return array.len;
|
||||
mem_copy(rawptr(data), items, elem_size * item_count)
|
||||
array.len += item_count
|
||||
return array.len
|
||||
}
|
||||
|
||||
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_)
|
||||
|
||||
ok := true;
|
||||
ok := true
|
||||
if array.cap <= array.len+1 {
|
||||
cap := 2 * array.cap + max(8, 1);
|
||||
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc);
|
||||
cap := 2 * array.cap + max(8, 1)
|
||||
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc)
|
||||
}
|
||||
// TODO(bill): Better error handling for failed reservation
|
||||
if !ok {
|
||||
return array.len;
|
||||
return array.len
|
||||
}
|
||||
|
||||
assert(array.data != nil);
|
||||
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
||||
mem_zero(rawptr(data), elem_size);
|
||||
array.len += 1;
|
||||
return array.len;
|
||||
assert(array.data != nil)
|
||||
data := uintptr(array.data) + uintptr(elem_size*array.len)
|
||||
mem_zero(rawptr(data), elem_size)
|
||||
array.len += 1
|
||||
return array.len
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
_ :: intrinsics;
|
||||
_ :: intrinsics
|
||||
|
||||
INITIAL_MAP_CAP :: 16;
|
||||
INITIAL_MAP_CAP :: 16
|
||||
|
||||
// Temporary data structure for comparing hashes and keys
|
||||
Map_Hash :: struct {
|
||||
@@ -12,16 +12,16 @@ Map_Hash :: struct {
|
||||
}
|
||||
|
||||
__get_map_hash :: proc "contextless" (k: ^$K) -> (map_hash: Map_Hash) {
|
||||
hasher := intrinsics.type_hasher_proc(K);
|
||||
map_hash.key_ptr = k;
|
||||
map_hash.hash = hasher(k, 0);
|
||||
return;
|
||||
hasher := intrinsics.type_hasher_proc(K)
|
||||
map_hash.key_ptr = k
|
||||
map_hash.hash = hasher(k, 0)
|
||||
return
|
||||
}
|
||||
|
||||
__get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) {
|
||||
hash.hash = entry.hash;
|
||||
hash.key_ptr = rawptr(uintptr(entry) + h.key_offset);
|
||||
return;
|
||||
hash.hash = entry.hash
|
||||
hash.key_ptr = rawptr(uintptr(entry) + h.key_offset)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -55,48 +55,48 @@ Map_Header :: struct {
|
||||
value_size: int,
|
||||
}
|
||||
|
||||
INITIAL_HASH_SEED :: 0xcbf29ce484222325;
|
||||
INITIAL_HASH_SEED :: 0xcbf29ce484222325
|
||||
|
||||
_fnv64a :: proc "contextless" (data: []byte, seed: u64 = INITIAL_HASH_SEED) -> u64 {
|
||||
h: u64 = seed;
|
||||
h: u64 = seed
|
||||
for b in data {
|
||||
h = (h ~ u64(b)) * 0x100000001b3;
|
||||
h = (h ~ u64(b)) * 0x100000001b3
|
||||
}
|
||||
return h;
|
||||
return h
|
||||
}
|
||||
|
||||
default_hash :: #force_inline proc "contextless" (data: []byte) -> uintptr {
|
||||
return uintptr(_fnv64a(data));
|
||||
return uintptr(_fnv64a(data))
|
||||
}
|
||||
default_hash_string :: #force_inline proc "contextless" (s: string) -> uintptr {
|
||||
return default_hash(transmute([]byte)(s));
|
||||
return default_hash(transmute([]byte)(s))
|
||||
}
|
||||
default_hash_ptr :: #force_inline proc "contextless" (data: rawptr, size: int) -> uintptr {
|
||||
s := Raw_Slice{data, size};
|
||||
return default_hash(transmute([]byte)(s));
|
||||
s := Raw_Slice{data, size}
|
||||
return default_hash(transmute([]byte)(s))
|
||||
}
|
||||
|
||||
@(private)
|
||||
_default_hasher_const :: #force_inline proc "contextless" (data: rawptr, seed: uintptr, $N: uint) -> uintptr where N <= 16 {
|
||||
h := u64(seed) + 0xcbf29ce484222325;
|
||||
p := uintptr(data);
|
||||
h := u64(seed) + 0xcbf29ce484222325
|
||||
p := uintptr(data)
|
||||
#unroll for _ in 0..<N {
|
||||
b := u64((^byte)(p)^);
|
||||
h = (h ~ b) * 0x100000001b3;
|
||||
p += 1;
|
||||
b := u64((^byte)(p)^)
|
||||
h = (h ~ b) * 0x100000001b3
|
||||
p += 1
|
||||
}
|
||||
return uintptr(h);
|
||||
return uintptr(h)
|
||||
}
|
||||
|
||||
default_hasher_n :: #force_inline proc "contextless" (data: rawptr, seed: uintptr, N: int) -> uintptr {
|
||||
h := u64(seed) + 0xcbf29ce484222325;
|
||||
p := uintptr(data);
|
||||
h := u64(seed) + 0xcbf29ce484222325
|
||||
p := uintptr(data)
|
||||
for _ in 0..<N {
|
||||
b := u64((^byte)(p)^);
|
||||
h = (h ~ b) * 0x100000001b3;
|
||||
p += 1;
|
||||
b := u64((^byte)(p)^)
|
||||
h = (h ~ b) * 0x100000001b3
|
||||
p += 1
|
||||
}
|
||||
return uintptr(h);
|
||||
return uintptr(h)
|
||||
}
|
||||
|
||||
// NOTE(bill): There are loads of predefined ones to improve optimizations for small types
|
||||
@@ -119,270 +119,270 @@ default_hasher15 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr
|
||||
default_hasher16 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return #force_inline _default_hasher_const(data, seed, 16); }
|
||||
|
||||
default_hasher_string :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr {
|
||||
h := u64(seed) + 0xcbf29ce484222325;
|
||||
str := (^[]byte)(data)^;
|
||||
h := u64(seed) + 0xcbf29ce484222325
|
||||
str := (^[]byte)(data)^
|
||||
for b in str {
|
||||
h = (h ~ u64(b)) * 0x100000001b3;
|
||||
h = (h ~ u64(b)) * 0x100000001b3
|
||||
}
|
||||
return uintptr(h);
|
||||
return uintptr(h)
|
||||
}
|
||||
default_hasher_cstring :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr {
|
||||
h := u64(seed) + 0xcbf29ce484222325;
|
||||
ptr := (^uintptr)(data)^;
|
||||
h := u64(seed) + 0xcbf29ce484222325
|
||||
ptr := (^uintptr)(data)^
|
||||
for (^byte)(ptr)^ != 0 {
|
||||
b := (^byte)(ptr)^;
|
||||
h = (h ~ u64(b)) * 0x100000001b3;
|
||||
ptr += 1;
|
||||
b := (^byte)(ptr)^
|
||||
h = (h ~ u64(b)) * 0x100000001b3
|
||||
ptr += 1
|
||||
}
|
||||
return uintptr(h);
|
||||
return uintptr(h)
|
||||
}
|
||||
|
||||
|
||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
header := Map_Header{m = (^Raw_Map)(m)};
|
||||
header := Map_Header{m = (^Raw_Map)(m)}
|
||||
Entry :: struct {
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
key: K,
|
||||
value: V,
|
||||
};
|
||||
}
|
||||
|
||||
header.equal = intrinsics.type_equal_proc(K);
|
||||
header.equal = intrinsics.type_equal_proc(K)
|
||||
|
||||
header.entry_size = size_of(Entry);
|
||||
header.entry_align = align_of(Entry);
|
||||
header.entry_size = size_of(Entry)
|
||||
header.entry_align = align_of(Entry)
|
||||
|
||||
header.key_offset = offset_of(Entry, key);
|
||||
header.key_size = size_of(K);
|
||||
header.key_offset = offset_of(Entry, key)
|
||||
header.key_size = size_of(K)
|
||||
|
||||
header.value_offset = offset_of(Entry, value);
|
||||
header.value_size = size_of(V);
|
||||
header.value_offset = offset_of(Entry, value)
|
||||
header.value_size = size_of(V)
|
||||
|
||||
return header;
|
||||
return header
|
||||
}
|
||||
|
||||
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
||||
array := (^Raw_Slice)(array_);
|
||||
array := (^Raw_Slice)(array_)
|
||||
|
||||
if new_count < array.len {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
assert(allocator.procedure != nil);
|
||||
assert(allocator.procedure != nil)
|
||||
|
||||
old_size := array.len*size_of(T);
|
||||
new_size := new_count*size_of(T);
|
||||
old_size := array.len*size_of(T)
|
||||
new_size := new_count*size_of(T)
|
||||
|
||||
new_data, err := mem_resize(array.data, old_size, new_size, align_of(T), allocator, loc);
|
||||
new_data, err := mem_resize(array.data, old_size, new_size, align_of(T), allocator, loc)
|
||||
if new_data == nil || err != nil {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
array.data = new_data;
|
||||
array.len = new_count;
|
||||
return true;
|
||||
array.data = new_data
|
||||
array.len = new_count
|
||||
return true
|
||||
}
|
||||
|
||||
__dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller_location) {
|
||||
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc);
|
||||
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc)
|
||||
|
||||
old_len := len(m.hashes);
|
||||
__slice_resize(&m.hashes, cap, m.entries.allocator, loc);
|
||||
old_len := len(m.hashes)
|
||||
__slice_resize(&m.hashes, cap, m.entries.allocator, loc)
|
||||
for i in old_len..<len(m.hashes) {
|
||||
m.hashes[i] = -1;
|
||||
m.hashes[i] = -1
|
||||
}
|
||||
|
||||
}
|
||||
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
|
||||
c := context;
|
||||
c := context
|
||||
if m.entries.allocator.procedure != nil {
|
||||
c.allocator = m.entries.allocator;
|
||||
c.allocator = m.entries.allocator
|
||||
}
|
||||
context = c;
|
||||
context = c
|
||||
|
||||
nm := Raw_Map{};
|
||||
nm.entries.allocator = m.entries.allocator;
|
||||
nm.hashes = m.hashes;
|
||||
nm := Raw_Map{}
|
||||
nm.entries.allocator = m.entries.allocator
|
||||
nm.hashes = m.hashes
|
||||
|
||||
new_header: Map_Header = header;
|
||||
new_header.m = &nm;
|
||||
new_header: Map_Header = header
|
||||
new_header.m = &nm
|
||||
|
||||
new_count := new_count;
|
||||
new_count = max(new_count, 2*m.entries.len);
|
||||
new_count := new_count
|
||||
new_count = max(new_count, 2*m.entries.len)
|
||||
|
||||
__slice_resize(&nm.hashes, new_count, m.entries.allocator, loc);
|
||||
__slice_resize(&nm.hashes, new_count, m.entries.allocator, loc)
|
||||
for i in 0 ..< new_count {
|
||||
nm.hashes[i] = -1;
|
||||
nm.hashes[i] = -1
|
||||
}
|
||||
|
||||
__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len, loc);
|
||||
__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len, loc)
|
||||
for i in 0 ..< m.entries.len {
|
||||
if len(nm.hashes) == 0 {
|
||||
__dynamic_map_grow(new_header, loc);
|
||||
__dynamic_map_grow(new_header, loc)
|
||||
}
|
||||
|
||||
entry_header := __dynamic_map_get_entry(header, i);
|
||||
entry_hash := __get_map_hash_from_entry(header, entry_header);
|
||||
entry_header := __dynamic_map_get_entry(header, i)
|
||||
entry_hash := __get_map_hash_from_entry(header, entry_header)
|
||||
|
||||
fr := __dynamic_map_find(new_header, entry_hash);
|
||||
j := __dynamic_map_add_entry(new_header, entry_hash, loc);
|
||||
fr := __dynamic_map_find(new_header, entry_hash)
|
||||
j := __dynamic_map_add_entry(new_header, entry_hash, loc)
|
||||
if fr.entry_prev < 0 {
|
||||
nm.hashes[fr.hash_index] = j;
|
||||
nm.hashes[fr.hash_index] = j
|
||||
} else {
|
||||
e := __dynamic_map_get_entry(new_header, fr.entry_prev);
|
||||
e.next = j;
|
||||
e := __dynamic_map_get_entry(new_header, fr.entry_prev)
|
||||
e.next = j
|
||||
}
|
||||
|
||||
e := __dynamic_map_get_entry(new_header, j);
|
||||
__dynamic_map_copy_entry(header, e, entry_header);
|
||||
e.next = fr.entry_index;
|
||||
e := __dynamic_map_get_entry(new_header, j)
|
||||
__dynamic_map_copy_entry(header, e, entry_header)
|
||||
e.next = fr.entry_index
|
||||
|
||||
if __dynamic_map_full(new_header) {
|
||||
__dynamic_map_grow(new_header, loc);
|
||||
__dynamic_map_grow(new_header, loc)
|
||||
}
|
||||
}
|
||||
|
||||
free(m.entries.data, m.entries.allocator, loc);
|
||||
header.m^ = nm;
|
||||
free(m.entries.data, m.entries.allocator, loc)
|
||||
header.m^ = nm
|
||||
}
|
||||
|
||||
__dynamic_map_get :: proc(h: Map_Header, hash: Map_Hash) -> rawptr {
|
||||
index := __dynamic_map_find(h, hash).entry_index;
|
||||
index := __dynamic_map_find(h, hash).entry_index
|
||||
if index >= 0 {
|
||||
data := uintptr(__dynamic_map_get_entry(h, index));
|
||||
return rawptr(data + h.value_offset);
|
||||
data := uintptr(__dynamic_map_get_entry(h, index))
|
||||
return rawptr(data + h.value_offset)
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
__dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
|
||||
index: int;
|
||||
assert(value != nil);
|
||||
index: int
|
||||
assert(value != nil)
|
||||
|
||||
if len(h.m.hashes) == 0 {
|
||||
__dynamic_map_reserve(h, INITIAL_MAP_CAP, loc);
|
||||
__dynamic_map_grow(h, loc);
|
||||
__dynamic_map_reserve(h, INITIAL_MAP_CAP, loc)
|
||||
__dynamic_map_grow(h, loc)
|
||||
}
|
||||
|
||||
fr := __dynamic_map_find(h, hash);
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
index = fr.entry_index;
|
||||
index = fr.entry_index
|
||||
} else {
|
||||
index = __dynamic_map_add_entry(h, hash, loc);
|
||||
index = __dynamic_map_add_entry(h, hash, loc)
|
||||
if fr.entry_prev >= 0 {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_prev);
|
||||
entry.next = index;
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
entry.next = index
|
||||
} else {
|
||||
h.m.hashes[fr.hash_index] = index;
|
||||
h.m.hashes[fr.hash_index] = index
|
||||
}
|
||||
}
|
||||
|
||||
e := __dynamic_map_get_entry(h, index);
|
||||
e.hash = hash.hash;
|
||||
e := __dynamic_map_get_entry(h, index)
|
||||
e.hash = hash.hash
|
||||
|
||||
key := rawptr(uintptr(e) + h.key_offset);
|
||||
mem_copy(key, hash.key_ptr, h.key_size);
|
||||
key := rawptr(uintptr(e) + h.key_offset)
|
||||
mem_copy(key, hash.key_ptr, h.key_size)
|
||||
|
||||
val := rawptr(uintptr(e) + h.value_offset);
|
||||
mem_copy(val, value, h.value_size);
|
||||
val := rawptr(uintptr(e) + h.value_offset)
|
||||
mem_copy(val, value, h.value_size)
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
__dynamic_map_grow(h, loc);
|
||||
index = __dynamic_map_find(h, hash).entry_index;
|
||||
assert(index >= 0);
|
||||
__dynamic_map_grow(h, loc)
|
||||
index = __dynamic_map_find(h, hash).entry_index
|
||||
assert(index >= 0)
|
||||
}
|
||||
|
||||
return __dynamic_map_get_entry(h, index);
|
||||
return __dynamic_map_get_entry(h, index)
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_grow :: proc(using h: Map_Header, loc := #caller_location) {
|
||||
// TODO(bill): Determine an efficient growing rate
|
||||
new_count := max(4*m.entries.cap + 7, INITIAL_MAP_CAP);
|
||||
__dynamic_map_rehash(h, new_count, loc);
|
||||
new_count := max(4*m.entries.cap + 7, INITIAL_MAP_CAP)
|
||||
__dynamic_map_rehash(h, new_count, loc)
|
||||
}
|
||||
|
||||
__dynamic_map_full :: #force_inline proc "contextless" (using h: Map_Header) -> bool {
|
||||
return int(0.75 * f64(len(m.hashes))) <= m.entries.len;
|
||||
return int(0.75 * f64(len(m.hashes))) <= m.entries.len
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_hash_equal :: proc "contextless" (h: Map_Header, a, b: Map_Hash) -> bool {
|
||||
if a.hash == b.hash {
|
||||
return h.equal(a.key_ptr, b.key_ptr);
|
||||
return h.equal(a.key_ptr, b.key_ptr)
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
__dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Result #no_bounds_check {
|
||||
fr := Map_Find_Result{-1, -1, -1};
|
||||
fr := Map_Find_Result{-1, -1, -1}
|
||||
if n := uintptr(len(m.hashes)); n > 0 {
|
||||
fr.hash_index = int(hash.hash % n);
|
||||
fr.entry_index = m.hashes[fr.hash_index];
|
||||
fr.hash_index = int(hash.hash % n)
|
||||
fr.entry_index = m.hashes[fr.hash_index]
|
||||
for fr.entry_index >= 0 {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index);
|
||||
entry_hash := __get_map_hash_from_entry(h, entry);
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
entry_hash := __get_map_hash_from_entry(h, entry)
|
||||
if __dynamic_map_hash_equal(h, entry_hash, hash) {
|
||||
return fr;
|
||||
return fr
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = entry.next;
|
||||
fr.entry_prev = fr.entry_index
|
||||
fr.entry_index = entry.next
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
return fr
|
||||
}
|
||||
|
||||
__dynamic_map_add_entry :: proc(using h: Map_Header, hash: Map_Hash, loc := #caller_location) -> int {
|
||||
prev := m.entries.len;
|
||||
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc);
|
||||
prev := m.entries.len
|
||||
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc)
|
||||
if c != prev {
|
||||
end := __dynamic_map_get_entry(h, c-1);
|
||||
end.hash = hash.hash;
|
||||
mem_copy(rawptr(uintptr(end) + key_offset), hash.key_ptr, key_size);
|
||||
end.next = -1;
|
||||
end := __dynamic_map_get_entry(h, c-1)
|
||||
end.hash = hash.hash
|
||||
mem_copy(rawptr(uintptr(end) + key_offset), hash.key_ptr, key_size)
|
||||
end.next = -1
|
||||
}
|
||||
return prev;
|
||||
return prev
|
||||
}
|
||||
|
||||
__dynamic_map_delete_key :: proc(using h: Map_Header, hash: Map_Hash) {
|
||||
fr := __dynamic_map_find(h, hash);
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
__dynamic_map_erase(h, fr);
|
||||
__dynamic_map_erase(h, fr)
|
||||
}
|
||||
}
|
||||
|
||||
__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header {
|
||||
assert(0 <= index && index < m.entries.len);
|
||||
return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size));
|
||||
assert(0 <= index && index < m.entries.len)
|
||||
return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size))
|
||||
}
|
||||
|
||||
__dynamic_map_copy_entry :: proc "contextless" (h: Map_Header, new, old: ^Map_Entry_Header) {
|
||||
mem_copy(new, old, h.entry_size);
|
||||
mem_copy(new, old, h.entry_size)
|
||||
}
|
||||
|
||||
__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
|
||||
if fr.entry_prev < 0 {
|
||||
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
|
||||
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
|
||||
} else {
|
||||
prev := __dynamic_map_get_entry(h, fr.entry_prev);
|
||||
curr := __dynamic_map_get_entry(h, fr.entry_index);
|
||||
prev.next = curr.next;
|
||||
prev := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
curr := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
prev.next = curr.next
|
||||
}
|
||||
if fr.entry_index == m.entries.len-1 {
|
||||
// NOTE(bill): No need to do anything else, just pop
|
||||
} else {
|
||||
old := __dynamic_map_get_entry(h, fr.entry_index);
|
||||
end := __dynamic_map_get_entry(h, m.entries.len-1);
|
||||
__dynamic_map_copy_entry(h, old, end);
|
||||
old := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
end := __dynamic_map_get_entry(h, m.entries.len-1)
|
||||
__dynamic_map_copy_entry(h, old, end)
|
||||
|
||||
old_hash := __get_map_hash_from_entry(h, old);
|
||||
old_hash := __get_map_hash_from_entry(h, old)
|
||||
|
||||
if last := __dynamic_map_find(h, old_hash); last.entry_prev >= 0 {
|
||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev);
|
||||
last_entry.next = fr.entry_index;
|
||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev)
|
||||
last_entry.next = fr.entry_index
|
||||
} else {
|
||||
m.hashes[last.hash_index] = fr.entry_index;
|
||||
m.hashes[last.hash_index] = fr.entry_index
|
||||
}
|
||||
}
|
||||
|
||||
m.entries.len -= 1;
|
||||
m.entries.len -= 1
|
||||
}
|
||||
|
||||
+107
-107
@@ -2,210 +2,210 @@ package runtime
|
||||
|
||||
bounds_trap :: proc "contextless" () -> ! {
|
||||
when ODIN_OS == "windows" {
|
||||
windows_trap_array_bounds();
|
||||
windows_trap_array_bounds()
|
||||
} else {
|
||||
trap();
|
||||
trap()
|
||||
}
|
||||
}
|
||||
|
||||
type_assertion_trap :: proc "contextless" () -> ! {
|
||||
when ODIN_OS == "windows" {
|
||||
windows_trap_type_assertion();
|
||||
windows_trap_type_assertion()
|
||||
} else {
|
||||
trap();
|
||||
trap()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
|
||||
if 0 <= index && index < count {
|
||||
return;
|
||||
return
|
||||
}
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""});
|
||||
print_string(" Index ");
|
||||
print_i64(i64(index));
|
||||
print_string(" is out of bounds range 0:");
|
||||
print_i64(i64(count));
|
||||
print_byte('\n');
|
||||
bounds_trap();
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Index ")
|
||||
print_i64(i64(index))
|
||||
print_string(" is out of bounds range 0:")
|
||||
print_i64(i64(count))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
}
|
||||
handle_error(file, line, column, index, count);
|
||||
handle_error(file, line, column, index, count)
|
||||
}
|
||||
|
||||
slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""});
|
||||
print_string(" Invalid slice indices: ");
|
||||
print_i64(i64(lo));
|
||||
print_string(":");
|
||||
print_i64(i64(hi));
|
||||
print_string(":");
|
||||
print_i64(i64(len));
|
||||
print_byte('\n');
|
||||
bounds_trap();
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid slice indices: ")
|
||||
print_i64(i64(lo))
|
||||
print_string(":")
|
||||
print_i64(i64(hi))
|
||||
print_string(":")
|
||||
print_i64(i64(len))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
}
|
||||
|
||||
multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""});
|
||||
print_string(" Invalid slice indices: ");
|
||||
print_i64(i64(lo));
|
||||
print_string(":");
|
||||
print_i64(i64(hi));
|
||||
print_byte('\n');
|
||||
bounds_trap();
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid slice indices: ")
|
||||
print_i64(i64(lo))
|
||||
print_string(":")
|
||||
print_i64(i64(hi))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
}
|
||||
|
||||
|
||||
multi_pointer_slice_expr_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) {
|
||||
if lo <= hi {
|
||||
return;
|
||||
return
|
||||
}
|
||||
multi_pointer_slice_handle_error(file, line, column, lo, hi);
|
||||
multi_pointer_slice_handle_error(file, line, column, lo, hi)
|
||||
}
|
||||
|
||||
slice_expr_error_hi :: proc "contextless" (file: string, line, column: i32, hi: int, len: int) {
|
||||
if 0 <= hi && hi <= len {
|
||||
return;
|
||||
return
|
||||
}
|
||||
slice_handle_error(file, line, column, 0, hi, len);
|
||||
slice_handle_error(file, line, column, 0, hi, len)
|
||||
}
|
||||
|
||||
slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) {
|
||||
if 0 <= lo && lo <= len && lo <= hi && hi <= len {
|
||||
return;
|
||||
return
|
||||
}
|
||||
slice_handle_error(file, line, column, lo, hi, len);
|
||||
slice_handle_error(file, line, column, lo, hi, len)
|
||||
}
|
||||
|
||||
dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
|
||||
if 0 <= low && low <= high && high <= max {
|
||||
return;
|
||||
return
|
||||
}
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""});
|
||||
print_string(" Invalid dynamic array values: ");
|
||||
print_i64(i64(low));
|
||||
print_string(":");
|
||||
print_i64(i64(high));
|
||||
print_string(":");
|
||||
print_i64(i64(max));
|
||||
print_byte('\n');
|
||||
bounds_trap();
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid dynamic array values: ")
|
||||
print_i64(i64(low))
|
||||
print_string(":")
|
||||
print_i64(i64(high))
|
||||
print_string(":")
|
||||
print_i64(i64(max))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
}
|
||||
handle_error(file, line, column, low, high, max);
|
||||
handle_error(file, line, column, low, high, max)
|
||||
}
|
||||
|
||||
|
||||
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) {
|
||||
if ok {
|
||||
return;
|
||||
return
|
||||
}
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""});
|
||||
print_string(" Invalid type assertion from ");
|
||||
print_typeid(from);
|
||||
print_string(" to ");
|
||||
print_typeid(to);
|
||||
print_byte('\n');
|
||||
type_assertion_trap();
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion from ")
|
||||
print_typeid(from)
|
||||
print_string(" to ")
|
||||
print_typeid(to)
|
||||
print_byte('\n')
|
||||
type_assertion_trap()
|
||||
}
|
||||
handle_error(file, line, column, from, to);
|
||||
handle_error(file, line, column, from, to)
|
||||
}
|
||||
|
||||
type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||
if ok {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid {
|
||||
if id == nil || data == nil {
|
||||
return id;
|
||||
return id
|
||||
}
|
||||
ti := type_info_base(type_info_of(id));
|
||||
ti := type_info_base(type_info_of(id))
|
||||
#partial switch v in ti.variant {
|
||||
case Type_Info_Any:
|
||||
return (^any)(data).id;
|
||||
return (^any)(data).id
|
||||
case Type_Info_Union:
|
||||
tag_ptr := uintptr(data) + v.tag_offset;
|
||||
idx := 0;
|
||||
tag_ptr := uintptr(data) + v.tag_offset
|
||||
idx := 0
|
||||
switch v.tag_type.size {
|
||||
case 1: idx = int((^u8)(tag_ptr)^) - 1;
|
||||
case 2: idx = int((^u16)(tag_ptr)^) - 1;
|
||||
case 4: idx = int((^u32)(tag_ptr)^) - 1;
|
||||
case 8: idx = int((^u64)(tag_ptr)^) - 1;
|
||||
case 16: idx = int((^u128)(tag_ptr)^) - 1;
|
||||
case 1: idx = int((^u8)(tag_ptr)^) - 1
|
||||
case 2: idx = int((^u16)(tag_ptr)^) - 1
|
||||
case 4: idx = int((^u32)(tag_ptr)^) - 1
|
||||
case 8: idx = int((^u64)(tag_ptr)^) - 1
|
||||
case 16: idx = int((^u128)(tag_ptr)^) - 1
|
||||
}
|
||||
if idx < 0 {
|
||||
return nil;
|
||||
return nil
|
||||
} else if idx < len(v.variants) {
|
||||
return v.variants[idx].id;
|
||||
return v.variants[idx].id
|
||||
}
|
||||
}
|
||||
return id;
|
||||
return id
|
||||
}
|
||||
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||
|
||||
actual := variant_type(from, from_data);
|
||||
actual := variant_type(from, from_data)
|
||||
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""});
|
||||
print_string(" Invalid type assertion from ");
|
||||
print_typeid(from);
|
||||
print_string(" to ");
|
||||
print_typeid(to);
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion from ")
|
||||
print_typeid(from)
|
||||
print_string(" to ")
|
||||
print_typeid(to)
|
||||
if actual != from {
|
||||
print_string(", actual type: ");
|
||||
print_typeid(actual);
|
||||
print_string(", actual type: ")
|
||||
print_typeid(actual)
|
||||
}
|
||||
print_byte('\n');
|
||||
type_assertion_trap();
|
||||
print_byte('\n')
|
||||
type_assertion_trap()
|
||||
}
|
||||
handle_error(file, line, column, from, to, from_data);
|
||||
handle_error(file, line, column, from, to, from_data)
|
||||
}
|
||||
|
||||
|
||||
make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_location, len: int) {
|
||||
if 0 <= len {
|
||||
return;
|
||||
return
|
||||
}
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
|
||||
print_caller_location(loc);
|
||||
print_string(" Invalid slice length for make: ");
|
||||
print_i64(i64(len));
|
||||
print_byte('\n');
|
||||
bounds_trap();
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid slice length for make: ")
|
||||
print_i64(i64(len))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
}
|
||||
handle_error(loc, len);
|
||||
handle_error(loc, len)
|
||||
}
|
||||
|
||||
make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, len, cap: int) {
|
||||
if 0 <= len && len <= cap {
|
||||
return;
|
||||
return
|
||||
}
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
|
||||
print_caller_location(loc);
|
||||
print_string(" Invalid dynamic array parameters for make: ");
|
||||
print_i64(i64(len));
|
||||
print_byte(':');
|
||||
print_i64(i64(cap));
|
||||
print_byte('\n');
|
||||
bounds_trap();
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid dynamic array parameters for make: ")
|
||||
print_i64(i64(len))
|
||||
print_byte(':')
|
||||
print_i64(i64(cap))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
}
|
||||
handle_error(loc, len, cap);
|
||||
handle_error(loc, len, cap)
|
||||
}
|
||||
|
||||
make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_location, cap: int) {
|
||||
if 0 <= cap {
|
||||
return;
|
||||
return
|
||||
}
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
|
||||
print_caller_location(loc);
|
||||
print_string(" Invalid map capacity for make: ");
|
||||
print_i64(i64(cap));
|
||||
print_byte('\n');
|
||||
bounds_trap();
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid map capacity for make: ")
|
||||
print_i64(i64(cap))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
}
|
||||
handle_error(loc, cap);
|
||||
handle_error(loc, cap)
|
||||
}
|
||||
|
||||
|
||||
@@ -213,17 +213,17 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca
|
||||
|
||||
|
||||
bounds_check_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, index, count: int) {
|
||||
bounds_check_error(file_path, line, column, index, count);
|
||||
bounds_check_error(file_path, line, column, index, count)
|
||||
}
|
||||
|
||||
slice_expr_error_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, hi: int, len: int) {
|
||||
slice_expr_error_hi(file_path, line, column, hi, len);
|
||||
slice_expr_error_hi(file_path, line, column, hi, len)
|
||||
}
|
||||
|
||||
slice_expr_error_lo_hi_loc :: #force_inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) {
|
||||
slice_expr_error_lo_hi(file_path, line, column, lo, hi, len);
|
||||
slice_expr_error_lo_hi(file_path, line, column, lo, hi, len)
|
||||
}
|
||||
|
||||
dynamic_array_expr_error_loc :: #force_inline proc "contextless" (using loc := #caller_location, low, high, max: int) {
|
||||
dynamic_array_expr_error(file_path, line, column, low, high, max);
|
||||
dynamic_array_expr_error(file_path, line, column, low, high, max)
|
||||
}
|
||||
|
||||
+318
-318
File diff suppressed because it is too large
Load Diff
@@ -4,86 +4,86 @@ import "core:intrinsics"
|
||||
|
||||
@(link_name="__umodti3")
|
||||
umodti3 :: proc "c" (a, b: u128) -> u128 {
|
||||
r: u128 = ---;
|
||||
_ = udivmod128(a, b, &r);
|
||||
return r;
|
||||
r: u128 = ---
|
||||
_ = udivmod128(a, b, &r)
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
@(link_name="__udivmodti4")
|
||||
udivmodti4 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
|
||||
return udivmod128(a, b, rem);
|
||||
return udivmod128(a, b, rem)
|
||||
}
|
||||
|
||||
@(link_name="__udivti3")
|
||||
udivti3 :: proc "c" (a, b: u128) -> u128 {
|
||||
return udivmodti4(a, b, nil);
|
||||
return udivmodti4(a, b, nil)
|
||||
}
|
||||
|
||||
|
||||
@(link_name="__modti3")
|
||||
modti3 :: proc "c" (a, b: i128) -> i128 {
|
||||
s_a := a >> (128 - 1);
|
||||
s_b := b >> (128 - 1);
|
||||
an := (a ~ s_a) - s_a;
|
||||
bn := (b ~ s_b) - s_b;
|
||||
s_a := a >> (128 - 1)
|
||||
s_b := b >> (128 - 1)
|
||||
an := (a ~ s_a) - s_a
|
||||
bn := (b ~ s_b) - s_b
|
||||
|
||||
r: u128 = ---;
|
||||
_ = udivmod128(transmute(u128)an, transmute(u128)bn, &r);
|
||||
return (transmute(i128)r ~ s_a) - s_a;
|
||||
r: u128 = ---
|
||||
_ = udivmod128(transmute(u128)an, transmute(u128)bn, &r)
|
||||
return (transmute(i128)r ~ s_a) - s_a
|
||||
}
|
||||
|
||||
|
||||
@(link_name="__divmodti4")
|
||||
divmodti4 :: proc "c" (a, b: i128, rem: ^i128) -> i128 {
|
||||
u := udivmod128(transmute(u128)a, transmute(u128)b, cast(^u128)rem);
|
||||
return transmute(i128)u;
|
||||
u := udivmod128(transmute(u128)a, transmute(u128)b, cast(^u128)rem)
|
||||
return transmute(i128)u
|
||||
}
|
||||
|
||||
@(link_name="__divti3")
|
||||
divti3 :: proc "c" (a, b: i128) -> i128 {
|
||||
u := udivmodti4(transmute(u128)a, transmute(u128)b, nil);
|
||||
return transmute(i128)u;
|
||||
u := udivmodti4(transmute(u128)a, transmute(u128)b, nil)
|
||||
return transmute(i128)u
|
||||
}
|
||||
|
||||
|
||||
@(link_name="__fixdfti")
|
||||
fixdfti :: proc(a: u64) -> i128 {
|
||||
significandBits :: 52;
|
||||
typeWidth :: (size_of(u64)*8);
|
||||
exponentBits :: (typeWidth - significandBits - 1);
|
||||
maxExponent :: ((1 << exponentBits) - 1);
|
||||
exponentBias :: (maxExponent >> 1);
|
||||
significandBits :: 52
|
||||
typeWidth :: (size_of(u64)*8)
|
||||
exponentBits :: (typeWidth - significandBits - 1)
|
||||
maxExponent :: ((1 << exponentBits) - 1)
|
||||
exponentBias :: (maxExponent >> 1)
|
||||
|
||||
implicitBit :: (u64(1) << significandBits);
|
||||
significandMask :: (implicitBit - 1);
|
||||
signBit :: (u64(1) << (significandBits + exponentBits));
|
||||
absMask :: (signBit - 1);
|
||||
exponentMask :: (absMask ~ significandMask);
|
||||
implicitBit :: (u64(1) << significandBits)
|
||||
significandMask :: (implicitBit - 1)
|
||||
signBit :: (u64(1) << (significandBits + exponentBits))
|
||||
absMask :: (signBit - 1)
|
||||
exponentMask :: (absMask ~ significandMask)
|
||||
|
||||
// Break a into sign, exponent, significand
|
||||
aRep := a;
|
||||
aAbs := aRep & absMask;
|
||||
sign := i128(-1 if aRep & signBit != 0 else 1);
|
||||
exponent := (aAbs >> significandBits) - exponentBias;
|
||||
significand := (aAbs & significandMask) | implicitBit;
|
||||
aRep := a
|
||||
aAbs := aRep & absMask
|
||||
sign := i128(-1 if aRep & signBit != 0 else 1)
|
||||
exponent := (aAbs >> significandBits) - exponentBias
|
||||
significand := (aAbs & significandMask) | implicitBit
|
||||
|
||||
// If exponent is negative, the result is zero.
|
||||
if exponent < 0 {
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
// If the value is too large for the integer type, saturate.
|
||||
if exponent >= size_of(i128) * 8 {
|
||||
return max(i128) if sign == 1 else min(i128);
|
||||
return max(i128) if sign == 1 else min(i128)
|
||||
}
|
||||
|
||||
// If 0 <= exponent < significandBits, right shift to get the result.
|
||||
// Otherwise, shift left.
|
||||
if exponent < significandBits {
|
||||
return sign * i128(significand >> (significandBits - exponent));
|
||||
return sign * i128(significand >> (significandBits - exponent))
|
||||
} else {
|
||||
return sign * (i128(significand) << (exponent - significandBits));
|
||||
return sign * (i128(significand) << (exponent - significandBits))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package runtime
|
||||
|
||||
_OS_Errno :: distinct int;
|
||||
_OS_Errno :: distinct int
|
||||
|
||||
os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||
return _os_write(data);
|
||||
return _os_write(data)
|
||||
}
|
||||
|
||||
@@ -26,59 +26,59 @@ foreign kernel32 {
|
||||
|
||||
_os_write :: proc "contextless" (data: []byte) -> (n: int, err: _OS_Errno) #no_bounds_check {
|
||||
if len(data) == 0 {
|
||||
return 0, 0;
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
STD_ERROR_HANDLE :: ~u32(0) -12 + 1;
|
||||
HANDLE_FLAG_INHERIT :: 0x00000001;
|
||||
MAX_RW :: 1<<30;
|
||||
STD_ERROR_HANDLE :: ~u32(0) -12 + 1
|
||||
HANDLE_FLAG_INHERIT :: 0x00000001
|
||||
MAX_RW :: 1<<30
|
||||
|
||||
h := GetStdHandle(STD_ERROR_HANDLE);
|
||||
h := GetStdHandle(STD_ERROR_HANDLE)
|
||||
when size_of(uintptr) == 8 {
|
||||
SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0);
|
||||
SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0)
|
||||
}
|
||||
|
||||
single_write_length: u32;
|
||||
total_write: i64;
|
||||
length := i64(len(data));
|
||||
single_write_length: u32
|
||||
total_write: i64
|
||||
length := i64(len(data))
|
||||
|
||||
for total_write < length {
|
||||
remaining := length - total_write;
|
||||
to_write := u32(min(i32(remaining), MAX_RW));
|
||||
remaining := length - total_write
|
||||
to_write := u32(min(i32(remaining), MAX_RW))
|
||||
|
||||
e := WriteFile(h, &data[total_write], to_write, &single_write_length, nil);
|
||||
e := WriteFile(h, &data[total_write], to_write, &single_write_length, nil)
|
||||
if single_write_length <= 0 || !e {
|
||||
err = _OS_Errno(GetLastError());
|
||||
n = int(total_write);
|
||||
return;
|
||||
err = _OS_Errno(GetLastError())
|
||||
n = int(total_write)
|
||||
return
|
||||
}
|
||||
total_write += i64(single_write_length);
|
||||
total_write += i64(single_write_length)
|
||||
}
|
||||
n = int(total_write);
|
||||
return;
|
||||
n = int(total_write)
|
||||
return
|
||||
}
|
||||
|
||||
heap_alloc :: proc "contextless" (size: int) -> rawptr {
|
||||
HEAP_ZERO_MEMORY :: 0x00000008;
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, uint(size));
|
||||
HEAP_ZERO_MEMORY :: 0x00000008
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, uint(size))
|
||||
}
|
||||
heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr {
|
||||
if new_size == 0 {
|
||||
heap_free(ptr);
|
||||
return nil;
|
||||
heap_free(ptr)
|
||||
return nil
|
||||
}
|
||||
if ptr == nil {
|
||||
return heap_alloc(new_size);
|
||||
return heap_alloc(new_size)
|
||||
}
|
||||
|
||||
HEAP_ZERO_MEMORY :: 0x00000008;
|
||||
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, uint(new_size));
|
||||
HEAP_ZERO_MEMORY :: 0x00000008
|
||||
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, uint(new_size))
|
||||
}
|
||||
heap_free :: proc "contextless" (ptr: rawptr) {
|
||||
if ptr == nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, ptr);
|
||||
HeapFree(GetProcessHeap(), 0, ptr)
|
||||
}
|
||||
|
||||
|
||||
@@ -93,46 +93,46 @@ heap_free :: proc "contextless" (ptr: rawptr) {
|
||||
|
||||
_windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, Allocator_Error) {
|
||||
if size == 0 {
|
||||
_windows_default_free(old_ptr);
|
||||
return nil, nil;
|
||||
_windows_default_free(old_ptr)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
a := max(alignment, align_of(rawptr));
|
||||
space := size + a - 1;
|
||||
a := max(alignment, align_of(rawptr))
|
||||
space := size + a - 1
|
||||
|
||||
allocated_mem: rawptr;
|
||||
allocated_mem: rawptr
|
||||
if old_ptr != nil {
|
||||
original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^;
|
||||
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr));
|
||||
original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^
|
||||
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
|
||||
} else {
|
||||
allocated_mem = heap_alloc(space+size_of(rawptr));
|
||||
allocated_mem = heap_alloc(space+size_of(rawptr))
|
||||
}
|
||||
aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr)));
|
||||
aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
||||
|
||||
ptr := uintptr(aligned_mem);
|
||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a);
|
||||
diff := int(aligned_ptr - ptr);
|
||||
ptr := uintptr(aligned_mem)
|
||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||
diff := int(aligned_ptr - ptr)
|
||||
if (size + diff) > space {
|
||||
return nil, .Out_Of_Memory;
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
|
||||
aligned_mem = rawptr(aligned_ptr);
|
||||
intrinsics.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem;
|
||||
aligned_mem = rawptr(aligned_ptr)
|
||||
intrinsics.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem
|
||||
|
||||
return byte_slice(aligned_mem, size), nil;
|
||||
return byte_slice(aligned_mem, size), nil
|
||||
}
|
||||
|
||||
_windows_default_alloc :: proc "contextless" (size, alignment: int) -> ([]byte, Allocator_Error) {
|
||||
return _windows_default_alloc_or_resize(size, alignment, nil);
|
||||
return _windows_default_alloc_or_resize(size, alignment, nil)
|
||||
}
|
||||
|
||||
|
||||
_windows_default_free :: proc "contextless" (ptr: rawptr) {
|
||||
if ptr != nil {
|
||||
heap_free(intrinsics.ptr_offset((^rawptr)(ptr), -1)^);
|
||||
heap_free(intrinsics.ptr_offset((^rawptr)(ptr), -1)^)
|
||||
}
|
||||
}
|
||||
|
||||
_windows_default_resize :: proc "contextless" (p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, Allocator_Error) {
|
||||
return _windows_default_alloc_or_resize(new_size, new_alignment, p);
|
||||
return _windows_default_alloc_or_resize(new_size, new_alignment, p)
|
||||
}
|
||||
|
||||
+188
-188
@@ -1,370 +1,370 @@
|
||||
package runtime
|
||||
|
||||
_INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
_INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
|
||||
r := c;
|
||||
r := c
|
||||
|
||||
buf: [4]u8;
|
||||
i := u32(r);
|
||||
mask :: u8(0x3f);
|
||||
buf: [4]u8
|
||||
i := u32(r)
|
||||
mask :: u8(0x3f)
|
||||
if i <= 1<<7-1 {
|
||||
buf[0] = u8(r);
|
||||
return buf, 1;
|
||||
buf[0] = u8(r)
|
||||
return buf, 1
|
||||
}
|
||||
if i <= 1<<11-1 {
|
||||
buf[0] = 0xc0 | u8(r>>6);
|
||||
buf[1] = 0x80 | u8(r) & mask;
|
||||
return buf, 2;
|
||||
buf[0] = 0xc0 | u8(r>>6)
|
||||
buf[1] = 0x80 | u8(r) & mask
|
||||
return buf, 2
|
||||
}
|
||||
|
||||
// Invalid or Surrogate range
|
||||
if i > 0x0010ffff ||
|
||||
(0xd800 <= i && i <= 0xdfff) {
|
||||
r = 0xfffd;
|
||||
r = 0xfffd
|
||||
}
|
||||
|
||||
if i <= 1<<16-1 {
|
||||
buf[0] = 0xe0 | u8(r>>12);
|
||||
buf[1] = 0x80 | u8(r>>6) & mask;
|
||||
buf[2] = 0x80 | u8(r) & mask;
|
||||
return buf, 3;
|
||||
buf[0] = 0xe0 | u8(r>>12)
|
||||
buf[1] = 0x80 | u8(r>>6) & mask
|
||||
buf[2] = 0x80 | u8(r) & mask
|
||||
return buf, 3
|
||||
}
|
||||
|
||||
buf[0] = 0xf0 | u8(r>>18);
|
||||
buf[1] = 0x80 | u8(r>>12) & mask;
|
||||
buf[2] = 0x80 | u8(r>>6) & mask;
|
||||
buf[3] = 0x80 | u8(r) & mask;
|
||||
return buf, 4;
|
||||
buf[0] = 0xf0 | u8(r>>18)
|
||||
buf[1] = 0x80 | u8(r>>12) & mask
|
||||
buf[2] = 0x80 | u8(r>>6) & mask
|
||||
buf[3] = 0x80 | u8(r) & mask
|
||||
return buf, 4
|
||||
}
|
||||
|
||||
print_string :: proc "contextless" (str: string) -> (int, _OS_Errno) {
|
||||
return os_write(transmute([]byte)str);
|
||||
return os_write(transmute([]byte)str)
|
||||
}
|
||||
|
||||
print_strings :: proc "contextless" (args: ..string) -> (n: int, err: _OS_Errno) {
|
||||
for str in args {
|
||||
m: int;
|
||||
m, err = os_write(transmute([]byte)str);
|
||||
n += m;
|
||||
m: int
|
||||
m, err = os_write(transmute([]byte)str)
|
||||
n += m
|
||||
if err != 0 {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
print_byte :: proc "contextless" (b: byte) -> (int, _OS_Errno) {
|
||||
return os_write([]byte{b});
|
||||
return os_write([]byte{b})
|
||||
}
|
||||
|
||||
print_encoded_rune :: proc "contextless" (r: rune) {
|
||||
print_byte('\'');
|
||||
print_byte('\'')
|
||||
|
||||
switch r {
|
||||
case '\a': print_string("\\a");
|
||||
case '\b': print_string("\\b");
|
||||
case '\e': print_string("\\e");
|
||||
case '\f': print_string("\\f");
|
||||
case '\n': print_string("\\n");
|
||||
case '\r': print_string("\\r");
|
||||
case '\t': print_string("\\t");
|
||||
case '\v': print_string("\\v");
|
||||
case '\a': print_string("\\a")
|
||||
case '\b': print_string("\\b")
|
||||
case '\e': print_string("\\e")
|
||||
case '\f': print_string("\\f")
|
||||
case '\n': print_string("\\n")
|
||||
case '\r': print_string("\\r")
|
||||
case '\t': print_string("\\t")
|
||||
case '\v': print_string("\\v")
|
||||
case:
|
||||
if r <= 0 {
|
||||
print_string("\\x00");
|
||||
print_string("\\x00")
|
||||
} else if r < 32 {
|
||||
digits := _INTEGER_DIGITS;
|
||||
n0, n1 := u8(r) >> 4, u8(r) & 0xf;
|
||||
print_string("\\x");
|
||||
print_byte(digits[n0]);
|
||||
print_byte(digits[n1]);
|
||||
digits := _INTEGER_DIGITS
|
||||
n0, n1 := u8(r) >> 4, u8(r) & 0xf
|
||||
print_string("\\x")
|
||||
print_byte(digits[n0])
|
||||
print_byte(digits[n1])
|
||||
} else {
|
||||
print_rune(r);
|
||||
print_rune(r)
|
||||
}
|
||||
}
|
||||
print_byte('\'');
|
||||
print_byte('\'')
|
||||
}
|
||||
|
||||
print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) #no_bounds_check {
|
||||
RUNE_SELF :: 0x80;
|
||||
RUNE_SELF :: 0x80
|
||||
|
||||
if r < RUNE_SELF {
|
||||
return print_byte(byte(r));
|
||||
return print_byte(byte(r))
|
||||
}
|
||||
|
||||
b, n := encode_rune(r);
|
||||
return os_write(b[:n]);
|
||||
b, n := encode_rune(r)
|
||||
return os_write(b[:n])
|
||||
}
|
||||
|
||||
|
||||
print_u64 :: proc "contextless" (x: u64) #no_bounds_check {
|
||||
digits := _INTEGER_DIGITS;
|
||||
digits := _INTEGER_DIGITS
|
||||
|
||||
a: [129]byte;
|
||||
i := len(a);
|
||||
b := u64(10);
|
||||
u := x;
|
||||
a: [129]byte
|
||||
i := len(a)
|
||||
b := u64(10)
|
||||
u := x
|
||||
for u >= b {
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
u /= b;
|
||||
i -= 1; a[i] = digits[u % b]
|
||||
u /= b
|
||||
}
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
i -= 1; a[i] = digits[u % b]
|
||||
|
||||
os_write(a[i:]);
|
||||
os_write(a[i:])
|
||||
}
|
||||
|
||||
|
||||
print_i64 :: proc "contextless" (x: i64) #no_bounds_check {
|
||||
digits := _INTEGER_DIGITS;
|
||||
b :: i64(10);
|
||||
digits := _INTEGER_DIGITS
|
||||
b :: i64(10)
|
||||
|
||||
u := x;
|
||||
neg := u < 0;
|
||||
u = abs(u);
|
||||
u := x
|
||||
neg := u < 0
|
||||
u = abs(u)
|
||||
|
||||
a: [129]byte;
|
||||
i := len(a);
|
||||
a: [129]byte
|
||||
i := len(a)
|
||||
for u >= b {
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
u /= b;
|
||||
i -= 1; a[i] = digits[u % b]
|
||||
u /= b
|
||||
}
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
i -= 1; a[i] = digits[u % b]
|
||||
if neg {
|
||||
i -= 1; a[i] = '-';
|
||||
i -= 1; a[i] = '-'
|
||||
}
|
||||
|
||||
os_write(a[i:]);
|
||||
os_write(a[i:])
|
||||
}
|
||||
|
||||
print_caller_location :: proc "contextless" (using loc: Source_Code_Location) {
|
||||
print_string(file_path);
|
||||
print_byte('(');
|
||||
print_u64(u64(line));
|
||||
print_byte(':');
|
||||
print_u64(u64(column));
|
||||
print_byte(')');
|
||||
print_string(file_path)
|
||||
print_byte('(')
|
||||
print_u64(u64(line))
|
||||
print_byte(':')
|
||||
print_u64(u64(column))
|
||||
print_byte(')')
|
||||
}
|
||||
print_typeid :: proc "contextless" (id: typeid) {
|
||||
if id == nil {
|
||||
print_string("nil");
|
||||
print_string("nil")
|
||||
} else {
|
||||
ti := type_info_of(id);
|
||||
print_type(ti);
|
||||
ti := type_info_of(id)
|
||||
print_type(ti)
|
||||
}
|
||||
}
|
||||
print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
if ti == nil {
|
||||
print_string("nil");
|
||||
return;
|
||||
print_string("nil")
|
||||
return
|
||||
}
|
||||
|
||||
switch info in ti.variant {
|
||||
case Type_Info_Named:
|
||||
print_string(info.name);
|
||||
print_string(info.name)
|
||||
case Type_Info_Integer:
|
||||
switch ti.id {
|
||||
case int: print_string("int");
|
||||
case uint: print_string("uint");
|
||||
case uintptr: print_string("uintptr");
|
||||
case int: print_string("int")
|
||||
case uint: print_string("uint")
|
||||
case uintptr: print_string("uintptr")
|
||||
case:
|
||||
print_byte('i' if info.signed else 'u');
|
||||
print_u64(u64(8*ti.size));
|
||||
print_byte('i' if info.signed else 'u')
|
||||
print_u64(u64(8*ti.size))
|
||||
}
|
||||
case Type_Info_Rune:
|
||||
print_string("rune");
|
||||
print_string("rune")
|
||||
case Type_Info_Float:
|
||||
print_byte('f');
|
||||
print_u64(u64(8*ti.size));
|
||||
print_byte('f')
|
||||
print_u64(u64(8*ti.size))
|
||||
case Type_Info_Complex:
|
||||
print_string("complex");
|
||||
print_u64(u64(8*ti.size));
|
||||
print_string("complex")
|
||||
print_u64(u64(8*ti.size))
|
||||
case Type_Info_Quaternion:
|
||||
print_string("quaternion");
|
||||
print_u64(u64(8*ti.size));
|
||||
print_string("quaternion")
|
||||
print_u64(u64(8*ti.size))
|
||||
case Type_Info_String:
|
||||
print_string("string");
|
||||
print_string("string")
|
||||
case Type_Info_Boolean:
|
||||
switch ti.id {
|
||||
case bool: print_string("bool");
|
||||
case bool: print_string("bool")
|
||||
case:
|
||||
print_byte('b');
|
||||
print_u64(u64(8*ti.size));
|
||||
print_byte('b')
|
||||
print_u64(u64(8*ti.size))
|
||||
}
|
||||
case Type_Info_Any:
|
||||
print_string("any");
|
||||
print_string("any")
|
||||
case Type_Info_Type_Id:
|
||||
print_string("typeid");
|
||||
print_string("typeid")
|
||||
|
||||
case Type_Info_Pointer:
|
||||
if info.elem == nil {
|
||||
print_string("rawptr");
|
||||
print_string("rawptr")
|
||||
} else {
|
||||
print_string("^");
|
||||
print_type(info.elem);
|
||||
print_string("^")
|
||||
print_type(info.elem)
|
||||
}
|
||||
case Type_Info_Multi_Pointer:
|
||||
print_string("[^]");
|
||||
print_type(info.elem);
|
||||
print_string("[^]")
|
||||
print_type(info.elem)
|
||||
case Type_Info_Procedure:
|
||||
print_string("proc");
|
||||
print_string("proc")
|
||||
if info.params == nil {
|
||||
print_string("()");
|
||||
print_string("()")
|
||||
} else {
|
||||
t := info.params.variant.(Type_Info_Tuple);
|
||||
print_byte('(');
|
||||
t := info.params.variant.(Type_Info_Tuple)
|
||||
print_byte('(')
|
||||
for t, i in t.types {
|
||||
if i > 0 { print_string(", "); }
|
||||
print_type(t);
|
||||
print_type(t)
|
||||
}
|
||||
print_string(")");
|
||||
print_string(")")
|
||||
}
|
||||
if info.results != nil {
|
||||
print_string(" -> ");
|
||||
print_type(info.results);
|
||||
print_string(" -> ")
|
||||
print_type(info.results)
|
||||
}
|
||||
case Type_Info_Tuple:
|
||||
count := len(info.names);
|
||||
count := len(info.names)
|
||||
if count != 1 { print_byte('('); }
|
||||
for name, i in info.names {
|
||||
if i > 0 { print_string(", "); }
|
||||
|
||||
t := info.types[i];
|
||||
t := info.types[i]
|
||||
|
||||
if len(name) > 0 {
|
||||
print_string(name);
|
||||
print_string(": ");
|
||||
print_string(name)
|
||||
print_string(": ")
|
||||
}
|
||||
print_type(t);
|
||||
print_type(t)
|
||||
}
|
||||
if count != 1 { print_string(")"); }
|
||||
|
||||
case Type_Info_Array:
|
||||
print_byte('[');
|
||||
print_u64(u64(info.count));
|
||||
print_byte(']');
|
||||
print_type(info.elem);
|
||||
print_byte('[')
|
||||
print_u64(u64(info.count))
|
||||
print_byte(']')
|
||||
print_type(info.elem)
|
||||
|
||||
case Type_Info_Enumerated_Array:
|
||||
print_byte('[');
|
||||
print_type(info.index);
|
||||
print_byte(']');
|
||||
print_type(info.elem);
|
||||
print_byte('[')
|
||||
print_type(info.index)
|
||||
print_byte(']')
|
||||
print_type(info.elem)
|
||||
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
print_string("[dynamic]");
|
||||
print_type(info.elem);
|
||||
print_string("[dynamic]")
|
||||
print_type(info.elem)
|
||||
case Type_Info_Slice:
|
||||
print_string("[]");
|
||||
print_type(info.elem);
|
||||
print_string("[]")
|
||||
print_type(info.elem)
|
||||
|
||||
case Type_Info_Map:
|
||||
print_string("map[");
|
||||
print_type(info.key);
|
||||
print_byte(']');
|
||||
print_type(info.value);
|
||||
print_string("map[")
|
||||
print_type(info.key)
|
||||
print_byte(']')
|
||||
print_type(info.value)
|
||||
|
||||
case Type_Info_Struct:
|
||||
switch info.soa_kind {
|
||||
case .None: // Ignore
|
||||
case .Fixed:
|
||||
print_string("#soa[");
|
||||
print_u64(u64(info.soa_len));
|
||||
print_byte(']');
|
||||
print_type(info.soa_base_type);
|
||||
return;
|
||||
print_string("#soa[")
|
||||
print_u64(u64(info.soa_len))
|
||||
print_byte(']')
|
||||
print_type(info.soa_base_type)
|
||||
return
|
||||
case .Slice:
|
||||
print_string("#soa[]");
|
||||
print_type(info.soa_base_type);
|
||||
return;
|
||||
print_string("#soa[]")
|
||||
print_type(info.soa_base_type)
|
||||
return
|
||||
case .Dynamic:
|
||||
print_string("#soa[dynamic]");
|
||||
print_type(info.soa_base_type);
|
||||
return;
|
||||
print_string("#soa[dynamic]")
|
||||
print_type(info.soa_base_type)
|
||||
return
|
||||
}
|
||||
|
||||
print_string("struct ");
|
||||
print_string("struct ")
|
||||
if info.is_packed { print_string("#packed "); }
|
||||
if info.is_raw_union { print_string("#raw_union "); }
|
||||
if info.custom_align {
|
||||
print_string("#align ");
|
||||
print_u64(u64(ti.align));
|
||||
print_byte(' ');
|
||||
print_string("#align ")
|
||||
print_u64(u64(ti.align))
|
||||
print_byte(' ')
|
||||
}
|
||||
print_byte('{');
|
||||
print_byte('{')
|
||||
for name, i in info.names {
|
||||
if i > 0 { print_string(", "); }
|
||||
print_string(name);
|
||||
print_string(": ");
|
||||
print_type(info.types[i]);
|
||||
print_string(name)
|
||||
print_string(": ")
|
||||
print_type(info.types[i])
|
||||
}
|
||||
print_byte('}');
|
||||
print_byte('}')
|
||||
|
||||
case Type_Info_Union:
|
||||
print_string("union ");
|
||||
print_string("union ")
|
||||
if info.custom_align {
|
||||
print_string("#align ");
|
||||
print_u64(u64(ti.align));
|
||||
print_string("#align ")
|
||||
print_u64(u64(ti.align))
|
||||
}
|
||||
if info.no_nil {
|
||||
print_string("#no_nil ");
|
||||
print_string("#no_nil ")
|
||||
}
|
||||
print_byte('{');
|
||||
print_byte('{')
|
||||
for variant, i in info.variants {
|
||||
if i > 0 { print_string(", "); }
|
||||
print_type(variant);
|
||||
print_type(variant)
|
||||
}
|
||||
print_string("}");
|
||||
print_string("}")
|
||||
|
||||
case Type_Info_Enum:
|
||||
print_string("enum ");
|
||||
print_type(info.base);
|
||||
print_string(" {");
|
||||
print_string("enum ")
|
||||
print_type(info.base)
|
||||
print_string(" {")
|
||||
for name, i in info.names {
|
||||
if i > 0 { print_string(", "); }
|
||||
print_string(name);
|
||||
print_string(name)
|
||||
}
|
||||
print_string("}");
|
||||
print_string("}")
|
||||
|
||||
case Type_Info_Bit_Set:
|
||||
print_string("bit_set[");
|
||||
print_string("bit_set[")
|
||||
|
||||
#partial switch elem in type_info_base(info.elem).variant {
|
||||
case Type_Info_Enum:
|
||||
print_type(info.elem);
|
||||
print_type(info.elem)
|
||||
case Type_Info_Rune:
|
||||
print_encoded_rune(rune(info.lower));
|
||||
print_string("..");
|
||||
print_encoded_rune(rune(info.upper));
|
||||
print_encoded_rune(rune(info.lower))
|
||||
print_string("..")
|
||||
print_encoded_rune(rune(info.upper))
|
||||
case:
|
||||
print_i64(info.lower);
|
||||
print_string("..");
|
||||
print_i64(info.upper);
|
||||
print_i64(info.lower)
|
||||
print_string("..")
|
||||
print_i64(info.upper)
|
||||
}
|
||||
if info.underlying != nil {
|
||||
print_string("; ");
|
||||
print_type(info.underlying);
|
||||
print_string("; ")
|
||||
print_type(info.underlying)
|
||||
}
|
||||
print_byte(']');
|
||||
print_byte(']')
|
||||
|
||||
|
||||
case Type_Info_Simd_Vector:
|
||||
print_string("#simd[");
|
||||
print_u64(u64(info.count));
|
||||
print_byte(']');
|
||||
print_type(info.elem);
|
||||
print_string("#simd[")
|
||||
print_u64(u64(info.count))
|
||||
print_byte(']')
|
||||
print_type(info.elem)
|
||||
|
||||
case Type_Info_Relative_Pointer:
|
||||
print_string("#relative(");
|
||||
print_type(info.base_integer);
|
||||
print_string(") ");
|
||||
print_type(info.pointer);
|
||||
print_string("#relative(")
|
||||
print_type(info.base_integer)
|
||||
print_string(") ")
|
||||
print_type(info.pointer)
|
||||
|
||||
case Type_Info_Relative_Slice:
|
||||
print_string("#relative(");
|
||||
print_type(info.base_integer);
|
||||
print_string(") ");
|
||||
print_type(info.slice);
|
||||
print_string("#relative(")
|
||||
print_type(info.base_integer)
|
||||
print_string(") ")
|
||||
print_type(info.slice)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ foreign kernel32 {
|
||||
}
|
||||
|
||||
windows_trap_array_bounds :: proc "contextless" () -> ! {
|
||||
EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C;
|
||||
EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C
|
||||
|
||||
|
||||
RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0, 0, nil);
|
||||
RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0, 0, nil)
|
||||
}
|
||||
|
||||
windows_trap_type_assertion :: proc "contextless" () -> ! {
|
||||
windows_trap_array_bounds();
|
||||
windows_trap_array_bounds()
|
||||
}
|
||||
|
||||
// @private
|
||||
@@ -32,10 +32,10 @@ memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||
RtlCopyMemory :: proc "c" (dst, src: rawptr, len: int) ---
|
||||
}
|
||||
if dst == nil || src == nil || len == 0 {
|
||||
return dst;
|
||||
return dst
|
||||
}
|
||||
RtlCopyMemory(dst, src, len);
|
||||
return dst;
|
||||
RtlCopyMemory(dst, src, len)
|
||||
return dst
|
||||
}
|
||||
|
||||
// @(link_name="memmove")
|
||||
@@ -44,27 +44,27 @@ memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||
RtlMoveMemory :: proc "c" (dst, src: rawptr, len: int) ---
|
||||
}
|
||||
if dst == nil || src == nil || len == 0 {
|
||||
return dst;
|
||||
return dst
|
||||
}
|
||||
RtlMoveMemory(dst, src, len);
|
||||
return dst;
|
||||
RtlMoveMemory(dst, src, len)
|
||||
return dst
|
||||
}
|
||||
|
||||
// @(link_name="memset")
|
||||
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
|
||||
if ptr == nil || len == 0 {
|
||||
return ptr;
|
||||
return ptr
|
||||
}
|
||||
|
||||
b := byte(val);
|
||||
b := byte(val)
|
||||
|
||||
p_start := uintptr(ptr);
|
||||
p_end := p_start + uintptr(max(len, 0));
|
||||
p_start := uintptr(ptr)
|
||||
p_end := p_start + uintptr(max(len, 0))
|
||||
for p := p_start; p < p_end; p += 1 {
|
||||
(^byte)(p)^ = b;
|
||||
(^byte)(p)^ = b
|
||||
}
|
||||
|
||||
return ptr;
|
||||
return ptr
|
||||
}
|
||||
|
||||
// @(link_name="memcmp")
|
||||
|
||||
@@ -3,154 +3,154 @@ package runtime
|
||||
import "core:intrinsics"
|
||||
|
||||
udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
|
||||
_ctz :: intrinsics.count_trailing_zeros;
|
||||
_clz :: intrinsics.count_leading_zeros;
|
||||
_ctz :: intrinsics.count_trailing_zeros
|
||||
_clz :: intrinsics.count_leading_zeros
|
||||
|
||||
n := transmute([2]u64)a;
|
||||
d := transmute([2]u64)b;
|
||||
q, r: [2]u64 = ---, ---;
|
||||
sr: u32 = 0;
|
||||
n := transmute([2]u64)a
|
||||
d := transmute([2]u64)b
|
||||
q, r: [2]u64 = ---, ---
|
||||
sr: u32 = 0
|
||||
|
||||
low :: 1 when ODIN_ENDIAN == "big" else 0;
|
||||
high :: 1 - low;
|
||||
U64_BITS :: 8*size_of(u64);
|
||||
U128_BITS :: 8*size_of(u128);
|
||||
low :: 1 when ODIN_ENDIAN == "big" else 0
|
||||
high :: 1 - low
|
||||
U64_BITS :: 8*size_of(u64)
|
||||
U128_BITS :: 8*size_of(u128)
|
||||
|
||||
// Special Cases
|
||||
|
||||
if n[high] == 0 {
|
||||
if d[high] == 0 {
|
||||
if rem != nil {
|
||||
res := n[low] % d[low];
|
||||
rem^ = u128(res);
|
||||
res := n[low] % d[low]
|
||||
rem^ = u128(res)
|
||||
}
|
||||
return u128(n[low] / d[low]);
|
||||
return u128(n[low] / d[low])
|
||||
}
|
||||
|
||||
if rem != nil {
|
||||
rem^ = u128(n[low]);
|
||||
rem^ = u128(n[low])
|
||||
}
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
if d[low] == 0 {
|
||||
if d[high] == 0 {
|
||||
if rem != nil {
|
||||
rem^ = u128(n[high] % d[low]);
|
||||
rem^ = u128(n[high] % d[low])
|
||||
}
|
||||
return u128(n[high] / d[low]);
|
||||
return u128(n[high] / d[low])
|
||||
}
|
||||
if n[low] == 0 {
|
||||
if rem != nil {
|
||||
r[high] = n[high] % d[high];
|
||||
r[low] = 0;
|
||||
rem^ = transmute(u128)r;
|
||||
r[high] = n[high] % d[high]
|
||||
r[low] = 0
|
||||
rem^ = transmute(u128)r
|
||||
}
|
||||
return u128(n[high] / d[high]);
|
||||
return u128(n[high] / d[high])
|
||||
}
|
||||
|
||||
if d[high] & (d[high]-1) == 0 {
|
||||
if rem != nil {
|
||||
r[low] = n[low];
|
||||
r[high] = n[high] & (d[high] - 1);
|
||||
rem^ = transmute(u128)r;
|
||||
r[low] = n[low]
|
||||
r[high] = n[high] & (d[high] - 1)
|
||||
rem^ = transmute(u128)r
|
||||
}
|
||||
return u128(n[high] >> _ctz(d[high]));
|
||||
return u128(n[high] >> _ctz(d[high]))
|
||||
}
|
||||
|
||||
sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high])));
|
||||
sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high])))
|
||||
if sr > U64_BITS - 2 {
|
||||
if rem != nil {
|
||||
rem^ = a;
|
||||
rem^ = a
|
||||
}
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
sr += 1;
|
||||
sr += 1
|
||||
|
||||
q[low] = 0;
|
||||
q[high] = n[low] << u64(U64_BITS - sr);
|
||||
r[high] = n[high] >> sr;
|
||||
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
|
||||
q[low] = 0
|
||||
q[high] = n[low] << u64(U64_BITS - sr)
|
||||
r[high] = n[high] >> sr
|
||||
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr)
|
||||
} else {
|
||||
if d[high] == 0 {
|
||||
if d[low] & (d[low] - 1) == 0 {
|
||||
if rem != nil {
|
||||
rem^ = u128(n[low] & (d[low] - 1));
|
||||
rem^ = u128(n[low] & (d[low] - 1))
|
||||
}
|
||||
if d[low] == 1 {
|
||||
return a;
|
||||
return a
|
||||
}
|
||||
sr = u32(_ctz(d[low]));
|
||||
q[high] = n[high] >> sr;
|
||||
q[low] = (n[high] << (U64_BITS-sr)) | (n[low] >> sr);
|
||||
return transmute(u128)q;
|
||||
sr = u32(_ctz(d[low]))
|
||||
q[high] = n[high] >> sr
|
||||
q[low] = (n[high] << (U64_BITS-sr)) | (n[low] >> sr)
|
||||
return transmute(u128)q
|
||||
}
|
||||
|
||||
sr = 1 + U64_BITS + u32(_clz(d[low])) - u32(_clz(n[high]));
|
||||
sr = 1 + U64_BITS + u32(_clz(d[low])) - u32(_clz(n[high]))
|
||||
|
||||
switch {
|
||||
case sr == U64_BITS:
|
||||
q[low] = 0;
|
||||
q[high] = n[low];
|
||||
r[high] = 0;
|
||||
r[low] = n[high];
|
||||
q[low] = 0
|
||||
q[high] = n[low]
|
||||
r[high] = 0
|
||||
r[low] = n[high]
|
||||
case sr < U64_BITS:
|
||||
q[low] = 0;
|
||||
q[high] = n[low] << (U64_BITS - sr);
|
||||
r[high] = n[high] >> sr;
|
||||
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
|
||||
q[low] = 0
|
||||
q[high] = n[low] << (U64_BITS - sr)
|
||||
r[high] = n[high] >> sr
|
||||
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr)
|
||||
case:
|
||||
q[low] = n[low] << (U128_BITS - sr);
|
||||
q[high] = (n[high] << (U128_BITS - sr)) | (n[low] >> (sr - U64_BITS));
|
||||
r[high] = 0;
|
||||
r[low] = n[high] >> (sr - U64_BITS);
|
||||
q[low] = n[low] << (U128_BITS - sr)
|
||||
q[high] = (n[high] << (U128_BITS - sr)) | (n[low] >> (sr - U64_BITS))
|
||||
r[high] = 0
|
||||
r[low] = n[high] >> (sr - U64_BITS)
|
||||
}
|
||||
} else {
|
||||
sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high])));
|
||||
sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high])))
|
||||
|
||||
if sr > U64_BITS - 1 {
|
||||
if rem != nil {
|
||||
rem^ = a;
|
||||
rem^ = a
|
||||
}
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
sr += 1;
|
||||
sr += 1
|
||||
|
||||
q[low] = 0;
|
||||
q[low] = 0
|
||||
if sr == U64_BITS {
|
||||
q[high] = n[low];
|
||||
r[high] = 0;
|
||||
r[low] = n[high];
|
||||
q[high] = n[low]
|
||||
r[high] = 0
|
||||
r[low] = n[high]
|
||||
} else {
|
||||
r[high] = n[high] >> sr;
|
||||
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
|
||||
q[high] = n[low] << (U64_BITS - sr);
|
||||
r[high] = n[high] >> sr
|
||||
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr)
|
||||
q[high] = n[low] << (U64_BITS - sr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
carry: u32 = 0;
|
||||
r_all: u128 = ---;
|
||||
carry: u32 = 0
|
||||
r_all: u128 = ---
|
||||
|
||||
for ; sr > 0; sr -= 1 {
|
||||
r[high] = (r[high] << 1) | (r[low] >> (U64_BITS - 1));
|
||||
r[low] = (r[low] << 1) | (q[high] >> (U64_BITS - 1));
|
||||
q[high] = (q[high] << 1) | (q[low] >> (U64_BITS - 1));
|
||||
q[low] = (q[low] << 1) | u64(carry);
|
||||
r[high] = (r[high] << 1) | (r[low] >> (U64_BITS - 1))
|
||||
r[low] = (r[low] << 1) | (q[high] >> (U64_BITS - 1))
|
||||
q[high] = (q[high] << 1) | (q[low] >> (U64_BITS - 1))
|
||||
q[low] = (q[low] << 1) | u64(carry)
|
||||
|
||||
r_all = transmute(u128)r;
|
||||
s := i128(b - r_all - 1) >> (U128_BITS - 1);
|
||||
carry = u32(s & 1);
|
||||
r_all -= b & transmute(u128)s;
|
||||
r = transmute([2]u64)r_all;
|
||||
r_all = transmute(u128)r
|
||||
s := i128(b - r_all - 1) >> (U128_BITS - 1)
|
||||
carry = u32(s & 1)
|
||||
r_all -= b & transmute(u128)s
|
||||
r = transmute([2]u64)r_all
|
||||
}
|
||||
|
||||
q_all := ((transmute(u128)q) << 1) | u128(carry);
|
||||
q_all := ((transmute(u128)q) << 1) | u128(carry)
|
||||
if rem != nil {
|
||||
rem^ = r_all;
|
||||
rem^ = r_all
|
||||
}
|
||||
|
||||
return q_all;
|
||||
return q_all
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user