Merge branch 'odin-lang:master' into attr_error

This commit is contained in:
jon lipstate
2023-05-30 08:23:28 -07:00
committed by GitHub
205 changed files with 19817 additions and 10362 deletions
+12 -12
View File
@@ -104,13 +104,13 @@ jobs:
run: ./odin check examples/all -vet -strict-style -target:linux_arm64 run: ./odin check examples/all -vet -strict-style -target:linux_arm64
timeout-minutes: 10 timeout-minutes: 10
build_windows: build_windows:
runs-on: windows-2019 runs-on: windows-2022
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: build Odin - name: build Odin
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
./build.bat 1 ./build.bat 1
- name: Odin version - name: Odin version
run: ./odin version run: ./odin version
@@ -121,65 +121,65 @@ jobs:
- name: Odin check - name: Odin check
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/demo -vet odin check examples/demo -vet
timeout-minutes: 10 timeout-minutes: 10
- name: Odin run - name: Odin run
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo odin run examples/demo
timeout-minutes: 10 timeout-minutes: 10
- name: Odin run -debug - name: Odin run -debug
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo -debug odin run examples/demo -debug
timeout-minutes: 10 timeout-minutes: 10
- name: Odin check examples/all - name: Odin check examples/all
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/all -strict-style odin check examples/all -strict-style
timeout-minutes: 10 timeout-minutes: 10
- name: Core library tests - name: Core library tests
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\core cd tests\core
call build.bat call build.bat
timeout-minutes: 10 timeout-minutes: 10
- name: Vendor library tests - name: Vendor library tests
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\vendor cd tests\vendor
call build.bat call build.bat
timeout-minutes: 10 timeout-minutes: 10
- name: Odin internals tests - name: Odin internals tests
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\internal cd tests\internal
call build.bat call build.bat
timeout-minutes: 10 timeout-minutes: 10
- name: Odin documentation tests - name: Odin documentation tests
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\documentation cd tests\documentation
call build.bat call build.bat
timeout-minutes: 10 timeout-minutes: 10
- name: core:math/big tests - name: core:math/big tests
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\core\math\big cd tests\core\math\big
call build.bat call build.bat
timeout-minutes: 10 timeout-minutes: 10
- name: Odin check examples/all for Windows 32bits - name: Odin check examples/all for Windows 32bits
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/all -strict-style -target:windows_i386 odin check examples/all -strict-style -target:windows_i386
timeout-minutes: 10 timeout-minutes: 10
+3 -3
View File
@@ -7,18 +7,18 @@ on:
jobs: jobs:
build_windows: build_windows:
runs-on: windows-2019 runs-on: windows-2022
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: build Odin - name: build Odin
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
./build.bat 1 1 ./build.bat 1 1
- name: Odin run - name: Odin run
shell: cmd shell: cmd
run: | run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo odin run examples/demo
- name: Copy artifacts - name: Copy artifacts
run: | run: |
+9 -4
View File
@@ -4,14 +4,12 @@ set -eu
: ${CXX=clang++} : ${CXX=clang++}
: ${CPPFLAGS=} : ${CPPFLAGS=}
: ${CXXFLAGS=} : ${CXXFLAGS=}
: ${INCLUDE_DIRECTORIES=}
: ${LDFLAGS=} : ${LDFLAGS=}
: ${ODIN_VERSION=dev-$(date +"%Y-%m")} : ${ODIN_VERSION=dev-$(date +"%Y-%m")}
: ${GIT_SHA=} : ${GIT_SHA=}
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\"" CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
CXXFLAGS="$CXXFLAGS -std=c++14" CXXFLAGS="$CXXFLAGS -std=c++14"
INCLUDE_DIRECTORIES="$INCLUDE_DIRECTORIES -Isrc/"
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++" LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
if [ -d ".git" ]; then if [ -d ".git" ]; then
@@ -137,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"
@@ -148,7 +153,7 @@ build_odin() {
esac esac
set -x set -x
$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $INCLUDE_DIRECTORIES $EXTRAFLAGS $LDFLAGS -o odin $CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $EXTRAFLAGS $LDFLAGS -o odin
set +x set +x
} }
+5
View File
@@ -38,6 +38,11 @@ buffer_init_string :: proc(b: ^Buffer, s: string) {
} }
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) { buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) {
if b.buf == nil {
b.buf = make([dynamic]byte, len, cap, allocator)
return
}
b.buf.allocator = allocator b.buf.allocator = allocator
reserve(&b.buf, cap) reserve(&b.buf, cap)
resize(&b.buf, len) resize(&b.buf, len)
+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}
+142 -83
View File
@@ -27,27 +27,28 @@ Bit_Array_Iterator :: struct {
word_idx: int, word_idx: int,
bit_idx: uint, bit_idx: uint,
} }
/* /*
In: Wraps a `Bit_Array` into an Iterator
- ba: ^Bit_Array - the array to iterate over
Out: Inputs:
- it: ^Bit_Array_Iterator - the iterator that holds iteration state - ba: Pointer to the Bit_Array
Returns:
- it: Iterator struct
*/ */
make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) { make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
return Bit_Array_Iterator { array = ba } return Bit_Array_Iterator { array = ba }
} }
/* /*
In: Returns the next bit, including its set-state. ok=false once exhausted
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
Out: Inputs:
- set: bool - the state of the bit at `index` - it: The iterator that holds the state.
- index: int - the next bit of the Bit_Array referenced by `it`.
- ok: bool - `true` if the iterator returned a valid index, Returns:
`false` if there were no more bits - set: `true` if the bit at `index` is set.
- index: The next bit of the Bit_Array referenced by `it`.
- ok: `true` if the iterator can continue, `false` if the iterator is done
*/ */
iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) { iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
@@ -64,39 +65,51 @@ iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok:
return set, index, true return set, index, true
} }
/* /*
In: Returns the next Set Bit, for example if `0b1010`, then the iterator will return index={1, 3} over two calls.
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
Out: Inputs:
- index: int - the next set bit of the Bit_Array referenced by `it`. - it: The iterator that holds the state.
- ok: bool - `true` if the iterator returned a valid index,
`false` if there were no more bits set Returns:
- index: The next *set* bit of the Bit_Array referenced by `it`.
- ok: `true` if the iterator can continue, `false` if the iterator is done
*/ */
iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
return iterate_internal_(it, true) return iterate_internal_(it, true)
} }
/* /*
In: Returns the next Unset Bit, for example if `0b1010`, then the iterator will return index={0, 2} over two calls.
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
Out: Inputs:
- index: int - the next unset bit of the Bit_Array referenced by `it`. - it: The iterator that holds the state.
- ok: bool - `true` if the iterator returned a valid index,
`false` if there were no more unset bits Returns:
- index: The next *unset* bit of the Bit_Array referenced by `it`.
- ok: `true` if the iterator can continue, `false` if the iterator is done
*/ */
iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) { iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
return iterate_internal_(it, false) return iterate_internal_(it, false)
} }
/*
Iterates through set/unset bits
*Private*
Inputs:
- it: The iterator that holds the state.
- ITERATE_SET_BITS: `true` for returning only set bits, false for returning only unset bits
Returns:
- index: The next *unset* bit of the Bit_Array referenced by `it`.
- ok: `true` if the iterator can continue, `false` if the iterator is done
*/
@(private="file") @(private="file")
iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) { iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0 word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
when ! ITERATE_SET_BITS { word = ~word } when ! ITERATE_SET_BITS { word = ~word }
// if the word is empty or we have already gone over all the bits in it, // If the word is empty or we have already gone over all the bits in it,
// b.bit_idx is greater than the index of any set bit in the word, // b.bit_idx is greater than the index of any set bit in the word,
// meaning that word >> b.bit_idx == 0. // meaning that word >> b.bit_idx == 0.
for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 { for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
@@ -106,14 +119,14 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
when ! ITERATE_SET_BITS { word = ~word } when ! ITERATE_SET_BITS { word = ~word }
} }
// if we are iterating the set bits, reaching the end of the array means we have no more bits to check // If we are iterating the set bits, reaching the end of the array means we have no more bits to check
when ITERATE_SET_BITS { when ITERATE_SET_BITS {
if it.word_idx >= len(it.array.bits) { if it.word_idx >= len(it.array.bits) {
return 0, false return 0, false
} }
} }
// reaching here means that the word has some set bits // Reaching here means that the word has some set bits
it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx)) it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
@@ -124,24 +137,21 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
} }
return index, index <= it.array.max_index return index, index <= it.array.max_index
} }
/* /*
In: Gets the state of a bit in the bit-array
- ba: ^Bit_Array - a pointer to the Bit Array
- index: The bit index. Can be an enum member.
Out: Inputs:
- res: The bit you're interested in. - ba: Pointer to the Bit_Array
- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias. - index: Which bit in the array
The `ok` return value may be ignored. Returns:
- res: `true` if the bit at `index` is set.
- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
*/ */
get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) { get :: proc(ba: ^Bit_Array, #any_int index: uint) -> (res: bool, ok: bool) #optional_ok {
idx := int(index) - ba.bias idx := int(index) - ba.bias
if ba == nil || int(index) < ba.bias { return false, false } if ba == nil || int(index) < ba.bias { return false, false }
context.allocator = allocator
leg_index := idx >> INDEX_SHIFT leg_index := idx >> INDEX_SHIFT
bit_index := idx & INDEX_MASK bit_index := idx & INDEX_MASK
@@ -157,18 +167,36 @@ get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
return res, true return res, true
} }
/* /*
In: Gets the state of a bit in the bit-array
- ba: ^Bit_Array - a pointer to the Bit Array
- index: The bit index. Can be an enum member.
Out: *Bypasses all Checks*
- ok: Whether or not we managed to set requested bit.
`set` automatically resizes the Bit Array to accommodate the requested index if needed. Inputs:
- ba: Pointer to the Bit_Array
- index: Which bit in the array
Returns:
- `true` if bit is set
*/ */
set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) { unsafe_get :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint) -> bool #no_bounds_check {
return bool((ba.bits[index >> INDEX_SHIFT] >> uint(index & INDEX_MASK)) & 1)
}
/*
Sets the state of a bit in the bit-array
*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
Inputs:
- ba: Pointer to the Bit_Array
- index: Which bit in the array
- set_to: `true` sets the bit on, `false` to turn it off
- allocator: (default is context.allocator)
Returns:
- ok: Whether the set was successful, `false` on allocation failure or bad index
*/
set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator := context.allocator) -> (ok: bool) {
idx := int(index) - ba.bias idx := int(index) - ba.bias
@@ -181,65 +209,97 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
resize_if_needed(ba, leg_index) or_return resize_if_needed(ba, leg_index) or_return
ba.max_index = max(idx, ba.max_index) ba.max_index = max(idx, ba.max_index)
ba.bits[leg_index] |= 1 << uint(bit_index)
if set_to{ ba.bits[leg_index] |= 1 << uint(bit_index) }
else { ba.bits[leg_index] &= ~(1 << uint(bit_index)) }
return true return true
} }
/* /*
In: Sets the state of a bit in the bit-array
- ba: ^Bit_Array - a pointer to the Bit Array
- index: The bit index. Can be an enum member.
Out: *Bypasses all checks*
- ok: Whether or not we managed to unset requested bit.
`unset` automatically resizes the Bit Array to accommodate the requested index if needed. Inputs:
- ba: Pointer to the Bit_Array
- index: Which bit in the array
*/ */
unset :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) { unsafe_set :: proc(ba: ^Bit_Array, bit: int) #no_bounds_check {
ba.bits[bit >> INDEX_SHIFT] |= 1 << uint(bit & INDEX_MASK)
idx := int(index) - ba.bias
if ba == nil || int(index) < ba.bias { return false }
context.allocator = allocator
leg_index := idx >> INDEX_SHIFT
bit_index := idx & INDEX_MASK
resize_if_needed(ba, leg_index) or_return
ba.max_index = max(idx, ba.max_index)
ba.bits[leg_index] &= ~(1 << uint(bit_index))
return true
} }
/* /*
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative). Unsets the state of a bit in the bit-array. (Convienence wrapper for `set`)
*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
Inputs:
- ba: Pointer to the Bit_Array
- index: Which bit in the array
- allocator: (default is context.allocator)
Returns:
- ok: Whether the unset was successful, `false` on allocation failure or bad index
*/ */
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok { unset :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
return set(ba, index, false, allocator)
}
/*
Unsets the state of a bit in the bit-array
*Bypasses all Checks*
Inputs:
- ba: Pointer to the Bit_Array
- index: Which bit in the array
*/
unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check {
b.bits[bit >> INDEX_SHIFT] &= ~(1 << uint(bit & INDEX_MASK))
}
/*
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
*Allocates (`new(Bit_Array) & make(ba.bits)`)*
Inputs:
- max_index: maximum starting index
- min_index: minimum starting index (used as a bias)
- allocator: (default is context.allocator)
Returns:
- ba: Allocates a bit_Array, backing data is set to `max-min / 64` indices, rounded up (eg 65 - 0 allocates for [2]u64).
*/
create :: proc(max_index: int, min_index: int = 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
context.allocator = allocator context.allocator = allocator
size_in_bits := max_index - min_index size_in_bits := max_index - min_index
if size_in_bits < 1 { return {}, false } if size_in_bits < 1 { return {}, false }
legs := size_in_bits >> INDEX_SHIFT legs := size_in_bits >> INDEX_SHIFT
if size_in_bits & INDEX_MASK > 0 {legs+=1}
bits, err := make([dynamic]u64, legs)
ok = err == mem.Allocator_Error.None
res = new(Bit_Array) res = new(Bit_Array)
res.bits = bits
res.bias = min_index res.bias = min_index
res.max_index = max_index res.max_index = max_index
res.free_pointer = true res.free_pointer = true
return res, resize_if_needed(res, legs) return
} }
/* /*
Sets all bits to `false`. Sets all values in the Bit_Array to zero.
Inputs:
- ba: The target Bit_Array
*/ */
clear :: proc(ba: ^Bit_Array) { clear :: proc(ba: ^Bit_Array) {
if ba == nil { return } if ba == nil { return }
mem.zero_slice(ba.bits[:]) mem.zero_slice(ba.bits[:])
} }
/* /*
Releases the memory used by the Bit Array. Deallocates the Bit_Array and its backing storage
Inputs:
- ba: The target Bit_Array
*/ */
destroy :: proc(ba: ^Bit_Array) { destroy :: proc(ba: ^Bit_Array) {
if ba == nil { return } if ba == nil { return }
@@ -248,9 +308,8 @@ destroy :: proc(ba: ^Bit_Array) {
free(ba) free(ba)
} }
} }
/* /*
Resizes the Bit Array. For internal use. Resizes the Bit Array. For internal use. Provisions needed capacity+1
If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`. If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
*/ */
@(private="file") @(private="file")
+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
} }
+73
View File
@@ -0,0 +1,73 @@
package hex
import "core:strings"
encode :: proc(src: []byte, allocator := context.allocator) -> []byte #no_bounds_check {
dst := make([]byte, len(src) * 2, allocator)
for i, j := 0, 0; i < len(src); i += 1 {
v := src[i]
dst[j] = HEXTABLE[v>>4]
dst[j+1] = HEXTABLE[v&0x0f]
j += 2
}
return dst
}
decode :: proc(src: []byte, allocator := context.allocator) -> (dst: []byte, ok: bool) #no_bounds_check {
if len(src) % 2 == 1 {
return
}
dst = make([]byte, len(src) / 2, allocator)
for i, j := 0, 1; j < len(src); j += 2 {
p := src[j-1]
q := src[j]
a := hex_digit(p) or_return
b := hex_digit(q) or_return
dst[i] = (a << 4) | b
i += 1
}
return dst, true
}
// Decodes the given sequence into one byte.
// Should be called with one byte worth of the source, eg: 0x23 -> '#'.
decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
str := str
if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") {
str = str[2:]
}
if len(str) != 2 {
return 0, false
}
upper := hex_digit(str[0]) or_return
lower := hex_digit(str[1]) or_return
return upper << 4 | lower, true
}
@(private)
HEXTABLE := [16]byte {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f',
}
@(private)
hex_digit :: proc(char: byte) -> (u8, bool) {
switch char {
case '0' ..= '9': return char - '0', true
case 'a' ..= 'f': return char - 'a' + 10, true
case 'A' ..= 'F': return char - 'A' + 10, true
case: return 0, false
}
}
+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'
+4 -12
View File
@@ -2647,18 +2647,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
+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
+18 -7
View File
@@ -16,6 +16,7 @@ set_global_seed :: proc(seed: u64) {
init(&global_rand, seed) init(&global_rand, seed)
} }
@(require_results)
create :: proc(seed: u64) -> Rand { create :: proc(seed: u64) -> Rand {
r: Rand r: Rand
init(&r, seed) init(&r, seed)
@@ -60,14 +61,17 @@ _random :: proc(r: ^Rand) -> u32 {
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31)) return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31))
} }
@(require_results)
uint32 :: proc(r: ^Rand = nil) -> u32 { return _random(r) } uint32 :: proc(r: ^Rand = nil) -> u32 { return _random(r) }
@(require_results)
uint64 :: proc(r: ^Rand = nil) -> u64 { uint64 :: proc(r: ^Rand = nil) -> 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
} }
@(require_results)
uint128 :: proc(r: ^Rand = nil) -> u128 { uint128 :: proc(r: ^Rand = nil) -> u128 {
a := u128(_random(r)) a := u128(_random(r))
b := u128(_random(r)) b := u128(_random(r))
@@ -76,10 +80,11 @@ 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) } @(require_results) int31 :: proc(r: ^Rand = nil) -> i32 { return i32(uint32(r) << 1 >> 1) }
int63 :: proc(r: ^Rand = nil) -> i64 { return i64(uint64(r) << 1 >> 1) } @(require_results) int63 :: proc(r: ^Rand = nil) -> i64 { return i64(uint64(r) << 1 >> 1) }
int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1) } @(require_results) int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1) }
@(require_results)
int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 { int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
if n <= 0 { if n <= 0 {
panic("Invalid argument to int31_max") panic("Invalid argument to int31_max")
@@ -95,6 +100,7 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
return v % n return v % n
} }
@(require_results)
int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 { int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
if n <= 0 { if n <= 0 {
panic("Invalid argument to int63_max") panic("Invalid argument to int63_max")
@@ -110,6 +116,7 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
return v % n return v % n
} }
@(require_results)
int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 { int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
if n <= 0 { if n <= 0 {
panic("Invalid argument to int127_max") panic("Invalid argument to int127_max")
@@ -125,6 +132,7 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
return v % n return v % n
} }
@(require_results)
int_max :: proc(n: int, r: ^Rand = nil) -> int { int_max :: proc(n: int, r: ^Rand = nil) -> int {
if n <= 0 { if n <= 0 {
panic("Invalid argument to int_max") panic("Invalid argument to int_max")
@@ -137,13 +145,14 @@ int_max :: proc(n: int, r: ^Rand = nil) -> int {
} }
// Uniform random distribution [0, 1) // Uniform random distribution [0, 1)
float64 :: proc(r: ^Rand = nil) -> f64 { return f64(int63_max(1<<53, r)) / (1 << 53) } @(require_results) float64 :: proc(r: ^Rand = nil) -> f64 { return f64(int63_max(1<<53, r)) / (1 << 53) }
// Uniform random distribution [0, 1) // Uniform random distribution [0, 1)
float32 :: proc(r: ^Rand = nil) -> f32 { return f32(float64(r)) } @(require_results) 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 } @(require_results) float64_range :: proc(lo, hi: f64, r: ^Rand = nil) -> f64 { return (hi-lo)*float64(r) + lo }
float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float32(r) + lo } @(require_results) float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float32(r) + lo }
@(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)
@@ -160,6 +169,7 @@ read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
} }
// perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n) // perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n)
@(require_results)
perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int { perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int {
m := make([]int, n, allocator) m := make([]int, n, allocator)
for i := 0; i < n; i += 1 { for i := 0; i < n; i += 1 {
@@ -184,6 +194,7 @@ shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
} }
// Returns a random element from the given slice // Returns a random element from the given slice
@(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 {
+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
+14 -40
View File
@@ -19,7 +19,7 @@ package net
import "core:strings" import "core:strings"
import "core:strconv" import "core:strconv"
import "core:unicode/utf8" import "core:unicode/utf8"
import "core:mem" import "core:encoding/hex"
split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) { split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host, path: string, queries: map[string]string) {
s := url s := url
@@ -36,9 +36,11 @@ split_url :: proc(url: string, allocator := context.allocator) -> (scheme, host,
s = s[:i] s = s[:i]
if query_str != "" { if query_str != "" {
queries_parts := strings.split(query_str, "&") queries_parts := strings.split(query_str, "&")
defer delete(queries_parts)
queries = make(map[string]string, len(queries_parts), allocator) queries = make(map[string]string, len(queries_parts), allocator)
for q in queries_parts { for q in queries_parts {
parts := strings.split(q, "=") parts := strings.split(q, "=")
defer delete(parts)
switch len(parts) { switch len(parts) {
case 1: queries[parts[0]] = "" // NOTE(tetra): Query not set to anything, was but present. case 1: queries[parts[0]] = "" // NOTE(tetra): Query not set to anything, was but present.
case 2: queries[parts[0]] = parts[1] // NOTE(tetra): Query set to something. case 2: queries[parts[0]] = parts[1] // NOTE(tetra): Query set to something.
@@ -76,13 +78,19 @@ join_url :: proc(scheme, host, path: string, queries: map[string]string, allocat
} }
if len(queries) > 0 do write_string(&b, "?") query_length := len(queries)
if query_length > 0 do write_string(&b, "?")
i := 0
for query_name, query_value in queries { for query_name, query_value in queries {
write_string(&b, query_name) write_string(&b, query_name)
if query_value != "" { if query_value != "" {
write_string(&b, "=") write_string(&b, "=")
write_string(&b, query_value) write_string(&b, query_value)
} }
if i < query_length - 1 {
write_string(&b, "&")
}
i += 1
} }
return to_string(b) return to_string(b)
@@ -119,12 +127,10 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) -
builder_grow(&b, len(encoded_string)) builder_grow(&b, len(encoded_string))
defer if !ok do builder_destroy(&b) defer if !ok do builder_destroy(&b)
stack_buf: [4]u8
pending := mem.buffer_from_slice(stack_buf[:])
s := encoded_string s := encoded_string
for len(s) > 0 { for len(s) > 0 {
i := index_rune(s, '%') i := index_byte(s, '%')
if i == -1 { if i == -1 {
write_string(&b, s) // no '%'s; the string is already decoded write_string(&b, s) // no '%'s; the string is already decoded
break break
@@ -137,47 +143,15 @@ percent_decode :: proc(encoded_string: string, allocator := context.allocator) -
s = s[1:] s = s[1:]
if s[0] == '%' { if s[0] == '%' {
write_rune(&b, '%') write_byte(&b, '%')
s = s[1:] s = s[1:]
continue continue
} }
if len(s) < 2 do return // percent without encoded value if len(s) < 2 do return // percent without encoded value
n: int val := hex.decode_sequence(s[:2]) or_return
n, _ = strconv.parse_int(s[:2], 16) write_byte(&b, val)
switch n {
case 0x20: write_rune(&b, ' ')
case 0x21: write_rune(&b, '!')
case 0x23: write_rune(&b, '#')
case 0x24: write_rune(&b, '$')
case 0x25: write_rune(&b, '%')
case 0x26: write_rune(&b, '&')
case 0x27: write_rune(&b, '\'')
case 0x28: write_rune(&b, '(')
case 0x29: write_rune(&b, ')')
case 0x2A: write_rune(&b, '*')
case 0x2B: write_rune(&b, '+')
case 0x2C: write_rune(&b, ',')
case 0x2F: write_rune(&b, '/')
case 0x3A: write_rune(&b, ':')
case 0x3B: write_rune(&b, ';')
case 0x3D: write_rune(&b, '=')
case 0x3F: write_rune(&b, '?')
case 0x40: write_rune(&b, '@')
case 0x5B: write_rune(&b, '[')
case 0x5D: write_rune(&b, ']')
case:
// utf-8 bytes
// TODO(tetra): Audit this - 4 bytes???
append(&pending, s[0])
append(&pending, s[1])
if len(pending) == 4 {
r, _ := utf8.decode_rune(pending[:])
write_rune(&b, r)
clear(&pending)
}
}
s = s[2:] s = s[2:]
} }
+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)^
+27 -10
View File
@@ -220,6 +220,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
@(private) @(private)
MAX_RW :: 1<<30 MAX_RW :: 1<<30
ERROR_EOF :: 38
@(private) @(private)
pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
@@ -228,11 +229,6 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
buf = buf[:MAX_RW] buf = buf[:MAX_RW]
} }
curr_offset, e := seek(fd, offset, 1)
if e != 0 {
return 0, e
}
defer seek(fd, curr_offset, 0)
o := win32.OVERLAPPED{ o := win32.OVERLAPPED{
OffsetHigh = u32(offset>>32), OffsetHigh = u32(offset>>32),
@@ -243,6 +239,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
h := win32.HANDLE(fd) h := win32.HANDLE(fd)
done: win32.DWORD done: win32.DWORD
e: Errno
if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
e = Errno(win32.GetLastError()) e = Errno(win32.GetLastError())
done = 0 done = 0
@@ -256,11 +253,6 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
buf = buf[:MAX_RW] buf = buf[:MAX_RW]
} }
curr_offset, e := seek(fd, offset, 1)
if e != 0 {
return 0, e
}
defer seek(fd, curr_offset, 0)
o := win32.OVERLAPPED{ o := win32.OVERLAPPED{
OffsetHigh = u32(offset>>32), OffsetHigh = u32(offset>>32),
@@ -269,6 +261,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
h := win32.HANDLE(fd) h := win32.HANDLE(fd)
done: win32.DWORD done: win32.DWORD
e: Errno
if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
e = Errno(win32.GetLastError()) e = Errno(win32.GetLastError())
done = 0 done = 0
@@ -276,6 +269,16 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
return int(done), e return int(done), e
} }
/*
read_at returns n: 0, err: 0 on EOF
on Windows, read_at changes the position of the file cursor, on *nix, it does not.
bytes: [8]u8{}
read_at(fd, bytes, 0)
read(fd, bytes)
will read from the location twice on *nix, and from two different locations on Windows
*/
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
if offset < 0 { if offset < 0 {
return 0, ERROR_NEGATIVE_OFFSET return 0, ERROR_NEGATIVE_OFFSET
@@ -284,6 +287,10 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
b, offset := data, offset b, offset := data, offset
for len(b) > 0 { for len(b) > 0 {
m, e := pread(fd, b, offset) m, e := pread(fd, b, offset)
if e == ERROR_EOF {
err = 0
break
}
if e != 0 { if e != 0 {
err = e err = e
break break
@@ -294,6 +301,16 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
} }
return return
} }
/*
on Windows, write_at changes the position of the file cursor, on *nix, it does not.
bytes: [8]u8{}
write_at(fd, bytes, 0)
write(fd, bytes)
will write to the location twice on *nix, and to two different locations on Windows
*/
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) { write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
if offset < 0 { if offset < 0 {
return 0, ERROR_NEGATIVE_OFFSET return 0, ERROR_NEGATIVE_OFFSET
+1 -1
View File
@@ -194,7 +194,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
ptr := uintptr(aligned_mem) ptr := uintptr(aligned_mem)
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
diff := int(aligned_ptr - ptr) diff := int(aligned_ptr - ptr)
if (size + diff) > space { if (size + diff) > space || allocated_mem == nil {
return nil, .Out_Of_Memory return nil, .Out_Of_Memory
} }
+1 -1
View File
@@ -3,7 +3,7 @@ package os2
import "core:runtime" import "core:runtime"
_get_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
//TODO //TODO
return return
} }
+39 -86
View File
@@ -9,19 +9,20 @@ import "core:sys/unix"
INVALID_HANDLE :: -1 INVALID_HANDLE :: -1
_O_RDONLY :: 0o0 _O_RDONLY :: 0o00000000
_O_WRONLY :: 0o1 _O_WRONLY :: 0o00000001
_O_RDWR :: 0o2 _O_RDWR :: 0o00000002
_O_CREAT :: 0o100 _O_CREAT :: 0o00000100
_O_EXCL :: 0o200 _O_EXCL :: 0o00000200
_O_TRUNC :: 0o1000 _O_NOCTTY :: 0o00000400
_O_APPEND :: 0o2000 _O_TRUNC :: 0o00001000
_O_NONBLOCK :: 0o4000 _O_APPEND :: 0o00002000
_O_LARGEFILE :: 0o100000 _O_NONBLOCK :: 0o00004000
_O_DIRECTORY :: 0o200000 _O_LARGEFILE :: 0o00100000
_O_NOFOLLOW :: 0o400000 _O_DIRECTORY :: 0o00200000
_O_SYNC :: 0o4010000 _O_NOFOLLOW :: 0o00400000
_O_CLOEXEC :: 0o2000000 _O_SYNC :: 0o04010000
_O_CLOEXEC :: 0o02000000
_O_PATH :: 0o10000000 _O_PATH :: 0o10000000
_AT_FDCWD :: -100 _AT_FDCWD :: -100
@@ -40,9 +41,12 @@ _file_allocator :: proc() -> runtime.Allocator {
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) { _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
name_cstr := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
flags_i: int // Just default to using O_NOCTTY because needing to open a controlling
// terminal would be incredibly rare. This has no effect on files while
// allowing us to open serial devices.
flags_i: int = _O_NOCTTY
switch flags & O_RDONLY|O_WRONLY|O_RDWR { switch flags & O_RDONLY|O_WRONLY|O_RDWR {
case O_RDONLY: flags_i = _O_RDONLY case O_RDONLY: flags_i = _O_RDONLY
case O_WRONLY: flags_i = _O_WRONLY case O_WRONLY: flags_i = _O_WRONLY
@@ -56,7 +60,7 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error
flags_i |= (_O_TRUNC * int(.Trunc in flags)) flags_i |= (_O_TRUNC * int(.Trunc in flags))
flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags)) flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags))
fd := unix.sys_open(name_cstr, flags_i, int(perm)) fd := unix.sys_open(name_cstr, flags_i, uint(perm))
if fd < 0 { if fd < 0 {
return nil, _get_platform_error(fd) return nil, _get_platform_error(fd)
} }
@@ -196,10 +200,7 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
} }
_remove :: proc(name: string) -> Error { _remove :: proc(name: string) -> Error {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
fd := unix.sys_open(name_cstr, int(File_Flags.Read)) fd := unix.sys_open(name_cstr, int(File_Flags.Read))
if fd < 0 { if fd < 0 {
@@ -214,40 +215,22 @@ _remove :: proc(name: string) -> Error {
} }
_rename :: proc(old_name, new_name: string) -> Error { _rename :: proc(old_name, new_name: string) -> Error {
old_name_cstr, old_allocated := _name_to_cstring(old_name) old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
new_name_cstr, new_allocated := _name_to_cstring(new_name) new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
defer if old_allocated {
delete(old_name_cstr)
}
defer if new_allocated {
delete(new_name_cstr)
}
return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr)) return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr))
} }
_link :: proc(old_name, new_name: string) -> Error { _link :: proc(old_name, new_name: string) -> Error {
old_name_cstr, old_allocated := _name_to_cstring(old_name) old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
new_name_cstr, new_allocated := _name_to_cstring(new_name) new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
defer if old_allocated {
delete(old_name_cstr)
}
defer if new_allocated {
delete(new_name_cstr)
}
return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr)) return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr))
} }
_symlink :: proc(old_name, new_name: string) -> Error { _symlink :: proc(old_name, new_name: string) -> Error {
old_name_cstr, old_allocated := _name_to_cstring(old_name) old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
new_name_cstr, new_allocated := _name_to_cstring(new_name) new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
defer if old_allocated {
delete(old_name_cstr)
}
defer if new_allocated {
delete(new_name_cstr)
}
return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr)) return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr))
} }
@@ -271,26 +254,17 @@ _read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (st
} }
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) { _read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
return _read_link_cstr(name_cstr, allocator) return _read_link_cstr(name_cstr, allocator)
} }
_unlink :: proc(name: string) -> Error { _unlink :: proc(name: string) -> Error {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
return _ok_or_error(unix.sys_unlink(name_cstr)) return _ok_or_error(unix.sys_unlink(name_cstr))
} }
_chdir :: proc(name: string) -> Error { _chdir :: proc(name: string) -> Error {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
return _ok_or_error(unix.sys_chdir(name_cstr)) return _ok_or_error(unix.sys_chdir(name_cstr))
} }
@@ -299,32 +273,23 @@ _fchdir :: proc(f: ^File) -> Error {
} }
_chmod :: proc(name: string, mode: File_Mode) -> Error { _chmod :: proc(name: string, mode: File_Mode) -> Error {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated { return _ok_or_error(unix.sys_chmod(name_cstr, uint(mode)))
delete(name_cstr)
}
return _ok_or_error(unix.sys_chmod(name_cstr, int(mode)))
} }
_fchmod :: proc(f: ^File, mode: File_Mode) -> Error { _fchmod :: proc(f: ^File, mode: File_Mode) -> Error {
return _ok_or_error(unix.sys_fchmod(f.impl.fd, int(mode))) return _ok_or_error(unix.sys_fchmod(f.impl.fd, uint(mode)))
} }
// NOTE: will throw error without super user priviledges // NOTE: will throw error without super user priviledges
_chown :: proc(name: string, uid, gid: int) -> Error { _chown :: proc(name: string, uid, gid: int) -> Error {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
return _ok_or_error(unix.sys_chown(name_cstr, uid, gid)) return _ok_or_error(unix.sys_chown(name_cstr, uid, gid))
} }
// NOTE: will throw error without super user priviledges // NOTE: will throw error without super user priviledges
_lchown :: proc(name: string, uid, gid: int) -> Error { _lchown :: proc(name: string, uid, gid: int) -> Error {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid)) return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid))
} }
@@ -334,10 +299,7 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
} }
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
times := [2]Unix_File_Time { times := [2]Unix_File_Time {
{ atime._nsec, 0 }, { atime._nsec, 0 },
{ mtime._nsec, 0 }, { mtime._nsec, 0 },
@@ -354,18 +316,12 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
} }
_exists :: proc(name: string) -> bool { _exists :: proc(name: string) -> bool {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
return unix.sys_access(name_cstr, F_OK) == 0 return unix.sys_access(name_cstr, F_OK) == 0
} }
_is_file :: proc(name: string) -> bool { _is_file :: proc(name: string) -> bool {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
s: _Stat s: _Stat
res := unix.sys_stat(name_cstr, &s) res := unix.sys_stat(name_cstr, &s)
if res < 0 { if res < 0 {
@@ -384,10 +340,7 @@ _is_file_fd :: proc(fd: int) -> bool {
} }
_is_dir :: proc(name: string) -> bool { _is_dir :: proc(name: string) -> bool {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
s: _Stat s: _Stat
res := unix.sys_stat(name_cstr, &s) res := unix.sys_stat(name_cstr, &s)
if res < 0 { if res < 0 {
+1 -1
View File
@@ -166,7 +166,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
ptr := uintptr(aligned_mem) ptr := uintptr(aligned_mem)
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
diff := int(aligned_ptr - ptr) diff := int(aligned_ptr - ptr)
if (size + diff) > space { if (size + diff) > space || allocated_mem == nil {
return nil, .Out_Of_Memory return nil, .Out_Of_Memory
} }
+1 -1
View File
@@ -52,7 +52,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
ptr := uintptr(aligned_mem) ptr := uintptr(aligned_mem)
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
diff := int(aligned_ptr - ptr) diff := int(aligned_ptr - ptr)
if (size + diff) > space { if (size + diff) > space || allocated_mem == nil {
return nil, .Out_Of_Memory return nil, .Out_Of_Memory
} }
+5 -17
View File
@@ -31,11 +31,8 @@ _mkdir :: proc(path: string, perm: File_Mode) -> Error {
return .Invalid_Argument return .Invalid_Argument
} }
path_cstr, allocated := _name_to_cstring(path) path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
defer if allocated { return _ok_or_error(unix.sys_mkdir(path_cstr, uint(perm & 0o777)))
delete(path_cstr)
}
return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777)))
} }
_mkdir_all :: proc(path: string, perm: File_Mode) -> Error { _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
@@ -49,7 +46,7 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
new_dfd := unix.sys_openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS) new_dfd := unix.sys_openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS)
switch new_dfd { switch new_dfd {
case -ENOENT: case -ENOENT:
if res := unix.sys_mkdirat(dfd, cstring(&path[0]), perm); res < 0 { if res := unix.sys_mkdirat(dfd, cstring(&path[0]), uint(perm)); res < 0 {
return _get_platform_error(res) return _get_platform_error(res)
} }
has_created^ = true has_created^ = true
@@ -83,9 +80,6 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
} else { } else {
path_bytes = make([]u8, len(path) + 1, context.temp_allocator) path_bytes = make([]u8, len(path) + 1, context.temp_allocator)
} }
defer if allocated {
delete(path_bytes)
}
// NULL terminate the byte slice to make it a valid cstring // NULL terminate the byte slice to make it a valid cstring
copy(path_bytes, path) copy(path_bytes, path)
@@ -182,10 +176,7 @@ _remove_all :: proc(path: string) -> Error {
return nil return nil
} }
path_cstr, allocated := _name_to_cstring(path) path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
defer if allocated {
delete(path_cstr)
}
fd := unix.sys_open(path_cstr, _OPENDIR_FLAGS) fd := unix.sys_open(path_cstr, _OPENDIR_FLAGS)
switch fd { switch fd {
@@ -222,10 +213,7 @@ _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) {
} }
_setwd :: proc(dir: string) -> Error { _setwd :: proc(dir: string) -> Error {
dir_cstr, allocated := _name_to_cstring(dir) dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator)
defer if allocated {
delete(dir_cstr)
}
return _ok_or_error(unix.sys_chdir(dir_cstr)) return _ok_or_error(unix.sys_chdir(dir_cstr))
} }
+5 -12
View File
@@ -3,6 +3,7 @@ package os2
import "core:time" import "core:time"
import "core:runtime" import "core:runtime"
import "core:strings"
import "core:sys/unix" import "core:sys/unix"
import "core:path/filepath" import "core:path/filepath"
@@ -112,10 +113,7 @@ _fstat_internal :: proc(fd: int, allocator: runtime.Allocator) -> (File_Info, Er
// NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath // NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath
_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { _stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
fd := unix.sys_open(name_cstr, _O_RDONLY) fd := unix.sys_open(name_cstr, _O_RDONLY)
if fd < 0 { if fd < 0 {
@@ -126,10 +124,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error)
} }
_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) { _lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW) fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW)
if fd < 0 { if fd < 0 {
return {}, _get_platform_error(fd) return {}, _get_platform_error(fd)
@@ -143,10 +139,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool {
} }
_stat_internal :: proc(name: string) -> (s: _Stat, res: int) { _stat_internal :: proc(name: string) -> (s: _Stat, res: int) {
name_cstr, allocated := _name_to_cstring(name) name_cstr := strings.clone_to_cstring(name, context.temp_allocator)
defer if allocated {
delete(name_cstr)
}
res = unix.sys_stat(name_cstr, &s) res = unix.sys_stat(name_cstr, &s)
return return
} }
+6 -6
View File
@@ -8,12 +8,12 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
case .Windows: case .Windows:
dir = get_env("LocalAppData", allocator) dir = get_env("LocalAppData", allocator)
if dir != "" { if dir != "" {
dir = strings.clone_safe(dir, allocator) or_return dir = strings.clone(dir, allocator) or_return
} }
case .Darwin: case .Darwin:
dir = get_env("HOME", allocator) dir = get_env("HOME", allocator)
if dir != "" { if dir != "" {
dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return dir = strings.concatenate({dir, "/Library/Caches"}, allocator) or_return
} }
case: // All other UNIX systems case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME", allocator) dir = get_env("XDG_CACHE_HOME", allocator)
@@ -22,7 +22,7 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
if dir == "" { if dir == "" {
return return
} }
dir = strings.concatenate_safe({dir, "/.cache"}, allocator) or_return dir = strings.concatenate({dir, "/.cache"}, allocator) or_return
} }
} }
if dir == "" { if dir == "" {
@@ -36,12 +36,12 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
case .Windows: case .Windows:
dir = get_env("AppData", allocator) dir = get_env("AppData", allocator)
if dir != "" { if dir != "" {
dir = strings.clone_safe(dir, allocator) or_return dir = strings.clone(dir, allocator) or_return
} }
case .Darwin: case .Darwin:
dir = get_env("HOME", allocator) dir = get_env("HOME", allocator)
if dir != "" { if dir != "" {
dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return dir = strings.concatenate({dir, "/Library/Application Support"}, allocator) or_return
} }
case: // All other UNIX systems case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME", allocator) dir = get_env("XDG_CACHE_HOME", allocator)
@@ -50,7 +50,7 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
if dir == "" { if dir == "" {
return return
} }
dir = strings.concatenate_safe({dir, "/.config"}, allocator) or_return dir = strings.concatenate({dir, "/.config"}, allocator) or_return
} }
} }
if dir == "" { if dir == "" {
+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
}
+12 -5
View File
@@ -67,16 +67,15 @@ Buffer :: struct {
BUFFER_DEFAULT_SIZE :: 0x10_0000 BUFFER_DEFAULT_SIZE :: 0x10_0000
context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_ok { context_create_with_scale :: proc(filename: string, precise_time: bool, timestamp_scale: f64) -> (ctx: Context, ok: bool) #optional_ok {
fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600) fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600)
if err != os.ERROR_NONE { if err != os.ERROR_NONE {
return return
} }
ctx.fd = fd
freq, freq_ok := time.tsc_frequency() ctx.fd = fd
ctx.precise_time = freq_ok ctx.precise_time = precise_time
ctx.timestamp_scale = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1 ctx.timestamp_scale = timestamp_scale
temp := [size_of(Manual_Header)]u8{} temp := [size_of(Manual_Header)]u8{}
_build_header(temp[:], ctx.timestamp_scale) _build_header(temp[:], ctx.timestamp_scale)
@@ -85,6 +84,14 @@ context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_o
return return
} }
context_create_with_sleep :: proc(filename: string, sleep := 2 * time.Second) -> (ctx: Context, ok: bool) #optional_ok {
freq, freq_ok := time.tsc_frequency(sleep)
timestamp_scale: f64 = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1
return context_create_with_scale(filename, freq_ok, timestamp_scale)
}
context_create :: proc{context_create_with_scale, context_create_with_sleep}
context_destroy :: proc(ctx: ^Context) { context_destroy :: proc(ctx: ^Context) {
if ctx == nil { if ctx == nil {
return return
+80 -77
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 {
@@ -179,17 +179,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 +202,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 +213,19 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
return transmute(T)s, err return transmute(T)s, err
} }
@(builtin) @(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) @(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) @(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) @(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 +236,7 @@ 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) @(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 +244,7 @@ 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) @(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
@@ -287,10 +289,9 @@ reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) ->
Shrinks the capacity of a map down to the current length. Shrinks the capacity of a map down to the current length.
*/ */
@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 +314,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 +335,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 +371,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 +385,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 +402,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) 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 +421,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 +444,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 +467,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 +479,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 +493,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 +507,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
} }
@@ -528,14 +534,14 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
} }
@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 +553,26 @@ 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
} }
@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 +584,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
} }
/* /*
@@ -598,7 +604,7 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
If `len(array) < new_cap`, then `len(array)` will be left unchanged. If `len(array) < new_cap`, then `len(array)` will be left unchanged.
*/ */
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 +624,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
+7 -5
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,26 +139,26 @@ 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) {
context.allocator = allocator context.allocator = allocator
reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc)
return return
} }
@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) {
context.allocator = allocator context.allocator = allocator
resize_soa(&array, length, loc) resize_soa(&array, length, loc)
return return
} }
@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) {
context.allocator = allocator context.allocator = allocator
if reserve_soa(&array, capacity, loc) { if reserve_soa(&array, capacity, loc) {
+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(m))
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
@@ -112,7 +112,7 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
ptr := uintptr(aligned_mem) ptr := uintptr(aligned_mem)
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
diff := int(aligned_ptr - ptr) diff := int(aligned_ptr - ptr)
if (size + diff) > space { if (size + diff) > space || allocated_mem == nil {
return nil, .Out_Of_Memory return nil, .Out_Of_Memory
} }
+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
+3 -3
View File
@@ -41,7 +41,7 @@ Returns:
*/ */
@(deprecated="Prefer clone. It now returns an optional allocator error") @(deprecated="Prefer clone. It now returns an optional allocator error")
clone_safe :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) { clone_safe :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) {
return clone(s, allocator, loc) return clone(s, allocator, loc)
} }
/* /*
Clones a string and appends a null-byte to make it a cstring Clones a string and appends a null-byte to make it a cstring
@@ -629,7 +629,7 @@ Returns:
*/ */
@(deprecated="Prefer join. It now returns an optional allocator error") @(deprecated="Prefer join. It now returns an optional allocator error")
join_safe :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) { join_safe :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
return join(a, sep, allocator) return join(a, sep, allocator)
} }
/* /*
Returns a combined string from the slice of strings `a` without a separator Returns a combined string from the slice of strings `a` without a separator
@@ -689,7 +689,7 @@ The concatenated string, and an error if allocation fails
*/ */
@(deprecated="Prefer concatenate. It now returns an optional allocator error") @(deprecated="Prefer concatenate. It now returns an optional allocator error")
concatenate_safe :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) { concatenate_safe :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
return concatenate(a, allocator) return concatenate(a, allocator)
} }
/* /*
Returns a substring of the input string `s` with the specified rune offset and length Returns a substring of the input string `s` with the specified rune offset and length
+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()
} }
+9 -2
View File
@@ -38,7 +38,7 @@ cpu_name: Maybe(string)
@(init, private) @(init, private)
init_cpu_features :: proc "c" () { init_cpu_features :: proc "c" () {
is_set :: #force_inline proc "c" (hwc: u32, value: u32) -> bool { is_set :: #force_inline proc "c" (hwc: u32, value: u32) -> bool {
return hwc&value != 0 return hwc&(1 << value) != 0
} }
try_set :: #force_inline proc "c" (set: ^CPU_Features, feature: CPU_Feature, hwc: u32, value: u32) { try_set :: #force_inline proc "c" (set: ^CPU_Features, feature: CPU_Feature, hwc: u32, value: u32) {
if is_set(hwc, value) { if is_set(hwc, value) {
@@ -74,8 +74,15 @@ init_cpu_features :: proc "c" () {
return return
} }
// In certain rare cases (reason unknown), XGETBV generates an
// illegal instruction, even if OSXSAVE is set per CPUID.
//
// When Chrome ran into this problem, the problem went away
// after they started checking both OSXSAVE and XSAVE.
//
// See: crbug.com/375968
os_supports_avx := false os_supports_avx := false
if .os_xsave in set { if .os_xsave in set && is_set(26, ecx1) {
eax, _ := xgetbv(0) eax, _ := xgetbv(0)
os_supports_avx = is_set(1, eax) && is_set(2, eax) os_supports_avx = is_set(1, eax) && is_set(2, eax)
} }
+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 -1
View File
@@ -219,7 +219,7 @@ selection_delete :: proc(s: ^State) {
translate_position :: proc(s: ^State, pos: int, t: Translation) -> int { translate_position :: proc(s: ^State, pos: int, t: Translation) -> int {
is_continuation_byte :: proc(b: byte) -> bool { is_continuation_byte :: proc(b: byte) -> bool {
return b <= 0x80 && b < 0xc0 return b >= 0x80 && b < 0xc0
} }
is_space :: proc(b: byte) -> bool { is_space :: proc(b: byte) -> bool {
return b == ' ' || b == '\t' || b == '\n' return b == ' ' || b == '\t' || b == '\n'
+2 -2
View File
@@ -70,7 +70,7 @@ has_invariant_tsc :: proc "contextless" () -> bool {
return false return false
} }
tsc_frequency :: proc "contextless" () -> (u64, bool) { tsc_frequency :: proc "contextless" (fallback_sleep := 2 * Second) -> (u64, bool) {
if !has_invariant_tsc() { if !has_invariant_tsc() {
return 0, false return 0, false
} }
@@ -81,7 +81,7 @@ tsc_frequency :: proc "contextless" () -> (u64, bool) {
tsc_begin := intrinsics.read_cycle_counter() tsc_begin := intrinsics.read_cycle_counter()
tick_begin := tick_now() tick_begin := tick_now()
sleep(2 * Second) sleep(fallback_sleep)
tsc_end := intrinsics.read_cycle_counter() tsc_end := intrinsics.read_cycle_counter()
tick_end := tick_now() tick_end := tick_now()
+6
View File
@@ -170,6 +170,12 @@ day :: proc "contextless" (t: Time) -> (day: int) {
return return
} }
weekday :: proc "contextless" (t: Time) -> (weekday: Weekday) {
abs := _time_abs(t)
sec := (abs + u64(Weekday.Monday) * SECONDS_PER_DAY) % SECONDS_PER_WEEK
return Weekday(int(sec) / SECONDS_PER_DAY)
}
clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch } clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) { clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) {
+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
+28 -6
View File
@@ -262,6 +262,7 @@ struct BuildContext {
String microarch; String microarch;
BuildModeKind build_mode; BuildModeKind build_mode;
bool generate_docs; bool generate_docs;
bool custom_optimization_level;
i32 optimization_level; i32 optimization_level;
bool show_timings; bool show_timings;
TimingsExportFormat export_timings_format; TimingsExportFormat export_timings_format;
@@ -1272,6 +1273,12 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
gb_exit(1); gb_exit(1);
} }
if (bc->ODIN_DEBUG && !bc->custom_optimization_level) {
// NOTE(bill): when building with `-debug` but not specifying an optimization level
// default to `-o:none` to improve the debug symbol generation by default
bc->optimization_level = -1; // -o:none
}
bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2); bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2);
// ENFORCE DYNAMIC MAP CALLS // ENFORCE DYNAMIC MAP CALLS
@@ -1285,9 +1292,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
break; break;
} }
} }
#undef LINK_FLAG_X64
#undef LINK_FLAG_386
} }
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
@@ -1497,13 +1501,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.
@@ -1615,6 +1629,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;
} }
+52 -30
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;
} }
@@ -7887,8 +7905,11 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
rhs.type = right_type; rhs.type = right_type;
rhs.mode = Addressing_Value; rhs.mode = Addressing_Value;
// TODO(bill): better error message if (is_type_boolean(right_type) && is_type_boolean(end_type)) {
if (!check_is_assignable_to(c, &rhs, end_type)) { // NOTE(bill): allow implicit conversion between boolean types
// within 'or_return' to improve the experience using third-party code
} else if (!check_is_assignable_to(c, &rhs, end_type)) {
// TODO(bill): better error message
gbString a = type_to_string(right_type); gbString a = type_to_string(right_type);
gbString b = type_to_string(end_type); gbString b = type_to_string(end_type);
gbString ret_type = type_to_string(result_type); gbString ret_type = type_to_string(result_type);
@@ -9577,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;
@@ -10142,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");
+2 -2
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) {
+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);
+14 -3
View File
@@ -8,8 +8,9 @@ struct ErrorCollector {
BlockingMutex string_mutex; BlockingMutex string_mutex;
RecursiveMutex block_mutex; RecursiveMutex block_mutex;
Array<u8> error_buffer; RecursiveMutex error_buffer_mutex;
Array<String> errors; Array<u8> error_buffer;
Array<String> errors;
}; };
gb_global ErrorCollector global_error_collector; gb_global ErrorCollector global_error_collector;
@@ -119,6 +120,7 @@ gb_internal void begin_error_block(void) {
} }
gb_internal void end_error_block(void) { gb_internal void end_error_block(void) {
mutex_lock(&global_error_collector.error_buffer_mutex);
isize n = global_error_collector.error_buffer.count; isize n = global_error_collector.error_buffer.count;
if (n > 0) { if (n > 0) {
u8 *text = global_error_collector.error_buffer.data; u8 *text = global_error_collector.error_buffer.data;
@@ -150,11 +152,16 @@ gb_internal void end_error_block(void) {
text = gb_alloc_array(permanent_allocator(), u8, n+1); text = gb_alloc_array(permanent_allocator(), u8, n+1);
gb_memmove(text, global_error_collector.error_buffer.data, n); gb_memmove(text, global_error_collector.error_buffer.data, n);
text[n] = 0; text[n] = 0;
mutex_lock(&global_error_collector.error_out_mutex);
String s = {text, n}; String s = {text, n};
array_add(&global_error_collector.errors, s); array_add(&global_error_collector.errors, s);
mutex_unlock(&global_error_collector.error_out_mutex);
global_error_collector.error_buffer.count = 0; global_error_collector.error_buffer.count = 0;
} }
mutex_unlock(&global_error_collector.error_buffer_mutex);
global_error_collector.in_block.store(false); global_error_collector.in_block.store(false);
mutex_unlock(&global_error_collector.block_mutex); mutex_unlock(&global_error_collector.block_mutex);
} }
@@ -172,11 +179,15 @@ gb_internal ERROR_OUT_PROC(default_error_out_va) {
isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va); isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
isize n = len-1; isize n = len-1;
if (global_error_collector.in_block) { if (global_error_collector.in_block) {
mutex_lock(&global_error_collector.error_buffer_mutex);
isize cap = global_error_collector.error_buffer.count + n; isize cap = global_error_collector.error_buffer.count + n;
array_reserve(&global_error_collector.error_buffer, cap); array_reserve(&global_error_collector.error_buffer, cap);
u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count; u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count;
gb_memmove(data, buf, n); gb_memmove(data, buf, n);
global_error_collector.error_buffer.count += n; global_error_collector.error_buffer.count += n;
mutex_unlock(&global_error_collector.error_buffer_mutex);
} else { } else {
mutex_lock(&global_error_collector.error_out_mutex); mutex_lock(&global_error_collector.error_out_mutex);
{ {
+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);
+1 -1
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;
} }
+1 -1
View File
@@ -282,7 +282,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;
} }

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