Remove unneeded semicolons from the core library

This commit is contained in:
gingerBill
2021-08-31 22:21:13 +01:00
parent b176af2742
commit 251da264ed
187 changed files with 27227 additions and 27227 deletions
+86 -86
View File
@@ -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
View File
@@ -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
View File
@@ -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,
};
}
+7 -7
View File
@@ -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,
};
}
}
+74 -74
View File
@@ -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,
};
}
}
+44 -44
View File
@@ -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
}
+152 -152
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+35 -35
View File
@@ -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))
}
}
+2 -2
View File
@@ -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)
}
+46 -46
View File
@@ -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
View File
@@ -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)
}
}
+15 -15
View File
@@ -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")
+77 -77
View File
@@ -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
}