mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-22 15:37:51 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
// This is purely for documentation
|
||||
package builtin
|
||||
|
||||
nil :: nil;
|
||||
false :: 0!==0;
|
||||
true :: 0==0;
|
||||
|
||||
ODIN_OS :: ODIN_OS;
|
||||
ODIN_ARCH :: ODIN_ARCH;
|
||||
ODIN_ENDIAN :: ODIN_ENDIAN;
|
||||
ODIN_VENDOR :: ODIN_VENDOR;
|
||||
ODIN_VERSION :: ODIN_VERSION;
|
||||
ODIN_ROOT :: ODIN_ROOT;
|
||||
ODIN_DEBUG :: ODIN_DEBUG;
|
||||
|
||||
byte :: u8; // alias
|
||||
|
||||
bool :: bool;
|
||||
b8 :: b8;
|
||||
b16 :: b16;
|
||||
b32 :: b32;
|
||||
b64 :: b64;
|
||||
|
||||
i8 :: i8;
|
||||
u8 :: u8;
|
||||
i16 :: i16;
|
||||
u16 :: u16;
|
||||
i32 :: i32;
|
||||
u32 :: u32;
|
||||
i64 :: i64;
|
||||
u64 :: u64;
|
||||
|
||||
i128 :: i128;
|
||||
u128 :: u128;
|
||||
|
||||
rune :: rune;
|
||||
|
||||
f16 :: f16;
|
||||
f32 :: f32;
|
||||
f64 :: f64;
|
||||
|
||||
complex32 :: complex32;
|
||||
complex64 :: complex64;
|
||||
complex128 :: complex128;
|
||||
|
||||
quaternion128 :: quaternion128;
|
||||
quaternion256 :: quaternion256;
|
||||
|
||||
int :: int;
|
||||
uint :: uint;
|
||||
uintptr :: uintptr;
|
||||
|
||||
rawptr :: rawptr;
|
||||
string :: string;
|
||||
cstring :: cstring;
|
||||
any :: any;
|
||||
|
||||
typeid :: typeid;
|
||||
|
||||
// Endian Specific Types
|
||||
i16le :: i16le;
|
||||
u16le :: u16le;
|
||||
i32le :: i32le;
|
||||
u32le :: u32le;
|
||||
i64le :: i64le;
|
||||
u64le :: u64le;
|
||||
i128le :: i128le;
|
||||
u128le :: u128le;
|
||||
|
||||
i16be :: i16be;
|
||||
u16be :: u16be;
|
||||
i32be :: i32be;
|
||||
u32be :: u32be;
|
||||
i64be :: i64be;
|
||||
u64be :: u64be;
|
||||
i128be :: i128be;
|
||||
u128be :: u128be;
|
||||
|
||||
// Procedures
|
||||
len :: proc(array: Array_Type) -> int ---
|
||||
cap :: proc(array: Array_Type) -> int ---
|
||||
|
||||
size_of :: proc($T: typeid) -> int ---
|
||||
align_of :: proc($T: typeid) -> int ---
|
||||
offset_of :: proc($T: typeid) -> uintptr ---
|
||||
type_of :: proc(x: expr) -> type ---
|
||||
type_info_of :: proc($T: typeid) -> ^runtime.Type_Info ---
|
||||
typeid_of :: proc($T: typeid) -> typeid ---
|
||||
|
||||
swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T ---
|
||||
|
||||
complex :: proc(real, imag: Float) -> Complex_Type ---
|
||||
quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type ---
|
||||
real :: proc(value: Complex_Or_Quaternion) -> Float ---
|
||||
imag :: proc(value: Complex_Or_Quaternion) -> Float ---
|
||||
jmag :: proc(value: Quaternion) -> Float ---
|
||||
kmag :: proc(value: Quaternion) -> Float ---
|
||||
conj :: proc(value: Complex_Or_Quaternion) -> Complex_Or_Quaternion ---
|
||||
|
||||
expand_to_tuple :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
|
||||
|
||||
min :: proc(values: ..T) -> T ---
|
||||
max :: proc(values: ..T) -> T ---
|
||||
abs :: proc(value: T) -> T ---
|
||||
clamp :: proc(value, minimum, maximum: T) -> T ---
|
||||
@@ -31,3 +31,5 @@ ssize_t :: b.int;
|
||||
ptrdiff_t :: b.int;
|
||||
uintptr_t :: b.uintptr;
|
||||
intptr_t :: b.int;
|
||||
|
||||
wchar_t :: (ODIN_OS == "windows") ? b.u16 : b.u32;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package base64
|
||||
|
||||
// @note(zh): Encoding utility for Base64
|
||||
// A secondary param can be used to supply a custom alphabet to
|
||||
// @link(encode) and a matching decoding table to @link(decode).
|
||||
// If none is supplied it just uses the standard Base64 alphabet.
|
||||
// Incase your specific version does not use padding, you may
|
||||
// truncate it from the encoded output.
|
||||
|
||||
ENC_TABLE := [64]byte {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
PADDING :: '=';
|
||||
|
||||
DEC_TABLE := [128]int {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, 62, -1, -1, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22,
|
||||
23, 24, 25, -1, -1, -1, -1, -1,
|
||||
-1, 26, 27, 28, 29, 30, 31, 32,
|
||||
33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48,
|
||||
49, 50, 51, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string #no_bounds_check {
|
||||
length := len(data);
|
||||
if length == 0 do return "";
|
||||
|
||||
out_length := ((4 * length / 3) + 3) &~ 3;
|
||||
out := make([]byte, out_length, allocator);
|
||||
|
||||
c0, c1, c2, block: int;
|
||||
|
||||
for i, d := 0, 0; i < length; i, d = i + 3, d + 4 {
|
||||
c0, c1, c2 = int(data[i]), 0, 0;
|
||||
|
||||
if i + 1 < length do c1 = int(data[i + 1]);
|
||||
if i + 2 < length do c2 = int(data[i + 2]);
|
||||
|
||||
block = (c0 << 16) | (max(c1, 0) << 8) | max(c2, 0);
|
||||
|
||||
out[d] = ENC_TBL[block >> 18 & 63];
|
||||
out[d + 1] = ENC_TBL[block >> 12 & 63];
|
||||
out[d + 2] = c1 == 0 ? PADDING : ENC_TBL[block >> 6 & 63];
|
||||
out[d + 3] = c2 == 0 ? PADDING : ENC_TBL[block & 63];
|
||||
}
|
||||
return string(out);
|
||||
}
|
||||
|
||||
decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{
|
||||
length := len(data);
|
||||
if length == 0 do return []byte{};
|
||||
|
||||
pad_count := data[length - 1] == PADDING ? (data[length - 2] == PADDING ? 2 : 1) : 0;
|
||||
out_length := ((length * 6) >> 3) - pad_count;
|
||||
out := make([]byte, out_length, allocator);
|
||||
|
||||
c0, c1, c2, c3: int;
|
||||
b0, b1, b2: int;
|
||||
|
||||
for i, j := 0, 0; i < length; i, j = i + 4, j + 3 {
|
||||
c0 = DEC_TBL[data[i]];
|
||||
c1 = DEC_TBL[data[i + 1]];
|
||||
c2 = DEC_TBL[data[i + 2]];
|
||||
c3 = DEC_TBL[data[i + 3]];
|
||||
|
||||
b0 = (c0 << 2) | (c1 >> 4);
|
||||
b1 = (c1 << 4) | (c2 >> 2);
|
||||
b2 = (c2 << 6) | c3;
|
||||
|
||||
out[j] = byte(b0);
|
||||
out[j + 1] = byte(b1);
|
||||
out[j + 2] = byte(b2);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -168,9 +168,9 @@ destroy :: proc(p: ^Parser) {
|
||||
}
|
||||
|
||||
error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
|
||||
fmt.printf_err("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
|
||||
fmt.printf_err(msg, ..args);
|
||||
fmt.println_err();
|
||||
fmt.eprintf("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
|
||||
fmt.eprintf(msg, ..args);
|
||||
fmt.eprintln();
|
||||
|
||||
p.error_count += 1;
|
||||
}
|
||||
|
||||
@@ -183,9 +183,9 @@ tokenizer_init :: proc(t: ^Tokenizer, src: []byte, file := "") {
|
||||
}
|
||||
|
||||
token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) {
|
||||
fmt.printf_err("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
|
||||
fmt.printf_err(msg, ..args);
|
||||
fmt.println_err();
|
||||
fmt.eprintf("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
|
||||
fmt.eprintf(msg, ..args);
|
||||
fmt.eprintln();
|
||||
t.error_count += 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import "core:math/bits"
|
||||
import "core:runtime"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:types"
|
||||
import "core:reflect"
|
||||
|
||||
Marshal_Error :: enum {
|
||||
None,
|
||||
@@ -194,7 +194,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
||||
data := uintptr(entries.data) + uintptr(i*entry_size);
|
||||
header := cast(^Map_Entry_Header)data;
|
||||
|
||||
if types.is_string(info.key) {
|
||||
if reflect.is_string(info.key) {
|
||||
marshal_arg(b, header.key.str);
|
||||
} else {
|
||||
marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
|
||||
@@ -284,11 +284,10 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
||||
t := runtime.type_info_base(ti);
|
||||
switch info in t.variant {
|
||||
case runtime.Type_Info_Integer:
|
||||
using runtime.Type_Info_Endianness;
|
||||
switch info.endianness {
|
||||
case Platform: return false;
|
||||
case Little: return ODIN_ENDIAN != "little";
|
||||
case Big: return ODIN_ENDIAN != "big";
|
||||
case .Platform: return false;
|
||||
case .Little: return ODIN_ENDIAN != "little";
|
||||
case .Big: return ODIN_ENDIAN != "big";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
+57
-231
@@ -5,9 +5,9 @@ import "core:os"
|
||||
import "core:mem"
|
||||
import "core:math/bits"
|
||||
import "core:unicode/utf8"
|
||||
import "core:types"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:reflect"
|
||||
|
||||
|
||||
@private
|
||||
@@ -59,12 +59,18 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
||||
|
||||
|
||||
// print* procedures return the number of bytes written
|
||||
print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
|
||||
print_err :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
|
||||
println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
|
||||
println_err :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
|
||||
printf_err :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
|
||||
print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
|
||||
println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
|
||||
|
||||
eprint :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
|
||||
eprintln :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
|
||||
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
|
||||
|
||||
|
||||
@(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); }
|
||||
@(deprecated="prefer eprintf") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); }
|
||||
@(deprecated="prefer eprintln") println_err :: proc(args: ..any) -> int { return eprintln(..args); }
|
||||
|
||||
|
||||
// aprint* procedures return a string that was allocated with the current context
|
||||
@@ -143,7 +149,7 @@ panicf :: proc "contextless" (fmt: string, args: ..any, loc := #caller_location)
|
||||
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
|
||||
data: [DEFAULT_BUFFER_SIZE]byte;
|
||||
buf := strings.builder_from_slice(data[:]);
|
||||
write_type(&buf, info);
|
||||
reflect.write_type(&buf, info);
|
||||
os.write_string(fd, strings.to_string(buf));
|
||||
}
|
||||
|
||||
@@ -156,7 +162,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any) -> string {
|
||||
fi.buf = buf;
|
||||
|
||||
for arg, i in args {
|
||||
is_string := arg != nil && types.is_string(type_info_of(arg.id));
|
||||
is_string := arg != nil && reflect.is_string(type_info_of(arg.id));
|
||||
if i > 0 && !is_string && !prev_string {
|
||||
strings.write_byte(buf, ' ');
|
||||
}
|
||||
@@ -399,7 +405,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
|
||||
strings.write_rune(buf, verb);
|
||||
strings.write_byte(buf, '(');
|
||||
if arg.id != nil {
|
||||
write_typeid(buf, arg.id);
|
||||
reflect.write_typeid(buf, arg.id);
|
||||
strings.write_byte(buf, '=');
|
||||
fmt_value(fi, arg, 'v');
|
||||
} else {
|
||||
@@ -792,7 +798,7 @@ enum_value_to_string :: proc(val: any) -> (string, bool) {
|
||||
case: return "", false;
|
||||
case runtime.Type_Info_Enum:
|
||||
get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
|
||||
if types.is_string(e.base) {
|
||||
if reflect.is_string(e.base) {
|
||||
for val, idx in e.values {
|
||||
if v, ok := val.(T); ok && v == i {
|
||||
return e.names[idx], true;
|
||||
@@ -947,7 +953,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
||||
if name != "" {
|
||||
strings.write_string(fi.buf, name);
|
||||
} else {
|
||||
write_type(fi.buf, type_info);
|
||||
reflect.write_type(fi.buf, type_info);
|
||||
}
|
||||
strings.write_byte(fi.buf, '{');
|
||||
defer strings.write_byte(fi.buf, '}');
|
||||
@@ -1042,7 +1048,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
|
||||
if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok {
|
||||
elem := rt.type_info_base(ot.elem);
|
||||
if elem == nil do return;
|
||||
write_type(fi.buf, type_info);
|
||||
reflect.write_type(fi.buf, type_info);
|
||||
strings.write_byte(fi.buf, '{');
|
||||
defer strings.write_byte(fi.buf, '}');
|
||||
|
||||
@@ -1053,7 +1059,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
|
||||
// Okay
|
||||
}
|
||||
} else {
|
||||
write_type(fi.buf, type_info);
|
||||
reflect.write_type(fi.buf, type_info);
|
||||
strings.write_byte(fi.buf, '{');
|
||||
strings.write_byte(fi.buf, '}');
|
||||
}
|
||||
@@ -1101,7 +1107,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
strings.write_string(fi.buf, name);
|
||||
strings.write_string(fi.buf, " = ");
|
||||
|
||||
if t := b.types[i]; types.is_any(t) {
|
||||
if t := b.types[i]; reflect.is_any(t) {
|
||||
strings.write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := rawptr(uintptr(v.data) + b.offsets[i]);
|
||||
@@ -1129,11 +1135,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
case runtime.Type_Info_Rune: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Float: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Complex: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_String: fmt_arg(fi, v, verb);
|
||||
|
||||
case runtime.Type_Info_Pointer:
|
||||
if v.id == typeid_of(^runtime.Type_Info) {
|
||||
write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
|
||||
reflect.write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
|
||||
} else {
|
||||
ptr := (^rawptr)(v.data)^;
|
||||
if verb != 'p' && info.elem != nil {
|
||||
@@ -1256,7 +1263,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
data := uintptr(entries.data) + uintptr(i*entry_size);
|
||||
header := cast(^runtime.Map_Entry_Header)data;
|
||||
|
||||
if types.is_string(info.key) {
|
||||
if reflect.is_string(info.key) {
|
||||
strings.write_string(fi.buf, header.key.str);
|
||||
} else {
|
||||
fi := Info{buf = fi.buf};
|
||||
@@ -1297,7 +1304,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
strings.write_string(fi.buf, info.names[i]);
|
||||
strings.write_string(fi.buf, " = ");
|
||||
|
||||
if t := info.types[i]; types.is_any(t) {
|
||||
if t := info.types[i]; reflect.is_any(t) {
|
||||
strings.write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := uintptr(v.data) + info.offsets[i];
|
||||
@@ -1349,14 +1356,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
if ptr == nil {
|
||||
strings.write_string(fi.buf, "nil");
|
||||
} else {
|
||||
write_typeid(fi.buf, v.id);
|
||||
reflect.write_typeid(fi.buf, v.id);
|
||||
strings.write_string(fi.buf, " @ ");
|
||||
fmt_pointer(fi, ptr, 'p');
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Type_Id:
|
||||
id := (^typeid)(v.data)^;
|
||||
write_typeid(fi.buf, id);
|
||||
reflect.write_typeid(fi.buf, id);
|
||||
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
fmt_bit_field(fi, v);
|
||||
@@ -1386,6 +1393,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
|
||||
}
|
||||
}
|
||||
|
||||
fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) {
|
||||
switch verb {
|
||||
case 'f', 'F', 'v', 'h', 'H':
|
||||
r, i, j, k := real(q), imag(q), jmag(q), kmag(q);
|
||||
|
||||
fmt_float(fi, r, bits/4, verb);
|
||||
|
||||
if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+');
|
||||
fmt_float(fi, i, bits/4, verb);
|
||||
strings.write_rune(fi.buf, 'i');
|
||||
|
||||
if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+');
|
||||
fmt_float(fi, j, bits/4, verb);
|
||||
strings.write_rune(fi.buf, 'j');
|
||||
|
||||
if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+');
|
||||
fmt_float(fi, k, bits/4, verb);
|
||||
strings.write_rune(fi.buf, 'k');
|
||||
|
||||
case:
|
||||
fmt_bad_verb(fi, verb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
if arg == nil {
|
||||
strings.write_string(fi.buf, "<nil>");
|
||||
@@ -1398,7 +1430,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
switch a in arg {
|
||||
case ^runtime.Type_Info: ti = a;
|
||||
}
|
||||
write_type(fi.buf, ti);
|
||||
reflect.write_type(fi.buf, ti);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1434,6 +1466,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
case complex64: fmt_complex(fi, complex128(a), 64, verb);
|
||||
case complex128: fmt_complex(fi, a, 128, verb);
|
||||
|
||||
case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb);
|
||||
case quaternion256: fmt_quaternion(fi, a, 256, verb);
|
||||
|
||||
case i8: fmt_int(fi, u64(a), true, 8, verb);
|
||||
case u8: fmt_int(fi, u64(a), false, 8, verb);
|
||||
case i16: fmt_int(fi, u64(a), true, 16, verb);
|
||||
@@ -1449,7 +1484,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
case string: fmt_string(fi, a, verb);
|
||||
case cstring: fmt_cstring(fi, a, verb);
|
||||
|
||||
case typeid: write_typeid(fi.buf, a);
|
||||
case typeid: reflect.write_typeid(fi.buf, a);
|
||||
|
||||
case i16le: fmt_int(fi, u64(a), true, 16, verb);
|
||||
case u16le: fmt_int(fi, u64(a), false, 16, verb);
|
||||
@@ -1482,212 +1517,3 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
|
||||
|
||||
|
||||
|
||||
write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
|
||||
write_type(buf, type_info_of(id));
|
||||
}
|
||||
|
||||
write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) {
|
||||
using strings;
|
||||
if ti == nil {
|
||||
write_string(buf, "nil");
|
||||
return;
|
||||
}
|
||||
|
||||
switch info in ti.variant {
|
||||
case runtime.Type_Info_Named:
|
||||
write_string(buf, info.name);
|
||||
case runtime.Type_Info_Integer:
|
||||
switch ti.id {
|
||||
case int: write_string(buf, "int");
|
||||
case uint: write_string(buf, "uint");
|
||||
case uintptr: write_string(buf, "uintptr");
|
||||
case:
|
||||
write_byte(buf, info.signed ? 'i' : 'u');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
switch info.endianness {
|
||||
case runtime.Type_Info_Endianness.Little:
|
||||
write_string(buf, "le");
|
||||
case runtime.Type_Info_Endianness.Big:
|
||||
write_string(buf, "be");
|
||||
}
|
||||
}
|
||||
case runtime.Type_Info_Rune:
|
||||
write_string(buf, "rune");
|
||||
case runtime.Type_Info_Float:
|
||||
write_byte(buf, 'f');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case runtime.Type_Info_Complex:
|
||||
write_string(buf, "complex");
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case runtime.Type_Info_String:
|
||||
if info.is_cstring {
|
||||
write_string(buf, "cstring");
|
||||
} else {
|
||||
write_string(buf, "string");
|
||||
}
|
||||
case runtime.Type_Info_Boolean:
|
||||
switch ti.id {
|
||||
case bool: write_string(buf, "bool");
|
||||
case:
|
||||
write_byte(buf, 'b');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
}
|
||||
case runtime.Type_Info_Any:
|
||||
write_string(buf, "any");
|
||||
|
||||
case runtime.Type_Info_Type_Id:
|
||||
write_string(buf, "typeid");
|
||||
|
||||
case runtime.Type_Info_Pointer:
|
||||
if info.elem == nil {
|
||||
write_string(buf, "rawptr");
|
||||
} else {
|
||||
write_string(buf, "^");
|
||||
write_type(buf, info.elem);
|
||||
}
|
||||
case runtime.Type_Info_Procedure:
|
||||
write_string(buf, "proc");
|
||||
if info.params == nil {
|
||||
write_string(buf, "()");
|
||||
} else {
|
||||
t := info.params.variant.(runtime.Type_Info_Tuple);
|
||||
write_string(buf, "(");
|
||||
for t, i in t.types {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_type(buf, t);
|
||||
}
|
||||
write_string(buf, ")");
|
||||
}
|
||||
if info.results != nil {
|
||||
write_string(buf, " -> ");
|
||||
write_type(buf, info.results);
|
||||
}
|
||||
case runtime.Type_Info_Tuple:
|
||||
count := len(info.names);
|
||||
if count != 1 do write_string(buf, "(");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
|
||||
t := info.types[i];
|
||||
|
||||
if len(name) > 0 {
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
}
|
||||
write_type(buf, t);
|
||||
}
|
||||
if count != 1 do write_string(buf, ")");
|
||||
|
||||
case runtime.Type_Info_Array:
|
||||
write_string(buf, "[");
|
||||
write_i64(buf, i64(info.count), 10);
|
||||
write_string(buf, "]");
|
||||
write_type(buf, info.elem);
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
write_string(buf, "[dynamic]");
|
||||
write_type(buf, info.elem);
|
||||
case runtime.Type_Info_Slice:
|
||||
write_string(buf, "[]");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case runtime.Type_Info_Map:
|
||||
write_string(buf, "map[");
|
||||
write_type(buf, info.key);
|
||||
write_byte(buf, ']');
|
||||
write_type(buf, info.value);
|
||||
|
||||
case runtime.Type_Info_Struct:
|
||||
write_string(buf, "struct ");
|
||||
if info.is_packed do write_string(buf, "#packed ");
|
||||
if info.is_raw_union do write_string(buf, "#raw_union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_type(buf, info.types[i]);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case runtime.Type_Info_Union:
|
||||
write_string(buf, "union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for variant, i in info.variants {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_type(buf, variant);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case runtime.Type_Info_Enum:
|
||||
write_string(buf, "enum ");
|
||||
write_type(buf, info.base);
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
write_string(buf, "bit_field ");
|
||||
if ti.align != 1 {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_i64(buf, i64(info.bits[i]), 10);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
write_string(buf, "bit_set[");
|
||||
switch {
|
||||
case types.is_enum(info.elem):
|
||||
write_type(buf, info.elem);
|
||||
case types.is_rune(info.elem):
|
||||
write_encoded_rune(buf, rune(info.lower));
|
||||
write_string(buf, "..");
|
||||
write_encoded_rune(buf, rune(info.upper));
|
||||
case:
|
||||
write_i64(buf, info.lower, 10);
|
||||
write_string(buf, "..");
|
||||
write_i64(buf, info.upper, 10);
|
||||
}
|
||||
if info.underlying != nil {
|
||||
write_string(buf, "; ");
|
||||
write_type(buf, info.underlying);
|
||||
}
|
||||
write_byte(buf, ']');
|
||||
|
||||
case runtime.Type_Info_Opaque:
|
||||
write_string(buf, "opaque ");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case runtime.Type_Info_Simd_Vector:
|
||||
if info.is_x86_mmx {
|
||||
write_string(buf, "intrinsics.x86_mmx");
|
||||
} else {
|
||||
write_string(buf, "intrinsics.vector(");
|
||||
write_i64(buf, i64(info.count));
|
||||
write_string(buf, ", ");
|
||||
write_type(buf, info.elem);
|
||||
write_byte(buf, ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// This is purely for documentation
|
||||
package intrinsics
|
||||
|
||||
|
||||
vector :: proc() ---
|
||||
|
||||
atomic_fence :: proc() ---
|
||||
atomic_fence_acq :: proc() ---
|
||||
atomic_fence_rel :: proc() ---
|
||||
atomic_fence_acqrel :: proc() ---
|
||||
|
||||
atomic_store :: proc(dst: ^$T, val: $T) ---
|
||||
atomic_store_rel :: proc(dst: ^$T, val: $T) ---
|
||||
atomic_store_relaxed :: proc(dst: ^$T, val: $T) ---
|
||||
atomic_store_unordered :: proc(dst: ^$T, val: $T) ---
|
||||
|
||||
atomic_load :: proc(dst: ^$T) -> T ---
|
||||
atomic_load_acq :: proc(dst: ^$T) -> T ---
|
||||
atomic_load_relaxed :: proc(dst: ^$T) -> T ---
|
||||
atomic_load_unordered :: proc(dst: ^$T) -> T ---
|
||||
|
||||
atomic_add :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_add_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_add_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_add_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_add_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_nand :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_nand_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_nand_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_nand_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_nand_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_or :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_or_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_or_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_or_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_or_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xor :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xor_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xor_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xor_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xor_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
|
||||
atomic_xchg :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xchg_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xchg_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xchg_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xchg_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
|
||||
atomic_cxchg :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
|
||||
atomic_cxchgweak :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
|
||||
|
||||
// Constant type tests
|
||||
|
||||
type_base_type :: proc($T: typeid) -> type ---
|
||||
type_core_type :: proc($T: typeid) -> type ---
|
||||
type_elem_type :: proc($T: typeid) -> type ---
|
||||
|
||||
type_is_boolean :: proc($T: typeid) -> bool ---
|
||||
type_is_integer :: proc($T: typeid) -> bool ---
|
||||
type_is_rune :: proc($T: typeid) -> bool ---
|
||||
type_is_float :: proc($T: typeid) -> bool ---
|
||||
type_is_complex :: proc($T: typeid) -> bool ---
|
||||
type_is_quaternion :: proc($T: typeid) -> bool ---
|
||||
type_is_string :: proc($T: typeid) -> bool ---
|
||||
type_is_typeid :: proc($T: typeid) -> bool ---
|
||||
type_is_any :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_is_endian_little :: proc($T: typeid) -> bool ---
|
||||
type_is_endian_big :: proc($T: typeid) -> bool ---
|
||||
type_is_numeric :: proc($T: typeid) -> bool ---
|
||||
type_is_ordered :: proc($T: typeid) -> bool ---
|
||||
type_is_ordered_numeric :: proc($T: typeid) -> bool ---
|
||||
type_is_indexable :: proc($T: typeid) -> bool ---
|
||||
type_is_sliceable :: proc($T: typeid) -> bool ---
|
||||
type_is_simple_compare :: proc($T: typeid) -> bool --- // easily compared using memcmp
|
||||
type_is_dereferenceable :: proc($T: typeid) -> bool ---
|
||||
type_is_valid_map_key :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_is_named :: proc($T: typeid) -> bool ---
|
||||
type_is_pointer :: proc($T: typeid) -> bool ---
|
||||
type_is_opaque :: proc($T: typeid) -> bool ---
|
||||
type_is_array :: proc($T: typeid) -> bool ---
|
||||
type_is_slice :: proc($T: typeid) -> bool ---
|
||||
type_is_dynamic_array :: proc($T: typeid) -> bool ---
|
||||
type_is_map :: proc($T: typeid) -> bool ---
|
||||
type_is_struct :: proc($T: typeid) -> bool ---
|
||||
type_is_union :: proc($T: typeid) -> bool ---
|
||||
type_is_enum :: proc($T: typeid) -> bool ---
|
||||
type_is_proc :: proc($T: typeid) -> bool ---
|
||||
type_is_bit_field :: proc($T: typeid) -> bool ---
|
||||
type_is_bit_field_value :: proc($T: typeid) -> bool ---
|
||||
type_is_bit_set :: proc($T: typeid) -> bool ---
|
||||
type_is_simd_vector :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_has_nil :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_proc_parameter_count :: proc($T: typeid) -> int where type_is_proc(T) ---
|
||||
type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) ---
|
||||
@@ -14,18 +14,18 @@ Level_Headers := []string{
|
||||
};
|
||||
|
||||
Default_Console_Logger_Opts :: Options{
|
||||
Option.Level,
|
||||
Option.Terminal_Color,
|
||||
Option.Short_File_Path,
|
||||
Option.Line,
|
||||
Option.Procedure,
|
||||
.Level,
|
||||
.Terminal_Color,
|
||||
.Short_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
} | Full_Timestamp_Opts;
|
||||
|
||||
Default_File_Logger_Opts :: Options{
|
||||
Option.Level,
|
||||
Option.Short_File_Path,
|
||||
Option.Line,
|
||||
Option.Procedure,
|
||||
.Level,
|
||||
.Short_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
} | Full_Timestamp_Opts;
|
||||
|
||||
|
||||
@@ -109,10 +109,10 @@ do_level_header :: proc(opts : Options, level : Level, str : ^strings.Builder) {
|
||||
case Level.Error, Level.Fatal : col = RED;
|
||||
}
|
||||
|
||||
if Option.Level in opts {
|
||||
if Option.Terminal_Color in opts do fmt.sbprint(str, col);
|
||||
if .Level in opts {
|
||||
if .Terminal_Color in opts do fmt.sbprint(str, col);
|
||||
fmt.sbprint(str, Level_Headers[level]);
|
||||
if Option.Terminal_Color in opts do fmt.sbprint(str, RESET);
|
||||
if .Terminal_Color in opts do fmt.sbprint(str, RESET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
|
||||
if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
|
||||
|
||||
file := location.file_path;
|
||||
if Option.Short_File_Path in opts {
|
||||
if .Short_File_Path in opts {
|
||||
when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/';
|
||||
last := 0;
|
||||
for r, i in location.file_path do if r == delimiter do last = i+1;
|
||||
@@ -129,13 +129,13 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
|
||||
|
||||
if Location_File_Opts & opts != nil do fmt.sbprint(buf, file);
|
||||
|
||||
if Option.Procedure in opts {
|
||||
if .Procedure in opts {
|
||||
if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
|
||||
fmt.sbprintf(buf, "%s()", location.procedure);
|
||||
}
|
||||
|
||||
if Option.Line in opts {
|
||||
if Location_File_Opts & opts != nil || Option.Procedure in opts do fmt.sbprint(buf, ":");
|
||||
if .Line in opts {
|
||||
if Location_File_Opts & opts != nil || .Procedure in opts do fmt.sbprint(buf, ":");
|
||||
fmt.sbprint(buf, location.line);
|
||||
}
|
||||
|
||||
|
||||
+36
-31
@@ -11,30 +11,30 @@ Level :: enum {
|
||||
}
|
||||
|
||||
Option :: enum {
|
||||
Level,
|
||||
Date,
|
||||
Time,
|
||||
Short_File_Path,
|
||||
Long_File_Path,
|
||||
Line,
|
||||
Procedure,
|
||||
Terminal_Color
|
||||
Level,
|
||||
Date,
|
||||
Time,
|
||||
Short_File_Path,
|
||||
Long_File_Path,
|
||||
Line,
|
||||
Procedure,
|
||||
Terminal_Color
|
||||
}
|
||||
|
||||
Options :: bit_set[Option];
|
||||
Full_Timestamp_Opts :: Options{
|
||||
Option.Date,
|
||||
Option.Time
|
||||
.Date,
|
||||
.Time
|
||||
};
|
||||
Location_Header_Opts :: Options{
|
||||
Option.Short_File_Path,
|
||||
Option.Long_File_Path,
|
||||
Option.Line,
|
||||
Option.Procedure,
|
||||
.Short_File_Path,
|
||||
.Long_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
};
|
||||
Location_File_Opts :: Options{
|
||||
Option.Short_File_Path,
|
||||
Option.Long_File_Path
|
||||
.Short_File_Path,
|
||||
.Long_File_Path
|
||||
};
|
||||
|
||||
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
|
||||
@@ -42,30 +42,34 @@ Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Opt
|
||||
Logger :: struct {
|
||||
procedure: Logger_Proc,
|
||||
data: rawptr,
|
||||
options: Options,
|
||||
options: Options,
|
||||
}
|
||||
|
||||
Multi_Logger_Data :: struct {
|
||||
loggers : []Logger,
|
||||
loggers : []Logger,
|
||||
}
|
||||
|
||||
create_multi_logger :: proc(logs: ..Logger) -> Logger {
|
||||
data := new(Multi_Logger_Data);
|
||||
data.loggers = make([]Logger, len(logs));
|
||||
copy(data.loggers, logs);
|
||||
return Logger{multi_logger_proc, data, nil};
|
||||
data := new(Multi_Logger_Data);
|
||||
data.loggers = make([]Logger, len(logs));
|
||||
copy(data.loggers, logs);
|
||||
return Logger{multi_logger_proc, data, nil};
|
||||
}
|
||||
|
||||
destroy_multi_logger ::proc(log : ^Logger) {
|
||||
free(log.data);
|
||||
log^ = nil_logger();
|
||||
destroy_multi_logger :: proc(log : ^Logger) {
|
||||
free(log.data);
|
||||
log^ = nil_logger();
|
||||
}
|
||||
|
||||
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
|
||||
options: Options, location := #caller_location) {
|
||||
data := cast(^Multi_Logger_Data)logger_data;
|
||||
if data.loggers == nil || len(data.loggers) == 0 do return;
|
||||
for log in data.loggers do log.procedure(log.data, level, text, log.options, location);
|
||||
data := cast(^Multi_Logger_Data)logger_data;
|
||||
if data.loggers == nil || len(data.loggers) == 0 {
|
||||
return;
|
||||
}
|
||||
for log in data.loggers {
|
||||
log.procedure(log.data, level, text, log.options, location);
|
||||
}
|
||||
}
|
||||
|
||||
nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
|
||||
@@ -76,6 +80,7 @@ nil_logger :: proc() -> Logger {
|
||||
return Logger{nil_logger_proc, nil, nil};
|
||||
}
|
||||
|
||||
// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
|
||||
debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location);
|
||||
info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location);
|
||||
warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
|
||||
@@ -83,7 +88,7 @@ error :: proc(fmt_str : string, args : ..any, location := #caller_location) do l
|
||||
fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location);
|
||||
|
||||
logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) {
|
||||
logger := context.logger;
|
||||
str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
|
||||
logger.procedure(logger.data, level, str, logger.options, location);
|
||||
logger := context.logger;
|
||||
str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
|
||||
logger.procedure(logger.data, level, str, logger.options, location);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
package linalg
|
||||
|
||||
import "core:math"
|
||||
import "intrinsics"
|
||||
|
||||
// Generic
|
||||
|
||||
dot_vector :: proc(a, b: $T/[$N]$E) -> (c: E) {
|
||||
for i in 0..<N {
|
||||
c += a[i] * b[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
dot_quaternion128 :: proc(a, b: $T/quaternion128) -> (c: f32) {
|
||||
return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
|
||||
}
|
||||
dot_quaternion256 :: proc(a, b: $T/quaternion256) -> (c: f64) {
|
||||
return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
|
||||
}
|
||||
|
||||
dot :: proc{dot_vector, dot_quaternion128, dot_quaternion256};
|
||||
|
||||
cross2 :: proc(a, b: $T/[2]$E) -> E {
|
||||
return a[0]*b[1] - b[0]*a[1];
|
||||
}
|
||||
|
||||
cross3 :: proc(a, b: $T/[3]$E) -> (c: T) {
|
||||
c[0] = +(a[1]*b[2] - b[1]*a[2]);
|
||||
c[1] = -(a[2]*b[3] - b[2]*a[3]);
|
||||
c[2] = +(a[3]*b[1] - b[3]*a[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
cross :: proc{cross2, cross3};
|
||||
|
||||
|
||||
normalize_vector :: proc(v: $T/[$N]$E) -> T {
|
||||
return v / length(v);
|
||||
}
|
||||
normalize_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
|
||||
return q/abs(q);
|
||||
}
|
||||
normalize_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
|
||||
return q/abs(q);
|
||||
}
|
||||
normalize :: proc{normalize_vector, normalize_quaternion128, normalize_quaternion256};
|
||||
|
||||
normalize0_vector :: proc(v: $T/[$N]$E) -> T {
|
||||
m := length(v);
|
||||
return m == 0 ? 0 : v/m;
|
||||
}
|
||||
normalize0_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
|
||||
m := abs(q);
|
||||
return m == 0 ? 0 : q/m;
|
||||
}
|
||||
normalize0_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
|
||||
m := abs(q);
|
||||
return m == 0 ? 0 : q/m;
|
||||
}
|
||||
normalize0 :: proc{normalize0_vector, normalize0_quaternion128, normalize0_quaternion256};
|
||||
|
||||
|
||||
length :: proc(v: $T/[$N]$E) -> E {
|
||||
return math.sqrt(dot(v, v));
|
||||
}
|
||||
|
||||
|
||||
identity :: proc($T: typeid/[$N][N]$E) -> (m: T) {
|
||||
for i in 0..<N do m[i][i] = E(1);
|
||||
return m;
|
||||
}
|
||||
|
||||
transpose :: proc(a: $T/[$N][$M]$E) -> (m: [M][N]E) {
|
||||
for j in 0..<M {
|
||||
for i in 0..<N {
|
||||
m[j][i] = a[i][j];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mul_matrix :: proc(a, b: $M/[$N][N]$E) -> (c: M)
|
||||
where !intrinsics.type_is_array(E),
|
||||
intrinsics.type_is_numeric(E) {
|
||||
for i in 0..<N {
|
||||
for k in 0..<N {
|
||||
for j in 0..<N {
|
||||
c[i][k] += a[i][j] * b[j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mul_matrix_differ :: proc(a: $A/[$I][$J]$E, b: $B/[J][$K]E) -> (c: [I][K]E)
|
||||
where !intrinsics.type_is_array(E),
|
||||
intrinsics.type_is_numeric(E),
|
||||
I != J {
|
||||
for i in 0..<I {
|
||||
for k in 0..<K {
|
||||
for j in 0..<J {
|
||||
c[i][k] += a[i][j] * b[j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mul_matrix_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
|
||||
where !intrinsics.type_is_array(E),
|
||||
intrinsics.type_is_numeric(E) {
|
||||
for i in 0..<I {
|
||||
for j in 0..<J {
|
||||
c[i] += a[i][j] * b[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mul_quaternion128_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
|
||||
Raw_Quaternion :: struct {xyz: [3]f32, r: f32};
|
||||
|
||||
q := transmute(Raw_Quaternion)q;
|
||||
v := transmute([3]f32)v;
|
||||
|
||||
t := cross(2*q.xyz, v);
|
||||
return V(v + q.r*t + cross(q.xyz, t));
|
||||
}
|
||||
|
||||
mul_quaternion256_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
|
||||
Raw_Quaternion :: struct {xyz: [3]f64, r: f64};
|
||||
|
||||
q := transmute(Raw_Quaternion)q;
|
||||
v := transmute([3]f64)v;
|
||||
|
||||
t := cross(2*q.xyz, v);
|
||||
return V(v + q.r*t + cross(q.xyz, t));
|
||||
}
|
||||
mul_quaternion_vector3 :: proc{mul_quaternion128_vector3, mul_quaternion256_vector3};
|
||||
|
||||
mul :: proc{
|
||||
mul_matrix,
|
||||
mul_matrix_differ,
|
||||
mul_matrix_vector,
|
||||
mul_quaternion128_vector3,
|
||||
mul_quaternion256_vector3,
|
||||
};
|
||||
|
||||
|
||||
// Specific
|
||||
|
||||
Float :: f32;
|
||||
|
||||
Vector2 :: distinct [2]Float;
|
||||
Vector3 :: distinct [3]Float;
|
||||
Vector4 :: distinct [4]Float;
|
||||
|
||||
Matrix2x1 :: distinct [2][1]Float;
|
||||
Matrix2x2 :: distinct [2][2]Float;
|
||||
Matrix2x3 :: distinct [2][3]Float;
|
||||
Matrix2x4 :: distinct [2][4]Float;
|
||||
|
||||
Matrix3x1 :: distinct [3][1]Float;
|
||||
Matrix3x2 :: distinct [3][2]Float;
|
||||
Matrix3x3 :: distinct [3][3]Float;
|
||||
Matrix3x4 :: distinct [3][4]Float;
|
||||
|
||||
Matrix4x1 :: distinct [4][1]Float;
|
||||
Matrix4x2 :: distinct [4][2]Float;
|
||||
Matrix4x3 :: distinct [4][3]Float;
|
||||
Matrix4x4 :: distinct [4][4]Float;
|
||||
|
||||
|
||||
Matrix2 :: Matrix2x2;
|
||||
Matrix3 :: Matrix3x3;
|
||||
Matrix4 :: Matrix4x4;
|
||||
|
||||
|
||||
Quaternion :: distinct (size_of(Float) == size_of(f32) ? quaternion128 : quaternion256);
|
||||
|
||||
|
||||
translate_matrix4 :: proc(v: Vector3) -> Matrix4 {
|
||||
m := identity(Matrix4);
|
||||
m[3][0] = v[0];
|
||||
m[3][1] = v[1];
|
||||
m[3][2] = v[2];
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
rotate_matrix4 :: proc(v: Vector3, angle_radians: Float) -> Matrix4 {
|
||||
c := math.cos(angle_radians);
|
||||
s := math.sin(angle_radians);
|
||||
|
||||
a := normalize(v);
|
||||
t := a * (1-c);
|
||||
|
||||
rot := identity(Matrix4);
|
||||
|
||||
rot[0][0] = c + t[0]*a[0];
|
||||
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
|
||||
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
|
||||
rot[0][3] = 0;
|
||||
|
||||
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
|
||||
rot[1][1] = c + t[1]*a[1];
|
||||
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
|
||||
rot[1][3] = 0;
|
||||
|
||||
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
|
||||
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
|
||||
rot[2][2] = c + t[2]*a[2];
|
||||
rot[2][3] = 0;
|
||||
|
||||
return rot;
|
||||
}
|
||||
|
||||
scale_matrix4 :: proc(m: Matrix4, v: Vector3) -> Matrix4 {
|
||||
mm := m;
|
||||
mm[0][0] *= v[0];
|
||||
mm[1][1] *= v[1];
|
||||
mm[2][2] *= v[2];
|
||||
return mm;
|
||||
}
|
||||
|
||||
|
||||
look_at :: proc(eye, centre, up: Vector3) -> Matrix4 {
|
||||
f := normalize(centre - eye);
|
||||
s := normalize(cross(f, up));
|
||||
u := cross(s, f);
|
||||
return Matrix4{
|
||||
{+s.x, +u.x, -f.x, 0},
|
||||
{+s.y, +u.y, -f.y, 0},
|
||||
{+s.z, +u.z, -f.z, 0},
|
||||
{-dot(s, eye), -dot(u, eye), +dot(f, eye), 1},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
perspective :: proc(fovy, aspect, near, far: Float) -> (m: Matrix4) {
|
||||
tan_half_fovy := math.tan(0.5 * fovy);
|
||||
m[0][0] = 1 / (aspect*tan_half_fovy);
|
||||
m[1][1] = 1 / (tan_half_fovy);
|
||||
m[2][2] = -(far + near) / (far - near);
|
||||
m[2][3] = -1;
|
||||
m[3][2] = -2*far*near / (far - near);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ortho3d :: proc(left, right, bottom, top, near, far: Float) -> (m: Matrix4) {
|
||||
m[0][0] = +2 / (right - left);
|
||||
m[1][1] = +2 / (top - bottom);
|
||||
m[2][2] = -2 / (far - near);
|
||||
m[3][0] = -(right + left) / (right - left);
|
||||
m[3][1] = -(top + bottom) / (top - bottom);
|
||||
m[3][2] = -(far + near) / (far- near);
|
||||
m[3][3] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
axis_angle :: proc(axis: Vector3, angle_radians: Float) -> Quaternion {
|
||||
t := angle_radians*0.5;
|
||||
w := math.cos(t);
|
||||
v := normalize(axis) * math.sin(t);
|
||||
return quaternion(w, v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
angle_axis :: proc(angle_radians: Float, axis: Vector3) -> Quaternion {
|
||||
t := angle_radians*0.5;
|
||||
w := math.cos(t);
|
||||
v := normalize(axis) * math.sin(t);
|
||||
return quaternion(w, v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
euler_angles :: proc(pitch, yaw, roll: Float) -> Quaternion {
|
||||
p := axis_angle({1, 0, 0}, pitch);
|
||||
y := axis_angle({0, 1, 0}, yaw);
|
||||
r := axis_angle({0, 0, 1}, roll);
|
||||
return (y * p) * r;
|
||||
}
|
||||
+390
-391
@@ -1,36 +1,41 @@
|
||||
package math
|
||||
|
||||
import "intrinsics"
|
||||
|
||||
Float_Class :: enum {
|
||||
Normal, // an ordinary nonzero floating point value
|
||||
Subnormal, // a subnormal floating point value
|
||||
Zero, // zero
|
||||
Neg_Zero, // the negative zero
|
||||
NaN, // Not-A-Number (NaN)
|
||||
Inf, // positive infinity
|
||||
Neg_Inf // negative infinity
|
||||
};
|
||||
|
||||
TAU :: 6.28318530717958647692528676655900576;
|
||||
PI :: 3.14159265358979323846264338327950288;
|
||||
|
||||
E :: 2.71828182845904523536;
|
||||
|
||||
τ :: TAU;
|
||||
π :: PI;
|
||||
e :: E;
|
||||
|
||||
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
||||
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
||||
|
||||
LOG_TWO :: 0.693147180559945309417232121458176568;
|
||||
LOG_TEN :: 2.30258509299404568401799145468436421;
|
||||
LN2 :: 0.693147180559945309417232121458176568;
|
||||
LN10 :: 2.30258509299404568401799145468436421;
|
||||
|
||||
EPSILON :: 1.19209290e-7;
|
||||
MAX_F64_PRECISION :: 16; // Maximum number of meaningful digits after the decimal point for 'f64'
|
||||
MAX_F32_PRECISION :: 8; // Maximum number of meaningful digits after the decimal point for 'f32'
|
||||
|
||||
τ :: TAU;
|
||||
π :: PI;
|
||||
|
||||
Vec2 :: distinct [2]f32;
|
||||
Vec3 :: distinct [3]f32;
|
||||
Vec4 :: distinct [4]f32;
|
||||
|
||||
// Column major
|
||||
Mat2 :: distinct [2][2]f32;
|
||||
Mat3 :: distinct [3][3]f32;
|
||||
Mat4 :: distinct [4][4]f32;
|
||||
|
||||
Quat :: struct {x, y, z, w: f32};
|
||||
|
||||
QUAT_IDENTITY := Quat{x = 0, y = 0, z = 0, w = 1};
|
||||
RAD_PER_DEG :: TAU/360.0;
|
||||
DEG_PER_RAD :: 360.0/TAU;
|
||||
|
||||
|
||||
@(default_calling_convention="c")
|
||||
@(default_calling_convention="none")
|
||||
foreign _ {
|
||||
@(link_name="llvm.sqrt.f32")
|
||||
sqrt_f32 :: proc(x: f32) -> f32 ---;
|
||||
@@ -58,9 +63,9 @@ foreign _ {
|
||||
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.log.f32")
|
||||
log_f32 :: proc(x: f32) -> f32 ---;
|
||||
ln_f32 :: proc(x: f32) -> f32 ---;
|
||||
@(link_name="llvm.log.f64")
|
||||
log_f64 :: proc(x: f64) -> f64 ---;
|
||||
ln_f64 :: proc(x: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.exp.f32")
|
||||
exp_f32 :: proc(x: f32) -> f32 ---;
|
||||
@@ -68,20 +73,40 @@ foreign _ {
|
||||
exp_f64 :: proc(x: f64) -> f64 ---;
|
||||
}
|
||||
|
||||
log :: proc{log_f32, log_f64};
|
||||
exp :: proc{exp_f32, exp_f64};
|
||||
sqrt :: proc{sqrt_f32, sqrt_f64};
|
||||
sin :: proc{sin_f32, sin_f64};
|
||||
cos :: proc{cos_f32, cos_f64};
|
||||
pow :: proc{pow_f32, pow_f64};
|
||||
fmuladd :: proc{fmuladd_f32, fmuladd_f64};
|
||||
ln :: proc{ln_f32, ln_f64};
|
||||
exp :: proc{exp_f32, exp_f64};
|
||||
|
||||
log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base); }
|
||||
log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base); }
|
||||
log :: proc{log_f32, log_f64};
|
||||
|
||||
log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2; }
|
||||
log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2; }
|
||||
log2 :: proc{log2_f32, log2_f64};
|
||||
|
||||
log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10; }
|
||||
log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10; }
|
||||
log10 :: proc{log10_f32, log10_f64};
|
||||
|
||||
|
||||
tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
|
||||
tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
|
||||
tan :: proc{tan_f32, tan_f64};
|
||||
|
||||
lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
|
||||
|
||||
unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
|
||||
unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
|
||||
unlerp :: proc{unlerp_f32, unlerp_f64};
|
||||
|
||||
|
||||
sign_f32 :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
||||
sign_f64 :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
|
||||
sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)); }
|
||||
sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); }
|
||||
sign :: proc{sign_f32, sign_f64};
|
||||
|
||||
copy_sign_f32 :: proc(x, y: f32) -> f32 {
|
||||
ix := transmute(u32)x;
|
||||
@@ -90,7 +115,6 @@ copy_sign_f32 :: proc(x, y: f32) -> f32 {
|
||||
ix |= iy & 0x8000_0000;
|
||||
return transmute(f32)ix;
|
||||
}
|
||||
|
||||
copy_sign_f64 :: proc(x, y: f64) -> f64 {
|
||||
ix := transmute(u64)x;
|
||||
iy := transmute(u64)y;
|
||||
@@ -98,22 +122,89 @@ copy_sign_f64 :: proc(x, y: f64) -> f64 {
|
||||
ix |= iy & 0x8000_0000_0000_0000;
|
||||
return transmute(f64)ix;
|
||||
}
|
||||
|
||||
|
||||
sqrt :: proc{sqrt_f32, sqrt_f64};
|
||||
sin :: proc{sin_f32, sin_f64};
|
||||
cos :: proc{cos_f32, cos_f64};
|
||||
tan :: proc{tan_f32, tan_f64};
|
||||
pow :: proc{pow_f32, pow_f64};
|
||||
fmuladd :: proc{fmuladd_f32, fmuladd_f64};
|
||||
sign :: proc{sign_f32, sign_f64};
|
||||
copy_sign :: proc{copy_sign_f32, copy_sign_f64};
|
||||
|
||||
|
||||
round_f32 :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
round_f64 :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; }
|
||||
to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG; }
|
||||
to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD; }
|
||||
to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD; }
|
||||
to_radians :: proc{to_radians_f32, to_radians_f64};
|
||||
to_degrees :: proc{to_degrees_f32, to_degrees_f64};
|
||||
|
||||
trunc_f32 :: proc(x: f32) -> f32 {
|
||||
trunc_internal :: proc(f: f32) -> f32 {
|
||||
mask :: 0xff;
|
||||
shift :: 32 - 9;
|
||||
bias :: 0x7f;
|
||||
|
||||
if f < 1 {
|
||||
switch {
|
||||
case f < 0: return -trunc_internal(-f);
|
||||
case f == 0: return f;
|
||||
case: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
x := transmute(u32)f;
|
||||
e := (x >> shift) & mask - bias;
|
||||
|
||||
if e < shift {
|
||||
x &= ~(1 << (shift-e)) - 1;
|
||||
}
|
||||
return transmute(f32)x;
|
||||
}
|
||||
switch classify(x) {
|
||||
case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
|
||||
return x;
|
||||
}
|
||||
return trunc_internal(x);
|
||||
}
|
||||
|
||||
trunc_f64 :: proc(x: f64) -> f64 {
|
||||
trunc_internal :: proc(f: f64) -> f64 {
|
||||
mask :: 0x7ff;
|
||||
shift :: 64 - 12;
|
||||
bias :: 0x3ff;
|
||||
|
||||
if f < 1 {
|
||||
switch {
|
||||
case f < 0: return -trunc_internal(-f);
|
||||
case f == 0: return f;
|
||||
case: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
x := transmute(u64)f;
|
||||
e := (x >> shift) & mask - bias;
|
||||
|
||||
if e < shift {
|
||||
x &= ~(1 << (shift-e)) - 1;
|
||||
}
|
||||
return transmute(f64)x;
|
||||
}
|
||||
switch classify(x) {
|
||||
case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
|
||||
return x;
|
||||
}
|
||||
return trunc_internal(x);
|
||||
}
|
||||
|
||||
trunc :: proc{trunc_f32, trunc_f64};
|
||||
|
||||
round_f32 :: proc(x: f32) -> f32 {
|
||||
return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
|
||||
}
|
||||
round_f64 :: proc(x: f64) -> f64 {
|
||||
return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
|
||||
}
|
||||
round :: proc{round_f32, round_f64};
|
||||
|
||||
|
||||
ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); }
|
||||
ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); }
|
||||
ceil :: proc{ceil_f32, ceil_f64};
|
||||
|
||||
floor_f32 :: proc(x: f32) -> f32 {
|
||||
if x == 0 || is_nan(x) || is_inf(x) {
|
||||
return x;
|
||||
@@ -144,33 +235,27 @@ floor_f64 :: proc(x: f64) -> f64 {
|
||||
}
|
||||
floor :: proc{floor_f32, floor_f64};
|
||||
|
||||
ceil_f32 :: proc(x: f32) -> f32 { return -floor_f32(-x); }
|
||||
ceil_f64 :: proc(x: f64) -> f64 { return -floor_f64(-x); }
|
||||
ceil :: proc{ceil_f32, ceil_f64};
|
||||
|
||||
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
|
||||
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
|
||||
remainder :: proc{remainder_f32, remainder_f64};
|
||||
|
||||
mod_f32 :: proc(x, y: f32) -> (n: f32) {
|
||||
z := abs(y);
|
||||
n = remainder(abs(x), z);
|
||||
if sign(n) < 0 {
|
||||
n += z;
|
||||
floor_div :: proc(x, y: $T) -> T
|
||||
where intrinsics.type_is_integer(T) {
|
||||
a := x / y;
|
||||
r := x % y;
|
||||
if (r > 0 && y < 0) || (r < 0 && y > 0) {
|
||||
a -= 1;
|
||||
}
|
||||
return copy_sign(n, x);
|
||||
return a;
|
||||
}
|
||||
mod_f64 :: proc(x, y: f64) -> (n: f64) {
|
||||
z := abs(y);
|
||||
n = remainder(abs(x), z);
|
||||
if sign(n) < 0 {
|
||||
n += z;
|
||||
}
|
||||
return copy_sign(n, x);
|
||||
}
|
||||
mod :: proc{mod_f32, mod_f64};
|
||||
|
||||
// TODO(bill): These need to implemented with the actual instructions
|
||||
floor_mod :: proc(x, y: $T) -> T
|
||||
where intrinsics.type_is_integer(T) {
|
||||
r := x % y;
|
||||
if (r > 0 && y < 0) || (r < 0 && y > 0) {
|
||||
r += y;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
|
||||
shift :: 32 - 8 - 1;
|
||||
mask :: 0xff;
|
||||
@@ -190,8 +275,8 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
|
||||
i := transmute(u32)x;
|
||||
e := uint(i>>shift)&mask - bias;
|
||||
|
||||
if e < 32-9 {
|
||||
i &~= 1<<(32-9-e) - 1;
|
||||
if e < shift {
|
||||
i &~= 1<<(shift-e) - 1;
|
||||
}
|
||||
int = transmute(f32)i;
|
||||
frac = x - int;
|
||||
@@ -216,360 +301,274 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
|
||||
i := transmute(u64)x;
|
||||
e := uint(i>>shift)&mask - bias;
|
||||
|
||||
if e < 64-12 {
|
||||
i &~= 1<<(64-12-e) - 1;
|
||||
if e < shift {
|
||||
i &~= 1<<(shift-e) - 1;
|
||||
}
|
||||
int = transmute(f64)i;
|
||||
frac = x - int;
|
||||
return;
|
||||
}
|
||||
modf :: proc{modf_f32, modf_f64};
|
||||
split_decimal :: modf;
|
||||
|
||||
is_nan_f32 :: inline proc(x: f32) -> bool { return x != x; }
|
||||
is_nan_f64 :: inline proc(x: f64) -> bool { return x != x; }
|
||||
mod_f32 :: proc(x, y: f32) -> (n: f32) {
|
||||
z := abs(y);
|
||||
n = remainder(abs(x), z);
|
||||
if sign(n) < 0 {
|
||||
n += z;
|
||||
}
|
||||
return copy_sign(n, x);
|
||||
}
|
||||
mod_f64 :: proc(x, y: f64) -> (n: f64) {
|
||||
z := abs(y);
|
||||
n = remainder(abs(x), z);
|
||||
if sign(n) < 0 {
|
||||
n += z;
|
||||
}
|
||||
return copy_sign(n, x);
|
||||
}
|
||||
mod :: proc{mod_f32, mod_f64};
|
||||
|
||||
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
|
||||
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
|
||||
remainder :: proc{remainder_f32, remainder_f64};
|
||||
|
||||
|
||||
|
||||
gcd :: proc(x, y: $T) -> T
|
||||
where intrinsics.type_is_ordered_numeric(T) {
|
||||
x, y := x, y;
|
||||
for y != 0 {
|
||||
x %= y;
|
||||
x, y = y, x;
|
||||
}
|
||||
return abs(x);
|
||||
}
|
||||
|
||||
lcm :: proc(x, y: $T) -> T
|
||||
where intrinsics.type_is_ordered_numeric(T) {
|
||||
return x / gcd(x, y) * y;
|
||||
}
|
||||
|
||||
frexp_f32 :: proc(x: f32) -> (significand: f32, exponent: int) {
|
||||
switch {
|
||||
case x == 0:
|
||||
return 0, 0;
|
||||
case x < 0:
|
||||
significand, exponent = frexp(-x);
|
||||
return -significand, exponent;
|
||||
}
|
||||
ex := trunc(log2(x));
|
||||
exponent = int(ex);
|
||||
significand = x / pow(2.0, ex);
|
||||
if abs(significand) >= 1 {
|
||||
exponent += 1;
|
||||
significand /= 2;
|
||||
}
|
||||
if exponent == 1024 && significand == 0 {
|
||||
significand = 0.99999999999999988898;
|
||||
}
|
||||
return;
|
||||
}
|
||||
frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) {
|
||||
switch {
|
||||
case x == 0:
|
||||
return 0, 0;
|
||||
case x < 0:
|
||||
significand, exponent = frexp(-x);
|
||||
return -significand, exponent;
|
||||
}
|
||||
ex := trunc(log2(x));
|
||||
exponent = int(ex);
|
||||
significand = x / pow(2.0, ex);
|
||||
if abs(significand) >= 1 {
|
||||
exponent += 1;
|
||||
significand /= 2;
|
||||
}
|
||||
if exponent == 1024 && significand == 0 {
|
||||
significand = 0.99999999999999988898;
|
||||
}
|
||||
return;
|
||||
}
|
||||
frexp :: proc{frexp_f32, frexp_f64};
|
||||
|
||||
|
||||
|
||||
|
||||
binomial :: proc(n, k: int) -> int {
|
||||
switch {
|
||||
case k <= 0: return 1;
|
||||
case 2*k > n: return binomial(n, n-k);
|
||||
}
|
||||
|
||||
b := n;
|
||||
for i in 2..<k {
|
||||
b = (b * (n+1-i))/i;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
factorial :: proc(n: int) -> int {
|
||||
when size_of(int) == size_of(i64) {
|
||||
@static table := [21]int{
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
6,
|
||||
24,
|
||||
120,
|
||||
720,
|
||||
5_040,
|
||||
40_320,
|
||||
362_880,
|
||||
3_628_800,
|
||||
39_916_800,
|
||||
479_001_600,
|
||||
6_227_020_800,
|
||||
87_178_291_200,
|
||||
1_307_674_368_000,
|
||||
20_922_789_888_000,
|
||||
355_687_428_096_000,
|
||||
6_402_373_705_728_000,
|
||||
121_645_100_408_832_000,
|
||||
2_432_902_008_176_640_000,
|
||||
};
|
||||
} else {
|
||||
@static table := [13]int{
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
6,
|
||||
24,
|
||||
120,
|
||||
720,
|
||||
5_040,
|
||||
40_320,
|
||||
362_880,
|
||||
3_628_800,
|
||||
39_916_800,
|
||||
479_001_600,
|
||||
};
|
||||
}
|
||||
|
||||
assert(n >= 0, "parameter must not be negative");
|
||||
assert(n < len(table), "parameter is too large to lookup in the table");
|
||||
return 0;
|
||||
}
|
||||
|
||||
classify_f32 :: proc(x: f32) -> Float_Class {
|
||||
switch {
|
||||
case x == 0:
|
||||
i := transmute(i32)x;
|
||||
if i < 0 {
|
||||
return .Neg_Zero;
|
||||
}
|
||||
return .Zero;
|
||||
case x*0.5 == x:
|
||||
if x < 0 {
|
||||
return .Neg_Inf;
|
||||
}
|
||||
return .Inf;
|
||||
case x != x:
|
||||
return .NaN;
|
||||
}
|
||||
|
||||
u := transmute(u32)x;
|
||||
exp := int(u>>23) & (1<<8 - 1);
|
||||
if exp == 0 {
|
||||
return .Subnormal;
|
||||
}
|
||||
return .Normal;
|
||||
}
|
||||
classify_f64 :: proc(x: f64) -> Float_Class {
|
||||
switch {
|
||||
case x == 0:
|
||||
i := transmute(i64)x;
|
||||
if i < 0 {
|
||||
return .Neg_Zero;
|
||||
}
|
||||
return .Zero;
|
||||
case x*0.5 == x:
|
||||
if x < 0 {
|
||||
return .Neg_Inf;
|
||||
}
|
||||
return .Inf;
|
||||
case x != x:
|
||||
return .NaN;
|
||||
}
|
||||
u := transmute(u64)x;
|
||||
exp := int(u>>52) & (1<<11 - 1);
|
||||
if exp == 0 {
|
||||
return .Subnormal;
|
||||
}
|
||||
return .Normal;
|
||||
}
|
||||
classify :: proc{classify_f32, classify_f64};
|
||||
|
||||
is_nan_f32 :: proc(x: f32) -> bool { return classify(x) == .NaN; }
|
||||
is_nan_f64 :: proc(x: f64) -> bool { return classify(x) == .NaN; }
|
||||
is_nan :: proc{is_nan_f32, is_nan_f64};
|
||||
|
||||
is_finite_f32 :: inline proc(x: f32) -> bool { return !is_nan(x-x); }
|
||||
is_finite_f64 :: inline proc(x: f64) -> bool { return !is_nan(x-x); }
|
||||
is_finite :: proc{is_finite_f32, is_finite_f64};
|
||||
|
||||
is_inf_f32 :: proc(x: f32, sign := 0) -> bool {
|
||||
return sign >= 0 && x > F32_MAX || sign <= 0 && x < -F32_MAX;
|
||||
}
|
||||
is_inf_f64 :: proc(x: f64, sign := 0) -> bool {
|
||||
return sign >= 0 && x > F64_MAX || sign <= 0 && x < -F64_MAX;
|
||||
}
|
||||
// If sign > 0, is_inf reports whether f is positive infinity
|
||||
// If sign < 0, is_inf reports whether f is negative infinity
|
||||
// If sign == 0, is_inf reports whether f is either infinity
|
||||
is_inf_f32 :: proc(x: f32) -> bool { return classify(abs(x)) == .Inf; }
|
||||
is_inf_f64 :: proc(x: f64) -> bool { return classify(abs(x)) == .Inf; }
|
||||
is_inf :: proc{is_inf_f32, is_inf_f64};
|
||||
|
||||
|
||||
|
||||
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
|
||||
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
||||
is_power_of_two :: proc(x: int) -> bool {
|
||||
return x > 0 && (x & (x-1)) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
mul :: proc{
|
||||
mat3_mul,
|
||||
mat4_mul, mat4_mul_vec4,
|
||||
quat_mul, quat_mulf,
|
||||
};
|
||||
|
||||
div :: proc{quat_div, quat_divf};
|
||||
|
||||
inverse :: proc{mat4_inverse, quat_inverse};
|
||||
dot :: proc{vec_dot, quat_dot};
|
||||
cross :: proc{cross2, cross3};
|
||||
|
||||
vec_dot :: proc(a, b: $T/[$N]$E) -> E {
|
||||
res: E;
|
||||
for i in 0..<N {
|
||||
res += a[i] * b[i];
|
||||
next_power_of_two :: proc(x: int) -> int {
|
||||
k := x -1;
|
||||
when size_of(int) == 8 {
|
||||
k = k | (k >> 32);
|
||||
}
|
||||
return res;
|
||||
k = k | (k >> 16);
|
||||
k = k | (k >> 8);
|
||||
k = k | (k >> 4);
|
||||
k = k | (k >> 2);
|
||||
k = k | (k >> 1);
|
||||
k += 1 + int(x <= 0);
|
||||
return k;
|
||||
}
|
||||
|
||||
cross2 :: proc(a, b: $T/[2]$E) -> E {
|
||||
return a[0]*b[1] - a[1]*b[0];
|
||||
sum :: proc(x: $T/[]$E) -> (res: E)
|
||||
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||
for i in x {
|
||||
res += i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cross3 :: proc(a, b: $T/[3]$E) -> T {
|
||||
i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
|
||||
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
|
||||
return T(i - j);
|
||||
prod :: proc(x: $T/[]$E) -> (res: E)
|
||||
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||
for i in x {
|
||||
res *= i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cumsum_inplace :: proc(x: $T/[]$E) -> T
|
||||
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||
for i in 1..<len(x) {
|
||||
x[i] = x[i-1] + x[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
length :: proc(v: $T/[$N]$E) -> E { return sqrt(dot(v, v)); }
|
||||
|
||||
norm :: proc(v: $T/[$N]$E) -> T { return v / length(v); }
|
||||
|
||||
norm0 :: proc(v: $T/[$N]$E) -> T {
|
||||
m := length(v);
|
||||
return m == 0 ? 0 : v/m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
identity :: proc($T: typeid/[$N][N]$E) -> T {
|
||||
m: T;
|
||||
for i in 0..<N do m[i][i] = E(1);
|
||||
return m;
|
||||
}
|
||||
|
||||
transpose :: proc(m: $M/[$N][N]f32) -> M {
|
||||
for j in 0..<N {
|
||||
for i in 0..<N {
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||
cumsum :: proc(dst, src: $T/[]$E) -> T
|
||||
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||
N := min(len(dst), len(src));
|
||||
if N > 0 {
|
||||
dst[0] = src[0];
|
||||
for i in 1..<N {
|
||||
dst[i] = dst[i-1] + src[i];
|
||||
}
|
||||
}
|
||||
return m;
|
||||
return dst[:N];
|
||||
}
|
||||
|
||||
mat3_mul :: proc(a, b: Mat3) -> Mat3 {
|
||||
c: Mat3;
|
||||
for j in 0..<3 {
|
||||
for i in 0..<3 {
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
c: Mat4;
|
||||
for j in 0..<4 {
|
||||
for i in 0..<4 {
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2] +
|
||||
a[3][i]*b[j][3];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
return Vec4{
|
||||
m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3],
|
||||
m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3],
|
||||
m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3],
|
||||
m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3],
|
||||
};
|
||||
}
|
||||
|
||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
||||
o: Mat4;
|
||||
|
||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
|
||||
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
|
||||
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
|
||||
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
|
||||
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
|
||||
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
|
||||
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
|
||||
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
|
||||
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
|
||||
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
|
||||
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
|
||||
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
|
||||
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
|
||||
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
|
||||
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
|
||||
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
|
||||
|
||||
|
||||
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
|
||||
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
|
||||
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05);
|
||||
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05);
|
||||
|
||||
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02);
|
||||
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04);
|
||||
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05);
|
||||
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05);
|
||||
|
||||
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08);
|
||||
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10);
|
||||
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12);
|
||||
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12);
|
||||
|
||||
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15);
|
||||
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17);
|
||||
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
|
||||
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
|
||||
|
||||
ood := 1.0 / (m[0][0] * o[0][0] +
|
||||
m[0][1] * o[0][1] +
|
||||
m[0][2] * o[0][2] +
|
||||
m[0][3] * o[0][3]);
|
||||
|
||||
o[0][0] *= ood;
|
||||
o[0][1] *= ood;
|
||||
o[0][2] *= ood;
|
||||
o[0][3] *= ood;
|
||||
o[1][0] *= ood;
|
||||
o[1][1] *= ood;
|
||||
o[1][2] *= ood;
|
||||
o[1][3] *= ood;
|
||||
o[2][0] *= ood;
|
||||
o[2][1] *= ood;
|
||||
o[2][2] *= ood;
|
||||
o[2][3] *= ood;
|
||||
o[3][0] *= ood;
|
||||
o[3][1] *= ood;
|
||||
o[3][2] *= ood;
|
||||
o[3][3] *= ood;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
||||
m := identity(Mat4);
|
||||
m[3][0] = v[0];
|
||||
m[3][1] = v[1];
|
||||
m[3][2] = v[2];
|
||||
m[3][3] = 1;
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
c := cos(angle_radians);
|
||||
s := sin(angle_radians);
|
||||
|
||||
a := norm(v);
|
||||
t := a * (1-c);
|
||||
|
||||
rot := identity(Mat4);
|
||||
|
||||
rot[0][0] = c + t[0]*a[0];
|
||||
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
|
||||
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
|
||||
rot[0][3] = 0;
|
||||
|
||||
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
|
||||
rot[1][1] = c + t[1]*a[1];
|
||||
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
|
||||
rot[1][3] = 0;
|
||||
|
||||
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
|
||||
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
|
||||
rot[2][2] = c + t[2]*a[2];
|
||||
rot[2][3] = 0;
|
||||
|
||||
return rot;
|
||||
}
|
||||
|
||||
scale_vec3 :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||
mm := m;
|
||||
mm[0][0] *= v[0];
|
||||
mm[1][1] *= v[1];
|
||||
mm[2][2] *= v[2];
|
||||
return m;
|
||||
}
|
||||
|
||||
scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
mm := m;
|
||||
mm[0][0] *= s;
|
||||
mm[1][1] *= s;
|
||||
mm[2][2] *= s;
|
||||
return m;
|
||||
}
|
||||
|
||||
scale :: proc{scale_vec3, scale_f32};
|
||||
|
||||
|
||||
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||
f := norm(centre - eye);
|
||||
s := norm(cross(f, up));
|
||||
u := cross(s, f);
|
||||
|
||||
return Mat4{
|
||||
{+s.x, +u.x, -f.x, 0},
|
||||
{+s.y, +u.y, -f.y, 0},
|
||||
{+s.z, +u.z, -f.z, 0},
|
||||
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
|
||||
};
|
||||
}
|
||||
|
||||
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
m: Mat4;
|
||||
tan_half_fovy := tan(0.5 * fovy);
|
||||
|
||||
m[0][0] = 1.0 / (aspect*tan_half_fovy);
|
||||
m[1][1] = 1.0 / (tan_half_fovy);
|
||||
m[2][2] = -(far + near) / (far - near);
|
||||
m[2][3] = -1.0;
|
||||
m[3][2] = -2.0*far*near / (far - near);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||
m := identity(Mat4);
|
||||
m[0][0] = +2.0 / (right - left);
|
||||
m[1][1] = +2.0 / (top - bottom);
|
||||
m[2][2] = -2.0 / (far - near);
|
||||
m[3][0] = -(right + left) / (right - left);
|
||||
m[3][1] = -(top + bottom) / (top - bottom);
|
||||
m[3][2] = -(far + near) / (far - near);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
// Quaternion operations
|
||||
|
||||
conj :: proc(q: Quat) -> Quat {
|
||||
return Quat{-q.x, -q.y, -q.z, q.w};
|
||||
}
|
||||
|
||||
quat_mul :: proc(q0, q1: Quat) -> Quat {
|
||||
d: Quat;
|
||||
d.x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y;
|
||||
d.y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x;
|
||||
d.z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w;
|
||||
d.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
|
||||
return d;
|
||||
}
|
||||
|
||||
quat_mulf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x*f, q.y*f, q.z*f, q.w*f}; }
|
||||
quat_divf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x/f, q.y/f, q.z/f, q.w/f}; }
|
||||
|
||||
quat_div :: proc(q0, q1: Quat) -> Quat { return mul(q0, quat_inverse(q1)); }
|
||||
quat_inverse :: proc(q: Quat) -> Quat { return div(conj(q), dot(q, q)); }
|
||||
quat_dot :: proc(q0, q1: Quat) -> f32 { return q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w; }
|
||||
|
||||
quat_norm :: proc(q: Quat) -> Quat {
|
||||
m := sqrt(dot(q, q));
|
||||
return div(q, m);
|
||||
}
|
||||
|
||||
axis_angle :: proc(axis: Vec3, angle_radians: f32) -> Quat {
|
||||
v := norm(axis) * sin(0.5*angle_radians);
|
||||
w := cos(0.5*angle_radians);
|
||||
return Quat{v.x, v.y, v.z, w};
|
||||
}
|
||||
|
||||
euler_angles :: proc(pitch, yaw, roll: f32) -> Quat {
|
||||
p := axis_angle(Vec3{1, 0, 0}, pitch);
|
||||
y := axis_angle(Vec3{0, 1, 0}, yaw);
|
||||
r := axis_angle(Vec3{0, 0, 1}, roll);
|
||||
return mul(mul(y, p), r);
|
||||
}
|
||||
|
||||
quat_to_mat4 :: proc(q: Quat) -> Mat4 {
|
||||
a := quat_norm(q);
|
||||
xx := a.x*a.x; yy := a.y*a.y; zz := a.z*a.z;
|
||||
xy := a.x*a.y; xz := a.x*a.z; yz := a.y*a.z;
|
||||
wx := a.w*a.x; wy := a.w*a.y; wz := a.w*a.z;
|
||||
|
||||
m := identity(Mat4);
|
||||
|
||||
m[0][0] = 1 - 2*(yy + zz);
|
||||
m[0][1] = 2*(xy + wz);
|
||||
m[0][2] = 2*(xz - wy);
|
||||
|
||||
m[1][0] = 2*(xy - wz);
|
||||
m[1][1] = 1 - 2*(xx + zz);
|
||||
m[1][2] = 2*(yz + wx);
|
||||
|
||||
m[2][0] = 2*(xz + wy);
|
||||
m[2][1] = 2*(yz - wx);
|
||||
m[2][2] = 1 - 2*(xx + yy);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
F32_DIG :: 6;
|
||||
F32_EPSILON :: 1.192092896e-07;
|
||||
|
||||
@@ -128,8 +128,8 @@ norm_float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 {
|
||||
|
||||
if i == 0 {
|
||||
for {
|
||||
x = -math.log(float64(r)) * (1.0/ rn);
|
||||
y := -math.log(float64(r));
|
||||
x = -math.ln(float64(r)) * (1.0/ rn);
|
||||
y := -math.ln(float64(r));
|
||||
if y+y >= x*x {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package mem
|
||||
|
||||
|
||||
|
||||
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
||||
|
||||
@@ -31,6 +31,12 @@ Raw_Map :: struct {
|
||||
entries: Raw_Dynamic_Array,
|
||||
}
|
||||
|
||||
Raw_Complex64 :: struct {real, imag: f32};
|
||||
Raw_Complex128 :: struct {real, imag: f64};
|
||||
Raw_Quaternion128 :: struct {imag, jmag, kmag: f32, real: f32};
|
||||
Raw_Quaternion256 :: struct {imag, jmag, kmag: f64, real: f64};
|
||||
Raw_Quaternion128_Vector_Scalar :: struct {vector: [3]f32, scalar: f32};
|
||||
Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64};
|
||||
|
||||
make_any :: inline proc(data: rawptr, id: typeid) -> any {
|
||||
return transmute(any)Raw_Any{data, id};
|
||||
|
||||
+114
-105
@@ -1,11 +1,10 @@
|
||||
package odin_ast
|
||||
|
||||
import "core:odin/token"
|
||||
import "core:odin/tokenizer"
|
||||
|
||||
Proc_Tag :: enum {
|
||||
Bounds_Check,
|
||||
No_Bounds_Check,
|
||||
Require_Results,
|
||||
}
|
||||
Proc_Tags :: distinct bit_set[Proc_Tag; u32];
|
||||
|
||||
@@ -34,12 +33,12 @@ Node_State_Flags :: distinct bit_set[Node_State_Flag];
|
||||
|
||||
|
||||
Comment_Group :: struct {
|
||||
list: []token.Token,
|
||||
list: []tokenizer.Token,
|
||||
}
|
||||
|
||||
Node :: struct {
|
||||
pos: token.Pos,
|
||||
end: token.Pos,
|
||||
pos: tokenizer.Pos,
|
||||
end: tokenizer.Pos,
|
||||
derived: any,
|
||||
state_flags: Node_State_Flags,
|
||||
}
|
||||
@@ -68,29 +67,29 @@ Ident :: struct {
|
||||
|
||||
Implicit :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
}
|
||||
|
||||
|
||||
Undef :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
}
|
||||
|
||||
Basic_Lit :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
}
|
||||
|
||||
Basic_Directive :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
name: string,
|
||||
}
|
||||
|
||||
Ellipsis :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
@@ -100,42 +99,44 @@ Proc_Lit :: struct {
|
||||
body: ^Stmt,
|
||||
tags: Proc_Tags,
|
||||
inlining: Proc_Inlining,
|
||||
where_token: tokenizer.Token,
|
||||
where_clauses: []^Expr,
|
||||
}
|
||||
|
||||
Comp_Lit :: struct {
|
||||
using node: Expr,
|
||||
type: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
elems: []^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
|
||||
Tag_Expr :: struct {
|
||||
using node: Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
name: string,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
Unary_Expr :: struct {
|
||||
using node: Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
Binary_Expr :: struct {
|
||||
using node: Expr,
|
||||
left: ^Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
right: ^Expr,
|
||||
}
|
||||
|
||||
Paren_Expr :: struct {
|
||||
using node: Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
expr: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Selector_Expr :: struct {
|
||||
@@ -152,74 +153,74 @@ Implicit_Selector_Expr :: struct {
|
||||
Index_Expr :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
index: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Deref_Expr :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
}
|
||||
|
||||
Slice_Expr :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
low: ^Expr,
|
||||
interval: token.Token,
|
||||
interval: tokenizer.Token,
|
||||
high: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Call_Expr :: struct {
|
||||
using node: Expr,
|
||||
inlining: Proc_Inlining,
|
||||
expr: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
args: []^Expr,
|
||||
ellipsis: token.Token,
|
||||
close: token.Pos,
|
||||
ellipsis: tokenizer.Token,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Field_Value :: struct {
|
||||
using node: Expr,
|
||||
field: ^Expr,
|
||||
sep: token.Pos,
|
||||
sep: tokenizer.Pos,
|
||||
value: ^Expr,
|
||||
}
|
||||
|
||||
Ternary_Expr :: struct {
|
||||
using node: Expr,
|
||||
cond: ^Expr,
|
||||
op1: token.Token,
|
||||
op1: tokenizer.Token,
|
||||
x: ^Expr,
|
||||
op2: token.Token,
|
||||
op2: tokenizer.Token,
|
||||
y: ^Expr,
|
||||
}
|
||||
|
||||
Type_Assertion :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
dot: token.Pos,
|
||||
open: token.Pos,
|
||||
dot: tokenizer.Pos,
|
||||
open: tokenizer.Pos,
|
||||
type: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Type_Cast :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
open: token.Pos,
|
||||
tok: tokenizer.Token,
|
||||
open: tokenizer.Pos,
|
||||
type: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
Auto_Cast :: struct {
|
||||
using node: Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
@@ -234,7 +235,7 @@ Bad_Stmt :: struct {
|
||||
|
||||
Empty_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
semicolon: token.Pos, // Position of the following ';'
|
||||
semicolon: tokenizer.Pos, // Position of the following ';'
|
||||
}
|
||||
|
||||
Expr_Stmt :: struct {
|
||||
@@ -244,7 +245,7 @@ Expr_Stmt :: struct {
|
||||
|
||||
Tag_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
name: string,
|
||||
stmt: ^Stmt,
|
||||
}
|
||||
@@ -252,7 +253,7 @@ Tag_Stmt :: struct {
|
||||
Assign_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
lhs: []^Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
rhs: []^Expr,
|
||||
}
|
||||
|
||||
@@ -260,15 +261,15 @@ Assign_Stmt :: struct {
|
||||
Block_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
stmts: []^Stmt,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
If_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
if_pos: token.Pos,
|
||||
if_pos: tokenizer.Pos,
|
||||
init: ^Stmt,
|
||||
cond: ^Expr,
|
||||
body: ^Stmt,
|
||||
@@ -277,7 +278,7 @@ If_Stmt :: struct {
|
||||
|
||||
When_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
when_pos: token.Pos,
|
||||
when_pos: tokenizer.Pos,
|
||||
cond: ^Expr,
|
||||
body: ^Stmt,
|
||||
else_stmt: ^Stmt,
|
||||
@@ -296,7 +297,7 @@ Defer_Stmt :: struct {
|
||||
For_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
for_pos: token.Pos,
|
||||
for_pos: tokenizer.Pos,
|
||||
init: ^Stmt,
|
||||
cond: ^Expr,
|
||||
post: ^Stmt,
|
||||
@@ -306,10 +307,10 @@ For_Stmt :: struct {
|
||||
Range_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
for_pos: token.Pos,
|
||||
for_pos: tokenizer.Pos,
|
||||
val0: ^Expr,
|
||||
val1: ^Expr,
|
||||
in_pos: token.Pos,
|
||||
in_pos: tokenizer.Pos,
|
||||
expr: ^Expr,
|
||||
body: ^Stmt,
|
||||
}
|
||||
@@ -317,16 +318,16 @@ Range_Stmt :: struct {
|
||||
|
||||
Case_Clause :: struct {
|
||||
using node: Stmt,
|
||||
case_pos: token.Pos,
|
||||
case_pos: tokenizer.Pos,
|
||||
list: []^Expr,
|
||||
terminator: token.Token,
|
||||
terminator: tokenizer.Token,
|
||||
body: []^Stmt,
|
||||
}
|
||||
|
||||
Switch_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
switch_pos: token.Pos,
|
||||
switch_pos: tokenizer.Pos,
|
||||
init: ^Stmt,
|
||||
cond: ^Expr,
|
||||
body: ^Stmt,
|
||||
@@ -336,7 +337,7 @@ Switch_Stmt :: struct {
|
||||
Type_Switch_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
switch_pos: token.Pos,
|
||||
switch_pos: tokenizer.Pos,
|
||||
tag: ^Stmt,
|
||||
expr: ^Expr,
|
||||
body: ^Stmt,
|
||||
@@ -345,7 +346,7 @@ Type_Switch_Stmt :: struct {
|
||||
|
||||
Branch_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
label: ^Ident,
|
||||
}
|
||||
|
||||
@@ -376,7 +377,7 @@ Value_Decl :: struct {
|
||||
Package_Decl :: struct {
|
||||
using node: Decl,
|
||||
docs: ^Comment_Group,
|
||||
token: token.Token,
|
||||
token: tokenizer.Token,
|
||||
name: string,
|
||||
comment: ^Comment_Group,
|
||||
}
|
||||
@@ -385,9 +386,9 @@ Import_Decl :: struct {
|
||||
using node: Decl,
|
||||
docs: ^Comment_Group,
|
||||
is_using: bool,
|
||||
import_tok: token.Token,
|
||||
name: token.Token,
|
||||
relpath: token.Token,
|
||||
import_tok: tokenizer.Token,
|
||||
name: tokenizer.Token,
|
||||
relpath: tokenizer.Token,
|
||||
fullpath: string,
|
||||
comment: ^Comment_Group,
|
||||
}
|
||||
@@ -396,7 +397,7 @@ Foreign_Block_Decl :: struct {
|
||||
using node: Decl,
|
||||
docs: ^Comment_Group,
|
||||
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
foreign_library: ^Expr,
|
||||
body: ^Stmt,
|
||||
}
|
||||
@@ -404,8 +405,8 @@ Foreign_Block_Decl :: struct {
|
||||
Foreign_Import_Decl :: struct {
|
||||
using node: Decl,
|
||||
docs: ^Comment_Group,
|
||||
foreign_tok: token.Token,
|
||||
import_tok: token.Token,
|
||||
foreign_tok: tokenizer.Token,
|
||||
import_tok: tokenizer.Token,
|
||||
name: ^Ident,
|
||||
collection_name: string,
|
||||
fullpaths: []string,
|
||||
@@ -435,7 +436,9 @@ Field_Flag :: enum {
|
||||
C_Vararg,
|
||||
Auto_Cast,
|
||||
In,
|
||||
|
||||
Results,
|
||||
Tags,
|
||||
Default_Parameters,
|
||||
Typeid_Token,
|
||||
}
|
||||
@@ -443,18 +446,19 @@ Field_Flag :: enum {
|
||||
Field_Flags :: distinct bit_set[Field_Flag];
|
||||
|
||||
Field_Flags_Struct :: Field_Flags{
|
||||
Field_Flag.Using,
|
||||
.Using,
|
||||
.Tags,
|
||||
};
|
||||
Field_Flags_Record_Poly_Params :: Field_Flags{
|
||||
Field_Flag.Typeid_Token,
|
||||
.Typeid_Token,
|
||||
};
|
||||
Field_Flags_Signature :: Field_Flags{
|
||||
Field_Flag.Ellipsis,
|
||||
Field_Flag.Using,
|
||||
Field_Flag.No_Alias,
|
||||
Field_Flag.C_Vararg,
|
||||
Field_Flag.Auto_Cast,
|
||||
Field_Flag.Default_Parameters,
|
||||
.Ellipsis,
|
||||
.Using,
|
||||
.No_Alias,
|
||||
.C_Vararg,
|
||||
.Auto_Cast,
|
||||
.Default_Parameters,
|
||||
};
|
||||
|
||||
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
|
||||
@@ -463,18 +467,18 @@ Field_Flags_Signature_Results :: Field_Flags_Signature;
|
||||
|
||||
Proc_Group :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
open: token.Pos,
|
||||
tok: tokenizer.Token,
|
||||
open: tokenizer.Pos,
|
||||
args: []^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Attribute :: struct {
|
||||
using node: Node,
|
||||
tok: token.Kind,
|
||||
open: token.Pos,
|
||||
tok: tokenizer.Token_Kind,
|
||||
open: tokenizer.Pos,
|
||||
elems: []^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Field :: struct {
|
||||
@@ -483,56 +487,57 @@ Field :: struct {
|
||||
names: []^Expr, // Could be polymorphic
|
||||
type: ^Expr,
|
||||
default_value: ^Expr,
|
||||
tag: tokenizer.Token,
|
||||
flags: Field_Flags,
|
||||
comment: ^Comment_Group,
|
||||
}
|
||||
|
||||
Field_List :: struct {
|
||||
using node: Node,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
list: []^Field,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
|
||||
// Types
|
||||
Typeid_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
specialization: ^Expr,
|
||||
}
|
||||
|
||||
Helper_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
type: ^Expr,
|
||||
}
|
||||
|
||||
Distinct_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
type: ^Expr,
|
||||
}
|
||||
|
||||
Opaque_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
type: ^Expr,
|
||||
}
|
||||
|
||||
Poly_Type :: struct {
|
||||
using node: Expr,
|
||||
dollar: token.Pos,
|
||||
dollar: tokenizer.Pos,
|
||||
type: ^Ident,
|
||||
specialization: ^Expr,
|
||||
}
|
||||
|
||||
Proc_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
calling_convention: Proc_Calling_Convention,
|
||||
params: ^Field_List,
|
||||
arrow: token.Pos,
|
||||
arrow: tokenizer.Pos,
|
||||
results: ^Field_List,
|
||||
tags: Proc_Tags,
|
||||
generic: bool,
|
||||
@@ -541,77 +546,81 @@ Proc_Type :: struct {
|
||||
|
||||
Pointer_Type :: struct {
|
||||
using node: Expr,
|
||||
pointer: token.Pos,
|
||||
pointer: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
}
|
||||
|
||||
Array_Type :: struct {
|
||||
using node: Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
}
|
||||
|
||||
Dynamic_Array_Type :: struct {
|
||||
using node: Expr,
|
||||
open: token.Pos,
|
||||
dynamic_pos: token.Pos,
|
||||
close: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
dynamic_pos: tokenizer.Pos,
|
||||
close: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
}
|
||||
|
||||
Struct_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
poly_params: ^Field_List,
|
||||
align: ^Expr,
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
fields: ^Field_List,
|
||||
name_count: int,
|
||||
tok_pos: tokenizer.Pos,
|
||||
poly_params: ^Field_List,
|
||||
align: ^Expr,
|
||||
fields: ^Field_List,
|
||||
name_count: int,
|
||||
where_token: tokenizer.Token,
|
||||
where_clauses: []^Expr,
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
}
|
||||
|
||||
Union_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
poly_params: ^Field_List,
|
||||
align: ^Expr,
|
||||
variants: []^Expr,
|
||||
where_token: tokenizer.Token,
|
||||
where_clauses: []^Expr,
|
||||
}
|
||||
|
||||
Enum_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
base_type: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
fields: []^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
|
||||
is_using: bool,
|
||||
}
|
||||
|
||||
Bit_Field_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
align: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
fields: []^Field_Value, // Field_Value with ':' rather than '='
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Bit_Set_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
open: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
open: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
underlying: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Map_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
key: ^Expr,
|
||||
value: ^Expr,
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package odin_ast
|
||||
|
||||
import "core:mem"
|
||||
import "core:fmt"
|
||||
import "core:odin/token"
|
||||
import "core:odin/tokenizer"
|
||||
|
||||
new :: proc($T: typeid, pos, end: token.Pos) -> ^T {
|
||||
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
|
||||
n := mem.new(T);
|
||||
n.pos = pos;
|
||||
n.end = end;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package odin_ast
|
||||
|
||||
import "core:odin/token"
|
||||
import "core:odin/tokenizer"
|
||||
|
||||
Package_Kind :: enum {
|
||||
Normal,
|
||||
@@ -26,7 +26,7 @@ File :: struct {
|
||||
src: []byte,
|
||||
|
||||
pkg_decl: ^Package_Decl,
|
||||
pkg_token: token.Token,
|
||||
pkg_token: tokenizer.Token,
|
||||
pkg_name: string,
|
||||
|
||||
decls: [dynamic]^Stmt,
|
||||
|
||||
+448
-394
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
package odin_token
|
||||
package odin_tokenizer
|
||||
|
||||
import "core:strings"
|
||||
|
||||
Token :: struct {
|
||||
kind: Kind,
|
||||
kind: Token_Kind,
|
||||
text: string,
|
||||
pos: Pos,
|
||||
}
|
||||
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
|
||||
return strings.compare(lhs.file, rhs.file);
|
||||
}
|
||||
|
||||
using Kind :: enum u32 {
|
||||
Token_Kind :: enum u32 {
|
||||
Invalid,
|
||||
EOF,
|
||||
Comment,
|
||||
@@ -118,6 +118,7 @@ using Kind :: enum u32 {
|
||||
Package,
|
||||
Typeid,
|
||||
When,
|
||||
Where,
|
||||
If,
|
||||
Else,
|
||||
For,
|
||||
@@ -154,9 +155,6 @@ using Kind :: enum u32 {
|
||||
Offset_Of,
|
||||
Type_Of,
|
||||
Const,
|
||||
Asm,
|
||||
Yield,
|
||||
Await,
|
||||
B_Keyword_End,
|
||||
|
||||
COUNT,
|
||||
@@ -165,7 +163,7 @@ using Kind :: enum u32 {
|
||||
// ... Custom keywords
|
||||
};
|
||||
|
||||
tokens := [Kind.COUNT]string {
|
||||
tokens := [Token_Kind.COUNT]string {
|
||||
"Invalid",
|
||||
"EOF",
|
||||
"Comment",
|
||||
@@ -255,6 +253,7 @@ tokens := [Kind.COUNT]string {
|
||||
"package",
|
||||
"typeid",
|
||||
"when",
|
||||
"where",
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
@@ -291,20 +290,17 @@ tokens := [Kind.COUNT]string {
|
||||
"offset_of",
|
||||
"type_of",
|
||||
"const",
|
||||
"asm",
|
||||
"yield",
|
||||
"await",
|
||||
"",
|
||||
};
|
||||
|
||||
custom_keyword_tokens: []string;
|
||||
|
||||
to_string :: proc(kind: Kind) -> string {
|
||||
if Invalid <= kind && kind < COUNT {
|
||||
to_string :: proc(kind: Token_Kind) -> string {
|
||||
if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
|
||||
return tokens[kind];
|
||||
}
|
||||
if B_Custom_Keyword_Begin < kind {
|
||||
n := int(u16(kind)-u16(B_Custom_Keyword_Begin));
|
||||
if Token_Kind.B_Custom_Keyword_Begin < kind {
|
||||
n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin));
|
||||
if n < len(custom_keyword_tokens) {
|
||||
return custom_keyword_tokens[n];
|
||||
}
|
||||
@@ -313,24 +309,26 @@ to_string :: proc(kind: Kind) -> string {
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
is_literal :: proc(kind: Kind) -> bool { return B_Literal_Begin < kind && kind < B_Literal_End; }
|
||||
is_operator :: proc(kind: Kind) -> bool {
|
||||
is_literal :: proc(kind: Token_Kind) -> bool {
|
||||
return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
|
||||
}
|
||||
is_operator :: proc(kind: Token_Kind) -> bool {
|
||||
switch kind {
|
||||
case B_Operator_Begin..B_Operator_End:
|
||||
case .B_Operator_Begin .. .B_Operator_End:
|
||||
return true;
|
||||
case In, Notin:
|
||||
case .In, .Notin:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_assignment_operator :: proc(kind: Kind) -> bool {
|
||||
return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq;
|
||||
is_assignment_operator :: proc(kind: Token_Kind) -> bool {
|
||||
return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq;
|
||||
}
|
||||
is_keyword :: proc(kind: Kind) -> bool {
|
||||
is_keyword :: proc(kind: Token_Kind) -> bool {
|
||||
switch {
|
||||
case B_Keyword_Begin < kind && kind < B_Keyword_End:
|
||||
case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
|
||||
return true;
|
||||
case B_Custom_Keyword_Begin < kind:
|
||||
case Token_Kind.B_Custom_Keyword_Begin < kind:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1,10 +1,9 @@
|
||||
package odin_tokenizer
|
||||
|
||||
import "core:fmt"
|
||||
import "core:odin/token"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any);
|
||||
Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any);
|
||||
|
||||
Tokenizer :: struct {
|
||||
// Immutable data
|
||||
@@ -41,11 +40,11 @@ init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = defa
|
||||
}
|
||||
|
||||
@(private)
|
||||
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
|
||||
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos {
|
||||
line := t.line_count;
|
||||
column := offset - t.line_offset + 1;
|
||||
|
||||
return token.Pos {
|
||||
return Pos {
|
||||
file = t.path,
|
||||
offset = offset,
|
||||
line = line,
|
||||
@@ -53,10 +52,10 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
|
||||
};
|
||||
}
|
||||
|
||||
default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) {
|
||||
fmt.printf_err("%s(%d:%d) ", pos.file, pos.line, pos.column);
|
||||
fmt.printf_err(msg, ..args);
|
||||
fmt.printf_err("\n");
|
||||
default_error_handler :: proc(pos: Pos, msg: string, args: ..any) {
|
||||
fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column);
|
||||
fmt.eprintf(msg, ..args);
|
||||
fmt.eprintf("\n");
|
||||
}
|
||||
|
||||
error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
|
||||
@@ -322,15 +321,15 @@ scan_rune :: proc(t: ^Tokenizer) -> string {
|
||||
return string(t.src[offset : t.offset]);
|
||||
}
|
||||
|
||||
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, string) {
|
||||
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) {
|
||||
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
|
||||
for digit_val(t.ch) < base || t.ch == '_' {
|
||||
advance_rune(t);
|
||||
}
|
||||
}
|
||||
scan_exponent :: proc(t: ^Tokenizer, kind: ^token.Kind) {
|
||||
scan_exponent :: proc(t: ^Tokenizer, kind: ^Token_Kind) {
|
||||
if t.ch == 'e' || t.ch == 'E' {
|
||||
kind^ = token.Float;
|
||||
kind^ = .Float;
|
||||
advance_rune(t);
|
||||
if t.ch == '-' || t.ch == '+' {
|
||||
advance_rune(t);
|
||||
@@ -343,17 +342,18 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
}
|
||||
|
||||
// NOTE(bill): This needs to be here for sanity's sake
|
||||
if t.ch == 'i' {
|
||||
kind^ = token.Imag;
|
||||
switch t.ch {
|
||||
case 'i', 'j', 'k':
|
||||
kind^ = .Imag;
|
||||
advance_rune(t);
|
||||
}
|
||||
}
|
||||
scan_fraction :: proc(t: ^Tokenizer, kind: ^token.Kind) -> (early_exit: bool) {
|
||||
scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) {
|
||||
if t.ch == '.' && peek_byte(t) == '.' {
|
||||
return true;
|
||||
}
|
||||
if t.ch == '.' {
|
||||
kind^ = token.Float;
|
||||
kind^ = .Float;
|
||||
advance_rune(t);
|
||||
scan_mantissa(t, 10);
|
||||
}
|
||||
@@ -362,22 +362,22 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
|
||||
|
||||
offset := t.offset;
|
||||
kind := token.Integer;
|
||||
kind := Token_Kind.Integer;
|
||||
seen_point := seen_decimal_point;
|
||||
|
||||
if seen_point {
|
||||
offset -= 1;
|
||||
kind = token.Float;
|
||||
kind = .Float;
|
||||
scan_mantissa(t, 10);
|
||||
scan_exponent(t, &kind);
|
||||
} else {
|
||||
if t.ch == '0' {
|
||||
int_base :: inline proc(t: ^Tokenizer, kind: ^token.Kind, base: int, msg: string) {
|
||||
int_base :: inline proc(t: ^Tokenizer, kind: ^Token_Kind, base: int, msg: string) {
|
||||
prev := t.offset;
|
||||
advance_rune(t);
|
||||
scan_mantissa(t, base);
|
||||
if t.offset - prev <= 1 {
|
||||
kind^ = token.Invalid;
|
||||
kind^ = .Invalid;
|
||||
error(t, t.offset, msg);
|
||||
}
|
||||
}
|
||||
@@ -394,7 +394,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
advance_rune(t);
|
||||
scan_mantissa(t, 16);
|
||||
if t.offset - prev <= 1 {
|
||||
kind = token.Invalid;
|
||||
kind = .Invalid;
|
||||
error(t, t.offset, "illegal hexadecimal floating-point number");
|
||||
} else {
|
||||
sub := t.src[prev+1 : t.offset];
|
||||
@@ -439,15 +439,15 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
}
|
||||
|
||||
|
||||
scan :: proc(t: ^Tokenizer) -> token.Token {
|
||||
switch2 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind) -> token.Kind {
|
||||
scan :: proc(t: ^Tokenizer) -> Token {
|
||||
switch2 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind) -> Token_Kind {
|
||||
if t.ch == '=' {
|
||||
advance_rune(t);
|
||||
return tok1;
|
||||
}
|
||||
return tok0;
|
||||
}
|
||||
switch3 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2: token.Kind) -> token.Kind {
|
||||
switch3 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2: Token_Kind) -> Token_Kind {
|
||||
if t.ch == '=' {
|
||||
advance_rune(t);
|
||||
return tok1;
|
||||
@@ -458,7 +458,7 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
||||
}
|
||||
return tok0;
|
||||
}
|
||||
switch4 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2, tok3: token.Kind) -> token.Kind {
|
||||
switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind {
|
||||
if t.ch == '=' {
|
||||
advance_rune(t);
|
||||
return tok1;
|
||||
@@ -479,25 +479,25 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
||||
|
||||
offset := t.offset;
|
||||
|
||||
kind: token.Kind;
|
||||
kind: Token_Kind;
|
||||
lit: string;
|
||||
pos := offset_to_pos(t, offset);
|
||||
|
||||
switch ch := t.ch; true {
|
||||
case is_letter(ch):
|
||||
lit = scan_identifier(t);
|
||||
kind = token.Ident;
|
||||
kind = .Ident;
|
||||
check_keyword: if len(lit) > 1 {
|
||||
// TODO(bill): Maybe have a hash table lookup rather than this linear search
|
||||
for i in token.B_Keyword_Begin .. token.B_Keyword_End {
|
||||
if lit == token.tokens[i] {
|
||||
kind = token.Kind(i);
|
||||
for i in Token_Kind.B_Keyword_Begin .. Token_Kind.B_Keyword_End {
|
||||
if lit == tokens[i] {
|
||||
kind = Token_Kind(i);
|
||||
break check_keyword;
|
||||
}
|
||||
}
|
||||
for keyword, i in token.custom_keyword_tokens {
|
||||
for keyword, i in custom_keyword_tokens {
|
||||
if lit == keyword {
|
||||
kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin;
|
||||
kind = Token_Kind(i+1) + .B_Custom_Keyword_Begin;
|
||||
break check_keyword;
|
||||
}
|
||||
}
|
||||
@@ -508,115 +508,115 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
||||
advance_rune(t);
|
||||
switch ch {
|
||||
case -1:
|
||||
kind = token.EOF;
|
||||
kind = .EOF;
|
||||
case '"':
|
||||
kind = token.String;
|
||||
kind = .String;
|
||||
lit = scan_string(t);
|
||||
case '\'':
|
||||
kind = token.Rune;
|
||||
kind = .Rune;
|
||||
lit = scan_rune(t);
|
||||
case '`':
|
||||
kind = token.String;
|
||||
kind = .String;
|
||||
lit = scan_raw_string(t);
|
||||
case '=':
|
||||
if t.ch == '>' {
|
||||
advance_rune(t);
|
||||
kind = token.Double_Arrow_Right;
|
||||
kind = .Double_Arrow_Right;
|
||||
} else {
|
||||
kind = switch2(t, token.Eq, token.Cmp_Eq);
|
||||
kind = switch2(t, .Eq, .Cmp_Eq);
|
||||
}
|
||||
case '!': kind = switch2(t, token.Not, token.Not_Eq);
|
||||
case '!': kind = switch2(t, .Not, .Not_Eq);
|
||||
case '#':
|
||||
kind = token.Hash;
|
||||
kind = .Hash;
|
||||
if t.ch == '!' {
|
||||
kind = token.Comment;
|
||||
kind = .Comment;
|
||||
lit = scan_comment(t);
|
||||
}
|
||||
case '?': kind = token.Question;
|
||||
case '@': kind = token.At;
|
||||
case '$': kind = token.Dollar;
|
||||
case '^': kind = token.Pointer;
|
||||
case '+': kind = switch2(t, token.Add, token.Add_Eq);
|
||||
case '?': kind = .Question;
|
||||
case '@': kind = .At;
|
||||
case '$': kind = .Dollar;
|
||||
case '^': kind = .Pointer;
|
||||
case '+': kind = switch2(t, .Add, .Add_Eq);
|
||||
case '-':
|
||||
if t.ch == '>' {
|
||||
advance_rune(t);
|
||||
kind = token.Arrow_Right;
|
||||
kind = .Arrow_Right;
|
||||
} else if t.ch == '-' && peek_byte(t) == '-' {
|
||||
advance_rune(t);
|
||||
advance_rune(t);
|
||||
kind = token.Undef;
|
||||
kind = .Undef;
|
||||
} else {
|
||||
kind = switch2(t, token.Sub, token.Sub_Eq);
|
||||
kind = switch2(t, .Sub, .Sub_Eq);
|
||||
}
|
||||
case '*': kind = switch2(t, token.Mul, token.Mul_Eq);
|
||||
case '*': kind = switch2(t, .Mul, .Mul_Eq);
|
||||
case '/':
|
||||
if t.ch == '/' || t.ch == '*' {
|
||||
kind = token.Comment;
|
||||
kind = .Comment;
|
||||
lit = scan_comment(t);
|
||||
} else {
|
||||
kind = switch2(t, token.Quo, token.Quo_Eq);
|
||||
kind = switch2(t, .Quo, .Quo_Eq);
|
||||
}
|
||||
case '%': kind = switch4(t, token.Mod, token.Mod_Eq, '%', token.Mod_Mod, token.Mod_Mod_Eq);
|
||||
case '%': kind = switch4(t, .Mod, .Mod_Eq, '%', .Mod_Mod, .Mod_Mod_Eq);
|
||||
case '&':
|
||||
if t.ch == '~' {
|
||||
advance_rune(t);
|
||||
kind = switch2(t, token.And_Not, token.And_Not_Eq);
|
||||
kind = switch2(t, .And_Not, .And_Not_Eq);
|
||||
} else {
|
||||
kind = switch3(t, token.And, token.And_Eq, '&', token.Cmp_And);
|
||||
kind = switch3(t, .And, .And_Eq, '&', .Cmp_And);
|
||||
}
|
||||
case '|': kind = switch3(t, token.Or, token.Or_Eq, '|', token.Cmp_Or);
|
||||
case '~': kind = token.Xor;
|
||||
case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
|
||||
case '~': kind = .Xor;
|
||||
case '<':
|
||||
if t.ch == '-' {
|
||||
advance_rune(t);
|
||||
kind = token.Arrow_Left;
|
||||
kind = .Arrow_Left;
|
||||
} else {
|
||||
kind = switch4(t, token.Lt, token.Lt_Eq, '<', token.Shl, token.Shl_Eq);
|
||||
kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq);
|
||||
}
|
||||
case '>': kind = switch4(t, token.Gt, token.Gt_Eq, '>', token.Shr,token.Shr_Eq);
|
||||
case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq);
|
||||
|
||||
case '≠': kind = token.Not_Eq;
|
||||
case '≤': kind = token.Lt_Eq;
|
||||
case '≥': kind = token.Gt_Eq;
|
||||
case '∈': kind = token.In;
|
||||
case '∉': kind = token.Notin;
|
||||
case '≠': kind = .Not_Eq;
|
||||
case '≤': kind = .Lt_Eq;
|
||||
case '≥': kind = .Gt_Eq;
|
||||
case '∈': kind = .In;
|
||||
case '∉': kind = .Notin;
|
||||
|
||||
case '.':
|
||||
if '0' <= t.ch && t.ch <= '9' {
|
||||
kind, lit = scan_number(t, true);
|
||||
} else {
|
||||
kind = token.Period;
|
||||
kind = .Period;
|
||||
if t.ch == '.' {
|
||||
advance_rune(t);
|
||||
kind = token.Ellipsis;
|
||||
kind = .Ellipsis;
|
||||
if t.ch == '<' {
|
||||
advance_rune(t);
|
||||
kind = token.Range_Half;
|
||||
kind = .Range_Half;
|
||||
}
|
||||
}
|
||||
}
|
||||
case ':': kind = token.Colon;
|
||||
case ',': kind = token.Comma;
|
||||
case ';': kind = token.Semicolon;
|
||||
case '(': kind = token.Open_Paren;
|
||||
case ')': kind = token.Close_Paren;
|
||||
case '[': kind = token.Open_Bracket;
|
||||
case ']': kind = token.Close_Bracket;
|
||||
case '{': kind = token.Open_Brace;
|
||||
case '}': kind = token.Close_Brace;
|
||||
case ':': kind = .Colon;
|
||||
case ',': kind = .Comma;
|
||||
case ';': kind = .Semicolon;
|
||||
case '(': kind = .Open_Paren;
|
||||
case ')': kind = .Close_Paren;
|
||||
case '[': kind = .Open_Bracket;
|
||||
case ']': kind = .Close_Bracket;
|
||||
case '{': kind = .Open_Brace;
|
||||
case '}': kind = .Close_Brace;
|
||||
|
||||
case '\\': kind = token.Back_Slash;
|
||||
case '\\': kind = .Back_Slash;
|
||||
|
||||
case:
|
||||
if ch != utf8.RUNE_BOM {
|
||||
error(t, t.offset, "illegal character '%r': %d", ch, ch);
|
||||
}
|
||||
kind = token.Invalid;
|
||||
kind = .Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
if lit == "" {
|
||||
lit = string(t.src[offset : t.offset]);
|
||||
}
|
||||
return token.Token{kind, lit, pos};
|
||||
return Token{kind, lit, pos};
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ foreign import libc "system:c"
|
||||
import "core:runtime"
|
||||
import "core:strings"
|
||||
|
||||
OS :: "osx";
|
||||
OS :: "darwin";
|
||||
|
||||
Handle :: distinct i32;
|
||||
File_Time :: distinct u64;
|
||||
@@ -319,9 +319,9 @@ dlerror :: proc() -> string {
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
args := make([]string, len(runtime.args__));
|
||||
res := make([]string, len(runtime.args__));
|
||||
for arg, i in runtime.args__ {
|
||||
args[i] = string(arg);
|
||||
res[i] = string(arg);
|
||||
}
|
||||
return args;
|
||||
return res;
|
||||
}
|
||||
+2422
-162
File diff suppressed because it is too large
Load Diff
@@ -392,9 +392,9 @@ dlerror :: proc() -> string {
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
args := make([]string, len(runtime.args__));
|
||||
res := make([]string, len(runtime.args__));
|
||||
for arg, i in runtime.args__ {
|
||||
args[i] = string(arg);
|
||||
res[i] = string(arg);
|
||||
}
|
||||
return args;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -322,4 +322,4 @@ is_windows_8_1 :: proc() -> bool {
|
||||
is_windows_10 :: proc() -> bool {
|
||||
osvi := get_windows_version_ansi();
|
||||
return (osvi.major_version == 10 && osvi.minor_version == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
package reflect
|
||||
|
||||
import "core:runtime"
|
||||
import "core:mem"
|
||||
|
||||
|
||||
Type_Kind :: enum {
|
||||
Invalid,
|
||||
|
||||
Named,
|
||||
Integer,
|
||||
Rune,
|
||||
Float,
|
||||
Complex,
|
||||
Quaternion,
|
||||
String,
|
||||
Boolean,
|
||||
Any,
|
||||
Type_Id,
|
||||
Pointer,
|
||||
Procedure,
|
||||
Array,
|
||||
Dynamic_Array,
|
||||
Slice,
|
||||
Tuple,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
Map,
|
||||
Bit_Field,
|
||||
Bit_Set,
|
||||
Opaque,
|
||||
Simd_Vector,
|
||||
}
|
||||
|
||||
|
||||
type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
ti := type_info_of(T);
|
||||
if ti != nil {
|
||||
#complete switch _ in ti.variant {
|
||||
case runtime.Type_Info_Named: return .Named;
|
||||
case runtime.Type_Info_Integer: return .Integer;
|
||||
case runtime.Type_Info_Rune: return .Rune;
|
||||
case runtime.Type_Info_Float: return .Float;
|
||||
case runtime.Type_Info_Complex: return .Complex;
|
||||
case runtime.Type_Info_Quaternion: return .Quaternion;
|
||||
case runtime.Type_Info_String: return .String;
|
||||
case runtime.Type_Info_Boolean: return .Boolean;
|
||||
case runtime.Type_Info_Any: return .Any;
|
||||
case runtime.Type_Info_Type_Id: return .Type_Id;
|
||||
case runtime.Type_Info_Pointer: return .Pointer;
|
||||
case runtime.Type_Info_Procedure: return .Procedure;
|
||||
case runtime.Type_Info_Array: return .Array;
|
||||
case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array;
|
||||
case runtime.Type_Info_Slice: return .Slice;
|
||||
case runtime.Type_Info_Tuple: return .Tuple;
|
||||
case runtime.Type_Info_Struct: return .Struct;
|
||||
case runtime.Type_Info_Union: return .Union;
|
||||
case runtime.Type_Info_Enum: return .Enum;
|
||||
case runtime.Type_Info_Map: return .Map;
|
||||
case runtime.Type_Info_Bit_Field: return .Bit_Field;
|
||||
case runtime.Type_Info_Bit_Set: return .Bit_Set;
|
||||
case runtime.Type_Info_Opaque: return .Opaque;
|
||||
case runtime.Type_Info_Simd_Vector: return .Simd_Vector;
|
||||
}
|
||||
|
||||
}
|
||||
return .Invalid;
|
||||
}
|
||||
|
||||
// TODO(bill): Better name
|
||||
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
return type_kind(runtime.typeid_base(T));
|
||||
}
|
||||
|
||||
// TODO(bill): Better name
|
||||
backing_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
return type_kind(runtime.typeid_core(T));
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_of_typeid :: proc(T: typeid) -> int {
|
||||
if ti := type_info_of(T); ti != nil {
|
||||
return ti.size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
align_of_typeid :: proc(T: typeid) -> int {
|
||||
if ti := type_info_of(T); ti != nil {
|
||||
return ti.align;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
to_bytes :: proc(v: any) -> []byte {
|
||||
if v != nil {
|
||||
sz := size_of_typeid(v.id);
|
||||
return mem.slice_ptr((^byte)(v.data), sz);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
any_data :: inline proc(v: any) -> (data: rawptr, id: typeid) {
|
||||
return v.data, v.id;
|
||||
}
|
||||
|
||||
is_nil :: proc(v: any) -> bool {
|
||||
data := to_bytes(v);
|
||||
if data != nil {
|
||||
return true;
|
||||
}
|
||||
for v in data do if v != 0 {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
length :: proc(val: any) -> int {
|
||||
if val == nil do return 0;
|
||||
|
||||
v := val;
|
||||
v.id = runtime.typeid_base(v.id);
|
||||
switch a in v {
|
||||
case runtime.Type_Info_Array:
|
||||
return a.count;
|
||||
|
||||
case runtime.Type_Info_Slice:
|
||||
return (^mem.Raw_Slice)(v.data).len;
|
||||
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
return (^mem.Raw_Dynamic_Array)(v.data).len;
|
||||
|
||||
case runtime.Type_Info_String:
|
||||
if a.is_cstring {
|
||||
return len((^cstring)(v.data)^);
|
||||
} else {
|
||||
return (^mem.Raw_String)(v.data).len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||
if val == nil do return nil;
|
||||
|
||||
v := val;
|
||||
v.id = runtime.typeid_base(v.id);
|
||||
switch a in v {
|
||||
case runtime.Type_Info_Array:
|
||||
runtime.bounds_check_error_loc(loc, i, a.count);
|
||||
offset := uintptr(a.elem.size * i);
|
||||
data := rawptr(uintptr(v.data) + offset);
|
||||
return any{data, a.elem.id};
|
||||
|
||||
case runtime.Type_Info_Slice:
|
||||
raw := (^mem.Raw_Slice)(v.data);
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len);
|
||||
offset := uintptr(a.elem.size * i);
|
||||
data := rawptr(uintptr(raw.data) + offset);
|
||||
return any{data, a.elem.id};
|
||||
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
raw := (^mem.Raw_Dynamic_Array)(v.data);
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len);
|
||||
offset := uintptr(a.elem.size * i);
|
||||
data := rawptr(uintptr(raw.data) + offset);
|
||||
return any{data, a.elem.id};
|
||||
|
||||
case runtime.Type_Info_String:
|
||||
if a.is_cstring do return nil;
|
||||
|
||||
raw := (^mem.Raw_String)(v.data);
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len);
|
||||
offset := uintptr(size_of(u8) * i);
|
||||
data := rawptr(uintptr(raw.data) + offset);
|
||||
return any{data, typeid_of(u8)};
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Struct_Tag :: distinct string;
|
||||
|
||||
Struct_Field :: struct {
|
||||
name: string,
|
||||
type: typeid,
|
||||
tag: Struct_Tag,
|
||||
offset: uintptr,
|
||||
}
|
||||
|
||||
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
if 0 <= i && i < len(s.names) {
|
||||
field.name = s.names[i];
|
||||
field.type = s.types[i].id;
|
||||
field.tag = Struct_Tag(s.tags[i]);
|
||||
field.offset = s.offsets[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
for fname, i in s.names {
|
||||
if fname == name {
|
||||
field.name = s.names[i];
|
||||
field.type = s.types[i].id;
|
||||
field.tag = Struct_Tag(s.tags[i]);
|
||||
field.offset = s.offsets[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
|
||||
if a == nil do return nil;
|
||||
|
||||
ti := runtime.type_info_base(type_info_of(a.id));
|
||||
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
for name, i in s.names {
|
||||
if name == field {
|
||||
return any{
|
||||
rawptr(uintptr(a.data) + s.offsets[i]),
|
||||
s.types[i].id,
|
||||
};
|
||||
}
|
||||
|
||||
if recurse && s.usings[i] {
|
||||
f := any{
|
||||
rawptr(uintptr(a.data) + s.offsets[i]),
|
||||
s.types[i].id,
|
||||
};
|
||||
|
||||
if res := struct_field_value_by_name(f, field, recurse); res != nil {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct_field_names :: proc(T: typeid) -> []string {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
return s.names;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
return s.types;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
return transmute([]Struct_Tag)s.tags;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
return s.offsets;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) {
|
||||
value, _ = struct_tag_lookup(tag, key);
|
||||
return;
|
||||
}
|
||||
|
||||
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) {
|
||||
for t := tag; t != ""; /**/ {
|
||||
i := 0;
|
||||
for i < len(t) && t[i] == ' ' { // Skip whitespace
|
||||
i += 1;
|
||||
}
|
||||
t = t[i:];
|
||||
if len(t) == 0 do break;
|
||||
|
||||
i = 0;
|
||||
loop: for i < len(t) {
|
||||
switch t[i] {
|
||||
case ':', '"':
|
||||
break loop;
|
||||
case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found
|
||||
break loop;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if i == 0 do break;
|
||||
if i+1 >= len(t) do break;
|
||||
|
||||
if t[i] != ':' || t[i+1] != '"' {
|
||||
break;
|
||||
}
|
||||
name := string(t[:i]);
|
||||
t = t[i+1:];
|
||||
|
||||
i = 1;
|
||||
for i < len(t) && t[i] != '"' { // find closing quote
|
||||
if t[i] == '\\' do i += 1; // Skip escaped characters
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if i >= len(t) do break;
|
||||
|
||||
val := string(t[:i+1]);
|
||||
t = t[i+1:];
|
||||
|
||||
if key == name {
|
||||
return val[1:i], true;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
enum_string :: proc(a: any) -> string {
|
||||
if a == nil do return "";
|
||||
ti := runtime.type_info_base(type_info_of(a.id));
|
||||
if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
|
||||
for _, i in e.values {
|
||||
value := &e.values[i];
|
||||
n := mem.compare_byte_ptrs((^byte)(a.data), (^byte)(value), ti.size);
|
||||
if n == 0 {
|
||||
return e.names[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic("expected an enum to reflect.enum_string");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
|
||||
id := union_variant_typeid(a);
|
||||
return type_info_of(id);
|
||||
}
|
||||
|
||||
union_variant_typeid :: proc(a: any) -> typeid {
|
||||
if a == nil do return nil;
|
||||
|
||||
ti := runtime.type_info_base(type_info_of(a.id));
|
||||
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
||||
tag_ptr := uintptr(a.data) + info.tag_offset;
|
||||
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
||||
|
||||
tag: i64 = ---;
|
||||
switch i in tag_any {
|
||||
case u8: tag = i64(i);
|
||||
case i8: tag = i64(i);
|
||||
case u16: tag = i64(i);
|
||||
case i16: tag = i64(i);
|
||||
case u32: tag = i64(i);
|
||||
case i32: tag = i64(i);
|
||||
case u64: tag = i64(i);
|
||||
case i64: tag = i64(i);
|
||||
case: unimplemented();
|
||||
}
|
||||
|
||||
if a.data != nil && tag != 0 {
|
||||
return info.variants[tag-1].id;
|
||||
}
|
||||
} else {
|
||||
panic("expected a union to reflect.union_variant_typeid");
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package types
|
||||
package reflect
|
||||
|
||||
import rt "core:runtime"
|
||||
import "core:strings"
|
||||
|
||||
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
||||
if a == b do return true;
|
||||
@@ -108,9 +109,11 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
||||
for _, i in x.types {
|
||||
xn, yn := x.names[i], y.names[i];
|
||||
xt, yt := x.types[i], y.types[i];
|
||||
xl, yl := x.tags[i], y.tags[i];
|
||||
|
||||
if xn != yn do return false;
|
||||
if !are_types_identical(xt, yt) do return false;
|
||||
if xl != yl do return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -272,3 +275,216 @@ is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
|
||||
write_type(buf, type_info_of(id));
|
||||
}
|
||||
|
||||
write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
|
||||
using strings;
|
||||
if ti == nil {
|
||||
write_string(buf, "nil");
|
||||
return;
|
||||
}
|
||||
|
||||
switch info in ti.variant {
|
||||
case rt.Type_Info_Named:
|
||||
write_string(buf, info.name);
|
||||
case rt.Type_Info_Integer:
|
||||
switch ti.id {
|
||||
case int: write_string(buf, "int");
|
||||
case uint: write_string(buf, "uint");
|
||||
case uintptr: write_string(buf, "uintptr");
|
||||
case:
|
||||
write_byte(buf, info.signed ? 'i' : 'u');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
switch info.endianness {
|
||||
case .Little: write_string(buf, "le");
|
||||
case .Big: write_string(buf, "be");
|
||||
}
|
||||
}
|
||||
case rt.Type_Info_Rune:
|
||||
write_string(buf, "rune");
|
||||
case rt.Type_Info_Float:
|
||||
write_byte(buf, 'f');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case rt.Type_Info_Complex:
|
||||
write_string(buf, "complex");
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case rt.Type_Info_String:
|
||||
if info.is_cstring {
|
||||
write_string(buf, "cstring");
|
||||
} else {
|
||||
write_string(buf, "string");
|
||||
}
|
||||
case rt.Type_Info_Boolean:
|
||||
switch ti.id {
|
||||
case bool: write_string(buf, "bool");
|
||||
case:
|
||||
write_byte(buf, 'b');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
}
|
||||
case rt.Type_Info_Any:
|
||||
write_string(buf, "any");
|
||||
|
||||
case rt.Type_Info_Type_Id:
|
||||
write_string(buf, "typeid");
|
||||
|
||||
case rt.Type_Info_Pointer:
|
||||
if info.elem == nil {
|
||||
write_string(buf, "rawptr");
|
||||
} else {
|
||||
write_string(buf, "^");
|
||||
write_type(buf, info.elem);
|
||||
}
|
||||
case rt.Type_Info_Procedure:
|
||||
write_string(buf, "proc");
|
||||
if info.params == nil {
|
||||
write_string(buf, "()");
|
||||
} else {
|
||||
t := info.params.variant.(rt.Type_Info_Tuple);
|
||||
write_string(buf, "(");
|
||||
for t, i in t.types {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_type(buf, t);
|
||||
}
|
||||
write_string(buf, ")");
|
||||
}
|
||||
if info.results != nil {
|
||||
write_string(buf, " -> ");
|
||||
write_type(buf, info.results);
|
||||
}
|
||||
case rt.Type_Info_Tuple:
|
||||
count := len(info.names);
|
||||
if count != 1 do write_string(buf, "(");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
|
||||
t := info.types[i];
|
||||
|
||||
if len(name) > 0 {
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
}
|
||||
write_type(buf, t);
|
||||
}
|
||||
if count != 1 do write_string(buf, ")");
|
||||
|
||||
case rt.Type_Info_Array:
|
||||
write_string(buf, "[");
|
||||
write_i64(buf, i64(info.count), 10);
|
||||
write_string(buf, "]");
|
||||
write_type(buf, info.elem);
|
||||
case rt.Type_Info_Dynamic_Array:
|
||||
write_string(buf, "[dynamic]");
|
||||
write_type(buf, info.elem);
|
||||
case rt.Type_Info_Slice:
|
||||
write_string(buf, "[]");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case rt.Type_Info_Map:
|
||||
write_string(buf, "map[");
|
||||
write_type(buf, info.key);
|
||||
write_byte(buf, ']');
|
||||
write_type(buf, info.value);
|
||||
|
||||
case rt.Type_Info_Struct:
|
||||
write_string(buf, "struct ");
|
||||
if info.is_packed do write_string(buf, "#packed ");
|
||||
if info.is_raw_union do write_string(buf, "#raw_union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_type(buf, info.types[i]);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case rt.Type_Info_Union:
|
||||
write_string(buf, "union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for variant, i in info.variants {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_type(buf, variant);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case rt.Type_Info_Enum:
|
||||
write_string(buf, "enum ");
|
||||
write_type(buf, info.base);
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case rt.Type_Info_Bit_Field:
|
||||
write_string(buf, "bit_field ");
|
||||
if ti.align != 1 {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_i64(buf, i64(info.bits[i]), 10);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case rt.Type_Info_Bit_Set:
|
||||
write_string(buf, "bit_set[");
|
||||
switch {
|
||||
case is_enum(info.elem):
|
||||
write_type(buf, info.elem);
|
||||
case is_rune(info.elem):
|
||||
write_encoded_rune(buf, rune(info.lower));
|
||||
write_string(buf, "..");
|
||||
write_encoded_rune(buf, rune(info.upper));
|
||||
case:
|
||||
write_i64(buf, info.lower, 10);
|
||||
write_string(buf, "..");
|
||||
write_i64(buf, info.upper, 10);
|
||||
}
|
||||
if info.underlying != nil {
|
||||
write_string(buf, "; ");
|
||||
write_type(buf, info.underlying);
|
||||
}
|
||||
write_byte(buf, ']');
|
||||
|
||||
case rt.Type_Info_Opaque:
|
||||
write_string(buf, "opaque ");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case rt.Type_Info_Simd_Vector:
|
||||
if info.is_x86_mmx {
|
||||
write_string(buf, "intrinsics.x86_mmx");
|
||||
} else {
|
||||
write_string(buf, "intrinsics.vector(");
|
||||
write_i64(buf, i64(info.count));
|
||||
write_string(buf, ", ");
|
||||
write_type(buf, info.elem);
|
||||
write_byte(buf, ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+98
-75
@@ -6,6 +6,7 @@ package runtime
|
||||
import "core:os"
|
||||
import "core:mem"
|
||||
import "core:log"
|
||||
import "intrinsics"
|
||||
|
||||
// Naming Conventions:
|
||||
// In general, Ada_Case for types and snake_case for values
|
||||
@@ -40,23 +41,24 @@ Type_Info_Enum_Value :: union {
|
||||
u8, u16, u32, u64, uint, uintptr,
|
||||
};
|
||||
|
||||
Type_Info_Endianness :: enum u8 {
|
||||
Platform_Endianness :: enum u8 {
|
||||
Platform = 0,
|
||||
Little = 1,
|
||||
Big = 2,
|
||||
}
|
||||
|
||||
// Variant Types
|
||||
Type_Info_Named :: struct {name: string, base: ^Type_Info};
|
||||
Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness};
|
||||
Type_Info_Rune :: struct {};
|
||||
Type_Info_Float :: struct {};
|
||||
Type_Info_Complex :: 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 {
|
||||
Type_Info_Named :: struct {name: string, base: ^Type_Info};
|
||||
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness};
|
||||
Type_Info_Rune :: struct {};
|
||||
Type_Info_Float :: struct {};
|
||||
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_Procedure :: struct {
|
||||
@@ -79,8 +81,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures
|
||||
Type_Info_Struct :: struct {
|
||||
types: []^Type_Info,
|
||||
names: []string,
|
||||
offsets: []uintptr, // offsets may not be used in tuples
|
||||
usings: []bool, // usings may not be used in tuples
|
||||
offsets: []uintptr,
|
||||
usings: []bool,
|
||||
tags: []string,
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
custom_align: bool,
|
||||
@@ -134,6 +137,7 @@ Type_Info :: struct {
|
||||
Type_Info_Rune,
|
||||
Type_Info_Float,
|
||||
Type_Info_Complex,
|
||||
Type_Info_Quaternion,
|
||||
Type_Info_String,
|
||||
Type_Info_Boolean,
|
||||
Type_Info_Any,
|
||||
@@ -162,6 +166,7 @@ Typeid_Kind :: enum u8 {
|
||||
Rune,
|
||||
Float,
|
||||
Complex,
|
||||
Quaternion,
|
||||
String,
|
||||
Boolean,
|
||||
Any,
|
||||
@@ -183,12 +188,13 @@ Typeid_Kind :: enum u8 {
|
||||
#assert(len(Typeid_Kind) < 32);
|
||||
|
||||
Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
|
||||
index: 8*size_of(align_of(uintptr)) - 8,
|
||||
index: 8*size_of(uintptr) - 8,
|
||||
kind: 5, // Typeid_Kind
|
||||
named: 1,
|
||||
special: 1, // signed, cstring, etc
|
||||
reserved: 1,
|
||||
}
|
||||
#assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
|
||||
|
||||
// NOTE(bill): only the ones that are needed (not all types)
|
||||
// This will be set by the compiler
|
||||
@@ -231,7 +237,22 @@ global_scratch_allocator_data: mem.Scratch_Allocator;
|
||||
|
||||
|
||||
|
||||
Raw_Slice :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Raw_Dynamic_Array :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
cap: int,
|
||||
allocator: mem.Allocator,
|
||||
}
|
||||
|
||||
Raw_Map :: struct {
|
||||
hashes: []int,
|
||||
entries: Raw_Dynamic_Array,
|
||||
}
|
||||
|
||||
INITIAL_MAP_CAP :: 16;
|
||||
|
||||
@@ -255,7 +276,7 @@ Map_Entry_Header :: struct {
|
||||
}
|
||||
|
||||
Map_Header :: struct {
|
||||
m: ^mem.Raw_Map,
|
||||
m: ^Raw_Map,
|
||||
is_key_string: bool,
|
||||
|
||||
entry_size: int,
|
||||
@@ -282,19 +303,21 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
}
|
||||
|
||||
|
||||
type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil do return nil;
|
||||
|
||||
base := info;
|
||||
loop: for {
|
||||
switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base;
|
||||
case Type_Info_Enum: base = i.base;
|
||||
case Type_Info_Named: base = i.base;
|
||||
case Type_Info_Enum: base = i.base;
|
||||
case Type_Info_Opaque: base = i.elem;
|
||||
case: break loop;
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
type_info_base_without_enum :: type_info_core;
|
||||
|
||||
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
|
||||
data := transmute(Typeid_Bit_Field)id;
|
||||
@@ -310,10 +333,11 @@ typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti = type_info_base(ti);
|
||||
return ti.id;
|
||||
}
|
||||
typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid {
|
||||
typeid_core :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_base_without_enum(type_info_of(id));
|
||||
return ti.id;
|
||||
}
|
||||
typeid_base_without_enum :: typeid_core;
|
||||
|
||||
|
||||
|
||||
@@ -385,7 +409,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
|
||||
@builtin
|
||||
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
n := max(0, min(len(dst), len(src)));
|
||||
if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E));
|
||||
if n > 0 do mem_copy(&dst[0], &src[0], n*size_of(E));
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -396,7 +420,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
|
||||
if array == nil do return E{};
|
||||
assert(len(array) > 0);
|
||||
res := array[len(array)-1];
|
||||
(^mem.Raw_Dynamic_Array)(array).len -= 1;
|
||||
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -460,14 +484,11 @@ make :: proc{
|
||||
mem.make_map,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
if m == nil do return;
|
||||
raw_map := (^mem.Raw_Map)(m);
|
||||
entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries);
|
||||
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;
|
||||
@@ -498,11 +519,11 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
if arg_len > 0 {
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
data := (^E)(a.data);
|
||||
assert(data != nil);
|
||||
val := arg;
|
||||
mem.copy(mem.ptr_offset(data, a.len), &val, size_of(E));
|
||||
mem_copy(mem.ptr_offset(data, a.len), &val, size_of(E));
|
||||
a.len += arg_len;
|
||||
}
|
||||
}
|
||||
@@ -520,10 +541,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
if arg_len > 0 {
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
data := (^E)(a.data);
|
||||
assert(data != nil);
|
||||
mem.copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
|
||||
mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
|
||||
a.len += arg_len;
|
||||
}
|
||||
}
|
||||
@@ -540,13 +561,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
|
||||
|
||||
@builtin
|
||||
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
|
||||
if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0;
|
||||
if array != nil do (^Raw_Dynamic_Array)(array).len = 0;
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||
if array == nil do return false;
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
|
||||
if capacity <= a.cap do return true;
|
||||
|
||||
@@ -573,7 +594,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
|
||||
@builtin
|
||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
||||
if array == nil do return false;
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
|
||||
if length <= a.cap {
|
||||
a.len = max(length, 0);
|
||||
@@ -666,11 +687,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
||||
@builtin
|
||||
assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
|
||||
if !condition {
|
||||
p := context.assertion_failure_proc;
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
}
|
||||
p("Runtime assertion", message, loc);
|
||||
proc(message: string, loc: Source_Code_Location) {
|
||||
p := context.assertion_failure_proc;
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
}
|
||||
p("runtime assertion", message, loc);
|
||||
}(message, loc);
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
@@ -681,7 +704,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
}
|
||||
p("Panic", message, loc);
|
||||
p("panic", message, loc);
|
||||
}
|
||||
|
||||
@builtin
|
||||
@@ -711,7 +734,7 @@ unreachable :: proc(message := "", loc := #caller_location) -> ! {
|
||||
|
||||
|
||||
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
array.allocator = context.allocator;
|
||||
assert(array.allocator.procedure != nil);
|
||||
|
||||
@@ -722,7 +745,7 @@ __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, ca
|
||||
}
|
||||
|
||||
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
|
||||
if cap <= array.cap do return true;
|
||||
|
||||
@@ -744,7 +767,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
|
||||
}
|
||||
|
||||
__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
|
||||
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
|
||||
if ok do array.len = len;
|
||||
@@ -754,7 +777,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len:
|
||||
|
||||
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
items: rawptr, item_count: int, loc := #caller_location) -> int {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
|
||||
if items == nil do return 0;
|
||||
if item_count <= 0 do return 0;
|
||||
@@ -771,13 +794,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
assert(array.data != nil);
|
||||
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
||||
|
||||
mem.copy(rawptr(data), items, elem_size * item_count);
|
||||
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 := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
|
||||
ok := true;
|
||||
if array.cap <= array.len+1 {
|
||||
@@ -800,15 +823,14 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
||||
// Map
|
||||
|
||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
header := Map_Header{m = (^mem.Raw_Map)(m)};
|
||||
header := Map_Header{m = (^Raw_Map)(m)};
|
||||
Entry :: struct {
|
||||
key: Map_Key,
|
||||
next: int,
|
||||
value: V,
|
||||
}
|
||||
};
|
||||
|
||||
_, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String);
|
||||
header.is_key_string = is_string;
|
||||
header.is_key_string = intrinsics.type_is_string(K);
|
||||
header.entry_size = int(size_of(Entry));
|
||||
header.entry_align = int(align_of(Entry));
|
||||
header.value_offset = uintptr(offset_of(Entry, value));
|
||||
@@ -819,33 +841,34 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
__get_map_key :: proc "contextless" (k: $K) -> Map_Key {
|
||||
key := k;
|
||||
map_key: Map_Key;
|
||||
ti := type_info_base_without_enum(type_info_of(K));
|
||||
switch _ in ti.variant {
|
||||
case Type_Info_Integer:
|
||||
switch 8*size_of(key) {
|
||||
case 8: map_key.hash = u64(( ^u8)(&key)^);
|
||||
case 16: map_key.hash = u64(( ^u16)(&key)^);
|
||||
case 32: map_key.hash = u64(( ^u32)(&key)^);
|
||||
case 64: map_key.hash = u64(( ^u64)(&key)^);
|
||||
case: panic("Unhandled integer size");
|
||||
}
|
||||
case Type_Info_Rune:
|
||||
|
||||
T :: intrinsics.type_core_type(K);
|
||||
|
||||
when intrinsics.type_is_integer(T) {
|
||||
sz :: 8*size_of(T);
|
||||
when sz == 8 do map_key.hash = u64(( ^u8)(&key)^);
|
||||
else when sz == 16 do map_key.hash = u64((^u16)(&key)^);
|
||||
else when sz == 32 do map_key.hash = u64((^u32)(&key)^);
|
||||
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
|
||||
else do #assert(false, "Unhandled integer size");
|
||||
} else when intrinsics.type_is_rune(T) {
|
||||
map_key.hash = u64((^rune)(&key)^);
|
||||
case Type_Info_Pointer:
|
||||
} else when intrinsics.type_is_pointer(T) {
|
||||
map_key.hash = u64(uintptr((^rawptr)(&key)^));
|
||||
case Type_Info_Float:
|
||||
switch 8*size_of(key) {
|
||||
case 32: map_key.hash = u64((^u32)(&key)^);
|
||||
case 64: map_key.hash = u64((^u64)(&key)^);
|
||||
case: panic("Unhandled float size");
|
||||
}
|
||||
case Type_Info_String:
|
||||
} else when intrinsics.type_is_float(T) {
|
||||
sz :: 8*size_of(T);
|
||||
when sz == 32 do map_key.hash = u64((^u32)(&key)^);
|
||||
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
|
||||
else do #assert(false, "Unhandled float size");
|
||||
} else when intrinsics.type_is_string(T) {
|
||||
#assert(T == string);
|
||||
str := (^string)(&key)^;
|
||||
map_key.hash = default_hash_string(str);
|
||||
map_key.str = str;
|
||||
case:
|
||||
panic("Unhandled map key type");
|
||||
} else {
|
||||
#assert(false, "Unhandled map key type");
|
||||
}
|
||||
|
||||
return map_key;
|
||||
}
|
||||
|
||||
@@ -874,7 +897,7 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
|
||||
|
||||
|
||||
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool {
|
||||
array := (^mem.Raw_Slice)(array_);
|
||||
array := (^Raw_Slice)(array_);
|
||||
|
||||
if new_count < array.len do return true;
|
||||
|
||||
@@ -900,7 +923,7 @@ __dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller
|
||||
}
|
||||
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
|
||||
new_header: Map_Header = header;
|
||||
nm := mem.Raw_Map{};
|
||||
nm := Raw_Map{};
|
||||
nm.entries.allocator = m.entries.allocator;
|
||||
new_header.m = &nm;
|
||||
|
||||
@@ -932,7 +955,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c
|
||||
e := __dynamic_map_get_entry(new_header, j);
|
||||
e.next = fr.entry_index;
|
||||
ndata := uintptr(e);
|
||||
mem.copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
|
||||
mem_copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
|
||||
|
||||
if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
|
||||
}
|
||||
@@ -975,7 +998,7 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #ca
|
||||
e := __dynamic_map_get_entry(h, index);
|
||||
e.key = key;
|
||||
val := (^byte)(uintptr(e) + h.value_offset);
|
||||
mem.copy(val, value, h.value_size);
|
||||
mem_copy(val, value, h.value_size);
|
||||
}
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
@@ -1054,7 +1077,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds
|
||||
} else {
|
||||
old := __dynamic_map_get_entry(h, fr.entry_index);
|
||||
end := __dynamic_map_get_entry(h, m.entries.len-1);
|
||||
mem.copy(old, end, entry_size);
|
||||
mem_copy(old, end, entry_size);
|
||||
|
||||
if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 {
|
||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev);
|
||||
|
||||
+242
-12
@@ -1,9 +1,22 @@
|
||||
package runtime
|
||||
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
if src == nil do return dst;
|
||||
// NOTE(bill): This _must_ be implemented like C's memmove
|
||||
foreign _ {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i64")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i32")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
}
|
||||
}
|
||||
llvm_memmove(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
|
||||
print_u64 :: proc(fd: os.Handle, x: u64) {
|
||||
digits := "0123456789";
|
||||
@@ -243,6 +256,78 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
|
||||
}
|
||||
}
|
||||
|
||||
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
|
||||
x := uintptr(a);
|
||||
y := uintptr(b);
|
||||
n := uintptr(n);
|
||||
|
||||
SU :: size_of(uintptr);
|
||||
fast := uintptr(n/SU + 1);
|
||||
offset := (fast-1)*SU;
|
||||
curr_block := uintptr(0);
|
||||
if n < SU {
|
||||
fast = 0;
|
||||
}
|
||||
|
||||
for /**/; curr_block < fast; curr_block += 1 {
|
||||
va := (^uintptr)(x + curr_block * size_of(uintptr))^;
|
||||
vb := (^uintptr)(y + curr_block * size_of(uintptr))^;
|
||||
if va ~ vb != 0 {
|
||||
for pos := curr_block*SU; pos < n; pos += 1 {
|
||||
a := (^byte)(x+pos)^;
|
||||
b := (^byte)(y+pos)^;
|
||||
if a ~ b != 0 {
|
||||
return (int(a) - int(b)) < 0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; offset < n; offset += 1 {
|
||||
a := (^byte)(x+offset)^;
|
||||
b := (^byte)(y+offset)^;
|
||||
if a ~ b != 0 {
|
||||
return (int(a) - int(b)) < 0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
|
||||
x := uintptr(a);
|
||||
n := uintptr(n);
|
||||
|
||||
SU :: size_of(uintptr);
|
||||
fast := uintptr(n/SU + 1);
|
||||
offset := (fast-1)*SU;
|
||||
curr_block := uintptr(0);
|
||||
if n < SU {
|
||||
fast = 0;
|
||||
}
|
||||
|
||||
for /**/; curr_block < fast; curr_block += 1 {
|
||||
va := (^uintptr)(x + curr_block * size_of(uintptr))^;
|
||||
if va ~ 0 != 0 {
|
||||
for pos := curr_block*SU; pos < n; pos += 1 {
|
||||
a := (^byte)(x+pos)^;
|
||||
if a ~ 0 != 0 {
|
||||
return int(a) < 0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; offset < n; offset += 1 {
|
||||
a := (^byte)(x+offset)^;
|
||||
if a ~ 0 != 0 {
|
||||
return int(a) < 0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string_eq :: proc "contextless" (a, b: string) -> bool {
|
||||
switch {
|
||||
case len(a) != len(b): return false;
|
||||
@@ -253,7 +338,7 @@ string_eq :: proc "contextless" (a, b: string) -> bool {
|
||||
}
|
||||
|
||||
string_cmp :: proc "contextless" (a, b: string) -> int {
|
||||
return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
|
||||
return memory_compare(&a[0], &b[0], min(len(a), len(b)));
|
||||
}
|
||||
|
||||
string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
|
||||
@@ -263,18 +348,23 @@ string_le :: inline proc "contextless" (a, b: string) -> bool { return string_cm
|
||||
string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
|
||||
|
||||
cstring_len :: proc "contextless" (s: cstring) -> int {
|
||||
n := 0;
|
||||
for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) {
|
||||
n += 1;
|
||||
p0 := uintptr((^byte)(s));
|
||||
p := p0;
|
||||
for p != 0 && (^byte)(p)^ != 0 {
|
||||
p += 1;
|
||||
}
|
||||
return n;
|
||||
return int(p - p0);
|
||||
}
|
||||
|
||||
cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
Raw_String :: struct {
|
||||
data: ^byte,
|
||||
len: int,
|
||||
};
|
||||
if s == nil do return "";
|
||||
ptr := (^byte)(s);
|
||||
n := cstring_len(s);
|
||||
return transmute(string)mem.Raw_String{ptr, n};
|
||||
return transmute(string)Raw_String{ptr, n};
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +375,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r
|
||||
complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
|
||||
|
||||
|
||||
quaternion128_eq :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
|
||||
quaternion128_ne :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
|
||||
|
||||
quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
|
||||
quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
|
||||
|
||||
|
||||
bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
|
||||
@@ -358,8 +453,84 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column
|
||||
handle_error(file, line, column, from, to);
|
||||
}
|
||||
|
||||
|
||||
string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
|
||||
return utf8.decode_rune_in_string(s);
|
||||
// NOTE(bill): Duplicated here to remove dependency on package unicode/utf8
|
||||
|
||||
@static accept_sizes := [256]u8{
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
|
||||
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
|
||||
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||
};
|
||||
Accept_Range :: struct {lo, hi: u8};
|
||||
|
||||
@static accept_ranges := [5]Accept_Range{
|
||||
{0x80, 0xbf},
|
||||
{0xa0, 0xbf},
|
||||
{0x80, 0x9f},
|
||||
{0x90, 0xbf},
|
||||
{0x80, 0x8f},
|
||||
};
|
||||
|
||||
MASKX :: 0b0011_1111;
|
||||
MASK2 :: 0b0001_1111;
|
||||
MASK3 :: 0b0000_1111;
|
||||
MASK4 :: 0b0000_0111;
|
||||
|
||||
LOCB :: 0b1000_0000;
|
||||
HICB :: 0b1011_1111;
|
||||
|
||||
|
||||
RUNE_ERROR :: '\ufffd';
|
||||
|
||||
n := len(s);
|
||||
if n < 1 {
|
||||
return RUNE_ERROR, 0;
|
||||
}
|
||||
s0 := s[0];
|
||||
x := accept_sizes[s0];
|
||||
if x >= 0xF0 {
|
||||
mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
|
||||
return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
|
||||
}
|
||||
sz := x & 7;
|
||||
accept := accept_ranges[x>>4];
|
||||
if n < int(sz) {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
b1 := s[1];
|
||||
if b1 < accept.lo || accept.hi < b1 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
if sz == 2 {
|
||||
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
|
||||
}
|
||||
b2 := s[2];
|
||||
if b2 < LOCB || HICB < b2 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
if sz == 3 {
|
||||
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
|
||||
}
|
||||
b3 := s[3];
|
||||
if b3 < LOCB || HICB < b3 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
|
||||
}
|
||||
|
||||
bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
|
||||
@@ -474,9 +645,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
|
||||
r, i := real(x), imag(x);
|
||||
return _sqrt_f64(r*r + i*i);
|
||||
}
|
||||
abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 {
|
||||
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
|
||||
return _sqrt_f32(r*r + i*i + j*j + k*k);
|
||||
}
|
||||
abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 {
|
||||
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
|
||||
return _sqrt_f64(r*r + i*i + j*j + k*k);
|
||||
}
|
||||
|
||||
|
||||
quo_complex64 :: proc(n, m: complex64) -> complex64 {
|
||||
quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 {
|
||||
e, f: f32;
|
||||
|
||||
if abs(real(m)) >= abs(imag(m)) {
|
||||
@@ -494,7 +672,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 {
|
||||
return complex(e, f);
|
||||
}
|
||||
|
||||
quo_complex128 :: proc(n, m: complex128) -> complex128 {
|
||||
quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
|
||||
e, f: f64;
|
||||
|
||||
if abs(real(m)) >= abs(imag(m)) {
|
||||
@@ -511,3 +689,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
|
||||
|
||||
return complex(e, f);
|
||||
}
|
||||
|
||||
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
|
||||
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
|
||||
|
||||
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
|
||||
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
|
||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
|
||||
|
||||
return quaternion(t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
|
||||
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
|
||||
|
||||
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
|
||||
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
|
||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
|
||||
|
||||
return quaternion(t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
|
||||
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
|
||||
|
||||
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
|
||||
|
||||
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
|
||||
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
|
||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
|
||||
|
||||
return quaternion(t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
|
||||
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
|
||||
|
||||
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
|
||||
|
||||
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
|
||||
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
|
||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
|
||||
|
||||
return quaternion(t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,6 +1,7 @@
|
||||
package sort
|
||||
|
||||
import "core:mem"
|
||||
import "intrinsics"
|
||||
|
||||
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil);
|
||||
@@ -26,7 +27,7 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
}
|
||||
}
|
||||
|
||||
bubble_sort :: proc(array: $A/[]$T) {
|
||||
bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
count := len(array);
|
||||
|
||||
init_j, last_j := 0, count-1;
|
||||
@@ -73,7 +74,7 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
quick_sort_proc(a[i:n], f);
|
||||
}
|
||||
|
||||
quick_sort :: proc(array: $A/[]$T) {
|
||||
quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
a := array;
|
||||
n := len(a);
|
||||
if n < 2 do return;
|
||||
@@ -146,7 +147,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
if M & 1 == 0 do copy(arr2, arr1);
|
||||
}
|
||||
|
||||
merge_sort :: proc(array: $A/[]$T) {
|
||||
merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
merge_slices :: proc(arr1, arr2, out: A) {
|
||||
N1, N2 := len(arr1), len(arr2);
|
||||
i, j := 0, 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Multiple precision decimal numbers
|
||||
// NOTE: This is only for floating point printing and nothing else
|
||||
package decimal
|
||||
package strconv_decimal
|
||||
|
||||
Decimal :: struct {
|
||||
digits: [384]byte, // big-endian digits
|
||||
@@ -1,6 +1,6 @@
|
||||
package strconv
|
||||
|
||||
using import "core:decimal"
|
||||
using import "decimal"
|
||||
|
||||
Int_Flag :: enum {
|
||||
Prefix,
|
||||
@@ -105,7 +105,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
|
||||
Buffer :: struct {
|
||||
b: []byte,
|
||||
n: int,
|
||||
}
|
||||
};
|
||||
|
||||
to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
|
||||
add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
|
||||
|
||||
@@ -205,7 +205,11 @@ itoa :: proc(buf: []byte, i: int) -> string {
|
||||
atoi :: proc(s: string) -> int {
|
||||
return parse_int(s);
|
||||
}
|
||||
atof :: proc(s: string) -> f64 {
|
||||
return parse_f64(s);
|
||||
}
|
||||
|
||||
ftoa :: append_float;
|
||||
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ grow_builder :: proc(b: ^Builder, cap: int) {
|
||||
reserve(&b.buf, cap);
|
||||
}
|
||||
|
||||
reset_builder :: proc(b: ^Builder) {
|
||||
clear(&b.buf);
|
||||
}
|
||||
|
||||
builder_from_slice :: proc(backing: []byte) -> Builder {
|
||||
s := transmute(mem.Raw_Slice)backing;
|
||||
d := mem.Raw_Dynamic_Array{
|
||||
|
||||
+147
-3
@@ -155,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
|
||||
return string(b);
|
||||
}
|
||||
|
||||
@private
|
||||
_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string {
|
||||
s, n := s_, n_;
|
||||
|
||||
if n == 0 {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if sep == "" {
|
||||
l := utf8.rune_count_in_string(s);
|
||||
if n < 0 || n > l {
|
||||
n = l;
|
||||
}
|
||||
|
||||
res := make([dynamic]string, n, allocator);
|
||||
for i := 0; i < n-1; i += 1 {
|
||||
_, w := utf8.decode_rune_in_string(s);
|
||||
res[i] = s[:w];
|
||||
s = s[w:];
|
||||
}
|
||||
if n > 0 {
|
||||
res[n-1] = s;
|
||||
}
|
||||
return res[:];
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
n = count(s, sep) + 1;
|
||||
}
|
||||
|
||||
res := make([dynamic]string, n, allocator);
|
||||
|
||||
n -= 1;
|
||||
|
||||
i := 0;
|
||||
for ; i < n; i += 1 {
|
||||
m := index(s, sep);
|
||||
if m < 0 {
|
||||
break;
|
||||
}
|
||||
res[i] = s[:m+sep_save];
|
||||
s = s[m+len(sep):];
|
||||
}
|
||||
res[i] = s;
|
||||
|
||||
return res[:i+1];
|
||||
}
|
||||
|
||||
split :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, 0, -1, allocator);
|
||||
}
|
||||
|
||||
split_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, 0, n, allocator);
|
||||
}
|
||||
|
||||
split_after :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, len(sep), -1, allocator);
|
||||
}
|
||||
|
||||
split_after_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, len(sep), n, allocator);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
index_byte :: proc(s: string, c: byte) -> int {
|
||||
for i := 0; i < len(s); i += 1 {
|
||||
if s[i] == c do return i;
|
||||
@@ -170,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@private PRIME_RABIN_KARP :: 16777619;
|
||||
|
||||
index :: proc(s, substr: string) -> int {
|
||||
hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
|
||||
for i := 0; i < len(s); i += 1 {
|
||||
hash = hash*PRIME_RABIN_KARP + u32(s[i]);
|
||||
}
|
||||
sq := u32(PRIME_RABIN_KARP);
|
||||
for i := len(s); i > 0; i >>= 1 {
|
||||
if (i & 1) != 0 {
|
||||
pow *= sq;
|
||||
}
|
||||
sq *= sq;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n := len(substr);
|
||||
switch {
|
||||
case n == 0:
|
||||
@@ -186,9 +271,68 @@ index :: proc(s, substr: string) -> int {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for i := 0; i < len(s)-n+1; i += 1 {
|
||||
x := s[i:i+n];
|
||||
if x == substr {
|
||||
hash, pow := hash_str_rabin_karp(substr);
|
||||
h: u32;
|
||||
for i := 0; i < n; i += 1 {
|
||||
h = h*PRIME_RABIN_KARP + u32(s[i]);
|
||||
}
|
||||
if h == hash && s[:n] == substr {
|
||||
return 0;
|
||||
}
|
||||
for i := n; i < len(s); /**/ {
|
||||
h *= PRIME_RABIN_KARP;
|
||||
h += u32(s[i]);
|
||||
h -= pow * u32(s[i-n]);
|
||||
i += 1;
|
||||
if h == hash && s[i-n:i] == substr {
|
||||
return i - n;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
last_index :: proc(s, substr: string) -> int {
|
||||
hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
|
||||
for i := len(s) - 1; i >= 0; i -= 1 {
|
||||
hash = hash*PRIME_RABIN_KARP + u32(s[i]);
|
||||
}
|
||||
sq := u32(PRIME_RABIN_KARP);
|
||||
for i := len(s); i > 0; i >>= 1 {
|
||||
if (i & 1) != 0 {
|
||||
pow *= sq;
|
||||
}
|
||||
sq *= sq;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n := len(substr);
|
||||
switch {
|
||||
case n == 0:
|
||||
return len(s);
|
||||
case n == 1:
|
||||
return last_index_byte(s, substr[0]);
|
||||
case n == len(s):
|
||||
return substr == s ? 0 : -1;
|
||||
case n > len(s):
|
||||
return -1;
|
||||
}
|
||||
|
||||
hash, pow := hash_str_rabin_karp_reverse(substr);
|
||||
last := len(s) - n;
|
||||
h: u32;
|
||||
for i := len(s)-1; i >= last; i -= 1 {
|
||||
h = h*PRIME_RABIN_KARP + u32(s[i]);
|
||||
}
|
||||
if h == hash && s[last:] == substr {
|
||||
return last;
|
||||
}
|
||||
|
||||
for i := last-1; i >= 0; i -= 1 {
|
||||
h *= PRIME_RABIN_KARP;
|
||||
h += u32(s[i]);
|
||||
h -= pow * u32(s[i+n]);
|
||||
if h == hash && s[i:i+n] == substr {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ foreign kernel32 {
|
||||
@(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---;
|
||||
@(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---;
|
||||
|
||||
@(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
|
||||
@(link_name="Sleep") sleep :: proc(ms: u32) ---;
|
||||
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: cstring) ---;
|
||||
|
||||
@@ -182,7 +182,7 @@ foreign user32 {
|
||||
@(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---;
|
||||
|
||||
@(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
|
||||
@(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
|
||||
@(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: Wstring) -> Hcursor ---;
|
||||
@(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---;
|
||||
@(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---;
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
package time
|
||||
IS_SUPPORTED :: false;
|
||||
@@ -20,5 +20,5 @@ now :: proc() -> Time {
|
||||
|
||||
|
||||
sleep :: proc(d: Duration) {
|
||||
win32.sleep(i32(d/Millisecond));
|
||||
win32.sleep(u32(d/Millisecond));
|
||||
}
|
||||
|
||||
+60
-17
@@ -41,23 +41,17 @@ accept_ranges := [5]Accept_Range{
|
||||
};
|
||||
|
||||
accept_sizes := [256]u8{
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
|
||||
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
|
||||
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||
0x00..0x7f = 0xf0,
|
||||
0x80..0xc1 = 0xf1,
|
||||
0xc2..0xdf = 0x02,
|
||||
0xe0 = 0x13,
|
||||
0xe1..0xec = 0x03,
|
||||
0xed = 0x23,
|
||||
0xee..0xef = 0x03,
|
||||
0xf0 = 0x34,
|
||||
0xf1..0xf3 = 0x04,
|
||||
0xf4 = 0x44,
|
||||
0xf5..0xff = 0xf1,
|
||||
};
|
||||
|
||||
encode_rune :: proc(c: rune) -> ([4]u8, int) {
|
||||
@@ -167,9 +161,58 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
||||
return r, size;
|
||||
}
|
||||
|
||||
rune_at_pos :: proc(s: string, pos: int) -> rune {
|
||||
if pos < 0 {
|
||||
return RUNE_ERROR;
|
||||
}
|
||||
|
||||
i := 0;
|
||||
for r in s {
|
||||
if i == pos {
|
||||
return r;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return RUNE_ERROR;
|
||||
}
|
||||
|
||||
rune_string_at_pos :: proc(s: string, pos: int) -> string {
|
||||
if pos < 0 {
|
||||
return "";
|
||||
}
|
||||
|
||||
i := 0;
|
||||
for c, offset in s {
|
||||
if i == pos {
|
||||
w := rune_size(c);
|
||||
return s[offset:][:w];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
rune_at :: proc(s: string, byte_index: int) -> rune {
|
||||
r, _ := decode_rune_in_string(s[byte_index:]);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Returns the byte position of rune at position pos in s with an optional start byte position.
|
||||
// Returns -1 if it runs out of the string.
|
||||
rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
|
||||
if pos < 0 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
i := 0;
|
||||
for _, offset in s[start:] {
|
||||
if i == pos {
|
||||
return offset+start;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
valid_rune :: proc(r: rune) -> bool {
|
||||
if r < 0 {
|
||||
|
||||
Reference in New Issue
Block a user