Merge branch 'master' into separate-int-word-sizes

This commit is contained in:
gingerBill
2023-06-06 22:42:04 +01:00
147 changed files with 19917 additions and 10151 deletions
+8 -1
View File
@@ -135,7 +135,14 @@ build_odin() {
EXTRAFLAGS="-O3" EXTRAFLAGS="-O3"
;; ;;
release-native) release-native)
EXTRAFLAGS="-O3 -march=native" local ARCH=$(uname -m)
if [ "${ARCH}" == "arm64" ]; then
# Use preferred flag for Arm (ie arm64 / aarch64 / etc)
EXTRAFLAGS="-O3 -mcpu=native"
else
# Use preferred flag for x86 / amd64
EXTRAFLAGS="-O3 -march=native"
fi
;; ;;
nightly) nightly)
EXTRAFLAGS="-DNIGHTLY -O3" EXTRAFLAGS="-DNIGHTLY -O3"
+4 -8
View File
@@ -177,12 +177,10 @@ decompress_slice_to_string :: proc(input: []u8, model := DEFAULT_MODEL, allocato
max_output_size := decompress_bound(len(input), model) max_output_size := decompress_bound(len(input), model)
buf: [dynamic]u8 buf: [dynamic]u8
if !resize(&buf, max_output_size) { resize(&buf, max_output_size) or_return
return "", .Out_Of_Memory
}
length, result := decompress_slice_to_output_buffer(input, buf[:]) length, result := decompress_slice_to_output_buffer(input, buf[:])
resize(&buf, length) resize(&buf, length) or_return
return string(buf[:]), result return string(buf[:]), result
} }
decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string} decompress :: proc{decompress_slice_to_output_buffer, decompress_slice_to_string}
@@ -307,12 +305,10 @@ compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := cont
max_output_size := compress_bound(len(input)) max_output_size := compress_bound(len(input))
buf: [dynamic]u8 buf: [dynamic]u8
if !resize(&buf, max_output_size) { resize(&buf, max_output_size) or_return
return {}, .Out_Of_Memory
}
length, result := compress_string_to_buffer(input, buf[:]) length, result := compress_string_to_buffer(input, buf[:])
resize(&buf, length) resize(&buf, length) or_return
return buf[:length], result return buf[:length], result
} }
compress :: proc{compress_string_to_buffer, compress_string} compress :: proc{compress_string_to_buffer, compress_string}
+11 -11
View File
@@ -14,7 +14,7 @@ Queue :: struct($T: typeid) {
DEFAULT_CAPACITY :: 16 DEFAULT_CAPACITY :: 16
// Procedure to initialize a queue // Procedure to initialize a queue
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> bool { init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> runtime.Allocator_Error {
if q.data.allocator.procedure == nil { if q.data.allocator.procedure == nil {
q.data.allocator = allocator q.data.allocator = allocator
} }
@@ -55,11 +55,11 @@ space :: proc(q: $Q/Queue($T)) -> int {
} }
// Reserve enough space for at least the specified capacity // Reserve enough space for at least the specified capacity
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> bool { reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error {
if uint(capacity) > q.len { if uint(capacity) > q.len {
return _grow(q, uint(capacity)) return _grow(q, uint(capacity))
} }
return true return nil
} }
@@ -112,25 +112,25 @@ peek_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
} }
// Push an element to the back of the queue // Push an element to the back of the queue
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool { push_back :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) {
if space(q^) == 0 { if space(q^) == 0 {
_grow(q) or_return _grow(q) or_return
} }
idx := (q.offset+uint(q.len))%builtin.len(q.data) idx := (q.offset+uint(q.len))%builtin.len(q.data)
q.data[idx] = elem q.data[idx] = elem
q.len += 1 q.len += 1
return true return true, nil
} }
// Push an element to the front of the queue // Push an element to the front of the queue
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> bool { push_front :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) {
if space(q^) == 0 { if space(q^) == 0 {
_grow(q) or_return _grow(q) or_return
} }
q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data) q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data)
q.len += 1 q.len += 1
q.data[q.offset] = elem q.data[q.offset] = elem
return true return true, nil
} }
@@ -173,7 +173,7 @@ pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
} }
// Push multiple elements to the front of the queue // Push multiple elements to the front of the queue
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool { push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime.Allocator_Error) {
n := uint(builtin.len(elems)) n := uint(builtin.len(elems))
if space(q^) < int(n) { if space(q^) < int(n) {
_grow(q, q.len + n) or_return _grow(q, q.len + n) or_return
@@ -188,7 +188,7 @@ push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool {
copy(q.data[insert_from:], elems[:insert_to]) copy(q.data[insert_from:], elems[:insert_to])
copy(q.data[:insert_from], elems[insert_to:]) copy(q.data[:insert_from], elems[insert_to:])
q.len += n q.len += n
return true return true, nil
} }
// Consume `n` elements from the front of the queue // Consume `n` elements from the front of the queue
@@ -225,7 +225,7 @@ clear :: proc(q: ^$Q/Queue($T)) {
// Internal growinh procedure // Internal growinh procedure
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool { _grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> runtime.Allocator_Error {
new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2) new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2)
n := uint(builtin.len(q.data)) n := uint(builtin.len(q.data))
builtin.resize(&q.data, int(new_capacity)) or_return builtin.resize(&q.data, int(new_capacity)) or_return
@@ -234,5 +234,5 @@ _grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool {
copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff]) copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
q.offset += new_capacity - n q.offset += new_capacity - n
} }
return true return nil
} }
+2 -2
View File
@@ -165,8 +165,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
case runtime.Type_Info_String: case runtime.Type_Info_String:
switch s in a { switch s in a {
case string: io.write_quoted_string(w, s) or_return case string: io.write_quoted_string(w, s, '"', nil, true) or_return
case cstring: io.write_quoted_string(w, string(s)) or_return case cstring: io.write_quoted_string(w, string(s), '"', nil, true) or_return
} }
case runtime.Type_Info_Boolean: case runtime.Type_Info_Boolean:
+10 -1
View File
@@ -2,6 +2,7 @@ package json
import "core:mem" import "core:mem"
import "core:unicode/utf8" import "core:unicode/utf8"
import "core:unicode/utf16"
import "core:strconv" import "core:strconv"
Parser :: struct { Parser :: struct {
@@ -403,11 +404,19 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
} }
i += 6 i += 6
// If this is a surrogate pair, decode as such by taking the next rune too.
if r >= utf8.SURROGATE_MIN && r <= utf8.SURROGATE_HIGH_MAX && len(s) > i + 2 && s[i:i+2] == "\\u" {
r2 := get_u4_rune(s[i:])
if r2 >= utf8.SURROGATE_LOW_MIN && r2 <= utf8.SURROGATE_MAX {
i += 6
r = utf16.decode_surrogate_pair(r, r2)
}
}
buf, buf_width := utf8.encode_rune(r) buf, buf_width := utf8.encode_rune(r)
copy(b[w:], buf[:buf_width]) copy(b[w:], buf[:buf_width])
w += buf_width w += buf_width
case '0': case '0':
if spec != .JSON { if spec != .JSON {
b[w] = '\x00' b[w] = '\x00'
+20 -17
View File
@@ -1961,11 +1961,22 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
switch a in v { switch a in v {
case runtime.Source_Code_Location: case runtime.Source_Code_Location:
io.write_string(fi.writer, a.file_path, &fi.n) io.write_string(fi.writer, a.file_path, &fi.n)
io.write_byte(fi.writer, '(', &fi.n)
io.write_int(fi.writer, int(a.line), 10, &fi.n) when ODIN_ERROR_POS_STYLE == .Default {
io.write_byte(fi.writer, ':', &fi.n) io.write_byte(fi.writer, '(', &fi.n)
io.write_int(fi.writer, int(a.column), 10, &fi.n) io.write_int(fi.writer, int(a.line), 10, &fi.n)
io.write_byte(fi.writer, ')', &fi.n) io.write_byte(fi.writer, ':', &fi.n)
io.write_int(fi.writer, int(a.column), 10, &fi.n)
io.write_byte(fi.writer, ')', &fi.n)
} else when ODIN_ERROR_POS_STYLE == .Unix {
io.write_byte(fi.writer, ':', &fi.n)
io.write_int(fi.writer, int(a.line), 10, &fi.n)
io.write_byte(fi.writer, ':', &fi.n)
io.write_int(fi.writer, int(a.column), 10, &fi.n)
io.write_byte(fi.writer, ':', &fi.n)
} else {
#panic("Unhandled ODIN_ERROR_POS_STYLE")
}
return return
case time.Duration: case time.Duration:
@@ -2647,18 +2658,10 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
} }
} }
arg_info := type_info_of(arg.id)
custom_types: switch a in arg { if info, ok := arg_info.variant.(runtime.Type_Info_Named); ok {
case runtime.Source_Code_Location: fmt_named(fi, arg, verb, info)
if fi.hash && verb == 'v' { return
io.write_string(fi.writer, a.file_path, &fi.n)
io.write_byte(fi.writer, '(', &fi.n)
io.write_i64(fi.writer, i64(a.line), 10, &fi.n)
io.write_byte(fi.writer, ':', &fi.n)
io.write_i64(fi.writer, i64(a.column), 10, &fi.n)
io.write_byte(fi.writer, ')', &fi.n)
return
}
} }
base_arg := arg base_arg := arg
+1 -1
View File
@@ -7,7 +7,7 @@ foreign import "odin_env"
@(private="file") @(private="file")
foreign odin_env { foreign odin_env {
write :: proc "c" (fd: u32, p: []byte) --- write :: proc "contextless" (fd: u32, p: []byte) ---
} }
@(private="file") @(private="file")
+5 -5
View File
@@ -634,7 +634,7 @@ alpha_add_if_missing :: proc(img: ^Image, alpha_key := Alpha_Key{}, allocator :=
buf := bytes.Buffer{} buf := bytes.Buffer{}
// Can we allocate the return buffer? // Can we allocate the return buffer?
if !resize(&buf.buf, bytes_wanted) { if resize(&buf.buf, bytes_wanted) != nil {
delete(buf.buf) delete(buf.buf)
return false return false
} }
@@ -826,7 +826,7 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al
buf := bytes.Buffer{} buf := bytes.Buffer{}
// Can we allocate the return buffer? // Can we allocate the return buffer?
if !resize(&buf.buf, bytes_wanted) { if resize(&buf.buf, bytes_wanted) != nil {
delete(buf.buf) delete(buf.buf)
return false return false
} }
@@ -1075,7 +1075,7 @@ apply_palette_rgb :: proc(img: ^Image, palette: [256]RGB_Pixel, allocator := con
// Can we allocate the return buffer? // Can we allocate the return buffer?
buf := bytes.Buffer{} buf := bytes.Buffer{}
bytes_wanted := compute_buffer_size(img.width, img.height, 3, 8) bytes_wanted := compute_buffer_size(img.width, img.height, 3, 8)
if !resize(&buf.buf, bytes_wanted) { if resize(&buf.buf, bytes_wanted) != nil {
delete(buf.buf) delete(buf.buf)
return false return false
} }
@@ -1112,7 +1112,7 @@ apply_palette_rgba :: proc(img: ^Image, palette: [256]RGBA_Pixel, allocator := c
// Can we allocate the return buffer? // Can we allocate the return buffer?
buf := bytes.Buffer{} buf := bytes.Buffer{}
bytes_wanted := compute_buffer_size(img.width, img.height, 4, 8) bytes_wanted := compute_buffer_size(img.width, img.height, 4, 8)
if !resize(&buf.buf, bytes_wanted) { if resize(&buf.buf, bytes_wanted) != nil {
delete(buf.buf) delete(buf.buf)
return false return false
} }
@@ -1147,7 +1147,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
// Can we allocate the return buffer? // Can we allocate the return buffer?
buf := bytes.Buffer{} buf := bytes.Buffer{}
bytes_wanted := compute_buffer_size(img.width, img.height, img.channels + 2, img.depth) bytes_wanted := compute_buffer_size(img.width, img.height, img.channels + 2, img.depth)
if !resize(&buf.buf, bytes_wanted) { if resize(&buf.buf, bytes_wanted) != nil {
delete(buf.buf) delete(buf.buf)
return false return false
} }
+5 -5
View File
@@ -731,7 +731,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
// We need to create a new image buffer // We need to create a new image buffer
dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8) dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
t := bytes.Buffer{} t := bytes.Buffer{}
if !resize(&t.buf, dest_raw_size) { if resize(&t.buf, dest_raw_size) != nil {
return {}, .Unable_To_Allocate_Or_Resize return {}, .Unable_To_Allocate_Or_Resize
} }
@@ -812,7 +812,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
// We need to create a new image buffer // We need to create a new image buffer
dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 16) dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 16)
t := bytes.Buffer{} t := bytes.Buffer{}
if !resize(&t.buf, dest_raw_size) { if resize(&t.buf, dest_raw_size) != nil {
return {}, .Unable_To_Allocate_Or_Resize return {}, .Unable_To_Allocate_Or_Resize
} }
@@ -1011,7 +1011,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
// We need to create a new image buffer // We need to create a new image buffer
dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8) dest_raw_size := compute_buffer_size(int(header.width), int(header.height), out_image_channels, 8)
t := bytes.Buffer{} t := bytes.Buffer{}
if !resize(&t.buf, dest_raw_size) { if resize(&t.buf, dest_raw_size) != nil {
return {}, .Unable_To_Allocate_Or_Resize return {}, .Unable_To_Allocate_Or_Resize
} }
@@ -1522,7 +1522,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
bytes_per_channel := depth == 16 ? 2 : 1 bytes_per_channel := depth == 16 ? 2 : 1
num_bytes := compute_buffer_size(width, height, channels, depth == 16 ? 16 : 8) num_bytes := compute_buffer_size(width, height, channels, depth == 16 ? 16 : 8)
if !resize(&img.pixels.buf, num_bytes) { if resize(&img.pixels.buf, num_bytes) != nil {
return .Unable_To_Allocate_Or_Resize return .Unable_To_Allocate_Or_Resize
} }
@@ -1564,7 +1564,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
if x > 0 && y > 0 { if x > 0 && y > 0 {
temp: bytes.Buffer temp: bytes.Buffer
temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8) temp_len := compute_buffer_size(x, y, channels, depth == 16 ? 16 : 8)
if !resize(&temp.buf, temp_len) { if resize(&temp.buf, temp_len) != nil {
return .Unable_To_Allocate_Or_Resize return .Unable_To_Allocate_Or_Resize
} }
+2 -2
View File
@@ -53,7 +53,7 @@ save_to_buffer :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
// Calculate and allocate maximum size. We'll reclaim space to actually written output at the end. // Calculate and allocate maximum size. We'll reclaim space to actually written output at the end.
max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be) max_size := pixels * (img.channels + 1) + size_of(image.QOI_Header) + size_of(u64be)
if !resize(&output.buf, max_size) { if resize(&output.buf, max_size) != nil {
return .Unable_To_Allocate_Or_Resize return .Unable_To_Allocate_Or_Resize
} }
@@ -233,7 +233,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8) bytes_needed := image.compute_buffer_size(int(header.width), int(header.height), img.channels, 8)
if !resize(&img.pixels.buf, bytes_needed) { if resize(&img.pixels.buf, bytes_needed) != nil {
return img, .Unable_To_Allocate_Or_Resize return img, .Unable_To_Allocate_Or_Resize
} }
+2 -2
View File
@@ -57,7 +57,7 @@ save_to_buffer :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
// Calculate and allocate necessary space. // Calculate and allocate necessary space.
necessary := pixels * img.channels + size_of(image.TGA_Header) necessary := pixels * img.channels + size_of(image.TGA_Header)
if !resize(&output.buf, necessary) { if resize(&output.buf, necessary) != nil {
return .Unable_To_Allocate_Or_Resize return .Unable_To_Allocate_Or_Resize
} }
@@ -292,7 +292,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
return img, nil return img, nil
} }
if !resize(&img.pixels.buf, dest_channels * img.width * img.height) { if resize(&img.pixels.buf, dest_channels * img.width * img.height) != nil {
return img, .Unable_To_Allocate_Or_Resize return img, .Unable_To_Allocate_Or_Resize
} }
+1
View File
@@ -192,6 +192,7 @@ type_map_info :: proc($T: typeid/map[$K]$V) -> ^runtime.Map_Info ---
type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info --- type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info ---
type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
+20 -7
View File
@@ -2,6 +2,7 @@ package io
import "core:strconv" import "core:strconv"
import "core:unicode/utf8" import "core:unicode/utf8"
import "core:unicode/utf16"
read_ptr :: proc(r: Reader, p: rawptr, byte_size: int, n_read: ^int = nil) -> (n: int, err: Error) { read_ptr :: proc(r: Reader, p: rawptr, byte_size: int, n_read: ^int = nil) -> (n: int, err: Error) {
return read(r, ([^]byte)(p)[:byte_size], n_read) return read(r, ([^]byte)(p)[:byte_size], n_read)
@@ -146,7 +147,7 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^
return return
} }
write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false, n_written: ^int = nil) -> (n: int, err: Error) { write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false, n_written: ^int = nil, for_json := false) -> (n: int, err: Error) {
is_printable :: proc(r: rune) -> bool { is_printable :: proc(r: rune) -> bool {
if r <= 0xff { if r <= 0xff {
switch r { switch r {
@@ -211,17 +212,29 @@ write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false,
write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
} }
case: case:
write_byte(w, '\\', &n) or_return if for_json {
write_byte(w, 'U', &n) or_return buf: [2]u16
for s := 28; s >= 0; s -= 4 { utf16.encode(buf[:], []rune{c})
write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return for bc in buf {
write_byte(w, '\\', &n) or_return
write_byte(w, 'u', &n) or_return
for s := 12; s >= 0; s -= 4 {
write_byte(w, DIGITS_LOWER[bc>>uint(s) & 0xf], &n) or_return
}
}
} else {
write_byte(w, '\\', &n) or_return
write_byte(w, 'U', &n) or_return
for s := 24; s >= 0; s -= 4 {
write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
}
} }
} }
} }
return return
} }
write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written: ^int = nil) -> (n: int, err: Error) { write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written: ^int = nil, for_json := false) -> (n: int, err: Error) {
defer if n_written != nil { defer if n_written != nil {
n_written^ += n n_written^ += n
} }
@@ -240,7 +253,7 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written
continue continue
} }
n_wrapper(write_escaped_rune(w, r, quote), &n) or_return n_wrapper(write_escaped_rune(w, r, quote, false, nil, for_json), &n) or_return
} }
write_byte(w, quote, &n) or_return write_byte(w, quote, &n) or_return
+154 -77
View File
@@ -37,68 +37,96 @@ overflowing_sub :: intrinsics.overflow_sub
overflowing_mul :: intrinsics.overflow_mul overflowing_mul :: intrinsics.overflow_mul
log2 :: proc(x: $T) -> T where intrinsics.type_is_integer(T), intrinsics.type_is_unsigned(T) { @(require_results)
log2 :: proc "contextless" (x: $T) -> T where intrinsics.type_is_integer(T), intrinsics.type_is_unsigned(T) {
return (8*size_of(T)-1) - count_leading_zeros(x) return (8*size_of(T)-1) - count_leading_zeros(x)
} }
rotate_left8 :: proc(x: u8, k: int) -> u8 { @(require_results)
rotate_left8 :: proc "contextless" (x: u8, k: int) -> u8 {
n :: 8 n :: 8
s := uint(k) & (n-1) s := uint(k) & (n-1)
return x <<s | x>>(n-s) return x <<s | x>>(n-s)
} }
rotate_left16 :: proc(x: u16, k: int) -> u16 { @(require_results)
rotate_left16 :: proc "contextless" (x: u16, k: int) -> u16 {
n :: 16 n :: 16
s := uint(k) & (n-1) s := uint(k) & (n-1)
return x <<s | x>>(n-s) return x <<s | x>>(n-s)
} }
rotate_left32 :: proc(x: u32, k: int) -> u32 { @(require_results)
rotate_left32 :: proc "contextless" (x: u32, k: int) -> u32 {
n :: 32 n :: 32
s := uint(k) & (n-1) s := uint(k) & (n-1)
return x <<s | x>>(n-s) return x <<s | x>>(n-s)
} }
rotate_left64 :: proc(x: u64, k: int) -> u64 { @(require_results)
rotate_left64 :: proc "contextless" (x: u64, k: int) -> u64 {
n :: 64 n :: 64
s := uint(k) & (n-1) s := uint(k) & (n-1)
return x <<s | x>>(n-s) return x <<s | x>>(n-s)
} }
rotate_left :: proc(x: uint, k: int) -> uint { @(require_results)
rotate_left :: proc "contextless" (x: uint, k: int) -> uint {
n :: 8*size_of(uint) n :: 8*size_of(uint)
s := uint(k) & (n-1) s := uint(k) & (n-1)
return x <<s | x>>(n-s) return x <<s | x>>(n-s)
} }
from_be_u8 :: proc(i: u8) -> u8 { return i } @(require_results)
from_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } from_be_u8 :: proc "contextless" (i: u8) -> u8 { return i }
from_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } @(require_results)
from_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } from_be_u16 :: proc "contextless" (i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } @(require_results)
from_be_u32 :: proc "contextless" (i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
@(require_results)
from_be_u64 :: proc "contextless" (i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
@(require_results)
from_be_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
from_le_u8 :: proc(i: u8) -> u8 { return i } @(require_results)
from_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } from_le_u8 :: proc "contextless" (i: u8) -> u8 { return i }
from_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } @(require_results)
from_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } from_le_u16 :: proc "contextless" (i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } @(require_results)
from_le_u32 :: proc "contextless" (i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
@(require_results)
from_le_u64 :: proc "contextless" (i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
@(require_results)
from_le_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
to_be_u8 :: proc(i: u8) -> u8 { return i } @(require_results)
to_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } to_be_u8 :: proc "contextless" (i: u8) -> u8 { return i }
to_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } @(require_results)
to_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } to_be_u16 :: proc "contextless" (i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } @(require_results)
to_be_u32 :: proc "contextless" (i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
@(require_results)
to_be_u64 :: proc "contextless" (i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
@(require_results)
to_be_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
to_le_u8 :: proc(i: u8) -> u8 { return i } @(require_results)
to_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } to_le_u8 :: proc "contextless" (i: u8) -> u8 { return i }
to_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } @(require_results)
to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } to_le_u16 :: proc "contextless" (i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } @(require_results)
to_le_u32 :: proc "contextless" (i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
@(require_results)
to_le_u64 :: proc "contextless" (i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
@(require_results)
to_le_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
len_u8 :: proc(x: u8) -> int { @(require_results)
len_u8 :: proc "contextless" (x: u8) -> int {
return int(len_u8_table[x]) return int(len_u8_table[x])
} }
len_u16 :: proc(x: u16) -> (n: int) { @(require_results)
len_u16 :: proc "contextless" (x: u16) -> (n: int) {
x := x x := x
if x >= 1<<8 { if x >= 1<<8 {
x >>= 8 x >>= 8
@@ -106,7 +134,8 @@ len_u16 :: proc(x: u16) -> (n: int) {
} }
return n + int(len_u8_table[x]) return n + int(len_u8_table[x])
} }
len_u32 :: proc(x: u32) -> (n: int) { @(require_results)
len_u32 :: proc "contextless" (x: u32) -> (n: int) {
x := x x := x
if x >= 1<<16 { if x >= 1<<16 {
x >>= 16 x >>= 16
@@ -118,7 +147,8 @@ len_u32 :: proc(x: u32) -> (n: int) {
} }
return n + int(len_u8_table[x]) return n + int(len_u8_table[x])
} }
len_u64 :: proc(x: u64) -> (n: int) { @(require_results)
len_u64 :: proc "contextless" (x: u64) -> (n: int) {
x := x x := x
if x >= 1<<32 { if x >= 1<<32 {
x >>= 32 x >>= 32
@@ -134,7 +164,8 @@ len_u64 :: proc(x: u64) -> (n: int) {
} }
return n + int(len_u8_table[x]) return n + int(len_u8_table[x])
} }
len_uint :: proc(x: uint) -> (n: int) { @(require_results)
len_uint :: proc "contextless" (x: uint) -> (n: int) {
when size_of(uint) == size_of(u64) { when size_of(uint) == size_of(u64) {
return len_u64(u64(x)) return len_u64(u64(x))
} else { } else {
@@ -146,21 +177,24 @@ len_uint :: proc(x: uint) -> (n: int) {
len :: proc{len_u8, len_u16, len_u32, len_u64, len_uint} len :: proc{len_u8, len_u16, len_u32, len_u64, len_uint}
add_u32 :: proc(x, y, carry: u32) -> (sum, carry_out: u32) { @(require_results)
add_u32 :: proc "contextless" (x, y, carry: u32) -> (sum, carry_out: u32) {
tmp_carry, tmp_carry2: bool tmp_carry, tmp_carry2: bool
sum, tmp_carry = intrinsics.overflow_add(x, y) sum, tmp_carry = intrinsics.overflow_add(x, y)
sum, tmp_carry2 = intrinsics.overflow_add(sum, carry) sum, tmp_carry2 = intrinsics.overflow_add(sum, carry)
carry_out = u32(tmp_carry | tmp_carry2) carry_out = u32(tmp_carry | tmp_carry2)
return return
} }
add_u64 :: proc(x, y, carry: u64) -> (sum, carry_out: u64) { @(require_results)
add_u64 :: proc "contextless" (x, y, carry: u64) -> (sum, carry_out: u64) {
tmp_carry, tmp_carry2: bool tmp_carry, tmp_carry2: bool
sum, tmp_carry = intrinsics.overflow_add(x, y) sum, tmp_carry = intrinsics.overflow_add(x, y)
sum, tmp_carry2 = intrinsics.overflow_add(sum, carry) sum, tmp_carry2 = intrinsics.overflow_add(sum, carry)
carry_out = u64(tmp_carry | tmp_carry2) carry_out = u64(tmp_carry | tmp_carry2)
return return
} }
add_uint :: proc(x, y, carry: uint) -> (sum, carry_out: uint) { @(require_results)
add_uint :: proc "contextless" (x, y, carry: uint) -> (sum, carry_out: uint) {
when size_of(uint) == size_of(u64) { when size_of(uint) == size_of(u64) {
a, b := add_u64(u64(x), u64(y), u64(carry)) a, b := add_u64(u64(x), u64(y), u64(carry))
} else { } else {
@@ -172,21 +206,24 @@ add_uint :: proc(x, y, carry: uint) -> (sum, carry_out: uint) {
add :: proc{add_u32, add_u64, add_uint} add :: proc{add_u32, add_u64, add_uint}
sub_u32 :: proc(x, y, borrow: u32) -> (diff, borrow_out: u32) { @(require_results)
sub_u32 :: proc "contextless" (x, y, borrow: u32) -> (diff, borrow_out: u32) {
tmp_borrow, tmp_borrow2: bool tmp_borrow, tmp_borrow2: bool
diff, tmp_borrow = intrinsics.overflow_sub(x, y) diff, tmp_borrow = intrinsics.overflow_sub(x, y)
diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow) diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow)
borrow_out = u32(tmp_borrow | tmp_borrow2) borrow_out = u32(tmp_borrow | tmp_borrow2)
return return
} }
sub_u64 :: proc(x, y, borrow: u64) -> (diff, borrow_out: u64) { @(require_results)
sub_u64 :: proc "contextless" (x, y, borrow: u64) -> (diff, borrow_out: u64) {
tmp_borrow, tmp_borrow2: bool tmp_borrow, tmp_borrow2: bool
diff, tmp_borrow = intrinsics.overflow_sub(x, y) diff, tmp_borrow = intrinsics.overflow_sub(x, y)
diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow) diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow)
borrow_out = u64(tmp_borrow | tmp_borrow2) borrow_out = u64(tmp_borrow | tmp_borrow2)
return return
} }
sub_uint :: proc(x, y, borrow: uint) -> (diff, borrow_out: uint) { @(require_results)
sub_uint :: proc "contextless" (x, y, borrow: uint) -> (diff, borrow_out: uint) {
when size_of(uint) == size_of(u64) { when size_of(uint) == size_of(u64) {
a, b := sub_u64(u64(x), u64(y), u64(borrow)) a, b := sub_u64(u64(x), u64(y), u64(borrow))
} else { } else {
@@ -198,18 +235,21 @@ sub_uint :: proc(x, y, borrow: uint) -> (diff, borrow_out: uint) {
sub :: proc{sub_u32, sub_u64, sub_uint} sub :: proc{sub_u32, sub_u64, sub_uint}
mul_u32 :: proc(x, y: u32) -> (hi, lo: u32) { @(require_results)
mul_u32 :: proc "contextless" (x, y: u32) -> (hi, lo: u32) {
z := u64(x) * u64(y) z := u64(x) * u64(y)
hi, lo = u32(z>>32), u32(z) hi, lo = u32(z>>32), u32(z)
return return
} }
mul_u64 :: proc(x, y: u64) -> (hi, lo: u64) { @(require_results)
mul_u64 :: proc "contextless" (x, y: u64) -> (hi, lo: u64) {
prod_wide := u128(x) * u128(y) prod_wide := u128(x) * u128(y)
hi, lo = u64(prod_wide>>64), u64(prod_wide) hi, lo = u64(prod_wide>>64), u64(prod_wide)
return return
} }
mul_uint :: proc(x, y: uint) -> (hi, lo: uint) { @(require_results)
mul_uint :: proc "contextless" (x, y: uint) -> (hi, lo: uint) {
when size_of(uint) == size_of(u32) { when size_of(uint) == size_of(u32) {
a, b := mul_u32(u32(x), u32(y)) a, b := mul_u32(u32(x), u32(y))
} else { } else {
@@ -222,13 +262,15 @@ mul_uint :: proc(x, y: uint) -> (hi, lo: uint) {
mul :: proc{mul_u32, mul_u64, mul_uint} mul :: proc{mul_u32, mul_u64, mul_uint}
div_u32 :: proc(hi, lo, y: u32) -> (quo, rem: u32) { @(require_results)
div_u32 :: proc "odin" (hi, lo, y: u32) -> (quo, rem: u32) {
assert(y != 0 && y <= hi) assert(y != 0 && y <= hi)
z := u64(hi)<<32 | u64(lo) z := u64(hi)<<32 | u64(lo)
quo, rem = u32(z/u64(y)), u32(z%u64(y)) quo, rem = u32(z/u64(y)), u32(z%u64(y))
return return
} }
div_u64 :: proc(hi, lo, y: u64) -> (quo, rem: u64) { @(require_results)
div_u64 :: proc "odin" (hi, lo, y: u64) -> (quo, rem: u64) {
y := y y := y
two32 :: 1 << 32 two32 :: 1 << 32
mask32 :: two32 - 1 mask32 :: two32 - 1
@@ -273,7 +315,8 @@ div_u64 :: proc(hi, lo, y: u64) -> (quo, rem: u64) {
return q1*two32 + q0, (un21*two32 + un0 - q0*y) >> s return q1*two32 + q0, (un21*two32 + un0 - q0*y) >> s
} }
div_uint :: proc(hi, lo, y: uint) -> (quo, rem: uint) { @(require_results)
div_uint :: proc "odin" (hi, lo, y: uint) -> (quo, rem: uint) {
when size_of(uint) == size_of(u32) { when size_of(uint) == size_of(u32) {
a, b := div_u32(u32(hi), u32(lo), u32(y)) a, b := div_u32(u32(hi), u32(lo), u32(y))
} else { } else {
@@ -286,16 +329,26 @@ div :: proc{div_u32, div_u64, div_uint}
is_power_of_two_u8 :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0 } @(require_results)
is_power_of_two_i8 :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0 } is_power_of_two_u8 :: proc "contextless" (i: u8) -> bool { return i > 0 && (i & (i-1)) == 0 }
is_power_of_two_u16 :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0 } @(require_results)
is_power_of_two_i16 :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0 } is_power_of_two_i8 :: proc "contextless" (i: i8) -> bool { return i > 0 && (i & (i-1)) == 0 }
is_power_of_two_u32 :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0 } @(require_results)
is_power_of_two_i32 :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0 } is_power_of_two_u16 :: proc "contextless" (i: u16) -> bool { return i > 0 && (i & (i-1)) == 0 }
is_power_of_two_u64 :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0 } @(require_results)
is_power_of_two_i64 :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0 } is_power_of_two_i16 :: proc "contextless" (i: i16) -> bool { return i > 0 && (i & (i-1)) == 0 }
is_power_of_two_uint :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0 } @(require_results)
is_power_of_two_int :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0 } is_power_of_two_u32 :: proc "contextless" (i: u32) -> bool { return i > 0 && (i & (i-1)) == 0 }
@(require_results)
is_power_of_two_i32 :: proc "contextless" (i: i32) -> bool { return i > 0 && (i & (i-1)) == 0 }
@(require_results)
is_power_of_two_u64 :: proc "contextless" (i: u64) -> bool { return i > 0 && (i & (i-1)) == 0 }
@(require_results)
is_power_of_two_i64 :: proc "contextless" (i: i64) -> bool { return i > 0 && (i & (i-1)) == 0 }
@(require_results)
is_power_of_two_uint :: proc "contextless" (i: uint) -> bool { return i > 0 && (i & (i-1)) == 0 }
@(require_results)
is_power_of_two_int :: proc "contextless" (i: int) -> bool { return i > 0 && (i & (i-1)) == 0 }
is_power_of_two :: proc{ is_power_of_two :: proc{
is_power_of_two_u8, is_power_of_two_i8, is_power_of_two_u8, is_power_of_two_i8,
@@ -320,44 +373,56 @@ len_u8_table := [256]u8{
} }
bitfield_extract_u8 :: proc(value: u8, offset, bits: uint) -> u8 { return (value >> offset) & u8(1<<bits - 1) } @(require_results)
bitfield_extract_u16 :: proc(value: u16, offset, bits: uint) -> u16 { return (value >> offset) & u16(1<<bits - 1) } bitfield_extract_u8 :: proc "contextless" (value: u8, offset, bits: uint) -> u8 { return (value >> offset) & u8(1<<bits - 1) }
bitfield_extract_u32 :: proc(value: u32, offset, bits: uint) -> u32 { return (value >> offset) & u32(1<<bits - 1) } @(require_results)
bitfield_extract_u64 :: proc(value: u64, offset, bits: uint) -> u64 { return (value >> offset) & u64(1<<bits - 1) } bitfield_extract_u16 :: proc "contextless" (value: u16, offset, bits: uint) -> u16 { return (value >> offset) & u16(1<<bits - 1) }
bitfield_extract_u128 :: proc(value: u128, offset, bits: uint) -> u128 { return (value >> offset) & u128(1<<bits - 1) } @(require_results)
bitfield_extract_uint :: proc(value: uint, offset, bits: uint) -> uint { return (value >> offset) & uint(1<<bits - 1) } bitfield_extract_u32 :: proc "contextless" (value: u32, offset, bits: uint) -> u32 { return (value >> offset) & u32(1<<bits - 1) }
@(require_results)
bitfield_extract_u64 :: proc "contextless" (value: u64, offset, bits: uint) -> u64 { return (value >> offset) & u64(1<<bits - 1) }
@(require_results)
bitfield_extract_u128 :: proc "contextless" (value: u128, offset, bits: uint) -> u128 { return (value >> offset) & u128(1<<bits - 1) }
@(require_results)
bitfield_extract_uint :: proc "contextless" (value: uint, offset, bits: uint) -> uint { return (value >> offset) & uint(1<<bits - 1) }
bitfield_extract_i8 :: proc(value: i8, offset, bits: uint) -> i8 { @(require_results)
bitfield_extract_i8 :: proc "contextless" (value: i8, offset, bits: uint) -> i8 {
v := (u8(value) >> offset) & u8(1<<bits - 1) v := (u8(value) >> offset) & u8(1<<bits - 1)
m := u8(1<<(bits-1)) m := u8(1<<(bits-1))
r := (v~m) - m r := (v~m) - m
return i8(r) return i8(r)
} }
bitfield_extract_i16 :: proc(value: i16, offset, bits: uint) -> i16 { @(require_results)
bitfield_extract_i16 :: proc "contextless" (value: i16, offset, bits: uint) -> i16 {
v := (u16(value) >> offset) & u16(1<<bits - 1) v := (u16(value) >> offset) & u16(1<<bits - 1)
m := u16(1<<(bits-1)) m := u16(1<<(bits-1))
r := (v~m) - m r := (v~m) - m
return i16(r) return i16(r)
} }
bitfield_extract_i32 :: proc(value: i32, offset, bits: uint) -> i32 { @(require_results)
bitfield_extract_i32 :: proc "contextless" (value: i32, offset, bits: uint) -> i32 {
v := (u32(value) >> offset) & u32(1<<bits - 1) v := (u32(value) >> offset) & u32(1<<bits - 1)
m := u32(1<<(bits-1)) m := u32(1<<(bits-1))
r := (v~m) - m r := (v~m) - m
return i32(r) return i32(r)
} }
bitfield_extract_i64 :: proc(value: i64, offset, bits: uint) -> i64 { @(require_results)
bitfield_extract_i64 :: proc "contextless" (value: i64, offset, bits: uint) -> i64 {
v := (u64(value) >> offset) & u64(1<<bits - 1) v := (u64(value) >> offset) & u64(1<<bits - 1)
m := u64(1<<(bits-1)) m := u64(1<<(bits-1))
r := (v~m) - m r := (v~m) - m
return i64(r) return i64(r)
} }
bitfield_extract_i128 :: proc(value: i128, offset, bits: uint) -> i128 { @(require_results)
bitfield_extract_i128 :: proc "contextless" (value: i128, offset, bits: uint) -> i128 {
v := (u128(value) >> offset) & u128(1<<bits - 1) v := (u128(value) >> offset) & u128(1<<bits - 1)
m := u128(1<<(bits-1)) m := u128(1<<(bits-1))
r := (v~m) - m r := (v~m) - m
return i128(r) return i128(r)
} }
bitfield_extract_int :: proc(value: int, offset, bits: uint) -> int { @(require_results)
bitfield_extract_int :: proc "contextless" (value: int, offset, bits: uint) -> int {
v := (uint(value) >> offset) & uint(1<<bits - 1) v := (uint(value) >> offset) & uint(1<<bits - 1)
m := uint(1<<(bits-1)) m := uint(1<<(bits-1))
r := (v~m) - m r := (v~m) - m
@@ -381,52 +446,64 @@ bitfield_extract :: proc{
} }
bitfield_insert_u8 :: proc(base, insert: u8, offset, bits: uint) -> u8 { @(require_results)
bitfield_insert_u8 :: proc "contextless" (base, insert: u8, offset, bits: uint) -> u8 {
mask := u8(1<<bits - 1) mask := u8(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_u16 :: proc(base, insert: u16, offset, bits: uint) -> u16 { @(require_results)
bitfield_insert_u16 :: proc "contextless" (base, insert: u16, offset, bits: uint) -> u16 {
mask := u16(1<<bits - 1) mask := u16(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_u32 :: proc(base, insert: u32, offset, bits: uint) -> u32 { @(require_results)
bitfield_insert_u32 :: proc "contextless" (base, insert: u32, offset, bits: uint) -> u32 {
mask := u32(1<<bits - 1) mask := u32(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_u64 :: proc(base, insert: u64, offset, bits: uint) -> u64 { @(require_results)
bitfield_insert_u64 :: proc "contextless" (base, insert: u64, offset, bits: uint) -> u64 {
mask := u64(1<<bits - 1) mask := u64(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_u128 :: proc(base, insert: u128, offset, bits: uint) -> u128 { @(require_results)
bitfield_insert_u128 :: proc "contextless" (base, insert: u128, offset, bits: uint) -> u128 {
mask := u128(1<<bits - 1) mask := u128(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_uint :: proc(base, insert: uint, offset, bits: uint) -> uint { @(require_results)
bitfield_insert_uint :: proc "contextless" (base, insert: uint, offset, bits: uint) -> uint {
mask := uint(1<<bits - 1) mask := uint(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_i8 :: proc(base, insert: i8, offset, bits: uint) -> i8 { @(require_results)
bitfield_insert_i8 :: proc "contextless" (base, insert: i8, offset, bits: uint) -> i8 {
mask := i8(1<<bits - 1) mask := i8(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_i16 :: proc(base, insert: i16, offset, bits: uint) -> i16 { @(require_results)
bitfield_insert_i16 :: proc "contextless" (base, insert: i16, offset, bits: uint) -> i16 {
mask := i16(1<<bits - 1) mask := i16(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_i32 :: proc(base, insert: i32, offset, bits: uint) -> i32 { @(require_results)
bitfield_insert_i32 :: proc "contextless" (base, insert: i32, offset, bits: uint) -> i32 {
mask := i32(1<<bits - 1) mask := i32(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_i64 :: proc(base, insert: i64, offset, bits: uint) -> i64 { @(require_results)
bitfield_insert_i64 :: proc "contextless" (base, insert: i64, offset, bits: uint) -> i64 {
mask := i64(1<<bits - 1) mask := i64(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_i128 :: proc(base, insert: i128, offset, bits: uint) -> i128 { @(require_results)
bitfield_insert_i128 :: proc "contextless" (base, insert: i128, offset, bits: uint) -> i128 {
mask := i128(1<<bits - 1) mask := i128(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
bitfield_insert_int :: proc(base, insert: int, offset, bits: uint) -> int { @(require_results)
bitfield_insert_int :: proc "contextless" (base, insert: int, offset, bits: uint) -> int {
mask := int(1<<bits - 1) mask := int(1<<bits - 1)
return (base &~ (mask<<offset)) | ((insert&mask) << offset) return (base &~ (mask<<offset)) | ((insert&mask) << offset)
} }
+66 -31
View File
@@ -11,11 +11,13 @@ import "core:time"
// with additional enum based call // with additional enum based call
// Modeled after the parabola y = x^2 // Modeled after the parabola y = x^2
@(require_results)
quadratic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quadratic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p * p return p * p
} }
// Modeled after the parabola y = -x^2 + 2x // Modeled after the parabola y = -x^2 + 2x
@(require_results)
quadratic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quadratic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return -(p * (p - 2)) return -(p * (p - 2))
} }
@@ -23,6 +25,7 @@ quadratic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(
// Modeled after the piecewise quadratic // Modeled after the piecewise quadratic
// y = (1/2)((2x)^2) ; [0, 0.5) // y = (1/2)((2x)^2) ; [0, 0.5)
// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
@(require_results)
quadratic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quadratic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 { if p < 0.5 {
return 2 * p * p return 2 * p * p
@@ -32,11 +35,13 @@ quadratic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_flo
} }
// Modeled after the cubic y = x^3 // Modeled after the cubic y = x^3
@(require_results)
cubic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { cubic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p * p * p return p * p * p
} }
// Modeled after the cubic y = (x - 1)^3 + 1 // Modeled after the cubic y = (x - 1)^3 + 1
@(require_results)
cubic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { cubic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
f := p - 1 f := p - 1
return f * f * f + 1 return f * f * f + 1
@@ -45,6 +50,7 @@ cubic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
// Modeled after the piecewise cubic // Modeled after the piecewise cubic
// y = (1/2)((2x)^3) ; [0, 0.5) // y = (1/2)((2x)^3) ; [0, 0.5)
// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
@(require_results)
cubic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { cubic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 { if p < 0.5 {
return 4 * p * p * p return 4 * p * p * p
@@ -55,11 +61,13 @@ cubic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T
} }
// Modeled after the quartic x^4 // Modeled after the quartic x^4
@(require_results)
quartic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quartic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p * p * p * p return p * p * p * p
} }
// Modeled after the quartic y = 1 - (x - 1)^4 // Modeled after the quartic y = 1 - (x - 1)^4
@(require_results)
quartic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quartic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
f := p - 1 f := p - 1
return f * f * f * (1 - p) + 1 return f * f * f * (1 - p) + 1
@@ -68,6 +76,7 @@ quartic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
// Modeled after the piecewise quartic // Modeled after the piecewise quartic
// y = (1/2)((2x)^4) ; [0, 0.5) // y = (1/2)((2x)^4) ; [0, 0.5)
// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
@(require_results)
quartic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quartic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 { if p < 0.5 {
return 8 * p * p * p * p return 8 * p * p * p * p
@@ -78,11 +87,13 @@ quartic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float
} }
// Modeled after the quintic y = x^5 // Modeled after the quintic y = x^5
@(require_results)
quintic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quintic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p * p * p * p * p return p * p * p * p * p
} }
// Modeled after the quintic y = (x - 1)^5 + 1 // Modeled after the quintic y = (x - 1)^5 + 1
@(require_results)
quintic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quintic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
f := p - 1 f := p - 1
return f * f * f * f * f + 1 return f * f * f * f * f + 1
@@ -91,6 +102,7 @@ quintic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
// Modeled after the piecewise quintic // Modeled after the piecewise quintic
// y = (1/2)((2x)^5) ; [0, 0.5) // y = (1/2)((2x)^5) ; [0, 0.5)
// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
@(require_results)
quintic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { quintic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 { if p < 0.5 {
return 16 * p * p * p * p * p return 16 * p * p * p * p * p
@@ -101,26 +113,31 @@ quintic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float
} }
// Modeled after quarter-cycle of sine wave // Modeled after quarter-cycle of sine wave
@(require_results)
sine_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { sine_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.sin((p - 1) * PI_2) + 1 return math.sin((p - 1) * PI_2) + 1
} }
// Modeled after quarter-cycle of sine wave (different phase) // Modeled after quarter-cycle of sine wave (different phase)
@(require_results)
sine_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { sine_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.sin(p * PI_2) return math.sin(p * PI_2)
} }
// Modeled after half sine wave // Modeled after half sine wave
@(require_results)
sine_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { sine_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return 0.5 * (1 - math.cos(p * math.PI)) return 0.5 * (1 - math.cos(p * math.PI))
} }
// Modeled after shifted quadrant IV of unit circle // Modeled after shifted quadrant IV of unit circle
@(require_results)
circular_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { circular_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return 1 - math.sqrt(1 - (p * p)) return 1 - math.sqrt(1 - (p * p))
} }
// Modeled after shifted quadrant II of unit circle // Modeled after shifted quadrant II of unit circle
@(require_results)
circular_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { circular_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.sqrt((2 - p) * p) return math.sqrt((2 - p) * p)
} }
@@ -128,6 +145,7 @@ circular_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T
// Modeled after the piecewise circular function // Modeled after the piecewise circular function
// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) // y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5)
// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
@(require_results)
circular_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { circular_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 { if p < 0.5 {
return 0.5 * (1 - math.sqrt(1 - 4 * (p * p))) return 0.5 * (1 - math.sqrt(1 - 4 * (p * p)))
@@ -137,11 +155,13 @@ circular_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_floa
} }
// Modeled after the exponential function y = 2^(10(x - 1)) // Modeled after the exponential function y = 2^(10(x - 1))
@(require_results)
exponential_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { exponential_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p == 0.0 ? p : math.pow(2, 10 * (p - 1)) return p == 0.0 ? p : math.pow(2, 10 * (p - 1))
} }
// Modeled after the exponential function y = -2^(-10x) + 1 // Modeled after the exponential function y = -2^(-10x) + 1
@(require_results)
exponential_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { exponential_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p == 1.0 ? p : 1 - math.pow(2, -10 * p) return p == 1.0 ? p : 1 - math.pow(2, -10 * p)
} }
@@ -149,6 +169,7 @@ exponential_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_floa
// Modeled after the piecewise exponential // Modeled after the piecewise exponential
// y = (1/2)2^(10(2x - 1)) ; [0,0.5) // y = (1/2)2^(10(2x - 1)) ; [0,0.5)
// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
@(require_results)
exponential_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { exponential_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p == 0.0 || p == 1.0 { if p == 0.0 || p == 1.0 {
return p return p
@@ -162,11 +183,13 @@ exponential_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_f
} }
// Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
@(require_results)
elastic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { elastic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.sin(13 * PI_2 * p) * math.pow(2, 10 * (p - 1)) return math.sin(13 * PI_2 * p) * math.pow(2, 10 * (p - 1))
} }
// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
@(require_results)
elastic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { elastic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.sin(-13 * PI_2 * (p + 1)) * math.pow(2, -10 * p) + 1 return math.sin(-13 * PI_2 * (p + 1)) * math.pow(2, -10 * p) + 1
} }
@@ -174,6 +197,7 @@ elastic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
// Modeled after the piecewise exponentially-damped sine wave: // Modeled after the piecewise exponentially-damped sine wave:
// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5)
// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
@(require_results)
elastic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { elastic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 { if p < 0.5 {
return 0.5 * math.sin(13 * PI_2 * (2 * p)) * math.pow(2, 10 * ((2 * p) - 1)) return 0.5 * math.sin(13 * PI_2 * (2 * p)) * math.pow(2, 10 * ((2 * p) - 1))
@@ -183,11 +207,13 @@ elastic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float
} }
// Modeled after the overshooting cubic y = x^3-x*sin(x*pi) // Modeled after the overshooting cubic y = x^3-x*sin(x*pi)
@(require_results)
back_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { back_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p * p * p - p * math.sin(p * math.PI) return p * p * p - p * math.sin(p * math.PI)
} }
// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) // Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
@(require_results)
back_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { back_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
f := 1 - p f := 1 - p
return 1 - (f * f * f - f * math.sin(f * math.PI)) return 1 - (f * f * f - f * math.sin(f * math.PI))
@@ -196,6 +222,7 @@ back_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
// Modeled after the piecewise overshooting cubic function: // Modeled after the piecewise overshooting cubic function:
// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5)
// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
@(require_results)
back_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { back_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 { if p < 0.5 {
f := 2 * p f := 2 * p
@@ -206,10 +233,12 @@ back_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
} }
} }
@(require_results)
bounce_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { bounce_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return 1 - bounce_out(1 - p) return 1 - bounce_out(1 - p)
} }
@(require_results)
bounce_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { bounce_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 4/11.0 { if p < 4/11.0 {
return (121 * p * p)/16.0 return (121 * p * p)/16.0
@@ -222,6 +251,7 @@ bounce_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T)
} }
} }
@(require_results)
bounce_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) { bounce_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 { if p < 0.5 {
return 0.5 * bounce_in(p*2) return 0.5 * bounce_in(p*2)
@@ -276,50 +306,51 @@ Ease :: enum {
Bounce_In_Out, Bounce_In_Out,
} }
@(require_results)
ease :: proc "contextless" (type: Ease, p: $T) -> T ease :: proc "contextless" (type: Ease, p: $T) -> T
where intrinsics.type_is_float(T) { where intrinsics.type_is_float(T) {
switch type { switch type {
case .Linear: return p case .Linear: return p
case .Quadratic_In: return quadratic_in(p) case .Quadratic_In: return quadratic_in(p)
case .Quadratic_Out: return quadratic_out(p) case .Quadratic_Out: return quadratic_out(p)
case .Quadratic_In_Out: return quadratic_in_out(p) case .Quadratic_In_Out: return quadratic_in_out(p)
case .Cubic_In: return cubic_in(p) case .Cubic_In: return cubic_in(p)
case .Cubic_Out: return cubic_out(p) case .Cubic_Out: return cubic_out(p)
case .Cubic_In_Out: return cubic_in_out(p) case .Cubic_In_Out: return cubic_in_out(p)
case .Quartic_In: return quartic_in(p) case .Quartic_In: return quartic_in(p)
case .Quartic_Out: return quartic_out(p) case .Quartic_Out: return quartic_out(p)
case .Quartic_In_Out: return quartic_in_out(p) case .Quartic_In_Out: return quartic_in_out(p)
case .Quintic_In: return quintic_in(p) case .Quintic_In: return quintic_in(p)
case .Quintic_Out: return quintic_out(p) case .Quintic_Out: return quintic_out(p)
case .Quintic_In_Out: return quintic_in_out(p) case .Quintic_In_Out: return quintic_in_out(p)
case .Sine_In: return sine_in(p) case .Sine_In: return sine_in(p)
case .Sine_Out: return sine_out(p) case .Sine_Out: return sine_out(p)
case .Sine_In_Out: return sine_in_out(p) case .Sine_In_Out: return sine_in_out(p)
case .Circular_In: return circular_in(p) case .Circular_In: return circular_in(p)
case .Circular_Out: return circular_out(p) case .Circular_Out: return circular_out(p)
case .Circular_In_Out: return circular_in_out(p) case .Circular_In_Out: return circular_in_out(p)
case .Exponential_In: return exponential_in(p) case .Exponential_In: return exponential_in(p)
case .Exponential_Out: return exponential_out(p) case .Exponential_Out: return exponential_out(p)
case .Exponential_In_Out: return exponential_in_out(p) case .Exponential_In_Out: return exponential_in_out(p)
case .Elastic_In: return elastic_in(p) case .Elastic_In: return elastic_in(p)
case .Elastic_Out: return elastic_out(p) case .Elastic_Out: return elastic_out(p)
case .Elastic_In_Out: return elastic_in_out(p) case .Elastic_In_Out: return elastic_in_out(p)
case .Back_In: return back_in(p) case .Back_In: return back_in(p)
case .Back_Out: return back_out(p) case .Back_Out: return back_out(p)
case .Back_In_Out: return back_in_out(p) case .Back_In_Out: return back_in_out(p)
case .Bounce_In: return bounce_in(p) case .Bounce_In: return bounce_in(p)
case .Bounce_Out: return bounce_out(p) case .Bounce_Out: return bounce_out(p)
case .Bounce_In_Out: return bounce_in_out(p) case .Bounce_In_Out: return bounce_in_out(p)
} }
// in case type was invalid // in case type was invalid
@@ -353,6 +384,7 @@ Flux_Tween :: struct($T: typeid) {
} }
// init flux map to a float type and a wanted cap // init flux map to a float type and a wanted cap
@(require_results)
flux_init :: proc($T: typeid, value_capacity := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) { flux_init :: proc($T: typeid, value_capacity := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
return { return {
values = make(map[^T]Flux_Tween(T), value_capacity), values = make(map[^T]Flux_Tween(T), value_capacity),
@@ -374,6 +406,7 @@ flux_clear :: proc(flux: ^Flux_Map($T)) where intrinsics.type_is_float(T) {
// append / overwrite existing tween value to parameters // append / overwrite existing tween value to parameters
// rest is initialized in flux_tween_init, inside update // rest is initialized in flux_tween_init, inside update
// return value can be used to set callbacks // return value can be used to set callbacks
@(require_results)
flux_to :: proc( flux_to :: proc(
flux: ^Flux_Map($T), flux: ^Flux_Map($T),
value: ^T, value: ^T,
@@ -475,6 +508,7 @@ flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float
// stop a specific key inside the map // stop a specific key inside the map
// returns true when it successfully removed the key // returns true when it successfully removed the key
@(require_results)
flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) { flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) {
if key in flux.values { if key in flux.values {
delete_key(&flux.values, key) delete_key(&flux.values, key)
@@ -486,6 +520,7 @@ flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is
// returns the amount of time left for the tween animation, if the key exists in the map // returns the amount of time left for the tween animation, if the key exists in the map
// returns 0 if the tween doesnt exist on the map // returns 0 if the tween doesnt exist on the map
@(require_results)
flux_tween_time_left :: proc(flux: Flux_Map($T), key: ^T) -> f64 { flux_tween_time_left :: proc(flux: Flux_Map($T), key: ^T) -> f64 {
if tween, ok := flux.values[key]; ok { if tween, ok := flux.values[key]; ok {
return ((1 - tween.progress) * tween.rate) + tween.delay return ((1 - tween.progress) * tween.rate) + tween.delay
+11
View File
@@ -50,39 +50,48 @@ to_f64 :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> f64 {
} }
@(require_results)
add :: proc(x, y: $T/Fixed) -> T { add :: proc(x, y: $T/Fixed) -> T {
return {x.i + y.i} return {x.i + y.i}
} }
@(require_results)
sub :: proc(x, y: $T/Fixed) -> T { sub :: proc(x, y: $T/Fixed) -> T {
return {x.i - y.i} return {x.i - y.i}
} }
@(require_results)
mul :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) { mul :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
z.i = intrinsics.fixed_point_mul(x.i, y.i, Fraction_Width) z.i = intrinsics.fixed_point_mul(x.i, y.i, Fraction_Width)
return return
} }
@(require_results)
mul_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) { mul_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
z.i = intrinsics.fixed_point_mul_sat(x.i, y.i, Fraction_Width) z.i = intrinsics.fixed_point_mul_sat(x.i, y.i, Fraction_Width)
return return
} }
@(require_results)
div :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) { div :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
z.i = intrinsics.fixed_point_div(x.i, y.i, Fraction_Width) z.i = intrinsics.fixed_point_div(x.i, y.i, Fraction_Width)
return return
} }
@(require_results)
div_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) { div_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
z.i = intrinsics.fixed_point_div_sat(x.i, y.i, Fraction_Width) z.i = intrinsics.fixed_point_div_sat(x.i, y.i, Fraction_Width)
return return
} }
@(require_results)
floor :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing { floor :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
return x.i >> Fraction_Width return x.i >> Fraction_Width
} }
@(require_results)
ceil :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing { ceil :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
Integer :: 8*size_of(Backing) - Fraction_Width Integer :: 8*size_of(Backing) - Fraction_Width
return (x.i + (1 << Integer-1)) >> Fraction_Width return (x.i + (1 << Integer-1)) >> Fraction_Width
} }
@(require_results)
round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing { round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
Integer :: 8*size_of(Backing) - Fraction_Width Integer :: 8*size_of(Backing) - Fraction_Width
return (x.i + (1 << (Integer - 1))) >> Fraction_Width return (x.i + (1 << (Integer - 1))) >> Fraction_Width
@@ -90,6 +99,7 @@ round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
@(require_results)
append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
x := x x := x
buf: [48]byte buf: [48]byte
@@ -123,6 +133,7 @@ append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
} }
@(require_results)
to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string { to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string {
buf: [48]byte buf: [48]byte
s := append(buf[:], x) s := append(buf[:], x)
+124 -65
View File
@@ -3,7 +3,8 @@ package linalg
import "core:builtin" import "core:builtin"
import "core:math" import "core:math"
to_radians :: proc(degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
to_radians :: proc "contextless" (degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = degrees[i] * RAD_PER_DEG out[i] = degrees[i] * RAD_PER_DEG
@@ -14,7 +15,8 @@ to_radians :: proc(degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
return return
} }
to_degrees :: proc(radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
to_degrees :: proc "contextless" (radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = radians[i] * DEG_PER_RAD out[i] = radians[i] * DEG_PER_RAD
@@ -25,7 +27,8 @@ to_degrees :: proc(radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
return return
} }
min_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
min_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = builtin.min(a[i], b[i]) out[i] = builtin.min(a[i], b[i])
@@ -36,7 +39,8 @@ min_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
return return
} }
min_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
min_single :: proc "contextless" (a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
N :: len(T) N :: len(T)
@@ -56,13 +60,15 @@ min_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T))
return return
} }
min_triple :: proc(a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
min_triple :: proc "contextless" (a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
return min_double(a, min_double(b, c)) return min_double(a, min_double(b, c))
} }
min :: proc{min_single, min_double, min_triple} min :: proc{min_single, min_double, min_triple}
max_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
max_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = builtin.max(a[i], b[i]) out[i] = builtin.max(a[i], b[i])
@@ -73,7 +79,8 @@ max_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
return return
} }
max_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
max_single :: proc "contextless" (a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
N :: len(T) N :: len(T)
@@ -95,13 +102,15 @@ max_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T))
return return
} }
max_triple :: proc(a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
max_triple :: proc "contextless" (a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
return max_double(a, max_double(b, c)) return max_double(a, max_double(b, c))
} }
max :: proc{max_single, max_double, max_triple} max :: proc{max_single, max_double, max_triple}
abs :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
abs :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = auto_cast builtin.abs(a[i]) out[i] = auto_cast builtin.abs(a[i])
@@ -112,7 +121,8 @@ abs :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
return return
} }
sign :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
sign :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = #force_inline math.sign(a[i]) out[i] = #force_inline math.sign(a[i])
@@ -123,7 +133,8 @@ sign :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
return return
} }
clamp :: proc(x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { @(require_results)
clamp :: proc "contextless" (x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = builtin.clamp(x[i], a[i], b[i]) out[i] = builtin.clamp(x[i], a[i], b[i])
@@ -135,11 +146,13 @@ clamp :: proc(x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
} }
saturate :: proc(x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
saturate :: proc "contextless" (x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
return clamp(x, 0.0, 1.0) return clamp(x, 0.0, 1.0)
} }
lerp :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
lerp :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = a[i]*(1-t[i]) + b[i]*t[i] out[i] = a[i]*(1-t[i]) + b[i]*t[i]
@@ -149,7 +162,8 @@ lerp :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
} }
return return
} }
mix :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
mix :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = a[i]*(1-t[i]) + b[i]*t[i] out[i] = a[i]*(1-t[i]) + b[i]*t[i]
@@ -160,11 +174,13 @@ mix :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
unlerp :: proc(a, b, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
unlerp :: proc "contextless" (a, b, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
return (x - a) / (b - a) return (x - a) / (b - a)
} }
step :: proc(e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
step :: proc "contextless" (e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = x[i] < e[i] ? 0.0 : 1.0 out[i] = x[i] < e[i] ? 0.0 : 1.0
@@ -175,18 +191,21 @@ step :: proc(e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
smoothstep :: proc(e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
smoothstep :: proc "contextless" (e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
t := saturate(unlerp(e0, e1, x)) t := saturate(unlerp(e0, e1, x))
return t * t * (3.0 - 2.0 * t) return t * t * (3.0 - 2.0 * t)
} }
smootherstep :: proc(e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
smootherstep :: proc "contextless" (e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
t := saturate(unlerp(e0, e1, x)) t := saturate(unlerp(e0, e1, x))
return t * t * t * (t * (6*t - 15) + 10) return t * t * t * (t * (6*t - 15) + 10)
} }
sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.sqrt(x[i]) out[i] = math.sqrt(x[i])
@@ -197,7 +216,8 @@ sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
inverse_sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
inverse_sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = 1.0/math.sqrt(x[i]) out[i] = 1.0/math.sqrt(x[i])
@@ -208,7 +228,8 @@ inverse_sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
cos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
cos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.cos(x[i]) out[i] = math.cos(x[i])
@@ -219,7 +240,8 @@ cos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
sin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
sin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.sin(x[i]) out[i] = math.sin(x[i])
@@ -230,7 +252,8 @@ sin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
tan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
tan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.tan(x[i]) out[i] = math.tan(x[i])
@@ -241,7 +264,8 @@ tan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
acos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
acos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.acos(x[i]) out[i] = math.acos(x[i])
@@ -252,7 +276,8 @@ acos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
asin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
asin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.asin(x[i]) out[i] = math.asin(x[i])
@@ -263,7 +288,8 @@ asin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
atan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
atan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.atan(x[i]) out[i] = math.atan(x[i])
@@ -273,7 +299,8 @@ atan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
} }
return return
} }
atan2 :: proc(y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
atan2 :: proc "contextless" (y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.atan2(y[i], x[i]) out[i] = math.atan2(y[i], x[i])
@@ -285,7 +312,8 @@ atan2 :: proc(y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
} }
ln :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
ln :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.ln(x[i]) out[i] = math.ln(x[i])
@@ -296,7 +324,8 @@ ln :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
log2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
log2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = INVLN2 * math.ln(x[i]) out[i] = INVLN2 * math.ln(x[i])
@@ -307,7 +336,8 @@ log2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
log10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
log10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = INVLN10 * math.ln(x[i]) out[i] = INVLN10 * math.ln(x[i])
@@ -318,7 +348,8 @@ log10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
log :: proc(x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
log :: proc "contextless" (x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.ln(x[i]) / math.ln(cast(ELEM_TYPE(T))b[i]) out[i] = math.ln(x[i]) / math.ln(cast(ELEM_TYPE(T))b[i])
@@ -329,7 +360,8 @@ log :: proc(x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
exp :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
exp :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.exp(x[i]) out[i] = math.exp(x[i])
@@ -340,7 +372,8 @@ exp :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
exp2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
exp2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.exp(LN2 * x[i]) out[i] = math.exp(LN2 * x[i])
@@ -351,7 +384,8 @@ exp2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
exp10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
exp10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.exp(LN10 * x[i]) out[i] = math.exp(LN10 * x[i])
@@ -362,7 +396,8 @@ exp10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
pow :: proc(x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
pow :: proc "contextless" (x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = math.pow(x[i], e[i]) out[i] = math.pow(x[i], e[i])
@@ -374,7 +409,8 @@ pow :: proc(x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
} }
ceil :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
ceil :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = #force_inline math.ceil(x[i]) out[i] = #force_inline math.ceil(x[i])
@@ -385,7 +421,8 @@ ceil :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
floor :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
floor :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = #force_inline math.floor(x[i]) out[i] = #force_inline math.floor(x[i])
@@ -396,7 +433,8 @@ floor :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
round :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
round :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) { when IS_ARRAY(T) {
for i in 0..<len(T) { for i in 0..<len(T) {
out[i] = #force_inline math.round(x[i]) out[i] = #force_inline math.round(x[i])
@@ -407,30 +445,36 @@ round :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
return return
} }
fract :: proc(x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
fract :: proc "contextless" (x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
f := #force_inline floor(x) f := #force_inline floor(x)
return x - f return x - f
} }
mod :: proc(x, m: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
mod :: proc "contextless" (x, m: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
f := #force_inline floor(x / m) f := #force_inline floor(x / m)
return x - f * m return x - f * m
} }
face_forward :: proc(N, I, N_ref: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
face_forward :: proc "contextless" (N, I, N_ref: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
return dot(N_ref, I) < 0 ? N : -N return dot(N_ref, I) < 0 ? N : -N
} }
distance :: proc(p0, p1: $V/[$N]$E) -> E where IS_NUMERIC(E) { @(require_results)
distance :: proc "contextless" (p0, p1: $V/[$N]$E) -> E where IS_NUMERIC(E) {
return length(p1 - p0) return length(p1 - p0)
} }
reflect :: proc(I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { @(require_results)
reflect :: proc "contextless" (I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
b := N * (2 * dot(N, I)) b := N * (2 * dot(N, I))
return I - b return I - b
} }
refract :: proc(I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_FLOAT(ELEM_TYPE(V)) { @(require_results)
refract :: proc "contextless" (I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_FLOAT(ELEM_TYPE(V)) {
dv := dot(Normal, I) dv := dot(Normal, I)
k := 1 - eta*eta * (1 - dv*dv) k := 1 - eta*eta * (1 - dv*dv)
a := I * eta a := I * eta
@@ -441,33 +485,39 @@ refract :: proc(I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_
is_nan_single :: proc(x: $T) -> bool where IS_FLOAT(T) { @(require_results)
is_nan_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) {
return #force_inline math.is_nan(x) return #force_inline math.is_nan(x)
} }
is_nan_array :: proc(x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) { @(require_results)
is_nan_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
for i in 0..<N { for i in 0..<N {
out[i] = #force_inline is_nan(x[i]) out[i] = #force_inline is_nan(x[i])
} }
return return
} }
is_inf_single :: proc(x: $T) -> bool where IS_FLOAT(T) { @(require_results)
is_inf_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) {
return #force_inline math.is_inf(x) return #force_inline math.is_inf(x)
} }
is_inf_array :: proc(x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) { @(require_results)
is_inf_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
for i in 0..<N { for i in 0..<N {
out[i] = #force_inline is_inf(x[i]) out[i] = #force_inline is_inf(x[i])
} }
return return
} }
classify_single :: proc(x: $T) -> math.Float_Class where IS_FLOAT(T) { @(require_results)
classify_single :: proc "contextless" (x: $T) -> math.Float_Class where IS_FLOAT(T) {
return #force_inline math.classify(x) return #force_inline math.classify(x)
} }
classify_array :: proc(x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) { @(require_results)
classify_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) {
for i in 0..<N { for i in 0..<N {
out[i] = #force_inline classify_single(x[i]) out[i] = #force_inline classify_single(x[i])
} }
@@ -479,44 +529,50 @@ is_inf :: proc{is_inf_single, is_inf_array}
classify :: proc{classify_single, classify_array} classify :: proc{classify_single, classify_array}
less_than_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y } @(require_results) less_than_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y }
less_than_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x <= y } @(require_results) less_than_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x <= y }
greater_than_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x > y } @(require_results) greater_than_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x > y }
greater_than_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x >= y } @(require_results) greater_than_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x >= y }
equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x == y } @(require_results) equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x == y }
not_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x != y } @(require_results) not_equal_single :: proc "contextless" (x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x != y }
less_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { @(require_results)
less_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N { for i in 0..<N {
out[i] = x[i] < y[i] out[i] = x[i] < y[i]
} }
return return
} }
less_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { @(require_results)
less_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N { for i in 0..<N {
out[i] = x[i] <= y[i] out[i] = x[i] <= y[i]
} }
return return
} }
greater_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { @(require_results)
greater_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N { for i in 0..<N {
out[i] = x[i] > y[i] out[i] = x[i] > y[i]
} }
return return
} }
greater_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { @(require_results)
greater_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N { for i in 0..<N {
out[i] = x[i] >= y[i] out[i] = x[i] >= y[i]
} }
return return
} }
equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { @(require_results)
equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N { for i in 0..<N {
out[i] = x[i] == y[i] out[i] = x[i] == y[i]
} }
return return
} }
not_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { @(require_results)
not_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N { for i in 0..<N {
out[i] = x[i] != y[i] out[i] = x[i] != y[i]
} }
@@ -530,7 +586,8 @@ greater_than_equal :: proc{greater_than_equal_single, greater_than_equal_array}
equal :: proc{equal_single, equal_array} equal :: proc{equal_single, equal_array}
not_equal :: proc{not_equal_single, not_equal_array} not_equal :: proc{not_equal_single, not_equal_array}
any :: proc(x: $A/[$N]bool) -> (out: bool) { @(require_results)
any :: proc "contextless" (x: $A/[$N]bool) -> (out: bool) {
for e in x { for e in x {
if e { if e {
return true return true
@@ -538,7 +595,8 @@ any :: proc(x: $A/[$N]bool) -> (out: bool) {
} }
return false return false
} }
all :: proc(x: $A/[$N]bool) -> (out: bool) { @(require_results)
all :: proc "contextless" (x: $A/[$N]bool) -> (out: bool) {
for e in x { for e in x {
if !e { if !e {
return false return false
@@ -546,7 +604,8 @@ all :: proc(x: $A/[$N]bool) -> (out: bool) {
} }
return true return true
} }
not :: proc(x: $A/[$N]bool) -> (out: A) { @(require_results)
not :: proc "contextless" (x: $A/[$N]bool) -> (out: A) {
for e, i in x { for e, i in x {
out[i] = !e out[i] = !e
} }
+94 -56
View File
@@ -38,23 +38,28 @@ DEG_PER_RAD :: 360.0/TAU
@private ELEM_TYPE :: intrinsics.type_elem_type @private ELEM_TYPE :: intrinsics.type_elem_type
scalar_dot :: proc(a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) { @(require_results)
scalar_dot :: proc "contextless" (a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) {
return a * b return a * b
} }
vector_dot :: proc(a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E) #no_bounds_check { @(require_results)
vector_dot :: proc "contextless" (a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E) #no_bounds_check {
for i in 0..<N { for i in 0..<N {
c += a[i] * b[i] c += a[i] * b[i]
} }
return return
} }
quaternion64_dot :: proc(a, b: $T/quaternion64) -> (c: f16) { @(require_results)
quaternion64_dot :: proc "contextless" (a, b: $T/quaternion64) -> (c: f16) {
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
} }
quaternion128_dot :: proc(a, b: $T/quaternion128) -> (c: f32) { @(require_results)
quaternion128_dot :: proc "contextless" (a, b: $T/quaternion128) -> (c: f32) {
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
} }
quaternion256_dot :: proc(a, b: $T/quaternion256) -> (c: f64) { @(require_results)
quaternion256_dot :: proc "contextless" (a, b: $T/quaternion256) -> (c: f64) {
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
} }
@@ -63,27 +68,32 @@ dot :: proc{scalar_dot, vector_dot, quaternion64_dot, quaternion128_dot, quatern
inner_product :: dot inner_product :: dot
outer_product :: builtin.outer_product outer_product :: builtin.outer_product
quaternion_inverse :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { @(require_results)
quaternion_inverse :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0) return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0)
} }
scalar_cross :: proc(a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) { @(require_results)
scalar_cross :: proc "contextless" (a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) {
return a * b return a * b
} }
vector_cross2 :: proc(a, b: $T/[2]$E) -> E where IS_NUMERIC(E) { @(require_results)
vector_cross2 :: proc "contextless" (a, b: $T/[2]$E) -> E where IS_NUMERIC(E) {
return a[0]*b[1] - b[0]*a[1] return a[0]*b[1] - b[0]*a[1]
} }
vector_cross3 :: proc(a, b: $T/[3]$E) -> (c: T) where IS_NUMERIC(E) { @(require_results)
vector_cross3 :: proc "contextless" (a, b: $T/[3]$E) -> (c: T) where IS_NUMERIC(E) {
c[0] = a[1]*b[2] - b[1]*a[2] c[0] = a[1]*b[2] - b[1]*a[2]
c[1] = a[2]*b[0] - b[2]*a[0] c[1] = a[2]*b[0] - b[2]*a[0]
c[2] = a[0]*b[1] - b[0]*a[1] c[2] = a[0]*b[1] - b[0]*a[1]
return return
} }
quaternion_cross :: proc(q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) { @(require_results)
quaternion_cross :: proc "contextless" (q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) {
q3.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y q3.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
q3.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z q3.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z
q3.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x q3.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x
@@ -94,49 +104,59 @@ quaternion_cross :: proc(q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) {
vector_cross :: proc{scalar_cross, vector_cross2, vector_cross3} vector_cross :: proc{scalar_cross, vector_cross2, vector_cross3}
cross :: proc{scalar_cross, vector_cross2, vector_cross3, quaternion_cross} cross :: proc{scalar_cross, vector_cross2, vector_cross3, quaternion_cross}
vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_FLOAT(E) { @(require_results)
vector_normalize :: proc "contextless" (v: $T/[$N]$E) -> T where IS_FLOAT(E) {
return v / length(v) return v / length(v)
} }
quaternion_normalize :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { @(require_results)
quaternion_normalize :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
return q/abs(q) return q/abs(q)
} }
normalize :: proc{vector_normalize, quaternion_normalize} normalize :: proc{vector_normalize, quaternion_normalize}
vector_normalize0 :: proc(v: $T/[$N]$E) -> T where IS_FLOAT(E) { @(require_results)
vector_normalize0 :: proc "contextless" (v: $T/[$N]$E) -> T where IS_FLOAT(E) {
m := length(v) m := length(v)
return 0 if m == 0 else v/m return 0 if m == 0 else v/m
} }
quaternion_normalize0 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { @(require_results)
quaternion_normalize0 :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
m := abs(q) m := abs(q)
return 0 if m == 0 else q/m return 0 if m == 0 else q/m
} }
normalize0 :: proc{vector_normalize0, quaternion_normalize0} normalize0 :: proc{vector_normalize0, quaternion_normalize0}
vector_length :: proc(v: $T/[$N]$E) -> E where IS_FLOAT(E) { @(require_results)
vector_length :: proc "contextless" (v: $T/[$N]$E) -> E where IS_FLOAT(E) {
return math.sqrt(dot(v, v)) return math.sqrt(dot(v, v))
} }
vector_length2 :: proc(v: $T/[$N]$E) -> E where IS_NUMERIC(E) { @(require_results)
vector_length2 :: proc "contextless" (v: $T/[$N]$E) -> E where IS_NUMERIC(E) {
return dot(v, v) return dot(v, v)
} }
quaternion_length :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { @(require_results)
quaternion_length :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
return abs(q) return abs(q)
} }
quaternion_length2 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { @(require_results)
quaternion_length2 :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
return dot(q, q) return dot(q, q)
} }
scalar_triple_product :: proc(a, b, c: $T/[$N]$E) -> E where IS_NUMERIC(E) { @(require_results)
scalar_triple_product :: proc "contextless" (a, b, c: $T/[$N]$E) -> E where IS_NUMERIC(E) {
// a . (b x c) // a . (b x c)
// b . (c x a) // b . (c x a)
// c . (a x b) // c . (a x b)
return dot(a, cross(b, c)) return dot(a, cross(b, c))
} }
vector_triple_product :: proc(a, b, c: $T/[$N]$E) -> T where IS_NUMERIC(E) { @(require_results)
vector_triple_product :: proc "contextless" (a, b, c: $T/[$N]$E) -> T where IS_NUMERIC(E) {
// a x (b x c) // a x (b x c)
// (a . c)b - (a . b)c // (a . c)b - (a . b)c
return cross(a, cross(b, c)) return cross(a, cross(b, c))
@@ -146,11 +166,13 @@ vector_triple_product :: proc(a, b, c: $T/[$N]$E) -> T where IS_NUMERIC(E) {
length :: proc{vector_length, quaternion_length} length :: proc{vector_length, quaternion_length}
length2 :: proc{vector_length2, quaternion_length2} length2 :: proc{vector_length2, quaternion_length2}
projection :: proc(x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) { @(require_results)
projection :: proc "contextless" (x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) {
return dot(x, normal) / dot(normal, normal) * normal return dot(x, normal) / dot(normal, normal) * normal
} }
identity :: proc($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check { @(require_results)
identity :: proc "contextless" ($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check {
for i in 0..<N { for i in 0..<N {
m[i][i] = E(1) m[i][i] = E(1)
} }
@@ -160,32 +182,38 @@ identity :: proc($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check {
trace :: builtin.matrix_trace trace :: builtin.matrix_trace
transpose :: builtin.transpose transpose :: builtin.transpose
matrix_mul :: proc(a, b: $M/matrix[$N, N]$E) -> (c: M) @(require_results)
matrix_mul :: proc "contextless" (a, b: $M/matrix[$N, N]$E) -> (c: M)
where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check { where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
return a * b return a * b
} }
matrix_comp_mul :: proc(a, b: $M/matrix[$I, $J]$E) -> (c: M) @(require_results)
matrix_comp_mul :: proc "contextless" (a, b: $M/matrix[$I, $J]$E) -> (c: M)
where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check { where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
return hadamard_product(a, b) return hadamard_product(a, b)
} }
matrix_mul_differ :: proc(a: $A/matrix[$I, $J]$E, b: $B/matrix[J, $K]E) -> (c: matrix[I, K]E) @(require_results)
matrix_mul_differ :: proc "contextless" (a: $A/matrix[$I, $J]$E, b: $B/matrix[J, $K]E) -> (c: matrix[I, K]E)
where !IS_ARRAY(E), IS_NUMERIC(E), I != K #no_bounds_check { where !IS_ARRAY(E), IS_NUMERIC(E), I != K #no_bounds_check {
return a * b return a * b
} }
matrix_mul_vector :: proc(a: $A/matrix[$I, $J]$E, b: $B/[J]E) -> (c: B) @(require_results)
matrix_mul_vector :: proc "contextless" (a: $A/matrix[$I, $J]$E, b: $B/[J]E) -> (c: B)
where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check { where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
return a * b return a * b
} }
quaternion_mul_quaternion :: proc(q1, q2: $Q) -> Q where IS_QUATERNION(Q) { @(require_results)
quaternion_mul_quaternion :: proc "contextless" (q1, q2: $Q) -> Q where IS_QUATERNION(Q) {
return q1 * q2 return q1 * q2
} }
quaternion64_mul_vector3 :: proc(q: $Q/quaternion64, v: $V/[3]$F/f16) -> V { @(require_results)
quaternion64_mul_vector3 :: proc "contextless" (q: $Q/quaternion64, v: $V/[3]$F/f16) -> V {
Raw_Quaternion :: struct {xyz: [3]f16, r: f16} Raw_Quaternion :: struct {xyz: [3]f16, r: f16}
q := transmute(Raw_Quaternion)q q := transmute(Raw_Quaternion)q
@@ -194,7 +222,8 @@ quaternion64_mul_vector3 :: proc(q: $Q/quaternion64, v: $V/[3]$F/f16) -> V {
t := cross(2*q.xyz, v) t := cross(2*q.xyz, v)
return V(v + q.r*t + cross(q.xyz, t)) return V(v + q.r*t + cross(q.xyz, t))
} }
quaternion128_mul_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V { @(require_results)
quaternion128_mul_vector3 :: proc "contextless" (q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
Raw_Quaternion :: struct {xyz: [3]f32, r: f32} Raw_Quaternion :: struct {xyz: [3]f32, r: f32}
q := transmute(Raw_Quaternion)q q := transmute(Raw_Quaternion)q
@@ -203,7 +232,8 @@ quaternion128_mul_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
t := cross(2*q.xyz, v) t := cross(2*q.xyz, v)
return V(v + q.r*t + cross(q.xyz, t)) return V(v + q.r*t + cross(q.xyz, t))
} }
quaternion256_mul_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V { @(require_results)
quaternion256_mul_vector3 :: proc "contextless" (q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
Raw_Quaternion :: struct {xyz: [3]f64, r: f64} Raw_Quaternion :: struct {xyz: [3]f64, r: f64}
q := transmute(Raw_Quaternion)q q := transmute(Raw_Quaternion)q
@@ -224,10 +254,12 @@ mul :: proc{
quaternion_mul_quaternion, quaternion_mul_quaternion,
} }
vector_to_ptr :: proc(v: ^$V/[$N]$E) -> ^E where IS_NUMERIC(E), N > 0 #no_bounds_check { @(require_results)
vector_to_ptr :: proc "contextless" (v: ^$V/[$N]$E) -> ^E where IS_NUMERIC(E), N > 0 #no_bounds_check {
return &v[0] return &v[0]
} }
matrix_to_ptr :: proc(m: ^$A/matrix[$I, $J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check { @(require_results)
matrix_to_ptr :: proc "contextless" (m: ^$A/matrix[$I, $J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check {
return &m[0, 0] return &m[0, 0]
} }
@@ -239,7 +271,8 @@ to_ptr :: proc{vector_to_ptr, matrix_to_ptr}
// Splines // Splines
vector_slerp :: proc(x, y: $T/[$N]$E, a: E) -> T { @(require_results)
vector_slerp :: proc "contextless" (x, y: $T/[$N]$E, a: E) -> T {
cos_alpha := dot(x, y) cos_alpha := dot(x, y)
alpha := math.acos(cos_alpha) alpha := math.acos(cos_alpha)
sin_alpha := math.sin(alpha) sin_alpha := math.sin(alpha)
@@ -250,7 +283,8 @@ vector_slerp :: proc(x, y: $T/[$N]$E, a: E) -> T {
return x * t1 + y * t2 return x * t1 + y * t2
} }
catmull_rom :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T { @(require_results)
catmull_rom :: proc "contextless" (v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
s2 := s*s s2 := s*s
s3 := s2*s s3 := s2*s
@@ -262,7 +296,8 @@ catmull_rom :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) * 0.5 return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) * 0.5
} }
hermite :: proc(v1, t1, v2, t2: $T/[$N]$E, s: E) -> T { @(require_results)
hermite :: proc "contextless" (v1, t1, v2, t2: $T/[$N]$E, s: E) -> T {
s2 := s*s s2 := s*s
s3 := s2*s s3 := s2*s
@@ -274,20 +309,23 @@ hermite :: proc(v1, t1, v2, t2: $T/[$N]$E, s: E) -> T {
return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2 return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2
} }
cubic :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T { @(require_results)
cubic :: proc "contextless" (v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
return ((v1 * s + v2) * s + v3) * s + v4 return ((v1 * s + v2) * s + v3) * s + v4
} }
array_cast :: proc(v: $A/[$N]$T, $Elem_Type: typeid) -> (w: [N]Elem_Type) #no_bounds_check { @(require_results)
array_cast :: proc "contextless" (v: $A/[$N]$T, $Elem_Type: typeid) -> (w: [N]Elem_Type) #no_bounds_check {
for i in 0..<N { for i in 0..<N {
w[i] = Elem_Type(v[i]) w[i] = Elem_Type(v[i])
} }
return return
} }
matrix_cast :: proc(v: $A/matrix[$M, $N]$T, $Elem_Type: typeid) -> (w: matrix[M, N]Elem_Type) #no_bounds_check { @(require_results)
matrix_cast :: proc "contextless" (v: $A/matrix[$M, $N]$T, $Elem_Type: typeid) -> (w: matrix[M, N]Elem_Type) #no_bounds_check {
for j in 0..<N { for j in 0..<N {
for i in 0..<M { for i in 0..<M {
w[i, j] = Elem_Type(v[i, j]) w[i, j] = Elem_Type(v[i, j])
@@ -296,24 +334,24 @@ matrix_cast :: proc(v: $A/matrix[$M, $N]$T, $Elem_Type: typeid) -> (w: matrix[M,
return return
} }
to_f32 :: #force_inline proc(v: $A/[$N]$T) -> [N]f32 { return array_cast(v, f32) } @(require_results) to_f32 :: #force_inline proc(v: $A/[$N]$T) -> [N]f32 { return array_cast(v, f32) }
to_f64 :: #force_inline proc(v: $A/[$N]$T) -> [N]f64 { return array_cast(v, f64) } @(require_results) to_f64 :: #force_inline proc(v: $A/[$N]$T) -> [N]f64 { return array_cast(v, f64) }
to_i8 :: #force_inline proc(v: $A/[$N]$T) -> [N]i8 { return array_cast(v, i8) } @(require_results) to_i8 :: #force_inline proc(v: $A/[$N]$T) -> [N]i8 { return array_cast(v, i8) }
to_i16 :: #force_inline proc(v: $A/[$N]$T) -> [N]i16 { return array_cast(v, i16) } @(require_results) to_i16 :: #force_inline proc(v: $A/[$N]$T) -> [N]i16 { return array_cast(v, i16) }
to_i32 :: #force_inline proc(v: $A/[$N]$T) -> [N]i32 { return array_cast(v, i32) } @(require_results) to_i32 :: #force_inline proc(v: $A/[$N]$T) -> [N]i32 { return array_cast(v, i32) }
to_i64 :: #force_inline proc(v: $A/[$N]$T) -> [N]i64 { return array_cast(v, i64) } @(require_results) to_i64 :: #force_inline proc(v: $A/[$N]$T) -> [N]i64 { return array_cast(v, i64) }
to_int :: #force_inline proc(v: $A/[$N]$T) -> [N]int { return array_cast(v, int) } @(require_results) to_int :: #force_inline proc(v: $A/[$N]$T) -> [N]int { return array_cast(v, int) }
to_u8 :: #force_inline proc(v: $A/[$N]$T) -> [N]u8 { return array_cast(v, u8) } @(require_results) to_u8 :: #force_inline proc(v: $A/[$N]$T) -> [N]u8 { return array_cast(v, u8) }
to_u16 :: #force_inline proc(v: $A/[$N]$T) -> [N]u16 { return array_cast(v, u16) } @(require_results) to_u16 :: #force_inline proc(v: $A/[$N]$T) -> [N]u16 { return array_cast(v, u16) }
to_u32 :: #force_inline proc(v: $A/[$N]$T) -> [N]u32 { return array_cast(v, u32) } @(require_results) to_u32 :: #force_inline proc(v: $A/[$N]$T) -> [N]u32 { return array_cast(v, u32) }
to_u64 :: #force_inline proc(v: $A/[$N]$T) -> [N]u64 { return array_cast(v, u64) } @(require_results) to_u64 :: #force_inline proc(v: $A/[$N]$T) -> [N]u64 { return array_cast(v, u64) }
to_uint :: #force_inline proc(v: $A/[$N]$T) -> [N]uint { return array_cast(v, uint) } @(require_results) to_uint :: #force_inline proc(v: $A/[$N]$T) -> [N]uint { return array_cast(v, uint) }
to_complex32 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex32 { return array_cast(v, complex32) } @(require_results) to_complex32 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex32 { return array_cast(v, complex32) }
to_complex64 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex64 { return array_cast(v, complex64) } @(require_results) to_complex64 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex64 { return array_cast(v, complex64) }
to_complex128 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex128 { return array_cast(v, complex128) } @(require_results) to_complex128 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex128 { return array_cast(v, complex128) }
to_quaternion64 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion64 { return array_cast(v, quaternion64) } @(require_results) to_quaternion64 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion64 { return array_cast(v, quaternion64) }
to_quaternion128 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion128 { return array_cast(v, quaternion128) } @(require_results) to_quaternion128 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion128 { return array_cast(v, quaternion128) }
to_quaternion256 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion256 { return array_cast(v, quaternion256) } @(require_results) to_quaternion256 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion256 { return array_cast(v, quaternion256) }
File diff suppressed because it is too large Load Diff
+50 -48
View File
@@ -2,30 +2,31 @@ package math_linalg_glsl
import "core:math" import "core:math"
cos_f32 :: proc "c" (x: f32) -> f32 { return math.cos(x) } @(require_results) cos_f32 :: proc "c" (x: f32) -> f32 { return math.cos(x) }
sin_f32 :: proc "c" (x: f32) -> f32 { return math.sin(x) } @(require_results) sin_f32 :: proc "c" (x: f32) -> f32 { return math.sin(x) }
tan_f32 :: proc "c" (x: f32) -> f32 { return math.tan(x) } @(require_results) tan_f32 :: proc "c" (x: f32) -> f32 { return math.tan(x) }
acos_f32 :: proc "c" (x: f32) -> f32 { return math.acos(x) } @(require_results) acos_f32 :: proc "c" (x: f32) -> f32 { return math.acos(x) }
asin_f32 :: proc "c" (x: f32) -> f32 { return math.asin(x) } @(require_results) asin_f32 :: proc "c" (x: f32) -> f32 { return math.asin(x) }
atan_f32 :: proc "c" (x: f32) -> f32 { return math.atan(x) } @(require_results) atan_f32 :: proc "c" (x: f32) -> f32 { return math.atan(x) }
atan2_f32 :: proc "c" (y, x: f32) -> f32 { return math.atan2(y, x) } @(require_results) atan2_f32 :: proc "c" (y, x: f32) -> f32 { return math.atan2(y, x) }
cosh_f32 :: proc "c" (x: f32) -> f32 { return math.cosh(x) } @(require_results) cosh_f32 :: proc "c" (x: f32) -> f32 { return math.cosh(x) }
sinh_f32 :: proc "c" (x: f32) -> f32 { return math.sinh(x) } @(require_results) sinh_f32 :: proc "c" (x: f32) -> f32 { return math.sinh(x) }
tanh_f32 :: proc "c" (x: f32) -> f32 { return math.tanh(x) } @(require_results) tanh_f32 :: proc "c" (x: f32) -> f32 { return math.tanh(x) }
acosh_f32 :: proc "c" (x: f32) -> f32 { return math.acosh(x) } @(require_results) acosh_f32 :: proc "c" (x: f32) -> f32 { return math.acosh(x) }
asinh_f32 :: proc "c" (x: f32) -> f32 { return math.asinh(x) } @(require_results) asinh_f32 :: proc "c" (x: f32) -> f32 { return math.asinh(x) }
atanh_f32 :: proc "c" (x: f32) -> f32 { return math.atanh(x) } @(require_results) atanh_f32 :: proc "c" (x: f32) -> f32 { return math.atanh(x) }
sqrt_f32 :: proc "c" (x: f32) -> f32 { return math.sqrt(x) } @(require_results) sqrt_f32 :: proc "c" (x: f32) -> f32 { return math.sqrt(x) }
inversesqrt_f32 :: proc "c" (x: f32) -> f32 { return 1.0/math.sqrt(x) } @(require_results) inversesqrt_f32 :: proc "c" (x: f32) -> f32 { return 1.0/math.sqrt(x) }
pow_f32 :: proc "c" (x, y: f32) -> f32 { return math.pow(x, y) } @(require_results) pow_f32 :: proc "c" (x, y: f32) -> f32 { return math.pow(x, y) }
exp_f32 :: proc "c" (x: f32) -> f32 { return math.exp(x) } @(require_results) exp_f32 :: proc "c" (x: f32) -> f32 { return math.exp(x) }
log_f32 :: proc "c" (x: f32) -> f32 { return math.ln(x) } @(require_results) log_f32 :: proc "c" (x: f32) -> f32 { return math.ln(x) }
exp2_f32 :: proc "c" (x: f32) -> f32 { return math.pow(f32(2), x) } @(require_results) exp2_f32 :: proc "c" (x: f32) -> f32 { return math.pow(f32(2), x) }
sign_f32 :: proc "c" (x: f32) -> f32 { return math.sign(x) } @(require_results) sign_f32 :: proc "c" (x: f32) -> f32 { return math.sign(x) }
floor_f32 :: proc "c" (x: f32) -> f32 { return math.floor(x) } @(require_results) floor_f32 :: proc "c" (x: f32) -> f32 { return math.floor(x) }
round_f32 :: proc "c" (x: f32) -> f32 { return math.round(x) } @(require_results) round_f32 :: proc "c" (x: f32) -> f32 { return math.round(x) }
ceil_f32 :: proc "c" (x: f32) -> f32 { return math.ceil(x) } @(require_results) ceil_f32 :: proc "c" (x: f32) -> f32 { return math.ceil(x) }
mod_f32 :: proc "c" (x, y: f32) -> f32 { return math.mod(x, y) } @(require_results) mod_f32 :: proc "c" (x, y: f32) -> f32 { return math.mod(x, y) }
@(require_results)
fract_f32 :: proc "c" (x: f32) -> f32 { fract_f32 :: proc "c" (x: f32) -> f32 {
if x >= 0 { if x >= 0 {
return x - math.trunc(x) return x - math.trunc(x)
@@ -33,30 +34,31 @@ fract_f32 :: proc "c" (x: f32) -> f32 {
return math.trunc(-x) + x return math.trunc(-x) + x
} }
cos_f64 :: proc "c" (x: f64) -> f64 { return math.cos(x) } @(require_results) cos_f64 :: proc "c" (x: f64) -> f64 { return math.cos(x) }
sin_f64 :: proc "c" (x: f64) -> f64 { return math.sin(x) } @(require_results) sin_f64 :: proc "c" (x: f64) -> f64 { return math.sin(x) }
tan_f64 :: proc "c" (x: f64) -> f64 { return math.tan(x) } @(require_results) tan_f64 :: proc "c" (x: f64) -> f64 { return math.tan(x) }
acos_f64 :: proc "c" (x: f64) -> f64 { return math.acos(x) } @(require_results) acos_f64 :: proc "c" (x: f64) -> f64 { return math.acos(x) }
asin_f64 :: proc "c" (x: f64) -> f64 { return math.asin(x) } @(require_results) asin_f64 :: proc "c" (x: f64) -> f64 { return math.asin(x) }
atan_f64 :: proc "c" (x: f64) -> f64 { return math.atan(x) } @(require_results) atan_f64 :: proc "c" (x: f64) -> f64 { return math.atan(x) }
atan2_f64 :: proc "c" (y, x: f64) -> f64 { return math.atan2(y, x) } @(require_results) atan2_f64 :: proc "c" (y, x: f64) -> f64 { return math.atan2(y, x) }
cosh_f64 :: proc "c" (x: f64) -> f64 { return math.cosh(x) } @(require_results) cosh_f64 :: proc "c" (x: f64) -> f64 { return math.cosh(x) }
sinh_f64 :: proc "c" (x: f64) -> f64 { return math.sinh(x) } @(require_results) sinh_f64 :: proc "c" (x: f64) -> f64 { return math.sinh(x) }
tanh_f64 :: proc "c" (x: f64) -> f64 { return math.tanh(x) } @(require_results) tanh_f64 :: proc "c" (x: f64) -> f64 { return math.tanh(x) }
acosh_f64 :: proc "c" (x: f64) -> f64 { return math.acosh(x) } @(require_results) acosh_f64 :: proc "c" (x: f64) -> f64 { return math.acosh(x) }
asinh_f64 :: proc "c" (x: f64) -> f64 { return math.asinh(x) } @(require_results) asinh_f64 :: proc "c" (x: f64) -> f64 { return math.asinh(x) }
atanh_f64 :: proc "c" (x: f64) -> f64 { return math.atanh(x) } @(require_results) atanh_f64 :: proc "c" (x: f64) -> f64 { return math.atanh(x) }
sqrt_f64 :: proc "c" (x: f64) -> f64 { return math.sqrt(x) } @(require_results) sqrt_f64 :: proc "c" (x: f64) -> f64 { return math.sqrt(x) }
inversesqrt_f64 :: proc "c" (x: f64) -> f64 { return 1.0/math.sqrt(x) } @(require_results) inversesqrt_f64 :: proc "c" (x: f64) -> f64 { return 1.0/math.sqrt(x) }
pow_f64 :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) } @(require_results) pow_f64 :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) }
exp_f64 :: proc "c" (x: f64) -> f64 { return math.exp(x) } @(require_results) exp_f64 :: proc "c" (x: f64) -> f64 { return math.exp(x) }
log_f64 :: proc "c" (x: f64) -> f64 { return math.ln(x) } @(require_results) log_f64 :: proc "c" (x: f64) -> f64 { return math.ln(x) }
exp2_f64 :: proc "c" (x: f64) -> f64 { return math.pow(f64(2), x) } @(require_results) exp2_f64 :: proc "c" (x: f64) -> f64 { return math.pow(f64(2), x) }
sign_f64 :: proc "c" (x: f64) -> f64 { return math.sign(x) } @(require_results) sign_f64 :: proc "c" (x: f64) -> f64 { return math.sign(x) }
floor_f64 :: proc "c" (x: f64) -> f64 { return math.floor(x) } @(require_results) floor_f64 :: proc "c" (x: f64) -> f64 { return math.floor(x) }
round_f64 :: proc "c" (x: f64) -> f64 { return math.round(x) } @(require_results) round_f64 :: proc "c" (x: f64) -> f64 { return math.round(x) }
ceil_f64 :: proc "c" (x: f64) -> f64 { return math.ceil(x) } @(require_results) ceil_f64 :: proc "c" (x: f64) -> f64 { return math.ceil(x) }
mod_f64 :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) } @(require_results) mod_f64 :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) }
@(require_results)
fract_f64 :: proc "c" (x: f64) -> f64 { fract_f64 :: proc "c" (x: f64) -> f64 {
if x >= 0 { if x >= 0 {
return x - math.trunc(x) return x - math.trunc(x)
File diff suppressed because it is too large Load Diff
+58 -56
View File
@@ -2,34 +2,35 @@ package math_linalg_hlsl
import "core:math" import "core:math"
cos_float :: proc "c" (x: float) -> float { return math.cos(x) } @(require_results) cos_float :: proc "c" (x: float) -> float { return math.cos(x) }
sin_float :: proc "c" (x: float) -> float { return math.sin(x) } @(require_results) sin_float :: proc "c" (x: float) -> float { return math.sin(x) }
tan_float :: proc "c" (x: float) -> float { return math.tan(x) } @(require_results) tan_float :: proc "c" (x: float) -> float { return math.tan(x) }
acos_float :: proc "c" (x: float) -> float { return math.acos(x) } @(require_results) acos_float :: proc "c" (x: float) -> float { return math.acos(x) }
asin_float :: proc "c" (x: float) -> float { return math.asin(x) } @(require_results) asin_float :: proc "c" (x: float) -> float { return math.asin(x) }
atan_float :: proc "c" (x: float) -> float { return math.atan(x) } @(require_results) atan_float :: proc "c" (x: float) -> float { return math.atan(x) }
atan2_float :: proc "c" (y, x: float) -> float { return math.atan2(y, x) } @(require_results) atan2_float :: proc "c" (y, x: float) -> float { return math.atan2(y, x) }
cosh_float :: proc "c" (x: float) -> float { return math.cosh(x) } @(require_results) cosh_float :: proc "c" (x: float) -> float { return math.cosh(x) }
sinh_float :: proc "c" (x: float) -> float { return math.sinh(x) } @(require_results) sinh_float :: proc "c" (x: float) -> float { return math.sinh(x) }
tanh_float :: proc "c" (x: float) -> float { return math.tanh(x) } @(require_results) tanh_float :: proc "c" (x: float) -> float { return math.tanh(x) }
acosh_float :: proc "c" (x: float) -> float { return math.acosh(x) } @(require_results) acosh_float :: proc "c" (x: float) -> float { return math.acosh(x) }
asinh_float :: proc "c" (x: float) -> float { return math.asinh(x) } @(require_results) asinh_float :: proc "c" (x: float) -> float { return math.asinh(x) }
atanh_float :: proc "c" (x: float) -> float { return math.atanh(x) } @(require_results) atanh_float :: proc "c" (x: float) -> float { return math.atanh(x) }
sqrt_float :: proc "c" (x: float) -> float { return math.sqrt(x) } @(require_results) sqrt_float :: proc "c" (x: float) -> float { return math.sqrt(x) }
rsqrt_float :: proc "c" (x: float) -> float { return 1.0/math.sqrt(x) } @(require_results) rsqrt_float :: proc "c" (x: float) -> float { return 1.0/math.sqrt(x) }
rcp_float :: proc "c" (x: float) -> float { return 1.0/x } @(require_results) rcp_float :: proc "c" (x: float) -> float { return 1.0/x }
pow_float :: proc "c" (x, y: float) -> float { return math.pow(x, y) } @(require_results) pow_float :: proc "c" (x, y: float) -> float { return math.pow(x, y) }
exp_float :: proc "c" (x: float) -> float { return math.exp(x) } @(require_results) exp_float :: proc "c" (x: float) -> float { return math.exp(x) }
log_float :: proc "c" (x: float) -> float { return math.ln(x) } @(require_results) log_float :: proc "c" (x: float) -> float { return math.ln(x) }
log2_float :: proc "c" (x: float) -> float { return math.log(x, 2) } @(require_results) log2_float :: proc "c" (x: float) -> float { return math.log(x, 2) }
log10_float :: proc "c" (x: float) -> float { return math.log(x, 10) } @(require_results) log10_float :: proc "c" (x: float) -> float { return math.log(x, 10) }
exp2_float :: proc "c" (x: float) -> float { return math.pow(float(2), x) } @(require_results) exp2_float :: proc "c" (x: float) -> float { return math.pow(float(2), x) }
sign_float :: proc "c" (x: float) -> float { return math.sign(x) } @(require_results) sign_float :: proc "c" (x: float) -> float { return math.sign(x) }
floor_float :: proc "c" (x: float) -> float { return math.floor(x) } @(require_results) floor_float :: proc "c" (x: float) -> float { return math.floor(x) }
round_float :: proc "c" (x: float) -> float { return math.round(x) } @(require_results) round_float :: proc "c" (x: float) -> float { return math.round(x) }
ceil_float :: proc "c" (x: float) -> float { return math.ceil(x) } @(require_results) ceil_float :: proc "c" (x: float) -> float { return math.ceil(x) }
isnan_float :: proc "c" (x: float) -> bool { return math.classify(x) == .NaN} @(require_results) isnan_float :: proc "c" (x: float) -> bool { return math.classify(x) == .NaN}
fmod_float :: proc "c" (x, y: float) -> float { return math.mod(x, y) } @(require_results) fmod_float :: proc "c" (x, y: float) -> float { return math.mod(x, y) }
@(require_results)
frac_float :: proc "c" (x: float) -> float { frac_float :: proc "c" (x: float) -> float {
if x >= 0 { if x >= 0 {
return x - math.trunc(x) return x - math.trunc(x)
@@ -38,34 +39,35 @@ frac_float :: proc "c" (x: float) -> float {
} }
cos_double :: proc "c" (x: double) -> double { return math.cos(x) } @(require_results) cos_double :: proc "c" (x: double) -> double { return math.cos(x) }
sin_double :: proc "c" (x: double) -> double { return math.sin(x) } @(require_results) sin_double :: proc "c" (x: double) -> double { return math.sin(x) }
tan_double :: proc "c" (x: double) -> double { return math.tan(x) } @(require_results) tan_double :: proc "c" (x: double) -> double { return math.tan(x) }
acos_double :: proc "c" (x: double) -> double { return math.acos(x) } @(require_results) acos_double :: proc "c" (x: double) -> double { return math.acos(x) }
asin_double :: proc "c" (x: double) -> double { return math.asin(x) } @(require_results) asin_double :: proc "c" (x: double) -> double { return math.asin(x) }
atan_double :: proc "c" (x: double) -> double { return math.atan(x) } @(require_results) atan_double :: proc "c" (x: double) -> double { return math.atan(x) }
atan2_double :: proc "c" (y, x: double) -> double { return math.atan2(y, x) } @(require_results) atan2_double :: proc "c" (y, x: double) -> double { return math.atan2(y, x) }
cosh_double :: proc "c" (x: double) -> double { return math.cosh(x) } @(require_results) cosh_double :: proc "c" (x: double) -> double { return math.cosh(x) }
sinh_double :: proc "c" (x: double) -> double { return math.sinh(x) } @(require_results) sinh_double :: proc "c" (x: double) -> double { return math.sinh(x) }
tanh_double :: proc "c" (x: double) -> double { return math.tanh(x) } @(require_results) tanh_double :: proc "c" (x: double) -> double { return math.tanh(x) }
acosh_double :: proc "c" (x: double) -> double { return math.acosh(x) } @(require_results) acosh_double :: proc "c" (x: double) -> double { return math.acosh(x) }
asinh_double :: proc "c" (x: double) -> double { return math.asinh(x) } @(require_results) asinh_double :: proc "c" (x: double) -> double { return math.asinh(x) }
atanh_double :: proc "c" (x: double) -> double { return math.atanh(x) } @(require_results) atanh_double :: proc "c" (x: double) -> double { return math.atanh(x) }
sqrt_double :: proc "c" (x: double) -> double { return math.sqrt(x) } @(require_results) sqrt_double :: proc "c" (x: double) -> double { return math.sqrt(x) }
rsqrt_double :: proc "c" (x: double) -> double { return 1.0/math.sqrt(x) } @(require_results) rsqrt_double :: proc "c" (x: double) -> double { return 1.0/math.sqrt(x) }
rcp_double :: proc "c" (x: double) -> double { return 1.0/x } @(require_results) rcp_double :: proc "c" (x: double) -> double { return 1.0/x }
pow_double :: proc "c" (x, y: double) -> double { return math.pow(x, y) } @(require_results) pow_double :: proc "c" (x, y: double) -> double { return math.pow(x, y) }
exp_double :: proc "c" (x: double) -> double { return math.exp(x) } @(require_results) exp_double :: proc "c" (x: double) -> double { return math.exp(x) }
log_double :: proc "c" (x: double) -> double { return math.ln(x) } @(require_results) log_double :: proc "c" (x: double) -> double { return math.ln(x) }
log2_double :: proc "c" (x: double) -> double { return math.log(x, 2) } @(require_results) log2_double :: proc "c" (x: double) -> double { return math.log(x, 2) }
log10_double :: proc "c" (x: double) -> double { return math.log(x, 10) } @(require_results) log10_double :: proc "c" (x: double) -> double { return math.log(x, 10) }
exp2_double :: proc "c" (x: double) -> double { return math.pow(double(2), x) } @(require_results) exp2_double :: proc "c" (x: double) -> double { return math.pow(double(2), x) }
sign_double :: proc "c" (x: double) -> double { return math.sign(x) } @(require_results) sign_double :: proc "c" (x: double) -> double { return math.sign(x) }
floor_double :: proc "c" (x: double) -> double { return math.floor(x) } @(require_results) floor_double :: proc "c" (x: double) -> double { return math.floor(x) }
round_double :: proc "c" (x: double) -> double { return math.round(x) } @(require_results) round_double :: proc "c" (x: double) -> double { return math.round(x) }
ceil_double :: proc "c" (x: double) -> double { return math.ceil(x) } @(require_results) ceil_double :: proc "c" (x: double) -> double { return math.ceil(x) }
isnan_double :: proc "c" (x: double) -> bool { return math.classify(x) == .NaN} @(require_results) isnan_double :: proc "c" (x: double) -> bool { return math.classify(x) == .NaN}
fmod_double :: proc "c" (x, y: double) -> double { return math.mod(x, y) } @(require_results) fmod_double :: proc "c" (x, y: double) -> double { return math.mod(x, y) }
@(require_results)
frac_double :: proc "c" (x: double) -> double { frac_double :: proc "c" (x: double) -> double {
if x >= 0 { if x >= 0 {
return x - math.trunc(x) return x - math.trunc(x)
File diff suppressed because it is too large Load Diff
+200 -100
View File
@@ -2,7 +2,8 @@ package linalg
import "core:math" import "core:math"
euler_angles_from_matrix3_f16 :: proc(m: Matrix3f16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m)
@@ -19,7 +20,8 @@ euler_angles_from_matrix3_f16 :: proc(m: Matrix3f16, order: Euler_Angle_Order) -
} }
return return
} }
euler_angles_from_matrix4_f16 :: proc(m: Matrix4f16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m)
@@ -36,7 +38,8 @@ euler_angles_from_matrix4_f16 :: proc(m: Matrix4f16, order: Euler_Angle_Order) -
} }
return return
} }
euler_angles_from_quaternion_f16 :: proc(m: Quaternionf16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_from_quaternion_f16 :: proc "contextless" (m: Quaternionf16, order: Euler_Angle_Order) -> (t1, t2, t3: f16) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m)
@@ -54,7 +57,8 @@ euler_angles_from_quaternion_f16 :: proc(m: Quaternionf16, order: Euler_Angle_Or
return return
} }
matrix3_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_f16 :: proc "contextless" (t1, t2, t3: f16, order: Euler_Angle_Order) -> (m: Matrix3f16) {
switch order { switch order {
case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3); case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3); case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -71,7 +75,8 @@ matrix3_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order)
} }
return return
} }
matrix4_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_f16 :: proc "contextless" (t1, t2, t3: f16, order: Euler_Angle_Order) -> (m: Matrix4f16) {
switch order { switch order {
case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3); case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3); case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -89,7 +94,8 @@ matrix4_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order)
return return
} }
quaternion_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Order) -> Quaternionf16 { @(require_results)
quaternion_from_euler_angles_f16 :: proc "contextless" (t1, t2, t3: f16, order: Euler_Angle_Order) -> Quaternionf16 {
X :: quaternion_from_euler_angle_x X :: quaternion_from_euler_angle_x
Y :: quaternion_from_euler_angle_y Y :: quaternion_from_euler_angle_y
Z :: quaternion_from_euler_angle_z Z :: quaternion_from_euler_angle_z
@@ -117,17 +123,21 @@ quaternion_from_euler_angles_f16 :: proc(t1, t2, t3: f16, order: Euler_Angle_Ord
// Quaternionf16s // Quaternionf16s
quaternion_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (q: Quaternionf16) { @(require_results)
quaternion_from_euler_angle_x_f16 :: proc "contextless" (angle_x: f16) -> (q: Quaternionf16) {
return quaternion_angle_axis_f16(angle_x, {1, 0, 0}) return quaternion_angle_axis_f16(angle_x, {1, 0, 0})
} }
quaternion_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (q: Quaternionf16) { @(require_results)
quaternion_from_euler_angle_y_f16 :: proc "contextless" (angle_y: f16) -> (q: Quaternionf16) {
return quaternion_angle_axis_f16(angle_y, {0, 1, 0}) return quaternion_angle_axis_f16(angle_y, {0, 1, 0})
} }
quaternion_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (q: Quaternionf16) { @(require_results)
quaternion_from_euler_angle_z_f16 :: proc "contextless" (angle_z: f16) -> (q: Quaternionf16) {
return quaternion_angle_axis_f16(angle_z, {0, 0, 1}) return quaternion_angle_axis_f16(angle_z, {0, 0, 1})
} }
quaternion_from_pitch_yaw_roll_f16 :: proc(pitch, yaw, roll: f16) -> Quaternionf16 { @(require_results)
quaternion_from_pitch_yaw_roll_f16 :: proc "contextless" (pitch, yaw, roll: f16) -> Quaternionf16 {
a, b, c := pitch, yaw, roll a, b, c := pitch, yaw, roll
ca, sa := math.cos(a*0.5), math.sin(a*0.5) ca, sa := math.cos(a*0.5), math.sin(a*0.5)
@@ -142,11 +152,13 @@ quaternion_from_pitch_yaw_roll_f16 :: proc(pitch, yaw, roll: f16) -> Quaternionf
return q return q
} }
roll_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 { @(require_results)
roll_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> f16 {
return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z) return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z)
} }
pitch_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 { @(require_results)
pitch_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> f16 {
y := 2 * (q.y*q.z + q.w*q.w) y := 2 * (q.y*q.z + q.w*q.w)
x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z
@@ -157,52 +169,66 @@ pitch_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 {
return math.atan2(y, x) return math.atan2(y, x)
} }
yaw_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 { @(require_results)
yaw_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> f16 {
return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1)) return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1))
} }
pitch_yaw_roll_from_quaternion_f16 :: proc(q: Quaternionf16) -> (pitch, yaw, roll: f16) { @(require_results)
pitch_yaw_roll_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (pitch, yaw, roll: f16) {
pitch = pitch_from_quaternion(q) pitch = pitch_from_quaternion(q)
yaw = yaw_from_quaternion(q) yaw = yaw_from_quaternion(q)
roll = roll_from_quaternion(q) roll = roll_from_quaternion(q)
return return
} }
euler_angles_xyz_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xyz_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yxz_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yxz_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xzx_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xzx_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xyx_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xyx_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yxy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yxy_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yzy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yzy_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zyz_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zyz_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zxz_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zxz_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xzy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xzy_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yzx_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yzx_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zyx_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zyx_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zxy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zxy_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> (t1, t2, t3: f16) {
return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q))
} }
@@ -210,7 +236,8 @@ euler_angles_zxy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f
// Matrix3 // Matrix3
matrix3_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angle_x_f16 :: proc "contextless" (angle_x: f16) -> (m: Matrix3f16) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
m[0, 0] = 1 m[0, 0] = 1
m[1, 1] = +cos_x m[1, 1] = +cos_x
@@ -219,7 +246,8 @@ matrix3_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix3f16) {
m[2, 2] = +cos_x m[2, 2] = +cos_x
return return
} }
matrix3_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angle_y_f16 :: proc "contextless" (angle_y: f16) -> (m: Matrix3f16) {
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = +cos_y m[0, 0] = +cos_y
m[0, 2] = -sin_y m[0, 2] = -sin_y
@@ -228,7 +256,8 @@ matrix3_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix3f16) {
m[2, 2] = +cos_y m[2, 2] = +cos_y
return return
} }
matrix3_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angle_z_f16 :: proc "contextless" (angle_z: f16) -> (m: Matrix3f16) {
cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
m[0, 0] = +cos_z m[0, 0] = +cos_z
m[0, 1] = +sin_z m[0, 1] = +sin_z
@@ -239,7 +268,8 @@ matrix3_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix3f16) {
} }
matrix3_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_derived_euler_angle_x_f16 :: proc "contextless" (angle_x: f16, angular_velocity_x: f16) -> (m: Matrix3f16) {
cos_x := math.cos(angle_x) * angular_velocity_x cos_x := math.cos(angle_x) * angular_velocity_x
sin_x := math.sin(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x
m[0, 0] = 1 m[0, 0] = 1
@@ -249,7 +279,8 @@ matrix3_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x:
m[2, 2] = +cos_x m[2, 2] = +cos_x
return return
} }
matrix3_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_derived_euler_angle_y_f16 :: proc "contextless" (angle_y: f16, angular_velocity_y: f16) -> (m: Matrix3f16) {
cos_y := math.cos(angle_y) * angular_velocity_y cos_y := math.cos(angle_y) * angular_velocity_y
sin_y := math.sin(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y
m[0, 0] = +cos_y m[0, 0] = +cos_y
@@ -259,7 +290,8 @@ matrix3_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y:
m[2, 2] = +cos_y m[2, 2] = +cos_y
return return
} }
matrix3_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_derived_euler_angle_z_f16 :: proc "contextless" (angle_z: f16, angular_velocity_z: f16) -> (m: Matrix3f16) {
cos_z := math.cos(angle_z) * angular_velocity_z cos_z := math.cos(angle_z) * angular_velocity_z
sin_z := math.sin(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z
m[0, 0] = +cos_z m[0, 0] = +cos_z
@@ -271,7 +303,8 @@ matrix3_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z:
} }
matrix3_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_xy_f16 :: proc "contextless" (angle_x, angle_y: f16) -> (m: Matrix3f16) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -286,7 +319,8 @@ matrix3_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix3f1
} }
matrix3_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_yx_f16 :: proc "contextless" (angle_y, angle_x: f16) -> (m: Matrix3f16) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -300,21 +334,26 @@ matrix3_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix3f1
return return
} }
matrix3_from_euler_angles_xz_f16 :: proc(angle_x, angle_z: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_xz_f16 :: proc "contextless" (angle_x, angle_z: f16) -> (m: Matrix3f16) {
return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z)) return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z))
} }
matrix3_from_euler_angles_zx_f16 :: proc(angle_z, angle_x: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_zx_f16 :: proc "contextless" (angle_z, angle_x: f16) -> (m: Matrix3f16) {
return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x)) return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x))
} }
matrix3_from_euler_angles_yz_f16 :: proc(angle_y, angle_z: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_yz_f16 :: proc "contextless" (angle_y, angle_z: f16) -> (m: Matrix3f16) {
return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z)) return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z))
} }
matrix3_from_euler_angles_zy_f16 :: proc(angle_z, angle_y: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_zy_f16 :: proc "contextless" (angle_z, angle_y: f16) -> (m: Matrix3f16) {
return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y)) return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y))
} }
matrix3_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_xyz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(-t1) c1 := math.cos(-t1)
c2 := math.cos(-t2) c2 := math.cos(-t2)
c3 := math.cos(-t3) c3 := math.cos(-t3)
@@ -334,7 +373,8 @@ matrix3_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_yxz_f16 :: proc "contextless" (yaw, pitch, roll: f16) -> (m: Matrix3f16) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -354,7 +394,8 @@ matrix3_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f
return return
} }
matrix3_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_xzx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -374,7 +415,8 @@ matrix3_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_xyx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -394,7 +436,8 @@ matrix3_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_yxy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -414,7 +457,8 @@ matrix3_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_yzy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -434,7 +478,8 @@ matrix3_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_zyz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -454,7 +499,8 @@ matrix3_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_zxz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -475,7 +521,8 @@ matrix3_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
} }
matrix3_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_xzy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -495,7 +542,8 @@ matrix3_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_yzx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -515,7 +563,8 @@ matrix3_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_zyx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -535,7 +584,8 @@ matrix3_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
return return
} }
matrix3_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_euler_angles_zxy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix3f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -556,7 +606,8 @@ matrix3_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) {
} }
matrix3_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f16) { @(require_results)
matrix3_from_yaw_pitch_roll_f16 :: proc "contextless" (yaw, pitch, roll: f16) -> (m: Matrix3f16) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -576,7 +627,8 @@ matrix3_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f16
return m return m
} }
euler_angles_xyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xyz_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[1, 2], m[2, 2]) T1 := math.atan2(m[1, 2], m[2, 2])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
T2 := math.atan2(-m[0, 2], C2) T2 := math.atan2(-m[0, 2], C2)
@@ -589,7 +641,8 @@ euler_angles_xyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_yxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yxz_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[0, 2], m[2, 2]) T1 := math.atan2(m[0, 2], m[2, 2])
C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
T2 := math.atan2(-m[1, 2], C2) T2 := math.atan2(-m[1, 2], C2)
@@ -602,7 +655,8 @@ euler_angles_yxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_xzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xzx_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[2, 0], m[1, 0]) T1 := math.atan2(m[2, 0], m[1, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -615,7 +669,8 @@ euler_angles_xzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_xyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xyx_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[1, 0], -m[2, 0]) T1 := math.atan2(m[1, 0], -m[2, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -628,7 +683,8 @@ euler_angles_xyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_yxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yxy_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[0, 1], m[2, 1]) T1 := math.atan2(m[0, 1], m[2, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -641,7 +697,8 @@ euler_angles_yxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_yzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yzy_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[2, 1], -m[0, 1]) T1 := math.atan2(m[2, 1], -m[0, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -653,7 +710,8 @@ euler_angles_yzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
t3 = T3 t3 = T3
return return
} }
euler_angles_zyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zyz_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[1, 2], m[0, 2]) T1 := math.atan2(m[1, 2], m[0, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -666,7 +724,8 @@ euler_angles_zyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_zxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zxz_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[0, 2], -m[1, 2]) T1 := math.atan2(m[0, 2], -m[1, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -679,7 +738,8 @@ euler_angles_zxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_xzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xzy_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[2, 1], m[1, 1]) T1 := math.atan2(m[2, 1], m[1, 1])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
T2 := math.atan2(-m[0, 1], C2) T2 := math.atan2(-m[0, 1], C2)
@@ -692,7 +752,8 @@ euler_angles_xzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_yzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yzx_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(-m[2, 0], m[0, 0]) T1 := math.atan2(-m[2, 0], m[0, 0])
C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
T2 := math.atan2(m[1, 0], C2) T2 := math.atan2(m[1, 0], C2)
@@ -705,7 +766,8 @@ euler_angles_yzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_zyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zyx_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[1, 0], m[0, 0]) T1 := math.atan2(m[1, 0], m[0, 0])
C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
T2 := math.atan2(-m[2, 0], C2) T2 := math.atan2(-m[2, 0], C2)
@@ -718,7 +780,8 @@ euler_angles_zyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_zxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zxy_from_matrix3_f16 :: proc "contextless" (m: Matrix3f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(-m[0, 1], m[1, 1]) T1 := math.atan2(-m[0, 1], m[1, 1])
C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
T2 := math.atan2(m[2, 1], C2) T2 := math.atan2(m[2, 1], C2)
@@ -735,7 +798,8 @@ euler_angles_zxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) {
// Matrix4 // Matrix4
matrix4_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angle_x_f16 :: proc "contextless" (angle_x: f16) -> (m: Matrix4f16) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
m[0, 0] = 1 m[0, 0] = 1
m[1, 1] = +cos_x m[1, 1] = +cos_x
@@ -745,7 +809,8 @@ matrix4_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix4f16) {
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angle_y_f16 :: proc "contextless" (angle_y: f16) -> (m: Matrix4f16) {
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = +cos_y m[0, 0] = +cos_y
m[0, 2] = -sin_y m[0, 2] = -sin_y
@@ -755,7 +820,8 @@ matrix4_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix4f16) {
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angle_z_f16 :: proc "contextless" (angle_z: f16) -> (m: Matrix4f16) {
cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
m[0, 0] = +cos_z m[0, 0] = +cos_z
m[0, 1] = +sin_z m[0, 1] = +sin_z
@@ -767,7 +833,8 @@ matrix4_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix4f16) {
} }
matrix4_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_derived_euler_angle_x_f16 :: proc "contextless" (angle_x: f16, angular_velocity_x: f16) -> (m: Matrix4f16) {
cos_x := math.cos(angle_x) * angular_velocity_x cos_x := math.cos(angle_x) * angular_velocity_x
sin_x := math.sin(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x
m[0, 0] = 1 m[0, 0] = 1
@@ -778,7 +845,8 @@ matrix4_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x:
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_derived_euler_angle_y_f16 :: proc "contextless" (angle_y: f16, angular_velocity_y: f16) -> (m: Matrix4f16) {
cos_y := math.cos(angle_y) * angular_velocity_y cos_y := math.cos(angle_y) * angular_velocity_y
sin_y := math.sin(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y
m[0, 0] = +cos_y m[0, 0] = +cos_y
@@ -789,7 +857,8 @@ matrix4_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y:
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_derived_euler_angle_z_f16 :: proc "contextless" (angle_z: f16, angular_velocity_z: f16) -> (m: Matrix4f16) {
cos_z := math.cos(angle_z) * angular_velocity_z cos_z := math.cos(angle_z) * angular_velocity_z
sin_z := math.sin(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z
m[0, 0] = +cos_z m[0, 0] = +cos_z
@@ -802,7 +871,8 @@ matrix4_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z:
} }
matrix4_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_xy_f16 :: proc "contextless" (angle_x, angle_y: f16) -> (m: Matrix4f16) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -818,7 +888,8 @@ matrix4_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix4f1
} }
matrix4_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_yx_f16 :: proc "contextless" (angle_y, angle_x: f16) -> (m: Matrix4f16) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -833,21 +904,26 @@ matrix4_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix4f1
return return
} }
matrix4_from_euler_angles_xz_f16 :: proc(angle_x, angle_z: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_xz_f16 :: proc "contextless" (angle_x, angle_z: f16) -> (m: Matrix4f16) {
return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z)) return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z))
} }
matrix4_from_euler_angles_zx_f16 :: proc(angle_z, angle_x: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_zx_f16 :: proc "contextless" (angle_z, angle_x: f16) -> (m: Matrix4f16) {
return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x)) return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x))
} }
matrix4_from_euler_angles_yz_f16 :: proc(angle_y, angle_z: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_yz_f16 :: proc "contextless" (angle_y, angle_z: f16) -> (m: Matrix4f16) {
return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z)) return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z))
} }
matrix4_from_euler_angles_zy_f16 :: proc(angle_z, angle_y: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_zy_f16 :: proc "contextless" (angle_z, angle_y: f16) -> (m: Matrix4f16) {
return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y)) return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y))
} }
matrix4_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_xyz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(-t1) c1 := math.cos(-t1)
c2 := math.cos(-t2) c2 := math.cos(-t2)
c3 := math.cos(-t3) c3 := math.cos(-t3)
@@ -874,7 +950,8 @@ matrix4_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_yxz_f16 :: proc "contextless" (yaw, pitch, roll: f16) -> (m: Matrix4f16) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -901,7 +978,8 @@ matrix4_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f
return return
} }
matrix4_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_xzx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -928,7 +1006,8 @@ matrix4_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_xyx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -955,7 +1034,8 @@ matrix4_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_yxy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -982,7 +1062,8 @@ matrix4_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_yzy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1009,7 +1090,8 @@ matrix4_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_zyz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1036,7 +1118,8 @@ matrix4_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_zxz_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1064,7 +1147,8 @@ matrix4_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
} }
matrix4_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_xzy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1091,7 +1175,8 @@ matrix4_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_yzx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1118,7 +1203,8 @@ matrix4_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_zyx_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1145,7 +1231,8 @@ matrix4_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
return return
} }
matrix4_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_euler_angles_zxy_f16 :: proc "contextless" (t1, t2, t3: f16) -> (m: Matrix4f16) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1173,7 +1260,8 @@ matrix4_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) {
} }
matrix4_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f16) { @(require_results)
matrix4_from_yaw_pitch_roll_f16 :: proc "contextless" (yaw, pitch, roll: f16) -> (m: Matrix4f16) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -1200,7 +1288,8 @@ matrix4_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f16
return m return m
} }
euler_angles_xyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xyz_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[1, 2], m[2, 2]) T1 := math.atan2(m[1, 2], m[2, 2])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
T2 := math.atan2(-m[0, 2], C2) T2 := math.atan2(-m[0, 2], C2)
@@ -1213,7 +1302,8 @@ euler_angles_xyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_yxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yxz_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[0, 2], m[2, 2]) T1 := math.atan2(m[0, 2], m[2, 2])
C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
T2 := math.atan2(-m[1, 2], C2) T2 := math.atan2(-m[1, 2], C2)
@@ -1226,7 +1316,8 @@ euler_angles_yxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_xzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xzx_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[2, 0], m[1, 0]) T1 := math.atan2(m[2, 0], m[1, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -1239,7 +1330,8 @@ euler_angles_xzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_xyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xyx_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[1, 0], -m[2, 0]) T1 := math.atan2(m[1, 0], -m[2, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -1252,7 +1344,8 @@ euler_angles_xyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_yxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yxy_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[0, 1], m[2, 1]) T1 := math.atan2(m[0, 1], m[2, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -1265,7 +1358,8 @@ euler_angles_yxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_yzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yzy_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[2, 1], -m[0, 1]) T1 := math.atan2(m[2, 1], -m[0, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -1277,7 +1371,8 @@ euler_angles_yzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
t3 = T3 t3 = T3
return return
} }
euler_angles_zyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zyz_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[1, 2], m[0, 2]) T1 := math.atan2(m[1, 2], m[0, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -1290,7 +1385,8 @@ euler_angles_zyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_zxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zxz_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[0, 2], -m[1, 2]) T1 := math.atan2(m[0, 2], -m[1, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -1303,7 +1399,8 @@ euler_angles_zxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_xzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_xzy_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[2, 1], m[1, 1]) T1 := math.atan2(m[2, 1], m[1, 1])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
T2 := math.atan2(-m[0, 1], C2) T2 := math.atan2(-m[0, 1], C2)
@@ -1316,7 +1413,8 @@ euler_angles_xzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_yzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_yzx_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(-m[2, 0], m[0, 0]) T1 := math.atan2(-m[2, 0], m[0, 0])
C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
T2 := math.atan2(m[1, 0], C2) T2 := math.atan2(m[1, 0], C2)
@@ -1329,7 +1427,8 @@ euler_angles_yzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_zyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zyx_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(m[1, 0], m[0, 0]) T1 := math.atan2(m[1, 0], m[0, 0])
C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
T2 := math.atan2(-m[2, 0], C2) T2 := math.atan2(-m[2, 0], C2)
@@ -1342,7 +1441,8 @@ euler_angles_zyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) {
return return
} }
euler_angles_zxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { @(require_results)
euler_angles_zxy_from_matrix4_f16 :: proc "contextless" (m: Matrix4f16) -> (t1, t2, t3: f16) {
T1 := math.atan2(-m[0, 1], m[1, 1]) T1 := math.atan2(-m[0, 1], m[1, 1])
C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
T2 := math.atan2(m[2, 1], C2) T2 := math.atan2(m[2, 1], C2)
+200 -100
View File
@@ -2,7 +2,8 @@ package linalg
import "core:math" import "core:math"
euler_angles_from_matrix3_f32 :: proc(m: Matrix3f32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m)
@@ -19,7 +20,8 @@ euler_angles_from_matrix3_f32 :: proc(m: Matrix3f32, order: Euler_Angle_Order) -
} }
return return
} }
euler_angles_from_matrix4_f32 :: proc(m: Matrix4f32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m)
@@ -36,7 +38,8 @@ euler_angles_from_matrix4_f32 :: proc(m: Matrix4f32, order: Euler_Angle_Order) -
} }
return return
} }
euler_angles_from_quaternion_f32 :: proc(m: Quaternionf32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_from_quaternion_f32 :: proc "contextless" (m: Quaternionf32, order: Euler_Angle_Order) -> (t1, t2, t3: f32) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m)
@@ -54,7 +57,8 @@ euler_angles_from_quaternion_f32 :: proc(m: Quaternionf32, order: Euler_Angle_Or
return return
} }
matrix3_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_f32 :: proc "contextless" (t1, t2, t3: f32, order: Euler_Angle_Order) -> (m: Matrix3f32) {
switch order { switch order {
case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3); case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3); case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -71,7 +75,8 @@ matrix3_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order)
} }
return return
} }
matrix4_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_f32 :: proc "contextless" (t1, t2, t3: f32, order: Euler_Angle_Order) -> (m: Matrix4f32) {
switch order { switch order {
case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3); case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3); case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -89,7 +94,8 @@ matrix4_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order)
return return
} }
quaternion_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Order) -> Quaternionf32 { @(require_results)
quaternion_from_euler_angles_f32 :: proc "contextless" (t1, t2, t3: f32, order: Euler_Angle_Order) -> Quaternionf32 {
X :: quaternion_from_euler_angle_x X :: quaternion_from_euler_angle_x
Y :: quaternion_from_euler_angle_y Y :: quaternion_from_euler_angle_y
Z :: quaternion_from_euler_angle_z Z :: quaternion_from_euler_angle_z
@@ -117,17 +123,21 @@ quaternion_from_euler_angles_f32 :: proc(t1, t2, t3: f32, order: Euler_Angle_Ord
// Quaternionf32s // Quaternionf32s
quaternion_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (q: Quaternionf32) { @(require_results)
quaternion_from_euler_angle_x_f32 :: proc "contextless" (angle_x: f32) -> (q: Quaternionf32) {
return quaternion_angle_axis_f32(angle_x, {1, 0, 0}) return quaternion_angle_axis_f32(angle_x, {1, 0, 0})
} }
quaternion_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (q: Quaternionf32) { @(require_results)
quaternion_from_euler_angle_y_f32 :: proc "contextless" (angle_y: f32) -> (q: Quaternionf32) {
return quaternion_angle_axis_f32(angle_y, {0, 1, 0}) return quaternion_angle_axis_f32(angle_y, {0, 1, 0})
} }
quaternion_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (q: Quaternionf32) { @(require_results)
quaternion_from_euler_angle_z_f32 :: proc "contextless" (angle_z: f32) -> (q: Quaternionf32) {
return quaternion_angle_axis_f32(angle_z, {0, 0, 1}) return quaternion_angle_axis_f32(angle_z, {0, 0, 1})
} }
quaternion_from_pitch_yaw_roll_f32 :: proc(pitch, yaw, roll: f32) -> Quaternionf32 { @(require_results)
quaternion_from_pitch_yaw_roll_f32 :: proc "contextless" (pitch, yaw, roll: f32) -> Quaternionf32 {
a, b, c := pitch, yaw, roll a, b, c := pitch, yaw, roll
ca, sa := math.cos(a*0.5), math.sin(a*0.5) ca, sa := math.cos(a*0.5), math.sin(a*0.5)
@@ -142,11 +152,13 @@ quaternion_from_pitch_yaw_roll_f32 :: proc(pitch, yaw, roll: f32) -> Quaternionf
return q return q
} }
roll_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 { @(require_results)
roll_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> f32 {
return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z) return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z)
} }
pitch_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 { @(require_results)
pitch_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> f32 {
y := 2 * (q.y*q.z + q.w*q.w) y := 2 * (q.y*q.z + q.w*q.w)
x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z
@@ -157,52 +169,66 @@ pitch_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 {
return math.atan2(y, x) return math.atan2(y, x)
} }
yaw_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 { @(require_results)
yaw_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> f32 {
return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1)) return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1))
} }
pitch_yaw_roll_from_quaternion_f32 :: proc(q: Quaternionf32) -> (pitch, yaw, roll: f32) { @(require_results)
pitch_yaw_roll_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (pitch, yaw, roll: f32) {
pitch = pitch_from_quaternion(q) pitch = pitch_from_quaternion(q)
yaw = yaw_from_quaternion(q) yaw = yaw_from_quaternion(q)
roll = roll_from_quaternion(q) roll = roll_from_quaternion(q)
return return
} }
euler_angles_xyz_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xyz_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yxz_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yxz_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xzx_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xzx_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xyx_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xyx_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yxy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yxy_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yzy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yzy_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zyz_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zyz_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zxz_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zxz_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xzy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xzy_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yzx_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yzx_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zyx_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zyx_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zxy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zxy_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> (t1, t2, t3: f32) {
return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q))
} }
@@ -210,7 +236,8 @@ euler_angles_zxy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f
// Matrix3 // Matrix3
matrix3_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angle_x_f32 :: proc "contextless" (angle_x: f32) -> (m: Matrix3f32) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
m[0, 0] = 1 m[0, 0] = 1
m[1, 1] = +cos_x m[1, 1] = +cos_x
@@ -219,7 +246,8 @@ matrix3_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix3f32) {
m[2, 2] = +cos_x m[2, 2] = +cos_x
return return
} }
matrix3_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angle_y_f32 :: proc "contextless" (angle_y: f32) -> (m: Matrix3f32) {
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = +cos_y m[0, 0] = +cos_y
m[0, 2] = -sin_y m[0, 2] = -sin_y
@@ -228,7 +256,8 @@ matrix3_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix3f32) {
m[2, 2] = +cos_y m[2, 2] = +cos_y
return return
} }
matrix3_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angle_z_f32 :: proc "contextless" (angle_z: f32) -> (m: Matrix3f32) {
cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
m[0, 0] = +cos_z m[0, 0] = +cos_z
m[0, 1] = +sin_z m[0, 1] = +sin_z
@@ -239,7 +268,8 @@ matrix3_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix3f32) {
} }
matrix3_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_derived_euler_angle_x_f32 :: proc "contextless" (angle_x: f32, angular_velocity_x: f32) -> (m: Matrix3f32) {
cos_x := math.cos(angle_x) * angular_velocity_x cos_x := math.cos(angle_x) * angular_velocity_x
sin_x := math.sin(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x
m[0, 0] = 1 m[0, 0] = 1
@@ -249,7 +279,8 @@ matrix3_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x:
m[2, 2] = +cos_x m[2, 2] = +cos_x
return return
} }
matrix3_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_derived_euler_angle_y_f32 :: proc "contextless" (angle_y: f32, angular_velocity_y: f32) -> (m: Matrix3f32) {
cos_y := math.cos(angle_y) * angular_velocity_y cos_y := math.cos(angle_y) * angular_velocity_y
sin_y := math.sin(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y
m[0, 0] = +cos_y m[0, 0] = +cos_y
@@ -259,7 +290,8 @@ matrix3_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y:
m[2, 2] = +cos_y m[2, 2] = +cos_y
return return
} }
matrix3_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_derived_euler_angle_z_f32 :: proc "contextless" (angle_z: f32, angular_velocity_z: f32) -> (m: Matrix3f32) {
cos_z := math.cos(angle_z) * angular_velocity_z cos_z := math.cos(angle_z) * angular_velocity_z
sin_z := math.sin(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z
m[0, 0] = +cos_z m[0, 0] = +cos_z
@@ -271,7 +303,8 @@ matrix3_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z:
} }
matrix3_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_xy_f32 :: proc "contextless" (angle_x, angle_y: f32) -> (m: Matrix3f32) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -286,7 +319,8 @@ matrix3_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix3f3
} }
matrix3_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_yx_f32 :: proc "contextless" (angle_y, angle_x: f32) -> (m: Matrix3f32) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -300,21 +334,26 @@ matrix3_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix3f3
return return
} }
matrix3_from_euler_angles_xz_f32 :: proc(angle_x, angle_z: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_xz_f32 :: proc "contextless" (angle_x, angle_z: f32) -> (m: Matrix3f32) {
return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z)) return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z))
} }
matrix3_from_euler_angles_zx_f32 :: proc(angle_z, angle_x: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_zx_f32 :: proc "contextless" (angle_z, angle_x: f32) -> (m: Matrix3f32) {
return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x)) return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x))
} }
matrix3_from_euler_angles_yz_f32 :: proc(angle_y, angle_z: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_yz_f32 :: proc "contextless" (angle_y, angle_z: f32) -> (m: Matrix3f32) {
return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z)) return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z))
} }
matrix3_from_euler_angles_zy_f32 :: proc(angle_z, angle_y: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_zy_f32 :: proc "contextless" (angle_z, angle_y: f32) -> (m: Matrix3f32) {
return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y)) return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y))
} }
matrix3_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_xyz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(-t1) c1 := math.cos(-t1)
c2 := math.cos(-t2) c2 := math.cos(-t2)
c3 := math.cos(-t3) c3 := math.cos(-t3)
@@ -334,7 +373,8 @@ matrix3_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_yxz_f32 :: proc "contextless" (yaw, pitch, roll: f32) -> (m: Matrix3f32) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -354,7 +394,8 @@ matrix3_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f
return return
} }
matrix3_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_xzx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -374,7 +415,8 @@ matrix3_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_xyx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -394,7 +436,8 @@ matrix3_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_yxy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -414,7 +457,8 @@ matrix3_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_yzy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -434,7 +478,8 @@ matrix3_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_zyz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -454,7 +499,8 @@ matrix3_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_zxz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -475,7 +521,8 @@ matrix3_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
} }
matrix3_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_xzy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -495,7 +542,8 @@ matrix3_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_yzx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -515,7 +563,8 @@ matrix3_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_zyx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -535,7 +584,8 @@ matrix3_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
return return
} }
matrix3_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_euler_angles_zxy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix3f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -556,7 +606,8 @@ matrix3_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) {
} }
matrix3_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f32) { @(require_results)
matrix3_from_yaw_pitch_roll_f32 :: proc "contextless" (yaw, pitch, roll: f32) -> (m: Matrix3f32) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -576,7 +627,8 @@ matrix3_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f32
return m return m
} }
euler_angles_xyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xyz_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[1, 2], m[2, 2]) T1 := math.atan2(m[1, 2], m[2, 2])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
T2 := math.atan2(-m[0, 2], C2) T2 := math.atan2(-m[0, 2], C2)
@@ -589,7 +641,8 @@ euler_angles_xyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_yxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yxz_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[0, 2], m[2, 2]) T1 := math.atan2(m[0, 2], m[2, 2])
C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
T2 := math.atan2(-m[1, 2], C2) T2 := math.atan2(-m[1, 2], C2)
@@ -602,7 +655,8 @@ euler_angles_yxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_xzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xzx_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[2, 0], m[1, 0]) T1 := math.atan2(m[2, 0], m[1, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -615,7 +669,8 @@ euler_angles_xzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_xyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xyx_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[1, 0], -m[2, 0]) T1 := math.atan2(m[1, 0], -m[2, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -628,7 +683,8 @@ euler_angles_xyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_yxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yxy_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[0, 1], m[2, 1]) T1 := math.atan2(m[0, 1], m[2, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -641,7 +697,8 @@ euler_angles_yxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_yzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yzy_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[2, 1], -m[0, 1]) T1 := math.atan2(m[2, 1], -m[0, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -653,7 +710,8 @@ euler_angles_yzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
t3 = T3 t3 = T3
return return
} }
euler_angles_zyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zyz_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[1, 2], m[0, 2]) T1 := math.atan2(m[1, 2], m[0, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -666,7 +724,8 @@ euler_angles_zyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_zxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zxz_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[0, 2], -m[1, 2]) T1 := math.atan2(m[0, 2], -m[1, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -679,7 +738,8 @@ euler_angles_zxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_xzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xzy_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[2, 1], m[1, 1]) T1 := math.atan2(m[2, 1], m[1, 1])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
T2 := math.atan2(-m[0, 1], C2) T2 := math.atan2(-m[0, 1], C2)
@@ -692,7 +752,8 @@ euler_angles_xzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_yzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yzx_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(-m[2, 0], m[0, 0]) T1 := math.atan2(-m[2, 0], m[0, 0])
C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
T2 := math.atan2(m[1, 0], C2) T2 := math.atan2(m[1, 0], C2)
@@ -705,7 +766,8 @@ euler_angles_yzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_zyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zyx_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[1, 0], m[0, 0]) T1 := math.atan2(m[1, 0], m[0, 0])
C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
T2 := math.atan2(-m[2, 0], C2) T2 := math.atan2(-m[2, 0], C2)
@@ -718,7 +780,8 @@ euler_angles_zyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_zxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zxy_from_matrix3_f32 :: proc "contextless" (m: Matrix3f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(-m[0, 1], m[1, 1]) T1 := math.atan2(-m[0, 1], m[1, 1])
C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
T2 := math.atan2(m[2, 1], C2) T2 := math.atan2(m[2, 1], C2)
@@ -735,7 +798,8 @@ euler_angles_zxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) {
// Matrix4 // Matrix4
matrix4_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angle_x_f32 :: proc "contextless" (angle_x: f32) -> (m: Matrix4f32) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
m[0, 0] = 1 m[0, 0] = 1
m[1, 1] = +cos_x m[1, 1] = +cos_x
@@ -745,7 +809,8 @@ matrix4_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix4f32) {
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angle_y_f32 :: proc "contextless" (angle_y: f32) -> (m: Matrix4f32) {
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = +cos_y m[0, 0] = +cos_y
m[0, 2] = -sin_y m[0, 2] = -sin_y
@@ -755,7 +820,8 @@ matrix4_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix4f32) {
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angle_z_f32 :: proc "contextless" (angle_z: f32) -> (m: Matrix4f32) {
cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
m[0, 0] = +cos_z m[0, 0] = +cos_z
m[0, 1] = +sin_z m[0, 1] = +sin_z
@@ -767,7 +833,8 @@ matrix4_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix4f32) {
} }
matrix4_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_derived_euler_angle_x_f32 :: proc "contextless" (angle_x: f32, angular_velocity_x: f32) -> (m: Matrix4f32) {
cos_x := math.cos(angle_x) * angular_velocity_x cos_x := math.cos(angle_x) * angular_velocity_x
sin_x := math.sin(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x
m[0, 0] = 1 m[0, 0] = 1
@@ -778,7 +845,8 @@ matrix4_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x:
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_derived_euler_angle_y_f32 :: proc "contextless" (angle_y: f32, angular_velocity_y: f32) -> (m: Matrix4f32) {
cos_y := math.cos(angle_y) * angular_velocity_y cos_y := math.cos(angle_y) * angular_velocity_y
sin_y := math.sin(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y
m[0, 0] = +cos_y m[0, 0] = +cos_y
@@ -789,7 +857,8 @@ matrix4_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y:
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_derived_euler_angle_z_f32 :: proc "contextless" (angle_z: f32, angular_velocity_z: f32) -> (m: Matrix4f32) {
cos_z := math.cos(angle_z) * angular_velocity_z cos_z := math.cos(angle_z) * angular_velocity_z
sin_z := math.sin(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z
m[0, 0] = +cos_z m[0, 0] = +cos_z
@@ -802,7 +871,8 @@ matrix4_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z:
} }
matrix4_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_xy_f32 :: proc "contextless" (angle_x, angle_y: f32) -> (m: Matrix4f32) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -818,7 +888,8 @@ matrix4_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix4f3
} }
matrix4_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_yx_f32 :: proc "contextless" (angle_y, angle_x: f32) -> (m: Matrix4f32) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -833,21 +904,26 @@ matrix4_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix4f3
return return
} }
matrix4_from_euler_angles_xz_f32 :: proc(angle_x, angle_z: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_xz_f32 :: proc "contextless" (angle_x, angle_z: f32) -> (m: Matrix4f32) {
return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z)) return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z))
} }
matrix4_from_euler_angles_zx_f32 :: proc(angle_z, angle_x: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_zx_f32 :: proc "contextless" (angle_z, angle_x: f32) -> (m: Matrix4f32) {
return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x)) return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x))
} }
matrix4_from_euler_angles_yz_f32 :: proc(angle_y, angle_z: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_yz_f32 :: proc "contextless" (angle_y, angle_z: f32) -> (m: Matrix4f32) {
return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z)) return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z))
} }
matrix4_from_euler_angles_zy_f32 :: proc(angle_z, angle_y: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_zy_f32 :: proc "contextless" (angle_z, angle_y: f32) -> (m: Matrix4f32) {
return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y)) return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y))
} }
matrix4_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_xyz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(-t1) c1 := math.cos(-t1)
c2 := math.cos(-t2) c2 := math.cos(-t2)
c3 := math.cos(-t3) c3 := math.cos(-t3)
@@ -874,7 +950,8 @@ matrix4_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_yxz_f32 :: proc "contextless" (yaw, pitch, roll: f32) -> (m: Matrix4f32) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -901,7 +978,8 @@ matrix4_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f
return return
} }
matrix4_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_xzx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -928,7 +1006,8 @@ matrix4_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_xyx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -955,7 +1034,8 @@ matrix4_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_yxy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -982,7 +1062,8 @@ matrix4_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_yzy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1009,7 +1090,8 @@ matrix4_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_zyz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1036,7 +1118,8 @@ matrix4_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_zxz_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1064,7 +1147,8 @@ matrix4_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
} }
matrix4_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_xzy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1091,7 +1175,8 @@ matrix4_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_yzx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1118,7 +1203,8 @@ matrix4_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_zyx_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1145,7 +1231,8 @@ matrix4_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
return return
} }
matrix4_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_euler_angles_zxy_f32 :: proc "contextless" (t1, t2, t3: f32) -> (m: Matrix4f32) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1173,7 +1260,8 @@ matrix4_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) {
} }
matrix4_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f32) { @(require_results)
matrix4_from_yaw_pitch_roll_f32 :: proc "contextless" (yaw, pitch, roll: f32) -> (m: Matrix4f32) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -1200,7 +1288,8 @@ matrix4_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f32
return m return m
} }
euler_angles_xyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xyz_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[1, 2], m[2, 2]) T1 := math.atan2(m[1, 2], m[2, 2])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
T2 := math.atan2(-m[0, 2], C2) T2 := math.atan2(-m[0, 2], C2)
@@ -1213,7 +1302,8 @@ euler_angles_xyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_yxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yxz_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[0, 2], m[2, 2]) T1 := math.atan2(m[0, 2], m[2, 2])
C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
T2 := math.atan2(-m[1, 2], C2) T2 := math.atan2(-m[1, 2], C2)
@@ -1226,7 +1316,8 @@ euler_angles_yxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_xzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xzx_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[2, 0], m[1, 0]) T1 := math.atan2(m[2, 0], m[1, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -1239,7 +1330,8 @@ euler_angles_xzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_xyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xyx_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[1, 0], -m[2, 0]) T1 := math.atan2(m[1, 0], -m[2, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -1252,7 +1344,8 @@ euler_angles_xyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_yxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yxy_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[0, 1], m[2, 1]) T1 := math.atan2(m[0, 1], m[2, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -1265,7 +1358,8 @@ euler_angles_yxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_yzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yzy_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[2, 1], -m[0, 1]) T1 := math.atan2(m[2, 1], -m[0, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -1277,7 +1371,8 @@ euler_angles_yzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
t3 = T3 t3 = T3
return return
} }
euler_angles_zyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zyz_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[1, 2], m[0, 2]) T1 := math.atan2(m[1, 2], m[0, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -1290,7 +1385,8 @@ euler_angles_zyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_zxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zxz_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[0, 2], -m[1, 2]) T1 := math.atan2(m[0, 2], -m[1, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -1303,7 +1399,8 @@ euler_angles_zxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_xzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_xzy_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[2, 1], m[1, 1]) T1 := math.atan2(m[2, 1], m[1, 1])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
T2 := math.atan2(-m[0, 1], C2) T2 := math.atan2(-m[0, 1], C2)
@@ -1316,7 +1413,8 @@ euler_angles_xzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_yzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_yzx_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(-m[2, 0], m[0, 0]) T1 := math.atan2(-m[2, 0], m[0, 0])
C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
T2 := math.atan2(m[1, 0], C2) T2 := math.atan2(m[1, 0], C2)
@@ -1329,7 +1427,8 @@ euler_angles_yzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_zyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zyx_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(m[1, 0], m[0, 0]) T1 := math.atan2(m[1, 0], m[0, 0])
C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
T2 := math.atan2(-m[2, 0], C2) T2 := math.atan2(-m[2, 0], C2)
@@ -1342,7 +1441,8 @@ euler_angles_zyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) {
return return
} }
euler_angles_zxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { @(require_results)
euler_angles_zxy_from_matrix4_f32 :: proc "contextless" (m: Matrix4f32) -> (t1, t2, t3: f32) {
T1 := math.atan2(-m[0, 1], m[1, 1]) T1 := math.atan2(-m[0, 1], m[1, 1])
C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
T2 := math.atan2(m[2, 1], C2) T2 := math.atan2(m[2, 1], C2)
+200 -100
View File
@@ -2,7 +2,8 @@ package linalg
import "core:math" import "core:math"
euler_angles_from_matrix3_f64 :: proc(m: Matrix3f64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix3(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix3(m)
@@ -19,7 +20,8 @@ euler_angles_from_matrix3_f64 :: proc(m: Matrix3f64, order: Euler_Angle_Order) -
} }
return return
} }
euler_angles_from_matrix4_f64 :: proc(m: Matrix4f64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_matrix4(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_matrix4(m)
@@ -36,7 +38,8 @@ euler_angles_from_matrix4_f64 :: proc(m: Matrix4f64, order: Euler_Angle_Order) -
} }
return return
} }
euler_angles_from_quaternion_f64 :: proc(m: Quaternionf64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_from_quaternion_f64 :: proc "contextless" (m: Quaternionf64, order: Euler_Angle_Order) -> (t1, t2, t3: f64) {
switch order { switch order {
case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m) case .XYZ: t1, t2, t3 = euler_angles_xyz_from_quaternion(m)
case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m) case .XZY: t1, t2, t3 = euler_angles_xzy_from_quaternion(m)
@@ -54,7 +57,8 @@ euler_angles_from_quaternion_f64 :: proc(m: Quaternionf64, order: Euler_Angle_Or
return return
} }
matrix3_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_f64 :: proc "contextless" (t1, t2, t3: f64, order: Euler_Angle_Order) -> (m: Matrix3f64) {
switch order { switch order {
case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3); case .XYZ: return matrix3_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3); case .XZY: return matrix3_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -71,7 +75,8 @@ matrix3_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order)
} }
return return
} }
matrix4_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_f64 :: proc "contextless" (t1, t2, t3: f64, order: Euler_Angle_Order) -> (m: Matrix4f64) {
switch order { switch order {
case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3); case .XYZ: return matrix4_from_euler_angles_xyz(t1, t2, t3) // m1, m2, m3 = X(t1), Y(t2), Z(t3);
case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3); case .XZY: return matrix4_from_euler_angles_xzy(t1, t2, t3) // m1, m2, m3 = X(t1), Z(t2), Y(t3);
@@ -89,7 +94,8 @@ matrix4_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order)
return return
} }
quaternion_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Order) -> Quaternionf64 { @(require_results)
quaternion_from_euler_angles_f64 :: proc "contextless" (t1, t2, t3: f64, order: Euler_Angle_Order) -> Quaternionf64 {
X :: quaternion_from_euler_angle_x X :: quaternion_from_euler_angle_x
Y :: quaternion_from_euler_angle_y Y :: quaternion_from_euler_angle_y
Z :: quaternion_from_euler_angle_z Z :: quaternion_from_euler_angle_z
@@ -117,17 +123,21 @@ quaternion_from_euler_angles_f64 :: proc(t1, t2, t3: f64, order: Euler_Angle_Ord
// Quaternionf64s // Quaternionf64s
quaternion_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (q: Quaternionf64) { @(require_results)
quaternion_from_euler_angle_x_f64 :: proc "contextless" (angle_x: f64) -> (q: Quaternionf64) {
return quaternion_angle_axis_f64(angle_x, {1, 0, 0}) return quaternion_angle_axis_f64(angle_x, {1, 0, 0})
} }
quaternion_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (q: Quaternionf64) { @(require_results)
quaternion_from_euler_angle_y_f64 :: proc "contextless" (angle_y: f64) -> (q: Quaternionf64) {
return quaternion_angle_axis_f64(angle_y, {0, 1, 0}) return quaternion_angle_axis_f64(angle_y, {0, 1, 0})
} }
quaternion_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (q: Quaternionf64) { @(require_results)
quaternion_from_euler_angle_z_f64 :: proc "contextless" (angle_z: f64) -> (q: Quaternionf64) {
return quaternion_angle_axis_f64(angle_z, {0, 0, 1}) return quaternion_angle_axis_f64(angle_z, {0, 0, 1})
} }
quaternion_from_pitch_yaw_roll_f64 :: proc(pitch, yaw, roll: f64) -> Quaternionf64 { @(require_results)
quaternion_from_pitch_yaw_roll_f64 :: proc "contextless" (pitch, yaw, roll: f64) -> Quaternionf64 {
a, b, c := pitch, yaw, roll a, b, c := pitch, yaw, roll
ca, sa := math.cos(a*0.5), math.sin(a*0.5) ca, sa := math.cos(a*0.5), math.sin(a*0.5)
@@ -142,11 +152,13 @@ quaternion_from_pitch_yaw_roll_f64 :: proc(pitch, yaw, roll: f64) -> Quaternionf
return q return q
} }
roll_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 { @(require_results)
roll_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> f64 {
return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z) return math.atan2(2 * q.x*q.y + q.w*q.z, q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z)
} }
pitch_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 { @(require_results)
pitch_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> f64 {
y := 2 * (q.y*q.z + q.w*q.w) y := 2 * (q.y*q.z + q.w*q.w)
x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z x := q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z
@@ -157,52 +169,66 @@ pitch_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 {
return math.atan2(y, x) return math.atan2(y, x)
} }
yaw_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 { @(require_results)
yaw_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> f64 {
return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1)) return math.asin(clamp(-2 * (q.x*q.z - q.w*q.y), -1, 1))
} }
pitch_yaw_roll_from_quaternion_f64 :: proc(q: Quaternionf64) -> (pitch, yaw, roll: f64) { @(require_results)
pitch_yaw_roll_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (pitch, yaw, roll: f64) {
pitch = pitch_from_quaternion(q) pitch = pitch_from_quaternion(q)
yaw = yaw_from_quaternion(q) yaw = yaw_from_quaternion(q)
roll = roll_from_quaternion(q) roll = roll_from_quaternion(q)
return return
} }
euler_angles_xyz_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xyz_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xyz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yxz_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yxz_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yxz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xzx_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xzx_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xzx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xyx_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xyx_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xyx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yxy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yxy_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yxy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yzy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yzy_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yzy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zyz_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zyz_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zyz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zxz_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zxz_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zxz_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_xzy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xzy_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_xzy_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_yzx_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yzx_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_yzx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zyx_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zyx_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zyx_from_matrix4(matrix4_from_quaternion(q))
} }
euler_angles_zxy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zxy_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> (t1, t2, t3: f64) {
return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q)) return euler_angles_zxy_from_matrix4(matrix4_from_quaternion(q))
} }
@@ -210,7 +236,8 @@ euler_angles_zxy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f
// Matrix3 // Matrix3
matrix3_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angle_x_f64 :: proc "contextless" (angle_x: f64) -> (m: Matrix3f64) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
m[0, 0] = 1 m[0, 0] = 1
m[1, 1] = +cos_x m[1, 1] = +cos_x
@@ -219,7 +246,8 @@ matrix3_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix3f64) {
m[2, 2] = +cos_x m[2, 2] = +cos_x
return return
} }
matrix3_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angle_y_f64 :: proc "contextless" (angle_y: f64) -> (m: Matrix3f64) {
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = +cos_y m[0, 0] = +cos_y
m[0, 2] = -sin_y m[0, 2] = -sin_y
@@ -228,7 +256,8 @@ matrix3_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix3f64) {
m[2, 2] = +cos_y m[2, 2] = +cos_y
return return
} }
matrix3_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angle_z_f64 :: proc "contextless" (angle_z: f64) -> (m: Matrix3f64) {
cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
m[0, 0] = +cos_z m[0, 0] = +cos_z
m[0, 1] = +sin_z m[0, 1] = +sin_z
@@ -239,7 +268,8 @@ matrix3_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix3f64) {
} }
matrix3_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_derived_euler_angle_x_f64 :: proc "contextless" (angle_x: f64, angular_velocity_x: f64) -> (m: Matrix3f64) {
cos_x := math.cos(angle_x) * angular_velocity_x cos_x := math.cos(angle_x) * angular_velocity_x
sin_x := math.sin(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x
m[0, 0] = 1 m[0, 0] = 1
@@ -249,7 +279,8 @@ matrix3_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x:
m[2, 2] = +cos_x m[2, 2] = +cos_x
return return
} }
matrix3_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_derived_euler_angle_y_f64 :: proc "contextless" (angle_y: f64, angular_velocity_y: f64) -> (m: Matrix3f64) {
cos_y := math.cos(angle_y) * angular_velocity_y cos_y := math.cos(angle_y) * angular_velocity_y
sin_y := math.sin(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y
m[0, 0] = +cos_y m[0, 0] = +cos_y
@@ -259,7 +290,8 @@ matrix3_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y:
m[2, 2] = +cos_y m[2, 2] = +cos_y
return return
} }
matrix3_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_derived_euler_angle_z_f64 :: proc "contextless" (angle_z: f64, angular_velocity_z: f64) -> (m: Matrix3f64) {
cos_z := math.cos(angle_z) * angular_velocity_z cos_z := math.cos(angle_z) * angular_velocity_z
sin_z := math.sin(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z
m[0, 0] = +cos_z m[0, 0] = +cos_z
@@ -271,7 +303,8 @@ matrix3_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z:
} }
matrix3_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_xy_f64 :: proc "contextless" (angle_x, angle_y: f64) -> (m: Matrix3f64) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -286,7 +319,8 @@ matrix3_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix3f6
} }
matrix3_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_yx_f64 :: proc "contextless" (angle_y, angle_x: f64) -> (m: Matrix3f64) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -300,21 +334,26 @@ matrix3_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix3f6
return return
} }
matrix3_from_euler_angles_xz_f64 :: proc(angle_x, angle_z: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_xz_f64 :: proc "contextless" (angle_x, angle_z: f64) -> (m: Matrix3f64) {
return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z)) return mul(matrix3_from_euler_angle_x(angle_x), matrix3_from_euler_angle_z(angle_z))
} }
matrix3_from_euler_angles_zx_f64 :: proc(angle_z, angle_x: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_zx_f64 :: proc "contextless" (angle_z, angle_x: f64) -> (m: Matrix3f64) {
return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x)) return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_x(angle_x))
} }
matrix3_from_euler_angles_yz_f64 :: proc(angle_y, angle_z: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_yz_f64 :: proc "contextless" (angle_y, angle_z: f64) -> (m: Matrix3f64) {
return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z)) return mul(matrix3_from_euler_angle_y(angle_y), matrix3_from_euler_angle_z(angle_z))
} }
matrix3_from_euler_angles_zy_f64 :: proc(angle_z, angle_y: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_zy_f64 :: proc "contextless" (angle_z, angle_y: f64) -> (m: Matrix3f64) {
return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y)) return mul(matrix3_from_euler_angle_z(angle_z), matrix3_from_euler_angle_y(angle_y))
} }
matrix3_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_xyz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(-t1) c1 := math.cos(-t1)
c2 := math.cos(-t2) c2 := math.cos(-t2)
c3 := math.cos(-t3) c3 := math.cos(-t3)
@@ -334,7 +373,8 @@ matrix3_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_yxz_f64 :: proc "contextless" (yaw, pitch, roll: f64) -> (m: Matrix3f64) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -354,7 +394,8 @@ matrix3_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f
return return
} }
matrix3_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_xzx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -374,7 +415,8 @@ matrix3_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_xyx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -394,7 +436,8 @@ matrix3_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_yxy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -414,7 +457,8 @@ matrix3_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_yzy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -434,7 +478,8 @@ matrix3_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_zyz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -454,7 +499,8 @@ matrix3_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_zxz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -475,7 +521,8 @@ matrix3_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
} }
matrix3_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_xzy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -495,7 +542,8 @@ matrix3_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_yzx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -515,7 +563,8 @@ matrix3_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_zyx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -535,7 +584,8 @@ matrix3_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
return return
} }
matrix3_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_euler_angles_zxy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix3f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -556,7 +606,8 @@ matrix3_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) {
} }
matrix3_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f64) { @(require_results)
matrix3_from_yaw_pitch_roll_f64 :: proc "contextless" (yaw, pitch, roll: f64) -> (m: Matrix3f64) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -576,7 +627,8 @@ matrix3_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f64
return m return m
} }
euler_angles_xyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xyz_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[1, 2], m[2, 2]) T1 := math.atan2(m[1, 2], m[2, 2])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
T2 := math.atan2(-m[0, 2], C2) T2 := math.atan2(-m[0, 2], C2)
@@ -589,7 +641,8 @@ euler_angles_xyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_yxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yxz_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[0, 2], m[2, 2]) T1 := math.atan2(m[0, 2], m[2, 2])
C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
T2 := math.atan2(-m[1, 2], C2) T2 := math.atan2(-m[1, 2], C2)
@@ -602,7 +655,8 @@ euler_angles_yxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_xzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xzx_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[2, 0], m[1, 0]) T1 := math.atan2(m[2, 0], m[1, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -615,7 +669,8 @@ euler_angles_xzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_xyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xyx_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[1, 0], -m[2, 0]) T1 := math.atan2(m[1, 0], -m[2, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -628,7 +683,8 @@ euler_angles_xyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_yxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yxy_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[0, 1], m[2, 1]) T1 := math.atan2(m[0, 1], m[2, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -641,7 +697,8 @@ euler_angles_yxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_yzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yzy_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[2, 1], -m[0, 1]) T1 := math.atan2(m[2, 1], -m[0, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -653,7 +710,8 @@ euler_angles_yzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
t3 = T3 t3 = T3
return return
} }
euler_angles_zyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zyz_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[1, 2], m[0, 2]) T1 := math.atan2(m[1, 2], m[0, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -666,7 +724,8 @@ euler_angles_zyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_zxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zxz_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[0, 2], -m[1, 2]) T1 := math.atan2(m[0, 2], -m[1, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -679,7 +738,8 @@ euler_angles_zxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_xzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xzy_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[2, 1], m[1, 1]) T1 := math.atan2(m[2, 1], m[1, 1])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
T2 := math.atan2(-m[0, 1], C2) T2 := math.atan2(-m[0, 1], C2)
@@ -692,7 +752,8 @@ euler_angles_xzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_yzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yzx_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(-m[2, 0], m[0, 0]) T1 := math.atan2(-m[2, 0], m[0, 0])
C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
T2 := math.atan2(m[1, 0], C2) T2 := math.atan2(m[1, 0], C2)
@@ -705,7 +766,8 @@ euler_angles_yzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_zyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zyx_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[1, 0], m[0, 0]) T1 := math.atan2(m[1, 0], m[0, 0])
C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
T2 := math.atan2(-m[2, 0], C2) T2 := math.atan2(-m[2, 0], C2)
@@ -718,7 +780,8 @@ euler_angles_zyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_zxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zxy_from_matrix3_f64 :: proc "contextless" (m: Matrix3f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(-m[0, 1], m[1, 1]) T1 := math.atan2(-m[0, 1], m[1, 1])
C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
T2 := math.atan2(m[2, 1], C2) T2 := math.atan2(m[2, 1], C2)
@@ -735,7 +798,8 @@ euler_angles_zxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) {
// Matrix4 // Matrix4
matrix4_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angle_x_f64 :: proc "contextless" (angle_x: f64) -> (m: Matrix4f64) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
m[0, 0] = 1 m[0, 0] = 1
m[1, 1] = +cos_x m[1, 1] = +cos_x
@@ -745,7 +809,8 @@ matrix4_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix4f64) {
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angle_y_f64 :: proc "contextless" (angle_y: f64) -> (m: Matrix4f64) {
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = +cos_y m[0, 0] = +cos_y
m[0, 2] = -sin_y m[0, 2] = -sin_y
@@ -755,7 +820,8 @@ matrix4_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix4f64) {
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angle_z_f64 :: proc "contextless" (angle_z: f64) -> (m: Matrix4f64) {
cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) cos_z, sin_z := math.cos(angle_z), math.sin(angle_z)
m[0, 0] = +cos_z m[0, 0] = +cos_z
m[0, 1] = +sin_z m[0, 1] = +sin_z
@@ -767,7 +833,8 @@ matrix4_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix4f64) {
} }
matrix4_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_derived_euler_angle_x_f64 :: proc "contextless" (angle_x: f64, angular_velocity_x: f64) -> (m: Matrix4f64) {
cos_x := math.cos(angle_x) * angular_velocity_x cos_x := math.cos(angle_x) * angular_velocity_x
sin_x := math.sin(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x
m[0, 0] = 1 m[0, 0] = 1
@@ -778,7 +845,8 @@ matrix4_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x:
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_derived_euler_angle_y_f64 :: proc "contextless" (angle_y: f64, angular_velocity_y: f64) -> (m: Matrix4f64) {
cos_y := math.cos(angle_y) * angular_velocity_y cos_y := math.cos(angle_y) * angular_velocity_y
sin_y := math.sin(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y
m[0, 0] = +cos_y m[0, 0] = +cos_y
@@ -789,7 +857,8 @@ matrix4_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y:
m[3, 3] = 1 m[3, 3] = 1
return return
} }
matrix4_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_derived_euler_angle_z_f64 :: proc "contextless" (angle_z: f64, angular_velocity_z: f64) -> (m: Matrix4f64) {
cos_z := math.cos(angle_z) * angular_velocity_z cos_z := math.cos(angle_z) * angular_velocity_z
sin_z := math.sin(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z
m[0, 0] = +cos_z m[0, 0] = +cos_z
@@ -802,7 +871,8 @@ matrix4_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z:
} }
matrix4_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_xy_f64 :: proc "contextless" (angle_x, angle_y: f64) -> (m: Matrix4f64) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -818,7 +888,8 @@ matrix4_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix4f6
} }
matrix4_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_yx_f64 :: proc "contextless" (angle_y, angle_x: f64) -> (m: Matrix4f64) {
cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_x, sin_x := math.cos(angle_x), math.sin(angle_x)
cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y)
m[0, 0] = cos_y m[0, 0] = cos_y
@@ -833,21 +904,26 @@ matrix4_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix4f6
return return
} }
matrix4_from_euler_angles_xz_f64 :: proc(angle_x, angle_z: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_xz_f64 :: proc "contextless" (angle_x, angle_z: f64) -> (m: Matrix4f64) {
return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z)) return mul(matrix4_from_euler_angle_x(angle_x), matrix4_from_euler_angle_z(angle_z))
} }
matrix4_from_euler_angles_zx_f64 :: proc(angle_z, angle_x: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_zx_f64 :: proc "contextless" (angle_z, angle_x: f64) -> (m: Matrix4f64) {
return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x)) return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_x(angle_x))
} }
matrix4_from_euler_angles_yz_f64 :: proc(angle_y, angle_z: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_yz_f64 :: proc "contextless" (angle_y, angle_z: f64) -> (m: Matrix4f64) {
return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z)) return mul(matrix4_from_euler_angle_y(angle_y), matrix4_from_euler_angle_z(angle_z))
} }
matrix4_from_euler_angles_zy_f64 :: proc(angle_z, angle_y: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_zy_f64 :: proc "contextless" (angle_z, angle_y: f64) -> (m: Matrix4f64) {
return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y)) return mul(matrix4_from_euler_angle_z(angle_z), matrix4_from_euler_angle_y(angle_y))
} }
matrix4_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_xyz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(-t1) c1 := math.cos(-t1)
c2 := math.cos(-t2) c2 := math.cos(-t2)
c3 := math.cos(-t3) c3 := math.cos(-t3)
@@ -874,7 +950,8 @@ matrix4_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_yxz_f64 :: proc "contextless" (yaw, pitch, roll: f64) -> (m: Matrix4f64) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -901,7 +978,8 @@ matrix4_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f
return return
} }
matrix4_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_xzx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -928,7 +1006,8 @@ matrix4_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_xyx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -955,7 +1034,8 @@ matrix4_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_yxy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -982,7 +1062,8 @@ matrix4_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_yzy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1009,7 +1090,8 @@ matrix4_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_zyz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1036,7 +1118,8 @@ matrix4_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_zxz_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1064,7 +1147,8 @@ matrix4_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
} }
matrix4_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_xzy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1091,7 +1175,8 @@ matrix4_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_yzx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1118,7 +1203,8 @@ matrix4_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_zyx_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1145,7 +1231,8 @@ matrix4_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
return return
} }
matrix4_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_euler_angles_zxy_f64 :: proc "contextless" (t1, t2, t3: f64) -> (m: Matrix4f64) {
c1 := math.cos(t1) c1 := math.cos(t1)
s1 := math.sin(t1) s1 := math.sin(t1)
c2 := math.cos(t2) c2 := math.cos(t2)
@@ -1173,7 +1260,8 @@ matrix4_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) {
} }
matrix4_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f64) { @(require_results)
matrix4_from_yaw_pitch_roll_f64 :: proc "contextless" (yaw, pitch, roll: f64) -> (m: Matrix4f64) {
ch := math.cos(yaw) ch := math.cos(yaw)
sh := math.sin(yaw) sh := math.sin(yaw)
cp := math.cos(pitch) cp := math.cos(pitch)
@@ -1200,7 +1288,8 @@ matrix4_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f64
return m return m
} }
euler_angles_xyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xyz_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[1, 2], m[2, 2]) T1 := math.atan2(m[1, 2], m[2, 2])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1])
T2 := math.atan2(-m[0, 2], C2) T2 := math.atan2(-m[0, 2], C2)
@@ -1213,7 +1302,8 @@ euler_angles_xyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_yxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yxz_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[0, 2], m[2, 2]) T1 := math.atan2(m[0, 2], m[2, 2])
C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1])
T2 := math.atan2(-m[1, 2], C2) T2 := math.atan2(-m[1, 2], C2)
@@ -1226,7 +1316,8 @@ euler_angles_yxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_xzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xzx_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[2, 0], m[1, 0]) T1 := math.atan2(m[2, 0], m[1, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -1239,7 +1330,8 @@ euler_angles_xzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_xyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xyx_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[1, 0], -m[2, 0]) T1 := math.atan2(m[1, 0], -m[2, 0])
S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2])
T2 := math.atan2(S2, m[0, 0]) T2 := math.atan2(S2, m[0, 0])
@@ -1252,7 +1344,8 @@ euler_angles_xyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_yxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yxy_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[0, 1], m[2, 1]) T1 := math.atan2(m[0, 1], m[2, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -1265,7 +1358,8 @@ euler_angles_yxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_yzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yzy_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[2, 1], -m[0, 1]) T1 := math.atan2(m[2, 1], -m[0, 1])
S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2])
T2 := math.atan2(S2, m[1, 1]) T2 := math.atan2(S2, m[1, 1])
@@ -1277,7 +1371,8 @@ euler_angles_yzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
t3 = T3 t3 = T3
return return
} }
euler_angles_zyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zyz_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[1, 2], m[0, 2]) T1 := math.atan2(m[1, 2], m[0, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -1290,7 +1385,8 @@ euler_angles_zyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_zxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zxz_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[0, 2], -m[1, 2]) T1 := math.atan2(m[0, 2], -m[1, 2])
S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1])
T2 := math.atan2(S2, m[2, 2]) T2 := math.atan2(S2, m[2, 2])
@@ -1303,7 +1399,8 @@ euler_angles_zxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_xzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_xzy_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[2, 1], m[1, 1]) T1 := math.atan2(m[2, 1], m[1, 1])
C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2])
T2 := math.atan2(-m[0, 1], C2) T2 := math.atan2(-m[0, 1], C2)
@@ -1316,7 +1413,8 @@ euler_angles_xzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_yzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_yzx_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(-m[2, 0], m[0, 0]) T1 := math.atan2(-m[2, 0], m[0, 0])
C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2])
T2 := math.atan2(m[1, 0], C2) T2 := math.atan2(m[1, 0], C2)
@@ -1329,7 +1427,8 @@ euler_angles_yzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_zyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zyx_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(m[1, 0], m[0, 0]) T1 := math.atan2(m[1, 0], m[0, 0])
C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2])
T2 := math.atan2(-m[2, 0], C2) T2 := math.atan2(-m[2, 0], C2)
@@ -1342,7 +1441,8 @@ euler_angles_zyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) {
return return
} }
euler_angles_zxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { @(require_results)
euler_angles_zxy_from_matrix4_f64 :: proc "contextless" (m: Matrix4f64) -> (t1, t2, t3: f64) {
T1 := math.atan2(-m[0, 1], m[1, 1]) T1 := math.atan2(-m[0, 1], m[1, 1])
C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2])
T2 := math.atan2(m[2, 1], C2) T2 := math.atan2(m[2, 1], C2)
+64 -32
View File
@@ -37,110 +37,142 @@ Vector4_Components :: enum u8 {
a = 3, a = 3,
} }
scalar_f32_swizzle1 :: proc(f: f32, c0: Scalar_Components) -> f32 { @(require_results)
scalar_f32_swizzle1 :: proc "contextless" (f: f32, c0: Scalar_Components) -> f32 {
return f return f
} }
scalar_f32_swizzle2 :: proc(f: f32, c0, c1: Scalar_Components) -> Vector2f32 { @(require_results)
scalar_f32_swizzle2 :: proc "contextless" (f: f32, c0, c1: Scalar_Components) -> Vector2f32 {
return {f, f} return {f, f}
} }
scalar_f32_swizzle3 :: proc(f: f32, c0, c1, c2: Scalar_Components) -> Vector3f32 { @(require_results)
scalar_f32_swizzle3 :: proc "contextless" (f: f32, c0, c1, c2: Scalar_Components) -> Vector3f32 {
return {f, f, f} return {f, f, f}
} }
scalar_f32_swizzle4 :: proc(f: f32, c0, c1, c2, c3: Scalar_Components) -> Vector4f32 { @(require_results)
scalar_f32_swizzle4 :: proc "contextless" (f: f32, c0, c1, c2, c3: Scalar_Components) -> Vector4f32 {
return {f, f, f, f} return {f, f, f, f}
} }
vector2f32_swizzle1 :: proc(v: Vector2f32, c0: Vector2_Components) -> f32 { @(require_results)
vector2f32_swizzle1 :: proc "contextless" (v: Vector2f32, c0: Vector2_Components) -> f32 {
return v[c0] return v[c0]
} }
vector2f32_swizzle2 :: proc(v: Vector2f32, c0, c1: Vector2_Components) -> Vector2f32 { @(require_results)
vector2f32_swizzle2 :: proc "contextless" (v: Vector2f32, c0, c1: Vector2_Components) -> Vector2f32 {
return {v[c0], v[c1]} return {v[c0], v[c1]}
} }
vector2f32_swizzle3 :: proc(v: Vector2f32, c0, c1, c2: Vector2_Components) -> Vector3f32 { @(require_results)
vector2f32_swizzle3 :: proc "contextless" (v: Vector2f32, c0, c1, c2: Vector2_Components) -> Vector3f32 {
return {v[c0], v[c1], v[c2]} return {v[c0], v[c1], v[c2]}
} }
vector2f32_swizzle4 :: proc(v: Vector2f32, c0, c1, c2, c3: Vector2_Components) -> Vector4f32 { @(require_results)
vector2f32_swizzle4 :: proc "contextless" (v: Vector2f32, c0, c1, c2, c3: Vector2_Components) -> Vector4f32 {
return {v[c0], v[c1], v[c2], v[c3]} return {v[c0], v[c1], v[c2], v[c3]}
} }
vector3f32_swizzle1 :: proc(v: Vector3f32, c0: Vector3_Components) -> f32 { @(require_results)
vector3f32_swizzle1 :: proc "contextless" (v: Vector3f32, c0: Vector3_Components) -> f32 {
return v[c0] return v[c0]
} }
vector3f32_swizzle2 :: proc(v: Vector3f32, c0, c1: Vector3_Components) -> Vector2f32 { @(require_results)
vector3f32_swizzle2 :: proc "contextless" (v: Vector3f32, c0, c1: Vector3_Components) -> Vector2f32 {
return {v[c0], v[c1]} return {v[c0], v[c1]}
} }
vector3f32_swizzle3 :: proc(v: Vector3f32, c0, c1, c2: Vector3_Components) -> Vector3f32 { @(require_results)
vector3f32_swizzle3 :: proc "contextless" (v: Vector3f32, c0, c1, c2: Vector3_Components) -> Vector3f32 {
return {v[c0], v[c1], v[c2]} return {v[c0], v[c1], v[c2]}
} }
vector3f32_swizzle4 :: proc(v: Vector3f32, c0, c1, c2, c3: Vector3_Components) -> Vector4f32 { @(require_results)
vector3f32_swizzle4 :: proc "contextless" (v: Vector3f32, c0, c1, c2, c3: Vector3_Components) -> Vector4f32 {
return {v[c0], v[c1], v[c2], v[c3]} return {v[c0], v[c1], v[c2], v[c3]}
} }
vector4f32_swizzle1 :: proc(v: Vector4f32, c0: Vector4_Components) -> f32 { @(require_results)
vector4f32_swizzle1 :: proc "contextless" (v: Vector4f32, c0: Vector4_Components) -> f32 {
return v[c0] return v[c0]
} }
vector4f32_swizzle2 :: proc(v: Vector4f32, c0, c1: Vector4_Components) -> Vector2f32 { @(require_results)
vector4f32_swizzle2 :: proc "contextless" (v: Vector4f32, c0, c1: Vector4_Components) -> Vector2f32 {
return {v[c0], v[c1]} return {v[c0], v[c1]}
} }
vector4f32_swizzle3 :: proc(v: Vector4f32, c0, c1, c2: Vector4_Components) -> Vector3f32 { @(require_results)
vector4f32_swizzle3 :: proc "contextless" (v: Vector4f32, c0, c1, c2: Vector4_Components) -> Vector3f32 {
return {v[c0], v[c1], v[c2]} return {v[c0], v[c1], v[c2]}
} }
vector4f32_swizzle4 :: proc(v: Vector4f32, c0, c1, c2, c3: Vector4_Components) -> Vector4f32 { @(require_results)
vector4f32_swizzle4 :: proc "contextless" (v: Vector4f32, c0, c1, c2, c3: Vector4_Components) -> Vector4f32 {
return {v[c0], v[c1], v[c2], v[c3]} return {v[c0], v[c1], v[c2], v[c3]}
} }
scalar_f64_swizzle1 :: proc(f: f64, c0: Scalar_Components) -> f64 { @(require_results)
scalar_f64_swizzle1 :: proc "contextless" (f: f64, c0: Scalar_Components) -> f64 {
return f return f
} }
scalar_f64_swizzle2 :: proc(f: f64, c0, c1: Scalar_Components) -> Vector2f64 { @(require_results)
scalar_f64_swizzle2 :: proc "contextless" (f: f64, c0, c1: Scalar_Components) -> Vector2f64 {
return {f, f} return {f, f}
} }
scalar_f64_swizzle3 :: proc(f: f64, c0, c1, c2: Scalar_Components) -> Vector3f64 { @(require_results)
scalar_f64_swizzle3 :: proc "contextless" (f: f64, c0, c1, c2: Scalar_Components) -> Vector3f64 {
return {f, f, f} return {f, f, f}
} }
scalar_f64_swizzle4 :: proc(f: f64, c0, c1, c2, c3: Scalar_Components) -> Vector4f64 { @(require_results)
scalar_f64_swizzle4 :: proc "contextless" (f: f64, c0, c1, c2, c3: Scalar_Components) -> Vector4f64 {
return {f, f, f, f} return {f, f, f, f}
} }
vector2f64_swizzle1 :: proc(v: Vector2f64, c0: Vector2_Components) -> f64 { @(require_results)
vector2f64_swizzle1 :: proc "contextless" (v: Vector2f64, c0: Vector2_Components) -> f64 {
return v[c0] return v[c0]
} }
vector2f64_swizzle2 :: proc(v: Vector2f64, c0, c1: Vector2_Components) -> Vector2f64 { @(require_results)
vector2f64_swizzle2 :: proc "contextless" (v: Vector2f64, c0, c1: Vector2_Components) -> Vector2f64 {
return {v[c0], v[c1]} return {v[c0], v[c1]}
} }
vector2f64_swizzle3 :: proc(v: Vector2f64, c0, c1, c2: Vector2_Components) -> Vector3f64 { @(require_results)
vector2f64_swizzle3 :: proc "contextless" (v: Vector2f64, c0, c1, c2: Vector2_Components) -> Vector3f64 {
return {v[c0], v[c1], v[c2]} return {v[c0], v[c1], v[c2]}
} }
vector2f64_swizzle4 :: proc(v: Vector2f64, c0, c1, c2, c3: Vector2_Components) -> Vector4f64 { @(require_results)
vector2f64_swizzle4 :: proc "contextless" (v: Vector2f64, c0, c1, c2, c3: Vector2_Components) -> Vector4f64 {
return {v[c0], v[c1], v[c2], v[c3]} return {v[c0], v[c1], v[c2], v[c3]}
} }
vector3f64_swizzle1 :: proc(v: Vector3f64, c0: Vector3_Components) -> f64 { @(require_results)
vector3f64_swizzle1 :: proc "contextless" (v: Vector3f64, c0: Vector3_Components) -> f64 {
return v[c0] return v[c0]
} }
vector3f64_swizzle2 :: proc(v: Vector3f64, c0, c1: Vector3_Components) -> Vector2f64 { @(require_results)
vector3f64_swizzle2 :: proc "contextless" (v: Vector3f64, c0, c1: Vector3_Components) -> Vector2f64 {
return {v[c0], v[c1]} return {v[c0], v[c1]}
} }
vector3f64_swizzle3 :: proc(v: Vector3f64, c0, c1, c2: Vector3_Components) -> Vector3f64 { @(require_results)
vector3f64_swizzle3 :: proc "contextless" (v: Vector3f64, c0, c1, c2: Vector3_Components) -> Vector3f64 {
return {v[c0], v[c1], v[c2]} return {v[c0], v[c1], v[c2]}
} }
vector3f64_swizzle4 :: proc(v: Vector3f64, c0, c1, c2, c3: Vector3_Components) -> Vector4f64 { @(require_results)
vector3f64_swizzle4 :: proc "contextless" (v: Vector3f64, c0, c1, c2, c3: Vector3_Components) -> Vector4f64 {
return {v[c0], v[c1], v[c2], v[c3]} return {v[c0], v[c1], v[c2], v[c3]}
} }
vector4f64_swizzle1 :: proc(v: Vector4f64, c0: Vector4_Components) -> f64 { @(require_results)
vector4f64_swizzle1 :: proc "contextless" (v: Vector4f64, c0: Vector4_Components) -> f64 {
return v[c0] return v[c0]
} }
vector4f64_swizzle2 :: proc(v: Vector4f64, c0, c1: Vector4_Components) -> Vector2f64 { @(require_results)
vector4f64_swizzle2 :: proc "contextless" (v: Vector4f64, c0, c1: Vector4_Components) -> Vector2f64 {
return {v[c0], v[c1]} return {v[c0], v[c1]}
} }
vector4f64_swizzle3 :: proc(v: Vector4f64, c0, c1, c2: Vector4_Components) -> Vector3f64 { @(require_results)
vector4f64_swizzle3 :: proc "contextless" (v: Vector4f64, c0, c1, c2: Vector4_Components) -> Vector3f64 {
return {v[c0], v[c1], v[c2]} return {v[c0], v[c1], v[c2]}
} }
vector4f64_swizzle4 :: proc(v: Vector4f64, c0, c1, c2, c3: Vector4_Components) -> Vector4f64 { @(require_results)
vector4f64_swizzle4 :: proc "contextless" (v: Vector4f64, c0, c1, c2, c3: Vector4_Components) -> Vector4f64 {
return {v[c0], v[c1], v[c2], v[c3]} return {v[c0], v[c1], v[c2], v[c3]}
} }
+391 -249
View File
File diff suppressed because it is too large Load Diff
+27 -23
View File
@@ -5,54 +5,58 @@ import "core:intrinsics"
@(default_calling_convention="none") @(default_calling_convention="none")
foreign _ { foreign _ {
@(link_name="llvm.sin.f16") @(link_name="llvm.sin.f16", require_results)
sin_f16 :: proc(θ: f16) -> f16 --- sin_f16 :: proc(θ: f16) -> f16 ---
@(link_name="llvm.sin.f32") @(link_name="llvm.sin.f32", require_results)
sin_f32 :: proc(θ: f32) -> f32 --- sin_f32 :: proc(θ: f32) -> f32 ---
@(link_name="llvm.sin.f64") @(link_name="llvm.sin.f64", require_results)
sin_f64 :: proc(θ: f64) -> f64 --- sin_f64 :: proc(θ: f64) -> f64 ---
@(link_name="llvm.cos.f16") @(link_name="llvm.cos.f16", require_results)
cos_f16 :: proc(θ: f16) -> f16 --- cos_f16 :: proc(θ: f16) -> f16 ---
@(link_name="llvm.cos.f32") @(link_name="llvm.cos.f32", require_results)
cos_f32 :: proc(θ: f32) -> f32 --- cos_f32 :: proc(θ: f32) -> f32 ---
@(link_name="llvm.cos.f64") @(link_name="llvm.cos.f64", require_results)
cos_f64 :: proc(θ: f64) -> f64 --- cos_f64 :: proc(θ: f64) -> f64 ---
@(link_name="llvm.pow.f16") @(link_name="llvm.pow.f16", require_results)
pow_f16 :: proc(x, power: f16) -> f16 --- pow_f16 :: proc(x, power: f16) -> f16 ---
@(link_name="llvm.pow.f32") @(link_name="llvm.pow.f32", require_results)
pow_f32 :: proc(x, power: f32) -> f32 --- pow_f32 :: proc(x, power: f32) -> f32 ---
@(link_name="llvm.pow.f64") @(link_name="llvm.pow.f64", require_results)
pow_f64 :: proc(x, power: f64) -> f64 --- pow_f64 :: proc(x, power: f64) -> f64 ---
@(link_name="llvm.fmuladd.f16") @(link_name="llvm.fmuladd.f16", require_results)
fmuladd_f16 :: proc(a, b, c: f16) -> f16 --- fmuladd_f16 :: proc(a, b, c: f16) -> f16 ---
@(link_name="llvm.fmuladd.f32") @(link_name="llvm.fmuladd.f32", require_results)
fmuladd_f32 :: proc(a, b, c: f32) -> f32 --- fmuladd_f32 :: proc(a, b, c: f32) -> f32 ---
@(link_name="llvm.fmuladd.f64") @(link_name="llvm.fmuladd.f64", require_results)
fmuladd_f64 :: proc(a, b, c: f64) -> f64 --- fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---
@(link_name="llvm.exp.f16") @(link_name="llvm.exp.f16", require_results)
exp_f16 :: proc(x: f16) -> f16 --- exp_f16 :: proc(x: f16) -> f16 ---
@(link_name="llvm.exp.f32") @(link_name="llvm.exp.f32", require_results)
exp_f32 :: proc(x: f32) -> f32 --- exp_f32 :: proc(x: f32) -> f32 ---
@(link_name="llvm.exp.f64") @(link_name="llvm.exp.f64", require_results)
exp_f64 :: proc(x: f64) -> f64 --- exp_f64 :: proc(x: f64) -> f64 ---
} }
@(require_results)
sqrt_f16 :: proc "contextless" (x: f16) -> f16 { sqrt_f16 :: proc "contextless" (x: f16) -> f16 {
return intrinsics.sqrt(x) return intrinsics.sqrt(x)
} }
@(require_results)
sqrt_f32 :: proc "contextless" (x: f32) -> f32 { sqrt_f32 :: proc "contextless" (x: f32) -> f32 {
return intrinsics.sqrt(x) return intrinsics.sqrt(x)
} }
@(require_results)
sqrt_f64 :: proc "contextless" (x: f64) -> f64 { sqrt_f64 :: proc "contextless" (x: f64) -> f64 {
return intrinsics.sqrt(x) return intrinsics.sqrt(x)
} }
@(require_results)
ln_f64 :: proc "contextless" (x: f64) -> f64 { ln_f64 :: proc "contextless" (x: f64) -> f64 {
// The original C code, the long comment, and the constants // The original C code, the long comment, and the constants
// below are from FreeBSD's /usr/src/lib/msun/src/e_log.c // below are from FreeBSD's /usr/src/lib/msun/src/e_log.c
@@ -154,14 +158,14 @@ ln_f64 :: proc "contextless" (x: f64) -> f64 {
return k*LN2_HI - ((hfsq - (s*(hfsq+R) + k*LN2_LO)) - f) return k*LN2_HI - ((hfsq - (s*(hfsq+R) + k*LN2_LO)) - f)
} }
ln_f16 :: proc "contextless" (x: f16) -> f16 { return #force_inline f16(ln_f64(f64(x))) } @(require_results) ln_f16 :: proc "contextless" (x: f16) -> f16 { return #force_inline f16(ln_f64(f64(x))) }
ln_f32 :: proc "contextless" (x: f32) -> f32 { return #force_inline f32(ln_f64(f64(x))) } @(require_results) ln_f32 :: proc "contextless" (x: f32) -> f32 { return #force_inline f32(ln_f64(f64(x))) }
ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) } @(require_results) ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) }
ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) } @(require_results) ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) }
ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) } @(require_results) ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) }
ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) } @(require_results) ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) }
ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) } @(require_results) ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) }
ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) } @(require_results) ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) }
ln :: proc{ ln :: proc{
ln_f16, ln_f16le, ln_f16be, ln_f16, ln_f16le, ln_f16be,
ln_f32, ln_f32le, ln_f32be, ln_f32, ln_f32le, ln_f32be,
+27 -26
View File
@@ -7,46 +7,47 @@ foreign import "odin_env"
@(default_calling_convention="c") @(default_calling_convention="c")
foreign odin_env { foreign odin_env {
@(link_name="sin") @(link_name="sin", require_results)
sin_f64 :: proc(θ: f64) -> f64 --- sin_f64 :: proc(θ: f64) -> f64 ---
@(link_name="cos") @(link_name="cos", require_results)
cos_f64 :: proc(θ: f64) -> f64 --- cos_f64 :: proc(θ: f64) -> f64 ---
@(link_name="pow") @(link_name="pow", require_results)
pow_f64 :: proc(x, power: f64) -> f64 --- pow_f64 :: proc(x, power: f64) -> f64 ---
@(link_name="fmuladd") @(link_name="fmuladd", require_results)
fmuladd_f64 :: proc(a, b, c: f64) -> f64 --- fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---
@(link_name="ln") @(link_name="ln", require_results)
ln_f64 :: proc(x: f64) -> f64 --- ln_f64 :: proc(x: f64) -> f64 ---
@(link_name="exp") @(link_name="exp", require_results)
exp_f64 :: proc(x: f64) -> f64 --- exp_f64 :: proc(x: f64) -> f64 ---
} }
@(require_results)
sqrt_f64 :: proc "contextless" (x: f64) -> f64 { sqrt_f64 :: proc "contextless" (x: f64) -> f64 {
return intrinsics.sqrt(x) return intrinsics.sqrt(x)
} }
sqrt_f16 :: proc "c" (x: f16) -> f16 { return f16(sqrt_f64(f64(x))) } @(require_results) sqrt_f16 :: proc "c" (x: f16) -> f16 { return f16(sqrt_f64(f64(x))) }
sin_f16 :: proc "c" (θ: f16) -> f16 { return f16(sin_f64(f64(θ))) } @(require_results) sin_f16 :: proc "c" (θ: f16) -> f16 { return f16(sin_f64(f64(θ))) }
cos_f16 :: proc "c" (θ: f16) -> f16 { return f16(cos_f64(f64(θ))) } @(require_results) cos_f16 :: proc "c" (θ: f16) -> f16 { return f16(cos_f64(f64(θ))) }
pow_f16 :: proc "c" (x, power: f16) -> f16 { return f16(pow_f64(f64(x), f64(power))) } @(require_results) pow_f16 :: proc "c" (x, power: f16) -> f16 { return f16(pow_f64(f64(x), f64(power))) }
fmuladd_f16 :: proc "c" (a, b, c: f16) -> f16 { return f16(fmuladd_f64(f64(a), f64(a), f64(c))) } @(require_results) fmuladd_f16 :: proc "c" (a, b, c: f16) -> f16 { return f16(fmuladd_f64(f64(a), f64(a), f64(c))) }
ln_f16 :: proc "c" (x: f16) -> f16 { return f16(ln_f64(f64(x))) } @(require_results) ln_f16 :: proc "c" (x: f16) -> f16 { return f16(ln_f64(f64(x))) }
exp_f16 :: proc "c" (x: f16) -> f16 { return f16(exp_f64(f64(x))) } @(require_results) exp_f16 :: proc "c" (x: f16) -> f16 { return f16(exp_f64(f64(x))) }
sqrt_f32 :: proc "c" (x: f32) -> f32 { return f32(sqrt_f64(f64(x))) } @(require_results) sqrt_f32 :: proc "c" (x: f32) -> f32 { return f32(sqrt_f64(f64(x))) }
sin_f32 :: proc "c" (θ: f32) -> f32 { return f32(sin_f64(f64(θ))) } @(require_results) sin_f32 :: proc "c" (θ: f32) -> f32 { return f32(sin_f64(f64(θ))) }
cos_f32 :: proc "c" (θ: f32) -> f32 { return f32(cos_f64(f64(θ))) } @(require_results) cos_f32 :: proc "c" (θ: f32) -> f32 { return f32(cos_f64(f64(θ))) }
pow_f32 :: proc "c" (x, power: f32) -> f32 { return f32(pow_f64(f64(x), f64(power))) } @(require_results) pow_f32 :: proc "c" (x, power: f32) -> f32 { return f32(pow_f64(f64(x), f64(power))) }
fmuladd_f32 :: proc "c" (a, b, c: f32) -> f32 { return f32(fmuladd_f64(f64(a), f64(a), f64(c))) } @(require_results) fmuladd_f32 :: proc "c" (a, b, c: f32) -> f32 { return f32(fmuladd_f64(f64(a), f64(a), f64(c))) }
ln_f32 :: proc "c" (x: f32) -> f32 { return f32(ln_f64(f64(x))) } @(require_results) ln_f32 :: proc "c" (x: f32) -> f32 { return f32(ln_f64(f64(x))) }
exp_f32 :: proc "c" (x: f32) -> f32 { return f32(exp_f64(f64(x))) } @(require_results) exp_f32 :: proc "c" (x: f32) -> f32 { return f32(exp_f64(f64(x))) }
ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) } @(require_results) ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) }
ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) } @(require_results) ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) }
ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) } @(require_results) ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) }
ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) } @(require_results) ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) }
ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) } @(require_results) ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) }
ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) } @(require_results) ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) }
ln :: proc{ ln :: proc{
ln_f16, ln_f16le, ln_f16be, ln_f16, ln_f16le, ln_f16be,
ln_f32, ln_f32le, ln_f32be, ln_f32, ln_f32le, ln_f32be,
+14 -12
View File
@@ -117,13 +117,14 @@ erf :: proc{
erf_f64, erf_f64,
} }
erf_f16 :: proc "contextless" (x: f16) -> f16 { return f16(erf_f64(f64(x))) } @(require_results) erf_f16 :: proc "contextless" (x: f16) -> f16 { return f16(erf_f64(f64(x))) }
erf_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erf_f64(f64(x))) } @(require_results) erf_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erf_f64(f64(x))) }
erf_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erf_f64(f64(x))) } @(require_results) erf_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erf_f64(f64(x))) }
erf_f32 :: proc "contextless" (x: f32) -> f32 { return f32(erf_f64(f64(x))) } @(require_results) erf_f32 :: proc "contextless" (x: f32) -> f32 { return f32(erf_f64(f64(x))) }
erf_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erf_f64(f64(x))) } @(require_results) erf_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erf_f64(f64(x))) }
erf_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erf_f64(f64(x))) } @(require_results) erf_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erf_f64(f64(x))) }
@(require_results)
erf_f64 :: proc "contextless" (x: f64) -> f64 { erf_f64 :: proc "contextless" (x: f64) -> f64 {
erx :: 0h3FEB0AC160000000 erx :: 0h3FEB0AC160000000
// Coefficients for approximation to erf in [0, 0.84375] // Coefficients for approximation to erf in [0, 0.84375]
@@ -268,13 +269,14 @@ erfc :: proc{
erfc_f64, erfc_f64,
} }
erfc_f16 :: proc "contextless" (x: f16) -> f16 { return f16(erfc_f64(f64(x))) } @(require_results) erfc_f16 :: proc "contextless" (x: f16) -> f16 { return f16(erfc_f64(f64(x))) }
erfc_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erfc_f64(f64(x))) } @(require_results) erfc_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erfc_f64(f64(x))) }
erfc_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erfc_f64(f64(x))) } @(require_results) erfc_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erfc_f64(f64(x))) }
erfc_f32 :: proc "contextless" (x: f32) -> f32 { return f32(erfc_f64(f64(x))) } @(require_results) erfc_f32 :: proc "contextless" (x: f32) -> f32 { return f32(erfc_f64(f64(x))) }
erfc_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erfc_f64(f64(x))) } @(require_results) erfc_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erfc_f64(f64(x))) }
erfc_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erfc_f64(f64(x))) } @(require_results) erfc_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erfc_f64(f64(x))) }
@(require_results)
erfc_f64 :: proc "contextless" (x: f64) -> f64 { erfc_f64 :: proc "contextless" (x: f64) -> f64 {
erx :: 0h3FEB0AC160000000 erx :: 0h3FEB0AC160000000
// Coefficients for approximation to erf in [0, 0.84375] // Coefficients for approximation to erf in [0, 0.84375]
+10 -9
View File
@@ -65,7 +65,7 @@ package math
// The polynomial is valid for 33 <= x <= 172; larger values are only used // The polynomial is valid for 33 <= x <= 172; larger values are only used
// in reciprocal and produce denormalized floats. The lower precision there // in reciprocal and produce denormalized floats. The lower precision there
// masks any imprecision in the polynomial. // masks any imprecision in the polynomial.
@(private="file") @(private="file", require_results)
stirling :: proc "contextless" (x: f64) -> (f64, f64) { stirling :: proc "contextless" (x: f64) -> (f64, f64) {
@(static) gamS := [?]f64{ @(static) gamS := [?]f64{
+7.87311395793093628397e-04, +7.87311395793093628397e-04,
@@ -93,6 +93,7 @@ stirling :: proc "contextless" (x: f64) -> (f64, f64) {
return y1, SQRT_TWO_PI * w * y2 return y1, SQRT_TWO_PI * w * y2
} }
@(require_results)
gamma_f64 :: proc "contextless" (x: f64) -> f64 { gamma_f64 :: proc "contextless" (x: f64) -> f64 {
is_neg_int :: proc "contextless" (x: f64) -> bool { is_neg_int :: proc "contextless" (x: f64) -> bool {
if x < 0 { if x < 0 {
@@ -210,14 +211,14 @@ gamma_f64 :: proc "contextless" (x: f64) -> f64 {
} }
gamma_f16 :: proc "contextless" (x: f16) -> f16 { return f16(gamma_f64(f64(x))) } @(require_results) gamma_f16 :: proc "contextless" (x: f16) -> f16 { return f16(gamma_f64(f64(x))) }
gamma_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(gamma_f64(f64(x))) } @(require_results) gamma_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(gamma_f64(f64(x))) }
gamma_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(gamma_f64(f64(x))) } @(require_results) gamma_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(gamma_f64(f64(x))) }
gamma_f32 :: proc "contextless" (x: f32) -> f32 { return f32(gamma_f64(f64(x))) } @(require_results) gamma_f32 :: proc "contextless" (x: f32) -> f32 { return f32(gamma_f64(f64(x))) }
gamma_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(gamma_f64(f64(x))) } @(require_results) gamma_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(gamma_f64(f64(x))) }
gamma_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(gamma_f64(f64(x))) } @(require_results) gamma_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(gamma_f64(f64(x))) }
gamma_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(gamma_f64(f64(x))) } @(require_results) gamma_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(gamma_f64(f64(x))) }
gamma_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(gamma_f64(f64(x))) } @(require_results) gamma_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(gamma_f64(f64(x))) }
gamma :: proc{ gamma :: proc{
gamma_f16, gamma_f16le, gamma_f16be, gamma_f16, gamma_f16le, gamma_f16be,
+10 -8
View File
@@ -80,7 +80,9 @@ package math
// //
@(require_results)
lgamma_f64 :: proc "contextless" (x: f64) -> (lgamma: f64, sign: int) { lgamma_f64 :: proc "contextless" (x: f64) -> (lgamma: f64, sign: int) {
@(require_results)
sin_pi :: proc "contextless" (x: f64) -> f64 { sin_pi :: proc "contextless" (x: f64) -> f64 {
if x < 0.25 { if x < 0.25 {
return -sin(PI * x) return -sin(PI * x)
@@ -345,14 +347,14 @@ lgamma_f64 :: proc "contextless" (x: f64) -> (lgamma: f64, sign: int) {
} }
lgamma_f16 :: proc "contextless" (x: f16) -> (lgamma: f16, sign: int) { r, s := lgamma_f64(f64(x)); return f16(r), s } @(require_results) lgamma_f16 :: proc "contextless" (x: f16) -> (lgamma: f16, sign: int) { r, s := lgamma_f64(f64(x)); return f16(r), s }
lgamma_f32 :: proc "contextless" (x: f32) -> (lgamma: f32, sign: int) { r, s := lgamma_f64(f64(x)); return f32(r), s } @(require_results) lgamma_f32 :: proc "contextless" (x: f32) -> (lgamma: f32, sign: int) { r, s := lgamma_f64(f64(x)); return f32(r), s }
lgamma_f16le :: proc "contextless" (x: f16le) -> (lgamma: f16le, sign: int) { r, s := lgamma_f64(f64(x)); return f16le(r), s } @(require_results) lgamma_f16le :: proc "contextless" (x: f16le) -> (lgamma: f16le, sign: int) { r, s := lgamma_f64(f64(x)); return f16le(r), s }
lgamma_f16be :: proc "contextless" (x: f16be) -> (lgamma: f16be, sign: int) { r, s := lgamma_f64(f64(x)); return f16be(r), s } @(require_results) lgamma_f16be :: proc "contextless" (x: f16be) -> (lgamma: f16be, sign: int) { r, s := lgamma_f64(f64(x)); return f16be(r), s }
lgamma_f32le :: proc "contextless" (x: f32le) -> (lgamma: f32le, sign: int) { r, s := lgamma_f64(f64(x)); return f32le(r), s } @(require_results) lgamma_f32le :: proc "contextless" (x: f32le) -> (lgamma: f32le, sign: int) { r, s := lgamma_f64(f64(x)); return f32le(r), s }
lgamma_f32be :: proc "contextless" (x: f32be) -> (lgamma: f32be, sign: int) { r, s := lgamma_f64(f64(x)); return f32be(r), s } @(require_results) lgamma_f32be :: proc "contextless" (x: f32be) -> (lgamma: f32be, sign: int) { r, s := lgamma_f64(f64(x)); return f32be(r), s }
lgamma_f64le :: proc "contextless" (x: f64le) -> (lgamma: f64le, sign: int) { r, s := lgamma_f64(f64(x)); return f64le(r), s } @(require_results) lgamma_f64le :: proc "contextless" (x: f64le) -> (lgamma: f64le, sign: int) { r, s := lgamma_f64(f64(x)); return f64le(r), s }
lgamma_f64be :: proc "contextless" (x: f64be) -> (lgamma: f64be, sign: int) { r, s := lgamma_f64(f64(x)); return f64be(r), s } @(require_results) lgamma_f64be :: proc "contextless" (x: f64be) -> (lgamma: f64be, sign: int) { r, s := lgamma_f64(f64(x)); return f64be(r), s }
lgamma :: proc{ lgamma :: proc{
lgamma_f16, lgamma_f16le, lgamma_f16be, lgamma_f16, lgamma_f16le, lgamma_f16be,
+9 -8
View File
@@ -90,15 +90,16 @@ log1p :: proc {
log1p_f64le, log1p_f64le,
log1p_f64be, log1p_f64be,
} }
log1p_f16 :: proc "contextless" (x: f16) -> f16 { return f16(log1p_f64(f64(x))) } @(require_results) log1p_f16 :: proc "contextless" (x: f16) -> f16 { return f16(log1p_f64(f64(x))) }
log1p_f32 :: proc "contextless" (x: f32) -> f32 { return f32(log1p_f64(f64(x))) } @(require_results) log1p_f32 :: proc "contextless" (x: f32) -> f32 { return f32(log1p_f64(f64(x))) }
log1p_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log1p_f64(f64(x))) } @(require_results) log1p_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log1p_f64(f64(x))) }
log1p_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log1p_f64(f64(x))) } @(require_results) log1p_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log1p_f64(f64(x))) }
log1p_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log1p_f64(f64(x))) } @(require_results) log1p_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log1p_f64(f64(x))) }
log1p_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log1p_f64(f64(x))) } @(require_results) log1p_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log1p_f64(f64(x))) }
log1p_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log1p_f64(f64(x))) } @(require_results) log1p_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log1p_f64(f64(x))) }
log1p_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log1p_f64(f64(x))) } @(require_results) log1p_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log1p_f64(f64(x))) }
@(require_results)
log1p_f64 :: proc "contextless" (x: f64) -> f64 { log1p_f64 :: proc "contextless" (x: f64) -> f64 {
SQRT2_M1 :: 0h3fda827999fcef34 // sqrt(2)-1 SQRT2_M1 :: 0h3fda827999fcef34 // sqrt(2)-1
SQRT2_HALF_M1 :: 0hbfd2bec333018866 // sqrt(2)/2-1 SQRT2_HALF_M1 :: 0hbfd2bec333018866 // sqrt(2)/2-1
+9
View File
@@ -20,6 +20,7 @@ Vec4 :: [4]f64
/* /*
2D Simplex noise, standard lattice orientation. 2D Simplex noise, standard lattice orientation.
*/ */
@(require_results)
noise_2d :: proc(seed: i64, coord: Vec2) -> (value: f32) { noise_2d :: proc(seed: i64, coord: Vec2) -> (value: f32) {
// Get points for A2* lattice // Get points for A2* lattice
skew := SKEW_2D * (coord.x + coord.y) skew := SKEW_2D * (coord.x + coord.y)
@@ -35,6 +36,7 @@ noise_2d :: proc(seed: i64, coord: Vec2) -> (value: f32) {
unless your map is centered around an equator. It's a subtle unless your map is centered around an equator. It's a subtle
difference, but the option is here to make it an easy choice. difference, but the option is here to make it an easy choice.
*/ */
@(require_results)
noise_2d_improve_x :: proc(seed: i64, coord: Vec2) -> (value: f32) { noise_2d_improve_x :: proc(seed: i64, coord: Vec2) -> (value: f32) {
// Skew transform and rotation baked into one. // Skew transform and rotation baked into one.
xx := coord.x * ROOT_2_OVER_2 xx := coord.x * ROOT_2_OVER_2
@@ -51,6 +53,7 @@ noise_2d_improve_x :: proc(seed: i64, coord: Vec2) -> (value: f32) {
If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, y, Z)`. If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, y, Z)`.
For a time varied animation, call `noise_3d_improve_xz(x, y, T)`. For a time varied animation, call `noise_3d_improve_xz(x, y, T)`.
*/ */
@(require_results)
noise_3d_improve_xy :: proc(seed: i64, coord: Vec3) -> (value: f32) { noise_3d_improve_xy :: proc(seed: i64, coord: Vec3) -> (value: f32) {
/* /*
Re-orient the cubic lattices without skewing, so Z points up the main lattice diagonal, Re-orient the cubic lattices without skewing, so Z points up the main lattice diagonal,
@@ -75,6 +78,7 @@ noise_3d_improve_xy :: proc(seed: i64, coord: Vec3) -> (value: f32) {
If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, Z, y)` or use `noise_3d_improve_xy`. If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, Z, y)` or use `noise_3d_improve_xy`.
For a time varied animation, call `noise_3d_improve_xz(x, T, y)` or use `noise_3d_improve_xy`. For a time varied animation, call `noise_3d_improve_xz(x, T, y)` or use `noise_3d_improve_xy`.
*/ */
@(require_results)
noise_3d_improve_xz :: proc(seed: i64, coord: Vec3) -> (value: f32) { noise_3d_improve_xz :: proc(seed: i64, coord: Vec3) -> (value: f32) {
/* /*
Re-orient the cubic lattices without skewing, so Y points up the main lattice diagonal, Re-orient the cubic lattices without skewing, so Y points up the main lattice diagonal,
@@ -96,6 +100,7 @@ noise_3d_improve_xz :: proc(seed: i64, coord: Vec3) -> (value: f32) {
Use `noise_3d_improve_xy` or `noise_3d_improve_xz` instead, wherever appropriate. Use `noise_3d_improve_xy` or `noise_3d_improve_xz` instead, wherever appropriate.
They have less diagonal bias. This function's best use is as a fallback. They have less diagonal bias. This function's best use is as a fallback.
*/ */
@(require_results)
noise_3d_fallback :: proc(seed: i64, coord: Vec3) -> (value: f32) { noise_3d_fallback :: proc(seed: i64, coord: Vec3) -> (value: f32) {
/* /*
Re-orient the cubic lattices via rotation, to produce a familiar look. Re-orient the cubic lattices via rotation, to produce a familiar look.
@@ -114,6 +119,7 @@ noise_3d_fallback :: proc(seed: i64, coord: Vec3) -> (value: f32) {
Recommended for time-varied animations which texture a 3D object (W=time) Recommended for time-varied animations which texture a 3D object (W=time)
in a space where Z is vertical. in a space where Z is vertical.
*/ */
@(require_results)
noise_4d_improve_xyz_improve_xy :: proc(seed: i64, coord: Vec4) -> (value: f32) { noise_4d_improve_xyz_improve_xy :: proc(seed: i64, coord: Vec4) -> (value: f32) {
xy := coord.x + coord.y xy := coord.x + coord.y
s2 := xy * -0.21132486540518699998 s2 := xy * -0.21132486540518699998
@@ -133,6 +139,7 @@ noise_4d_improve_xyz_improve_xy :: proc(seed: i64, coord: Vec4) -> (value: f32)
Recommended for time-varied animations which texture a 3D object (W=time) Recommended for time-varied animations which texture a 3D object (W=time)
in a space where Y is vertical. in a space where Y is vertical.
*/ */
@(require_results)
noise_4d_improve_xyz_improve_xz :: proc(seed: i64, coord: Vec4) -> (value: f32) { noise_4d_improve_xyz_improve_xz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
xz := coord.x + coord.z xz := coord.x + coord.z
s2 := xz * -0.21132486540518699998 s2 := xz * -0.21132486540518699998
@@ -152,6 +159,7 @@ noise_4d_improve_xyz_improve_xz :: proc(seed: i64, coord: Vec4) -> (value: f32)
Recommended for time-varied animations which texture a 3D object (W=time) Recommended for time-varied animations which texture a 3D object (W=time)
where there isn't a clear distinction between horizontal and vertical where there isn't a clear distinction between horizontal and vertical
*/ */
@(require_results)
noise_4d_improve_xyz :: proc(seed: i64, coord: Vec4) -> (value: f32) { noise_4d_improve_xyz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
xyz := coord.x + coord.y + coord.z xyz := coord.x + coord.y + coord.z
ww := coord.w * 0.2236067977499788 ww := coord.w * 0.2236067977499788
@@ -164,6 +172,7 @@ noise_4d_improve_xyz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
/* /*
4D OpenSimplex2 noise, fallback lattice orientation. 4D OpenSimplex2 noise, fallback lattice orientation.
*/ */
@(require_results)
noise_4d_fallback :: proc(seed: i64, coord: Vec4) -> (value: f32) { noise_4d_fallback :: proc(seed: i64, coord: Vec4) -> (value: f32) {
// Get points for A4 lattice // Get points for A4 lattice
skew := f64(SKEW_4D) * (coord.x + coord.y + coord.z + coord.w) skew := f64(SKEW_4D) * (coord.x + coord.y + coord.z + coord.w)
+26
View File
@@ -7,6 +7,7 @@ float32_uniform :: float32_range
// Triangular Distribution // Triangular Distribution
// See: http://wikipedia.org/wiki/Triangular_distribution // See: http://wikipedia.org/wiki/Triangular_distribution
@(require_results)
float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 { float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 {
if hi-lo == 0 { if hi-lo == 0 {
return lo return lo
@@ -24,6 +25,7 @@ float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64
} }
// Triangular Distribution // Triangular Distribution
// See: http://wikipedia.org/wiki/Triangular_distribution // See: http://wikipedia.org/wiki/Triangular_distribution
@(require_results)
float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 { float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 {
if hi-lo == 0 { if hi-lo == 0 {
return lo return lo
@@ -41,20 +43,24 @@ float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32
// Normal/Gaussian Distribution // Normal/Gaussian Distribution
@(require_results)
float64_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 { float64_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 {
return norm_float64(r) * stddev + mean return norm_float64(r) * stddev + mean
} }
// Normal/Gaussian Distribution // Normal/Gaussian Distribution
@(require_results)
float32_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { float32_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
return f32(float64_normal(f64(mean), f64(stddev), r)) return f32(float64_normal(f64(mean), f64(stddev), r))
} }
// Log Normal Distribution // Log Normal Distribution
@(require_results)
float64_log_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 { float64_log_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 {
return math.exp(float64_normal(mean, stddev, r)) return math.exp(float64_normal(mean, stddev, r))
} }
// Log Normal Distribution // Log Normal Distribution
@(require_results)
float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 { float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
return f32(float64_log_normal(f64(mean), f64(stddev), r)) return f32(float64_log_normal(f64(mean), f64(stddev), r))
} }
@@ -65,6 +71,7 @@ float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
// Return values range from // Return values range from
// 0 to positive infinity if lambda > 0 // 0 to positive infinity if lambda > 0
// negative infinity to 0 if lambda <= 0 // negative infinity to 0 if lambda <= 0
@(require_results)
float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 { float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 {
return - math.ln(1 - float64(r)) / lambda return - math.ln(1 - float64(r)) / lambda
} }
@@ -73,6 +80,7 @@ float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 {
// Return values range from // Return values range from
// 0 to positive infinity if lambda > 0 // 0 to positive infinity if lambda > 0
// negative infinity to 0 if lambda <= 0 // negative infinity to 0 if lambda <= 0
@(require_results)
float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 { float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 {
return f32(float64_exponential(f64(lambda), r)) return f32(float64_exponential(f64(lambda), r))
} }
@@ -87,6 +95,7 @@ float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 {
// math.gamma(alpha) * math.pow(beta, alpha) // math.gamma(alpha) * math.pow(beta, alpha)
// //
// mean is alpha*beta, variance is math.pow(alpha*beta, 2) // mean is alpha*beta, variance is math.pow(alpha*beta, 2)
@(require_results)
float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
if alpha <= 0 || beta <= 0 { if alpha <= 0 || beta <= 0 {
panic(#procedure + ": alpha and beta must be > 0.0") panic(#procedure + ": alpha and beta must be > 0.0")
@@ -152,6 +161,7 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
// math.gamma(alpha) * math.pow(beta, alpha) // math.gamma(alpha) * math.pow(beta, alpha)
// //
// mean is alpha*beta, variance is math.pow(alpha*beta, 2) // mean is alpha*beta, variance is math.pow(alpha*beta, 2)
@(require_results)
float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
return f32(float64_gamma(f64(alpha), f64(beta), r)) return f32(float64_gamma(f64(alpha), f64(beta), r))
} }
@@ -162,6 +172,7 @@ float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
// Required: alpha > 0 and beta > 0 // Required: alpha > 0 and beta > 0
// //
// Return values range between 0 and 1 // Return values range between 0 and 1
@(require_results)
float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
if alpha <= 0 || beta <= 0 { if alpha <= 0 || beta <= 0 {
panic(#procedure + ": alpha and beta must be > 0.0") panic(#procedure + ": alpha and beta must be > 0.0")
@@ -178,6 +189,7 @@ float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
// Required: alpha > 0 and beta > 0 // Required: alpha > 0 and beta > 0
// //
// Return values range between 0 and 1 // Return values range between 0 and 1
@(require_results)
float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
return f32(float64_beta(f64(alpha), f64(beta), r)) return f32(float64_beta(f64(alpha), f64(beta), r))
} }
@@ -185,22 +197,26 @@ float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
// Pareto distribution, `alpha` is the shape parameter. // Pareto distribution, `alpha` is the shape parameter.
// https://wikipedia.org/wiki/Pareto_distribution // https://wikipedia.org/wiki/Pareto_distribution
@(require_results)
float64_pareto :: proc(alpha: f64, r: ^Rand = nil) -> f64 { float64_pareto :: proc(alpha: f64, r: ^Rand = nil) -> f64 {
return math.pow(1 - float64(r), -1.0 / alpha) return math.pow(1 - float64(r), -1.0 / alpha)
} }
// Pareto distribution, `alpha` is the shape parameter. // Pareto distribution, `alpha` is the shape parameter.
// https://wikipedia.org/wiki/Pareto_distribution // https://wikipedia.org/wiki/Pareto_distribution
@(require_results)
float32_pareto :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { float32_pareto :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
return f32(float64_pareto(f64(alpha), r)) return f32(float64_pareto(f64(alpha), r))
} }
// Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter. // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
@(require_results)
float64_weibull :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 { float64_weibull :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
u := 1 - float64(r) u := 1 - float64(r)
return alpha * math.pow(-math.ln(u), 1.0/beta) return alpha * math.pow(-math.ln(u), 1.0/beta)
} }
// Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter. // Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
@(require_results)
float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 { float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
return f32(float64_weibull(f64(alpha), f64(beta), r)) return f32(float64_weibull(f64(alpha), f64(beta), r))
} }
@@ -210,6 +226,7 @@ float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
// `mean_angle` is the in mean angle between 0 and 2pi radians // `mean_angle` is the in mean angle between 0 and 2pi radians
// `kappa` is the concentration parameter which must be >= 0 // `kappa` is the concentration parameter which must be >= 0
// When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi
@(require_results)
float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 { float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 {
// Fisher, N.I., "Statistical Analysis of Circular Data", Cambridge University Press, 1993. // Fisher, N.I., "Statistical Analysis of Circular Data", Cambridge University Press, 1993.
@@ -245,6 +262,7 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 {
// `mean_angle` is the in mean angle between 0 and 2pi radians // `mean_angle` is the in mean angle between 0 and 2pi radians
// `kappa` is the concentration parameter which must be >= 0 // `kappa` is the concentration parameter which must be >= 0
// When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi // When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi
@(require_results)
float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 { float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 {
return f32(float64_von_mises(f64(mean_angle), f64(kappa), r)) return f32(float64_von_mises(f64(mean_angle), f64(kappa), r))
} }
@@ -252,6 +270,7 @@ float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 {
// Cauchy-Lorentz Distribution // Cauchy-Lorentz Distribution
// `x_0` is the location, `gamma` is the scale where `gamma` > 0 // `x_0` is the location, `gamma` is the scale where `gamma` > 0
@(require_results)
float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 {
assert(gamma > 0) assert(gamma > 0)
@@ -261,6 +280,7 @@ float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 {
} }
// Cauchy-Lorentz Distribution // Cauchy-Lorentz Distribution
// `x_0` is the location, `gamma` is the scale where `gamma` > 0 // `x_0` is the location, `gamma` is the scale where `gamma` > 0
@(require_results)
float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), r)) return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), r))
} }
@@ -268,12 +288,14 @@ float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
// Log Cauchy-Lorentz Distribution // Log Cauchy-Lorentz Distribution
// `x_0` is the location, `gamma` is the scale where `gamma` > 0 // `x_0` is the location, `gamma` is the scale where `gamma` > 0
@(require_results)
float64_log_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 { float64_log_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 {
assert(gamma > 0) assert(gamma > 0)
return math.exp(math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0) return math.exp(math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0)
} }
// Log Cauchy-Lorentz Distribution // Log Cauchy-Lorentz Distribution
// `x_0` is the location, `gamma` is the scale where `gamma` > 0 // `x_0` is the location, `gamma` is the scale where `gamma` > 0
@(require_results)
float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 { float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), r)) return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), r))
} }
@@ -281,6 +303,7 @@ float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
// Laplace Distribution // Laplace Distribution
// `b` is the scale where `b` > 0 // `b` is the scale where `b` > 0
@(require_results)
float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 { float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 {
assert(b > 0) assert(b > 0)
p := float64(r)-0.5 p := float64(r)-0.5
@@ -288,6 +311,7 @@ float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 {
} }
// Laplace Distribution // Laplace Distribution
// `b` is the scale where `b` > 0 // `b` is the scale where `b` > 0
@(require_results)
float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 { float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 {
return f32(float64_laplace(f64(mean), f64(b), r)) return f32(float64_laplace(f64(mean), f64(b), r))
} }
@@ -296,6 +320,7 @@ float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 {
// Gompertz Distribution // Gompertz Distribution
// `eta` is the shape, `b` is the scale // `eta` is the shape, `b` is the scale
// Both `eta` and `b` must be > 0 // Both `eta` and `b` must be > 0
@(require_results)
float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 { float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 {
if eta <= 0 || b <= 0 { if eta <= 0 || b <= 0 {
panic(#procedure + ": eta and b must be > 0.0") panic(#procedure + ": eta and b must be > 0.0")
@@ -307,6 +332,7 @@ float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 {
// Gompertz Distribution // Gompertz Distribution
// `eta` is the shape, `b` is the scale // `eta` is the shape, `b` is the scale
// Both `eta` and `b` must be > 0 // Both `eta` and `b` must be > 0
@(require_results)
float32_gompertz :: proc(eta, b: f32, r: ^Rand = nil) -> f32 { float32_gompertz :: proc(eta, b: f32, r: ^Rand = nil) -> f32 {
return f32(float64_gompertz(f64(eta), f64(b), r)) return f32(float64_gompertz(f64(eta), f64(b), r))
} }
+1
View File
@@ -15,6 +15,7 @@ import "core:math"
// https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf] // https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf]
// https://www.jstatsoft.org/article/view/v005i08 [web page] // https://www.jstatsoft.org/article/view/v005i08 [web page]
// //
@(require_results)
exp_float64 :: proc(r: ^Rand = nil) -> f64 { exp_float64 :: proc(r: ^Rand = nil) -> f64 {
re :: 7.69711747013104972 re :: 7.69711747013104972
+1
View File
@@ -17,6 +17,7 @@ import "core:math"
// https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf] // https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf]
// https://www.jstatsoft.org/article/view/v005i08 [web page] // https://www.jstatsoft.org/article/view/v005i08 [web page]
// //
@(require_results)
norm_float64 :: proc(r: ^Rand = nil) -> f64 { norm_float64 :: proc(r: ^Rand = nil) -> f64 {
rn :: 3.442619855899 rn :: 3.442619855899
+645 -22
View File
@@ -1,6 +1,10 @@
/*
Package core:math/rand implements various random number generators
*/
package rand package rand
import "core:intrinsics" import "core:intrinsics"
import "core:mem"
Rand :: struct { Rand :: struct {
state: u64, state: u64,
@@ -12,16 +16,82 @@ Rand :: struct {
@(private) @(private)
global_rand := create(u64(intrinsics.read_cycle_counter())) global_rand := create(u64(intrinsics.read_cycle_counter()))
/*
Sets the seed used by the global random number generator.
Inputs:
- seed: The seed value
Example:
import "core:math/rand"
import "core:fmt"
set_global_seed_example :: proc() {
rand.set_global_seed(1)
fmt.println(rand.uint64())
}
Possible Output:
10
*/
set_global_seed :: proc(seed: u64) { set_global_seed :: proc(seed: u64) {
init(&global_rand, seed) init(&global_rand, seed)
} }
create :: proc(seed: u64) -> Rand { /*
Creates a new random number generator.
Inputs:
- seed: The seed value to create the random number generator with
Returns:
- res: The created random number generator
Example:
import "core:math/rand"
import "core:fmt"
create_example :: proc() {
my_rand := rand.create(1)
fmt.println(rand.uint64(&my_rand))
}
Possible Output:
10
*/
@(require_results)
create :: proc(seed: u64) -> (res: Rand) {
r: Rand r: Rand
init(&r, seed) init(&r, seed)
return r return r
} }
/*
Initialises a random number generator.
Inputs:
- r: The random number generator to initialise
- seed: The seed value to initialise this random number generator
Example:
import "core:math/rand"
import "core:fmt"
init_example :: proc() {
my_rand: rand.Rand
rand.init(&my_rand, 1)
fmt.println(rand.uint64(&my_rand))
}
Possible Output:
10
*/
init :: proc(r: ^Rand, seed: u64) { init :: proc(r: ^Rand, seed: u64) {
r.state = 0 r.state = 0
r.inc = (seed << 1) | 1 r.inc = (seed << 1) | 1
@@ -30,6 +100,35 @@ init :: proc(r: ^Rand, seed: u64) {
_random(r) _random(r)
} }
/*
Initialises a random number generator to use the system random number generator.
The system random number generator is platform specific.
On `linux` refer to the `getrandom` syscall.
On `darwin` refer to `getentropy`.
On `windows` refer to `BCryptGenRandom`.
All other platforms wi
Inputs:
- r: The random number generator to use the system random number generator
WARNING: Panics if the system is not either `windows`, `darwin` or `linux`
Example:
import "core:math/rand"
import "core:fmt"
init_as_system_example :: proc() {
my_rand: rand.Rand
rand.init_as_system(&my_rand)
fmt.println(rand.uint64(&my_rand))
}
Possible Output:
10
*/
init_as_system :: proc(r: ^Rand) { init_as_system :: proc(r: ^Rand) {
if !#defined(_system_random) { if !#defined(_system_random) {
panic(#procedure + " is not supported on this platform yet") panic(#procedure + " is not supported on this platform yet")
@@ -60,15 +159,99 @@ _random :: proc(r: ^Rand) -> u32 {
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31)) return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31))
} }
uint32 :: proc(r: ^Rand = nil) -> u32 { return _random(r) } /*
Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
uint64 :: proc(r: ^Rand = nil) -> u64 { Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random unsigned 32 bit value
Example:
import "core:math/rand"
import "core:fmt"
uint32_example :: proc() {
// Using the global random number generator
fmt.println(rand.uint32())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.uint32(&my_rand))
}
Possible Output:
10
389
*/
@(require_results)
uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return _random(r) }
/*
Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random unsigned 64 bit value
Example:
import "core:math/rand"
import "core:fmt"
uint64_example :: proc() {
// Using the global random number generator
fmt.println(rand.uint64())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.uint64(&my_rand))
}
Possible Output:
10
389
*/
@(require_results)
uint64 :: proc(r: ^Rand = nil) -> (val: u64) {
a := u64(_random(r)) a := u64(_random(r))
b := u64(_random(r)) b := u64(_random(r))
return (a<<32) | b return (a<<32) | b
} }
uint128 :: proc(r: ^Rand = nil) -> u128 { /*
Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random unsigned 128 bit value
Example:
import "core:math/rand"
import "core:fmt"
uint128_example :: proc() {
// Using the global random number generator
fmt.println(rand.uint128())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.uint128(&my_rand))
}
Possible Output:
10
389
*/
@(require_results)
uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
a := u128(_random(r)) a := u128(_random(r))
b := u128(_random(r)) b := u128(_random(r))
c := u128(_random(r)) c := u128(_random(r))
@@ -76,11 +259,126 @@ uint128 :: proc(r: ^Rand = nil) -> u128 {
return (a<<96) | (b<<64) | (c<<32) | d return (a<<96) | (b<<64) | (c<<32) | d
} }
int31 :: proc(r: ^Rand = nil) -> i32 { return i32(uint32(r) << 1 >> 1) } /*
int63 :: proc(r: ^Rand = nil) -> i64 { return i64(uint64(r) << 1 >> 1) } Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1) } The sign bit will always be set to 0, thus all generated numbers will be positive.
int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 { Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 31 bit value
Example:
import "core:math/rand"
import "core:fmt"
int31_example :: proc() {
// Using the global random number generator
fmt.println(rand.int31())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int31(&my_rand))
}
Possible Output:
10
389
*/
@(require_results) int31 :: proc(r: ^Rand = nil) -> (val: i32) { return i32(uint32(r) << 1 >> 1) }
/*
Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 63 bit value
Example:
import "core:math/rand"
import "core:fmt"
int63_example :: proc() {
// Using the global random number generator
fmt.println(rand.int63())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int63(&my_rand))
}
Possible Output:
10
389
*/
@(require_results) int63 :: proc(r: ^Rand = nil) -> (val: i64) { return i64(uint64(r) << 1 >> 1) }
/*
Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 127 bit value
Example:
import "core:math/rand"
import "core:fmt"
int127_example :: proc() {
// Using the global random number generator
fmt.println(rand.int127())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int127(&my_rand))
}
Possible Output:
10
389
*/
@(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) }
/*
Generates a random 31 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 31 bit value in the range `(0, n]`
WARNING: Panics if n is less than 0
Example:
import "core:math/rand"
import "core:fmt"
int31_max_example :: proc() {
// Using the global random number generator
fmt.println(rand.int31_max(16))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int31_max(1024, &my_rand))
}
Possible Output:
6
500
*/
@(require_results)
int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
if n <= 0 { if n <= 0 {
panic("Invalid argument to int31_max") panic("Invalid argument to int31_max")
} }
@@ -94,8 +392,38 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
} }
return v % n return v % n
} }
/*
Generates a random 63 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.
int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 { Inputs:
- n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 63 bit value in the range `(0, n]`
WARNING: Panics if n is less than 0
Example:
import "core:math/rand"
import "core:fmt"
int63_max_example :: proc() {
// Using the global random number generator
fmt.println(rand.int63_max(16))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int63_max(1024, &my_rand))
}
Possible Output:
6
500
*/
@(require_results)
int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
if n <= 0 { if n <= 0 {
panic("Invalid argument to int63_max") panic("Invalid argument to int63_max")
} }
@@ -109,8 +437,38 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
} }
return v % n return v % n
} }
/*
Generates a random 127 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.
int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 { Inputs:
- n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 127 bit value in the range `(0, n]`
WARNING: Panics if n is less than 0
Example:
import "core:math/rand"
import "core:fmt"
int127_max_example :: proc() {
// Using the global random number generator
fmt.println(rand.int127_max(16))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int127_max(1024, &my_rand))
}
Possible Output:
6
500
*/
@(require_results)
int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
if n <= 0 { if n <= 0 {
panic("Invalid argument to int127_max") panic("Invalid argument to int127_max")
} }
@@ -124,8 +482,38 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
} }
return v % n return v % n
} }
/*
Generates a random integer value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.
int_max :: proc(n: int, r: ^Rand = nil) -> int { Inputs:
- n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random integer value in the range `(0, n]`
WARNING: Panics if n is less than 0
Example:
import "core:math/rand"
import "core:fmt"
int_max_example :: proc() {
// Using the global random number generator
fmt.println(rand.int_max(16))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int_max(1024, &my_rand))
}
Possible Output:
6
500
*/
@(require_results)
int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) {
if n <= 0 { if n <= 0 {
panic("Invalid argument to int_max") panic("Invalid argument to int_max")
} }
@@ -136,14 +524,154 @@ int_max :: proc(n: int, r: ^Rand = nil) -> int {
} }
} }
// Uniform random distribution [0, 1) /*
float64 :: proc(r: ^Rand = nil) -> f64 { return f64(int63_max(1<<53, r)) / (1 << 53) } Generates a random double floating point value in the range `(0, 1]` using the provided random number generator. If no generator is provided the global random number generator will be used.
// Uniform random distribution [0, 1)
float32 :: proc(r: ^Rand = nil) -> f32 { return f32(float64(r)) }
float64_range :: proc(lo, hi: f64, r: ^Rand = nil) -> f64 { return (hi-lo)*float64(r) + lo } Inputs:
float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float32(r) + lo } - r: The random number generator to use, or nil for the global generator
Returns:
- val: A random double floating point value in the range `(0, 1]`
Example:
import "core:math/rand"
import "core:fmt"
float64_example :: proc() {
// Using the global random number generator
fmt.println(rand.float64())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.float64(&my_rand))
}
Possible Output:
0.043
0.511
*/
@(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) }
/*
Generates a random single floating point value in the range `(0, 1]` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random single floating point value in the range `(0, 1]`
Example:
import "core:math/rand"
import "core:fmt"
float32_example :: proc() {
// Using the global random number generator
fmt.println(rand.float32())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.float32(&my_rand))
}
Possible Output:
0.043
0.511
*/
@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(float64(r)) }
/*
Generates a random double floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- low: The lower bounds of the value, this value is inclusive
- high: The upper bounds of the value, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random double floating point value in the range `(low, high]`
Example:
import "core:math/rand"
import "core:fmt"
float64_range_example :: proc() {
// Using the global random number generator
fmt.println(rand.float64_range(-10, 300))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.float64_range(600, 900, &my_rand))
}
Possible Output:
15.312
673.130
*/
@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { return (high-low)*float64(r) + low }
/*
Generates a random single floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- low: The lower bounds of the value, this value is inclusive
- high: The upper bounds of the value, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random single floating point value in the range `(low, high]`
Example:
import "core:math/rand"
import "core:fmt"
float32_range_example :: proc() {
// Using the global random number generator
fmt.println(rand.float32_range(-10, 300))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.float32_range(600, 900, &my_rand))
}
Possible Output:
15.312
673.130
*/
@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { return (high-low)*float32(r) + low }
/*
Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- p: The byte slice to fill
- r: The random number generator to use, or nil for the global generator
Returns:
- n: The number of bytes generated
Example:
import "core:math/rand"
import "core:fmt"
read_example :: proc() {
// Using the global random number generator
data: [8]byte
n := rand.read(data[:])
fmt.println(n)
fmt.println(data)
}
Possible Output:
8
[32, 4, 59, 7, 1, 2, 2, 119]
*/
@(require_results)
read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) { read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
pos := i8(0) pos := i8(0)
val := i64(0) val := i64(0)
@@ -159,18 +687,81 @@ read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
return return
} }
// perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n) /*
perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int { Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
m := make([]int, n, allocator)
*Allocates Using Provided Allocator*
Inputs:
- n: The size of the created slice
- r: The random number generator to use, or nil for the global generator
- allocator: (default: context.allocator)
Returns:
- res: A slice filled with random values
- err: An allocator error if one occured, `nil` otherwise
Example:
import "core:math/rand"
import "core:mem"
import "core:fmt"
perm_example :: proc() -> (err: mem.Allocator_Error) {
// Using the global random number generator and using the context allocator
data := rand.perm(4) or_return
fmt.println(data)
defer delete(data, context.allocator)
// Using local random number generator and temp allocator
my_rand := rand.create(1)
data_tmp := rand.perm(4, &my_rand, context.temp_allocator) or_return
fmt.println(data_tmp)
return
}
Possible Output:
[7201011, 3, 9123, 231131]
[19578, 910081, 131, 7]
*/
@(require_results)
perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error {
m := make([]int, n, allocator) or_return
for i := 0; i < n; i += 1 { for i := 0; i < n; i += 1 {
j := int_max(i+1, r) j := int_max(i+1, r)
m[i] = m[j] m[i] = m[j]
m[j] = i m[j] = i
} }
return m return m, {}
} }
/*
Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used.
Inputs:
- array: The slice to randomize
- r: The random number generator to use, or nil for the global generator
Example:
import "core:math/rand"
import "core:fmt"
shuffle_example :: proc() {
// Using the global random number generator
data: [4]int = { 1, 2, 3, 4 }
fmt.println(data) // the contents are in order
rand.shuffle(data[:])
fmt.println(data) // the contents have been shuffled
}
Possible Output:
[1, 2, 3, 4]
[2, 4, 3, 1]
*/
shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) { shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
n := i64(len(array)) n := i64(len(array))
if n < 2 { if n < 2 {
@@ -183,7 +774,39 @@ shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
} }
} }
// Returns a random element from the given slice /*
Returns a random element from the provided slice. If no generator is provided the global random number generator will be used.
Inputs:
- array: The slice to choose an element from
- r: The random number generator to use, or nil for the global generator
Returns:
- res: A random element from `array`
Example:
import "core:math/rand"
import "core:fmt"
choice_example :: proc() {
// Using the global random number generator
data: [4]int = { 1, 2, 3, 4 }
fmt.println(rand.choice(data[:]))
fmt.println(rand.choice(data[:]))
fmt.println(rand.choice(data[:]))
fmt.println(rand.choice(data[:]))
}
Possible Output:
3
2
2
4
*/
@(require_results)
choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) { choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
n := i64(len(array)) n := i64(len(array))
if n < 1 { if n < 1 {
+1
View File
@@ -2,6 +2,7 @@ package rand
import "core:sys/darwin" import "core:sys/darwin"
@(require_results)
_system_random :: proc() -> u32 { _system_random :: proc() -> u32 {
for { for {
value: u32 value: u32
+1
View File
@@ -2,6 +2,7 @@ package rand
import "core:sys/unix" import "core:sys/unix"
@(require_results)
_system_random :: proc() -> u32 { _system_random :: proc() -> u32 {
for { for {
value: u32 value: u32
+1
View File
@@ -2,6 +2,7 @@ package rand
import win32 "core:sys/windows" import win32 "core:sys/windows"
@(require_results)
_system_random :: proc() -> u32 { _system_random :: proc() -> u32 {
value: u32 value: u32
status := win32.BCryptGenRandom(nil, ([^]u8)(&value), 4, win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG) status := win32.BCryptGenRandom(nil, ([^]u8)(&value), 4, win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)
+33 -33
View File
@@ -60,15 +60,18 @@ DEFAULT_PAGE_SIZE ::
16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else 16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else
4 * 1024 4 * 1024
alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { @(require_results)
data, _ := runtime.mem_alloc(size, alignment, allocator, loc) alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
return raw_data(data) data, err := runtime.mem_alloc(size, alignment, allocator, loc)
return raw_data(data), err
} }
@(require_results)
alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
return runtime.mem_alloc(size, alignment, allocator, loc) return runtime.mem_alloc(size, alignment, allocator, loc)
} }
@(require_results)
alloc_bytes_non_zeroed :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { alloc_bytes_non_zeroed :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
return runtime.mem_alloc_non_zeroed(size, alignment, allocator, loc) return runtime.mem_alloc_non_zeroed(size, alignment, allocator, loc)
} }
@@ -93,15 +96,18 @@ free_all :: proc(allocator := context.allocator, loc := #caller_location) -> All
return runtime.mem_free_all(allocator, loc) return runtime.mem_free_all(allocator, loc)
} }
resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { @(require_results)
data, _ := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc) resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
return raw_data(data) data, err := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
return raw_data(data), err
} }
@(require_results)
resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc) return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
} }
@(require_results)
query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) { query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
if allocator.procedure != nil { if allocator.procedure != nil {
allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc) allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
@@ -110,6 +116,7 @@ query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: A
return nil return nil
} }
@(require_results)
query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) { query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
props.pointer = pointer props.pointer = pointer
if allocator.procedure != nil { if allocator.procedure != nil {
@@ -146,14 +153,17 @@ delete :: proc{
} }
@(require_results)
new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) { new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) {
return new_aligned(T, align_of(T), allocator, loc) return new_aligned(T, align_of(T), allocator, loc)
} }
@(require_results)
new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) { new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
data := alloc_bytes(size_of(T), alignment, allocator, loc) or_return data := alloc_bytes(size_of(T), alignment, allocator, loc) or_return
t = (^T)(raw_data(data)) t = (^T)(raw_data(data))
return return
} }
@(require_results)
new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) { new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
backing := alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return backing := alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
t = (^T)(raw_data(backing)) t = (^T)(raw_data(backing))
@@ -164,6 +174,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat
return nil, .Out_Of_Memory return nil, .Out_Of_Memory
} }
@(require_results)
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) { make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) {
runtime.make_slice_error_loc(loc, len) runtime.make_slice_error_loc(loc, len)
data := alloc_bytes(size_of(E)*len, alignment, allocator, loc) or_return data := alloc_bytes(size_of(E)*len, alignment, allocator, loc) or_return
@@ -173,15 +184,19 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
slice = transmute(T)Raw_Slice{raw_data(data), len} slice = transmute(T)Raw_Slice{raw_data(data), len}
return return
} }
@(require_results)
make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) { make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
return make_aligned(T, len, align_of(E), allocator, loc) return make_aligned(T, len, align_of(E), allocator, loc)
} }
@(require_results)
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) { make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
return make_dynamic_array_len_cap(T, 0, 16, allocator, loc) return make_dynamic_array_len_cap(T, 0, 16, allocator, loc)
} }
@(require_results)
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) { make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
return make_dynamic_array_len_cap(T, len, len, allocator, loc) return make_dynamic_array_len_cap(T, len, len, allocator, loc)
} }
@(require_results)
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) { make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) {
runtime.make_dynamic_array_error_loc(loc, len, cap) runtime.make_dynamic_array_error_loc(loc, len, cap)
data := alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return data := alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
@@ -192,14 +207,15 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a
array = transmute(T)s array = transmute(T)s
return return
} }
make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> T { @(require_results)
make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) {
runtime.make_map_expr_error_loc(loc, cap) runtime.make_map_expr_error_loc(loc, cap)
context.allocator = allocator context.allocator = allocator
m: T err = reserve_map(&m, cap, loc)
reserve_map(&m, cap, loc) return
return m
} }
@(require_results)
make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) { make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) {
runtime.make_slice_error_loc(loc, len) runtime.make_slice_error_loc(loc, len)
data := alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return data := alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
@@ -220,30 +236,14 @@ make :: proc{
} }
@(require_results)
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> rawptr { default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> (res: rawptr, err: Allocator_Error) {
if old_memory == nil { data: []byte
return alloc(new_size, alignment, allocator, loc) data, err = default_resize_bytes_align(([^]byte)(old_memory)[:old_size], new_size, alignment, allocator, loc)
} res = raw_data(data)
return
if new_size == 0 {
free(old_memory, allocator, loc)
return nil
}
if new_size == old_size {
return old_memory
}
new_memory := alloc(new_size, alignment, allocator, loc)
if new_memory == nil {
return nil
}
copy(new_memory, old_memory, min(old_size, new_size))
free(old_memory, allocator, loc)
return new_memory
} }
@(require_results)
default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
old_memory := raw_data(old_data) old_memory := raw_data(old_data)
old_size := len(old_data) old_size := len(old_data)
+19 -3
View File
@@ -2,6 +2,7 @@ package mem
import "core:intrinsics" import "core:intrinsics"
import "core:runtime" import "core:runtime"
import "core:sync"
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int, size, alignment: int,
@@ -46,6 +47,7 @@ init_arena :: proc(a: ^Arena, data: []byte) {
a.temp_count = 0 a.temp_count = 0
} }
@(require_results)
arena_allocator :: proc(arena: ^Arena) -> Allocator { arena_allocator :: proc(arena: ^Arena) -> Allocator {
return Allocator{ return Allocator{
procedure = arena_allocator_proc, procedure = arena_allocator_proc,
@@ -100,6 +102,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, nil return nil, nil
} }
@(require_results)
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory { begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory tmp: Arena_Temp_Memory
tmp.arena = a tmp.arena = a
@@ -286,6 +289,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, nil return nil, nil
} }
@(require_results)
scratch_allocator :: proc(allocator: ^Scratch_Allocator) -> Allocator { scratch_allocator :: proc(allocator: ^Scratch_Allocator) -> Allocator {
return Allocator{ return Allocator{
procedure = scratch_allocator_proc, procedure = scratch_allocator_proc,
@@ -325,6 +329,7 @@ init_stack :: proc(s: ^Stack, data: []byte) {
s.peak_used = 0 s.peak_used = 0
} }
@(require_results)
stack_allocator :: proc(stack: ^Stack) -> Allocator { stack_allocator :: proc(stack: ^Stack) -> Allocator {
return Allocator{ return Allocator{
procedure = stack_allocator_proc, procedure = stack_allocator_proc,
@@ -490,6 +495,7 @@ init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
s.peak_used = 0 s.peak_used = 0
} }
@(require_results)
small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator { small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
return Allocator{ return Allocator{
procedure = small_stack_allocator_proc, procedure = small_stack_allocator_proc,
@@ -673,6 +679,7 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode
} }
@(require_results)
dynamic_pool_allocator :: proc(pool: ^Dynamic_Pool) -> Allocator { dynamic_pool_allocator :: proc(pool: ^Dynamic_Pool) -> Allocator {
return Allocator{ return Allocator{
procedure = dynamic_pool_allocator_proc, procedure = dynamic_pool_allocator_proc,
@@ -705,12 +712,13 @@ dynamic_pool_destroy :: proc(using pool: ^Dynamic_Pool) {
} }
dynamic_pool_alloc :: proc(pool: ^Dynamic_Pool, bytes: int) -> rawptr { @(require_results)
dynamic_pool_alloc :: proc(pool: ^Dynamic_Pool, bytes: int) -> (rawptr, Allocator_Error) {
data, err := dynamic_pool_alloc_bytes(pool, bytes) data, err := dynamic_pool_alloc_bytes(pool, bytes)
assert(err == nil) return raw_data(data), err
return raw_data(data)
} }
@(require_results)
dynamic_pool_alloc_bytes :: proc(using pool: ^Dynamic_Pool, bytes: int) -> ([]byte, Allocator_Error) { dynamic_pool_alloc_bytes :: proc(using pool: ^Dynamic_Pool, bytes: int) -> ([]byte, Allocator_Error) {
cycle_new_block :: proc(using pool: ^Dynamic_Pool) -> (err: Allocator_Error) { cycle_new_block :: proc(using pool: ^Dynamic_Pool) -> (err: Allocator_Error) {
if block_allocator.procedure == nil { if block_allocator.procedure == nil {
@@ -836,6 +844,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, nil return nil, nil
} }
@(require_results)
panic_allocator :: proc() -> Allocator { panic_allocator :: proc() -> Allocator {
return Allocator{ return Allocator{
procedure = panic_allocator_proc, procedure = panic_allocator_proc,
@@ -860,6 +869,7 @@ Tracking_Allocator :: struct {
backing: Allocator, backing: Allocator,
allocation_map: map[rawptr]Tracking_Allocator_Entry, allocation_map: map[rawptr]Tracking_Allocator_Entry,
bad_free_array: [dynamic]Tracking_Allocator_Bad_Free_Entry, bad_free_array: [dynamic]Tracking_Allocator_Bad_Free_Entry,
mutex: sync.Mutex,
clear_on_free_all: bool, clear_on_free_all: bool,
} }
@@ -880,11 +890,14 @@ tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
tracking_allocator_clear :: proc(t: ^Tracking_Allocator) { tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
sync.mutex_lock(&t.mutex)
clear(&t.allocation_map) clear(&t.allocation_map)
clear(&t.bad_free_array) clear(&t.bad_free_array)
sync.mutex_unlock(&t.mutex)
} }
@(require_results)
tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator { tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
return Allocator{ return Allocator{
data = data, data = data,
@@ -896,6 +909,9 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int, size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> (result: []byte, err: Allocator_Error) { old_memory: rawptr, old_size: int, loc := #caller_location) -> (result: []byte, err: Allocator_Error) {
data := (^Tracking_Allocator)(allocator_data) data := (^Tracking_Allocator)(allocator_data)
sync.mutex_guard(&data.mutex)
if mode == .Query_Info { if mode == .Query_Info {
info := (^Allocator_Query_Info)(old_memory) info := (^Allocator_Query_Info)(old_memory)
if info != nil && info.pointer != nil { if info != nil && info.pointer != nil {
+1
View File
@@ -18,6 +18,7 @@ _main :: proc() {
main :: proc() { main :: proc() {
track: mem.Tracking_Allocator track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator) mem.tracking_allocator_init(&track, context.allocator)
defer mem.tracking_allocator_destroy(&track)
context.allocator = mem.tracking_allocator(&track) context.allocator = mem.tracking_allocator(&track)
_main() _main()
+28
View File
@@ -53,14 +53,17 @@ compare :: proc "contextless" (a, b: []byte) -> int {
return res return res
} }
@(require_results)
compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check { compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
return runtime.memory_compare(a, b, n) return runtime.memory_compare(a, b, n)
} }
@(require_results)
check_zero :: proc(data: []byte) -> bool { check_zero :: proc(data: []byte) -> bool {
return check_zero_ptr(raw_data(data), len(data)) return check_zero_ptr(raw_data(data), len(data))
} }
@(require_results)
check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool { check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool {
switch { switch {
case len <= 0: case len <= 0:
@@ -101,11 +104,13 @@ check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool {
return true return true
} }
@(require_results)
simple_equal :: proc "contextless" (a, b: $T) -> bool where intrinsics.type_is_simple_compare(T) { simple_equal :: proc "contextless" (a, b: $T) -> bool where intrinsics.type_is_simple_compare(T) {
a, b := a, b a, b := a, b
return compare_byte_ptrs((^byte)(&a), (^byte)(&b), size_of(T)) == 0 return compare_byte_ptrs((^byte)(&a), (^byte)(&b), size_of(T)) == 0
} }
@(require_results)
compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int { compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int {
return compare_byte_ptrs((^byte)(a), (^byte)(b), n) return compare_byte_ptrs((^byte)(a), (^byte)(b), n)
} }
@@ -113,20 +118,24 @@ compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int {
ptr_offset :: intrinsics.ptr_offset ptr_offset :: intrinsics.ptr_offset
ptr_sub :: intrinsics.ptr_sub ptr_sub :: intrinsics.ptr_sub
@(require_results)
slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T { slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T {
return ([^]T)(ptr)[:len] return ([^]T)(ptr)[:len]
} }
@(require_results)
byte_slice :: #force_inline proc "contextless" (data: rawptr, #any_int len: int) -> []byte { byte_slice :: #force_inline proc "contextless" (data: rawptr, #any_int len: int) -> []byte {
return ([^]u8)(data)[:max(len, 0)] return ([^]u8)(data)[:max(len, 0)]
} }
@(require_results)
slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte { slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte {
s := transmute(Raw_Slice)slice s := transmute(Raw_Slice)slice
s.len *= size_of(T) s.len *= size_of(T)
return transmute([]byte)s return transmute([]byte)s
} }
@(require_results)
slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T { slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T {
when size_of(A) == 0 || size_of(B) == 0 { when size_of(A) == 0 || size_of(B) == 0 {
return nil return nil
@@ -137,11 +146,13 @@ slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T {
} }
} }
@(require_results)
slice_to_components :: proc "contextless" (slice: $E/[]$T) -> (data: ^T, len: int) { slice_to_components :: proc "contextless" (slice: $E/[]$T) -> (data: ^T, len: int) {
s := transmute(Raw_Slice)slice s := transmute(Raw_Slice)slice
return (^T)(s.data), s.len return (^T)(s.data), s.len
} }
@(require_results)
buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E { buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E {
return transmute([dynamic]E)Raw_Dynamic_Array{ return transmute([dynamic]E)Raw_Dynamic_Array{
data = raw_data(backing), data = raw_data(backing),
@@ -154,10 +165,12 @@ buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E {
} }
} }
@(require_results)
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte { ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte {
return transmute([]byte)Raw_Slice{ptr, len*size_of(T)} return transmute([]byte)Raw_Slice{ptr, len*size_of(T)}
} }
@(require_results)
any_to_bytes :: proc "contextless" (val: any) -> []byte { any_to_bytes :: proc "contextless" (val: any) -> []byte {
ti := type_info_of(val.id) ti := type_info_of(val.id)
size := ti != nil ? ti.size : 0 size := ti != nil ? ti.size : 0
@@ -165,6 +178,7 @@ any_to_bytes :: proc "contextless" (val: any) -> []byte {
} }
@(require_results)
is_power_of_two :: proc "contextless" (x: uintptr) -> bool { is_power_of_two :: proc "contextless" (x: uintptr) -> bool {
if x <= 0 { if x <= 0 {
return false return false
@@ -172,10 +186,12 @@ is_power_of_two :: proc "contextless" (x: uintptr) -> bool {
return (x & (x-1)) == 0 return (x & (x-1)) == 0
} }
@(require_results)
align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr { align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
return rawptr(align_forward_uintptr(uintptr(ptr), align)) return rawptr(align_forward_uintptr(uintptr(ptr), align))
} }
@(require_results)
align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr { align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
assert(is_power_of_two(align)) assert(is_power_of_two(align))
@@ -187,33 +203,41 @@ align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
return p return p
} }
@(require_results)
align_forward_int :: proc(ptr, align: int) -> int { align_forward_int :: proc(ptr, align: int) -> int {
return int(align_forward_uintptr(uintptr(ptr), uintptr(align))) return int(align_forward_uintptr(uintptr(ptr), uintptr(align)))
} }
@(require_results)
align_forward_uint :: proc(ptr, align: uint) -> uint { align_forward_uint :: proc(ptr, align: uint) -> uint {
return uint(align_forward_uintptr(uintptr(ptr), uintptr(align))) return uint(align_forward_uintptr(uintptr(ptr), uintptr(align)))
} }
@(require_results)
align_backward :: proc(ptr: rawptr, align: uintptr) -> rawptr { align_backward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
return rawptr(align_backward_uintptr(uintptr(ptr), align)) return rawptr(align_backward_uintptr(uintptr(ptr), align))
} }
@(require_results)
align_backward_uintptr :: proc(ptr, align: uintptr) -> uintptr { align_backward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
return align_forward_uintptr(ptr - align + 1, align) return align_forward_uintptr(ptr - align + 1, align)
} }
@(require_results)
align_backward_int :: proc(ptr, align: int) -> int { align_backward_int :: proc(ptr, align: int) -> int {
return int(align_backward_uintptr(uintptr(ptr), uintptr(align))) return int(align_backward_uintptr(uintptr(ptr), uintptr(align)))
} }
@(require_results)
align_backward_uint :: proc(ptr, align: uint) -> uint { align_backward_uint :: proc(ptr, align: uint) -> uint {
return uint(align_backward_uintptr(uintptr(ptr), uintptr(align))) return uint(align_backward_uintptr(uintptr(ptr), uintptr(align)))
} }
@(require_results)
context_from_allocator :: proc(a: Allocator) -> type_of(context) { context_from_allocator :: proc(a: Allocator) -> type_of(context) {
context.allocator = a context.allocator = a
return context return context
} }
@(require_results)
reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) { reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) {
copy(&value, ptr, size_of(T)) copy(&value, ptr, size_of(T))
return return
@@ -222,6 +246,7 @@ reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) {
Fixed_Byte_Buffer :: distinct [dynamic]byte Fixed_Byte_Buffer :: distinct [dynamic]byte
@(require_results)
make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buffer { make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buffer {
s := transmute(Raw_Slice)backing s := transmute(Raw_Slice)backing
d: Raw_Dynamic_Array d: Raw_Dynamic_Array
@@ -237,11 +262,13 @@ make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buf
@(require_results)
align_formula :: proc "contextless" (size, align: int) -> int { align_formula :: proc "contextless" (size, align: int) -> int {
result := size + align-1 result := size + align-1
return result - result%align return result - result%align
} }
@(require_results)
calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, header_size: int) -> int { calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, header_size: int) -> int {
p, a := ptr, align p, a := ptr, align
modulo := p & (a-1) modulo := p & (a-1)
@@ -267,6 +294,7 @@ calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, he
@(require_results, deprecated="prefer 'slice.clone'")
clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) { clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) {
new_slice, _ = make(T, len(slice), allocator, loc) new_slice, _ = make(T, len(slice), allocator, loc)
runtime.copy(new_slice, slice) runtime.copy(new_slice, slice)
+4
View File
@@ -392,6 +392,10 @@ load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocato
} }
addr := parse_address(server_ip_str) addr := parse_address(server_ip_str)
if addr == nil {
continue
}
endpoint := Endpoint{ endpoint := Endpoint{
addr, addr,
53, 53,
+19 -2
View File
@@ -303,8 +303,25 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
@(private) @(private)
_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { _set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
// TODO: Implement socket := any_socket_to_socket(socket)
unimplemented()
flags, getfl_err := os.fcntl(int(socket), os.F_GETFL, 0)
if getfl_err != os.ERROR_NONE {
return Set_Blocking_Error(getfl_err)
}
if should_block {
flags &= ~int(os.O_NONBLOCK)
} else {
flags |= int(os.O_NONBLOCK)
}
_, setfl_err := os.fcntl(int(socket), os.F_SETFL, flags)
if setfl_err != os.ERROR_NONE {
return Set_Blocking_Error(setfl_err)
}
return nil
} }
@private @private
+5 -1
View File
@@ -82,7 +82,11 @@ clone_node :: proc(node: ^Node) -> ^Node {
panic("Cannot clone this node type") panic("Cannot clone this node type")
} }
res := cast(^Node)mem.alloc(size, align) res := cast(^Node)(mem.alloc(size, align) or_else nil)
if res == nil {
// allocation failure
return nil
}
src: rawptr = node src: rawptr = node
if node.derived != nil { if node.derived != nil {
src = (^rawptr)(&node.derived)^ src = (^rawptr)(&node.derived)^
+22 -3
View File
@@ -267,6 +267,8 @@ SHUT_RD :: 0
SHUT_WR :: 1 SHUT_WR :: 1
SHUT_RDWR :: 2 SHUT_RDWR :: 2
F_GETFL: int : 3 /* Get file flags */
F_SETFL: int : 4 /* Set file flags */
// "Argv" arguments converted to Odin strings // "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments() args := _alloc_command_line_arguments()
@@ -413,7 +415,7 @@ F_OK :: 0 // Test for file existance
F_GETPATH :: 50 // return the full path of the fd F_GETPATH :: 50 // return the full path of the fd
foreign libc { foreign libc {
@(link_name="__error") __error :: proc() -> ^int --- @(link_name="__error") __error :: proc() -> ^c.int ---
@(link_name="open") _unix_open :: proc(path: cstring, flags: i32, mode: u16) -> Handle --- @(link_name="open") _unix_open :: proc(path: cstring, flags: i32, mode: u16) -> Handle ---
@(link_name="close") _unix_close :: proc(handle: Handle) -> c.int --- @(link_name="close") _unix_close :: proc(handle: Handle) -> c.int ---
@@ -438,7 +440,7 @@ foreign libc {
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
@(link_name="__fcntl") _unix__fcntl :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int --- @(link_name="__fcntl") _unix__fcntl :: proc(fd: Handle, cmd: c.int, #c_vararg args: ..any) -> c.int ---
@(link_name="rename") _unix_rename :: proc(old: cstring, new: cstring) -> c.int --- @(link_name="rename") _unix_rename :: proc(old: cstring, new: cstring) -> c.int ---
@(link_name="remove") _unix_remove :: proc(path: cstring) -> c.int --- @(link_name="remove") _unix_remove :: proc(path: cstring) -> c.int ---
@@ -464,6 +466,7 @@ foreign libc {
@(link_name="connect") _unix_connect :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int --- @(link_name="connect") _unix_connect :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int ---
@(link_name="bind") _unix_bind :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int --- @(link_name="bind") _unix_bind :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int ---
@(link_name="setsockopt") _unix_setsockopt :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int --- @(link_name="setsockopt") _unix_setsockopt :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int ---
@(link_name="getsockopt") _unix_getsockopt :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int ---
@(link_name="recvfrom") _unix_recvfrom :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: ^socklen_t) -> c.ssize_t --- @(link_name="recvfrom") _unix_recvfrom :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: ^socklen_t) -> c.ssize_t ---
@(link_name="recv") _unix_recv :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t --- @(link_name="recv") _unix_recv :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t ---
@(link_name="sendto") _unix_sendto :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: socklen_t) -> c.ssize_t --- @(link_name="sendto") _unix_sendto :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: socklen_t) -> c.ssize_t ---
@@ -489,7 +492,7 @@ foreign dl {
} }
get_last_error :: proc "contextless" () -> int { get_last_error :: proc "contextless" () -> int {
return __error()^ return int(__error()^)
} }
get_last_error_string :: proc() -> string { get_last_error_string :: proc() -> string {
@@ -1016,6 +1019,14 @@ setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen:
return ERROR_NONE return ERROR_NONE
} }
getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Errno {
result := _unix_getsockopt(int(sd), level, optname, optval, optlen)
if result < 0 {
return Errno(get_last_error())
}
return ERROR_NONE
}
recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Errno) { recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Errno) {
result := _unix_recvfrom(int(sd), raw_data(data), len(data), flags, addr, addr_size) result := _unix_recvfrom(int(sd), raw_data(data), len(data), flags, addr, addr_size)
if result < 0 { if result < 0 {
@@ -1055,3 +1066,11 @@ shutdown :: proc(sd: Socket, how: int) -> (Errno) {
} }
return ERROR_NONE return ERROR_NONE
} }
fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) {
result := _unix__fcntl(Handle(fd), c.int(cmd), c.int(arg))
if result < 0 {
return 0, Errno(get_last_error())
}
return int(result), ERROR_NONE
}
+190 -83
View File
@@ -6,7 +6,7 @@ import "core:intrinsics"
Maybe :: union($T: typeid) {T} Maybe :: union($T: typeid) {T}
@builtin @(builtin, require_results)
container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: typeid, $field_name: string) -> ^T container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: typeid, $field_name: string) -> ^T
where intrinsics.type_has_field(T, field_name), where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Field_Type { intrinsics.type_field_type(T, field_name) == Field_Type {
@@ -27,6 +27,11 @@ init_global_temporary_allocator :: proc(size: int, backup_allocator := context.a
} }
// `copy_slice` is a built-in procedure that copies elements from a source slice `src` to a destination slice `dst`.
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
// of len(src) and len(dst).
//
// Prefer the procedure group `copy`.
@builtin @builtin
copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int { copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
n := max(0, min(len(dst), len(src))) n := max(0, min(len(dst), len(src)))
@@ -35,6 +40,11 @@ copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
} }
return n return n
} }
// `copy_from_string` is a built-in procedure that copies elements from a source slice `src` to a destination string `dst`.
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
// of len(src) and len(dst).
//
// Prefer the procedure group `copy`.
@builtin @builtin
copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int { copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
n := max(0, min(len(dst), len(src))) n := max(0, min(len(dst), len(src)))
@@ -43,11 +53,20 @@ copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int
} }
return n return n
} }
// `copy` is a built-in procedure that copies elements from a source slice `src` to a destination slice/string `dst`.
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
// of len(src) and len(dst).
@builtin @builtin
copy :: proc{copy_slice, copy_from_string} copy :: proc{copy_slice, copy_from_string}
// `unordered_remove` removed the element at the specified `index`. It does so by replacing the current end value
// with the old value, and reducing the length of the dynamic array by 1.
//
// Note: This is an O(1) operation.
// Note: If you the elements to remain in their order, use `ordered_remove`.
// Note: If the index is out of bounds, this procedure will panic.
@builtin @builtin
unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check { unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array)) bounds_check_error_loc(loc, index, len(array))
@@ -57,7 +76,11 @@ unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_loca
} }
(^Raw_Dynamic_Array)(array).len -= 1 (^Raw_Dynamic_Array)(array).len -= 1
} }
// `ordered_remove` removed the element at the specified `index` whilst keeping the order of the other elements.
//
// Note: This is an O(N) operation.
// Note: If you the elements do not have to remain in their order, prefer `unordered_remove`.
// Note: If the index is out of bounds, this procedure will panic.
@builtin @builtin
ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check { ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array)) bounds_check_error_loc(loc, index, len(array))
@@ -67,6 +90,10 @@ ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_locati
(^Raw_Dynamic_Array)(array).len -= 1 (^Raw_Dynamic_Array)(array).len -= 1
} }
// `remove_range` removes a range of elements specified by the range `lo` and `hi`, whilst keeping the order of the other elements.
//
// Note: This is an O(N) operation.
// Note: If the range is out of bounds, this procedure will panic.
@builtin @builtin
remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_location) #no_bounds_check { remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_location) #no_bounds_check {
slice_expr_error_lo_hi_loc(loc, lo, hi, len(array)) slice_expr_error_lo_hi_loc(loc, lo, hi, len(array))
@@ -80,6 +107,9 @@ remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_locatio
} }
// `pop` will remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
//
// Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic.
@builtin @builtin
pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
assert(len(array) > 0, "", loc) assert(len(array) > 0, "", loc)
@@ -89,6 +119,8 @@ pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bou
} }
// `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
// If the operation is not possible, it will return false.
@builtin @builtin
pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check { pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
if len(array) == 0 { if len(array) == 0 {
@@ -99,6 +131,9 @@ pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check
return return
} }
// `pop_front` will remove and return the first value of dynamic array `array` and reduces the length of `array` by 1.
//
// Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic.
@builtin @builtin
pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
assert(len(array) > 0, "", loc) assert(len(array) > 0, "", loc)
@@ -110,6 +145,8 @@ pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #
return res return res
} }
// `pop_front_safe` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1.
// If the operation is not possible, it will return false.
@builtin @builtin
pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check { pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
if len(array) == 0 { if len(array) == 0 {
@@ -124,12 +161,15 @@ pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_
} }
// `clear` will set the length of a passed dynamic array or map to `0`
@builtin @builtin
clear :: proc{clear_dynamic_array, clear_map} clear :: proc{clear_dynamic_array, clear_map}
// `reserve` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
@builtin @builtin
reserve :: proc{reserve_dynamic_array, reserve_map} reserve :: proc{reserve_dynamic_array, reserve_map}
// `resize` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
@builtin @builtin
resize :: proc{resize_dynamic_array} resize :: proc{resize_dynamic_array}
@@ -137,36 +177,56 @@ resize :: proc{resize_dynamic_array}
@builtin @builtin
shrink :: proc{shrink_dynamic_array, shrink_map} shrink :: proc{shrink_dynamic_array, shrink_map}
// `free` will try to free the passed pointer, with the given `allocator` if the allocator supports this operation.
@builtin @builtin
free :: proc{mem_free} free :: proc{mem_free}
// `free_all` will try to free/reset all of the memory of the given `allocator` if the allocator supports this operation.
@builtin @builtin
free_all :: proc{mem_free_all} free_all :: proc{mem_free_all}
// `delete_string` will try to free the underlying data of the passed string, with the given `allocator` if the allocator supports this operation.
//
// Note: Prefer the procedure group `delete`.
@builtin @builtin
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free_with_size(raw_data(str), len(str), allocator, loc) return mem_free_with_size(raw_data(str), len(str), allocator, loc)
} }
// `delete_cstring` will try to free the underlying data of the passed string, with the given `allocator` if the allocator supports this operation.
//
// Note: Prefer the procedure group `delete`.
@builtin @builtin
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free((^byte)(str), allocator, loc) return mem_free((^byte)(str), allocator, loc)
} }
// `delete_dynamic_array` will try to free the underlying data of the passed dynamic array, with the given `allocator` if the allocator supports this operation.
//
// Note: Prefer the procedure group `delete`.
@builtin @builtin
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error { delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc) return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
} }
// `delete_slice` will try to free the underlying data of the passed sliced, with the given `allocator` if the allocator supports this operation.
//
// Note: Prefer the procedure group `delete`.
@builtin @builtin
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc) return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
} }
// `delete_map` will try to free the underlying data of the passed map, with the given `allocator` if the allocator supports this operation.
//
// Note: Prefer the procedure group `delete`.
@builtin @builtin
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error { delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
return map_free_dynamic(transmute(Raw_Map)m, map_info(T), loc) return map_free_dynamic(transmute(Raw_Map)m, map_info(T), loc)
} }
// `delete` will try to free the underlying data of the passed built-in data structure (string, cstring, dynamic array, slice, or map), with the given `allocator` if the allocator supports this operation.
//
// Note: Prefer `delete` over the specific `delete_*` procedures where possible.
@builtin @builtin
delete :: proc{ delete :: proc{
delete_string, delete_string,
@@ -179,17 +239,18 @@ delete :: proc{
// The new built-in procedure allocates memory. The first argument is a type, not a value, and the value // The new built-in procedure allocates memory. The first argument is a type, not a value, and the value
// return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator // return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator
@builtin @(builtin, require_results)
new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error { new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error {
return new_aligned(T, align_of(T), allocator, loc) return new_aligned(T, align_of(T), allocator, loc)
} }
@(require_results)
new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) { new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return
t = (^T)(raw_data(data)) t = (^T)(raw_data(data))
return return
} }
@builtin @(builtin, require_results)
new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error { new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error {
t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
t = (^T)(raw_data(t_data)) t = (^T)(raw_data(t_data))
@@ -201,6 +262,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat
DEFAULT_RESERVE_CAPACITY :: 16 DEFAULT_RESERVE_CAPACITY :: 16
@(require_results)
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
make_slice_error_loc(loc, len) make_slice_error_loc(loc, len)
data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc) data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc)
@@ -211,19 +273,35 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
return transmute(T)s, err return transmute(T)s, err
} }
@(builtin) // `make_slice` allocates and initializes a slice. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
// Note: Prefer using the procedure group `make`.
@(builtin, require_results)
make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
return make_aligned(T, len, align_of(E), allocator, loc) return make_aligned(T, len, align_of(E), allocator, loc)
} }
@(builtin) // `make_dynamic_array` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
// Note: Prefer using the procedure group `make`.
@(builtin, require_results)
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc) return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc)
} }
@(builtin) // `make_dynamic_array_len` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
// Note: Prefer using the procedure group `make`.
@(builtin, require_results)
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
return make_dynamic_array_len_cap(T, len, len, allocator, loc) return make_dynamic_array_len_cap(T, len, len, allocator, loc)
} }
@(builtin) // `make_dynamic_array_len_cap` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
// Note: Prefer using the procedure group `make`.
@(builtin, require_results)
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error { make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
make_dynamic_array_error_loc(loc, len, cap) make_dynamic_array_error_loc(loc, len, cap)
data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
@@ -234,7 +312,11 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #a
array = transmute(T)s array = transmute(T)s
return return
} }
@(builtin) // `make_map` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
// Note: Prefer using the procedure group `make`.
@(builtin, require_results)
make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error { make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
make_map_expr_error_loc(loc, capacity) make_map_expr_error_loc(loc, capacity)
context.allocator = allocator context.allocator = allocator
@@ -242,7 +324,13 @@ make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_
err = reserve_map(&m, capacity, loc) err = reserve_map(&m, capacity, loc)
return return
} }
@(builtin) // `make_multi_pointer` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
// This is "similar" to doing `raw_data(make([]E, len, allocator))`.
//
// Note: Prefer using the procedure group `make`.
@(builtin, require_results)
make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_allocator_error { make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_allocator_error {
make_slice_error_loc(loc, len) make_slice_error_loc(loc, len)
data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
@@ -254,8 +342,9 @@ make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := con
} }
// The make built-in procedure allocates and initializes a value of type slice, dynamic array, or map (only) // `make` built-in procedure allocates and initializes a value of type slice, dynamic array, map, or multi-pointer (only).
// Similar to new, the first argument is a type, not a value. Unlike new, make's return type is the same as the //
// Similar to `new`, the first argument is a type, not a value. Unlike new, make's return type is the same as the
// type of its argument, not a pointer to it. // type of its argument, not a pointer to it.
// Make uses the specified allocator, default is context.allocator, default is context.allocator // Make uses the specified allocator, default is context.allocator, default is context.allocator
@builtin @builtin
@@ -270,6 +359,9 @@ make :: proc{
// `clear_map` will set the length of a passed map to `0`
//
// Note: Prefer the procedure group `clear`
@builtin @builtin
clear_map :: proc "contextless" (m: ^$T/map[$K]$V) { clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
if m == nil { if m == nil {
@@ -278,19 +370,21 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
map_clear_dynamic((^Raw_Map)(m), map_info(T)) map_clear_dynamic((^Raw_Map)(m), map_info(T))
} }
// `reserve_map` will try to reserve memory of a passed map to the requested element count (setting the `cap`).
//
// Note: Prefer the procedure group `reserve`
@builtin @builtin
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) -> Allocator_Error { reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) -> Allocator_Error {
return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
} }
/* // Shrinks the capacity of a map down to the current length.
Shrinks the capacity of a map down to the current length. //
*/ // Note: Prefer the procedure group `shrink`
@builtin @builtin
shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool) { shrink_map :: proc(m: ^$T/map[$K]$V, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
if m != nil { if m != nil {
err := map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc) return map_shrink_dynamic((^Raw_Map)(m), map_info(T), loc)
did_shrink = err == nil
} }
return return
} }
@@ -313,18 +407,18 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
@builtin @builtin
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int { append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return 0 return 0, nil
} }
when size_of(E) == 0 { when size_of(E) == 0 {
array := (^Raw_Dynamic_Array)(array) array := (^Raw_Dynamic_Array)(array)
array.len += 1 array.len += 1
return 1 return 1, nil
} else { } else {
if cap(array) < len(array)+1 { if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1) cap := 2 * cap(array) + max(8, 1)
_ = reserve(array, cap, loc) err = reserve(array, cap, loc) // do not 'or_return' here as it could be a partial success
} }
if cap(array)-len(array) > 0 { if cap(array)-len(array) > 0 {
a := (^Raw_Dynamic_Array)(array) a := (^Raw_Dynamic_Array)(array)
@@ -334,31 +428,31 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) ->
data[a.len] = arg data[a.len] = arg
} }
a.len += 1 a.len += 1
return 1 return 1, err
} }
return 0 return 0, err
} }
} }
@builtin @builtin
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int { append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return 0 return 0, nil
} }
arg_len := len(args) arg_len := len(args)
if arg_len <= 0 { if arg_len <= 0 {
return 0 return 0, nil
} }
when size_of(E) == 0 { when size_of(E) == 0 {
array := (^Raw_Dynamic_Array)(array) array := (^Raw_Dynamic_Array)(array)
array.len += arg_len array.len += arg_len
return arg_len return arg_len, nil
} else { } else {
if cap(array) < len(array)+arg_len { if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len) cap := 2 * cap(array) + max(8, arg_len)
_ = reserve(array, cap, loc) err = reserve(array, cap, loc) // do not 'or_return' here as it could be a partial success
} }
arg_len = min(cap(array)-len(array), arg_len) arg_len = min(cap(array)-len(array), arg_len)
if arg_len > 0 { if arg_len > 0 {
@@ -370,13 +464,13 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
} }
a.len += arg_len a.len += arg_len
} }
return arg_len return arg_len, err
} }
} }
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type // The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
@builtin @builtin
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> int { append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
args := transmute([]E)arg args := transmute([]E)arg
return append_elems(array=array, args=args, loc=loc) return append_elems(array=array, args=args, loc=loc)
} }
@@ -384,9 +478,14 @@ append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #ca
// The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type // The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
@builtin @builtin
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int) { append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
n_arg: int
for arg in args { for arg in args {
n += append(array = array, args = transmute([]E)(arg), loc = loc) n_arg, err = append(array = array, args = transmute([]E)(arg), loc = loc)
n += n_arg
if err != nil {
return
}
} }
return return
} }
@@ -396,18 +495,18 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
@builtin @builtin
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int { append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return 0 return 0, nil
} }
prev_len := len(array) prev_len := len(array)
resize(array, len(array)+1, loc) resize(array, len(array)+1, loc) or_return
return len(array)-prev_len return len(array)-prev_len, nil
} }
@builtin @builtin
inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check { inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if array == nil { if array == nil {
return return
} }
@@ -415,18 +514,17 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
m :: 1 m :: 1
new_size := n + m new_size := n + m
if resize(array, new_size, loc) { resize(array, new_size, loc) or_return
when size_of(E) != 0 { when size_of(E) != 0 {
copy(array[index + m:], array[index:]) copy(array[index + m:], array[index:])
array[index] = arg array[index] = arg
}
ok = true
} }
ok = true
return return
} }
@builtin @builtin
inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check { inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if array == nil { if array == nil {
return return
} }
@@ -439,18 +537,17 @@ inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
m := len(args) m := len(args)
new_size := n + m new_size := n + m
if resize(array, new_size, loc) { resize(array, new_size, loc) or_return
when size_of(E) != 0 { when size_of(E) != 0 {
copy(array[index + m:], array[index:]) copy(array[index + m:], array[index:])
copy(array[index:], args) copy(array[index:], args)
}
ok = true
} }
ok = true
return return
} }
@builtin @builtin
inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check { inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if array == nil { if array == nil {
return return
} }
@@ -463,11 +560,10 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
m := len(arg) m := len(arg)
new_size := n + m new_size := n + m
if resize(array, new_size, loc) { resize(array, new_size, loc) or_return
copy(array[index+m:], array[index:]) copy(array[index+m:], array[index:])
copy(array[index:], arg) copy(array[index:], arg)
ok = true ok = true
}
return return
} }
@@ -476,11 +572,12 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
@builtin @builtin
assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check { assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if index < len(array) { if index < len(array) {
array[index] = arg array[index] = arg
ok = true ok = true
} else if resize(array, index+1, loc) { } else {
resize(array, index+1, loc) or_return
array[index] = arg array[index] = arg
ok = true ok = true
} }
@@ -489,11 +586,12 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
@builtin @builtin
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check { assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if index+len(args) < len(array) { if index+len(args) < len(array) {
copy(array[index:], args) copy(array[index:], args)
ok = true ok = true
} else if resize(array, index+1+len(args), loc) { } else {
resize(array, index+1+len(args), loc) or_return
copy(array[index:], args) copy(array[index:], args)
ok = true ok = true
} }
@@ -502,13 +600,14 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
@builtin @builtin
assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check { assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if len(args) == 0 { if len(args) == 0 {
ok = true ok = true
} else if index+len(args) < len(array) { } else if index+len(args) < len(array) {
copy(array[index:], args) copy(array[index:], args)
ok = true ok = true
} else if resize(array, index+1+len(args), loc) { } else {
resize(array, index+1+len(args), loc) or_return
copy(array[index:], args) copy(array[index:], args)
ok = true ok = true
} }
@@ -520,6 +619,9 @@ assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
// `clear_dynamic_array` will set the length of a passed dynamic array to `0`
//
// Note: Prefer the procedure group `clear`.
@builtin @builtin
clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) { clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
if array != nil { if array != nil {
@@ -527,15 +629,18 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
} }
} }
// `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
//
// Note: Prefer the procedure group `reserve`.
@builtin @builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool { reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
if array == nil { if array == nil {
return false return nil
} }
a := (^Raw_Dynamic_Array)(array) a := (^Raw_Dynamic_Array)(array)
if capacity <= a.cap { if capacity <= a.cap {
return true return nil
} }
if a.allocator.procedure == nil { if a.allocator.procedure == nil {
@@ -547,26 +652,29 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
new_size := capacity * size_of(E) new_size := capacity * size_of(E)
allocator := a.allocator allocator := a.allocator
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
if new_data == nil || err != nil { if new_data == nil && new_size > 0 {
return false return .Out_Of_Memory
} }
a.data = raw_data(new_data) a.data = raw_data(new_data)
a.cap = capacity a.cap = capacity
return true return nil
} }
// `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
//
// Note: Prefer the procedure group `resize`
@builtin @builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool { resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
if array == nil { if array == nil {
return false return nil
} }
a := (^Raw_Dynamic_Array)(array) a := (^Raw_Dynamic_Array)(array)
if length <= a.cap { if length <= a.cap {
a.len = max(length, 0) a.len = max(length, 0)
return true return nil
} }
if a.allocator.procedure == nil { if a.allocator.procedure == nil {
@@ -578,15 +686,15 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
new_size := length * size_of(E) new_size := length * size_of(E)
allocator := a.allocator allocator := a.allocator
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
if new_data == nil || err != nil { if new_data == nil && new_size > 0 {
return false return .Out_Of_Memory
} }
a.data = raw_data(new_data) a.data = raw_data(new_data)
a.len = length a.len = length
a.cap = length a.cap = length
return true return nil
} }
/* /*
@@ -597,8 +705,10 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
Returns false if `cap(array) < new_cap`, or the allocator report failure. Returns false if `cap(array) < new_cap`, or the allocator report failure.
If `len(array) < new_cap`, then `len(array)` will be left unchanged. If `len(array) < new_cap`, then `len(array)` will be left unchanged.
Note: Prefer the procedure group `shrink`
*/ */
shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool) { shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
if array == nil { if array == nil {
return return
} }
@@ -618,15 +728,12 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
old_size := a.cap * size_of(E) old_size := a.cap * size_of(E)
new_size := new_cap * size_of(E) new_size := new_cap * size_of(E)
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc) new_data := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc) or_return
if err != nil {
return
}
a.data = raw_data(new_data) a.data = raw_data(new_data)
a.len = min(new_cap, a.len) a.len = min(new_cap, a.len)
a.cap = new_cap a.cap = new_cap
return true return true, nil
} }
@builtin @builtin
+19 -19
View File
@@ -37,12 +37,12 @@ inverse :: proc{
matrix4x4_inverse, matrix4x4_inverse,
} }
@(builtin) @(builtin, require_results)
hermitian_adjoint :: proc "contextless" (m: $M/matrix[$N, N]$T) -> M where intrinsics.type_is_complex(T), N >= 1 { hermitian_adjoint :: proc "contextless" (m: $M/matrix[$N, N]$T) -> M where intrinsics.type_is_complex(T), N >= 1 {
return conj(transpose(m)) return conj(transpose(m))
} }
@(builtin) @(builtin, require_results)
matrix_trace :: proc "contextless" (m: $M/matrix[$N, N]$T) -> (trace: T) { matrix_trace :: proc "contextless" (m: $M/matrix[$N, N]$T) -> (trace: T) {
for i in 0..<N { for i in 0..<N {
trace += m[i, i] trace += m[i, i]
@@ -50,7 +50,7 @@ matrix_trace :: proc "contextless" (m: $M/matrix[$N, N]$T) -> (trace: T) {
return return
} }
@(builtin) @(builtin, require_results)
matrix_minor :: proc "contextless" (m: $M/matrix[$N, N]$T, row, column: int) -> (minor: T) where N > 1 { matrix_minor :: proc "contextless" (m: $M/matrix[$N, N]$T, row, column: int) -> (minor: T) where N > 1 {
K :: N-1 K :: N-1
cut_down: matrix[K, K]T cut_down: matrix[K, K]T
@@ -66,23 +66,23 @@ matrix_minor :: proc "contextless" (m: $M/matrix[$N, N]$T, row, column: int) ->
@(builtin) @(builtin, require_results)
matrix1x1_determinant :: proc "contextless" (m: $M/matrix[1, 1]$T) -> (det: T) { matrix1x1_determinant :: proc "contextless" (m: $M/matrix[1, 1]$T) -> (det: T) {
return m[0, 0] return m[0, 0]
} }
@(builtin) @(builtin, require_results)
matrix2x2_determinant :: proc "contextless" (m: $M/matrix[2, 2]$T) -> (det: T) { matrix2x2_determinant :: proc "contextless" (m: $M/matrix[2, 2]$T) -> (det: T) {
return m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] return m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0]
} }
@(builtin) @(builtin, require_results)
matrix3x3_determinant :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) { matrix3x3_determinant :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) {
a := +m[0, 0] * (m[1, 1] * m[2, 2] - m[1, 2] * m[2, 1]) a := +m[0, 0] * (m[1, 1] * m[2, 2] - m[1, 2] * m[2, 1])
b := -m[0, 1] * (m[1, 0] * m[2, 2] - m[1, 2] * m[2, 0]) b := -m[0, 1] * (m[1, 0] * m[2, 2] - m[1, 2] * m[2, 0])
c := +m[0, 2] * (m[1, 0] * m[2, 1] - m[1, 1] * m[2, 0]) c := +m[0, 2] * (m[1, 0] * m[2, 1] - m[1, 1] * m[2, 0])
return a + b + c return a + b + c
} }
@(builtin) @(builtin, require_results)
matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) { matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
a := adjugate(m) a := adjugate(m)
#no_bounds_check for i in 0..<4 { #no_bounds_check for i in 0..<4 {
@@ -94,13 +94,13 @@ matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
@(builtin) @(builtin, require_results)
matrix1x1_adjugate :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { matrix1x1_adjugate :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
y = x y = x
return return
} }
@(builtin) @(builtin, require_results)
matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
y[0, 0] = +x[1, 1] y[0, 0] = +x[1, 1]
y[0, 1] = -x[1, 0] y[0, 1] = -x[1, 0]
@@ -109,7 +109,7 @@ matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
return return
} }
@(builtin) @(builtin, require_results)
matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
@@ -124,7 +124,7 @@ matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
} }
@(builtin) @(builtin, require_results)
matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
@@ -135,13 +135,13 @@ matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
return return
} }
@(builtin) @(builtin, require_results)
matrix1x1_inverse_transpose :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { matrix1x1_inverse_transpose :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
y[0, 0] = 1/x[0, 0] y[0, 0] = 1/x[0, 0]
return return
} }
@(builtin) @(builtin, require_results)
matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
d := x[0, 0]*x[1, 1] - x[0, 1]*x[1, 0] d := x[0, 0]*x[1, 1] - x[0, 1]*x[1, 0]
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
@@ -159,7 +159,7 @@ matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
return return
} }
@(builtin) @(builtin, require_results)
matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) a := adjugate(x)
d := determinant(x) d := determinant(x)
@@ -180,7 +180,7 @@ matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y:
return return
} }
@(builtin) @(builtin, require_results)
matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) a := adjugate(x)
d: T d: T
@@ -204,13 +204,13 @@ matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y:
return return
} }
@(builtin) @(builtin, require_results)
matrix1x1_inverse :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { matrix1x1_inverse :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
y[0, 0] = 1/x[0, 0] y[0, 0] = 1/x[0, 0]
return return
} }
@(builtin) @(builtin, require_results)
matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
d := x[0, 0]*x[1, 1] - x[0, 1]*x[1, 0] d := x[0, 0]*x[1, 1] - x[0, 1]*x[1, 0]
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
@@ -228,7 +228,7 @@ matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
return return
} }
@(builtin) @(builtin, require_results)
matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) a := adjugate(x)
d := determinant(x) d := determinant(x)
@@ -249,7 +249,7 @@ matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou
return return
} }
@(builtin) @(builtin, require_results)
matrix4x4_inverse :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { matrix4x4_inverse :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) a := adjugate(x)
d: T d: T
+48 -51
View File
@@ -50,6 +50,7 @@ Raw_SOA_Footer_Dynamic_Array :: struct {
allocator: Allocator, allocator: Allocator,
} }
@(builtin, require_results)
raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Slice) { raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Slice) {
if array == nil { if array == nil {
return nil return nil
@@ -58,6 +59,7 @@ raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Sl
footer = (^Raw_SOA_Footer_Slice)(uintptr(array) + field_count*size_of(rawptr)) footer = (^Raw_SOA_Footer_Slice)(uintptr(array) + field_count*size_of(rawptr))
return return
} }
@(builtin, require_results)
raw_soa_footer_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) -> (footer: ^Raw_SOA_Footer_Dynamic_Array) { raw_soa_footer_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) -> (footer: ^Raw_SOA_Footer_Dynamic_Array) {
if array == nil { if array == nil {
return nil return nil
@@ -78,7 +80,7 @@ raw_soa_footer :: proc{
@builtin @(builtin, require_results)
make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error { make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
if length <= 0 { if length <= 0 {
return return
@@ -137,32 +139,31 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc
return return
} }
@builtin @(builtin, require_results)
make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error { make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
return make_soa_aligned(T, length, align_of(E), allocator, loc) return make_soa_aligned(T, length, align_of(E), allocator, loc)
} }
@builtin @(builtin, require_results)
make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T) { make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
context.allocator = allocator context.allocator = allocator
reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) or_return
return return array, nil
} }
@builtin @(builtin, require_results)
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
context.allocator = allocator context.allocator = allocator
resize_soa(&array, length, loc) resize_soa(&array, length, loc) or_return
return return array, nil
} }
@builtin @(builtin, require_results)
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
context.allocator = allocator context.allocator = allocator
if reserve_soa(&array, capacity, loc) { reserve_soa(&array, capacity, loc) or_return
resize_soa(&array, length, loc) resize_soa(&array, length, loc) or_return
} return array, nil
return
} }
@@ -176,27 +177,25 @@ make_soa :: proc{
@builtin @builtin
resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> bool { resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
if array == nil { if array == nil {
return false return nil
}
if !reserve_soa(array, length, loc) {
return false
} }
reserve_soa(array, length, loc) or_return
footer := raw_soa_footer(array) footer := raw_soa_footer(array)
footer.len = length footer.len = length
return true return nil
} }
@builtin @builtin
reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool { reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
if array == nil { if array == nil {
return false return nil
} }
old_cap := cap(array) old_cap := cap(array)
if capacity <= old_cap { if capacity <= old_cap {
return true return nil
} }
if array.allocator.procedure == nil { if array.allocator.procedure == nil {
@@ -207,7 +206,7 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
footer := raw_soa_footer(array) footer := raw_soa_footer(array)
if size_of(E) == 0 { if size_of(E) == 0 {
footer.cap = capacity footer.cap = capacity
return true return nil
} }
ti := type_info_of(typeid_of(T)) ti := type_info_of(typeid_of(T))
@@ -238,13 +237,10 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
old_data := (^rawptr)(array)^ old_data := (^rawptr)(array)^
new_bytes, err := array.allocator.procedure( new_bytes := array.allocator.procedure(
array.allocator.data, .Alloc, new_size, max_align, array.allocator.data, .Alloc, new_size, max_align,
nil, old_size, loc, nil, old_size, loc,
) ) or_return
if new_bytes == nil || err != nil {
return false
}
new_data := raw_data(new_bytes) new_data := raw_data(new_bytes)
@@ -269,31 +265,28 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
new_offset += type.size * capacity new_offset += type.size * capacity
} }
_, err = array.allocator.procedure( array.allocator.procedure(
array.allocator.data, .Free, 0, max_align, array.allocator.data, .Free, 0, max_align,
old_data, old_size, loc, old_data, old_size, loc,
) ) or_return
return true return nil
} }
@builtin @builtin
append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) { append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return return 0, nil
} }
arg_len := 1 if cap(array) <= len(array) + 1 {
cap := 2 * cap(array) + 8
if cap(array) <= len(array)+arg_len { err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
cap := 2 * cap(array) + max(8, arg_len)
_ = reserve_soa(array, cap, loc)
} }
arg_len = min(cap(array)-len(array), arg_len)
footer := raw_soa_footer(array) footer := raw_soa_footer(array)
if size_of(E) > 0 && arg_len > 0 { if size_of(E) > 0 && cap(array)-len(array) > 0 {
ti := type_info_of(typeid_of(T)) ti := type_info_of(typeid_of(T))
ti = type_info_base(ti) ti = type_info_base(ti)
si := &ti.variant.(Type_Info_Struct) si := &ti.variant.(Type_Info_Struct)
@@ -326,12 +319,14 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat
soa_offset += type.size * cap(array) soa_offset += type.size * cap(array)
item_offset += type.size item_offset += type.size
} }
footer.len += 1
return 1, err
} }
footer.len += arg_len return 0, err
} }
@builtin @builtin
append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) { append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return return
} }
@@ -343,7 +338,7 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
if cap(array) <= len(array)+arg_len { if cap(array) <= len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len) cap := 2 * cap(array) + max(8, arg_len)
_ = reserve_soa(array, cap, loc) err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
} }
arg_len = min(cap(array)-len(array), arg_len) arg_len = min(cap(array)-len(array), arg_len)
@@ -380,8 +375,8 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
item_offset += type.size item_offset += type.size
} }
} }
footer.len += arg_len footer.len += arg_len
return arg_len, err
} }
@@ -393,21 +388,23 @@ append_soa :: proc{
} }
delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) { delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
when intrinsics.type_struct_field_count(E) != 0 { when intrinsics.type_struct_field_count(E) != 0 {
array := array array := array
ptr := (^rawptr)(&array)^ ptr := (^rawptr)(&array)^
free(ptr, allocator, loc) free(ptr, allocator, loc) or_return
} }
return nil
} }
delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) { delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) -> Allocator_Error {
when intrinsics.type_struct_field_count(E) != 0 { when intrinsics.type_struct_field_count(E) != 0 {
array := array array := array
ptr := (^rawptr)(&array)^ ptr := (^rawptr)(&array)^
footer := raw_soa_footer(&array) footer := raw_soa_footer(&array)
free(ptr, footer.allocator, loc) free(ptr, footer.allocator, loc) or_return
} }
return nil
} }
+90 -25
View File
@@ -251,6 +251,26 @@ map_hash_is_valid :: #force_inline proc "contextless" (hash: Map_Hash) -> bool {
return (hash != 0) & (hash & TOMBSTONE_MASK == 0) return (hash != 0) & (hash & TOMBSTONE_MASK == 0)
} }
@(require_results)
map_seed :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
return map_seed_from_map_data(map_data(m))
}
// splitmix for uintptr
@(require_results)
map_seed_from_map_data :: #force_inline proc "contextless" (data: uintptr) -> uintptr {
when size_of(uintptr) == size_of(u64) {
mix := data + 0x9e3779b97f4a7c15
mix = (mix ~ (mix >> 30)) * 0xbf58476d1ce4e5b9
mix = (mix ~ (mix >> 27)) * 0x94d049bb133111eb
return mix ~ (mix >> 31)
} else {
mix := data + 0x9e3779b9
mix = (mix ~ (mix >> 16)) * 0x21f0aaad
mix = (mix ~ (mix >> 15)) * 0x735a2d97
return mix ~ (mix >> 15)
}
}
// Computes the desired position in the array. This is just index % capacity, // Computes the desired position in the array. This is just index % capacity,
// but a procedure as there's some math involved here to recover the capacity. // but a procedure as there's some math involved here to recover the capacity.
@@ -394,32 +414,71 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
tk := map_cell_index_dynamic(sk, info.ks, 1) tk := map_cell_index_dynamic(sk, info.ks, 1)
tv := map_cell_index_dynamic(sv, info.vs, 1) tv := map_cell_index_dynamic(sv, info.vs, 1)
for { for {
hp := &hs[pos] hp := &hs[pos]
element_hash := hp^ element_hash := hp^
if map_hash_is_empty(element_hash) { if map_hash_is_empty(element_hash) {
k_dst := map_cell_index_dynamic(ks, info.ks, pos) kp := map_cell_index_dynamic(ks, info.ks, pos)
v_dst := map_cell_index_dynamic(vs, info.vs, pos) vp := map_cell_index_dynamic(vs, info.vs, pos)
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
hp^ = h hp^ = h
return result if result != 0 else v_dst return result if result != 0 else vp
}
if map_hash_is_deleted(element_hash) {
next_pos := (pos + 1) & mask
// backward shift
for !map_hash_is_empty(hs[next_pos]) {
probe_distance := map_probe_distance(m^, hs[next_pos], next_pos)
if probe_distance == 0 {
break
}
probe_distance -= 1
kp := map_cell_index_dynamic(ks, info.ks, pos)
vp := map_cell_index_dynamic(vs, info.vs, pos)
kn := map_cell_index_dynamic(ks, info.ks, next_pos)
vn := map_cell_index_dynamic(vs, info.vs, next_pos)
if distance > probe_distance {
if result == 0 {
result = vp
}
// move stored into pos; store next
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
hs[pos] = h
intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(kn), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(vn), size_of_v)
h = hs[next_pos]
} else {
// move next back 1
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(kn), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(vn), size_of_v)
hs[pos] = hs[next_pos]
distance = probe_distance
}
hs[next_pos] = 0
pos = (pos + 1) & mask
next_pos = (next_pos + 1) & mask
distance += 1
}
kp := map_cell_index_dynamic(ks, info.ks, pos)
vp := map_cell_index_dynamic(vs, info.vs, pos)
intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v)
hs[pos] = h
return result if result != 0 else vp
} }
if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance { if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance {
if map_hash_is_deleted(element_hash) {
k_dst := map_cell_index_dynamic(ks, info.ks, pos)
v_dst := map_cell_index_dynamic(vs, info.vs, pos)
intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k)
intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v)
hp^ = h
return result if result != 0 else v_dst
}
if result == 0 { if result == 0 {
result = map_cell_index_dynamic(vs, info.vs, pos) result = map_cell_index_dynamic(vs, info.vs, pos)
} }
@@ -503,6 +562,7 @@ map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_
} }
k := map_cell_index_dynamic(ks, info.ks, i) k := map_cell_index_dynamic(ks, info.ks, i)
v := map_cell_index_dynamic(vs, info.vs, i) v := map_cell_index_dynamic(vs, info.vs, i)
hash = info.key_hasher(rawptr(k), map_seed(resized))
_ = map_insert_hash_dynamic(&resized, info, hash, k, v) _ = map_insert_hash_dynamic(&resized, info, hash, k, v)
// Only need to do this comparison on each actually added pair, so do not // Only need to do this comparison on each actually added pair, so do not
// fold it into the for loop comparator as a micro-optimization. // fold it into the for loop comparator as a micro-optimization.
@@ -550,6 +610,7 @@ map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_I
k := map_cell_index_dynamic(ks, info.ks, i) k := map_cell_index_dynamic(ks, info.ks, i)
v := map_cell_index_dynamic(vs, info.vs, i) v := map_cell_index_dynamic(vs, info.vs, i)
hash = info.key_hasher(rawptr(k), map_seed(shrunk))
_ = map_insert_hash_dynamic(&shrunk, info, hash, k, v) _ = map_insert_hash_dynamic(&shrunk, info, hash, k, v)
// Only need to do this comparison on each actually added pair, so do not // Only need to do this comparison on each actually added pair, so do not
// fold it into the for loop comparator as a micro-optimization. // fold it into the for loop comparator as a micro-optimization.
@@ -581,7 +642,7 @@ map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
if map_len(m) == 0 { if map_len(m) == 0 {
return 0, false return 0, false
} }
h := info.key_hasher(rawptr(k), 0) h := info.key_hasher(rawptr(k), map_seed(m))
p := map_desired_position(m, h) p := map_desired_position(m, h)
d := uintptr(0) d := uintptr(0)
c := (uintptr(1) << map_log2_cap(m)) - 1 c := (uintptr(1) << map_log2_cap(m)) - 1
@@ -604,7 +665,7 @@ map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
if map_len(m) == 0 { if map_len(m) == 0 {
return false return false
} }
h := info.key_hasher(rawptr(k), 0) h := info.key_hasher(rawptr(k), map_seed(m))
p := map_desired_position(m, h) p := map_desired_position(m, h)
d := uintptr(0) d := uintptr(0)
c := (uintptr(1) << map_log2_cap(m)) - 1 c := (uintptr(1) << map_log2_cap(m)) - 1
@@ -637,7 +698,6 @@ map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n
{ // coalesce tombstones { // coalesce tombstones
// HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots // HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots
// TODO(bill): we should do backward shift deletion and not rely on tombstone slots
mask := (uintptr(1)<<map_log2_cap(m^)) - 1 mask := (uintptr(1)<<map_log2_cap(m^)) - 1
curr_index := uintptr(index) curr_index := uintptr(index)
@@ -711,7 +771,7 @@ map_get :: proc "contextless" (m: $T/map[$K]$V, key: K) -> (stored_key: K, store
info := intrinsics.type_map_info(T) info := intrinsics.type_map_info(T)
key := key key := key
h := info.key_hasher(&key, 0) h := info.key_hasher(&key, map_seed(rm))
pos := map_desired_position(rm, h) pos := map_desired_position(rm, h)
distance := uintptr(0) distance := uintptr(0)
mask := (uintptr(1) << map_log2_cap(rm)) - 1 mask := (uintptr(1) << map_log2_cap(rm)) - 1
@@ -762,15 +822,15 @@ __dynamic_map_get :: proc "contextless" (#no_alias m: ^Raw_Map, #no_alias info:
} }
// IMPORTANT: USED WITHIN THE COMPILER // IMPORTANT: USED WITHIN THE COMPILER
__dynamic_map_check_grow :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> Allocator_Error { __dynamic_map_check_grow :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> (err: Allocator_Error, has_grown: bool) {
if m.len >= map_resize_threshold(m^) { if m.len >= map_resize_threshold(m^) {
return map_grow_dynamic(m, info, loc) return map_grow_dynamic(m, info, loc), true
} }
return nil return nil, false
} }
__dynamic_map_set_without_hash :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key, value: rawptr, loc := #caller_location) -> rawptr { __dynamic_map_set_without_hash :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key, value: rawptr, loc := #caller_location) -> rawptr {
return __dynamic_map_set(m, info, info.key_hasher(key, 0), key, value, loc) return __dynamic_map_set(m, info, info.key_hasher(key, map_seed(m^)), key, value, loc)
} }
@@ -781,9 +841,14 @@ __dynamic_map_set :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_In
return found return found
} }
if __dynamic_map_check_grow(m, info, loc) != nil { hash := hash
err, has_grown := __dynamic_map_check_grow(m, info, loc)
if err != nil {
return nil return nil
} }
if has_grown {
hash = info.key_hasher(key, map_seed(m^))
}
result := map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(value)) result := map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(value))
m.len += 1 m.len += 1
+36
View File
@@ -500,6 +500,42 @@ string_decode_rune :: #force_inline proc "contextless" (s: string) -> (rune, int
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4 return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4
} }
string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) {
RUNE_ERROR :: '\ufffd'
RUNE_SELF :: 0x80
UTF_MAX :: 4
r: rune
size: int
start, end, limit: int
end = len(s)
if end == 0 {
return RUNE_ERROR, 0
}
start = end-1
r = rune(s[start])
if r < RUNE_SELF {
return r, 1
}
limit = max(end - UTF_MAX, 0)
for start-=1; start >= limit; start-=1 {
if (s[start] & 0xc0) != RUNE_SELF {
break
}
}
start = max(start, 0)
r, size = string_decode_rune(s[start:end])
if start+size != end {
return RUNE_ERROR, 1
}
return r, size
}
abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 { abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 {
return -x if x < 0 else x return -x if x < 0 else x
} }
+1 -1
View File
@@ -5,7 +5,7 @@ foreign import "odin_env"
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) { _os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
foreign odin_env { foreign odin_env {
write :: proc "c" (fd: u32, p: []byte) --- write :: proc "contextless" (fd: u32, p: []byte) ---
} }
write(1, data) write(1, data)
return len(data), 0 return len(data), 0
+2 -2
View File
@@ -8,7 +8,7 @@ ti_int :: struct #raw_union {
} }
@(link_name="__ashlti3", linkage="strong") @(link_name="__ashlti3", linkage="strong")
__ashlti3 :: proc "c" (a: i128, b_: u32) -> i128 { __ashlti3 :: proc "contextless" (a: i128, b_: u32) -> i128 {
bits_in_dword :: size_of(u32)*8 bits_in_dword :: size_of(u32)*8
b := u32(b_) b := u32(b_)
@@ -29,7 +29,7 @@ __ashlti3 :: proc "c" (a: i128, b_: u32) -> i128 {
@(link_name="__multi3", linkage="strong") @(link_name="__multi3", linkage="strong")
__multi3 :: proc "c" (a, b: i128) -> i128 { __multi3 :: proc "contextless" (a, b: i128) -> i128 {
x, y, r: ti_int x, y, r: ti_int
x.all = a x.all = a
+67 -19
View File
@@ -13,6 +13,7 @@ _ :: mem
/* /*
Turn a pointer and a length into a slice. Turn a pointer and a length into a slice.
*/ */
@(require_results)
from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T { from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T {
return ([^]T)(ptr)[:count] return ([^]T)(ptr)[:count]
} }
@@ -20,6 +21,7 @@ from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T {
/* /*
Turn a pointer and a length into a byte slice. Turn a pointer and a length into a byte slice.
*/ */
@(require_results)
bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte { bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte {
return ([^]byte)(ptr)[:byte_count] return ([^]byte)(ptr)[:byte_count]
} }
@@ -29,6 +31,7 @@ bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte {
See `slice.reinterpret` to go the other way. See `slice.reinterpret` to go the other way.
*/ */
@(require_results)
to_bytes :: proc "contextless" (s: []$T) -> []byte { to_bytes :: proc "contextless" (s: []$T) -> []byte {
return ([^]byte)(raw_data(s))[:len(s) * size_of(T)] return ([^]byte)(raw_data(s))[:len(s) * size_of(T)]
} }
@@ -51,10 +54,15 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte {
assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes. assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes.
``` ```
*/ */
@(require_results)
reinterpret :: proc "contextless" ($T: typeid/[]$U, s: []$V) -> []U { reinterpret :: proc "contextless" ($T: typeid/[]$U, s: []$V) -> []U {
bytes := to_bytes(s) when size_of(U) == 0 || size_of(V) == 0 {
n := len(bytes) / size_of(U) return nil
return ([^]U)(raw_data(bytes))[:n] } else {
bytes := to_bytes(s)
n := len(bytes) / size_of(U)
return ([^]U)(raw_data(bytes))[:n]
}
} }
@@ -82,11 +90,13 @@ reverse :: proc(array: $T/[]$E) {
} }
@(require_results)
contains :: proc(array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comparable(E) { contains :: proc(array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comparable(E) {
_, found := linear_search(array, value) _, found := linear_search(array, value)
return found return found
} }
@(require_results)
linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
where intrinsics.type_is_comparable(T) #no_bounds_check { where intrinsics.type_is_comparable(T) #no_bounds_check {
for x, i in array { for x, i in array {
@@ -97,6 +107,7 @@ linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
return -1, false return -1, false
} }
@(require_results)
linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check { linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check {
for x, i in array { for x, i in array {
if f(x) { if f(x) {
@@ -106,6 +117,7 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f
return -1, false return -1, false
} }
@(require_results)
binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
where intrinsics.type_is_ordered(T) #no_bounds_check { where intrinsics.type_is_ordered(T) #no_bounds_check {
@@ -146,6 +158,7 @@ binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
} }
@(require_results)
equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) { equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
@@ -162,6 +175,7 @@ equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
} }
} }
@(require_results)
simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_compare(E) { simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_compare(E) {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
@@ -176,6 +190,7 @@ simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_comp
slice.prefix_length([]u8{1, 2, 3, 4}, []u8{1, 2, 3}) -> 3 slice.prefix_length([]u8{1, 2, 3, 4}, []u8{1, 2, 3}) -> 3
slice.prefix_length([]u8{1, 2, 3, 4}, []u8{2, 3, 4}) -> 0 slice.prefix_length([]u8{1, 2, 3, 4}, []u8{2, 3, 4}) -> 0
*/ */
@(require_results)
prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) { prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) {
_len := builtin.min(len(a), len(b)) _len := builtin.min(len(a), len(b))
@@ -185,6 +200,7 @@ prefix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_compar
return return
} }
@(require_results)
has_prefix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_comparable(E) { has_prefix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_comparable(E) {
n := len(needle) n := len(needle)
if len(array) >= n { if len(array) >= n {
@@ -194,6 +210,7 @@ has_prefix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_c
} }
@(require_results)
has_suffix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_comparable(E) { has_suffix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_comparable(E) {
array := array array := array
m, n := len(array), len(needle) m, n := len(array), len(needle)
@@ -232,7 +249,8 @@ swap_with_slice :: proc(a, b: $T/[]$E, loc := #caller_location) {
ptr_swap_non_overlapping(raw_data(a), raw_data(b), len(a)*size_of(E)) ptr_swap_non_overlapping(raw_data(a), raw_data(b), len(a)*size_of(E))
} }
concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) { @(require_results)
concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T, err: mem.Allocator_Error) #optional_allocator_error {
if len(a) == 0 { if len(a) == 0 {
return return
} }
@@ -240,7 +258,7 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) {
for s in a { for s in a {
n += len(s) n += len(s)
} }
res = make(T, n, allocator) res = make(T, n, allocator) or_return
i := 0 i := 0
for s in a { for s in a {
i += copy(res[i:], s) i += copy(res[i:], s)
@@ -249,22 +267,24 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) {
} }
// copies a slice into a new slice // copies a slice into a new slice
clone :: proc(a: $T/[]$E, allocator := context.allocator) -> []E { @(require_results)
d := make([]E, len(a), allocator) clone :: proc(a: $T/[]$E, allocator := context.allocator) -> ([]E, mem.Allocator_Error) #optional_allocator_error {
d, err := make([]E, len(a), allocator)
copy(d[:], a) copy(d[:], a)
return d return d, err
} }
// copies slice into a new dynamic array // copies slice into a new dynamic array
clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> [dynamic]E { clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> ([dynamic]E, mem.Allocator_Error) #optional_allocator_error {
d := make([dynamic]E, len(a), allocator) d, err := make([dynamic]E, len(a), allocator)
copy(d[:], a) copy(d[:], a)
return d return d, err
} }
to_dynamic :: clone_to_dynamic to_dynamic :: clone_to_dynamic
// Converts slice into a dynamic array without cloning or allocating memory // Converts slice into a dynamic array without cloning or allocating memory
@(require_results)
into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E { into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E {
s := transmute(mem.Raw_Slice)a s := transmute(mem.Raw_Slice)a
d := mem.Raw_Dynamic_Array{ d := mem.Raw_Dynamic_Array{
@@ -277,43 +297,51 @@ into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E {
} }
@(require_results)
length :: proc(a: $T/[]$E) -> int { length :: proc(a: $T/[]$E) -> int {
return len(a) return len(a)
} }
@(require_results)
is_empty :: proc(a: $T/[]$E) -> bool { is_empty :: proc(a: $T/[]$E) -> bool {
return len(a) == 0 return len(a) == 0
} }
@(require_results)
split_at :: proc(array: $T/[]$E, index: int) -> (a, b: T) { split_at :: proc(array: $T/[]$E, index: int) -> (a, b: T) {
return array[:index], array[index:] return array[:index], array[index:]
} }
@(require_results)
split_first :: proc(array: $T/[]$E) -> (first: E, rest: T) { split_first :: proc(array: $T/[]$E) -> (first: E, rest: T) {
return array[0], array[1:] return array[0], array[1:]
} }
@(require_results)
split_last :: proc(array: $T/[]$E) -> (rest: T, last: E) { split_last :: proc(array: $T/[]$E) -> (rest: T, last: E) {
n := len(array)-1 n := len(array)-1
return array[:n], array[n] return array[:n], array[n]
} }
@(require_results)
first :: proc(array: $T/[]$E) -> E { first :: proc(array: $T/[]$E) -> E {
return array[0] return array[0]
} }
@(require_results)
last :: proc(array: $T/[]$E) -> E { last :: proc(array: $T/[]$E) -> E {
return array[len(array)-1] return array[len(array)-1]
} }
@(require_results)
first_ptr :: proc(array: $T/[]$E) -> ^E { first_ptr :: proc(array: $T/[]$E) -> ^E {
if len(array) != 0 { if len(array) != 0 {
return &array[0] return &array[0]
} }
return nil return nil
} }
@(require_results)
last_ptr :: proc(array: $T/[]$E) -> ^E { last_ptr :: proc(array: $T/[]$E) -> ^E {
if len(array) != 0 { if len(array) != 0 {
return &array[len(array)-1] return &array[len(array)-1]
@@ -321,6 +349,7 @@ last_ptr :: proc(array: $T/[]$E) -> ^E {
return nil return nil
} }
@(require_results)
get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) { get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) {
if uint(index) < len(array) { if uint(index) < len(array) {
value = array[index] value = array[index]
@@ -328,6 +357,7 @@ get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) {
} }
return return
} }
@(require_results)
get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) { get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) {
if uint(index) < len(array) { if uint(index) < len(array) {
value = &array[index] value = &array[index]
@@ -336,19 +366,22 @@ get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) {
return return
} }
@(require_results)
as_ptr :: proc(array: $T/[]$E) -> [^]E { as_ptr :: proc(array: $T/[]$E) -> [^]E {
return raw_data(array) return raw_data(array)
} }
mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> []V { @(require_results)
r := make([]V, len(s), allocator) mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> (r: []V, err: mem.Allocator_Error) #optional_allocator_error {
r = make([]V, len(s), allocator) or_return
for v, i in s { for v, i in s {
r[i] = f(v) r[i] = f(v)
} }
return r return
} }
@(require_results)
reduce :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V { reduce :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V {
r := initializer r := initializer
for v in s { for v in s {
@@ -357,6 +390,7 @@ reduce :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V {
return r return r
} }
@(require_results)
filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> S { filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> S {
r := make([dynamic]U, 0, 0, allocator) r := make([dynamic]U, 0, 0, allocator)
for v in s { for v in s {
@@ -367,10 +401,11 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -
return r[:] return r[:]
} }
scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> []V { @(require_results)
if len(s) == 0 { return {} } scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> (res: []V, err: mem.Allocator_Error) #optional_allocator_error {
if len(s) == 0 { return }
res := make([]V, len(s), allocator) res = make([]V, len(s), allocator) or_return
p := as_ptr(s) p := as_ptr(s)
q := as_ptr(res) q := as_ptr(res)
r := initializer r := initializer
@@ -382,10 +417,11 @@ scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := c
q = q[1:] q = q[1:]
} }
return res return
} }
@(require_results)
min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
if len(s) != 0 { if len(s) != 0 {
res = s[0] res = s[0]
@@ -396,6 +432,7 @@ min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T
} }
return return
} }
@(require_results)
max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
if len(s) != 0 { if len(s) != 0 {
res = s[0] res = s[0]
@@ -407,6 +444,7 @@ max :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T
return return
} }
@(require_results)
min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ordered(T) { min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_ordered(T) {
if len(s) != 0 { if len(s) != 0 {
min, max = s[0], s[0] min, max = s[0], s[0]
@@ -419,6 +457,7 @@ min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_
return return
} }
@(require_results)
any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
for v in s { for v in s {
if v == value { if v == value {
@@ -428,6 +467,7 @@ any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable
return false return false
} }
@(require_results)
none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
for v in s { for v in s {
if v == value { if v == value {
@@ -437,6 +477,7 @@ none_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparabl
return true return true
} }
@(require_results)
all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
if len(s) == 0 { if len(s) == 0 {
return false return false
@@ -450,6 +491,7 @@ all_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable
} }
@(require_results)
any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
for v in s { for v in s {
if f(v) { if f(v) {
@@ -459,6 +501,7 @@ any_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
return false return false
} }
@(require_results)
none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
for v in s { for v in s {
if f(v) { if f(v) {
@@ -468,6 +511,7 @@ none_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
return true return true
} }
@(require_results)
all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool { all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
if len(s) == 0 { if len(s) == 0 {
return false return false
@@ -481,6 +525,7 @@ all_of_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> bool {
} }
@(require_results)
count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_comparable(T) { count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_comparable(T) {
for v in s { for v in s {
if v == value { if v == value {
@@ -490,6 +535,7 @@ count :: proc(s: $S/[]$T, value: T) -> (n: int) where intrinsics.type_is_compara
return return
} }
@(require_results)
count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) { count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) {
for v in s { for v in s {
if f(v) { if f(v) {
@@ -500,6 +546,7 @@ count_proc :: proc(s: $S/[]$T, f: proc(T) -> bool) -> (n: int) {
} }
@(require_results)
dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool) dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
where intrinsics.type_is_numeric(T) { where intrinsics.type_is_numeric(T) {
if len(a) != len(b) { if len(a) != len(b) {
@@ -513,6 +560,7 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
// Convert a pointer to an enumerated array to a slice of the element type // Convert a pointer to an enumerated array to a slice of the element type
@(require_results)
enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T) enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
where intrinsics.type_is_enumerated_array(T) { where intrinsics.type_is_enumerated_array(T) {
return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)] return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]
+8 -1
View File
@@ -6,6 +6,7 @@ Ordering :: enum {
Greater = +1, Greater = +1,
} }
@(require_results)
cmp :: proc(a, b: $E) -> Ordering where ORD(E) { cmp :: proc(a, b: $E) -> Ordering where ORD(E) {
switch { switch {
case a < b: case a < b:
@@ -16,6 +17,7 @@ cmp :: proc(a, b: $E) -> Ordering where ORD(E) {
return .Equal return .Equal
} }
@(require_results)
cmp_proc :: proc($E: typeid) -> (proc(E, E) -> Ordering) where ORD(E) { cmp_proc :: proc($E: typeid) -> (proc(E, E) -> Ordering) where ORD(E) {
return proc(a, b: E) -> Ordering { return proc(a, b: E) -> Ordering {
switch { switch {
@@ -144,6 +146,7 @@ stable_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
} }
} }
@(require_results)
is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) { is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) {
for i := len(array)-1; i > 0; i -= 1 { for i := len(array)-1; i > 0; i -= 1 {
if array[i] < array[i-1] { if array[i] < array[i-1] {
@@ -153,6 +156,7 @@ is_sorted :: proc(array: $T/[]$E) -> bool where ORD(E) {
return true return true
} }
@(require_results)
is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool { is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool {
for i := len(array)-1; i > 0; i -= 1 { for i := len(array)-1; i > 0; i -= 1 {
if less(array[i], array[i-1]) { if less(array[i], array[i-1]) {
@@ -163,6 +167,8 @@ is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool {
} }
is_sorted_by_cmp :: is_sorted_cmp is_sorted_by_cmp :: is_sorted_cmp
@(require_results)
is_sorted_cmp :: proc(array: $T/[]$E, cmp: proc(i, j: E) -> Ordering) -> bool { is_sorted_cmp :: proc(array: $T/[]$E, cmp: proc(i, j: E) -> Ordering) -> bool {
for i := len(array)-1; i > 0; i -= 1 { for i := len(array)-1; i > 0; i -= 1 {
if cmp(array[i], array[i-1]) == .Less { if cmp(array[i], array[i-1]) == .Less {
@@ -215,6 +221,7 @@ reverse_sort_by_key :: proc(data: $T/[]$E, key: proc(E) -> $K) where ORD(K) {
}) })
} }
@(require_results)
is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K) { is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K) {
for i := len(array)-1; i > 0; i -= 1 { for i := len(array)-1; i > 0; i -= 1 {
if key(array[i]) < key(array[i-1]) { if key(array[i]) < key(array[i-1]) {
@@ -224,7 +231,7 @@ is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K
return true return true
} }
@(private) @(private, require_results)
_max_depth :: proc(n: int) -> (depth: int) { // 2*ceil(log2(n+1)) _max_depth :: proc(n: int) -> (depth: int) { // 2*ceil(log2(n+1))
for i := n; i > 0; i >>= 1 { for i := n; i > 0; i >>= 1 {
depth += 1 depth += 1
+7 -3
View File
@@ -3,7 +3,6 @@
package sync package sync
import "core:c" import "core:c"
import "core:os"
import "core:time" import "core:time"
FUTEX_WAIT :: 1 FUTEX_WAIT :: 1
@@ -14,11 +13,16 @@ FUTEX_PRIVATE_FLAG :: 128
FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
ETIMEDOUT :: 60
foreign import libc "system:c" foreign import libc "system:c"
foreign libc { foreign libc {
@(link_name="futex") @(link_name="futex")
_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int --- _unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
@(link_name="__errno") __errno :: proc() -> ^int ---
} }
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool { _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
@@ -28,7 +32,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
return true return true
} }
if os.Errno(os.get_last_error()) == os.ETIMEDOUT { if __errno()^ == ETIMEDOUT {
return false return false
} }
@@ -54,7 +58,7 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
return true return true
} }
if os.Errno(os.get_last_error()) == os.ETIMEDOUT { if __errno()^ == ETIMEDOUT {
return false return false
} }
+8 -2
View File
@@ -2,8 +2,14 @@
//+private //+private
package sync package sync
import "core:os" foreign import libc "system:c"
@(default_calling_convention="c")
foreign libc {
@(link_name="getthrid", private="file")
_unix_getthrid :: proc() -> int ---
}
_current_thread_id :: proc "contextless" () -> int { _current_thread_id :: proc "contextless" () -> int {
return os.current_thread_id() return _unix_getthrid()
} }
+22 -22
View File
@@ -968,7 +968,7 @@ prestat_t :: struct {
}, },
} }
@(default_calling_convention="c") @(default_calling_convention="contextless")
foreign wasi { foreign wasi {
/** /**
* Read command-line argument data. * Read command-line argument data.
@@ -1306,7 +1306,7 @@ foreign wasi {
* Returns the number of arguments and the size of the argument string * Returns the number of arguments and the size of the argument string
* data, or an error. * data, or an error.
*/ */
args_sizes_get :: proc "c" () -> (num_args, size_of_args: size_t, err: errno_t) { args_sizes_get :: proc "contextless" () -> (num_args, size_of_args: size_t, err: errno_t) {
err = wasi_args_sizes_get(&num_args, &size_of_args) err = wasi_args_sizes_get(&num_args, &size_of_args)
return return
} }
@@ -1316,7 +1316,7 @@ args_sizes_get :: proc "c" () -> (num_args, size_of_args: size_t, err: errno_t)
* Returns the number of environment variable arguments and the size of the * Returns the number of environment variable arguments and the size of the
* environment variable data. * environment variable data.
*/ */
environ_sizes_get :: proc "c" () -> (num_envs, size_of_envs: size_t, err: errno_t) { environ_sizes_get :: proc "contextless" () -> (num_envs, size_of_envs: size_t, err: errno_t) {
err = wasi_environ_sizes_get(&num_envs, &size_of_envs) err = wasi_environ_sizes_get(&num_envs, &size_of_envs)
return return
} }
@@ -1328,7 +1328,7 @@ environ_sizes_get :: proc "c" () -> (num_envs, size_of_envs: size_t, err: errno_
* @return * @return
* The resolution of the clock, or an error if one happened. * The resolution of the clock, or an error if one happened.
*/ */
clock_res_get :: proc "c" ( clock_res_get :: proc "contextless" (
/** /**
* The clock for which to return the resolution. * The clock for which to return the resolution.
*/ */
@@ -1343,7 +1343,7 @@ clock_res_get :: proc "c" (
* @return * @return
* The time value of the clock. * The time value of the clock.
*/ */
clock_time_get :: proc "c" ( clock_time_get :: proc "contextless" (
/** /**
* The clock for which to return the time. * The clock for which to return the time.
*/ */
@@ -1362,7 +1362,7 @@ clock_time_get :: proc "c" (
* @return * @return
* The buffer where the file descriptor's attributes are stored. * The buffer where the file descriptor's attributes are stored.
*/ */
fd_fdstat_get :: proc "c" ( fd_fdstat_get :: proc "contextless" (
fd: fd_t, fd: fd_t,
) -> (stat: fdstat_t, err: errno_t) { ) -> (stat: fdstat_t, err: errno_t) {
err = wasi_fd_fdstat_get(fd, &stat) err = wasi_fd_fdstat_get(fd, &stat)
@@ -1373,7 +1373,7 @@ fd_fdstat_get :: proc "c" (
* @return * @return
* The buffer where the file's attributes are stored. * The buffer where the file's attributes are stored.
*/ */
fd_filestat_get :: proc "c" ( fd_filestat_get :: proc "contextless" (
fd: fd_t, fd: fd_t,
) -> (stat: filestat_t, err: errno_t) { ) -> (stat: filestat_t, err: errno_t) {
err = wasi_fd_filestat_get(fd, &stat) err = wasi_fd_filestat_get(fd, &stat)
@@ -1389,7 +1389,7 @@ fd_filestat_get :: proc "c" (
* @return * @return
* The number of bytes read. * The number of bytes read.
*/ */
fd_pread :: proc "c" ( fd_pread :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* List of scatter/gather vectors in which to store data. * List of scatter/gather vectors in which to store data.
@@ -1408,7 +1408,7 @@ fd_pread :: proc "c" (
* @return * @return
* The buffer where the description is stored. * The buffer where the description is stored.
*/ */
fd_prestat_get :: proc "c" ( fd_prestat_get :: proc "contextless" (
fd: fd_t, fd: fd_t,
) -> (desc: prestat_t, err: errno_t) { ) -> (desc: prestat_t, err: errno_t) {
err = wasi_fd_prestat_get(fd, &desc) err = wasi_fd_prestat_get(fd, &desc)
@@ -1420,7 +1420,7 @@ fd_prestat_get :: proc "c" (
* @return * @return
* The number of bytes written. * The number of bytes written.
*/ */
fd_pwrite :: proc "c" ( fd_pwrite :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* List of scatter/gather vectors from which to retrieve data. * List of scatter/gather vectors from which to retrieve data.
@@ -1440,7 +1440,7 @@ fd_pwrite :: proc "c" (
* @return * @return
* The number of bytes read. * The number of bytes read.
*/ */
fd_read :: proc "c" ( fd_read :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* List of scatter/gather vectors to which to store data. * List of scatter/gather vectors to which to store data.
@@ -1463,7 +1463,7 @@ fd_read :: proc "c" (
* @return * @return
* The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. * The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached.
*/ */
fd_readdir :: proc "c" ( fd_readdir :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* The buffer where directory entries are stored * The buffer where directory entries are stored
@@ -1483,7 +1483,7 @@ fd_readdir :: proc "c" (
* @return * @return
* The new offset of the file descriptor, relative to the start of the file. * The new offset of the file descriptor, relative to the start of the file.
*/ */
fd_seek :: proc "c" ( fd_seek :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* The number of bytes to move. * The number of bytes to move.
@@ -1503,7 +1503,7 @@ fd_seek :: proc "c" (
* @return * @return
* The current offset of the file descriptor, relative to the start of the file. * The current offset of the file descriptor, relative to the start of the file.
*/ */
fd_tell :: proc "c" ( fd_tell :: proc "contextless" (
fd: fd_t, fd: fd_t,
) -> (offset: filesize_t, err: errno_t) { ) -> (offset: filesize_t, err: errno_t) {
err = wasi_fd_tell(fd, &offset) err = wasi_fd_tell(fd, &offset)
@@ -1513,7 +1513,7 @@ fd_tell :: proc "c" (
* Write to a file descriptor. * Write to a file descriptor.
* Note: This is similar to `writev` in POSIX. * Note: This is similar to `writev` in POSIX.
*/ */
fd_write :: proc "c" ( fd_write :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* List of scatter/gather vectors from which to retrieve data. * List of scatter/gather vectors from which to retrieve data.
@@ -1529,7 +1529,7 @@ fd_write :: proc "c" (
* @return * @return
* The buffer where the file's attributes are stored. * The buffer where the file's attributes are stored.
*/ */
path_filestat_get :: proc "c" ( path_filestat_get :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* Flags determining the method of how the path is resolved. * Flags determining the method of how the path is resolved.
@@ -1554,7 +1554,7 @@ path_filestat_get :: proc "c" (
* @return * @return
* The file descriptor of the file that has been opened. * The file descriptor of the file that has been opened.
*/ */
path_open :: proc "c" ( path_open :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* Flags determining the method of how the path is resolved. * Flags determining the method of how the path is resolved.
@@ -1591,7 +1591,7 @@ path_open :: proc "c" (
* @return * @return
* The number of bytes placed in the buffer. * The number of bytes placed in the buffer.
*/ */
path_readlink :: proc "c" ( path_readlink :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* The path of the symbolic link from which to read. * The path of the symbolic link from which to read.
@@ -1610,7 +1610,7 @@ path_readlink :: proc "c" (
* @return * @return
* The number of events stored. * The number of events stored.
*/ */
poll_oneoff :: proc "c" ( poll_oneoff :: proc "contextless" (
/** /**
* The events to which to subscribe. * The events to which to subscribe.
*/ */
@@ -1634,7 +1634,7 @@ poll_oneoff :: proc "c" (
* @return * @return
* Number of bytes stored in ri_data and message flags. * Number of bytes stored in ri_data and message flags.
*/ */
sock_recv :: proc "c" ( sock_recv :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* List of scatter/gather vectors to which to store data. * List of scatter/gather vectors to which to store data.
@@ -1655,7 +1655,7 @@ sock_recv :: proc "c" (
* @return * @return
* Number of bytes transmitted. * Number of bytes transmitted.
*/ */
sock_send :: proc "c" ( sock_send :: proc "contextless" (
fd: fd_t, fd: fd_t,
/** /**
* List of scatter/gather vectors to which to retrieve data * List of scatter/gather vectors to which to retrieve data
@@ -1675,7 +1675,7 @@ sock_send :: proc "c" (
@(default_calling_convention="c") @(default_calling_convention="contextless")
foreign wasi { foreign wasi {
@(link_name="args_sizes_get") @(link_name="args_sizes_get")
wasi_args_sizes_get :: proc( wasi_args_sizes_get :: proc(
+2 -1
View File
@@ -2,6 +2,7 @@
package sys_windows package sys_windows
foreign import kernel32 "system:Kernel32.lib" foreign import kernel32 "system:Kernel32.lib"
foreign import one_core "system:OneCore.lib"
FOREGROUND_BLUE :: WORD(0x0001) FOREGROUND_BLUE :: WORD(0x0001)
FOREGROUND_GREEN :: WORD(0x0002) FOREGROUND_GREEN :: WORD(0x0002)
@@ -891,7 +892,7 @@ WIN32_MEMORY_REGION_INFORMATION_u_s_Bitfield :: distinct ULONG
}*/ }*/
@(default_calling_convention="stdcall") @(default_calling_convention="stdcall")
foreign kernel32 { foreign one_core {
QueryVirtualMemoryInformation :: proc( QueryVirtualMemoryInformation :: proc(
Process: HANDLE, Process: HANDLE,
VirtualAddress: PVOID, VirtualAddress: PVOID,
+3 -1
View File
@@ -52,6 +52,8 @@ foreign user32 {
TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL --- TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL ---
DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT --- DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT ---
WaitMessage :: proc() -> BOOL ---
PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL ---
PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL --- PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL ---
@@ -222,6 +224,7 @@ foreign user32 {
GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL --- GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL ---
GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL --- GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL ---
SetWindowPlacement :: proc(hwnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL ---
SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int --- SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int ---
CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN --- CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN ---
GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int --- GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int ---
@@ -463,7 +466,6 @@ WINDOWPLACEMENT :: struct {
ptMinPosition: POINT, ptMinPosition: POINT,
ptMaxPosition: POINT, ptMaxPosition: POINT,
rcNormalPosition: RECT, rcNormalPosition: RECT,
rcDevice: RECT,
} }
WINDOWINFO :: struct { WINDOWINFO :: struct {
-1
View File
@@ -62,7 +62,6 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
thread.procedure = procedure thread.procedure = procedure
thread.win32_thread = win32_thread thread.win32_thread = win32_thread
thread.win32_thread_id = win32_thread_id thread.win32_thread_id = win32_thread_id
thread.init_context = context
ok := win32.SetThreadPriority(win32_thread, _thread_priority_map[priority]) ok := win32.SetThreadPriority(win32_thread, _thread_priority_map[priority])
assert(ok == true) assert(ok == true)
+23 -18
View File
@@ -10,6 +10,11 @@ UTF_MAX :: 4
SURROGATE_MIN :: 0xd800 SURROGATE_MIN :: 0xd800
SURROGATE_MAX :: 0xdfff SURROGATE_MAX :: 0xdfff
// A high/leading surrogate is in range SURROGATE_MIN..SURROGATE_HIGH_MAX,
// A low/trailing surrogate is in range SURROGATE_LOW_MIN..SURROGATE_MAX.
SURROGATE_HIGH_MAX :: 0xdbff
SURROGATE_LOW_MIN :: 0xdc00
T1 :: 0b0000_0000 T1 :: 0b0000_0000
TX :: 0b1000_0000 TX :: 0b1000_0000
T2 :: 0b1100_0000 T2 :: 0b1100_0000
@@ -54,7 +59,7 @@ accept_sizes := [256]u8{
0xf5..=0xff = 0xf1, 0xf5..=0xff = 0xf1,
} }
encode_rune :: proc(c: rune) -> ([4]u8, int) { encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
r := c r := c
buf: [4]u8 buf: [4]u8
@@ -95,10 +100,10 @@ decode_rune :: proc{
decode_rune_in_string, decode_rune_in_string,
decode_rune_in_bytes, decode_rune_in_bytes,
} }
decode_rune_in_string :: #force_inline proc(s: string) -> (rune, int) { decode_rune_in_string :: #force_inline proc "contextless" (s: string) -> (rune, int) {
return decode_rune_in_bytes(transmute([]u8)s) return decode_rune_in_bytes(transmute([]u8)s)
} }
decode_rune_in_bytes :: proc(s: []u8) -> (rune, int) { decode_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) {
n := len(s) n := len(s)
if n < 1 { if n < 1 {
return RUNE_ERROR, 0 return RUNE_ERROR, 0
@@ -135,7 +140,7 @@ decode_rune_in_bytes :: proc(s: []u8) -> (rune, int) {
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4 return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4
} }
string_to_runes :: proc(s: string, allocator := context.allocator) -> (runes: []rune) { string_to_runes :: proc "odin" (s: string, allocator := context.allocator) -> (runes: []rune) {
n := rune_count_in_string(s) n := rune_count_in_string(s)
runes = make([]rune, n, allocator) runes = make([]rune, n, allocator)
@@ -147,7 +152,7 @@ string_to_runes :: proc(s: string, allocator := context.allocator) -> (runes: []
return return
} }
runes_to_string :: proc(runes: []rune, allocator := context.allocator) -> string { runes_to_string :: proc "odin" (runes: []rune, allocator := context.allocator) -> string {
byte_count := 0 byte_count := 0
for r in runes { for r in runes {
_, w := encode_rune(r) _, w := encode_rune(r)
@@ -171,10 +176,10 @@ decode_last_rune :: proc{
decode_last_rune_in_bytes, decode_last_rune_in_bytes,
} }
decode_last_rune_in_string :: #force_inline proc(s: string) -> (rune, int) { decode_last_rune_in_string :: #force_inline proc "contextless" (s: string) -> (rune, int) {
return decode_last_rune_in_bytes(transmute([]u8)s) return decode_last_rune_in_bytes(transmute([]u8)s)
} }
decode_last_rune_in_bytes :: proc(s: []u8) -> (rune, int) { decode_last_rune_in_bytes :: proc "contextless" (s: []u8) -> (rune, int) {
r: rune r: rune
size: int size: int
start, end, limit: int start, end, limit: int
@@ -206,7 +211,7 @@ decode_last_rune_in_bytes :: proc(s: []u8) -> (rune, int) {
return r, size return r, size
} }
rune_at_pos :: proc(s: string, pos: int) -> rune { rune_at_pos :: proc "contextless" (s: string, pos: int) -> rune {
if pos < 0 { if pos < 0 {
return RUNE_ERROR return RUNE_ERROR
} }
@@ -221,7 +226,7 @@ rune_at_pos :: proc(s: string, pos: int) -> rune {
return RUNE_ERROR return RUNE_ERROR
} }
rune_string_at_pos :: proc(s: string, pos: int) -> string { rune_string_at_pos :: proc "contextless" (s: string, pos: int) -> string {
if pos < 0 { if pos < 0 {
return "" return ""
} }
@@ -237,14 +242,14 @@ rune_string_at_pos :: proc(s: string, pos: int) -> string {
return "" return ""
} }
rune_at :: proc(s: string, byte_index: int) -> rune { rune_at :: proc "contextless" (s: string, byte_index: int) -> rune {
r, _ := decode_rune_in_string(s[byte_index:]) r, _ := decode_rune_in_string(s[byte_index:])
return r return r
} }
// Returns the byte position of rune at position pos in s with an optional start byte position. // 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. // Returns -1 if it runs out of the string.
rune_offset :: proc(s: string, pos: int, start: int = 0) -> int { rune_offset :: proc "contextless" (s: string, pos: int, start: int = 0) -> int {
if pos < 0 { if pos < 0 {
return -1 return -1
} }
@@ -259,7 +264,7 @@ rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
return -1 return -1
} }
valid_rune :: proc(r: rune) -> bool { valid_rune :: proc "contextless" (r: rune) -> bool {
if r < 0 { if r < 0 {
return false return false
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX { } else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
@@ -270,7 +275,7 @@ valid_rune :: proc(r: rune) -> bool {
return true return true
} }
valid_string :: proc(s: string) -> bool { valid_string :: proc "contextless" (s: string) -> bool {
n := len(s) n := len(s)
for i := 0; i < n; { for i := 0; i < n; {
si := s[i] si := s[i]
@@ -303,7 +308,7 @@ valid_string :: proc(s: string) -> bool {
return true return true
} }
rune_start :: #force_inline proc(b: u8) -> bool { rune_start :: #force_inline proc "contextless" (b: u8) -> bool {
return b&0xc0 != 0x80 return b&0xc0 != 0x80
} }
@@ -315,7 +320,7 @@ rune_count :: proc{
rune_count_in_string :: #force_inline proc(s: string) -> int { rune_count_in_string :: #force_inline proc(s: string) -> int {
return rune_count_in_bytes(transmute([]u8)s) return rune_count_in_bytes(transmute([]u8)s)
} }
rune_count_in_bytes :: proc(s: []u8) -> int { rune_count_in_bytes :: proc "contextless" (s: []u8) -> int {
count := 0 count := 0
n := len(s) n := len(s)
@@ -354,7 +359,7 @@ rune_count_in_bytes :: proc(s: []u8) -> int {
} }
rune_size :: proc(r: rune) -> int { rune_size :: proc "contextless" (r: rune) -> int {
switch { switch {
case r < 0: return -1 case r < 0: return -1
case r <= 1<<7 - 1: return 1 case r <= 1<<7 - 1: return 1
@@ -375,7 +380,7 @@ full_rune :: proc{
// full_rune_in_bytes reports if the bytes in b begin with a full utf-8 encoding of a rune or not // full_rune_in_bytes reports if the bytes in b begin with a full utf-8 encoding of a rune or not
// An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR) // An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR)
full_rune_in_bytes :: proc(b: []byte) -> bool { full_rune_in_bytes :: proc "contextless" (b: []byte) -> bool {
n := len(b) n := len(b)
if n == 0 { if n == 0 {
return false return false
@@ -395,7 +400,7 @@ full_rune_in_bytes :: proc(b: []byte) -> bool {
// full_rune_in_string reports if the bytes in s begin with a full utf-8 encoding of a rune or not // full_rune_in_string reports if the bytes in s begin with a full utf-8 encoding of a rune or not
// An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR) // An invalid encoding is considered a full rune since it will convert as an error rune of width 1 (RUNE_ERROR)
full_rune_in_string :: proc(s: string) -> bool { full_rune_in_string :: proc "contextless" (s: string) -> bool {
return full_rune_in_bytes(transmute([]byte)s) return full_rune_in_bytes(transmute([]byte)s)
} }
+2
View File
@@ -24,6 +24,7 @@ import vk "vendor:vulkan"
import NS "vendor:darwin/Foundation" import NS "vendor:darwin/Foundation"
import MTL "vendor:darwin/Metal" import MTL "vendor:darwin/Metal"
import MTK "vendor:darwin/MetalKit"
import CA "vendor:darwin/QuartzCore" import CA "vendor:darwin/QuartzCore"
// NOTE(bill): only one can be checked at a time // NOTE(bill): only one can be checked at a time
@@ -53,6 +54,7 @@ _ :: vk
_ :: NS _ :: NS
_ :: MTL _ :: MTL
_ :: MTK
_ :: CA _ :: CA
_ :: lua_5_4 _ :: lua_5_4
+1 -3
View File
@@ -2145,10 +2145,8 @@ or_return_operator :: proc() {
return -345 * z, zerr return -345 * z, zerr
} }
// If the other return values need to be set depending on what the end value is,
// the 'defer if' idiom is can be used
defer if err != nil { defer if err != nil {
n = -1 fmt.println("Error in", #procedure, ":" , err)
} }
n = 123 n = 123
+21 -3
View File
@@ -1538,13 +1538,23 @@ gb_internal bool init_build_paths(String init_filename) {
} else if (is_arch_wasm()) { } else if (is_arch_wasm()) {
output_extension = STR_LIT("wasm"); output_extension = STR_LIT("wasm");
} else if (build_context.build_mode == BuildMode_Executable) { } else if (build_context.build_mode == BuildMode_Executable) {
// By default use a .bin executable extension. // By default use no executable extension.
output_extension = STR_LIT("bin"); output_extension = make_string(nullptr, 0);
String const single_file_extension = str_lit(".odin");
if (build_context.metrics.os == TargetOs_windows) { if (build_context.metrics.os == TargetOs_windows) {
output_extension = STR_LIT("exe"); output_extension = STR_LIT("exe");
} else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
output_extension = make_string(nullptr, 0); // Do nothing: we don't want the .bin extension
// when cross compiling
} else if (path_is_directory(last_path_element(bc->build_paths[BuildPath_Main_Package].basename))) {
// Add .bin extension to avoid collision
// with package directory name
output_extension = STR_LIT("bin");
} else if (string_ends_with(init_filename, single_file_extension) && path_is_directory(remove_extension_from_path(init_filename))) {
// Add bin extension if compiling single-file package
// with same output name as a directory
output_extension = STR_LIT("bin");
} }
} else if (build_context.build_mode == BuildMode_DynamicLibrary) { } else if (build_context.build_mode == BuildMode_DynamicLibrary) {
// By default use a .so shared library extension. // By default use a .so shared library extension.
@@ -1656,6 +1666,14 @@ gb_internal bool init_build_paths(String init_filename) {
return false; return false;
} }
if (!write_directory(bc->build_paths[BuildPath_Output].basename)) {
String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
defer (gb_free(ha, output_file.text));
gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file));
return false;
}
if (bc->target_features_string.len != 0) { if (bc->target_features_string.len != 0) {
enable_target_feature({}, bc->target_features_string); enable_target_feature({}, bc->target_features_string);
} }
+83
View File
@@ -4843,6 +4843,89 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
} }
operand->mode = Addressing_Type; operand->mode = Addressing_Type;
break; break;
case BuiltinProc_type_merge:
{
operand->mode = Addressing_Type;
operand->type = t_invalid;
Operand x = {};
Operand y = {};
check_expr_or_type(c, &x, ce->args[0]);
check_expr_or_type(c, &y, ce->args[1]);
if (x.mode != Addressing_Type) {
error(x.expr, "Expected a type for '%.*s'", LIT(builtin_name));
return false;
}
if (y.mode != Addressing_Type) {
error(y.expr, "Expected a type for '%.*s'", LIT(builtin_name));
return false;
}
if (is_type_polymorphic(x.type)) {
gbString t = type_to_string(x.type);
error(x.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
gb_string_free(t);
return false;
}
if (is_type_polymorphic(y.type)) {
gbString t = type_to_string(y.type);
error(y.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
gb_string_free(t);
return false;
}
if (!is_type_union(x.type)) {
gbString t = type_to_string(x.type);
error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t);
gb_string_free(t);
return false;
}
if (!is_type_union(y.type)) {
gbString t = type_to_string(y.type);
error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t);
gb_string_free(t);
return false;
}
Type *ux = base_type(x.type);
Type *uy = base_type(y.type);
GB_ASSERT(ux->kind == Type_Union);
GB_ASSERT(uy->kind == Type_Union);
i64 custom_align = gb_max(ux->Union.custom_align, uy->Union.custom_align);
if (ux->Union.kind != uy->Union.kind) {
error(x.expr, "Union kinds must match, got %s vs %s", union_type_kind_strings[ux->Union.kind], union_type_kind_strings[uy->Union.kind]);
}
Type *merged_union = alloc_type_union();
merged_union->Union.node = call;
merged_union->Union.scope = create_scope(c->info, c->scope);
merged_union->Union.kind = ux->Union.kind;
merged_union->Union.custom_align = custom_align;
auto variants = array_make<Type *>(permanent_allocator(), 0, ux->Union.variants.count+uy->Union.variants.count);
for (Type *t : ux->Union.variants) {
array_add(&variants, t);
}
for (Type *t : uy->Union.variants) {
bool ok = true;
for (Type *other_t : ux->Union.variants) {
if (are_types_identical(other_t, t)) {
ok = false;
break;
}
}
if (ok) {
array_add(&variants, t);
}
}
merged_union->Union.variants = slice_from_array(variants);
operand->mode = Addressing_Type;
operand->type = merged_union;
}
break;
case BuiltinProc_type_is_boolean: case BuiltinProc_type_is_boolean:
case BuiltinProc_type_is_integer: case BuiltinProc_type_is_integer:
+14 -10
View File
@@ -43,14 +43,20 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
} }
if (operand->mode == Addressing_Type) { if (operand->mode == Addressing_Type) {
if (e->type != nullptr && is_type_typeid(e->type)) { if (e->type != nullptr && is_type_typeid(e->type) && !is_type_polymorphic(operand->type)) {
add_type_info_type(ctx, operand->type); add_type_info_type(ctx, operand->type);
add_type_and_value(ctx, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type)); add_type_and_value(ctx, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
return e->type; return e->type;
} else { } else {
ERROR_BLOCK();
gbString t = type_to_string(operand->type); gbString t = type_to_string(operand->type);
defer (gb_string_free(t)); defer (gb_string_free(t));
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); if (is_type_polymorphic(operand->type)) {
error(operand->expr, "Cannot assign a non-specialized polymorphic type '%s' to variable '%.*s'", t, LIT(e->token.string));
} else {
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
}
if (e->type == nullptr) { if (e->type == nullptr) {
error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a default type\n", LIT(e->token.string)); error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a default type\n", LIT(e->token.string));
} }
@@ -59,20 +65,17 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
} }
} }
if (e->type == nullptr) { if (e->type == nullptr) {
// NOTE(bill): Use the type of the operand // NOTE(bill): Use the type of the operand
Type *t = operand->type; Type *t = operand->type;
if (is_type_untyped(t)) { if (is_type_untyped(t)) {
if (t == t_invalid || is_type_untyped_nil(t)) { if (is_type_untyped_uninit(t)) {
error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name)); error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
e->type = t_invalid; e->type = t_invalid;
return nullptr; return nullptr;
} } else if (t == t_invalid || is_type_untyped_nil(t)) {
if (t == t_invalid || is_type_untyped_undef(t)) { error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
e->type = t_invalid; e->type = t_invalid;
return nullptr; return nullptr;
} }
@@ -119,7 +122,7 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l
// an extra allocation // an extra allocation
TEMPORARY_ALLOCATOR_GUARD(); TEMPORARY_ALLOCATOR_GUARD();
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count); auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false); check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, UnpackFlag_AllowOk|UnpackFlag_AllowUndef);
isize rhs_count = operands.count; isize rhs_count = operands.count;
isize max = gb_min(lhs_count, rhs_count); isize max = gb_min(lhs_count, rhs_count);
@@ -947,6 +950,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
if (ac.require_declaration) { if (ac.require_declaration) {
e->flags |= EntityFlag_Require; e->flags |= EntityFlag_Require;
pl->inlining = ProcInlining_no_inline;
} }
+47 -28
View File
@@ -646,11 +646,8 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
Type *src = base_type(s); Type *src = base_type(s);
Type *dst = base_type(type); Type *dst = base_type(type);
if (is_type_untyped_undef(src)) { if (is_type_untyped_uninit(src)) {
if (type_has_undef(dst)) { return 1;
return 1;
}
return -1;
} }
if (is_type_untyped_nil(src)) { if (is_type_untyped_nil(src)) {
@@ -993,13 +990,13 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
if (is_type_untyped(operand->type)) { if (is_type_untyped(operand->type)) {
Type *target_type = type; Type *target_type = type;
if (type == nullptr || is_type_any(type)) { if (type == nullptr || is_type_any(type)) {
if (type == nullptr && is_type_untyped_nil(operand->type)) { if (type == nullptr && is_type_untyped_uninit(operand->type)) {
error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name)); error(operand->expr, "Use of --- in %.*s", LIT(context_name));
operand->mode = Addressing_Invalid; operand->mode = Addressing_Invalid;
return; return;
} }
if (type == nullptr && is_type_untyped_undef(operand->type)) { if (type == nullptr && is_type_untyped_nil(operand->type)) {
error(operand->expr, "Use of --- in %.*s", LIT(context_name)); error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name));
operand->mode = Addressing_Invalid; operand->mode = Addressing_Invalid;
return; return;
} }
@@ -1067,7 +1064,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
if (check_is_assignable_to(c, operand, type)) { if (check_is_assignable_to(c, operand, type)) {
if (operand->mode == Addressing_Type && is_type_typeid(type)) { if (operand->mode == Addressing_Type && is_type_typeid(type)) {
add_type_info_type(c, operand->type); add_type_info_type(c, operand->type);
add_type_and_value(c, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type)); add_type_and_value(c, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type));
} }
} else { } else {
@@ -3969,7 +3966,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
case Type_Union: case Type_Union:
if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) { if (!is_operand_nil(*operand) && !is_operand_uninit(*operand)) {
TEMPORARY_ALLOCATOR_GUARD(); TEMPORARY_ALLOCATOR_GUARD();
isize count = t->Union.variants.count; isize count = t->Union.variants.count;
@@ -4036,8 +4033,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
error_line("\n\n"); error_line("\n\n");
return; return;
} else if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) { } else if (is_type_untyped_uninit(operand->type)) {
target_type = t_untyped_undef; target_type = t_untyped_uninit;
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) { } else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
begin_error_block(); begin_error_block();
defer (end_error_block()); defer (end_error_block());
@@ -4070,8 +4067,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
default: default:
if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) { if (is_type_untyped_uninit(operand->type)) {
target_type = t_untyped_undef; target_type = t_untyped_uninit;
} else if (is_type_untyped_nil(operand->type) && type_has_nil(target_type)) { } else if (is_type_untyped_nil(operand->type) && type_has_nil(target_type)) {
target_type = t_untyped_nil; target_type = t_untyped_nil;
} else { } else {
@@ -4083,7 +4080,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
} }
if (is_type_any(target_type) && is_type_untyped(operand->type)) { if (is_type_any(target_type) && is_type_untyped(operand->type)) {
if (is_type_untyped_nil(operand->type) && is_type_untyped_undef(operand->type)) { if (is_type_untyped_nil(operand->type) && is_type_untyped_uninit(operand->type)) {
} else { } else {
target_type = default_type(operand->type); target_type = default_type(operand->type);
@@ -5144,8 +5141,20 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array<Operand>
} }
typedef u32 UnpackFlags;
enum UnpackFlag : u32 {
UnpackFlag_None = 0,
UnpackFlag_AllowOk = 1<<0,
UnpackFlag_IsVariadic = 1<<1,
UnpackFlag_AllowUndef = 1<<2,
};
gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs, UnpackFlags flags) {
bool allow_ok = (flags & UnpackFlag_AllowOk) != 0;
bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0;
bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0;
gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs, bool allow_ok, bool is_variadic) {
bool optional_ok = false; bool optional_ok = false;
isize tuple_index = 0; isize tuple_index = 0;
for_array(i, rhs) { for_array(i, rhs) {
@@ -5184,7 +5193,16 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
} }
} }
check_expr_base(c, &o, rhs[i], type_hint); Ast *rhs_expr = unparen_expr(rhs[i]);
if (allow_undef && rhs_expr != nullptr && rhs_expr->kind == Ast_Uninit) {
// NOTE(bill): Just handle this very specific logic here
o.type = t_untyped_uninit;
o.mode = Addressing_Value;
o.expr = rhs[i];
add_type_and_value(c, rhs[i], o.mode, o.type, o.value);
} else {
check_expr_base(c, &o, rhs[i], type_hint);
}
if (o.mode == Addressing_NoValue) { if (o.mode == Addressing_NoValue) {
error_operand_no_value(&o); error_operand_no_value(&o);
o.mode = Addressing_Invalid; o.mode = Addressing_Invalid;
@@ -5968,7 +5986,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic);
} }
if (operand->mode != Addressing_ProcGroup) { if (operand->mode != Addressing_ProcGroup) {
check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic); check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
} }
} }
@@ -6025,7 +6043,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
isize lhs_count = -1; isize lhs_count = -1;
bool is_variadic = false; bool is_variadic = false;
lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic);
check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic); check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
CallArgumentData data = {}; CallArgumentData data = {};
CallArgumentError err = call_checker(c, call, e->type, e, operands, CallArgumentMode_ShowErrors, &data); CallArgumentError err = call_checker(c, call, e->type, e, operands, CallArgumentMode_ShowErrors, &data);
@@ -6101,7 +6119,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
} }
check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, false); check_unpack_arguments(c, lhs, lhs_count, &operands, args, UnpackFlag_None);
if (lhs != nullptr) { if (lhs != nullptr) {
gb_free(heap_allocator(), lhs); gb_free(heap_allocator(), lhs);
@@ -6462,7 +6480,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
lhs_count = params->variables.count; lhs_count = params->variables.count;
} }
check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false); check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, UnpackFlag_None);
} }
} }
@@ -7146,11 +7164,11 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
} }
gb_internal bool ternary_compare_types(Type *x, Type *y) { gb_internal bool ternary_compare_types(Type *x, Type *y) {
if (is_type_untyped_undef(x) && type_has_undef(y)) { if (is_type_untyped_uninit(x)) {
return true; return true;
} else if (is_type_untyped_nil(x) && type_has_nil(y)) { } else if (is_type_untyped_nil(x) && type_has_nil(y)) {
return true; return true;
} else if (is_type_untyped_undef(y) && type_has_undef(x)) { } else if (is_type_untyped_uninit(y)) {
return true; return true;
} else if (is_type_untyped_nil(y) && type_has_nil(x)) { } else if (is_type_untyped_nil(y) && type_has_nil(x)) {
return true; return true;
@@ -7687,7 +7705,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
} }
o->type = x.type; o->type = x.type;
if (is_type_untyped_nil(o->type) || is_type_untyped_undef(o->type)) { if (is_type_untyped_nil(o->type) || is_type_untyped_uninit(o->type)) {
o->type = y.type; o->type = y.type;
} }
@@ -9580,9 +9598,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
check_ident(c, o, node, nullptr, type_hint, false); check_ident(c, o, node, nullptr, type_hint, false);
case_end; case_end;
case_ast_node(u, Undef, node); case_ast_node(u, Uninit, node);
o->mode = Addressing_Value; o->mode = Addressing_Value;
o->type = t_untyped_undef; o->type = t_untyped_uninit;
error(node, "Use of --- outside of variable declaration");
case_end; case_end;
@@ -10145,7 +10164,7 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
str = string_append_string(str, bd->name.string); str = string_append_string(str, bd->name.string);
case_end; case_end;
case_ast_node(ud, Undef, node); case_ast_node(ud, Uninit, node);
str = gb_string_appendc(str, "---"); str = gb_string_appendc(str, "---");
case_end; case_end;
+26 -2
View File
@@ -402,6 +402,12 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
Type *assignment_type = lhs->type; Type *assignment_type = lhs->type;
if (rhs->mode == Addressing_Type && is_type_polymorphic(rhs->type)) {
gbString t = type_to_string(rhs->type);
error(rhs->expr, "Invalid use of a non-specialized polymorphic type '%s'", t);
gb_string_free(t);
}
switch (lhs->mode) { switch (lhs->mode) {
case Addressing_Invalid: case Addressing_Invalid:
return nullptr; return nullptr;
@@ -1455,6 +1461,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
bool is_map = false; bool is_map = false;
bool use_by_reference_for_value = false; bool use_by_reference_for_value = false;
bool is_soa = false; bool is_soa = false;
bool is_reverse = rs->reverse;
Ast *expr = unparen_expr(rs->expr); Ast *expr = unparen_expr(rs->expr);
@@ -1470,6 +1477,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
} }
array_add(&vals, x.type); array_add(&vals, x.type);
array_add(&vals, t_int); array_add(&vals, t_int);
if (is_reverse) {
error(node, "#reverse for is not supported with ranges, prefer an explicit for loop with init, condition, and post arguments");
}
} else { } else {
Operand operand = {Addressing_Invalid}; Operand operand = {Addressing_Invalid};
check_expr_base(ctx, &operand, expr, nullptr); check_expr_base(ctx, &operand, expr, nullptr);
@@ -1482,6 +1493,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
gb_string_free(t); gb_string_free(t);
goto skip_expr_range_stmt; goto skip_expr_range_stmt;
} else { } else {
if (is_reverse) {
error(node, "#reverse for is not supported for enum types");
}
array_add(&vals, operand.type); array_add(&vals, operand.type);
array_add(&vals, t_int); array_add(&vals, t_int);
add_type_info_type(ctx, operand.type); add_type_info_type(ctx, operand.type);
@@ -1495,7 +1509,11 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
if (is_type_string(t) && t->Basic.kind != Basic_cstring) { if (is_type_string(t) && t->Basic.kind != Basic_cstring) {
array_add(&vals, t_rune); array_add(&vals, t_rune);
array_add(&vals, t_int); array_add(&vals, t_int);
add_package_dependency(ctx, "runtime", "string_decode_rune"); if (is_reverse) {
add_package_dependency(ctx, "runtime", "string_decode_last_rune");
} else {
add_package_dependency(ctx, "runtime", "string_decode_rune");
}
} }
break; break;
@@ -1528,6 +1546,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
is_map = true; is_map = true;
array_add(&vals, t->Map.key); array_add(&vals, t->Map.key);
array_add(&vals, t->Map.value); array_add(&vals, t->Map.value);
if (is_reverse) {
error(node, "#reverse for is not supported for map types, as maps are unordered");
}
break; break;
case Type_Tuple: case Type_Tuple:
@@ -1564,6 +1585,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
break; break;
} }
if (is_reverse) {
error(node, "#reverse for is not supported for multiple return valued parameters");
}
} }
break; break;
@@ -2170,7 +2194,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count); auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count);
defer (array_free(&operands)); defer (array_free(&operands));
check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, true, false); check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk);
if (result_count == 0 && rs->results.count > 0) { if (result_count == 0 && rs->results.count > 0) {
error(rs->results[0], "No return values expected"); error(rs->results[0], "No return values expected");
+3 -3
View File
@@ -135,7 +135,7 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
type = t_invalid; type = t_invalid;
} }
if (is_type_untyped(type)) { if (is_type_untyped(type)) {
if (is_type_untyped_undef(type)) { if (is_type_untyped_uninit(type)) {
error(params[i], "Cannot determine parameter type from ---"); error(params[i], "Cannot determine parameter type from ---");
} else { } else {
error(params[i], "Cannot determine parameter type from a nil"); error(params[i], "Cannot determine parameter type from a nil");
@@ -473,7 +473,7 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
type = t_invalid; type = t_invalid;
} }
if (is_type_untyped(type)) { if (is_type_untyped(type)) {
if (is_type_untyped_undef(type)) { if (is_type_untyped_uninit(type)) {
error(params[i], "Cannot determine parameter type from ---"); error(params[i], "Cannot determine parameter type from ---");
} else { } else {
error(params[i], "Cannot determine parameter type from a nil"); error(params[i], "Cannot determine parameter type from a nil");
@@ -1528,7 +1528,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
type = t_invalid; type = t_invalid;
} }
if (is_type_untyped(type)) { if (is_type_untyped(type)) {
if (is_type_untyped_undef(type)) { if (is_type_untyped_uninit(type)) {
error(param, "Cannot determine parameter type from ---"); error(param, "Cannot determine parameter type from ---");
} else { } else {
error(param, "Cannot determine parameter type from a nil"); error(param, "Cannot determine parameter type from a nil");
+30 -5
View File
@@ -27,8 +27,8 @@ gb_internal bool is_operand_value(Operand o) {
gb_internal bool is_operand_nil(Operand o) { gb_internal bool is_operand_nil(Operand o) {
return o.mode == Addressing_Value && o.type == t_untyped_nil; return o.mode == Addressing_Value && o.type == t_untyped_nil;
} }
gb_internal bool is_operand_undef(Operand o) { gb_internal bool is_operand_uninit(Operand o) {
return o.mode == Addressing_Value && o.type == t_untyped_undef; return o.mode == Addressing_Value && o.type == t_untyped_uninit;
} }
gb_internal bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) { gb_internal bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) {
@@ -3469,6 +3469,19 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
StringSet set = {}; StringSet set = {};
defer (string_set_destroy(&set)); defer (string_set_destroy(&set));
bool is_runtime = false;
if (c->scope && c->scope->file && (c->scope->flags & ScopeFlag_File) &&
c->scope->file->pkg &&
c->scope->file->pkg->kind == Package_Runtime) {
is_runtime = true;
} else if (c->scope && c->scope->parent &&
(c->scope->flags & ScopeFlag_Proc) &&
(c->scope->parent->flags & ScopeFlag_File) &&
c->scope->parent->file->pkg &&
c->scope->parent->file->pkg->kind == Package_Runtime) {
is_runtime = true;
}
for_array(i, attributes) { for_array(i, attributes) {
Ast *attr = attributes[i]; Ast *attr = attributes[i];
if (attr->kind != Ast_Attribute) continue; if (attr->kind != Ast_Attribute) continue;
@@ -3504,9 +3517,14 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
continue; continue;
} }
if (name == "builtin" && is_runtime) {
continue;
}
if (!proc(c, elem, name, value, ac)) { if (!proc(c, elem, name, value, ac)) {
if (!build_context.ignore_unknown_attributes) { if (!build_context.ignore_unknown_attributes) {
error(elem, "Unknown attribute element name '%.*s'", LIT(name)); error(elem, "Unknown attribute element name '%.*s'", LIT(name));
error_line("\tDid you forget to use build flag '-ignore-unknown-attributes'?\n");
} }
} }
} }
@@ -3663,9 +3681,9 @@ gb_internal void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array<
error(value, "'builtin' cannot have a field value"); error(value, "'builtin' cannot have a field value");
} }
// Remove the builtin tag // Remove the builtin tag
attr->Attribute.elems[k] = attr->Attribute.elems[attr->Attribute.elems.count-1]; // attr->Attribute.elems[k] = attr->Attribute.elems[attr->Attribute.elems.count-1];
attr->Attribute.elems.count -= 1; // attr->Attribute.elems.count -= 1;
k--; // k--;
mutex_unlock(&ctx->info->builtin_mutex); mutex_unlock(&ctx->info->builtin_mutex);
} }
@@ -3874,6 +3892,13 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
cc = ProcCC_CDecl; cc = ProcCC_CDecl;
if (c->foreign_context.default_cc > 0) { if (c->foreign_context.default_cc > 0) {
cc = c->foreign_context.default_cc; cc = c->foreign_context.default_cc;
} else if (is_arch_wasm()) {
begin_error_block();
error(init, "For wasm related targets, it is required that you either define the"
" @(default_calling_convention=<string>) on the foreign block or"
" explicitly assign it on the procedure signature");
error_line("\tSuggestion: when dealing with normal Odin code (e.g. js_wasm32), use \"contextless\"; when dealing with Emscripten like code, use \"c\"\n");
end_error_block();
} }
} }
e->Procedure.link_prefix = c->foreign_context.link_prefix; e->Procedure.link_prefix = c->foreign_context.link_prefix;
+2
View File
@@ -203,6 +203,7 @@ BuiltinProc__type_begin,
BuiltinProc_type_elem_type, BuiltinProc_type_elem_type,
BuiltinProc_type_convert_variants_to_pointers, BuiltinProc_type_convert_variants_to_pointers,
BuiltinProc_type_merge,
BuiltinProc__type_simple_boolean_begin, BuiltinProc__type_simple_boolean_begin,
BuiltinProc_type_is_boolean, BuiltinProc_type_is_boolean,
@@ -501,6 +502,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_merge"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+68 -12
View File
@@ -30,6 +30,7 @@ struct OdinDocWriter {
PtrMap<AstPackage *, OdinDocPkgIndex> pkg_cache; PtrMap<AstPackage *, OdinDocPkgIndex> pkg_cache;
PtrMap<Entity *, OdinDocEntityIndex> entity_cache; PtrMap<Entity *, OdinDocEntityIndex> entity_cache;
PtrMap<Type *, OdinDocTypeIndex> type_cache; PtrMap<Type *, OdinDocTypeIndex> type_cache;
PtrMap<Type *, Type *> stable_type_cache;
OdinDocWriterItemTracker<OdinDocFile> files; OdinDocWriterItemTracker<OdinDocFile> files;
OdinDocWriterItemTracker<OdinDocPkg> pkgs; OdinDocWriterItemTracker<OdinDocPkg> pkgs;
@@ -51,6 +52,7 @@ gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *
gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) { gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
debugf("odin_doc_writer_prepare\n");
w->state = OdinDocWriterState_Preparing; w->state = OdinDocWriterState_Preparing;
string_map_init(&w->string_cache); string_map_init(&w->string_cache);
@@ -59,6 +61,7 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
map_init(&w->pkg_cache); map_init(&w->pkg_cache);
map_init(&w->entity_cache); map_init(&w->entity_cache);
map_init(&w->type_cache); map_init(&w->type_cache);
map_init(&w->stable_type_cache);
odin_doc_writer_item_tracker_init(&w->files, 1); odin_doc_writer_item_tracker_init(&w->files, 1);
odin_doc_writer_item_tracker_init(&w->pkgs, 1); odin_doc_writer_item_tracker_init(&w->pkgs, 1);
@@ -70,6 +73,7 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) { gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
debugf("odin_doc_writer_destroy\n");
gb_free(heap_allocator(), w->data); gb_free(heap_allocator(), w->data);
string_map_destroy(&w->string_cache); string_map_destroy(&w->string_cache);
@@ -77,6 +81,7 @@ gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
map_destroy(&w->pkg_cache); map_destroy(&w->pkg_cache);
map_destroy(&w->entity_cache); map_destroy(&w->entity_cache);
map_destroy(&w->type_cache); map_destroy(&w->type_cache);
map_destroy(&w->stable_type_cache);
} }
@@ -102,6 +107,7 @@ gb_internal isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
} }
gb_internal void odin_doc_writer_start_writing(OdinDocWriter *w) { gb_internal void odin_doc_writer_start_writing(OdinDocWriter *w) {
debugf("odin_doc_writer_start_writing\n");
w->state = OdinDocWriterState_Writing; w->state = OdinDocWriterState_Writing;
string_map_clear(&w->string_cache); string_map_clear(&w->string_cache);
@@ -138,6 +144,7 @@ gb_internal void odin_doc_writer_assign_tracker(OdinDocArray<T> *array, OdinDocW
gb_internal void odin_doc_writer_end_writing(OdinDocWriter *w) { gb_internal void odin_doc_writer_end_writing(OdinDocWriter *w) {
debugf("odin_doc_writer_end_writing\n");
OdinDocHeader *h = w->header; OdinDocHeader *h = w->header;
gb_memmove(h->base.magic, OdinDocHeader_MagicString, gb_strlen(OdinDocHeader_MagicString)); gb_memmove(h->base.magic, OdinDocHeader_MagicString, gb_strlen(OdinDocHeader_MagicString));
@@ -471,22 +478,60 @@ gb_internal OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDo
return odin_write_item_as_slice(w, index); return odin_write_item_as_slice(w, index);
} }
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
if (type == nullptr) { if (type == nullptr) {
return 0; return 0;
} }
// Type **mapped_type = map_get(&w->stable_type_cache, type); // may map to itself
// if (mapped_type && *mapped_type) {
// type = *mapped_type;
// }
OdinDocTypeIndex *found = map_get(&w->type_cache, type); OdinDocTypeIndex *found = map_get(&w->type_cache, type);
if (found) { if (found) {
return *found; return *found;
} }
for (auto const &entry : w->type_cache) { for (auto const &entry : w->type_cache) {
// NOTE(bill): THIS IS SLOW // NOTE(bill): THIS IS SLOW
Type *other = entry.key; Type *x = type;
if (are_types_identical_unique_tuples(type, other)) { Type *y = entry.key;
OdinDocTypeIndex index = entry.value;
map_set(&w->type_cache, type, index); if (x == y) {
return index; goto do_set;
} }
if (!x | !y) {
continue;
}
if (x->kind == Type_Named) {
Entity *e = x->Named.type_name;
if (e->TypeName.is_type_alias) {
x = x->Named.base;
}
}
if (y->kind == Type_Named) {
Entity *e = y->Named.type_name;
if (e->TypeName.is_type_alias) {
y = y->Named.base;
}
}
if (x->kind != y->kind) {
continue;
}
if (!are_types_identical_internal(x, y, true)) {
continue;
}
do_set:
OdinDocTypeIndex index = entry.value;
map_set(&w->type_cache, type, index);
map_set(&w->stable_type_cache, type, entry.key);
return index;
} }
@@ -495,6 +540,7 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
OdinDocTypeIndex type_index = 0; OdinDocTypeIndex type_index = 0;
type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst); type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst);
map_set(&w->type_cache, type, type_index); map_set(&w->type_cache, type, type_index);
map_set(&w->stable_type_cache, type, type);
switch (type->kind) { switch (type->kind) {
case Type_Basic: case Type_Basic:
@@ -856,13 +902,12 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e)
break; break;
} }
if (e->flags & EntityFlag_Param) { if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; }
if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; } if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const; }
if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const; } if (e->flags & EntityFlag_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; }
if (e->flags & EntityFlag_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; } if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; }
if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; } if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; }
if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; }
}
if (e->scope && (e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) && !is_entity_exported(e)) { if (e->scope && (e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) && !is_entity_exported(e)) {
flags |= OdinDocEntityFlag_Private; flags |= OdinDocEntityFlag_Private;
} }
@@ -910,6 +955,8 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e)
} }
gb_internal void odin_doc_update_entities(OdinDocWriter *w) { gb_internal void odin_doc_update_entities(OdinDocWriter *w) {
debugf("odin_doc_update_entities %s\n", w->state ? "preparing" : "writing");
{ {
// NOTE(bill): Double pass, just in case entities are created on odin_doc_type // NOTE(bill): Double pass, just in case entities are created on odin_doc_type
auto entities = array_make<Entity *>(heap_allocator(), 0, w->entity_cache.count); auto entities = array_make<Entity *>(heap_allocator(), 0, w->entity_cache.count);
@@ -974,6 +1021,8 @@ gb_internal OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWrit
return {}; return {};
} }
debugf("odin_doc_add_pkg_entries %s -> package %.*s\n", w->state ? "preparing" : "writing", LIT(pkg->name));
auto entries = array_make<OdinDocScopeEntry>(heap_allocator(), 0, w->entity_cache.count); auto entries = array_make<OdinDocScopeEntry>(heap_allocator(), 0, w->entity_cache.count);
defer (array_free(&entries)); defer (array_free(&entries));
@@ -1017,6 +1066,8 @@ gb_internal OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWrit
gb_internal void odin_doc_write_docs(OdinDocWriter *w) { gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
debugf("odin_doc_write_docs %s", w->state ? "preparing" : "writing");
auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.count); auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.count);
defer (array_free(&pkgs)); defer (array_free(&pkgs));
for (auto const &entry : w->info->packages) { for (auto const &entry : w->info->packages) {
@@ -1032,6 +1083,7 @@ gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
} }
} }
debugf("odin_doc_update_entities sort pkgs %s\n", w->state ? "preparing" : "writing");
gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name); gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);
for_array(i, pkgs) { for_array(i, pkgs) {
@@ -1092,6 +1144,7 @@ gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) { gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
debugf("odin_doc_write_to_file %s\n", filename);
gbFile f = {}; gbFile f = {};
gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, filename); gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, filename);
if (err != gbFileError_None) { if (err != gbFileError_None) {
@@ -1102,6 +1155,7 @@ gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename)
defer (gb_file_close(&f)); defer (gb_file_close(&f));
if (gb_file_write(&f, w->data, w->data_len)) { if (gb_file_write(&f, w->data, w->data_len)) {
err = gb_file_truncate(&f, w->data_len); err = gb_file_truncate(&f, w->data_len);
debugf("Wrote .odin-doc file to: %s\n", filename);
gb_printf("Wrote .odin-doc file to: %s\n", filename); gb_printf("Wrote .odin-doc file to: %s\n", filename);
} }
} }
@@ -1112,6 +1166,8 @@ gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
defer (odin_doc_writer_destroy(w)); defer (odin_doc_writer_destroy(w));
w->info = info; w->info = info;
debugf("odin_doc_write %s\n", filename);
odin_doc_writer_prepare(w); odin_doc_writer_prepare(w);
odin_doc_write_docs(w); odin_doc_write_docs(w);
+27 -10
View File
@@ -1179,7 +1179,11 @@ namespace lbAbiArm64 {
if (is_register(type)) { if (is_register(type)) {
args[i] = non_struct(c, type); args[i] = non_struct(c, type);
} else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) { } else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
args[i] = lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr); if (is_homogenous_aggregate_small_enough(homo_base_type, homo_member_count)) {
args[i] = lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
} else {
args[i] = lb_arg_type_indirect(type, nullptr);;
}
} else { } else {
i64 size = lb_sizeof(type); i64 size = lb_sizeof(type);
if (size <= 16) { if (size <= 16) {
@@ -1213,7 +1217,7 @@ namespace lbAbiWasm {
The approach taken optimizes for passing things in multiple The approach taken optimizes for passing things in multiple
registers/arguments if possible rather than by pointer. registers/arguments if possible rather than by pointer.
*/ */
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count); gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type); gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
enum {MAX_DIRECT_STRUCT_SIZE = 32}; enum {MAX_DIRECT_STRUCT_SIZE = 32};
@@ -1221,7 +1225,7 @@ namespace lbAbiWasm {
gb_internal LB_ABI_INFO(abi_info) { gb_internal LB_ABI_INFO(abi_info) {
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c; ft->ctx = c;
ft->args = compute_arg_types(c, arg_types, arg_count); ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
ft->calling_convention = calling_convention; ft->calling_convention = calling_convention;
return ft; return ft;
@@ -1258,13 +1262,26 @@ namespace lbAbiWasm {
return false; return false;
} }
gb_internal bool type_can_be_direct(LLVMTypeRef type) { gb_internal bool type_can_be_direct(LLVMTypeRef type, ProcCallingConvention calling_convention) {
LLVMTypeKind kind = LLVMGetTypeKind(type); LLVMTypeKind kind = LLVMGetTypeKind(type);
i64 sz = lb_sizeof(type); i64 sz = lb_sizeof(type);
if (sz == 0) { if (sz == 0) {
return false; return false;
} }
if (sz <= MAX_DIRECT_STRUCT_SIZE) { if (calling_convention == ProcCC_CDecl) {
// WASM Basic C ABI:
// https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md#function-signatures
if (kind == LLVMArrayTypeKind) {
return false;
} else if (kind == LLVMStructTypeKind) {
unsigned count = LLVMCountStructElementTypes(type);
if (count == 1) {
return type_can_be_direct(LLVMStructGetTypeAtIndex(type, 0), calling_convention);
}
} else if (is_basic_register_type(type)) {
return true;
}
} else if (sz <= MAX_DIRECT_STRUCT_SIZE) {
if (kind == LLVMArrayTypeKind) { if (kind == LLVMArrayTypeKind) {
if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) { if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) {
return true; return true;
@@ -1284,7 +1301,7 @@ namespace lbAbiWasm {
return false; return false;
} }
gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) { gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
LLVMTypeKind kind = LLVMGetTypeKind(type); LLVMTypeKind kind = LLVMGetTypeKind(type);
GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind); GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
@@ -1292,21 +1309,21 @@ namespace lbAbiWasm {
if (sz == 0) { if (sz == 0) {
return lb_arg_type_ignore(type); return lb_arg_type_ignore(type);
} }
if (type_can_be_direct(type)) { if (type_can_be_direct(type, calling_convention)) {
return lb_arg_type_direct(type); return lb_arg_type_direct(type);
} }
return lb_arg_type_indirect(type, nullptr); return lb_arg_type_indirect(type, nullptr);
} }
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count); auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) { for (unsigned i = 0; i < arg_count; i++) {
LLVMTypeRef t = arg_types[i]; LLVMTypeRef t = arg_types[i];
LLVMTypeKind kind = LLVMGetTypeKind(t); LLVMTypeKind kind = LLVMGetTypeKind(t);
if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) { if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
args[i] = is_struct(c, t); args[i] = is_struct(c, t, calling_convention);
} else { } else {
args[i] = non_struct(c, t, false); args[i] = non_struct(c, t, false);
} }
@@ -1318,7 +1335,7 @@ namespace lbAbiWasm {
if (!return_is_defined) { if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c)); return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) { } else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
if (type_can_be_direct(return_type)) { if (type_can_be_direct(return_type, ft->calling_convention)) {
return lb_arg_type_direct(return_type); return lb_arg_type_direct(return_type);
} }
+26 -15
View File
@@ -720,6 +720,7 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) {
lbBlock *check_grow_block = lb_create_block(p, "check-grow"); lbBlock *check_grow_block = lb_create_block(p, "check-grow");
lbBlock *grow_fail_block = lb_create_block(p, "grow-fail"); lbBlock *grow_fail_block = lb_create_block(p, "grow-fail");
lbBlock *insert_block = lb_create_block(p, "insert"); lbBlock *insert_block = lb_create_block(p, "insert");
lbBlock *rehash_block = lb_create_block(p, "rehash");
lb_emit_if(p, lb_emit_comp_against_nil(p, Token_NotEq, found_ptr), found_block, check_grow_block); lb_emit_if(p, lb_emit_comp_against_nil(p, Token_NotEq, found_ptr), found_block, check_grow_block);
lb_start_block(p, found_block); lb_start_block(p, found_block);
@@ -737,12 +738,19 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) {
args[0] = lb_emit_conv(p, map_ptr, t_rawptr); args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
args[1] = map_info; args[1] = map_info;
args[2] = lb_emit_load(p, location_ptr); args[2] = lb_emit_load(p, location_ptr);
lbValue grow_err = lb_emit_runtime_call(p, "__dynamic_map_check_grow", args); lbValue grow_err_and_has_grown = lb_emit_runtime_call(p, "__dynamic_map_check_grow", args);
lbValue grow_err = lb_emit_struct_ev(p, grow_err_and_has_grown, 0);
lbValue has_grown = lb_emit_struct_ev(p, grow_err_and_has_grown, 1);
lb_emit_if(p, lb_emit_comp_against_nil(p, Token_NotEq, grow_err), grow_fail_block, insert_block); lb_emit_if(p, lb_emit_comp_against_nil(p, Token_NotEq, grow_err), grow_fail_block, insert_block);
lb_start_block(p, grow_fail_block); lb_start_block(p, grow_fail_block);
LLVMBuildRet(p->builder, LLVMConstNull(lb_type(m, t_rawptr))); LLVMBuildRet(p->builder, LLVMConstNull(lb_type(m, t_rawptr)));
lb_emit_if(p, has_grown, grow_fail_block, rehash_block);
lb_start_block(p, rehash_block);
lbValue key = lb_emit_load(p, key_ptr);
hash = lb_gen_map_key_hash(p, map_ptr, key, nullptr);
} }
lb_start_block(p, insert_block); lb_start_block(p, insert_block);
@@ -916,7 +924,7 @@ gb_internal lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
return hashed_key; return hashed_key;
} }
gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) { gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue const &map_ptr, lbValue key, lbValue *key_ptr_) {
TEMPORARY_ALLOCATOR_GUARD(); TEMPORARY_ALLOCATOR_GUARD();
lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
@@ -924,13 +932,22 @@ gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_t
if (key_ptr_) *key_ptr_ = key_ptr; if (key_ptr_) *key_ptr_ = key_ptr;
Type* key_type = base_type(type_deref(map_ptr.type))->Map.key;
lbValue hashed_key = lb_const_hash(p->module, key, key_type); lbValue hashed_key = lb_const_hash(p->module, key, key_type);
if (hashed_key.value == nullptr) { if (hashed_key.value == nullptr) {
lbValue hasher = lb_hasher_proc_for_type(p->module, key_type); lbValue hasher = lb_hasher_proc_for_type(p->module, key_type);
lbValue seed = {};
{
auto args = array_make<lbValue>(temporary_allocator(), 1);
args[0] = lb_map_data_uintptr(p, lb_emit_load(p, map_ptr));
seed = lb_emit_runtime_call(p, "map_seed_from_map_data", args);
}
auto args = array_make<lbValue>(temporary_allocator(), 2); auto args = array_make<lbValue>(temporary_allocator(), 2);
args[0] = key_ptr; args[0] = key_ptr;
args[1] = lb_const_int(p->module, t_uintptr, 0); args[1] = seed;
hashed_key = lb_emit_call(p, hasher, args); hashed_key = lb_emit_call(p, hasher, args);
} }
@@ -945,7 +962,7 @@ gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue cons
lbValue ptr = {}; lbValue ptr = {};
lbValue key_ptr = {}; lbValue key_ptr = {};
lbValue hash = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr); lbValue hash = lb_gen_map_key_hash(p, map_ptr, key, &key_ptr);
if (build_context.dynamic_map_calls) { if (build_context.dynamic_map_calls) {
auto args = array_make<lbValue>(temporary_allocator(), 4); auto args = array_make<lbValue>(temporary_allocator(), 4);
@@ -976,7 +993,7 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_
GB_ASSERT(map_type->kind == Type_Map); GB_ASSERT(map_type->kind == Type_Map);
lbValue key_ptr = {}; lbValue key_ptr = {};
lbValue hash = lb_gen_map_key_hash(p, map_key, map_type->Map.key, &key_ptr); lbValue hash = lb_gen_map_key_hash(p, map_ptr, map_key, &key_ptr);
lbValue v = lb_emit_conv(p, map_value, map_type->Map.value); lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
lbValue value_ptr = lb_address_from_load_or_generate_local(p, v); lbValue value_ptr = lb_address_from_load_or_generate_local(p, v);
@@ -1129,12 +1146,7 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
lbValue init = lb_build_expr(p, init_expr); lbValue init = lb_build_expr(p, init_expr);
if (init.value == nullptr) { if (init.value == nullptr) {
LLVMTypeRef global_type = llvm_addr_type(p->module, var.var); LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
if (is_type_untyped_undef(init.type)) { if (is_type_untyped_nil(init.type)) {
// LLVMSetInitializer(var.var.value, LLVMGetUndef(global_type));
LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
var.is_initialized = true;
continue;
} else if (is_type_untyped_nil(init.type)) {
LLVMSetInitializer(var.var.value, LLVMConstNull(global_type)); LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
var.is_initialized = true; var.is_initialized = true;
continue; continue;
@@ -1365,7 +1377,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_emit_worker_proc) {
gb_internal void lb_llvm_function_pass_per_function_internal(lbModule *module, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default) { gb_internal void lb_llvm_function_pass_per_function_internal(lbModule *module, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default) {
LLVMPassManagerRef pass_manager = module->function_pass_managers[pass_manager_kind]; LLVMPassManagerRef pass_manager = module->function_pass_managers[pass_manager_kind];
lb_run_function_pass_manager(pass_manager, p); lb_run_function_pass_manager(pass_manager, p, pass_manager_kind);
} }
gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
@@ -1899,7 +1911,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
LLVMVerifyFunction(p->value, LLVMAbortProcessAction); LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
} }
lb_run_function_pass_manager(default_function_pass_manager, p); lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default);
return p; return p;
} }
@@ -2363,8 +2375,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
} }
} }
} }
if (!var.is_initialized && if (!var.is_initialized && is_type_untyped_nil(tav.type)) {
(is_type_untyped_nil(tav.type) || is_type_untyped_undef(tav.type))) {
var.is_initialized = true; var.is_initialized = true;
} }
} }
+1 -1
View File
@@ -477,7 +477,7 @@ gb_internal String lb_get_const_string(lbModule *m, lbValue value);
gb_internal lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true); gb_internal lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
gb_internal lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id); gb_internal lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_); gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue const &map_ptr, lbValue key, lbValue *key_ptr_);
gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type); gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type);
gb_internal lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type); gb_internal lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type);
+10 -5
View File
@@ -1,6 +1,6 @@
gb_internal bool lb_is_const(lbValue value) { gb_internal bool lb_is_const(lbValue value) {
LLVMValueRef v = value.value; LLVMValueRef v = value.value;
if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) { if (is_type_untyped_nil(value.type)) {
// TODO(bill): Is this correct behaviour? // TODO(bill): Is this correct behaviour?
return true; return true;
} }
@@ -107,7 +107,11 @@ gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
case LLVMPointerTypeKind: case LLVMPointerTypeKind:
return LLVMConstPointerCast(val, dst); return LLVMConstPointerCast(val, dst);
case LLVMStructTypeKind: case LLVMStructTypeKind:
return LLVMConstBitCast(val, dst); // GB_PANIC("%s -> %s", LLVMPrintValueToString(val), LLVMPrintTypeToString(dst));
// NOTE(bill): It's not possible to do a bit cast on a struct, why was this code even here in the first place?
// It seems mostly to exist to get around the "anonymous -> named" struct assignments
// return LLVMConstBitCast(val, dst);
return val;
default: default:
GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst)); GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst));
} }
@@ -1036,9 +1040,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
} }
cv_type = cvt->Struct.fields[index]->type; cv_type = cvt->Struct.fields[index]->type;
if (is_type_struct(cv_type)) { if (is_type_struct(cvt)) {
auto cv_field_remapping = lb_get_struct_remapping(m, cv_type); auto cv_field_remapping = lb_get_struct_remapping(m, cvt);
idx_list[j-1] = cast(unsigned)cv_field_remapping[index]; unsigned remapped_index = cast(unsigned)cv_field_remapping[index];
idx_list[j-1] = remapped_index;
} else { } else {
idx_list[j-1] = cast(unsigned)index; idx_list[j-1] = cast(unsigned)index;
} }
+1 -1
View File
@@ -283,7 +283,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break; case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break;
case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break; case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break;
case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break; case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break;
case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break; case Basic_UntypedUninit: GB_PANIC("Basic_UntypedUninit"); break;
default: GB_PANIC("Basic Unhandled"); break; default: GB_PANIC("Basic Unhandled"); break;
} }
+41 -53
View File
@@ -1,20 +1,18 @@
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise); gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) { gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *final_type) {
lbModule *m = p->module; lbModule *m = p->module;
lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs"); lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs");
lbBlock *done = lb_create_block(p, "logical.cmp.done"); lbBlock *done = lb_create_block(p, "logical.cmp.done");
type = default_type(type);
lbValue short_circuit = {}; lbValue short_circuit = {};
if (op == Token_CmpAnd) { if (op == Token_CmpAnd) {
lb_build_cond(p, left, rhs, done); lb_build_cond(p, left, rhs, done);
short_circuit = lb_const_bool(m, type, false); short_circuit = lb_const_bool(m, t_llvm_bool, false);
} else if (op == Token_CmpOr) { } else if (op == Token_CmpOr) {
lb_build_cond(p, left, done, rhs); lb_build_cond(p, left, done, rhs);
short_circuit = lb_const_bool(m, type, true); short_circuit = lb_const_bool(m, t_llvm_bool, true);
} }
if (rhs->preds.count == 0) { if (rhs->preds.count == 0) {
@@ -25,7 +23,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
if (done->preds.count == 0) { if (done->preds.count == 0) {
lb_start_block(p, rhs); lb_start_block(p, rhs);
if (lb_is_expr_untyped_const(right)) { if (lb_is_expr_untyped_const(right)) {
return lb_expr_untyped_const_to_typed(m, right, type); return lb_expr_untyped_const_to_typed(m, right, default_type(final_type));
} }
return lb_build_expr(p, right); return lb_build_expr(p, right);
} }
@@ -43,10 +41,11 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
lb_start_block(p, rhs); lb_start_block(p, rhs);
lbValue edge = {}; lbValue edge = {};
if (lb_is_expr_untyped_const(right)) { if (lb_is_expr_untyped_const(right)) {
edge = lb_expr_untyped_const_to_typed(m, right, type); edge = lb_expr_untyped_const_to_typed(m, right, t_llvm_bool);
} else { } else {
edge = lb_build_expr(p, right); edge = lb_emit_conv(p, lb_build_expr(p, right), t_llvm_bool);
} }
GB_ASSERT(edge.type == t_llvm_bool);
incoming_values[done->preds.count] = edge.value; incoming_values[done->preds.count] = edge.value;
incoming_blocks[done->preds.count] = p->curr_block->block; incoming_blocks[done->preds.count] = p->curr_block->block;
@@ -54,7 +53,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
lb_emit_jump(p, done); lb_emit_jump(p, done);
lb_start_block(p, done); lb_start_block(p, done);
LLVMTypeRef dst_type = lb_type(m, type); LLVMTypeRef dst_type = lb_type(m, t_llvm_bool);
LLVMValueRef phi = nullptr; LLVMValueRef phi = nullptr;
GB_ASSERT(incoming_values.count == incoming_blocks.count); GB_ASSERT(incoming_values.count == incoming_blocks.count);
@@ -68,47 +67,35 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
} }
} }
lbValue res = {};
if (phi_type == nullptr) { if (phi_type == nullptr) {
phi = LLVMBuildPhi(p->builder, dst_type, ""); phi = LLVMBuildPhi(p->builder, dst_type, "");
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count); LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
lbValue res = {};
res.type = type;
res.value = phi; res.value = phi;
return res; res.type = t_llvm_bool;
}
for_array(i, incoming_values) {
LLVMValueRef incoming_value = incoming_values[i];
LLVMTypeRef incoming_type = LLVMTypeOf(incoming_value);
if (phi_type != incoming_type) {
GB_ASSERT_MSG(LLVMIsConstant(incoming_value), "%s vs %s", LLVMPrintTypeToString(phi_type), LLVMPrintTypeToString(incoming_type));
bool ok = !!LLVMConstIntGetZExtValue(incoming_value);
incoming_values[i] = LLVMConstInt(phi_type, ok, false);
}
}
phi = LLVMBuildPhi(p->builder, phi_type, "");
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
LLVMTypeRef i1 = LLVMInt1TypeInContext(m->ctx);
if ((phi_type == i1) ^ (dst_type == i1)) {
if (phi_type == i1) {
phi = LLVMBuildZExt(p->builder, phi, dst_type, "");
} else {
phi = LLVMBuildTruncOrBitCast(p->builder, phi, dst_type, "");
}
} else if (lb_sizeof(phi_type) < lb_sizeof(dst_type)) {
phi = LLVMBuildZExt(p->builder, phi, dst_type, "");
} else { } else {
phi = LLVMBuildTruncOrBitCast(p->builder, phi, dst_type, ""); for_array(i, incoming_values) {
} LLVMValueRef incoming_value = incoming_values[i];
LLVMTypeRef incoming_type = LLVMTypeOf(incoming_value);
lbValue res = {}; if (phi_type != incoming_type) {
res.type = type; GB_ASSERT_MSG(LLVMIsConstant(incoming_value), "%s vs %s", LLVMPrintTypeToString(phi_type), LLVMPrintTypeToString(incoming_type));
res.value = phi; bool ok = !!LLVMConstIntGetZExtValue(incoming_value);
return res; incoming_values[i] = LLVMConstInt(phi_type, ok, false);
}
}
// NOTE(bill): this now only uses i1 for the logic to prevent issues with corrupted booleans which are not of value 0 or 1 (e.g. 2)
// Doing this may produce slightly worse code as a result but it will be correct behaviour
phi = LLVMBuildPhi(p->builder, phi_type, "");
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
res.value = phi;
res.type = t_llvm_bool;
}
return lb_emit_conv(p, res, default_type(final_type));
} }
@@ -1499,12 +1486,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
GB_ASSERT(src != nullptr); GB_ASSERT(src != nullptr);
GB_ASSERT(dst != nullptr); GB_ASSERT(dst != nullptr);
if (is_type_untyped_uninit(src)) {
return lb_const_undef(m, t);
}
if (is_type_untyped_nil(src)) { if (is_type_untyped_nil(src)) {
return lb_const_nil(m, t); return lb_const_nil(m, t);
} }
if (is_type_untyped_undef(src)) {
return lb_const_undef(m, t);
}
if (LLVMIsConstant(value.value)) { if (LLVMIsConstant(value.value)) {
if (is_type_any(dst)) { if (is_type_any(dst)) {
@@ -1566,7 +1553,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
// bool <-> llvm bool // bool <-> llvm bool
if (is_type_boolean(src) && dst == t_llvm_bool) { if (is_type_boolean(src) && dst == t_llvm_bool) {
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), ""); res.value = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, src)), "");
res.type = t; res.type = t;
return res; return res;
} }
@@ -2145,12 +2132,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
if (is_type_any(dst)) { if (is_type_any(dst)) {
if (is_type_untyped_uninit(src)) {
return lb_const_undef(p->module, t);
}
if (is_type_untyped_nil(src)) { if (is_type_untyped_nil(src)) {
return lb_const_nil(p->module, t); return lb_const_nil(p->module, t);
} }
if (is_type_untyped_undef(src)) {
return lb_const_undef(p->module, t);
}
lbAddr result = lb_add_local_generated(p, t, true); lbAddr result = lb_add_local_generated(p, t, true);
@@ -3149,11 +3136,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
return lb_addr_load(p, lb_build_addr(p, expr)); return lb_addr_load(p, lb_build_addr(p, expr));
case_end; case_end;
case_ast_node(u, Undef, expr) case_ast_node(u, Uninit, expr)
lbValue res = {}; lbValue res = {};
if (is_type_untyped(type)) { if (is_type_untyped(type)) {
res.value = nullptr; res.value = nullptr;
res.type = t_untyped_undef; res.type = t_untyped_uninit;
} else { } else {
res.value = LLVMGetUndef(lb_type(m, type)); res.value = LLVMGetUndef(lb_type(m, type));
res.type = type; res.type = type;
@@ -3783,6 +3770,7 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
multi_ptr = lb_emit_load(p, multi_ptr); multi_ptr = lb_emit_load(p, multi_ptr);
} }
lbValue index = lb_build_expr(p, ie->index); lbValue index = lb_build_expr(p, ie->index);
index = lb_emit_conv(p, index, t_int);
lbValue v = {}; lbValue v = {};
LLVMValueRef indices[1] = {index.value}; LLVMValueRef indices[1] = {index.value};
+2 -2
View File
@@ -677,7 +677,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
return; return;
} }
GB_ASSERT(value.type != nullptr); GB_ASSERT(value.type != nullptr);
if (is_type_untyped_undef(value.type)) { if (is_type_untyped_uninit(value.type)) {
Type *t = lb_addr_type(addr); Type *t = lb_addr_type(addr);
value.type = t; value.type = t;
value.value = LLVMGetUndef(lb_type(p->module, t)); value.value = LLVMGetUndef(lb_type(p->module, t));
@@ -1830,7 +1830,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break; case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break;
case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break; case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break;
case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break; case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break;
case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break; case Basic_UntypedUninit: GB_PANIC("Basic_UntypedUninit"); break;
} }
break; break;
case Type_Named: case Type_Named:
+11 -1
View File
@@ -370,11 +370,21 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
} }
gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) { gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind) {
if (p == nullptr) { if (p == nullptr) {
return; return;
} }
LLVMRunFunctionPassManager(fpm, p->value); LLVMRunFunctionPassManager(fpm, p->value);
switch (pass_manager_kind) {
case lbFunctionPassManager_none:
return;
case lbFunctionPassManager_default:
case lbFunctionPassManager_default_without_memcpy:
if (build_context.optimization_level < 0) {
return;
}
break;
}
// NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM // NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM
// which means we cannot rely upon it // which means we cannot rely upon it
// This is also useful for read the .ll for debug purposes because a lot of instructions // This is also useful for read the .ll for debug purposes because a lot of instructions
+4 -4
View File
@@ -3218,10 +3218,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
Entity *e = params->variables[i]; Entity *e = params->variables[i];
if (args[i].type == nullptr) { if (args[i].type == nullptr) {
continue; continue;
} else if (is_type_untyped_uninit(args[i].type)) {
args[i] = lb_const_undef(m, e->type);
} else if (is_type_untyped_nil(args[i].type)) { } else if (is_type_untyped_nil(args[i].type)) {
args[i] = lb_const_nil(m, e->type); args[i] = lb_const_nil(m, e->type);
} else if (is_type_untyped_undef(args[i].type)) {
args[i] = lb_const_undef(m, e->type);
} }
} }
@@ -3409,10 +3409,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
Entity *e = param_tuple->variables[i]; Entity *e = param_tuple->variables[i];
if (args[i].type == nullptr) { if (args[i].type == nullptr) {
continue; continue;
} else if (is_type_untyped_uninit(args[i].type)) {
args[i] = lb_const_undef(m, e->type);
} else if (is_type_untyped_nil(args[i].type)) { } else if (is_type_untyped_nil(args[i].type)) {
args[i] = lb_const_nil(m, e->type); args[i] = lb_const_nil(m, e->type);
} else if (is_type_untyped_undef(args[i].type)) {
args[i] = lb_const_undef(m, e->type);
} }
} }
} }
+211 -51
View File
@@ -249,7 +249,8 @@ gb_internal void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr, gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_,
bool is_reverse) {
lbModule *m = p->module; lbModule *m = p->module;
lbValue count = {}; lbValue count = {};
@@ -266,25 +267,78 @@ gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_
lbBlock *done = nullptr; lbBlock *done = nullptr;
lbBlock *body = nullptr; lbBlock *body = nullptr;
lbAddr index = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1));
loop = lb_create_block(p, "for.index.loop"); loop = lb_create_block(p, "for.index.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int);
lb_addr_store(p, index, incr);
body = lb_create_block(p, "for.index.body"); body = lb_create_block(p, "for.index.body");
done = lb_create_block(p, "for.index.done"); done = lb_create_block(p, "for.index.done");
if (count.value == nullptr) {
GB_ASSERT(count_ptr.value != nullptr); lbAddr index = lb_add_local_generated(p, t_int, false);
count = lb_emit_load(p, count_ptr);
if (!is_reverse) {
/*
for x, i in array {
...
}
i := -1
for {
i += 1
if !(i < len(array)) {
break
}
#no_bounds_check x := array[i]
...
}
*/
lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1));
lb_emit_jump(p, loop);
lb_start_block(p, loop);
lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int);
lb_addr_store(p, index, incr);
if (count.value == nullptr) {
GB_ASSERT(count_ptr.value != nullptr);
count = lb_emit_load(p, count_ptr);
}
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
lb_emit_if(p, cond, body, done);
} else {
// NOTE(bill): REVERSED LOGIC
/*
#reverse for x, i in array {
...
}
i := len(array)
for {
i -= 1
if i < 0 {
break
}
#no_bounds_check x := array[i]
...
}
*/
if (count.value == nullptr) {
GB_ASSERT(count_ptr.value != nullptr);
count = lb_emit_load(p, count_ptr);
}
count = lb_emit_conv(p, count, t_int);
lb_addr_store(p, index, count);
lb_emit_jump(p, loop);
lb_start_block(p, loop);
lbValue incr = lb_emit_arith(p, Token_Sub, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int);
lb_addr_store(p, index, incr);
lbValue anti_cond = lb_emit_comp(p, Token_Lt, incr, lb_const_int(m, t_int, 0));
lb_emit_if(p, anti_cond, done, body);
} }
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
lb_emit_if(p, cond, body, done);
lb_start_block(p, body); lb_start_block(p, body);
idx = lb_addr_load(p, index); idx = lb_addr_load(p, index);
@@ -452,7 +506,8 @@ gb_internal void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type
gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type, gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_,
bool is_reverse) {
lbModule *m = p->module; lbModule *m = p->module;
lbValue count = lb_const_int(m, t_int, 0); lbValue count = lb_const_int(m, t_int, 0);
Type *expr_type = base_type(expr.type); Type *expr_type = base_type(expr.type);
@@ -471,35 +526,88 @@ gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_t
lbBlock *done = nullptr; lbBlock *done = nullptr;
lbBlock *body = nullptr; lbBlock *body = nullptr;
lbAddr offset_ = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
loop = lb_create_block(p, "for.string.loop"); loop = lb_create_block(p, "for.string.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
body = lb_create_block(p, "for.string.body"); body = lb_create_block(p, "for.string.body");
done = lb_create_block(p, "for.string.done"); done = lb_create_block(p, "for.string.done");
lbValue offset = lb_addr_load(p, offset_); lbAddr offset_ = lb_add_local_generated(p, t_int, false);
lbValue cond = lb_emit_comp(p, Token_Lt, offset, count); lbValue offset = {};
lbValue cond = {};
if (!is_reverse) {
/*
for c, offset in str {
...
}
offset := 0
for offset < len(str) {
c, _w := string_decode_rune(str[offset:])
...
offset += _w
}
*/
lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
lb_emit_jump(p, loop);
lb_start_block(p, loop);
offset = lb_addr_load(p, offset_);
cond = lb_emit_comp(p, Token_Lt, offset, count);
} else {
// NOTE(bill): REVERSED LOGIC
/*
#reverse for c, offset in str {
...
}
offset := len(str)
for offset > 0 {
c, _w := string_decode_last_rune(str[:offset])
offset -= _w
...
}
*/
lb_addr_store(p, offset_, count);
lb_emit_jump(p, loop);
lb_start_block(p, loop);
offset = lb_addr_load(p, offset_);
cond = lb_emit_comp(p, Token_Gt, offset, lb_const_int(m, t_int, 0));
}
lb_emit_if(p, cond, body, done); lb_emit_if(p, cond, body, done);
lb_start_block(p, body); lb_start_block(p, body);
lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset); lbValue rune_and_len = {};
lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int); if (!is_reverse) {
auto args = array_make<lbValue>(permanent_allocator(), 1); lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset);
args[0] = lb_emit_string(p, str_elem, str_len); lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int);
lbValue rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args); auto args = array_make<lbValue>(permanent_allocator(), 1);
lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); args[0] = lb_emit_string(p, str_elem, str_len);
lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int));
rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args);
lbValue len = lb_emit_struct_ev(p, rune_and_len, 1);
lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int));
idx = offset;
} else {
// NOTE(bill): REVERSED LOGIC
lbValue str_elem = lb_string_elem(p, expr);
lbValue str_len = offset;
auto args = array_make<lbValue>(permanent_allocator(), 1);
args[0] = lb_emit_string(p, str_elem, str_len);
rune_and_len = lb_emit_runtime_call(p, "string_decode_last_rune", args);
lbValue len = lb_emit_struct_ev(p, rune_and_len, 1);
lb_addr_store(p, offset_, lb_emit_arith(p, Token_Sub, offset, len, t_int));
idx = lb_addr_load(p, offset_);
}
idx = offset;
if (val_type != nullptr) { if (val_type != nullptr) {
val = lb_emit_struct_ev(p, rune_and_len, 0); val = lb_emit_struct_ev(p, rune_and_len, 0);
} }
@@ -702,6 +810,8 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
lbBlock *body = nullptr; lbBlock *body = nullptr;
lbBlock *done = nullptr; lbBlock *done = nullptr;
bool is_reverse = rs->reverse;
lb_open_scope(p, scope); lb_open_scope(p, scope);
@@ -723,20 +833,70 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
lbAddr index = lb_add_local_generated(p, t_int, false); lbAddr index = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1));
loop = lb_create_block(p, "for.soa.loop"); if (!is_reverse) {
lb_emit_jump(p, loop); /*
lb_start_block(p, loop); for x, i in array {
...
}
lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int); i := -1
lb_addr_store(p, index, incr); for {
i += 1
if !(i < len(array)) {
break
}
x := array[i] // but #soa-ified
...
}
*/
body = lb_create_block(p, "for.soa.body"); lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1));
done = lb_create_block(p, "for.soa.done");
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count); loop = lb_create_block(p, "for.soa.loop");
lb_emit_if(p, cond, body, done); lb_emit_jump(p, loop);
lb_start_block(p, loop);
lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int);
lb_addr_store(p, index, incr);
body = lb_create_block(p, "for.soa.body");
done = lb_create_block(p, "for.soa.done");
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
lb_emit_if(p, cond, body, done);
} else {
// NOTE(bill): REVERSED LOGIC
/*
#reverse for x, i in array {
...
}
i := len(array)
for {
i -= 1
if i < 0 {
break
}
#no_bounds_check x := array[i] // but #soa-ified
...
}
*/
lb_addr_store(p, index, count);
loop = lb_create_block(p, "for.soa.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
lbValue incr = lb_emit_arith(p, Token_Sub, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int);
lb_addr_store(p, index, incr);
body = lb_create_block(p, "for.soa.body");
done = lb_create_block(p, "for.soa.done");
lbValue cond = lb_emit_comp(p, Token_Lt, incr, lb_const_int(p->module, t_int, 0));
lb_emit_if(p, cond, done, body);
}
lb_start_block(p, body); lb_start_block(p, body);
@@ -820,7 +980,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
} }
lbAddr count_ptr = lb_add_local_generated(p, t_int, false); lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count)); lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count));
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done); lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse);
break; break;
} }
case Type_EnumeratedArray: { case Type_EnumeratedArray: {
@@ -830,7 +990,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
} }
lbAddr count_ptr = lb_add_local_generated(p, t_int, false); lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->EnumeratedArray.count)); lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->EnumeratedArray.count));
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done); lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse);
break; break;
} }
case Type_DynamicArray: { case Type_DynamicArray: {
@@ -840,7 +1000,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
array = lb_emit_load(p, array); array = lb_emit_load(p, array);
} }
count_ptr = lb_emit_struct_ep(p, array, 1); count_ptr = lb_emit_struct_ep(p, array, 1);
lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done); lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse);
break; break;
} }
case Type_Slice: { case Type_Slice: {
@@ -853,7 +1013,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
count_ptr = lb_add_local_generated(p, t_int, false).addr; count_ptr = lb_add_local_generated(p, t_int, false).addr;
lb_emit_store(p, count_ptr, lb_slice_len(p, slice)); lb_emit_store(p, count_ptr, lb_slice_len(p, slice));
} }
lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done); lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse);
break; break;
} }
case Type_Basic: { case Type_Basic: {
@@ -868,7 +1028,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
} }
Type *t = base_type(string.type); Type *t = base_type(string.type);
GB_ASSERT(!is_type_cstring(t)); GB_ASSERT(!is_type_cstring(t));
lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done); lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse);
break; break;
} }
case Type_Tuple: case Type_Tuple:
+36 -11
View File
@@ -115,7 +115,7 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
n->Ident.entity = nullptr; n->Ident.entity = nullptr;
break; break;
case Ast_Implicit: break; case Ast_Implicit: break;
case Ast_Undef: break; case Ast_Uninit: break;
case Ast_BasicLit: break; case Ast_BasicLit: break;
case Ast_BasicDirective: break; case Ast_BasicDirective: break;
@@ -646,9 +646,9 @@ gb_internal Ast *ast_implicit(AstFile *f, Token token) {
result->Implicit = token; result->Implicit = token;
return result; return result;
} }
gb_internal Ast *ast_undef(AstFile *f, Token token) { gb_internal Ast *ast_uninit(AstFile *f, Token token) {
Ast *result = alloc_ast_node(f, Ast_Undef); Ast *result = alloc_ast_node(f, Ast_Uninit);
result->Undef = token; result->Uninit = token;
return result; return result;
} }
@@ -2092,8 +2092,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
case Token_Ident: case Token_Ident:
return parse_ident(f); return parse_ident(f);
case Token_Undef: case Token_Uninit:
return ast_undef(f, expect_token(f, Token_Undef)); return ast_uninit(f, expect_token(f, Token_Uninit));
case Token_context: case Token_context:
return ast_implicit(f, expect_token(f, Token_context)); return ast_implicit(f, expect_token(f, Token_context));
@@ -2292,7 +2292,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
skip_possible_newline_for_literal(f); skip_possible_newline_for_literal(f);
if (allow_token(f, Token_Undef)) { if (allow_token(f, Token_Uninit)) {
if (where_token.kind != Token_Invalid) { if (where_token.kind != Token_Invalid) {
syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)"); syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)");
} }
@@ -3744,8 +3744,18 @@ gb_internal bool allow_field_separator(AstFile *f) {
if (allow_token(f, Token_Comma)) { if (allow_token(f, Token_Comma)) {
return true; return true;
} }
if (ALLOW_NEWLINE && token.kind == Token_Semicolon) { if (token.kind == Token_Semicolon) {
if (!token_is_newline(token)) { bool ok = false;
if (ALLOW_NEWLINE && token_is_newline(token)) {
TokenKind next = peek_token(f).kind;
switch (next) {
case Token_CloseBrace:
case Token_CloseParen:
ok = true;
break;
}
}
if (!ok) {
String p = token_to_string(token); String p = token_to_string(token);
syntax_error(token_end_of_line(f, f->prev_token), "Expected a comma, got a %.*s", LIT(p)); syntax_error(token_end_of_line(f, f->prev_token), "Expected a comma, got a %.*s", LIT(p));
} }
@@ -4509,7 +4519,7 @@ gb_internal Ast *parse_foreign_decl(AstFile *f) {
return ast_bad_decl(f, token, f->curr_token); return ast_bad_decl(f, token, f->curr_token);
} }
gb_internal Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind close_kind) { gb_internal Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind close_kind, CommentGroup *docs) {
Array<Ast *> elems = {}; Array<Ast *> elems = {};
Token open = {}; Token open = {};
Token close = {}; Token close = {};
@@ -4550,6 +4560,9 @@ gb_internal Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, T
Ast *decl = parse_stmt(f); Ast *decl = parse_stmt(f);
if (decl->kind == Ast_ValueDecl) { if (decl->kind == Ast_ValueDecl) {
if (decl->ValueDecl.docs == nullptr && docs != nullptr) {
decl->ValueDecl.docs = docs;
}
array_add(&decl->ValueDecl.attributes, attribute); array_add(&decl->ValueDecl.attributes, attribute);
} else if (decl->kind == Ast_ForeignBlockDecl) { } else if (decl->kind == Ast_ForeignBlockDecl) {
array_add(&decl->ForeignBlockDecl.attributes, attribute); array_add(&decl->ForeignBlockDecl.attributes, attribute);
@@ -4698,8 +4711,9 @@ gb_internal Ast *parse_stmt(AstFile *f) {
} break; } break;
case Token_At: { case Token_At: {
CommentGroup *docs = f->lead_comment;
Token token = expect_token(f, Token_At); Token token = expect_token(f, Token_At);
return parse_attribute(f, token, Token_OpenParen, Token_CloseParen); return parse_attribute(f, token, Token_OpenParen, Token_CloseParen, docs);
} }
case Token_Hash: { case Token_Hash: {
@@ -4749,6 +4763,17 @@ gb_internal Ast *parse_stmt(AstFile *f) {
return stmt; return stmt;
} else if (tag == "unroll") { } else if (tag == "unroll") {
return parse_unrolled_for_loop(f, name); return parse_unrolled_for_loop(f, name);
} else if (tag == "reverse") {
Ast *for_stmt = parse_for_stmt(f);
if (for_stmt->kind == Ast_RangeStmt) {
if (for_stmt->RangeStmt.reverse) {
syntax_error(token, "#reverse already applied to a 'for in' statement");
}
for_stmt->RangeStmt.reverse = true;
} else {
syntax_error(token, "#reverse can only be applied to a 'for in' statement");
}
return for_stmt;
} else if (tag == "include") { } else if (tag == "include") {
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?"); syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
s = ast_bad_stmt(f, token, f->curr_token); s = ast_bad_stmt(f, token, f->curr_token);
+11 -1
View File
@@ -356,6 +356,15 @@ enum UnionTypeKind : u8 {
UnionType_Normal = 0, UnionType_Normal = 0,
UnionType_no_nil = 2, UnionType_no_nil = 2,
UnionType_shared_nil = 3, UnionType_shared_nil = 3,
UnionType_COUNT
};
gb_global char const *union_type_kind_strings[UnionType_COUNT] = {
"(normal)",
"#maybe",
"#no_nil",
"#shared_nil",
}; };
#define AST_KINDS \ #define AST_KINDS \
@@ -364,7 +373,7 @@ enum UnionTypeKind : u8 {
Entity *entity; \ Entity *entity; \
}) \ }) \
AST_KIND(Implicit, "implicit", Token) \ AST_KIND(Implicit, "implicit", Token) \
AST_KIND(Undef, "undef", Token) \ AST_KIND(Uninit, "uninitialized value", Token) \
AST_KIND(BasicLit, "basic literal", struct { \ AST_KIND(BasicLit, "basic literal", struct { \
Token token; \ Token token; \
}) \ }) \
@@ -520,6 +529,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
Token in_token; \ Token in_token; \
Ast *expr; \ Ast *expr; \
Ast *body; \ Ast *body; \
bool reverse; \
}) \ }) \
AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \ AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \
Scope *scope; \ Scope *scope; \
+2 -2
View File
@@ -2,7 +2,7 @@ gb_internal Token ast_token(Ast *node) {
switch (node->kind) { switch (node->kind) {
case Ast_Ident: return node->Ident.token; case Ast_Ident: return node->Ident.token;
case Ast_Implicit: return node->Implicit; case Ast_Implicit: return node->Implicit;
case Ast_Undef: return node->Undef; case Ast_Uninit: return node->Uninit;
case Ast_BasicLit: return node->BasicLit.token; case Ast_BasicLit: return node->BasicLit.token;
case Ast_BasicDirective: return node->BasicDirective.token; case Ast_BasicDirective: return node->BasicDirective.token;
case Ast_ProcGroup: return node->ProcGroup.token; case Ast_ProcGroup: return node->ProcGroup.token;
@@ -137,7 +137,7 @@ Token ast_end_token(Ast *node) {
return empty_token; return empty_token;
case Ast_Ident: return node->Ident.token; case Ast_Ident: return node->Ident.token;
case Ast_Implicit: return node->Implicit; case Ast_Implicit: return node->Implicit;
case Ast_Undef: return node->Undef; case Ast_Uninit: return node->Uninit;
case Ast_BasicLit: return node->BasicLit.token; case Ast_BasicLit: return node->BasicLit.token;
case Ast_BasicDirective: return node->BasicDirective.token; case Ast_BasicDirective: return node->BasicDirective.token;
case Ast_ProcGroup: return node->ProcGroup.close; case Ast_ProcGroup: return node->ProcGroup.close;
+63
View File
@@ -1,6 +1,10 @@
/* /*
Path handling utilities. Path handling utilities.
*/ */
#if !defined(GB_SYSTEM_WINDOWS)
#include <unistd.h>
#endif
gb_internal String remove_extension_from_path(String const &s) { gb_internal String remove_extension_from_path(String const &s) {
if (s.len != 0 && s.text[s.len-1] == '.') { if (s.len != 0 && s.text[s.len-1] == '.') {
return s; return s;
@@ -25,6 +29,29 @@ gb_internal String remove_directory_from_path(String const &s) {
return substring(s, s.len-len, s.len); return substring(s, s.len-len, s.len);
} }
// NOTE(Mark Naughton): getcwd as String
#if !defined(GB_SYSTEM_WINDOWS)
gb_internal String get_current_directory(void) {
char cwd[256];
getcwd(cwd, 256);
return make_string_c(cwd);
}
#else
gb_internal String get_current_directory(void) {
gbAllocator a = heap_allocator();
wchar_t cwd[256];
GetCurrentDirectoryW(256, cwd);
String16 wstr = make_string16_c(cwd);
return string16_to_string(a, wstr);
}
#endif
gb_internal bool path_is_directory(String path); gb_internal bool path_is_directory(String path);
gb_internal String directory_from_path(String const &s) { gb_internal String directory_from_path(String const &s) {
@@ -392,7 +419,43 @@ gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi)
return ReadDirectory_None; return ReadDirectory_None;
} }
#else #else
#error Implement read_directory #error Implement read_directory
#endif #endif
#if !defined(GB_SYSTEM_WINDOWS)
gb_internal bool write_directory(String path) {
char const *pathname = (char *) path.text;
if (access(pathname, W_OK) < 0) {
return false;
}
return true;
}
#else
gb_internal bool write_directory(String path) {
String16 wstr = string_to_string16(heap_allocator(), path);
LPCWSTR wdirectory_name = wstr.text;
HANDLE directory = CreateFileW(wdirectory_name,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (directory == INVALID_HANDLE_VALUE) {
DWORD error_code = GetLastError();
if (error_code == ERROR_ACCESS_DENIED) {
return false;
}
}
CloseHandle(directory);
return true;
}
#endif
+3 -3
View File
@@ -54,7 +54,7 @@ TOKEN_KIND(Token__AssignOpEnd, ""), \
TOKEN_KIND(Token_Increment, "++"), \ TOKEN_KIND(Token_Increment, "++"), \
TOKEN_KIND(Token_Decrement, "--"), \ TOKEN_KIND(Token_Decrement, "--"), \
TOKEN_KIND(Token_ArrowRight,"->"), \ TOKEN_KIND(Token_ArrowRight,"->"), \
TOKEN_KIND(Token_Undef, "---"), \ TOKEN_KIND(Token_Uninit, "---"), \
\ \
TOKEN_KIND(Token__ComparisonBegin, ""), \ TOKEN_KIND(Token__ComparisonBegin, ""), \
TOKEN_KIND(Token_CmpEq, "=="), \ TOKEN_KIND(Token_CmpEq, "=="), \
@@ -917,7 +917,7 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
token->kind = Token_Decrement; token->kind = Token_Decrement;
if (t->curr_rune == '-') { if (t->curr_rune == '-') {
advance_to_next_rune(t); advance_to_next_rune(t);
token->kind = Token_Undef; token->kind = Token_Uninit;
} }
break; break;
case '>': case '>':
@@ -1078,7 +1078,7 @@ semicolon_check:;
case Token_Imag: case Token_Imag:
case Token_Rune: case Token_Rune:
case Token_String: case Token_String:
case Token_Undef: case Token_Uninit:
/*fallthrough*/ /*fallthrough*/
case Token_Question: case Token_Question:
case Token_Pointer: case Token_Pointer:
+19 -12
View File
@@ -83,7 +83,7 @@ enum BasicKind {
Basic_UntypedString, Basic_UntypedString,
Basic_UntypedRune, Basic_UntypedRune,
Basic_UntypedNil, Basic_UntypedNil,
Basic_UntypedUndef, Basic_UntypedUninit,
Basic_COUNT, Basic_COUNT,
@@ -515,7 +515,7 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}}, {Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}}, {Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}}, {Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
{Type_Basic, {Basic_UntypedUndef, BasicFlag_Untyped, 0, STR_LIT("untyped undefined")}}, {Type_Basic, {Basic_UntypedUninit, BasicFlag_Untyped, 0, STR_LIT("untyped uninitialized")}},
}; };
// gb_global Type basic_type_aliases[] = { // gb_global Type basic_type_aliases[] = {
@@ -589,7 +589,7 @@ gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil]; gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
gb_global Type *t_untyped_undef = &basic_types[Basic_UntypedUndef]; gb_global Type *t_untyped_uninit = &basic_types[Basic_UntypedUninit];
@@ -1866,14 +1866,15 @@ gb_internal bool is_type_typeid(Type *t) {
} }
gb_internal bool is_type_untyped_nil(Type *t) { gb_internal bool is_type_untyped_nil(Type *t) {
t = base_type(t); t = base_type(t);
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedNil); // NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
return (t->kind == Type_Basic && (t->Basic.kind == Basic_UntypedNil || t->Basic.kind == Basic_UntypedUninit));
} }
gb_internal bool is_type_untyped_undef(Type *t) { gb_internal bool is_type_untyped_uninit(Type *t) {
t = base_type(t); t = base_type(t);
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUndef); // NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUninit);
} }
gb_internal bool is_type_empty_union(Type *t) { gb_internal bool is_type_empty_union(Type *t) {
t = base_type(t); t = base_type(t);
return t->kind == Type_Union && t->Union.variants.count == 0; return t->kind == Type_Union && t->Union.variants.count == 0;
@@ -2206,10 +2207,6 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
} }
gb_internal gb_inline bool type_has_undef(Type *t) {
return true;
}
gb_internal bool type_has_nil(Type *t) { gb_internal bool type_has_nil(Type *t) {
t = base_type(t); t = base_type(t);
switch (t->kind) { switch (t->kind) {
@@ -2769,13 +2766,23 @@ gb_internal Type *default_type(Type *type) {
return type; return type;
} }
gb_internal bool union_variant_index_types_equal(Type *v, Type *vt) {
if (are_types_identical(v, vt)) {
return true;
}
if (is_type_proc(v) && is_type_proc(vt)) {
return are_types_identical(base_type(v), base_type(vt));
}
return false;
}
gb_internal i64 union_variant_index(Type *u, Type *v) { gb_internal i64 union_variant_index(Type *u, Type *v) {
u = base_type(u); u = base_type(u);
GB_ASSERT(u->kind == Type_Union); GB_ASSERT(u->kind == Type_Union);
for_array(i, u->Union.variants) { for_array(i, u->Union.variants) {
Type *vt = u->Union.variants[i]; Type *vt = u->Union.variants[i];
if (are_types_identical(v, vt)) { if (union_variant_index_types_equal(v, vt)) {
if (u->Union.kind == UnionType_no_nil) { if (u->Union.kind == UnionType_no_nil) {
return cast(i64)(i+0); return cast(i64)(i+0);
} else { } else {
@@ -272,7 +272,7 @@ test_x25519 :: proc(t: ^testing.T) {
// Local copy of this so that the base point doesn't need to be exported. // Local copy of this so that the base point doesn't need to be exported.
_BASE_POINT: [32]byte = { _BASE_POINT: [32]byte = {
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
} }
test_vectors := [?]TestECDH { test_vectors := [?]TestECDH {
@@ -32,6 +32,7 @@ main :: proc() {
parse_json(&t) parse_json(&t)
marshal_json(&t) marshal_json(&t)
unmarshal_json(&t) unmarshal_json(&t)
surrogate(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 { if TEST_fail > 0 {
@@ -345,3 +346,16 @@ unmarshal_json :: proc(t: ^testing.T) {
expect(t, p == original_data.products[i], "Producted unmarshaled improperly") expect(t, p == original_data.products[i], "Producted unmarshaled improperly")
} }
} }
@test
surrogate :: proc(t: ^testing.T) {
input := `+ + * 😃 - /`
out, err := json.marshal(input)
expect(t, err == nil, fmt.tprintf("Expected `json.marshal(%q)` to return a nil error, got %v", input, err))
back: string
uerr := json.unmarshal(out, &back)
expect(t, uerr == nil, fmt.tprintf("Expected `json.unmarshal(%q)` to return a nil error, got %v", string(out), uerr))
expect(t, back == input, fmt.tprintf("Expected `json.unmarshal(%q)` to return %q, got %v", string(out), input, uerr))
}
+32 -18
View File
@@ -14,6 +14,7 @@ Example_Test :: struct {
package_name: string, package_name: string,
example_code: []string, example_code: []string,
expected_output: []string, expected_output: []string,
skip_output_check: bool,
} }
g_header: ^doc.Header g_header: ^doc.Header
@@ -145,6 +146,7 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
curr_block_kind := Block_Kind.Other curr_block_kind := Block_Kind.Other
start := 0 start := 0
found_possible_output: bool
example_block: Block // when set the kind should be Example example_block: Block // when set the kind should be Example
output_block: Block // when set the kind should be Output output_block: Block // when set the kind should be Output
// rely on zii that the kinds have not been set // rely on zii that the kinds have not been set
@@ -178,10 +180,16 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
switch { switch {
case strings.has_prefix(line, "Example:"): next_block_kind = .Example case strings.has_prefix(line, "Example:"): next_block_kind = .Example
case strings.has_prefix(line, "Output:"): next_block_kind = .Output case strings.has_prefix(line, "Output:"): next_block_kind = .Output
case strings.has_prefix(line, "Possible Output:"):
next_block_kind = .Output
found_possible_output = true
} }
case .Example: case .Example:
switch { switch {
case strings.has_prefix(line, "Output:"): next_block_kind = .Output case strings.has_prefix(line, "Output:"): next_block_kind = .Output
case strings.has_prefix(line, "Possible Output:"):
next_block_kind = .Output
found_possible_output = true
case ! (text == "" || strings.has_prefix(line, "\t")): next_block_kind = .Other case ! (text == "" || strings.has_prefix(line, "\t")): next_block_kind = .Other
} }
case .Output: case .Output:
@@ -219,8 +227,9 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
{ {
// Output block starts with // Output block starts with
// `Output:` and a number of white spaces, // `Output:` and a number of white spaces,
// `Possible Output:` and a number of white spaces,
lines := &output_block.lines lines := &output_block.lines
for len(lines) > 0 && (strings.trim_space(lines[0]) == "" || strings.has_prefix(lines[0], "Output:")) { for len(lines) > 0 && (strings.trim_space(lines[0]) == "" || strings.has_prefix(lines[0], "Output:") || strings.has_prefix(lines[0], "Possible Output:")) {
lines^ = lines[1:] lines^ = lines[1:]
} }
// Additionally we need to strip all empty lines at the end of output to not include those in the expected output // Additionally we need to strip all empty lines at the end of output to not include those in the expected output
@@ -240,6 +249,7 @@ find_and_add_examples :: proc(docs: string, package_name: string, entity_name: s
package_name = package_name, package_name = package_name,
example_code = example_block.lines, example_code = example_block.lines,
expected_output = output_block.lines, expected_output = output_block.lines,
skip_output_check = found_possible_output,
}) })
} }
} }
@@ -404,25 +414,29 @@ main :: proc() {
continue continue
} }
fmt.sbprintf(&test_runner, "\t%v_%v()\n", test.package_name, code_test_name) // NOTE: packages like 'rand' are random by nature, in these cases we cannot verify against the output string
fmt.sbprintf(&test_runner, "\t_check(%q, `", code_test_name) // in these cases we just mark the output as 'Possible Output' and we simply skip checking against the output
had_line_error: bool if ! test.skip_output_check {
for line in test.expected_output { fmt.sbprintf(&test_runner, "\t%v_%v()\n", test.package_name, code_test_name)
// NOTE: this will escape the multiline string. Even with a backslash it still escapes due to the semantics of ` fmt.sbprintf(&test_runner, "\t_check(%q, `", code_test_name)
// I don't think any examples would really need this specific character so let's just make it forbidden and change had_line_error: bool
// in the future if we really need to for line in test.expected_output {
if strings.contains_rune(line, '`') { // NOTE: this will escape the multiline string. Even with a backslash it still escapes due to the semantics of `
fmt.eprintf("The line %q in the output for \"%s.%s\" contains a ` which is not allowed\n", line, test.package_name, test.entity_name) // I don't think any examples would really need this specific character so let's just make it forbidden and change
g_bad_doc = true // in the future if we really need to
had_line_error = true if strings.contains_rune(line, '`') {
fmt.eprintf("The line %q in the output for \"%s.%s\" contains a ` which is not allowed\n", line, test.package_name, test.entity_name)
g_bad_doc = true
had_line_error = true
}
strings.write_string(&test_runner, line)
strings.write_string(&test_runner, "\n")
} }
strings.write_string(&test_runner, line) if had_line_error {
strings.write_string(&test_runner, "\n") continue
}
strings.write_string(&test_runner, "`)\n")
} }
if had_line_error {
continue
}
strings.write_string(&test_runner, "`)\n")
save_path := fmt.tprintf("verify/test_%v_%v.odin", test.package_name, code_test_name) save_path := fmt.tprintf("verify/test_%v_%v.odin", test.package_name, code_test_name)
test_file_handle, err := os.open(save_path, os.O_WRONLY | os.O_CREATE); if err != 0 { test_file_handle, err := os.open(save_path, os.O_WRONLY | os.O_CREATE); if err != 0 {
+53 -53
View File
@@ -58,38 +58,38 @@ ApplicationPresentationOptionsDisableCursorLocationAssistance :: ApplicationPres
Application :: struct {using _: Object} Application :: struct {using _: Object}
@(objc_type=Application, objc_name="sharedApplication", objc_is_class_method=true) @(objc_type=Application, objc_name="sharedApplication", objc_is_class_method=true)
Application_sharedApplication :: proc() -> ^Application { Application_sharedApplication :: proc "c" () -> ^Application {
return msgSend(^Application, Application, "sharedApplication") return msgSend(^Application, Application, "sharedApplication")
} }
@(objc_type=Application, objc_name="setActivationPolicy") @(objc_type=Application, objc_name="setActivationPolicy")
Application_setActivationPolicy :: proc(self: ^Application, activationPolicy: ActivationPolicy) -> BOOL { Application_setActivationPolicy :: proc "c" (self: ^Application, activationPolicy: ActivationPolicy) -> BOOL {
return msgSend(BOOL, self, "setActivationPolicy:", activationPolicy) return msgSend(BOOL, self, "setActivationPolicy:", activationPolicy)
} }
@(objc_type=Application, objc_name="activateIgnoringOtherApps") @(objc_type=Application, objc_name="activateIgnoringOtherApps")
Application_activateIgnoringOtherApps :: proc(self: ^Application, ignoreOtherApps: BOOL) { Application_activateIgnoringOtherApps :: proc "c" (self: ^Application, ignoreOtherApps: BOOL) {
msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps) msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps)
} }
@(objc_type=Application, objc_name="setMainMenu") @(objc_type=Application, objc_name="setMainMenu")
Application_setMainMenu :: proc(self: ^Application, menu: ^Menu) { Application_setMainMenu :: proc "c" (self: ^Application, menu: ^Menu) {
msgSend(nil, self, "setMainMenu:", menu) msgSend(nil, self, "setMainMenu:", menu)
} }
@(objc_type=Application, objc_name="windows") @(objc_type=Application, objc_name="windows")
Application_windows :: proc(self: ^Application) -> ^Array { Application_windows :: proc "c" (self: ^Application) -> ^Array {
return msgSend(^Array, self, "windows") return msgSend(^Array, self, "windows")
} }
@(objc_type=Application, objc_name="run") @(objc_type=Application, objc_name="run")
Application_run :: proc(self: ^Application) { Application_run :: proc "c" (self: ^Application) {
msgSend(nil, self, "run") msgSend(nil, self, "run")
} }
@(objc_type=Application, objc_name="terminate") @(objc_type=Application, objc_name="terminate")
Application_terminate :: proc(self: ^Application, sender: ^Object) { Application_terminate :: proc "c" (self: ^Application, sender: ^Object) {
msgSend(nil, self, "terminate:", sender) msgSend(nil, self, "terminate:", sender)
} }
@@ -99,81 +99,81 @@ Application_terminate :: proc(self: ^Application, sender: ^Object) {
RunningApplication :: struct {using _: Object} RunningApplication :: struct {using _: Object}
@(objc_type=RunningApplication, objc_name="currentApplication", objc_is_class_method=true) @(objc_type=RunningApplication, objc_name="currentApplication", objc_is_class_method=true)
RunningApplication_currentApplication :: proc() -> ^RunningApplication { RunningApplication_currentApplication :: proc "c" () -> ^RunningApplication {
return msgSend(^RunningApplication, RunningApplication, "currentApplication") return msgSend(^RunningApplication, RunningApplication, "currentApplication")
} }
@(objc_type=RunningApplication, objc_name="localizedName") @(objc_type=RunningApplication, objc_name="localizedName")
RunningApplication_localizedName :: proc(self: ^RunningApplication) -> ^String { RunningApplication_localizedName :: proc "c" (self: ^RunningApplication) -> ^String {
return msgSend(^String, self, "localizedName") return msgSend(^String, self, "localizedName")
} }
ApplicationDelegateTemplate :: struct { ApplicationDelegateTemplate :: struct {
// Launching Applications // Launching Applications
applicationWillFinishLaunching: proc(notification: ^Notification), applicationWillFinishLaunching: proc(notification: ^Notification),
applicationDidFinishLaunching: proc(notification: ^Notification), applicationDidFinishLaunching: proc(notification: ^Notification),
// Managing Active Status // Managing Active Status
applicationWillBecomeActive: proc(notification: ^Notification), applicationWillBecomeActive: proc(notification: ^Notification),
applicationDidBecomeActive: proc(notification: ^Notification), applicationDidBecomeActive: proc(notification: ^Notification),
applicationWillResignActive: proc(notification: ^Notification), applicationWillResignActive: proc(notification: ^Notification),
applicationDidResignActive: proc(notification: ^Notification), applicationDidResignActive: proc(notification: ^Notification),
// Terminating Applications // Terminating Applications
applicationShouldTerminate: proc(sender: ^Application) -> ApplicationTerminateReply, applicationShouldTerminate: proc(sender: ^Application) -> ApplicationTerminateReply,
applicationShouldTerminateAfterLastWindowClosed: proc(sender: ^Application) -> BOOL, applicationShouldTerminateAfterLastWindowClosed: proc(sender: ^Application) -> BOOL,
applicationWillTerminate: proc(notification: ^Notification), applicationWillTerminate: proc(notification: ^Notification),
// Hiding Applications // Hiding Applications
applicationWillHide: proc(notification: ^Notification), applicationWillHide: proc(notification: ^Notification),
applicationDidHide: proc(notification: ^Notification), applicationDidHide: proc(notification: ^Notification),
applicationWillUnhide: proc(notification: ^Notification), applicationWillUnhide: proc(notification: ^Notification),
applicationDidUnhide: proc(notification: ^Notification), applicationDidUnhide: proc(notification: ^Notification),
// Managing Windows // Managing Windows
applicationWillUpdate: proc(notification: ^Notification), applicationWillUpdate: proc(notification: ^Notification),
applicationDidUpdate: proc(notification: ^Notification), applicationDidUpdate: proc(notification: ^Notification),
applicationShouldHandleReopenHasVisibleWindows: proc(sender: ^Application, flag: BOOL) -> BOOL, applicationShouldHandleReopenHasVisibleWindows: proc(sender: ^Application, flag: BOOL) -> BOOL,
// Managing the Dock Menu // Managing the Dock Menu
applicationDockMenu: proc(sender: ^Application) -> ^Menu, applicationDockMenu: proc(sender: ^Application) -> ^Menu,
// Localizing Keyboard Shortcuts // Localizing Keyboard Shortcuts
applicationShouldAutomaticallyLocalizeKeyEquivalents: proc(application: ^Application) -> BOOL, applicationShouldAutomaticallyLocalizeKeyEquivalents: proc(application: ^Application) -> BOOL,
// Displaying Errors // Displaying Errors
applicationWillPresentError: proc(application: ^Application, error: ^Error) -> ^Error, applicationWillPresentError: proc(application: ^Application, error: ^Error) -> ^Error,
// Managing the Screen // Managing the Screen
applicationDidChangeScreenParameters: proc(notification: ^Notification), applicationDidChangeScreenParameters: proc(notification: ^Notification),
// Continuing User Activities // Continuing User Activities
applicationWillContinueUserActivityWithType: proc(application: ^Application, userActivityType: ^String) -> BOOL, applicationWillContinueUserActivityWithType: proc(application: ^Application, userActivityType: ^String) -> BOOL,
applicationContinueUserActivityRestorationHandler: proc(application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL, applicationContinueUserActivityRestorationHandler: proc(application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL,
applicationDidFailToContinueUserActivityWithTypeError: proc(application: ^Application, userActivityType: ^String, error: ^Error), applicationDidFailToContinueUserActivityWithTypeError: proc(application: ^Application, userActivityType: ^String, error: ^Error),
applicationDidUpdateUserActivity: proc(application: ^Application, userActivity: ^UserActivity), applicationDidUpdateUserActivity: proc(application: ^Application, userActivity: ^UserActivity),
// Handling Push Notifications // Handling Push Notifications
applicationDidRegisterForRemoteNotificationsWithDeviceToken: proc(application: ^Application, deviceToken: ^Data), applicationDidRegisterForRemoteNotificationsWithDeviceToken: proc(application: ^Application, deviceToken: ^Data),
applicationDidFailToRegisterForRemoteNotificationsWithError: proc(application: ^Application, error: ^Error), applicationDidFailToRegisterForRemoteNotificationsWithError: proc(application: ^Application, error: ^Error),
applicationDidReceiveRemoteNotification: proc(application: ^Application, userInfo: ^Dictionary), applicationDidReceiveRemoteNotification: proc(application: ^Application, userInfo: ^Dictionary),
// Handling CloudKit Invitations // Handling CloudKit Invitations
// TODO: if/when we have cloud kit bindings implement // TODO: if/when we have cloud kit bindings implement
// applicationUserDidAcceptCloudKitShareWithMetadata: proc(application: ^Application, metadata: ^CKShareMetadata), // applicationUserDidAcceptCloudKitShareWithMetadata: proc(application: ^Application, metadata: ^CKShareMetadata),
// Handling SiriKit Intents // Handling SiriKit Intents
// TODO: if/when we have siri kit bindings implement // TODO: if/when we have siri kit bindings implement
// applicationHandlerForIntent: proc(application: ^Application, intent: ^INIntent) -> id, // applicationHandlerForIntent: proc(application: ^Application, intent: ^INIntent) -> id,
// Opening Files // Opening Files
applicationOpenURLs: proc(application: ^Application, urls: ^Array), applicationOpenURLs: proc(application: ^Application, urls: ^Array),
applicationOpenFile: proc(sender: ^Application, filename: ^String) -> BOOL, applicationOpenFile: proc(sender: ^Application, filename: ^String) -> BOOL,
applicationOpenFileWithoutUI: proc(sender: id, filename: ^String) -> BOOL, applicationOpenFileWithoutUI: proc(sender: id, filename: ^String) -> BOOL,
applicationOpenTempFile: proc(sender: ^Application, filename: ^String) -> BOOL, applicationOpenTempFile: proc(sender: ^Application, filename: ^String) -> BOOL,
applicationOpenFiles: proc(sender: ^Application, filenames: ^Array), applicationOpenFiles: proc(sender: ^Application, filenames: ^Array),
applicationShouldOpenUntitledFile: proc(sender: ^Application) -> BOOL, applicationShouldOpenUntitledFile: proc(sender: ^Application) -> BOOL,
applicationOpenUntitledFile: proc(sender: ^Application) -> BOOL, applicationOpenUntitledFile: proc(sender: ^Application) -> BOOL,
// Printing // Printing
applicationPrintFile: proc(sender: ^Application, filename: ^String) -> BOOL, applicationPrintFile: proc(sender: ^Application, filename: ^String) -> BOOL,
applicationPrintFilesWithSettingsShowPrintPanels: proc(application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply, applicationPrintFilesWithSettingsShowPrintPanels: proc(application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply,
// Restoring Application State // Restoring Application State
applicationSupportsSecureRestorableState: proc(app: ^Application) -> BOOL, applicationSupportsSecureRestorableState: proc(app: ^Application) -> BOOL,
applicationProtectedDataDidBecomeAvailable: proc(notification: ^Notification), applicationProtectedDataDidBecomeAvailable: proc(notification: ^Notification),
applicationProtectedDataWillBecomeUnavailable: proc(notification: ^Notification), applicationProtectedDataWillBecomeUnavailable: proc(notification: ^Notification),
applicationWillEncodeRestorableState: proc(app: ^Application, coder: ^Coder), applicationWillEncodeRestorableState: proc(app: ^Application, coder: ^Coder),
applicationDidDecodeRestorableState: proc(app: ^Application, coder: ^Coder), applicationDidDecodeRestorableState: proc(app: ^Application, coder: ^Coder),
// Handling Changes to the Occlusion State // Handling Changes to the Occlusion State
applicationDidChangeOcclusionState: proc(notification: ^Notification), applicationDidChangeOcclusionState: proc(notification: ^Notification),
// Scripting Your App // Scripting Your App
applicationDelegateHandlesKey: proc(sender: ^Application, key: ^String) -> BOOL, applicationDelegateHandlesKey: proc(sender: ^Application, key: ^String) -> BOOL,
} }
ApplicationDelegate :: struct { using _: Object } ApplicationDelegate :: struct { using _: Object }
@@ -559,6 +559,6 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
} }
@(objc_type=Application, objc_name="setDelegate") @(objc_type=Application, objc_name="setDelegate")
Application_setDelegate :: proc(self: ^Application, delegate: ^ApplicationDelegate) { Application_setDelegate :: proc "c" (self: ^Application, delegate: ^ApplicationDelegate) {
msgSend(nil, self, "setDelegate:", delegate) msgSend(nil, self, "setDelegate:", delegate)
} }
+7 -7
View File
@@ -8,35 +8,35 @@ Array :: struct {
} }
@(objc_type=Array, objc_name="alloc", objc_is_class_method=true) @(objc_type=Array, objc_name="alloc", objc_is_class_method=true)
Array_alloc :: proc() -> ^Array { Array_alloc :: proc "c" () -> ^Array {
return msgSend(^Array, Array, "alloc") return msgSend(^Array, Array, "alloc")
} }
@(objc_type=Array, objc_name="init") @(objc_type=Array, objc_name="init")
Array_init :: proc(self: ^Array) -> ^Array { Array_init :: proc "c" (self: ^Array) -> ^Array {
return msgSend(^Array, self, "init") return msgSend(^Array, self, "init")
} }
@(objc_type=Array, objc_name="initWithObjects") @(objc_type=Array, objc_name="initWithObjects")
Array_initWithObjects :: proc(self: ^Array, objects: [^]^Object, count: UInteger) -> ^Array { Array_initWithObjects :: proc "c" (self: ^Array, objects: [^]^Object, count: UInteger) -> ^Array {
return msgSend(^Array, self, "initWithObjects:count:", objects, count) return msgSend(^Array, self, "initWithObjects:count:", objects, count)
} }
@(objc_type=Array, objc_name="initWithCoder") @(objc_type=Array, objc_name="initWithCoder")
Array_initWithCoder :: proc(self: ^Array, coder: ^Coder) -> ^Array { Array_initWithCoder :: proc "c" (self: ^Array, coder: ^Coder) -> ^Array {
return msgSend(^Array, self, "initWithCoder:", coder) return msgSend(^Array, self, "initWithCoder:", coder)
} }
@(objc_type=Array, objc_name="object") @(objc_type=Array, objc_name="object")
Array_object :: proc(self: ^Array, index: UInteger) -> ^Object { Array_object :: proc "c" (self: ^Array, index: UInteger) -> ^Object {
return msgSend(^Object, self, "objectAtIndex:", index) return msgSend(^Object, self, "objectAtIndex:", index)
} }
@(objc_type=Array, objc_name="objectAs") @(objc_type=Array, objc_name="objectAs")
Array_objectAs :: proc(self: ^Array, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) { Array_objectAs :: proc "c" (self: ^Array, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) {
return (T)(Array_object(self, index)) return (T)(Array_object(self, index))
} }
@(objc_type=Array, objc_name="count") @(objc_type=Array, objc_name="count")
Array_count :: proc(self: ^Array) -> UInteger { Array_count :: proc "c" (self: ^Array) -> UInteger {
return msgSend(UInteger, self, "count") return msgSend(UInteger, self, "count")
} }
+6 -6
View File
@@ -4,30 +4,30 @@ package objc_Foundation
AutoreleasePool :: struct {using _: Object} AutoreleasePool :: struct {using _: Object}
@(objc_type=AutoreleasePool, objc_name="alloc", objc_is_class_method=true) @(objc_type=AutoreleasePool, objc_name="alloc", objc_is_class_method=true)
AutoreleasePool_alloc :: proc() -> ^AutoreleasePool { AutoreleasePool_alloc :: proc "c" () -> ^AutoreleasePool {
return msgSend(^AutoreleasePool, AutoreleasePool, "alloc") return msgSend(^AutoreleasePool, AutoreleasePool, "alloc")
} }
@(objc_type=AutoreleasePool, objc_name="init") @(objc_type=AutoreleasePool, objc_name="init")
AutoreleasePool_init :: proc(self: ^AutoreleasePool) -> ^AutoreleasePool { AutoreleasePool_init :: proc "c" (self: ^AutoreleasePool) -> ^AutoreleasePool {
return msgSend(^AutoreleasePool, self, "init") return msgSend(^AutoreleasePool, self, "init")
} }
@(objc_type=AutoreleasePool, objc_name="drain") @(objc_type=AutoreleasePool, objc_name="drain")
AutoreleasePool_drain :: proc(self: ^AutoreleasePool) { AutoreleasePool_drain :: proc "c" (self: ^AutoreleasePool) {
msgSend(nil, self, "drain") msgSend(nil, self, "drain")
} }
@(objc_type=AutoreleasePool, objc_name="addObject") @(objc_type=AutoreleasePool, objc_name="addObject")
AutoreleasePool_addObject :: proc(self: ^AutoreleasePool, obj: ^Object) { AutoreleasePool_addObject :: proc "c" (self: ^AutoreleasePool, obj: ^Object) {
msgSend(nil, self, "addObject:", obj) msgSend(nil, self, "addObject:", obj)
} }
@(objc_type=AutoreleasePool, objc_name="showPools") @(objc_type=AutoreleasePool, objc_name="showPools")
AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) { AutoreleasePool_showPools :: proc "c" (self: ^AutoreleasePool, obj: ^Object) {
msgSend(nil, self, "showPools") msgSend(nil, self, "showPools")
} }
@(deferred_out=AutoreleasePool_drain) @(deferred_out=AutoreleasePool_drain)
scoped_autoreleasepool :: proc() -> ^AutoreleasePool { scoped_autoreleasepool :: proc "c" () -> ^AutoreleasePool {
return AutoreleasePool.alloc()->init() return AutoreleasePool.alloc()->init()
} }
+37 -37
View File
@@ -4,188 +4,188 @@ package objc_Foundation
Bundle :: struct { using _: Object } Bundle :: struct { using _: Object }
@(objc_type=Bundle, objc_name="mainBundle", objc_is_class_method=true) @(objc_type=Bundle, objc_name="mainBundle", objc_is_class_method=true)
Bundle_mainBundle :: proc() -> ^Bundle { Bundle_mainBundle :: proc "c" () -> ^Bundle {
return msgSend(^Bundle, Bundle, "mainBundle") return msgSend(^Bundle, Bundle, "mainBundle")
} }
@(objc_type=Bundle, objc_name="bundleWithPath", objc_is_class_method=true) @(objc_type=Bundle, objc_name="bundleWithPath", objc_is_class_method=true)
Bundle_bundleWithPath :: proc(path: ^String) -> ^Bundle { Bundle_bundleWithPath :: proc "c" (path: ^String) -> ^Bundle {
return msgSend(^Bundle, Bundle, "bundleWithPath:", path) return msgSend(^Bundle, Bundle, "bundleWithPath:", path)
} }
@(objc_type=Bundle, objc_name="bundleWithURL", objc_is_class_method=true) @(objc_type=Bundle, objc_name="bundleWithURL", objc_is_class_method=true)
Bundle_bundleWithURL :: proc(url: ^URL) -> ^Bundle { Bundle_bundleWithURL :: proc "c" (url: ^URL) -> ^Bundle {
return msgSend(^Bundle, Bundle, "bundleWithUrl:", url) return msgSend(^Bundle, Bundle, "bundleWithUrl:", url)
} }
@(objc_type=Bundle, objc_name="alloc", objc_is_class_method=true) @(objc_type=Bundle, objc_name="alloc", objc_is_class_method=true)
Bundle_alloc :: proc() -> ^Bundle { Bundle_alloc :: proc "c" () -> ^Bundle {
return msgSend(^Bundle, Bundle, "alloc") return msgSend(^Bundle, Bundle, "alloc")
} }
@(objc_type=Bundle, objc_name="init") @(objc_type=Bundle, objc_name="init")
Bundle_init :: proc(self: ^Bundle) -> ^Bundle { Bundle_init :: proc "c" (self: ^Bundle) -> ^Bundle {
return msgSend(^Bundle, self, "init") return msgSend(^Bundle, self, "init")
} }
@(objc_type=Bundle, objc_name="initWithPath") @(objc_type=Bundle, objc_name="initWithPath")
Bundle_initWithPath :: proc(self: ^Bundle, path: ^String) -> ^Bundle { Bundle_initWithPath :: proc "c" (self: ^Bundle, path: ^String) -> ^Bundle {
return msgSend(^Bundle, self, "initWithPath:", path) return msgSend(^Bundle, self, "initWithPath:", path)
} }
@(objc_type=Bundle, objc_name="initWithURL") @(objc_type=Bundle, objc_name="initWithURL")
Bundle_initWithURL :: proc(self: ^Bundle, url: ^URL) -> ^Bundle { Bundle_initWithURL :: proc "c" (self: ^Bundle, url: ^URL) -> ^Bundle {
return msgSend(^Bundle, self, "initWithUrl:", url) return msgSend(^Bundle, self, "initWithUrl:", url)
} }
@(objc_type=Bundle, objc_name="allBundles") @(objc_type=Bundle, objc_name="allBundles")
Bundle_allBundles :: proc() -> (all: ^Array) { Bundle_allBundles :: proc "c" () -> (all: ^Array) {
return msgSend(type_of(all), Bundle, "allBundles") return msgSend(type_of(all), Bundle, "allBundles")
} }
@(objc_type=Bundle, objc_name="allFrameworks") @(objc_type=Bundle, objc_name="allFrameworks")
Bundle_allFrameworks :: proc() -> (all: ^Array) { Bundle_allFrameworks :: proc "c" () -> (all: ^Array) {
return msgSend(type_of(all), Bundle, "allFrameworks") return msgSend(type_of(all), Bundle, "allFrameworks")
} }
@(objc_type=Bundle, objc_name="load") @(objc_type=Bundle, objc_name="load")
Bundle_load :: proc(self: ^Bundle) -> BOOL { Bundle_load :: proc "c" (self: ^Bundle) -> BOOL {
return msgSend(BOOL, self, "load") return msgSend(BOOL, self, "load")
} }
@(objc_type=Bundle, objc_name="unload") @(objc_type=Bundle, objc_name="unload")
Bundle_unload :: proc(self: ^Bundle) -> BOOL { Bundle_unload :: proc "c" (self: ^Bundle) -> BOOL {
return msgSend(BOOL, self, "unload") return msgSend(BOOL, self, "unload")
} }
@(objc_type=Bundle, objc_name="isLoaded") @(objc_type=Bundle, objc_name="isLoaded")
Bundle_isLoaded :: proc(self: ^Bundle) -> BOOL { Bundle_isLoaded :: proc "c" (self: ^Bundle) -> BOOL {
return msgSend(BOOL, self, "isLoaded") return msgSend(BOOL, self, "isLoaded")
} }
@(objc_type=Bundle, objc_name="preflightAndReturnError") @(objc_type=Bundle, objc_name="preflightAndReturnError")
Bundle_preflightAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) { Bundle_preflightAndReturnError :: proc "contextless" (self: ^Bundle) -> (ok: BOOL, error: ^Error) {
ok = msgSend(BOOL, self, "preflightAndReturnError:", &error) ok = msgSend(BOOL, self, "preflightAndReturnError:", &error)
return return
} }
@(objc_type=Bundle, objc_name="loadAndReturnError") @(objc_type=Bundle, objc_name="loadAndReturnError")
Bundle_loadAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) { Bundle_loadAndReturnError :: proc "contextless" (self: ^Bundle) -> (ok: BOOL, error: ^Error) {
ok = msgSend(BOOL, self, "loadAndReturnError:", &error) ok = msgSend(BOOL, self, "loadAndReturnError:", &error)
return return
} }
@(objc_type=Bundle, objc_name="bundleURL") @(objc_type=Bundle, objc_name="bundleURL")
Bundle_bundleURL :: proc(self: ^Bundle) -> ^URL { Bundle_bundleURL :: proc "c" (self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "bundleURL") return msgSend(^URL, self, "bundleURL")
} }
@(objc_type=Bundle, objc_name="resourceURL") @(objc_type=Bundle, objc_name="resourceURL")
Bundle_resourceURL :: proc(self: ^Bundle) -> ^URL { Bundle_resourceURL :: proc "c" (self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "resourceURL") return msgSend(^URL, self, "resourceURL")
} }
@(objc_type=Bundle, objc_name="executableURL") @(objc_type=Bundle, objc_name="executableURL")
Bundle_executableURL :: proc(self: ^Bundle) -> ^URL { Bundle_executableURL :: proc "c" (self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "executableURL") return msgSend(^URL, self, "executableURL")
} }
@(objc_type=Bundle, objc_name="URLForAuxiliaryExecutable") @(objc_type=Bundle, objc_name="URLForAuxiliaryExecutable")
Bundle_URLForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^URL { Bundle_URLForAuxiliaryExecutable :: proc "c" (self: ^Bundle, executableName: ^String) -> ^URL {
return msgSend(^URL, self, "URLForAuxiliaryExecutable:", executableName) return msgSend(^URL, self, "URLForAuxiliaryExecutable:", executableName)
} }
@(objc_type=Bundle, objc_name="privateFrameworksURL") @(objc_type=Bundle, objc_name="privateFrameworksURL")
Bundle_privateFrameworksURL :: proc(self: ^Bundle) -> ^URL { Bundle_privateFrameworksURL :: proc "c" (self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "privateFrameworksURL") return msgSend(^URL, self, "privateFrameworksURL")
} }
@(objc_type=Bundle, objc_name="sharedFrameworksURL") @(objc_type=Bundle, objc_name="sharedFrameworksURL")
Bundle_sharedFrameworksURL :: proc(self: ^Bundle) -> ^URL { Bundle_sharedFrameworksURL :: proc "c" (self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "sharedFrameworksURL") return msgSend(^URL, self, "sharedFrameworksURL")
} }
@(objc_type=Bundle, objc_name="sharedSupportURL") @(objc_type=Bundle, objc_name="sharedSupportURL")
Bundle_sharedSupportURL :: proc(self: ^Bundle) -> ^URL { Bundle_sharedSupportURL :: proc "c" (self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "sharedSupportURL") return msgSend(^URL, self, "sharedSupportURL")
} }
@(objc_type=Bundle, objc_name="builtInPlugInsURL") @(objc_type=Bundle, objc_name="builtInPlugInsURL")
Bundle_builtInPlugInsURL :: proc(self: ^Bundle) -> ^URL { Bundle_builtInPlugInsURL :: proc "c" (self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "builtInPlugInsURL") return msgSend(^URL, self, "builtInPlugInsURL")
} }
@(objc_type=Bundle, objc_name="appStoreReceiptURL") @(objc_type=Bundle, objc_name="appStoreReceiptURL")
Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL { Bundle_appStoreReceiptURL :: proc "c" (self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "appStoreReceiptURL") return msgSend(^URL, self, "appStoreReceiptURL")
} }
@(objc_type=Bundle, objc_name="bundlePath") @(objc_type=Bundle, objc_name="bundlePath")
Bundle_bundlePath :: proc(self: ^Bundle) -> ^String { Bundle_bundlePath :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "bundlePath") return msgSend(^String, self, "bundlePath")
} }
@(objc_type=Bundle, objc_name="resourcePath") @(objc_type=Bundle, objc_name="resourcePath")
Bundle_resourcePath :: proc(self: ^Bundle) -> ^String { Bundle_resourcePath :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "resourcePath") return msgSend(^String, self, "resourcePath")
} }
@(objc_type=Bundle, objc_name="executablePath") @(objc_type=Bundle, objc_name="executablePath")
Bundle_executablePath :: proc(self: ^Bundle) -> ^String { Bundle_executablePath :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "executablePath") return msgSend(^String, self, "executablePath")
} }
@(objc_type=Bundle, objc_name="PathForAuxiliaryExecutable") @(objc_type=Bundle, objc_name="PathForAuxiliaryExecutable")
Bundle_PathForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^String { Bundle_PathForAuxiliaryExecutable :: proc "c" (self: ^Bundle, executableName: ^String) -> ^String {
return msgSend(^String, self, "PathForAuxiliaryExecutable:", executableName) return msgSend(^String, self, "PathForAuxiliaryExecutable:", executableName)
} }
@(objc_type=Bundle, objc_name="privateFrameworksPath") @(objc_type=Bundle, objc_name="privateFrameworksPath")
Bundle_privateFrameworksPath :: proc(self: ^Bundle) -> ^String { Bundle_privateFrameworksPath :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "privateFrameworksPath") return msgSend(^String, self, "privateFrameworksPath")
} }
@(objc_type=Bundle, objc_name="sharedFrameworksPath") @(objc_type=Bundle, objc_name="sharedFrameworksPath")
Bundle_sharedFrameworksPath :: proc(self: ^Bundle) -> ^String { Bundle_sharedFrameworksPath :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "sharedFrameworksPath") return msgSend(^String, self, "sharedFrameworksPath")
} }
@(objc_type=Bundle, objc_name="sharedSupportPath") @(objc_type=Bundle, objc_name="sharedSupportPath")
Bundle_sharedSupportPath :: proc(self: ^Bundle) -> ^String { Bundle_sharedSupportPath :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "sharedSupportPath") return msgSend(^String, self, "sharedSupportPath")
} }
@(objc_type=Bundle, objc_name="builtInPlugInsPath") @(objc_type=Bundle, objc_name="builtInPlugInsPath")
Bundle_builtInPlugInsPath :: proc(self: ^Bundle) -> ^String { Bundle_builtInPlugInsPath :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "builtInPlugInsPath") return msgSend(^String, self, "builtInPlugInsPath")
} }
@(objc_type=Bundle, objc_name="appStoreReceiptPath") @(objc_type=Bundle, objc_name="appStoreReceiptPath")
Bundle_appStoreReceiptPath :: proc(self: ^Bundle) -> ^String { Bundle_appStoreReceiptPath :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "appStoreReceiptPath") return msgSend(^String, self, "appStoreReceiptPath")
} }
@(objc_type=Bundle, objc_name="bundleIdentifier") @(objc_type=Bundle, objc_name="bundleIdentifier")
Bundle_bundleIdentifier :: proc(self: ^Bundle) -> ^String { Bundle_bundleIdentifier :: proc "c" (self: ^Bundle) -> ^String {
return msgSend(^String, self, "bundleIdentifier") return msgSend(^String, self, "bundleIdentifier")
} }
@(objc_type=Bundle, objc_name="infoDictionary") @(objc_type=Bundle, objc_name="infoDictionary")
Bundle_infoDictionary :: proc(self: ^Bundle) -> ^Dictionary { Bundle_infoDictionary :: proc "c" (self: ^Bundle) -> ^Dictionary {
return msgSend(^Dictionary, self, "infoDictionary") return msgSend(^Dictionary, self, "infoDictionary")
} }
@(objc_type=Bundle, objc_name="localizedInfoDictionary") @(objc_type=Bundle, objc_name="localizedInfoDictionary")
Bundle_localizedInfoDictionary :: proc(self: ^Bundle) -> ^Dictionary { Bundle_localizedInfoDictionary :: proc "c" (self: ^Bundle) -> ^Dictionary {
return msgSend(^Dictionary, self, "localizedInfoDictionary") return msgSend(^Dictionary, self, "localizedInfoDictionary")
} }
@(objc_type=Bundle, objc_name="objectForInfoDictionaryKey") @(objc_type=Bundle, objc_name="objectForInfoDictionaryKey")
Bundle_objectForInfoDictionaryKey :: proc(self: ^Bundle, key: ^String) -> ^Object { Bundle_objectForInfoDictionaryKey :: proc "c" (self: ^Bundle, key: ^String) -> ^Object {
return msgSend(^Object, self, "objectForInfoDictionaryKey:", key) return msgSend(^Object, self, "objectForInfoDictionaryKey:", key)
} }
@(objc_type=Bundle, objc_name="localizedStringForKey") @(objc_type=Bundle, objc_name="localizedStringForKey")
Bundle_localizedStringForKey :: proc(self: ^Bundle, key: ^String, value: ^String = nil, tableName: ^String = nil) -> ^String { Bundle_localizedStringForKey :: proc "c" (self: ^Bundle, key: ^String, value: ^String = nil, tableName: ^String = nil) -> ^String {
return msgSend(^String, self, "localizedStringForKey:value:table:", key, value, tableName) return msgSend(^String, self, "localizedStringForKey:value:table:", key, value, tableName)
} }

Some files were not shown because too many files have changed in this diff Show More