Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Chris Heyes
2019-11-01 19:18:33 +00:00
84 changed files with 10335 additions and 2865 deletions
+105
View File
@@ -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 ---
+2
View File
@@ -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;
+93
View File
@@ -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;
}
+3 -3
View File
@@ -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;
}
+3 -3
View File
@@ -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 -6
View File
@@ -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
View File
@@ -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, ')');
}
}
}
+126
View File
@@ -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) ---
+16 -16
View File
@@ -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
View File
@@ -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);
}
+283
View File
@@ -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
View File
@@ -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;
+2 -2
View File
@@ -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;
}
-2
View File
@@ -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 {
+6
View File
@@ -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
View File
@@ -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 -2
View File
@@ -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;
+2 -2
View File
@@ -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,
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;
+79 -79
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -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;
}
+1 -1
View File
@@ -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);
}
}
+396
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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) {
+4
View File
@@ -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));
}
+4
View File
@@ -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
View File
@@ -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;
}
}
-24
View File
@@ -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)
}
}
+1 -1
View File
@@ -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) ---;
+1 -1
View File
@@ -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 ---;
+2
View File
@@ -0,0 +1,2 @@
package time
IS_SUPPORTED :: false;
+1 -1
View File
@@ -20,5 +20,5 @@ now :: proc() -> Time {
sleep :: proc(d: Duration) {
win32.sleep(i32(d/Millisecond));
win32.sleep(u32(d/Millisecond));
}
+60 -17
View File
@@ -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 {