Merge branch 'odin-lang:master' into master

This commit is contained in:
avanspector
2025-01-06 16:42:29 +04:00
committed by GitHub
92 changed files with 2808 additions and 1206 deletions
+2
View File
@@ -1,6 +1,8 @@
// This is purely for documentation // This is purely for documentation
package builtin package builtin
import "base:runtime"
nil :: nil nil :: nil
false :: 0!=0 false :: 0!=0
true :: 0==0 true :: 0==0
+4 -2
View File
@@ -2,6 +2,8 @@
#+build ignore #+build ignore
package intrinsics package intrinsics
import "base:runtime"
// Package-Related // Package-Related
is_package_imported :: proc(package_name: string) -> bool --- is_package_imported :: proc(package_name: string) -> bool ---
@@ -72,7 +74,7 @@ prefetch_write_instruction :: proc(address: rawptr, #const locality: i32 /* 0..=
prefetch_write_data :: proc(address: rawptr, #const locality: i32 /* 0..=3 */) --- prefetch_write_data :: proc(address: rawptr, #const locality: i32 /* 0..=3 */) ---
// Compiler Hints // Compiler Hints
expect :: proc(val, expected_val: T) -> T --- expect :: proc(val, expected_val: $T) -> T ---
// Linux and Darwin Only // Linux and Darwin Only
syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr --- syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr ---
@@ -219,7 +221,7 @@ 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) --- type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) --- type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) ---
constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
+60 -3
View File
@@ -826,10 +826,12 @@ _resize_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem,
return nil return nil
} }
if should_zero && a.len < length {
num_reused := min(a.cap, length) - a.len
intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], num_reused*size_of_elem)
}
if length <= a.cap { if length <= a.cap {
if should_zero && a.len < length {
intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], (length-a.len)*size_of_elem)
}
a.len = max(length, 0) a.len = max(length, 0)
return nil return nil
} }
@@ -936,6 +938,32 @@ map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location)
return return
} }
/*
Retrieves a pointer to the key and value for a possibly just inserted entry into the map.
If the `key` was not in the map `m`, an entry is inserted with the zero value and `just_inserted` will be `true`.
Otherwise the existing entry is left untouched and pointers to its key and value are returned.
If the map has to grow in order to insert the entry and the allocation fails, `err` is set and returned.
If `err` is `nil`, `key_ptr` and `value_ptr` are valid pointers and will not be `nil`.
WARN: User modification of the key pointed at by `key_ptr` should only be done if the new key is equal to (in hash) the old key.
If that is not the case you will corrupt the map.
*/
@(builtin, require_results)
map_entry :: proc(m: ^$T/map[$K]$V, key: K, loc := #caller_location) -> (key_ptr: ^K, value_ptr: ^V, just_inserted: bool, err: Allocator_Error) {
key := key
zero: V
_key_ptr, _value_ptr: rawptr
_key_ptr, _value_ptr, just_inserted, err = __dynamic_map_entry((^Raw_Map)(m), map_info(T), &key, &zero, loc)
key_ptr = (^K)(_key_ptr)
value_ptr = (^V)(_value_ptr)
return
}
@builtin @builtin
card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int { card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
@@ -964,6 +992,24 @@ assert :: proc(condition: bool, message := #caller_expression(condition), loc :=
} }
} }
// Evaluates the condition and aborts the program iff the condition is
// false. This routine ignores `ODIN_DISABLE_ASSERT`, and will always
// execute.
@builtin
ensure :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
if !condition {
@(cold)
internal :: proc(message: string, loc: Source_Code_Location) {
p := context.assertion_failure_proc
if p == nil {
p = default_assertion_failure_proc
}
p("unsatisfied ensure", message, loc)
}
internal(message, loc)
}
}
@builtin @builtin
panic :: proc(message: string, loc := #caller_location) -> ! { panic :: proc(message: string, loc := #caller_location) -> ! {
p := context.assertion_failure_proc p := context.assertion_failure_proc
@@ -999,6 +1045,17 @@ assert_contextless :: proc "contextless" (condition: bool, message := #caller_ex
} }
} }
@builtin
ensure_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) {
if !condition {
@(cold)
internal :: proc "contextless" (message: string, loc: Source_Code_Location) {
default_assertion_contextless_failure_proc("unsatisfied ensure", message, loc)
}
internal(message, loc)
}
}
@builtin @builtin
panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! { panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! {
default_assertion_contextless_failure_proc("panic", message, loc) default_assertion_contextless_failure_proc("panic", message, loc)
+34 -11
View File
@@ -158,21 +158,21 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T
} else when (N & (N - 1)) == 0 && N <= 8*size_of(uintptr) { } else when (N & (N - 1)) == 0 && N <= 8*size_of(uintptr) {
// Likely case, N is a power of two because T is a power of two. // Likely case, N is a power of two because T is a power of two.
// Unique case, no need to index data here since only one element.
when N == 1 {
return &cells[index].data[0]
}
// Compute the integer log 2 of N, this is the shift amount to index the // Compute the integer log 2 of N, this is the shift amount to index the
// correct cell. Odin's intrinsics.count_leading_zeros does not produce a // correct cell. Odin's intrinsics.count_leading_zeros does not produce a
// constant, hence this approach. We only need to check up to N = 64. // constant, hence this approach. We only need to check up to N = 64.
SHIFT :: 1 when N < 2 else SHIFT :: 1 when N == 2 else
2 when N < 4 else 2 when N == 4 else
3 when N < 8 else 3 when N == 8 else
4 when N < 16 else 4 when N == 16 else
5 when N < 32 else 6 5 when N == 32 else 6
#assert(SHIFT <= MAP_CACHE_LINE_LOG2) #assert(SHIFT <= MAP_CACHE_LINE_LOG2)
// Unique case, no need to index data here since only one element. return &cells[index >> SHIFT].data[index & (N - 1)]
when N == 1 {
return &cells[index >> SHIFT].data[0]
} else {
return &cells[index >> SHIFT].data[index & (N - 1)]
}
} else { } else {
// Least likely (and worst case), we pay for a division operation but we // Least likely (and worst case), we pay for a division operation but we
// assume the compiler does not actually generate a division. N will be in the // assume the compiler does not actually generate a division. N will be in the
@@ -941,6 +941,29 @@ __dynamic_map_set_extra :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
return nil, rawptr(result) return nil, rawptr(result)
} }
__dynamic_map_entry :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key: rawptr, zero: rawptr, loc := #caller_location) -> (key_ptr: rawptr, value_ptr: rawptr, just_inserted: bool, err: Allocator_Error) {
hash := info.key_hasher(key, map_seed(m^))
if key_ptr, value_ptr = __dynamic_map_get_key_and_value(m, info, hash, key); value_ptr != nil {
return
}
has_grown: bool
if err, has_grown = __dynamic_map_check_grow(m, info, loc); err != nil {
return
} else if has_grown {
hash = info.key_hasher(key, map_seed(m^))
}
value_ptr = rawptr(map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(zero)))
assert(value_ptr != nil)
key_ptr = rawptr(map_cell_index_dynamic(map_data(m^), info.ks, map_desired_position(m^, hash)))
m.len += 1
just_inserted = true
return
}
// IMPORTANT: USED WITHIN THE COMPILER // IMPORTANT: USED WITHIN THE COMPILER
@(private) @(private)
+2 -2
View File
@@ -110,8 +110,8 @@ Linux)
LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN" LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN"
;; ;;
OpenBSD) OpenBSD)
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" CXXFLAGS="$CXXFLAGS -I/usr/local/include $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS -liconv" LDFLAGS="$LDFLAGS -L/usr/local/lib -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
;; ;;
Haiku) Haiku)
+230 -148
View File
@@ -1,148 +1,230 @@
package encoding_base32 // Base32 encoding/decoding implementation as specified in RFC 4648.
// [[ More; https://www.rfc-editor.org/rfc/rfc4648.html ]]
// @note(zh): Encoding utility for Base32 package encoding_base32
// A secondary param can be used to supply a custom alphabet to
// @link(encode) and a matching decoding table to @link(decode). // @note(zh): Encoding utility for Base32
// If none is supplied it just uses the standard Base32 alphabet. // A secondary param can be used to supply a custom alphabet to
// Incase your specific version does not use padding, you may // @link(encode) and a matching decoding table to @link(decode).
// truncate it from the encoded output. // If none is supplied it just uses the standard Base32 alphabet.
// In case your specific version does not use padding, you may
ENC_TABLE := [32]byte { // truncate it from the encoded output.
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // Error represents errors that can occur during base32 decoding operations.
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // As per RFC 4648:
'Y', 'Z', '2', '3', '4', '5', '6', '7', // - Section 3.3: Invalid character handling
} // - Section 3.2: Padding requirements
// - Section 6: Base32 encoding specifics (including block size requirements)
PADDING :: '=' Error :: enum {
None,
DEC_TABLE := [?]u8 { Invalid_Character, // Input contains characters outside the specified alphabet
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Invalid_Length, // Input length is not valid for base32 (must be a multiple of 8 with proper padding)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Malformed_Input, // Input has improper structure (wrong padding position or incomplete groups)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }
0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, Validate_Proc :: #type proc(c: byte) -> bool
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, @private
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, _validate_default :: proc(c: byte) -> bool {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7')
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @(rodata)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ENC_TABLE := [32]byte {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
} 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { 'Y', 'Z', '2', '3', '4', '5', '6', '7',
out_length := (len(data) + 4) / 5 * 8 }
out := make([]byte, out_length)
_encode(out, data) PADDING :: '='
return string(out)
} @(rodata)
DEC_TABLE := [256]u8 {
@private 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
_encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
out := out 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
data := data 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
for len(data) > 0 { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
carry: byte 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
switch len(data) { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
case: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
out[7] = ENC_TABLE[data[4] & 0x1f] 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
carry = data[4] >> 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
fallthrough 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
case 4: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
out[6] = ENC_TABLE[carry | (data[3] << 3) & 0x1f] 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
out[5] = ENC_TABLE[(data[3] >> 2) & 0x1f] 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
carry = data[3] >> 7 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
fallthrough }
case 3:
out[4] = ENC_TABLE[carry | (data[2] << 1) & 0x1f] encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string {
carry = (data[2] >> 4) & 0x1f out_length := (len(data) + 4) / 5 * 8
fallthrough out := make([]byte, out_length, allocator)
case 2: _encode(out, data, ENC_TBL)
out[3] = ENC_TABLE[carry | (data[1] << 4) & 0x1f] return string(out[:])
out[2] = ENC_TABLE[(data[1] >> 1) & 0x1f] }
carry = (data[1] >> 6) & 0x1f
fallthrough @private
case 1: _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) {
out[1] = ENC_TABLE[carry | (data[0] << 2) & 0x1f] out := out
out[0] = ENC_TABLE[data[0] >> 3] data := data
}
for len(data) > 0 {
if len(data) < 5 { carry: byte
out[7] = byte(PADDING) switch len(data) {
if len(data) < 4 { case:
out[6] = byte(PADDING) out[7] = ENC_TBL[data[4] & 0x1f]
out[5] = byte(PADDING) carry = data[4] >> 5
if len(data) < 3 { fallthrough
out[4] = byte(PADDING) case 4:
if len(data) < 2 { out[6] = ENC_TBL[carry | (data[3] << 3) & 0x1f]
out[3] = byte(PADDING) out[5] = ENC_TBL[(data[3] >> 2) & 0x1f]
out[2] = byte(PADDING) carry = data[3] >> 7
} fallthrough
} case 3:
} out[4] = ENC_TBL[carry | (data[2] << 1) & 0x1f]
break carry = (data[2] >> 4) & 0x1f
} fallthrough
data = data[5:] case 2:
out = out[8:] out[3] = ENC_TBL[carry | (data[1] << 4) & 0x1f]
} out[2] = ENC_TBL[(data[1] >> 1) & 0x1f]
} carry = (data[1] >> 6) & 0x1f
fallthrough
decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{ case 1:
if len(data) == 0 { out[1] = ENC_TBL[carry | (data[0] << 2) & 0x1f]
return nil out[0] = ENC_TBL[data[0] >> 3]
} }
outi := 0 if len(data) < 5 {
data := data out[7] = byte(PADDING)
if len(data) < 4 {
out := make([]byte, len(data) / 8 * 5, allocator) out[6] = byte(PADDING)
end := false out[5] = byte(PADDING)
for len(data) > 0 && !end { if len(data) < 3 {
dbuf : [8]byte out[4] = byte(PADDING)
dlen := 8 if len(data) < 2 {
out[3] = byte(PADDING)
for j := 0; j < 8; { out[2] = byte(PADDING)
if len(data) == 0 { }
dlen, end = j, true }
break }
} break
input := data[0] }
data = data[1:] data = data[5:]
if input == byte(PADDING) && j >= 2 && len(data) < 8 { out = out[8:]
assert(!(len(data) + j < 8 - 1), "Corrupted input") }
for k := 0; k < 8-1-j; k +=1 { }
assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input")
} @(optimization_mode="favor_size")
dlen, end = j, true decode :: proc(
assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input") data: string,
break DEC_TBL := DEC_TABLE,
} validate: Validate_Proc = _validate_default,
dbuf[j] = DEC_TABLE[input] allocator := context.allocator) -> (out: []byte, err: Error) {
assert(dbuf[j] != 0xff, "Corrupted input") if len(data) == 0 {
j += 1 return nil, .None
} }
switch dlen { // Check minimum length requirement first
case 8: if len(data) < 2 {
out[outi + 4] = dbuf[6] << 5 | dbuf[7] return nil, .Invalid_Length
fallthrough }
case 7:
out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3 // Validate characters using provided validation function
fallthrough for i := 0; i < len(data); i += 1 {
case 5: c := data[i]
out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1 if c == byte(PADDING) {
fallthrough break
case 4: }
out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4 if !validate(c) {
fallthrough return nil, .Invalid_Character
case 2: }
out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2 }
}
outi += 5 // Validate padding and length
} data_len := len(data)
return out padding_count := 0
} for i := data_len - 1; i >= 0; i -= 1 {
if data[i] != byte(PADDING) {
break
}
padding_count += 1
}
// Check for proper padding and length combinations
if padding_count > 0 {
// Verify no padding in the middle
for i := 0; i < data_len - padding_count; i += 1 {
if data[i] == byte(PADDING) {
return nil, .Malformed_Input
}
}
content_len := data_len - padding_count
mod8 := content_len % 8
required_padding: int
switch mod8 {
case 2: required_padding = 6 // 2 chars need 6 padding chars
case 4: required_padding = 4 // 4 chars need 4 padding chars
case 5: required_padding = 3 // 5 chars need 3 padding chars
case 7: required_padding = 1 // 7 chars need 1 padding char
case: required_padding = 0
}
if required_padding > 0 {
if padding_count != required_padding {
return nil, .Malformed_Input
}
} else if mod8 != 0 {
return nil, .Malformed_Input
}
} else {
// No padding - must be multiple of 8
if data_len % 8 != 0 {
return nil, .Malformed_Input
}
}
// Calculate decoded length: 5 bytes for every 8 input chars
input_chars := data_len - padding_count
out_len := input_chars * 5 / 8
out = make([]byte, out_len, allocator)
defer if err != .None {
delete(out)
}
// Process input in 8-byte blocks
outi := 0
for i := 0; i < input_chars; i += 8 {
buf: [8]byte
block_size := min(8, input_chars - i)
// Decode block
for j := 0; j < block_size; j += 1 {
buf[j] = DEC_TBL[data[i + j]]
}
// Convert to output bytes based on block size
bytes_to_write := block_size * 5 / 8
switch block_size {
case 8:
out[outi + 4] = (buf[6] << 5) | buf[7]
fallthrough
case 7:
out[outi + 3] = (buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3)
fallthrough
case 5:
out[outi + 2] = (buf[3] << 4) | (buf[4] >> 1)
fallthrough
case 4:
out[outi + 1] = (buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4)
fallthrough
case 2:
out[outi] = (buf[0] << 3) | (buf[1] >> 2)
}
outi += bytes_to_write
}
return
}
+227
View File
@@ -0,0 +1,227 @@
package encoding_base32
import "core:testing"
import "core:bytes"
@(test)
test_base32_decode_valid :: proc(t: ^testing.T) {
// RFC 4648 Section 10 - Test vectors
cases := [?]struct {
input, expected: string,
}{
{"", ""},
{"MY======", "f"},
{"MZXQ====", "fo"},
{"MZXW6===", "foo"},
{"MZXW6YQ=", "foob"},
{"MZXW6YTB", "fooba"},
{"MZXW6YTBOI======", "foobar"},
}
for c in cases {
output, err := decode(c.input)
if output != nil {
defer delete(output)
}
testing.expect_value(t, err, Error.None)
expected := transmute([]u8)c.expected
if output != nil {
testing.expect(t, bytes.equal(output, expected))
} else {
testing.expect(t, len(c.expected) == 0)
}
}
}
@(test)
test_base32_encode :: proc(t: ^testing.T) {
// RFC 4648 Section 10 - Test vectors
cases := [?]struct {
input, expected: string,
}{
{"", ""},
{"f", "MY======"},
{"fo", "MZXQ===="},
{"foo", "MZXW6==="},
{"foob", "MZXW6YQ="},
{"fooba", "MZXW6YTB"},
{"foobar", "MZXW6YTBOI======"},
}
for c in cases {
output := encode(transmute([]byte)c.input)
defer delete(output)
testing.expect(t, output == c.expected)
}
}
@(test)
test_base32_decode_invalid :: proc(t: ^testing.T) {
// Section 3.3 - Non-alphabet characters
{
// Characters outside alphabet
input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7)
output, err := decode(input)
if output != nil {
defer delete(output)
}
testing.expect_value(t, err, Error.Invalid_Character)
}
{
// Lowercase not allowed
input := "mzxq===="
output, err := decode(input)
if output != nil {
defer delete(output)
}
testing.expect_value(t, err, Error.Invalid_Character)
}
// Section 3.2 - Padding requirements
{
// Padding must only be at end
input := "MZ=Q===="
output, err := decode(input)
if output != nil {
defer delete(output)
}
testing.expect_value(t, err, Error.Malformed_Input)
}
{
// Missing padding
input := "MZXQ" // Should be MZXQ====
output, err := decode(input)
if output != nil {
defer delete(output)
}
testing.expect_value(t, err, Error.Malformed_Input)
}
{
// Incorrect padding length
input := "MZXQ=" // Needs 4 padding chars
output, err := decode(input)
if output != nil {
defer delete(output)
}
testing.expect_value(t, err, Error.Malformed_Input)
}
{
// Too much padding
input := "MY=========" // Extra padding chars
output, err := decode(input)
if output != nil {
defer delete(output)
}
testing.expect_value(t, err, Error.Malformed_Input)
}
// Section 6 - Base32 block size requirements
{
// Single character (invalid block)
input := "M"
output, err := decode(input)
if output != nil {
defer delete(output)
}
testing.expect_value(t, err, Error.Invalid_Length)
}
}
@(test)
test_base32_roundtrip :: proc(t: ^testing.T) {
cases := [?]string{
"",
"f",
"fo",
"foo",
"foob",
"fooba",
"foobar",
}
for input in cases {
encoded := encode(transmute([]byte)input)
defer delete(encoded)
decoded, err := decode(encoded)
if decoded != nil {
defer delete(decoded)
}
testing.expect_value(t, err, Error.None)
testing.expect(t, bytes.equal(decoded, transmute([]byte)input))
}
}
@(test)
test_base32_custom_alphabet :: proc(t: ^testing.T) {
custom_enc_table := [32]byte{
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
}
custom_dec_table: [256]u8
for i := 0; i < len(custom_enc_table); i += 1 {
custom_dec_table[custom_enc_table[i]] = u8(i)
}
/*
custom_dec_table := [256]u8{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10-0x1f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2f
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 0x30-0x3f ('0'-'9')
0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f ('A'-'O')
25, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x5f ('P'-'V')
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x7f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0-0xaf
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0-0xbf
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0-0xcf
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0-0xdf
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0-0xef
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0-0xff
}
*/
custom_validate :: proc(c: byte) -> bool {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'V') || c == byte(PADDING)
}
cases := [?]struct {
input: string,
enc_expected: string,
}{
{"f", "CO======"},
{"fo", "CPNG===="},
{"foo", "CPNMU==="},
}
for c in cases {
// Test encoding
encoded := encode(transmute([]byte)c.input, custom_enc_table)
defer delete(encoded)
testing.expect(t, encoded == c.enc_expected)
// Test decoding
decoded, err := decode(encoded, custom_dec_table, custom_validate)
defer if decoded != nil {
delete(decoded)
}
testing.expect_value(t, err, Error.None)
testing.expect(t, bytes.equal(decoded, transmute([]byte)c.input))
}
// Test invalid character detection
{
input := "WXY=====" // Contains chars not in our alphabet
output, err := decode(input, custom_dec_table, custom_validate)
if output != nil {
delete(output)
}
testing.expect_value(t, err, Error.Invalid_Character)
}
}
+2 -2
View File
@@ -439,7 +439,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
use_field_idx := -1 use_field_idx := -1
for field, field_idx in fields { for field, field_idx in fields {
tag_value := string(reflect.struct_tag_get(field.tag, "json")) tag_value := reflect.struct_tag_get(field.tag, "json")
json_name, _ := json_name_from_tag_value(tag_value) json_name, _ := json_name_from_tag_value(tag_value)
if key == json_name { if key == json_name {
use_field_idx = field_idx use_field_idx = field_idx
@@ -470,7 +470,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
} }
} }
if field.name == key { if field.name == key || (field.tag != "" && reflect.struct_tag_get(field.tag, "json") == key) {
offset = field.offset offset = field.offset
type = field.type type = field.type
found = true found = true
+1 -1
View File
@@ -146,7 +146,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
case s[6:10] == "JFIF", s[6:10] == "Exif": case s[6:10] == "JFIF", s[6:10] == "Exif":
return .JPEG return .JPEG
case s[:3] == "\xff\xd8\xff": case s[:3] == "\xff\xd8\xff":
switch s[4] { switch s[3] {
case 0xdb, 0xee, 0xe1, 0xe0: case 0xdb, 0xee, 0xe1, 0xe0:
return .JPEG return .JPEG
} }
+1 -129
View File
@@ -396,132 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
General helper functions General helper functions
*/ */
compute_buffer_size :: image.compute_buffer_size compute_buffer_size :: image.compute_buffer_size
/*
PNG save helpers
*/
when false {
make_chunk :: proc(c: any, t: Chunk_Type) -> (res: Chunk) {
data: []u8
if v, ok := c.([]u8); ok {
data = v
} else {
data = mem.any_to_bytes(c)
}
res.header.length = u32be(len(data))
res.header.type = t
res.data = data
// CRC the type
crc := hash.crc32(mem.any_to_bytes(res.header.type))
// Extend the CRC with the data
res.crc = u32be(hash.crc32(data, crc))
return
}
write_chunk :: proc(fd: os.Handle, chunk: Chunk) {
c := chunk
// Write length + type
os.write_ptr(fd, &c.header, 8)
// Write data
os.write_ptr(fd, mem.raw_data(c.data), int(c.header.length))
// Write CRC32
os.write_ptr(fd, &c.crc, 4)
}
write_image_as_png :: proc(filename: string, image: Image) -> (err: Error) {
profiler.timed_proc()
using image
using os
flags: int = O_WRONLY|O_CREATE|O_TRUNC
if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) {
return .Invalid_Image_Dimensions
}
mode: int = 0
when ODIN_OS == .Linux || ODIN_OS == .Darwin {
// NOTE(justasd): 644 (owner read, write; group read; others read)
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
}
fd, fderr := open(filename, flags, mode)
if fderr != nil {
return .Cannot_Open_File
}
defer close(fd)
magic := Signature
write_ptr(fd, &magic, 8)
ihdr := IHDR{
width = u32be(width),
height = u32be(height),
bit_depth = depth,
compression_method = 0,
filter_method = 0,
interlace_method = .None,
}
switch channels {
case 1: ihdr.color_type = Color_Type{}
case 2: ihdr.color_type = Color_Type{.Alpha}
case 3: ihdr.color_type = Color_Type{.Color}
case 4: ihdr.color_type = Color_Type{.Color, .Alpha}
case:// Unhandled
return .Unknown_Color_Type
}
h := make_chunk(ihdr, .IHDR)
write_chunk(fd, h)
bytes_needed := width * height * int(channels) + height
filter_bytes := mem.make_dynamic_array_len_cap([dynamic]u8, bytes_needed, bytes_needed, context.allocator)
defer delete(filter_bytes)
i := 0; j := 0
// Add a filter byte 0 per pixel row
for y := 0; y < height; y += 1 {
filter_bytes[j] = 0; j += 1
for x := 0; x < width; x += 1 {
for z := 0; z < channels; z += 1 {
filter_bytes[j+z] = image.pixels[i+z]
}
i += channels; j += channels
}
}
assert(j == bytes_needed)
a: []u8 = filter_bytes[:]
out_buf: ^[dynamic]u8
defer free(out_buf)
ctx := zlib.ZLIB_Context{
in_buf = &a,
out_buf = out_buf,
}
err = zlib.write_zlib_stream_from_memory(&ctx)
b: []u8
if err == nil {
b = ctx.out_buf[:]
} else {
return err
}
idat := make_chunk(b, .IDAT)
write_chunk(fd, idat)
iend := make_chunk([]u8{}, .IEND)
write_chunk(fd, iend)
return nil
}
}
+7 -3
View File
@@ -132,9 +132,13 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^
buf: [2]byte buf: [2]byte
s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil) s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil)
switch len(s) { switch len(s) {
case 0: write_string(w, "00", &n) or_return case 0:
case 1: write_byte(w, '0', &n) or_return write_string(w, "00", &n) or_return
case 2: write_string(w, s, &n) or_return case 1:
write_byte(w, '0', &n) or_return
fallthrough
case 2:
write_string(w, s, &n) or_return
} }
} else { } else {
write_rune(w, r, &n) or_return write_rune(w, r, &n) or_return
+66 -18
View File
@@ -417,6 +417,13 @@ adjugate :: proc{
matrix4x4_adjugate, matrix4x4_adjugate,
} }
cofactor :: proc{
matrix1x1_cofactor,
matrix2x2_cofactor,
matrix3x3_cofactor,
matrix4x4_cofactor,
}
inverse_transpose :: proc{ inverse_transpose :: proc{
matrix1x1_inverse_transpose, matrix1x1_inverse_transpose,
matrix2x2_inverse_transpose, matrix2x2_inverse_transpose,
@@ -479,9 +486,9 @@ matrix3x3_determinant :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) #
} }
@(require_results) @(require_results)
matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) #no_bounds_check { matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) #no_bounds_check {
a := adjugate(m) c := cofactor(m)
for i in 0..<4 { for i in 0..<4 {
det += m[0, i] * a[0, i] det += m[0, i] * c[0, i]
} }
return return
} }
@@ -497,6 +504,47 @@ matrix1x1_adjugate :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) #no_bo
@(require_results) @(require_results)
matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check { matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check {
y[0, 0] = +x[1, 1]
y[0, 1] = -x[0, 1]
y[1, 0] = -x[1, 0]
y[1, 1] = +x[0, 0]
return
}
@(require_results)
matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2])
y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2])
y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1])
y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2])
y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2])
y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1])
return
}
@(require_results)
matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
for i in 0..<4 {
for j in 0..<4 {
sign: T = 1 if (i + j) % 2 == 0 else -1
y[i, j] = sign * matrix_minor(x, j, i)
}
}
return
}
@(require_results)
matrix1x1_cofactor :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) #no_bounds_check {
y = x
return
}
@(require_results)
matrix2x2_cofactor :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check {
y[0, 0] = +x[1, 1] y[0, 0] = +x[1, 1]
y[0, 1] = -x[1, 0] y[0, 1] = -x[1, 0]
y[1, 0] = -x[0, 1] y[1, 0] = -x[0, 1]
@@ -505,7 +553,7 @@ matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bo
} }
@(require_results) @(require_results)
matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { matrix3x3_cofactor :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
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])
y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
@@ -520,7 +568,7 @@ matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bo
@(require_results) @(require_results)
matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { matrix4x4_cofactor :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
sign: T = 1 if (i + j) % 2 == 0 else -1 sign: T = 1 if (i + j) % 2 == 0 else -1
@@ -556,19 +604,19 @@ matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
@(require_results) @(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) c := cofactor(x)
d := determinant(x) d := determinant(x)
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[i, j] / d y[i, j] = c[i, j] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[i, j] * id y[i, j] = c[i, j] * id
} }
} }
} }
@@ -577,22 +625,22 @@ matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y:
@(require_results) @(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) c := cofactor(x)
d: T d: T
for i in 0..<4 { for i in 0..<4 {
d += x[0, i] * a[0, i] d += x[0, i] * c[0, i]
} }
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[i, j] / d y[i, j] = c[i, j] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[i, j] * id y[i, j] = c[i, j] * id
} }
} }
} }
@@ -625,19 +673,19 @@ matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bou
@(require_results) @(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) c := cofactor(x)
d := determinant(x) d := determinant(x)
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[j, i] / d y[i, j] = c[j, i] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[j, i] * id y[i, j] = c[j, i] * id
} }
} }
} }
@@ -646,22 +694,22 @@ matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou
@(require_results) @(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) c := cofactor(x)
d: T d: T
for i in 0..<4 { for i in 0..<4 {
d += x[0, i] * a[0, i] d += x[0, i] * c[0, i]
} }
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[j, i] / d y[i, j] = c[j, i] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[j, i] * id y[i, j] = c[j, i] * id
} }
} }
} }
+66 -18
View File
@@ -1882,6 +1882,13 @@ adjugate :: proc{
adjugate_matrix4x4, adjugate_matrix4x4,
} }
cofactor :: proc{
cofactor_matrix1x1,
cofactor_matrix2x2,
cofactor_matrix3x3,
cofactor_matrix4x4,
}
inverse_transpose :: proc{ inverse_transpose :: proc{
inverse_transpose_matrix1x1, inverse_transpose_matrix1x1,
inverse_transpose_matrix2x2, inverse_transpose_matrix2x2,
@@ -1944,9 +1951,9 @@ determinant_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) {
} }
@(require_results) @(require_results)
determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) { determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
a := adjugate(m) c := cofactor(m)
#no_bounds_check for i in 0..<4 { #no_bounds_check for i in 0..<4 {
det += m[0, i] * a[0, i] det += m[0, i] * c[0, i]
} }
return return
} }
@@ -1962,6 +1969,47 @@ adjugate_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
@(require_results) @(require_results)
adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
y[0, 0] = +x[1, 1]
y[0, 1] = -x[0, 1]
y[1, 0] = -x[1, 0]
y[1, 1] = +x[0, 0]
return
}
@(require_results)
adjugate_matrix3x3 :: 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[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2])
y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2])
y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1])
y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2])
y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2])
y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1])
return
}
@(require_results)
adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
for i in 0..<4 {
for j in 0..<4 {
sign: T = 1 if (i + j) % 2 == 0 else -1
y[i, j] = sign * matrix_minor(x, j, i)
}
}
return
}
@(require_results)
cofactor_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
y = x
return
}
@(require_results)
cofactor_matrix2x2 :: 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]
y[1, 0] = -x[0, 1] y[1, 0] = -x[0, 1]
@@ -1970,7 +2018,7 @@ adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
} }
@(require_results) @(require_results)
adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { cofactor_matrix3x3 :: 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])
y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
@@ -1985,7 +2033,7 @@ adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
@(require_results) @(require_results)
adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { cofactor_matrix4x4 :: 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 {
sign: T = 1 if (i + j) % 2 == 0 else -1 sign: T = 1 if (i + j) % 2 == 0 else -1
@@ -2021,19 +2069,19 @@ inverse_transpose_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
@(require_results) @(require_results)
inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) c := cofactor(x)
d := determinant(x) d := determinant(x)
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[i, j] / d y[i, j] = c[i, j] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[i, j] * id y[i, j] = c[i, j] * id
} }
} }
} }
@@ -2042,22 +2090,22 @@ inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y:
@(require_results) @(require_results)
inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) c := cofactor(x)
d: T d: T
for i in 0..<4 { for i in 0..<4 {
d += x[0, i] * a[0, i] d += x[0, i] * c[0, i]
} }
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[i, j] / d y[i, j] = c[i, j] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[i, j] * id y[i, j] = c[i, j] * id
} }
} }
} }
@@ -2090,19 +2138,19 @@ inverse_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
@(require_results) @(require_results)
inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) c := cofactor(x)
d := determinant(x) d := determinant(x)
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[j, i] / d y[i, j] = c[j, i] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[j, i] * id y[i, j] = c[j, i] * id
} }
} }
} }
@@ -2111,22 +2159,22 @@ inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou
@(require_results) @(require_results)
inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) c := cofactor(x)
d: T d: T
for i in 0..<4 { for i in 0..<4 {
d += x[0, i] * a[0, i] d += x[0, i] * c[0, i]
} }
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[j, i] / d y[i, j] = c[j, i] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[j, i] * id y[i, j] = c[j, i] * id
} }
} }
} }
+66 -18
View File
@@ -1514,6 +1514,13 @@ adjugate :: proc{
adjugate_matrix4x4, adjugate_matrix4x4,
} }
cofactor :: proc{
cofactor_matrix1x1,
cofactor_matrix2x2,
cofactor_matrix3x3,
cofactor_matrix4x4,
}
inverse_transpose :: proc{ inverse_transpose :: proc{
inverse_transpose_matrix1x1, inverse_transpose_matrix1x1,
inverse_transpose_matrix2x2, inverse_transpose_matrix2x2,
@@ -1568,9 +1575,9 @@ determinant_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) {
} }
@(require_results) @(require_results)
determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) { determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
a := adjugate(m) c := cofactor(m)
#no_bounds_check for i in 0..<4 { #no_bounds_check for i in 0..<4 {
det += m[0, i] * a[0, i] det += m[0, i] * c[0, i]
} }
return return
} }
@@ -1586,6 +1593,47 @@ adjugate_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
@(require_results) @(require_results)
adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
y[0, 0] = +x[1, 1]
y[0, 1] = -x[0, 1]
y[1, 0] = -x[1, 0]
y[1, 1] = +x[0, 0]
return
}
@(require_results)
adjugate_matrix3x3 :: 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[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2])
y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2])
y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1])
y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2])
y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2])
y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1])
return
}
@(require_results)
adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
for i in 0..<4 {
for j in 0..<4 {
sign: T = 1 if (i + j) % 2 == 0 else -1
y[i, j] = sign * matrix_minor(x, j, i)
}
}
return
}
@(require_results)
cofactor_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
y = x
return
}
@(require_results)
cofactor_matrix2x2 :: 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]
y[1, 0] = -x[0, 1] y[1, 0] = -x[0, 1]
@@ -1594,7 +1642,7 @@ adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
} }
@(require_results) @(require_results)
adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { cofactor_matrix3x3 :: 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])
y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
@@ -1609,7 +1657,7 @@ adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
@(require_results) @(require_results)
adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { cofactor_matrix4x4 :: 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 {
sign: T = 1 if (i + j) % 2 == 0 else -1 sign: T = 1 if (i + j) % 2 == 0 else -1
@@ -1645,19 +1693,19 @@ inverse_transpose_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
@(require_results) @(require_results)
inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) c := cofactor(x)
d := determinant(x) d := determinant(x)
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[i, j] / d y[i, j] = c[i, j] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[i, j] * id y[i, j] = c[i, j] * id
} }
} }
} }
@@ -1666,22 +1714,22 @@ inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y:
@(require_results) @(require_results)
inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) c := cofactor(x)
d: T d: T
for i in 0..<4 { for i in 0..<4 {
d += x[0, i] * a[0, i] d += x[0, i] * c[0, i]
} }
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[i, j] / d y[i, j] = c[i, j] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[i, j] * id y[i, j] = c[i, j] * id
} }
} }
} }
@@ -1714,19 +1762,19 @@ inverse_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
@(require_results) @(require_results)
inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) c := cofactor(x)
d := determinant(x) d := determinant(x)
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[j, i] / d y[i, j] = c[j, i] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<3 { for i in 0..<3 {
for j in 0..<3 { for j in 0..<3 {
y[i, j] = a[j, i] * id y[i, j] = c[j, i] * id
} }
} }
} }
@@ -1735,22 +1783,22 @@ inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou
@(require_results) @(require_results)
inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
a := adjugate(x) c := cofactor(x)
d: T d: T
for i in 0..<4 { for i in 0..<4 {
d += x[0, i] * a[0, i] d += x[0, i] * c[0, i]
} }
when intrinsics.type_is_integer(T) { when intrinsics.type_is_integer(T) {
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[j, i] / d y[i, j] = c[j, i] / d
} }
} }
} else { } else {
id := 1/d id := 1/d
for i in 0..<4 { for i in 0..<4 {
for j in 0..<4 { for j in 0..<4 {
y[i, j] = a[j, i] * id y[i, j] = c[j, i] * id
} }
} }
} }
-24
View File
@@ -29,30 +29,6 @@ Reset the seed used by the context.random_generator.
Inputs: Inputs:
- seed: The seed value - seed: The seed value
Example:
import "core:math/rand"
import "core:fmt"
set_global_seed_example :: proc() {
rand.set_global_seed(1)
fmt.println(rand.uint64())
}
Possible Output:
10
*/
@(deprecated="Prefer `rand.reset`")
set_global_seed :: proc(seed: u64) {
runtime.random_generator_reset_u64(context.random_generator, seed)
}
/*
Reset the seed used by the context.random_generator.
Inputs:
- seed: The seed value
Example: Example:
import "core:math/rand" import "core:math/rand"
import "core:fmt" import "core:fmt"
-23
View File
@@ -140,14 +140,6 @@ arena_init :: proc(a: ^Arena, data: []byte) {
a.temp_count = 0 a.temp_count = 0
} }
@(deprecated="prefer 'mem.arena_init'")
init_arena :: proc(a: ^Arena, data: []byte) {
a.data = data
a.offset = 0
a.peak_used = 0
a.temp_count = 0
}
/* /*
Allocate memory from an arena. Allocate memory from an arena.
@@ -786,14 +778,6 @@ stack_init :: proc(s: ^Stack, data: []byte) {
s.peak_used = 0 s.peak_used = 0
} }
@(deprecated="prefer 'mem.stack_init'")
init_stack :: proc(s: ^Stack, data: []byte) {
s.data = data
s.prev_offset = 0
s.curr_offset = 0
s.peak_used = 0
}
/* /*
Allocate memory from stack. Allocate memory from stack.
@@ -1162,13 +1146,6 @@ small_stack_init :: proc(s: ^Small_Stack, data: []byte) {
s.peak_used = 0 s.peak_used = 0
} }
@(deprecated="prefer 'small_stack_init'")
init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
s.data = data
s.offset = 0
s.peak_used = 0
}
/* /*
Small stack allocator. Small stack allocator.
+1 -8
View File
@@ -685,11 +685,4 @@ calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, he
} }
} }
return int(padding) return int(padding)
} }
@(require_results, deprecated="prefer 'slice.clone'")
clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) {
new_slice, _ = make(T, len(slice), allocator, loc)
runtime.copy(new_slice, slice)
return new_slice
}
+2 -1
View File
@@ -204,8 +204,9 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
} }
// Zero the first block's memory // Zero the first block's memory
if arena.curr_block != nil { if arena.curr_block != nil {
mem.zero(arena.curr_block.base, int(arena.curr_block.used)) curr_block_used := int(arena.curr_block.used)
arena.curr_block.used = 0 arena.curr_block.used = 0
mem.zero(arena.curr_block.base, curr_block_used)
} }
arena.total_used = 0 arena.total_used = 0
case .Static, .Buffer: case .Static, .Buffer:
+1 -1
View File
@@ -115,7 +115,7 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File,
@(require_results) @(require_results)
new_file :: proc(handle: uintptr, name: string) -> ^File { new_file :: proc(handle: uintptr, name: string) -> ^File {
file, err := _new_file(handle, name) file, err := _new_file(handle, name, file_allocator())
if err != nil { if err != nil {
panic(error_string(err)) panic(error_string(err))
} }
+27 -54
View File
@@ -39,37 +39,23 @@ _stderr := File{
@init @init
_standard_stream_init :: proc() { _standard_stream_init :: proc() {
@static stdin_impl := File_Impl { new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
name = "/proc/self/fd/0", impl.file.impl = impl
fd = 0, impl.fd = linux.Fd(fd)
impl.allocator = runtime.nil_allocator()
impl.name = name
impl.file.stream = {
data = impl,
procedure = _file_stream_proc,
}
impl.file.fstat = _fstat
return &impl.file
} }
@static stdout_impl := File_Impl { @(static) files: [3]File_Impl
name = "/proc/self/fd/1", stdin = new_std(&files[0], 0, "/proc/self/fd/0")
fd = 1, stdout = new_std(&files[1], 1, "/proc/self/fd/1")
} stderr = new_std(&files[2], 2, "/proc/self/fd/2")
@static stderr_impl := File_Impl {
name = "/proc/self/fd/2",
fd = 2,
}
stdin_impl.allocator = file_allocator()
stdout_impl.allocator = file_allocator()
stderr_impl.allocator = file_allocator()
_stdin.impl = &stdin_impl
_stdout.impl = &stdout_impl
_stderr.impl = &stderr_impl
// cannot define these initially because cyclic reference
_stdin.stream.data = &stdin_impl
_stdout.stream.data = &stdout_impl
_stderr.stream.data = &stderr_impl
stdin = &_stdin
stdout = &_stdout
stderr = &_stderr
} }
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
@@ -80,6 +66,9 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
// terminal would be incredibly rare. This has no effect on files while // terminal would be incredibly rare. This has no effect on files while
// allowing us to open serial devices. // allowing us to open serial devices.
sys_flags: linux.Open_Flags = {.NOCTTY, .CLOEXEC} sys_flags: linux.Open_Flags = {.NOCTTY, .CLOEXEC}
when size_of(rawptr) == 4 {
sys_flags += {.LARGEFILE}
}
switch flags & (O_RDONLY|O_WRONLY|O_RDWR) { switch flags & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: case O_RDONLY:
case O_WRONLY: sys_flags += {.WRONLY} case O_WRONLY: sys_flags += {.WRONLY}
@@ -97,18 +86,18 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
return nil, _get_platform_error(errno) return nil, _get_platform_error(errno)
} }
return _new_file(uintptr(fd), name) return _new_file(uintptr(fd), name, file_allocator())
} }
_new_file :: proc(fd: uintptr, _: string = "") -> (f: ^File, err: Error) { _new_file :: proc(fd: uintptr, _: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) {
impl := new(File_Impl, file_allocator()) or_return impl := new(File_Impl, allocator) or_return
defer if err != nil { defer if err != nil {
free(impl, file_allocator()) free(impl, allocator)
} }
impl.file.impl = impl impl.file.impl = impl
impl.fd = linux.Fd(fd) impl.fd = linux.Fd(fd)
impl.allocator = file_allocator() impl.allocator = allocator
impl.name = _get_full_path(impl.fd, file_allocator()) or_return impl.name = _get_full_path(impl.fd, impl.allocator) or_return
impl.file.stream = { impl.file.stream = {
data = impl, data = impl,
procedure = _file_stream_proc, procedure = _file_stream_proc,
@@ -272,28 +261,12 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
} }
_remove :: proc(name: string) -> Error { _remove :: proc(name: string) -> Error {
is_dir_fd :: proc(fd: linux.Fd) -> bool {
s: linux.Stat
if linux.fstat(fd, &s) != .NONE {
return false
}
return linux.S_ISDIR(s.mode)
}
TEMP_ALLOCATOR_GUARD() TEMP_ALLOCATOR_GUARD()
name_cstr := temp_cstring(name) or_return name_cstr := temp_cstring(name) or_return
fd, errno := linux.open(name_cstr, {.NOFOLLOW}) if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS + {.NOFOLLOW}); errno == .NONE {
#partial switch (errno) { linux.close(fd)
case .ELOOP: return _get_platform_error(linux.rmdir(name_cstr))
/* symlink */
case .NONE:
defer linux.close(fd)
if is_dir_fd(fd) {
return _get_platform_error(linux.rmdir(name_cstr))
}
case:
return _get_platform_error(errno)
} }
return _get_platform_error(linux.unlink(name_cstr)) return _get_platform_error(linux.unlink(name_cstr))
+29 -20
View File
@@ -21,23 +21,29 @@ File_Impl :: struct {
name: string, name: string,
cname: cstring, cname: cstring,
fd: posix.FD, fd: posix.FD,
allocator: runtime.Allocator,
} }
@(init) @(init)
init_std_files :: proc() { init_std_files :: proc() {
// NOTE: is this (paths) also the case on non darwin? new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
impl.file.impl = impl
impl.fd = fd
impl.allocator = runtime.nil_allocator()
impl.cname = name
impl.name = string(name)
impl.file.stream = {
data = impl,
procedure = _file_stream_proc,
}
impl.file.fstat = _fstat
return &impl.file
}
stdin = __new_file(posix.STDIN_FILENO) @(static) files: [3]File_Impl
(^File_Impl)(stdin.impl).name = "/dev/stdin" stdin = new_std(&files[0], posix.STDIN_FILENO, "/dev/stdin")
(^File_Impl)(stdin.impl).cname = "/dev/stdin" stdout = new_std(&files[1], posix.STDOUT_FILENO, "/dev/stdout")
stderr = new_std(&files[2], posix.STDERR_FILENO, "/dev/stderr")
stdout = __new_file(posix.STDIN_FILENO)
(^File_Impl)(stdout.impl).name = "/dev/stdout"
(^File_Impl)(stdout.impl).cname = "/dev/stdout"
stderr = __new_file(posix.STDIN_FILENO)
(^File_Impl)(stderr.impl).name = "/dev/stderr"
(^File_Impl)(stderr.impl).cname = "/dev/stderr"
} }
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
@@ -72,10 +78,10 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
return return
} }
return _new_file(uintptr(fd), name) return _new_file(uintptr(fd), name, file_allocator())
} }
_new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { _new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) {
if name == "" { if name == "" {
err = .Invalid_Path err = .Invalid_Path
return return
@@ -84,10 +90,10 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) {
return return
} }
crname := _posix_absolute_path(posix.FD(handle), name, file_allocator()) or_return crname := _posix_absolute_path(posix.FD(handle), name, allocator) or_return
rname := string(crname) rname := string(crname)
f = __new_file(posix.FD(handle)) f = __new_file(posix.FD(handle), allocator)
impl := (^File_Impl)(f.impl) impl := (^File_Impl)(f.impl)
impl.name = rname impl.name = rname
impl.cname = crname impl.cname = crname
@@ -95,10 +101,11 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) {
return f, nil return f, nil
} }
__new_file :: proc(handle: posix.FD) -> ^File { __new_file :: proc(handle: posix.FD, allocator: runtime.Allocator) -> ^File {
impl := new(File_Impl, file_allocator()) impl := new(File_Impl, allocator)
impl.file.impl = impl impl.file.impl = impl
impl.fd = posix.FD(handle) impl.fd = posix.FD(handle)
impl.allocator = allocator
impl.file.stream = { impl.file.stream = {
data = impl, data = impl,
procedure = _file_stream_proc, procedure = _file_stream_proc,
@@ -114,8 +121,10 @@ _close :: proc(f: ^File_Impl) -> (err: Error) {
err = _get_platform_error() err = _get_platform_error()
} }
delete(f.cname, file_allocator()) allocator := f.allocator
free(f, file_allocator())
delete(f.cname, allocator)
free(f, allocator)
return return
} }
+37 -16
View File
@@ -44,17 +44,38 @@ File_Impl :: struct {
@(init) @(init)
init_std_files :: proc() { init_std_files :: proc() {
stdin = new_file(uintptr(win32.GetStdHandle(win32.STD_INPUT_HANDLE)), "<stdin>") new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File {
stdout = new_file(uintptr(win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)), "<stdout>") impl.file.impl = impl
stderr = new_file(uintptr(win32.GetStdHandle(win32.STD_ERROR_HANDLE)), "<stderr>")
}
@(fini)
fini_std_files :: proc() {
_destroy((^File_Impl)(stdin.impl))
_destroy((^File_Impl)(stdout.impl))
_destroy((^File_Impl)(stderr.impl))
}
impl.allocator = runtime.nil_allocator()
impl.fd = win32.GetStdHandle(code)
impl.name = name
impl.wname = nil
handle := _handle(&impl.file)
kind := File_Impl_Kind.File
if m: u32; win32.GetConsoleMode(handle, &m) {
kind = .Console
}
if win32.GetFileType(handle) == win32.FILE_TYPE_PIPE {
kind = .Pipe
}
impl.kind = kind
impl.file.stream = {
data = impl,
procedure = _file_stream_proc,
}
impl.file.fstat = _fstat
return &impl.file
}
@(static) files: [3]File_Impl
stdin = new_std(&files[0], win32.STD_INPUT_HANDLE, "<stdin>")
stdout = new_std(&files[1], win32.STD_OUTPUT_HANDLE, "<stdout>")
stderr = new_std(&files[2], win32.STD_ERROR_HANDLE, "<stderr>")
}
_handle :: proc(f: ^File) -> win32.HANDLE { _handle :: proc(f: ^File) -> win32.HANDLE {
return win32.HANDLE(_fd(f)) return win32.HANDLE(_fd(f))
@@ -132,21 +153,21 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
flags := flags if flags != nil else {.Read} flags := flags if flags != nil else {.Read}
handle := _open_internal(name, flags, perm) or_return handle := _open_internal(name, flags, perm) or_return
return _new_file(handle, name) return _new_file(handle, name, file_allocator())
} }
_new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { _new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) {
if handle == INVALID_HANDLE { if handle == INVALID_HANDLE {
return return
} }
impl := new(File_Impl, file_allocator()) or_return impl := new(File_Impl, allocator) or_return
defer if err != nil { defer if err != nil {
free(impl, file_allocator()) free(impl, allocator)
} }
impl.file.impl = impl impl.file.impl = impl
impl.allocator = file_allocator() impl.allocator = allocator
impl.fd = rawptr(handle) impl.fd = rawptr(handle)
impl.name = clone_string(name, impl.allocator) or_return impl.name = clone_string(name, impl.allocator) or_return
impl.wname = win32_utf8_to_wstring(name, impl.allocator) or_return impl.wname = win32_utf8_to_wstring(name, impl.allocator) or_return
@@ -180,7 +201,7 @@ _open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Rea
} }
_new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> (f: ^File, err: Error) { _new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> (f: ^File, err: Error) {
f, err = _new_file(handle, name) f, err = _new_file(handle, name, file_allocator())
if f != nil && err == nil { if f != nil && err == nil {
impl := (^File_Impl)(f.impl) impl := (^File_Impl)(f.impl)
impl.r_buf = make([]byte, buffer_size, file_allocator()) impl.r_buf = make([]byte, buffer_size, file_allocator())
+1 -1
View File
@@ -415,7 +415,7 @@ _region_resize :: proc(alloc: ^Allocation_Header, new_size: int, alloc_is_free_l
back_idx := -1 back_idx := -1
idx: u16 idx: u16
infinite: for { infinite: for {
for i := 0; i < len(region_iter.hdr.free_list); i += 1 { for i := 0; i < int(region_iter.hdr.free_list_len); i += 1 {
idx = region_iter.hdr.free_list[i] idx = region_iter.hdr.free_list[i]
if _get_block_count(region_iter.memory[idx]) >= new_block_count { if _get_block_count(region_iter.memory[idx]) >= new_block_count {
break infinite break infinite
-2
View File
@@ -77,8 +77,6 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
} }
_remove_all :: proc(path: string) -> Error { _remove_all :: proc(path: string) -> Error {
DT_DIR :: 4
remove_all_dir :: proc(dfd: linux.Fd) -> Error { remove_all_dir :: proc(dfd: linux.Fd) -> Error {
n := 64 n := 64
buf := make([]u8, n) buf := make([]u8, n)
+2 -2
View File
@@ -10,8 +10,8 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
return nil, nil,_get_platform_error(errno) return nil, nil,_get_platform_error(errno)
} }
r = _new_file(uintptr(fds[0])) or_return r = _new_file(uintptr(fds[0]), "", file_allocator()) or_return
w = _new_file(uintptr(fds[1])) or_return w = _new_file(uintptr(fds[1]), "", file_allocator()) or_return
return return
} }
+2 -2
View File
@@ -21,7 +21,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
return return
} }
r = __new_file(fds[0]) r = __new_file(fds[0], file_allocator())
ri := (^File_Impl)(r.impl) ri := (^File_Impl)(r.impl)
rname := strings.builder_make(file_allocator()) rname := strings.builder_make(file_allocator())
@@ -31,7 +31,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
ri.name = strings.to_string(rname) ri.name = strings.to_string(rname)
ri.cname = strings.to_cstring(&rname) ri.cname = strings.to_cstring(&rname)
w = __new_file(fds[1]) w = __new_file(fds[1], file_allocator())
wi := (^File_Impl)(w.impl) wi := (^File_Impl)(w.impl)
wname := strings.builder_make(file_allocator()) wname := strings.builder_make(file_allocator())
+10 -1
View File
@@ -290,12 +290,21 @@ process_open :: proc(pid: int, flags := Process_Open_Flags {}) -> (Process, Erro
return _process_open(pid, flags) return _process_open(pid, flags)
} }
/*
OS-specific process attributes.
*/
Process_Attributes :: struct {
sys_attr: _Sys_Process_Attributes,
}
/* /*
The description of how a process should be created. The description of how a process should be created.
*/ */
Process_Desc :: struct { Process_Desc :: struct {
// OS-specific attributes. // OS-specific attributes.
sys_attr: _Sys_Process_Attributes, sys_attr: Process_Attributes,
// The working directory of the process. If the string has length 0, the // The working directory of the process. If the string has length 0, the
// working directory is assumed to be the current working directory of the // working directory is assumed to be the current working directory of the
// current process. // current process.
+11 -36
View File
@@ -384,14 +384,6 @@ _Sys_Process_Attributes :: struct {}
@(private="package") @(private="package")
_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
has_executable_permissions :: proc(fd: linux.Fd) -> bool {
backing: [48]u8
b := strings.builder_from_bytes(backing[:])
strings.write_string(&b, "/proc/self/fd/")
strings.write_int(&b, int(fd))
return linux.access(strings.to_cstring(&b), linux.X_OK) == .NONE
}
TEMP_ALLOCATOR_GUARD() TEMP_ALLOCATOR_GUARD()
if len(desc.command) == 0 { if len(desc.command) == 0 {
@@ -411,7 +403,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
} }
// search PATH if just a plain name is provided // search PATH if just a plain name is provided
exe_fd: linux.Fd exe_path: cstring
executable_name := desc.command[0] executable_name := desc.command[0]
if strings.index_byte(executable_name, '/') < 0 { if strings.index_byte(executable_name, '/') < 0 {
path_env := get_env("PATH", temp_allocator()) path_env := get_env("PATH", temp_allocator())
@@ -426,16 +418,11 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
strings.write_byte(&exe_builder, '/') strings.write_byte(&exe_builder, '/')
strings.write_string(&exe_builder, executable_name) strings.write_string(&exe_builder, executable_name)
exe_path := strings.to_cstring(&exe_builder) exe_path = strings.to_cstring(&exe_builder)
if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { if linux.access(exe_path, linux.X_OK) == .NONE {
continue found = true
break
} }
if !has_executable_permissions(exe_fd) {
linux.close(exe_fd)
continue
}
found = true
break
} }
if !found { if !found {
// check in cwd to match windows behavior // check in cwd to match windows behavior
@@ -443,29 +430,18 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
strings.write_string(&exe_builder, "./") strings.write_string(&exe_builder, "./")
strings.write_string(&exe_builder, executable_name) strings.write_string(&exe_builder, executable_name)
exe_path := strings.to_cstring(&exe_builder) exe_path = strings.to_cstring(&exe_builder)
if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { if linux.access(exe_path, linux.X_OK) != .NONE {
return process, .Not_Exist return process, .Not_Exist
} }
if !has_executable_permissions(exe_fd) {
linux.close(exe_fd)
return process, .Permission_Denied
}
} }
} else { } else {
exe_path := temp_cstring(executable_name) or_return exe_path = temp_cstring(executable_name) or_return
if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { if linux.access(exe_path, linux.X_OK) != .NONE {
return process, _get_platform_error(errno) return process, .Not_Exist
}
if !has_executable_permissions(exe_fd) {
linux.close(exe_fd)
return process, .Permission_Denied
} }
} }
// At this point, we have an executable.
defer linux.close(exe_fd)
// args and environment need to be a list of cstrings // args and environment need to be a list of cstrings
// that are terminated by a nil pointer. // that are terminated by a nil pointer.
cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return
@@ -492,7 +468,6 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
} }
defer linux.close(child_pipe_fds[READ]) defer linux.close(child_pipe_fds[READ])
// TODO: This is the traditional textbook implementation with fork. // TODO: This is the traditional textbook implementation with fork.
// A more efficient implementation with vfork: // A more efficient implementation with vfork:
// //
@@ -573,7 +548,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno) write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
} }
errno = linux.execveat(exe_fd, "", &cargs[0], env, {.AT_EMPTY_PATH}) errno = linux.execveat(dir_fd, exe_path, &cargs[0], env)
assert(errno != nil) assert(errno != nil)
write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno) write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
} }
+2
View File
@@ -18,6 +18,8 @@ Example:
defer spall.context_destroy(&spall_ctx) defer spall.context_destroy(&spall_ctx)
buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE) buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE)
defer delete(buffer_backing)
spall_buffer = spall.buffer_create(buffer_backing, u32(sync.current_thread_id())) spall_buffer = spall.buffer_create(buffer_backing, u32(sync.current_thread_id()))
defer spall.buffer_destroy(&spall_ctx, &spall_buffer) defer spall.buffer_destroy(&spall_ctx, &spall_buffer)
+58 -36
View File
@@ -152,43 +152,65 @@ Errno :: enum i32 {
RDONLY flag is not present, because it has the value of 0, i.e. it is the RDONLY flag is not present, because it has the value of 0, i.e. it is the
default, unless WRONLY or RDWR is specified. default, unless WRONLY or RDWR is specified.
*/ */
Open_Flags_Bits :: enum { when ODIN_ARCH != .arm64 && ODIN_ARCH != .arm32 {
WRONLY = 0, Open_Flags_Bits :: enum {
RDWR = 1, WRONLY = 0,
CREAT = 6, RDWR = 1,
EXCL = 7, CREAT = 6,
NOCTTY = 8, EXCL = 7,
TRUNC = 9, NOCTTY = 8,
APPEND = 10, TRUNC = 9,
NONBLOCK = 11, APPEND = 10,
DSYNC = 12, NONBLOCK = 11,
ASYNC = 13, DSYNC = 12,
DIRECT = 14, ASYNC = 13,
LARGEFILE = 15, DIRECT = 14,
DIRECTORY = 16, LARGEFILE = 15,
NOFOLLOW = 17, DIRECTORY = 16,
NOATIME = 18, NOFOLLOW = 17,
CLOEXEC = 19, NOATIME = 18,
PATH = 21, CLOEXEC = 19,
PATH = 21,
}
// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19
#assert(1 << uint(Open_Flags_Bits.WRONLY) == 0o0000000_1)
#assert(1 << uint(Open_Flags_Bits.RDWR) == 0o0000000_2)
#assert(1 << uint(Open_Flags_Bits.CREAT) == 0o00000_100)
#assert(1 << uint(Open_Flags_Bits.EXCL) == 0o00000_200)
#assert(1 << uint(Open_Flags_Bits.NOCTTY) == 0o00000_400)
#assert(1 << uint(Open_Flags_Bits.TRUNC) == 0o0000_1000)
#assert(1 << uint(Open_Flags_Bits.APPEND) == 0o0000_2000)
#assert(1 << uint(Open_Flags_Bits.NONBLOCK) == 0o0000_4000)
#assert(1 << uint(Open_Flags_Bits.DSYNC) == 0o000_10000)
#assert(1 << uint(Open_Flags_Bits.ASYNC) == 0o000_20000)
#assert(1 << uint(Open_Flags_Bits.DIRECT) == 0o000_40000)
#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000)
#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000)
#assert(1 << uint(Open_Flags_Bits.NOFOLLOW) == 0o00_400000)
#assert(1 << uint(Open_Flags_Bits.NOATIME) == 0o0_1000000)
#assert(1 << uint(Open_Flags_Bits.CLOEXEC) == 0o0_2000000)
#assert(1 << uint(Open_Flags_Bits.PATH) == 0o_10000000)
} else {
Open_Flags_Bits :: enum {
WRONLY = 0,
RDWR = 1,
CREAT = 6,
EXCL = 7,
NOCTTY = 8,
TRUNC = 9,
APPEND = 10,
NONBLOCK = 11,
DSYNC = 12,
ASYNC = 13,
DIRECTORY = 14,
NOFOLLOW = 15,
DIRECT = 16,
LARGEFILE = 17,
NOATIME = 18,
CLOEXEC = 19,
PATH = 21,
}
} }
// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19
#assert(1 << uint(Open_Flags_Bits.WRONLY) == 0o0000000_1)
#assert(1 << uint(Open_Flags_Bits.RDWR) == 0o0000000_2)
#assert(1 << uint(Open_Flags_Bits.CREAT) == 0o00000_100)
#assert(1 << uint(Open_Flags_Bits.EXCL) == 0o00000_200)
#assert(1 << uint(Open_Flags_Bits.NOCTTY) == 0o00000_400)
#assert(1 << uint(Open_Flags_Bits.TRUNC) == 0o0000_1000)
#assert(1 << uint(Open_Flags_Bits.APPEND) == 0o0000_2000)
#assert(1 << uint(Open_Flags_Bits.NONBLOCK) == 0o0000_4000)
#assert(1 << uint(Open_Flags_Bits.DSYNC) == 0o000_10000)
#assert(1 << uint(Open_Flags_Bits.ASYNC) == 0o000_20000)
#assert(1 << uint(Open_Flags_Bits.DIRECT) == 0o000_40000)
#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000)
#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000)
#assert(1 << uint(Open_Flags_Bits.NOFOLLOW) == 0o00_400000)
#assert(1 << uint(Open_Flags_Bits.NOATIME) == 0o0_1000000)
#assert(1 << uint(Open_Flags_Bits.CLOEXEC) == 0o0_2000000)
#assert(1 << uint(Open_Flags_Bits.PATH) == 0o_10000000)
/* /*
Bits for FD_Flags bitset Bits for FD_Flags bitset
+2 -2
View File
@@ -138,8 +138,8 @@ errno_unwrap :: proc {errno_unwrap2, errno_unwrap3}
when size_of(int) == 4 { when size_of(int) == 4 {
// xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer // xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer
@(private) @(private)
compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (hi: uint, lo: uint) { compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (lo: uint, hi: uint) {
no_sign := uint(a) no_sign := u64(a)
hi = uint(no_sign >> 32) hi = uint(no_sign >> 32)
lo = uint(no_sign & 0xffff_ffff) lo = uint(no_sign & 0xffff_ffff)
return return
+25 -15
View File
@@ -151,7 +151,8 @@ lseek :: proc "contextless" (fd: Fd, off: i64, whence: Seek_Whence) -> (i64, Err
return errno_unwrap(ret, i64) return errno_unwrap(ret, i64)
} else { } else {
result: i64 = --- result: i64 = ---
ret := syscall(SYS__llseek, fd, compat64_arg_pair(off), &result, whence) lo, hi := compat64_arg_pair(off)
ret := syscall(SYS__llseek, fd, hi, lo, &result, whence)
return result, Errno(-ret) return result, Errno(-ret)
} }
} }
@@ -251,7 +252,11 @@ ioctl :: proc "contextless" (fd: Fd, request: u32, arg: uintptr) -> (uintptr) {
Available since Linux 2.2. Available since Linux 2.2.
*/ */
pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) { pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) {
ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) when ODIN_ARCH == .arm32 {
ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), 0, compat64_arg_pair(offset))
} else {
ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset))
}
return errno_unwrap(ret, int) return errno_unwrap(ret, int)
} }
@@ -261,7 +266,11 @@ pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) {
Available since Linux 2.2. Available since Linux 2.2.
*/ */
pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) { pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) {
ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) when ODIN_ARCH == .arm32 {
ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), 0, compat64_arg_pair(offset))
} else {
ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset))
}
return errno_unwrap(ret, int) return errno_unwrap(ret, int)
} }
@@ -1127,7 +1136,10 @@ fdatasync :: proc "contextless" (fd: Fd) -> (Errno) {
On 32-bit architectures available since Linux 2.4. On 32-bit architectures available since Linux 2.4.
*/ */
truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) { truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) {
when size_of(int) == 4 { when ODIN_ARCH == .arm32 {
ret := syscall(SYS_truncate64, cast(rawptr) name, 0, compat64_arg_pair(length))
return Errno(-ret)
} else when size_of(int) == 4 {
ret := syscall(SYS_truncate64, cast(rawptr) name, compat64_arg_pair(length)) ret := syscall(SYS_truncate64, cast(rawptr) name, compat64_arg_pair(length))
return Errno(-ret) return Errno(-ret)
} else { } else {
@@ -1141,7 +1153,10 @@ truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) {
On 32-bit architectures available since 2.4. On 32-bit architectures available since 2.4.
*/ */
ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) { ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) {
when size_of(int) == 4 { when ODIN_ARCH == .arm32 {
ret := syscall(SYS_ftruncate64, fd, 0, compat64_arg_pair(length))
return Errno(-ret)
} else when size_of(int) == 4 {
ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length)) ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length))
return Errno(-ret) return Errno(-ret)
} else { } else {
@@ -1952,10 +1967,10 @@ sigaltstack :: proc "contextless" (stack: ^Sig_Stack, old_stack: ^Sig_Stack) ->
*/ */
mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) { mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) {
when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 {
ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, dev) ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, cast(uint) dev)
return Errno(-ret) return Errno(-ret)
} else { } else {
ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, dev) ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, cast(uint) dev)
return Errno(-ret) return Errno(-ret)
} }
} }
@@ -2586,7 +2601,7 @@ mkdirat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode) -> (Errno)
Available since Linux 2.6.16. Available since Linux 2.6.16.
*/ */
mknodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, dev: Dev) -> (Errno) { mknodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, dev: Dev) -> (Errno) {
ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, dev) ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, cast(uint) dev)
return Errno(-ret) return Errno(-ret)
} }
@@ -2684,13 +2699,8 @@ faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) ->
Available since Linux 2.6.16. Available since Linux 2.6.16.
*/ */
ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (i32, Errno) { ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (i32, Errno) {
when size_of(int) == 8 { ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) return errno_unwrap(ret, i32)
return errno_unwrap(ret, i32)
} else {
ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
return errno_unwrap(ret, i32)
}
} }
// TODO(flysand): unshare // TODO(flysand): unshare
+166 -66
View File
@@ -3,7 +3,7 @@ package linux
/* /*
Type for storage device handle. Type for storage device handle.
*/ */
Dev :: distinct int Dev :: distinct u64
/* /*
Type for 32-bit User IDs. Type for 32-bit User IDs.
@@ -153,6 +153,7 @@ when ODIN_ARCH == .amd64 {
uid: Uid, uid: Uid,
gid: Gid, gid: Gid,
rdev: Dev, rdev: Dev,
_: [4]u8,
size: i64, size: i64,
blksize: uint, blksize: uint,
blocks: u64, blocks: u64,
@@ -516,79 +517,79 @@ Pid_FD_Flags :: bit_set[Pid_FD_Flags_Bits; i32]
Sig_Set :: [_SIGSET_NWORDS]uint Sig_Set :: [_SIGSET_NWORDS]uint
@private SI_MAX_SIZE :: 128 @private SI_MAX_SIZE :: 128
@private SI_ARCH_PREAMBLE :: 4 * size_of(i32) @private SI_ARCH_PREAMBLE :: 4 * size_of(i32) when size_of(rawptr) == 8 else 3 * size_of(i32)
@private SI_PAD_SIZE :: SI_MAX_SIZE - SI_ARCH_PREAMBLE @private SI_PAD_SIZE :: SI_MAX_SIZE - SI_ARCH_PREAMBLE
Sig_Handler_Fn :: #type proc "c" (sig: Signal) Sig_Handler_Fn :: #type proc "c" (sig: Signal)
Sig_Restore_Fn :: #type proc "c" () -> ! Sig_Restore_Fn :: #type proc "c" () -> !
Sig_Info :: struct #packed { when size_of(rawptr) == 8 {
signo: Signal, Sig_Info :: struct #packed {
errno: Errno, signo: Signal,
code: i32, errno: Errno,
_pad0: i32, code: i32,
using _union: struct #raw_union { _pad0: i32,
_pad1: [SI_PAD_SIZE]u8, using _union: struct #raw_union {
using _kill: struct { _pad1: [SI_PAD_SIZE]u8,
pid: Pid, /* sender's pid */ using _kill: struct {
uid: Uid, /* sender's uid */ pid: Pid, /* sender's pid */
}, uid: Uid, /* sender's uid */
using _timer: struct { },
timerid: i32, /* timer id */ using _timer: struct {
overrun: i32, /* overrun count */ timerid: i32, /* timer id */
value: Sig_Val, /* timer value */ overrun: i32, /* overrun count */
}, value: Sig_Val, /* timer value */
/* POSIX.1b signals */ },
using _rt: struct { /* POSIX.1b signals */
_pid0: Pid, /* sender's pid */ using _rt: struct {
_uid0: Uid, /* sender's uid */ _pid0: Pid, /* sender's pid */
}, _uid0: Uid, /* sender's uid */
/* SIGCHLD */ },
using _sigchld: struct { /* SIGCHLD */
_pid1: Pid, /* which child */ using _sigchld: struct {
_uid1: Uid, /* sender's uid */ _pid1: Pid, /* which child */
status: i32, /* exit code */ _uid1: Uid, /* sender's uid */
utime: uint, status: i32, /* exit code */
stime: uint, //clock_t utime: uint,
}, stime: uint, //clock_t
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ },
using _sigfault: struct { /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
addr: rawptr, /* faulting insn/memory ref. */ using _sigfault: struct {
using _: struct #raw_union { addr: rawptr, /* faulting insn/memory ref. */
trapno: i32, /* Trap number that caused signal */ using _: struct #raw_union {
addr_lsb: i16, /* LSB of the reported address */ trapno: i32, /* Trap number that caused signal */
using _addr_bnd: struct { addr_lsb: i16, /* LSB of the reported address */
_pad2: u64, using _addr_bnd: struct {
lower: rawptr, /* lower bound during fault */ _pad2: u64,
upper: rawptr, /* upper bound during fault */ lower: rawptr, /* lower bound during fault */
}, upper: rawptr, /* upper bound during fault */
using _addr_pkey: struct { },
_pad3: u64, using _addr_pkey: struct {
pkey: u32, /* protection key on PTE that faulted */ _pad3: u64,
}, pkey: u32, /* protection key on PTE that faulted */
using _perf: struct { },
perf_data: u64, using _perf: struct {
perf_type: u32, perf_data: u64,
perf_flags: u32, perf_type: u32,
perf_flags: u32,
},
}, },
}, },
/* SIGPOLL */
using _sigpoll: struct {
band: int, /* POLL_IN, POLL_OUT, POLL_MSG */
fd: Fd,
},
/* SIGSYS */
using _sigsys: struct {
call_addr: rawptr, /* calling user insn */
syscall: i32, /* triggering system call number */
arch: u32, /* AUDIT_ARCH_* of syscall */
},
}, },
/* SIGPOLL */ }
using _sigpoll: struct {
band: int, /* POLL_IN, POLL_OUT, POLL_MSG */
fd: Fd,
},
/* SIGSYS */
using _sigsys: struct {
call_addr: rawptr, /* calling user insn */
syscall: i32, /* triggering system call number */
arch: u32, /* AUDIT_ARCH_* of syscall */
},
},
}
#assert(size_of(Sig_Info) == 128) #assert(size_of(Sig_Info) == 128)
when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
#assert(offset_of(Sig_Info, signo) == 0x00) #assert(offset_of(Sig_Info, signo) == 0x00)
#assert(offset_of(Sig_Info, errno) == 0x04) #assert(offset_of(Sig_Info, errno) == 0x04)
#assert(offset_of(Sig_Info, code) == 0x08) #assert(offset_of(Sig_Info, code) == 0x08)
@@ -615,7 +616,96 @@ when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
#assert(offset_of(Sig_Info, syscall) == 0x18) #assert(offset_of(Sig_Info, syscall) == 0x18)
#assert(offset_of(Sig_Info, arch) == 0x1C) #assert(offset_of(Sig_Info, arch) == 0x1C)
} else { } else {
// TODO Sig_Info :: struct {
signo: Signal,
errno: Errno,
code: i32,
using _union: struct #raw_union {
_pad1: [SI_PAD_SIZE]u8,
using _kill: struct {
pid: Pid, /* sender's pid */
uid: Uid, /* sender's uid */
},
using _timer: struct {
timerid: i32, /* timer id */
overrun: i32, /* overrun count */
value: Sig_Val, /* timer value */
},
/* POSIX.1b signals */
using _rt: struct {
_pid0: Pid, /* sender's pid */
_uid0: Uid, /* sender's uid */
},
/* SIGCHLD */
using _sigchld: struct {
_pid1: Pid, /* which child */
_uid1: Uid, /* sender's uid */
status: i32, /* exit code */
utime: uint,
stime: uint, //clock_t
},
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
using _sigfault: struct {
addr: rawptr, /* faulting insn/memory ref. */
using _: struct #raw_union {
trapno: i32, /* Trap number that caused signal */
addr_lsb: i16, /* LSB of the reported address */
using _addr_bnd: struct {
_pad2: u32,
lower: rawptr, /* lower bound during fault */
upper: rawptr, /* upper bound during fault */
},
using _addr_pkey: struct {
_pad3: u32,
pkey: u32, /* protection key on PTE that faulted */
},
using _perf: struct {
perf_data: u32,
perf_type: u32,
perf_flags: u32,
},
},
},
/* SIGPOLL */
using _sigpoll: struct {
band: int, /* POLL_IN, POLL_OUT, POLL_MSG */
fd: Fd,
},
/* SIGSYS */
using _sigsys: struct {
call_addr: rawptr, /* calling user insn */
syscall: i32, /* triggering system call number */
arch: u32, /* AUDIT_ARCH_* of syscall */
},
},
}
#assert(size_of(Sig_Info) == 128)
#assert(offset_of(Sig_Info, signo) == 0x00)
#assert(offset_of(Sig_Info, errno) == 0x04)
#assert(offset_of(Sig_Info, code) == 0x08)
#assert(offset_of(Sig_Info, pid) == 0x0c)
#assert(offset_of(Sig_Info, uid) == 0x10)
#assert(offset_of(Sig_Info, timerid) == 0x0c)
#assert(offset_of(Sig_Info, overrun) == 0x10)
#assert(offset_of(Sig_Info, value) == 0x14)
#assert(offset_of(Sig_Info, status) == 0x14)
#assert(offset_of(Sig_Info, utime) == 0x18)
#assert(offset_of(Sig_Info, stime) == 0x1c)
#assert(offset_of(Sig_Info, addr) == 0x0c)
#assert(offset_of(Sig_Info, addr_lsb) == 0x10)
#assert(offset_of(Sig_Info, trapno) == 0x10)
#assert(offset_of(Sig_Info, lower) == 0x14)
#assert(offset_of(Sig_Info, upper) == 0x18)
#assert(offset_of(Sig_Info, pkey) == 0x14)
#assert(offset_of(Sig_Info, perf_data) == 0x10)
#assert(offset_of(Sig_Info, perf_type) == 0x14)
#assert(offset_of(Sig_Info, perf_flags) == 0x18)
#assert(offset_of(Sig_Info, band) == 0x0c)
#assert(offset_of(Sig_Info, fd) == 0x10)
#assert(offset_of(Sig_Info, call_addr) == 0x0c)
#assert(offset_of(Sig_Info, syscall) == 0x10)
#assert(offset_of(Sig_Info, arch) == 0x14)
} }
SIGEV_MAX_SIZE :: 64 SIGEV_MAX_SIZE :: 64
@@ -684,6 +774,14 @@ Address_Family :: distinct Protocol_Family
*/ */
Socket_Msg :: bit_set[Socket_Msg_Bits; i32] Socket_Msg :: bit_set[Socket_Msg_Bits; i32]
/*
Struct representing a generic socket address.
*/
Sock_Addr :: struct #packed {
sa_family: Address_Family,
sa_data: [14]u8,
}
/* /*
Struct representing IPv4 socket address. Struct representing IPv4 socket address.
*/ */
@@ -691,6 +789,7 @@ Sock_Addr_In :: struct #packed {
sin_family: Address_Family, sin_family: Address_Family,
sin_port: u16be, sin_port: u16be,
sin_addr: [4]u8, sin_addr: [4]u8,
sin_zero: [size_of(Sock_Addr) - size_of(Address_Family) - size_of(u16be) - size_of([4]u8)]u8,
} }
/* /*
@@ -720,6 +819,7 @@ Sock_Addr_Any :: struct #raw_union {
family: Address_Family, family: Address_Family,
port: u16be, port: u16be,
}, },
using generic: Sock_Addr,
using ipv4: Sock_Addr_In, using ipv4: Sock_Addr_In,
using ipv6: Sock_Addr_In6, using ipv6: Sock_Addr_In6,
using uds: Sock_Addr_Un, using uds: Sock_Addr_Un,
+21 -1
View File
@@ -20,6 +20,15 @@ COMMON_LVB_GRID_RVERTICAL :: WORD(0x1000)
COMMON_LVB_REVERSE_VIDEO :: WORD(0x4000) COMMON_LVB_REVERSE_VIDEO :: WORD(0x4000)
COMMON_LVB_UNDERSCORE :: WORD(0x8000) COMMON_LVB_UNDERSCORE :: WORD(0x8000)
COMMON_LVB_SBCSDBCS :: WORD(0x0300) COMMON_LVB_SBCSDBCS :: WORD(0x0300)
EV_BREAK :: DWORD(0x0040)
EV_CTS :: DWORD(0x0008)
EV_DSR :: DWORD(0x0010)
EV_ERR :: DWORD(0x0080)
EV_RING :: DWORD(0x0100)
EV_RLSD :: DWORD(0x0020)
EV_RXCHAR :: DWORD(0x0001)
EV_RXFLAG :: DWORD(0x0002)
EV_TXEMPTY :: DWORD(0x0004)
@(default_calling_convention="system") @(default_calling_convention="system")
foreign kernel32 { foreign kernel32 {
@@ -109,7 +118,9 @@ foreign kernel32 {
ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL --- ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL ---
GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
GetCommPorts :: proc(lpPortNumbers: PULONG, uPortNumbersCount: ULONG, puPortNumbersFound: PULONG) -> ULONG --- SetCommMask :: proc(handle: HANDLE, dwEvtMap: DWORD) -> BOOL ---
GetCommMask :: proc(handle: HANDLE, lpEvtMask: LPDWORD) -> BOOL ---
WaitCommEvent :: proc(handle: HANDLE, lpEvtMask: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL ---
GetCommandLineW :: proc() -> LPCWSTR --- GetCommandLineW :: proc() -> LPCWSTR ---
GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD ---
GetCurrentProcess :: proc() -> HANDLE --- GetCurrentProcess :: proc() -> HANDLE ---
@@ -239,6 +250,10 @@ foreign kernel32 {
hThread: HANDLE, hThread: HANDLE,
lpContext: LPCONTEXT, lpContext: LPCONTEXT,
) -> BOOL --- ) -> BOOL ---
SetThreadContext :: proc(
hThread: HANDLE,
lpContext: LPCONTEXT,
) -> BOOL ---
CreateProcessW :: proc( CreateProcessW :: proc(
lpApplicationName: LPCWSTR, lpApplicationName: LPCWSTR,
lpCommandLine: LPWSTR, lpCommandLine: LPWSTR,
@@ -1068,6 +1083,11 @@ foreign one_core {
PageProtection: ULONG, PageProtection: ULONG,
PreferredNode: ULONG, PreferredNode: ULONG,
) -> PVOID --- ) -> PVOID ---
GetCommPorts :: proc(
lpPortNumbers: PULONG,
uPortNumbersCount: ULONG,
puPortNumbersFound: PULONG,
) -> ULONG ---
} }
+26 -2
View File
@@ -143,6 +143,7 @@ LPWSAPROTOCOL_INFO :: ^WSAPROTOCOL_INFO
LPSTR :: ^CHAR LPSTR :: ^CHAR
LPWSTR :: ^WCHAR LPWSTR :: ^WCHAR
OLECHAR :: WCHAR OLECHAR :: WCHAR
BSTR :: ^OLECHAR
LPOLESTR :: ^OLECHAR LPOLESTR :: ^OLECHAR
LPCOLESTR :: LPCSTR LPCOLESTR :: LPCSTR
LPFILETIME :: ^FILETIME LPFILETIME :: ^FILETIME
@@ -2694,11 +2695,23 @@ EXCEPTION_MAXIMUM_PARAMETERS :: 15
EXCEPTION_DATATYPE_MISALIGNMENT :: 0x80000002 EXCEPTION_DATATYPE_MISALIGNMENT :: 0x80000002
EXCEPTION_BREAKPOINT :: 0x80000003 EXCEPTION_BREAKPOINT :: 0x80000003
EXCEPTION_SINGLE_STEP :: 0x80000004
EXCEPTION_ACCESS_VIOLATION :: 0xC0000005 EXCEPTION_ACCESS_VIOLATION :: 0xC0000005
EXCEPTION_IN_PAGE_ERROR :: 0xC0000006
EXCEPTION_ILLEGAL_INSTRUCTION :: 0xC000001D EXCEPTION_ILLEGAL_INSTRUCTION :: 0xC000001D
EXCEPTION_NONCONTINUABLE_EXCEPTION :: 0xC0000025
EXCEPTION_INVALID_DISPOSITION :: 0xC0000026
EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C
EXCEPTION_FLT_DENORMAL_OPERAND :: 0xC000008D
EXCEPTION_FLT_DIVIDE_BY_ZERO :: 0xC000008E
EXCEPTION_FLT_INEXACT_RESULT :: 0xC000008F
EXCEPTION_FLT_INVALID_OPERATION :: 0xC0000090
EXCEPTION_FLT_OVERFLOW :: 0xC0000091
EXCEPTION_FLT_STACK_CHECK :: 0xC0000092
EXCEPTION_FLT_UNDERFLOW :: 0xC0000093
EXCEPTION_INT_DIVIDE_BY_ZERO :: 0xC0000094 EXCEPTION_INT_DIVIDE_BY_ZERO :: 0xC0000094
EXCEPTION_INT_OVERFLOW :: 0xC0000095 EXCEPTION_INT_OVERFLOW :: 0xC0000095
EXCEPTION_PRIV_INSTRUCTION :: 0xC0000096
EXCEPTION_STACK_OVERFLOW :: 0xC00000FD EXCEPTION_STACK_OVERFLOW :: 0xC00000FD
STATUS_PRIVILEGED_INSTRUCTION :: 0xC0000096 STATUS_PRIVILEGED_INSTRUCTION :: 0xC0000096
@@ -3415,8 +3428,6 @@ TIME_ZONE_INFORMATION :: struct {
DaylightBias: LONG, DaylightBias: LONG,
} }
@(private="file")
IMAGE_DOS_HEADER :: struct { IMAGE_DOS_HEADER :: struct {
e_magic: WORD, e_magic: WORD,
e_cblp: WORD, e_cblp: WORD,
@@ -3534,6 +3545,19 @@ IMAGE_EXPORT_DIRECTORY :: struct {
AddressOfNameOrdinals: DWORD, // RVA from base of image AddressOfNameOrdinals: DWORD, // RVA from base of image
} }
IMAGE_DEBUG_DIRECTORY :: struct {
Characteristics: DWORD,
TimeDateStamp: DWORD,
MajorVersion: WORD,
MinorVersion: WORD,
Type: DWORD,
SizeOfData: DWORD,
AddressOfRawData: DWORD,
PointerToRawData: DWORD,
}
IMAGE_DEBUG_TYPE_CODEVIEW :: 2
SICHINTF :: DWORD SICHINTF :: DWORD
SHCONTF :: DWORD SHCONTF :: DWORD
SFGAOF :: ULONG SFGAOF :: ULONG
+1
View File
@@ -51,6 +51,7 @@ foreign user32 {
IsWindowVisible :: proc(hwnd: HWND) -> BOOL --- IsWindowVisible :: proc(hwnd: HWND) -> BOOL ---
IsWindowEnabled :: proc(hwnd: HWND) -> BOOL --- IsWindowEnabled :: proc(hwnd: HWND) -> BOOL ---
IsIconic :: proc(hwnd: HWND) -> BOOL --- IsIconic :: proc(hwnd: HWND) -> BOOL ---
IsZoomed :: proc(hwnd: HWND) -> BOOL ---
BringWindowToTop :: proc(hWnd: HWND) -> BOOL --- BringWindowToTop :: proc(hWnd: HWND) -> BOOL ---
GetTopWindow :: proc(hWnd: HWND) -> HWND --- GetTopWindow :: proc(hWnd: HWND) -> HWND ---
SetForegroundWindow :: proc(hWnd: HWND) -> BOOL --- SetForegroundWindow :: proc(hWnd: HWND) -> BOOL ---
+153 -141
View File
@@ -11,146 +11,147 @@ TZ_Abbrev :: struct {
dst: string, dst: string,
} }
tz_abbrevs := map[string]TZ_Abbrev { @(rodata)
"Egypt Standard Time" = {"EET", "EEST"}, // Africa/Cairo tz_abbrevs := [?]struct{key: string, value: TZ_Abbrev}{
"Morocco Standard Time" = {"+00", "+01"}, // Africa/Casablanca {"Egypt Standard Time", {"EET", "EEST"}}, // Africa/Cairo
"South Africa Standard Time" = {"SAST", "SAST"}, // Africa/Johannesburg {"Morocco Standard Time", {"+00", "+01"}}, // Africa/Casablanca
"South Sudan Standard Time" = {"CAT", "CAT"}, // Africa/Juba {"South Africa Standard Time", {"SAST", "SAST"}}, // Africa/Johannesburg
"Sudan Standard Time" = {"CAT", "CAT"}, // Africa/Khartoum {"South Sudan Standard Time", {"CAT", "CAT"}}, // Africa/Juba
"W. Central Africa Standard Time" = {"WAT", "WAT"}, // Africa/Lagos {"Sudan Standard Time", {"CAT", "CAT"}}, // Africa/Khartoum
"E. Africa Standard Time" = {"EAT", "EAT"}, // Africa/Nairobi {"W. Central Africa Standard Time", {"WAT", "WAT"}}, // Africa/Lagos
"Sao Tome Standard Time" = {"GMT", "GMT"}, // Africa/Sao_Tome {"E. Africa Standard Time", {"EAT", "EAT"}}, // Africa/Nairobi
"Libya Standard Time" = {"EET", "EET"}, // Africa/Tripoli {"Sao Tome Standard Time", {"GMT", "GMT"}}, // Africa/Sao_Tome
"Namibia Standard Time" = {"CAT", "CAT"}, // Africa/Windhoek {"Libya Standard Time", {"EET", "EET"}}, // Africa/Tripoli
"Aleutian Standard Time" = {"HST", "HDT"}, // America/Adak {"Namibia Standard Time", {"CAT", "CAT"}}, // Africa/Windhoek
"Alaskan Standard Time" = {"AKST", "AKDT"}, // America/Anchorage {"Aleutian Standard Time", {"HST", "HDT"}}, // America/Adak
"Tocantins Standard Time" = {"-03", "-03"}, // America/Araguaina {"Alaskan Standard Time", {"AKST", "AKDT"}}, // America/Anchorage
"Paraguay Standard Time" = {"-04", "-03"}, // America/Asuncion {"Tocantins Standard Time", {"-03", "-03"}}, // America/Araguaina
"Bahia Standard Time" = {"-03", "-03"}, // America/Bahia {"Paraguay Standard Time", {"-04", "-03"}}, // America/Asuncion
"SA Pacific Standard Time" = {"-05", "-05"}, // America/Bogota {"Bahia Standard Time", {"-03", "-03"}}, // America/Bahia
"Argentina Standard Time" = {"-03", "-03"}, // America/Buenos_Aires {"SA Pacific Standard Time", {"-05", "-05"}}, // America/Bogota
"Eastern Standard Time (Mexico)" = {"EST", "EST"}, // America/Cancun {"Argentina Standard Time", {"-03", "-03"}}, // America/Buenos_Aires
"Venezuela Standard Time" = {"-04", "-04"}, // America/Caracas {"Eastern Standard Time (Mexico)", {"EST", "EST"}}, // America/Cancun
"SA Eastern Standard Time" = {"-03", "-03"}, // America/Cayenne {"Venezuela Standard Time", {"-04", "-04"}}, // America/Caracas
"Central Standard Time" = {"CST", "CDT"}, // America/Chicago {"SA Eastern Standard Time", {"-03", "-03"}}, // America/Cayenne
"Central Brazilian Standard Time" = {"-04", "-04"}, // America/Cuiaba {"Central Standard Time", {"CST", "CDT"}}, // America/Chicago
"Mountain Standard Time" = {"MST", "MDT"}, // America/Denver {"Central Brazilian Standard Time", {"-04", "-04"}}, // America/Cuiaba
"Greenland Standard Time" = {"-03", "-02"}, // America/Godthab {"Mountain Standard Time", {"MST", "MDT"}}, // America/Denver
"Turks And Caicos Standard Time" = {"EST", "EDT"}, // America/Grand_Turk {"Greenland Standard Time", {"-03", "-02"}}, // America/Godthab
"Central America Standard Time" = {"CST", "CST"}, // America/Guatemala {"Turks And Caicos Standard Time", {"EST", "EDT"}}, // America/Grand_Turk
"Atlantic Standard Time" = {"AST", "ADT"}, // America/Halifax {"Central America Standard Time", {"CST", "CST"}}, // America/Guatemala
"Cuba Standard Time" = {"CST", "CDT"}, // America/Havana {"Atlantic Standard Time", {"AST", "ADT"}}, // America/Halifax
"US Eastern Standard Time" = {"EST", "EDT"}, // America/Indianapolis {"Cuba Standard Time", {"CST", "CDT"}}, // America/Havana
"SA Western Standard Time" = {"-04", "-04"}, // America/La_Paz {"US Eastern Standard Time", {"EST", "EDT"}}, // America/Indianapolis
"Pacific Standard Time" = {"PST", "PDT"}, // America/Los_Angeles {"SA Western Standard Time", {"-04", "-04"}}, // America/La_Paz
"Mountain Standard Time (Mexico)" = {"MST", "MST"}, // America/Mazatlan {"Pacific Standard Time", {"PST", "PDT"}}, // America/Los_Angeles
"Central Standard Time (Mexico)" = {"CST", "CST"}, // America/Mexico_City {"Mountain Standard Time (Mexico)", {"MST", "MST"}}, // America/Mazatlan
"Saint Pierre Standard Time" = {"-03", "-02"}, // America/Miquelon {"Central Standard Time (Mexico)", {"CST", "CST"}}, // America/Mexico_City
"Montevideo Standard Time" = {"-03", "-03"}, // America/Montevideo {"Saint Pierre Standard Time", {"-03", "-02"}}, // America/Miquelon
"Eastern Standard Time" = {"EST", "EDT"}, // America/New_York {"Montevideo Standard Time", {"-03", "-03"}}, // America/Montevideo
"US Mountain Standard Time" = {"MST", "MST"}, // America/Phoenix {"Eastern Standard Time", {"EST", "EDT"}}, // America/New_York
"Haiti Standard Time" = {"EST", "EDT"}, // America/Port-au-Prince {"US Mountain Standard Time", {"MST", "MST"}}, // America/Phoenix
"Magallanes Standard Time" = {"-03", "-03"}, // America/Punta_Arenas {"Haiti Standard Time", {"EST", "EDT"}}, // America/Port-au-Prince
"Canada Central Standard Time" = {"CST", "CST"}, // America/Regina {"Magallanes Standard Time", {"-03", "-03"}}, // America/Punta_Arenas
"Pacific SA Standard Time" = {"-04", "-03"}, // America/Santiago {"Canada Central Standard Time", {"CST", "CST"}}, // America/Regina
"E. South America Standard Time" = {"-03", "-03"}, // America/Sao_Paulo {"Pacific SA Standard Time", {"-04", "-03"}}, // America/Santiago
"Newfoundland Standard Time" = {"NST", "NDT"}, // America/St_Johns {"E. South America Standard Time", {"-03", "-03"}}, // America/Sao_Paulo
"Pacific Standard Time (Mexico)" = {"PST", "PDT"}, // America/Tijuana {"Newfoundland Standard Time", {"NST", "NDT"}}, // America/St_Johns
"Yukon Standard Time" = {"MST", "MST"}, // America/Whitehorse {"Pacific Standard Time (Mexico)", {"PST", "PDT"}}, // America/Tijuana
"Central Asia Standard Time" = {"+06", "+06"}, // Asia/Almaty {"Yukon Standard Time", {"MST", "MST"}}, // America/Whitehorse
"Jordan Standard Time" = {"+03", "+03"}, // Asia/Amman {"Central Asia Standard Time", {"+06", "+06"}}, // Asia/Almaty
"Arabic Standard Time" = {"+03", "+03"}, // Asia/Baghdad {"Jordan Standard Time", {"+03", "+03"}}, // Asia/Amman
"Azerbaijan Standard Time" = {"+04", "+04"}, // Asia/Baku {"Arabic Standard Time", {"+03", "+03"}}, // Asia/Baghdad
"SE Asia Standard Time" = {"+07", "+07"}, // Asia/Bangkok {"Azerbaijan Standard Time", {"+04", "+04"}}, // Asia/Baku
"Altai Standard Time" = {"+07", "+07"}, // Asia/Barnaul {"SE Asia Standard Time", {"+07", "+07"}}, // Asia/Bangkok
"Middle East Standard Time" = {"EET", "EEST"}, // Asia/Beirut {"Altai Standard Time", {"+07", "+07"}}, // Asia/Barnaul
"India Standard Time" = {"IST", "IST"}, // Asia/Calcutta {"Middle East Standard Time", {"EET", "EEST"}}, // Asia/Beirut
"Transbaikal Standard Time" = {"+09", "+09"}, // Asia/Chita {"India Standard Time", {"IST", "IST"}}, // Asia/Calcutta
"Sri Lanka Standard Time" = {"+0530", "+0530"}, // Asia/Colombo {"Transbaikal Standard Time", {"+09", "+09"}}, // Asia/Chita
"Syria Standard Time" = {"+03", "+03"}, // Asia/Damascus {"Sri Lanka Standard Time", {"+0530", "+0530"}}, // Asia/Colombo
"Bangladesh Standard Time" = {"+06", "+06"}, // Asia/Dhaka {"Syria Standard Time", {"+03", "+03"}}, // Asia/Damascus
"Arabian Standard Time" = {"+04", "+04"}, // Asia/Dubai {"Bangladesh Standard Time", {"+06", "+06"}}, // Asia/Dhaka
"West Bank Standard Time" = {"EET", "EEST"}, // Asia/Hebron {"Arabian Standard Time", {"+04", "+04"}}, // Asia/Dubai
"W. Mongolia Standard Time" = {"+07", "+07"}, // Asia/Hovd {"West Bank Standard Time", {"EET", "EEST"}}, // Asia/Hebron
"North Asia East Standard Time" = {"+08", "+08"}, // Asia/Irkutsk {"W. Mongolia Standard Time", {"+07", "+07"}}, // Asia/Hovd
"Israel Standard Time" = {"IST", "IDT"}, // Asia/Jerusalem {"North Asia East Standard Time", {"+08", "+08"}}, // Asia/Irkutsk
"Afghanistan Standard Time" = {"+0430", "+0430"}, // Asia/Kabul {"Israel Standard Time", {"IST", "IDT"}}, // Asia/Jerusalem
"Russia Time Zone 11" = {"+12", "+12"}, // Asia/Kamchatka {"Afghanistan Standard Time", {"+0430", "+0430"}}, // Asia/Kabul
"Pakistan Standard Time" = {"PKT", "PKT"}, // Asia/Karachi {"Russia Time Zone 11", {"+12", "+12"}}, // Asia/Kamchatka
"Nepal Standard Time" = {"+0545", "+0545"}, // Asia/Katmandu {"Pakistan Standard Time", {"PKT", "PKT"}}, // Asia/Karachi
"North Asia Standard Time" = {"+07", "+07"}, // Asia/Krasnoyarsk {"Nepal Standard Time", {"+0545", "+0545"}}, // Asia/Katmandu
"Magadan Standard Time" = {"+11", "+11"}, // Asia/Magadan {"North Asia Standard Time", {"+07", "+07"}}, // Asia/Krasnoyarsk
"N. Central Asia Standard Time" = {"+07", "+07"}, // Asia/Novosibirsk {"Magadan Standard Time", {"+11", "+11"}}, // Asia/Magadan
"Omsk Standard Time" = {"+06", "+06"}, // Asia/Omsk {"N. Central Asia Standard Time", {"+07", "+07"}}, // Asia/Novosibirsk
"North Korea Standard Time" = {"KST", "KST"}, // Asia/Pyongyang {"Omsk Standard Time", {"+06", "+06"}}, // Asia/Omsk
"Qyzylorda Standard Time" = {"+05", "+05"}, // Asia/Qyzylorda {"North Korea Standard Time", {"KST", "KST"}}, // Asia/Pyongyang
"Myanmar Standard Time" = {"+0630", "+0630"}, // Asia/Rangoon {"Qyzylorda Standard Time", {"+05", "+05"}}, // Asia/Qyzylorda
"Arab Standard Time" = {"+03", "+03"}, // Asia/Riyadh {"Myanmar Standard Time", {"+0630", "+0630"}}, // Asia/Rangoon
"Sakhalin Standard Time" = {"+11", "+11"}, // Asia/Sakhalin {"Arab Standard Time", {"+03", "+03"}}, // Asia/Riyadh
"Korea Standard Time" = {"KST", "KST"}, // Asia/Seoul {"Sakhalin Standard Time", {"+11", "+11"}}, // Asia/Sakhalin
"China Standard Time" = {"CST", "CST"}, // Asia/Shanghai {"Korea Standard Time", {"KST", "KST"}}, // Asia/Seoul
"Singapore Standard Time" = {"+08", "+08"}, // Asia/Singapore {"China Standard Time", {"CST", "CST"}}, // Asia/Shanghai
"Russia Time Zone 10" = {"+11", "+11"}, // Asia/Srednekolymsk {"Singapore Standard Time", {"+08", "+08"}}, // Asia/Singapore
"Taipei Standard Time" = {"CST", "CST"}, // Asia/Taipei {"Russia Time Zone 10", {"+11", "+11"}}, // Asia/Srednekolymsk
"West Asia Standard Time" = {"+05", "+05"}, // Asia/Tashkent {"Taipei Standard Time", {"CST", "CST"}}, // Asia/Taipei
"Georgian Standard Time" = {"+04", "+04"}, // Asia/Tbilisi {"West Asia Standard Time", {"+05", "+05"}}, // Asia/Tashkent
"Iran Standard Time" = {"+0330", "+0330"}, // Asia/Tehran {"Georgian Standard Time", {"+04", "+04"}}, // Asia/Tbilisi
"Tokyo Standard Time" = {"JST", "JST"}, // Asia/Tokyo {"Iran Standard Time", {"+0330", "+0330"}}, // Asia/Tehran
"Tomsk Standard Time" = {"+07", "+07"}, // Asia/Tomsk {"Tokyo Standard Time", {"JST", "JST"}}, // Asia/Tokyo
"Ulaanbaatar Standard Time" = {"+08", "+08"}, // Asia/Ulaanbaatar {"Tomsk Standard Time", {"+07", "+07"}}, // Asia/Tomsk
"Vladivostok Standard Time" = {"+10", "+10"}, // Asia/Vladivostok {"Ulaanbaatar Standard Time", {"+08", "+08"}}, // Asia/Ulaanbaatar
"Yakutsk Standard Time" = {"+09", "+09"}, // Asia/Yakutsk {"Vladivostok Standard Time", {"+10", "+10"}}, // Asia/Vladivostok
"Ekaterinburg Standard Time" = {"+05", "+05"}, // Asia/Yekaterinburg {"Yakutsk Standard Time", {"+09", "+09"}}, // Asia/Yakutsk
"Caucasus Standard Time" = {"+04", "+04"}, // Asia/Yerevan {"Ekaterinburg Standard Time", {"+05", "+05"}}, // Asia/Yekaterinburg
"Azores Standard Time" = {"-01", "+00"}, // Atlantic/Azores {"Caucasus Standard Time", {"+04", "+04"}}, // Asia/Yerevan
"Cape Verde Standard Time" = {"-01", "-01"}, // Atlantic/Cape_Verde {"Azores Standard Time", {"-01", "+00"}}, // Atlantic/Azores
"Greenwich Standard Time" = {"GMT", "GMT"}, // Atlantic/Reykjavik {"Cape Verde Standard Time", {"-01", "-01"}}, // Atlantic/Cape_Verde
"Cen. Australia Standard Time" = {"ACST", "ACDT"}, // Australia/Adelaide {"Greenwich Standard Time", {"GMT", "GMT"}}, // Atlantic/Reykjavik
"E. Australia Standard Time" = {"AEST", "AEST"}, // Australia/Brisbane {"Cen. Australia Standard Time", {"ACST", "ACDT"}}, // Australia/Adelaide
"AUS Central Standard Time" = {"ACST", "ACST"}, // Australia/Darwin {"E. Australia Standard Time", {"AEST", "AEST"}}, // Australia/Brisbane
"Aus Central W. Standard Time" = {"+0845", "+0845"}, // Australia/Eucla {"AUS Central Standard Time", {"ACST", "ACST"}}, // Australia/Darwin
"Tasmania Standard Time" = {"AEST", "AEDT"}, // Australia/Hobart {"Aus Central W. Standard Time", {"+0845", "+0845"}}, // Australia/Eucla
"Lord Howe Standard Time" = {"+1030", "+11"}, // Australia/Lord_Howe {"Tasmania Standard Time", {"AEST", "AEDT"}}, // Australia/Hobart
"W. Australia Standard Time" = {"AWST", "AWST"}, // Australia/Perth {"Lord Howe Standard Time", {"+1030", "+11"}}, // Australia/Lord_Howe
"AUS Eastern Standard Time" = {"AEST", "AEDT"}, // Australia/Sydney {"W. Australia Standard Time", {"AWST", "AWST"}}, // Australia/Perth
"UTC-11" = {"-11", "-11"}, // Etc/GMT+11 {"AUS Eastern Standard Time", {"AEST", "AEDT"}}, // Australia/Sydney
"Dateline Standard Time" = {"-12", "-12"}, // Etc/GMT+12 {"UTC-11", {"-11", "-11"}}, // Etc/GMT+11
"UTC-02" = {"-02", "-02"}, // Etc/GMT+2 {"Dateline Standard Time", {"-12", "-12"}}, // Etc/GMT+12
"UTC-08" = {"-08", "-08"}, // Etc/GMT+8 {"UTC-02", {"-02", "-02"}}, // Etc/GMT+2
"UTC-09" = {"-09", "-09"}, // Etc/GMT+9 {"UTC-08", {"-08", "-08"}}, // Etc/GMT+8
"UTC+12" = {"+12", "+12"}, // Etc/GMT-12 {"UTC-09", {"-09", "-09"}}, // Etc/GMT+9
"UTC+13" = {"+13", "+13"}, // Etc/GMT-13 {"UTC+12", {"+12", "+12"}}, // Etc/GMT-12
"UTC" = {"UTC", "UTC"}, // Etc/UTC {"UTC+13", {"+13", "+13"}}, // Etc/GMT-13
"Astrakhan Standard Time" = {"+04", "+04"}, // Europe/Astrakhan {"UTC", {"UTC", "UTC"}}, // Etc/UTC
"W. Europe Standard Time" = {"CET", "CEST"}, // Europe/Berlin {"Astrakhan Standard Time", {"+04", "+04"}}, // Europe/Astrakhan
"GTB Standard Time" = {"EET", "EEST"}, // Europe/Bucharest {"W. Europe Standard Time", {"CET", "CEST"}}, // Europe/Berlin
"Central Europe Standard Time" = {"CET", "CEST"}, // Europe/Budapest {"GTB Standard Time", {"EET", "EEST"}}, // Europe/Bucharest
"E. Europe Standard Time" = {"EET", "EEST"}, // Europe/Chisinau {"Central Europe Standard Time", {"CET", "CEST"}}, // Europe/Budapest
"Turkey Standard Time" = {"+03", "+03"}, // Europe/Istanbul {"E. Europe Standard Time", {"EET", "EEST"}}, // Europe/Chisinau
"Kaliningrad Standard Time" = {"EET", "EET"}, // Europe/Kaliningrad {"Turkey Standard Time", {"+03", "+03"}}, // Europe/Istanbul
"FLE Standard Time" = {"EET", "EEST"}, // Europe/Kiev {"Kaliningrad Standard Time", {"EET", "EET"}}, // Europe/Kaliningrad
"GMT Standard Time" = {"GMT", "BST"}, // Europe/London {"FLE Standard Time", {"EET", "EEST"}}, // Europe/Kiev
"Belarus Standard Time" = {"+03", "+03"}, // Europe/Minsk {"GMT Standard Time", {"GMT", "BST"}}, // Europe/London
"Russian Standard Time" = {"MSK", "MSK"}, // Europe/Moscow {"Belarus Standard Time", {"+03", "+03"}}, // Europe/Minsk
"Romance Standard Time" = {"CET", "CEST"}, // Europe/Paris {"Russian Standard Time", {"MSK", "MSK"}}, // Europe/Moscow
"Russia Time Zone 3" = {"+04", "+04"}, // Europe/Samara {"Romance Standard Time", {"CET", "CEST"}}, // Europe/Paris
"Saratov Standard Time" = {"+04", "+04"}, // Europe/Saratov {"Russia Time Zone 3", {"+04", "+04"}}, // Europe/Samara
"Volgograd Standard Time" = {"MSK", "MSK"}, // Europe/Volgograd {"Saratov Standard Time", {"+04", "+04"}}, // Europe/Saratov
"Central European Standard Time" = {"CET", "CEST"}, // Europe/Warsaw {"Volgograd Standard Time", {"MSK", "MSK"}}, // Europe/Volgograd
"Mauritius Standard Time" = {"+04", "+04"}, // Indian/Mauritius {"Central European Standard Time", {"CET", "CEST"}}, // Europe/Warsaw
"Samoa Standard Time" = {"+13", "+13"}, // Pacific/Apia {"Mauritius Standard Time", {"+04", "+04"}}, // Indian/Mauritius
"New Zealand Standard Time" = {"NZST", "NZDT"}, // Pacific/Auckland {"Samoa Standard Time", {"+13", "+13"}}, // Pacific/Apia
"Bougainville Standard Time" = {"+11", "+11"}, // Pacific/Bougainville {"New Zealand Standard Time", {"NZST", "NZDT"}}, // Pacific/Auckland
"Chatham Islands Standard Time" = {"+1245", "+1345"}, // Pacific/Chatham {"Bougainville Standard Time", {"+11", "+11"}}, // Pacific/Bougainville
"Easter Island Standard Time" = {"-06", "-05"}, // Pacific/Easter {"Chatham Islands Standard Time", {"+1245", "+1345"}}, // Pacific/Chatham
"Fiji Standard Time" = {"+12", "+12"}, // Pacific/Fiji {"Easter Island Standard Time", {"-06", "-05"}}, // Pacific/Easter
"Central Pacific Standard Time" = {"+11", "+11"}, // Pacific/Guadalcanal {"Fiji Standard Time", {"+12", "+12"}}, // Pacific/Fiji
"Hawaiian Standard Time" = {"HST", "HST"}, // Pacific/Honolulu {"Central Pacific Standard Time", {"+11", "+11"}}, // Pacific/Guadalcanal
"Line Islands Standard Time" = {"+14", "+14"}, // Pacific/Kiritimati {"Hawaiian Standard Time", {"HST", "HST"}}, // Pacific/Honolulu
"Marquesas Standard Time" = {"-0930", "-0930"}, // Pacific/Marquesas {"Line Islands Standard Time", {"+14", "+14"}}, // Pacific/Kiritimati
"Norfolk Standard Time" = {"+11", "+12"}, // Pacific/Norfolk {"Marquesas Standard Time", {"-0930", "-0930"}}, // Pacific/Marquesas
"West Pacific Standard Time" = {"+10", "+10"}, // Pacific/Port_Moresby {"Norfolk Standard Time", {"+11", "+12"}}, // Pacific/Norfolk
"Tonga Standard Time" = {"+13", "+13"}, // Pacific/Tongatapu {"West Pacific Standard Time", {"+10", "+10"}}, // Pacific/Port_Moresby
{"Tonga Standard Time", {"+13", "+13"}}, // Pacific/Tongatapu
} }
iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) -> (name: string, success: bool) { iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) -> (name: string, success: bool) {
@@ -269,7 +270,18 @@ _region_load :: proc(reg_str: string, allocator := context.allocator) -> (out_re
defer delete(wintz_name, allocator) defer delete(wintz_name, allocator)
defer delete(iana_name, allocator) defer delete(iana_name, allocator)
abbrevs := tz_abbrevs[wintz_name] or_return abbrevs: TZ_Abbrev
abbrevs_ok: bool
for pair in tz_abbrevs {
if pair.key == wintz_name {
abbrevs = pair.value
abbrevs_ok = true
break
}
}
if !abbrevs_ok {
return
}
if abbrevs.std == "UTC" && abbrevs.dst == abbrevs.std { if abbrevs.std == "UTC" && abbrevs.dst == abbrevs.std {
return nil, true return nil, true
} }
+1
View File
@@ -1,4 +1,5 @@
#+vet !using-stmt !using-param #+vet !using-stmt !using-param
#+feature dynamic-literals
package main package main
import "core:fmt" import "core:fmt"
+12 -6
View File
@@ -324,6 +324,18 @@ u64 get_vet_flag_from_name(String const &name) {
return VetFlag_NONE; return VetFlag_NONE;
} }
enum OptInFeatureFlags : u64 {
OptInFeatureFlag_NONE = 0,
OptInFeatureFlag_DynamicLiterals = 1u<<0,
};
u64 get_feature_flag_from_name(String const &name) {
if (name == "dynamic-literals") {
return OptInFeatureFlag_DynamicLiterals;
}
return OptInFeatureFlag_NONE;
}
enum SanitizerFlags : u32 { enum SanitizerFlags : u32 {
SanitizerFlag_NONE = 0, SanitizerFlag_NONE = 0,
@@ -429,7 +441,6 @@ struct BuildContext {
bool ignore_unknown_attributes; bool ignore_unknown_attributes;
bool no_bounds_check; bool no_bounds_check;
bool no_type_assert; bool no_type_assert;
bool no_dynamic_literals;
bool no_output_files; bool no_output_files;
bool no_crt; bool no_crt;
bool no_rpath; bool no_rpath;
@@ -1855,11 +1866,6 @@ gb_internal bool init_build_paths(String init_filename) {
produces_output_file = true; produces_output_file = true;
} }
if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR ||
build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
bc->no_dynamic_literals = true;
}
if (!produces_output_file) { if (!produces_output_file) {
// Command doesn't produce output files. We're done. // Command doesn't produce output files. We're done.
return true; return true;
+48 -50
View File
@@ -94,12 +94,14 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
return nullptr; return nullptr;
} }
if (e2->state.load() != EntityState_Resolved) { if (e2->state.load() != EntityState_Resolved) {
gbString str = type_to_string(t); e->type = t;
defer (gb_string_free(str));
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
e->type = t_invalid;
return nullptr; return nullptr;
} }
gbString str = type_to_string(t);
defer (gb_string_free(str));
error(operand->expr, "Invalid use of a non-specialized polymorphic type '%s' in %.*s", str, LIT(context_name));
e->type = t_invalid;
return nullptr;
} else if (is_type_empty_union(t)) { } else if (is_type_empty_union(t)) {
gbString str = type_to_string(t); gbString str = type_to_string(t);
defer (gb_string_free(str)); defer (gb_string_free(str));
@@ -971,6 +973,43 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
} }
} }
gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) {
GB_ASSERT(e != nullptr);
GB_ASSERT(e->kind == Entity_Procedure);
String name = e->Procedure.link_name;
mutex_lock(&ctx->info->foreign_mutex);
auto *fp = &ctx->info->foreigns;
StringHashKey key = string_hash_string(name);
Entity **found = string_map_get(fp, key);
if (found && e != *found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (is_type_proc(this_type) && is_type_proc(other_type)) {
if (!are_signatures_similar_enough(this_type, other_type)) {
error(d->proc_lit,
"Redeclaration of foreign procedure '%.*s' with different type signatures\n"
"\tat %s",
LIT(name), token_pos_to_string(pos));
}
} else if (!signature_parameter_similar_enough(this_type, other_type)) {
error(d->proc_lit,
"Foreign entity '%.*s' previously declared elsewhere with a different type\n"
"\tat %s",
LIT(name), token_pos_to_string(pos));
}
} else if (name == "main") {
error(d->proc_lit, "The link name 'main' is reserved for internal use");
} else {
string_map_set(fp, key, e);
}
mutex_unlock(&ctx->info->foreign_mutex);
}
gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == nullptr); GB_ASSERT(e->type == nullptr);
if (d->proc_lit->kind != Ast_ProcLit) { if (d->proc_lit->kind != Ast_ProcLit) {
@@ -1307,57 +1346,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
name = e->Procedure.link_name; name = e->Procedure.link_name;
} }
Entity *foreign_library = init_entity_foreign_library(ctx, e); Entity *foreign_library = init_entity_foreign_library(ctx, e);
if (is_arch_wasm() && foreign_library != nullptr) {
String module_name = str_lit("env");
GB_ASSERT (foreign_library->kind == Entity_LibraryName);
if (foreign_library->LibraryName.paths.count != 1) {
error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td",
LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
}
if (foreign_library->LibraryName.paths.count >= 1) {
module_name = foreign_library->LibraryName.paths[0];
}
if (!string_ends_with(module_name, str_lit(".o"))) {
name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
}
}
e->Procedure.is_foreign = true; e->Procedure.is_foreign = true;
e->Procedure.link_name = name; e->Procedure.link_name = name;
e->Procedure.foreign_library = foreign_library;
mutex_lock(&ctx->info->foreign_mutex); if (is_arch_wasm() && foreign_library != nullptr) {
// NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later
auto *fp = &ctx->info->foreigns; mpsc_enqueue(&ctx->info->foreign_decls_to_check, e);
StringHashKey key = string_hash_string(name);
Entity **found = string_map_get(fp, key);
if (found && e != *found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (is_type_proc(this_type) && is_type_proc(other_type)) {
if (!are_signatures_similar_enough(this_type, other_type)) {
error(d->proc_lit,
"Redeclaration of foreign procedure '%.*s' with different type signatures\n"
"\tat %s",
LIT(name), token_pos_to_string(pos));
}
} else if (!signature_parameter_similar_enough(this_type, other_type)) {
error(d->proc_lit,
"Foreign entity '%.*s' previously declared elsewhere with a different type\n"
"\tat %s",
LIT(name), token_pos_to_string(pos));
}
} else if (name == "main") {
error(d->proc_lit, "The link name 'main' is reserved for internal use");
} else { } else {
string_map_set(fp, key, e); check_foreign_procedure(ctx, e, d);
} }
mutex_unlock(&ctx->info->foreign_mutex);
} else { } else {
String name = e->token.string; String name = e->token.string;
if (e->Procedure.link_name.len > 0) { if (e->Procedure.link_name.len > 0) {
+53 -10
View File
@@ -3672,6 +3672,13 @@ gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x
} }
} }
} }
if (is_type_simd_vector(x->type) && !is_type_simd_vector(y->type)) {
if (check_is_assignable_to(c, y, x->type)) {
if (check_binary_op(c, x, op)) {
return true;
}
}
}
return false; return false;
} }
@@ -4556,6 +4563,19 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
break; break;
} }
case Type_SimdVector: {
Type *elem = base_array_type(t);
if (check_is_assignable_to(c, operand, elem)) {
operand->mode = Addressing_Value;
} else {
operand->mode = Addressing_Invalid;
convert_untyped_error(c, operand, target_type);
return;
}
break;
}
case Type_Matrix: { case Type_Matrix: {
Type *elem = base_array_type(t); Type *elem = base_array_type(t);
if (check_is_assignable_to(c, operand, elem)) { if (check_is_assignable_to(c, operand, elem)) {
@@ -8725,6 +8745,18 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
error(node, "#caller_expression may only be used as a default argument parameter"); error(node, "#caller_expression may only be used as a default argument parameter");
o->type = t_string; o->type = t_string;
o->mode = Addressing_Value; o->mode = Addressing_Value;
} else if (name == "branch_location") {
if (!c->in_defer) {
error(node, "#branch_location may only be used within a 'defer' statement");
} else if (c->curr_proc_decl) {
Entity *e = c->curr_proc_decl->entity;
if (e != nullptr) {
GB_ASSERT(e->kind == Entity_Procedure);
e->Procedure.uses_branch_location = true;
}
}
o->type = t_source_code_location;
o->mode = Addressing_Value;
} else { } else {
if (name == "location") { if (name == "location") {
init_core_source_code_location(c->checker); init_core_source_code_location(c->checker);
@@ -9339,6 +9371,23 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {
return false; return false;
} }
gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) {
if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) {
ERROR_BLOCK();
error(node, "Compound literals of dynamic types are disabled by default");
error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n");
error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n");
if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) {
error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n");
} else if (build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n");
}
return false;
}
return cl->elems.count > 0;
}
gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
ExprKind kind = Expr_Expr; ExprKind kind = Expr_Expr;
ast_node(cl, CompoundLit, node); ast_node(cl, CompoundLit, node);
@@ -9539,11 +9588,6 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
elem_type = t->DynamicArray.elem; elem_type = t->DynamicArray.elem;
context_name = str_lit("dynamic array literal"); context_name = str_lit("dynamic array literal");
is_constant = false; is_constant = false;
if (!build_context.no_dynamic_literals) {
add_package_dependency(c, "runtime", "__dynamic_array_reserve");
add_package_dependency(c, "runtime", "__dynamic_array_append");
}
} else if (t->kind == Type_SimdVector) { } else if (t->kind == Type_SimdVector) {
elem_type = t->SimdVector.elem; elem_type = t->SimdVector.elem;
context_name = str_lit("simd vector literal"); context_name = str_lit("simd vector literal");
@@ -9718,8 +9762,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
if (t->kind == Type_DynamicArray) { if (t->kind == Type_DynamicArray) {
if (build_context.no_dynamic_literals && cl->elems.count) { if (check_for_dynamic_literals(c, node, cl)) {
error(node, "Compound literals of dynamic types have been disabled"); add_package_dependency(c, "runtime", "__dynamic_array_reserve");
add_package_dependency(c, "runtime", "__dynamic_array_append");
} }
} }
@@ -10108,9 +10153,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
} }
} }
if (build_context.no_dynamic_literals && cl->elems.count) { if (check_for_dynamic_literals(c, node, cl)) {
error(node, "Compound literals of dynamic types have been disabled");
} else {
add_map_reserve_dependencies(c); add_map_reserve_dependencies(c);
add_map_set_dependencies(c); add_map_set_dependencies(c);
} }
+8 -1
View File
@@ -2440,8 +2440,12 @@ gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc
bool success = true; bool success = true;
isize specialization_count = 0; isize specialization_count = 0;
Type *params = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands); Type *params = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands);
Type *results = check_get_results(c, c->scope, pt->results);
bool no_poly_return = c->disallow_polymorphic_return_types;
c->disallow_polymorphic_return_types = c->scope == c->polymorphic_scope;
// NOTE(zen3ger): if the parapoly scope is the current proc's scope, then the return types shall not declare new poly vars
Type *results = check_get_results(c, c->scope, pt->results);
c->disallow_polymorphic_return_types = no_poly_return;
isize param_count = 0; isize param_count = 0;
isize result_count = 0; isize result_count = 0;
@@ -3383,6 +3387,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
} }
Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific); Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific);
if (ctx->allow_polymorphic_types) { if (ctx->allow_polymorphic_types) {
if (ctx->disallow_polymorphic_return_types) {
error(ident, "Undeclared polymorphic parameter '%.*s' in return type", LIT(token.string));
}
Scope *ps = ctx->polymorphic_scope; Scope *ps = ctx->polymorphic_scope;
Scope *s = ctx->scope; Scope *s = ctx->scope;
Scope *entity_scope = s; Scope *entity_scope = s;
+51 -1
View File
@@ -542,6 +542,23 @@ gb_internal u64 check_vet_flags(Ast *node) {
return ast_file_vet_flags(file); return ast_file_vet_flags(file);
} }
gb_internal u64 check_feature_flags(CheckerContext *c, Ast *node) {
AstFile *file = c->file;
if (file == nullptr &&
c->curr_proc_decl &&
c->curr_proc_decl->proc_lit) {
file = c->curr_proc_decl->proc_lit->file();
}
if (file == nullptr) {
file = node->file();
}
if (file != nullptr && file->feature_flags_set) {
return file->feature_flags;
}
return 0;
}
enum VettedEntityKind { enum VettedEntityKind {
VettedEntity_Invalid, VettedEntity_Invalid,
@@ -1164,7 +1181,6 @@ gb_internal void init_universal(void) {
add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check); add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check);
add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert); add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert);
add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR); add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR);
add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals);
add_global_bool_constant("ODIN_NO_CRT", bc->no_crt); add_global_bool_constant("ODIN_NO_CRT", bc->no_crt);
add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules); add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules);
add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test);
@@ -1356,6 +1372,7 @@ gb_internal void init_checker_info(CheckerInfo *i) {
mpsc_init(&i->required_global_variable_queue, a); // 1<<10); mpsc_init(&i->required_global_variable_queue, a); // 1<<10);
mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10); mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10);
mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10); mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10);
mpsc_init(&i->foreign_decls_to_check, a); // 1<<10);
mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used
string_map_init(&i->load_directory_cache); string_map_init(&i->load_directory_cache);
@@ -1382,6 +1399,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
mpsc_destroy(&i->required_global_variable_queue); mpsc_destroy(&i->required_global_variable_queue);
mpsc_destroy(&i->required_foreign_imports_through_force_queue); mpsc_destroy(&i->required_foreign_imports_through_force_queue);
mpsc_destroy(&i->foreign_imports_to_check_fullpaths); mpsc_destroy(&i->foreign_imports_to_check_fullpaths);
mpsc_destroy(&i->foreign_decls_to_check);
map_destroy(&i->objc_msgSend_types); map_destroy(&i->objc_msgSend_types);
string_map_destroy(&i->load_file_cache); string_map_destroy(&i->load_file_cache);
@@ -5094,6 +5112,38 @@ gb_internal void check_foreign_import_fullpaths(Checker *c) {
e->LibraryName.paths = fl->fullpaths; e->LibraryName.paths = fl->fullpaths;
} }
for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_decls_to_check, &e); /**/) {
GB_ASSERT(e != nullptr);
if (e->kind != Entity_Procedure) {
continue;
}
if (!is_arch_wasm()) {
continue;
}
Entity *foreign_library = e->Procedure.foreign_library;
GB_ASSERT(foreign_library != nullptr);
String name = e->Procedure.link_name;
String module_name = str_lit("env");
GB_ASSERT (foreign_library->kind == Entity_LibraryName);
if (foreign_library->LibraryName.paths.count != 1) {
error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td",
LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
}
if (foreign_library->LibraryName.paths.count >= 1) {
module_name = foreign_library->LibraryName.paths[0];
}
if (!string_ends_with(module_name, str_lit(".o"))) {
name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
}
e->Procedure.link_name = name;
check_foreign_procedure(&ctx, e, e->decl_info);
}
} }
gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
+2
View File
@@ -461,6 +461,7 @@ struct CheckerInfo {
MPSCQueue<Entity *> required_global_variable_queue; MPSCQueue<Entity *> required_global_variable_queue;
MPSCQueue<Entity *> required_foreign_imports_through_force_queue; MPSCQueue<Entity *> required_foreign_imports_through_force_queue;
MPSCQueue<Entity *> foreign_imports_to_check_fullpaths; MPSCQueue<Entity *> foreign_imports_to_check_fullpaths;
MPSCQueue<Entity *> foreign_decls_to_check;
MPSCQueue<Ast *> intrinsics_entry_point_usage; MPSCQueue<Ast *> intrinsics_entry_point_usage;
@@ -521,6 +522,7 @@ struct CheckerContext {
bool in_enum_type; bool in_enum_type;
bool collect_delayed_decls; bool collect_delayed_decls;
bool allow_polymorphic_types; bool allow_polymorphic_types;
bool disallow_polymorphic_return_types; // NOTE(zen3ger): no poly type decl in return types
bool no_polymorphic_errors; bool no_polymorphic_errors;
bool hide_polymorphic_errors; bool hide_polymorphic_errors;
bool in_polymorphic_specialization; bool in_polymorphic_specialization;
+1
View File
@@ -256,6 +256,7 @@ struct Entity {
bool entry_point_only : 1; bool entry_point_only : 1;
bool has_instrumentation : 1; bool has_instrumentation : 1;
bool is_memcpy_like : 1; bool is_memcpy_like : 1;
bool uses_branch_location : 1;
} Procedure; } Procedure;
struct { struct {
Array<Entity *> entities; Array<Entity *> entities;
-2
View File
@@ -1096,8 +1096,6 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_
} }
gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) { gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) {
GB_ASSERT(!build_context.no_dynamic_literals);
TEMPORARY_ALLOCATOR_GUARD(); TEMPORARY_ALLOCATOR_GUARD();
String proc_name = {}; String proc_name = {};
+8 -1
View File
@@ -359,6 +359,10 @@ struct lbProcedure {
bool in_multi_assignment; bool in_multi_assignment;
Array<LLVMValueRef> raw_input_parameters; Array<LLVMValueRef> raw_input_parameters;
bool uses_branch_location;
TokenPos branch_location_pos;
TokenPos curr_token_pos;
Array<lbVariadicReuseSlices> variadic_reuses; Array<lbVariadicReuseSlices> variadic_reuses;
lbAddr variadic_reuse_base_array_ptr; lbAddr variadic_reuse_base_array_ptr;
@@ -444,7 +448,8 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz
gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type); gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type);
gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type); gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type);
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block); gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos);
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node);
gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t); gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right); gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none); gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none);
@@ -742,3 +747,5 @@ gb_global char const *llvm_linkage_strings[] = {
}; };
#define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed") #define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed")
#define ODIN_METADATA_MIN_ALIGN str_lit("odin-min-align")
#define ODIN_METADATA_MAX_ALIGN str_lit("odin-max-align")
+11 -5
View File
@@ -3502,7 +3502,13 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
case_ast_node(bd, BasicDirective, expr); case_ast_node(bd, BasicDirective, expr);
TokenPos pos = bd->token.pos; TokenPos pos = bd->token.pos;
GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); String name = bd->name.string;
if (name == "branch_location") {
GB_ASSERT(p->uses_branch_location);
String proc_name = p->entity->token.string;
return lb_emit_source_code_location_as_global(p, proc_name, p->branch_location_pos);
}
GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(name));
case_end; case_end;
case_ast_node(i, Implicit, expr); case_ast_node(i, Implicit, expr);
@@ -3668,7 +3674,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
lb_start_block(p, else_); lb_start_block(p, else_);
lb_emit_defer_stmts(p, lbDeferExit_Branch, block); lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr);
lb_emit_jump(p, block); lb_emit_jump(p, block);
lb_start_block(p, then); lb_start_block(p, then);
@@ -4807,7 +4813,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
if (cl->elems.count == 0) { if (cl->elems.count == 0) {
break; break;
} }
GB_ASSERT(!build_context.no_dynamic_literals); GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
gb_unused(err); gb_unused(err);
@@ -4896,7 +4902,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
if (cl->elems.count == 0) { if (cl->elems.count == 0) {
break; break;
} }
GB_ASSERT(!build_context.no_dynamic_literals); GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
Type *et = bt->DynamicArray.elem; Type *et = bt->DynamicArray.elem;
lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); lbValue size = lb_const_int(p->module, t_int, type_size_of(et));
@@ -5493,7 +5499,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
lb_start_block(p, else_); lb_start_block(p, else_);
lb_emit_defer_stmts(p, lbDeferExit_Branch, block); lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr);
lb_emit_jump(p, block); lb_emit_jump(p, block);
lb_start_block(p, then); lb_start_block(p, then);
+17 -1
View File
@@ -734,6 +734,17 @@ gb_internal LLVMValueRef OdinLLVMBuildLoad(lbProcedure *p, LLVMTypeRef type, LLV
if (is_packed != 0) { if (is_packed != 0) {
LLVMSetAlignment(result, 1); LLVMSetAlignment(result, 1);
} }
u64 align = LLVMGetAlignment(result);
u64 align_min = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MIN_ALIGN);
u64 align_max = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MAX_ALIGN);
if (align_min != 0 && align < align_min) {
align = align_min;
}
if (align_max != 0 && align > align_max) {
align = align_max;
}
GB_ASSERT(align <= UINT_MAX);
LLVMSetAlignment(result, (unsigned int)align);
} }
return result; return result;
@@ -2121,6 +2132,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
} }
i64 prev_offset = 0; i64 prev_offset = 0;
bool requires_packing = type->Struct.is_packed;
for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) { for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) {
Entity *field = type->Struct.fields[field_index]; Entity *field = type->Struct.fields[field_index];
i64 offset = type->Struct.offsets[field_index]; i64 offset = type->Struct.offsets[field_index];
@@ -2141,6 +2153,10 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
field_type = t_rawptr; field_type = t_rawptr;
} }
// max_field_align might misalign items in a way that requires packing
// so check the alignment of all fields to see if packing is required.
requires_packing = requires_packing || ((offset % type_align_of(field_type)) != 0);
array_add(&fields, lb_type(m, field_type)); array_add(&fields, lb_type(m, field_type));
prev_offset = offset + type_size_of(field->type); prev_offset = offset + type_size_of(field->type);
@@ -2155,7 +2171,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
GB_ASSERT(fields[i] != nullptr); GB_ASSERT(fields[i] != nullptr);
} }
LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, type->Struct.is_packed); LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, requires_packing);
map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping); map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
map_set(&m->struct_field_remapping, cast(void *)type, field_remapping); map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);
#if 0 #if 0
+5 -1
View File
@@ -125,6 +125,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
// map_init(&p->selector_addr, 0); // map_init(&p->selector_addr, 0);
// map_init(&p->tuple_fix_map, 0); // map_init(&p->tuple_fix_map, 0);
if (p->entity != nullptr && p->entity->Procedure.uses_branch_location) {
p->uses_branch_location = true;
}
if (p->is_foreign) { if (p->is_foreign) {
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
} }
@@ -757,7 +761,7 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) {
if (p->type->Proc.result_count == 0) { if (p->type->Proc.result_count == 0) {
instr = LLVMGetLastInstruction(p->curr_block->block); instr = LLVMGetLastInstruction(p->curr_block->block);
if (!lb_is_instr_terminating(instr)) { if (!lb_is_instr_terminating(instr)) {
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, p->body);
lb_set_debug_position_to_procedure_end(p); lb_set_debug_position_to_procedure_end(p);
LLVMBuildRetVoid(p->builder); LLVMBuildRetVoid(p->builder);
} }
+52 -29
View File
@@ -208,8 +208,8 @@ gb_internal void lb_open_scope(lbProcedure *p, Scope *s) {
} }
gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) { gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node, bool pop_stack=true) {
lb_emit_defer_stmts(p, kind, block); lb_emit_defer_stmts(p, kind, block, node);
GB_ASSERT(p->scope_index > 0); GB_ASSERT(p->scope_index > 0);
// NOTE(bill): Remove `context`s made in that scope // NOTE(bill): Remove `context`s made in that scope
@@ -721,7 +721,7 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
lb_build_stmt(p, rs->body); lb_build_stmt(p, rs->body);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, node->left);
lb_pop_target_list(p); lb_pop_target_list(p);
if (check != nullptr) { if (check != nullptr) {
@@ -854,7 +854,7 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s
lb_build_stmt(p, rs->body); lb_build_stmt(p, rs->body);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
lb_pop_target_list(p); lb_pop_target_list(p);
lb_emit_jump(p, loop); lb_emit_jump(p, loop);
lb_start_block(p, done); lb_start_block(p, done);
@@ -976,7 +976,7 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
lb_build_stmt(p, rs->body); lb_build_stmt(p, rs->body);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
lb_pop_target_list(p); lb_pop_target_list(p);
lb_emit_jump(p, loop); lb_emit_jump(p, loop);
lb_start_block(p, done); lb_start_block(p, done);
@@ -1192,7 +1192,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
lb_build_stmt(p, rs->body); lb_build_stmt(p, rs->body);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
lb_pop_target_list(p); lb_pop_target_list(p);
lb_emit_jump(p, loop); lb_emit_jump(p, loop);
lb_start_block(p, done); lb_start_block(p, done);
@@ -1363,7 +1363,7 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *
} }
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
} }
gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) { gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) {
@@ -1433,6 +1433,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
ast_node(body, BlockStmt, ss->body); ast_node(body, BlockStmt, ss->body);
isize case_count = body->stmts.count; isize case_count = body->stmts.count;
Ast *default_clause = nullptr;
Slice<Ast *> default_stmts = {}; Slice<Ast *> default_stmts = {};
lbBlock *default_fall = nullptr; lbBlock *default_fall = nullptr;
lbBlock *default_block = nullptr; lbBlock *default_block = nullptr;
@@ -1482,6 +1483,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
if (cc->list.count == 0) { if (cc->list.count == 0) {
// default case // default case
default_clause = clause;
default_stmts = cc->stmts; default_stmts = cc->stmts;
default_fall = fall; default_fall = fall;
if (switch_instr == nullptr) { if (switch_instr == nullptr) {
@@ -1552,7 +1554,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
lb_push_target_list(p, ss->label, done, nullptr, fall); lb_push_target_list(p, ss->label, done, nullptr, fall);
lb_open_scope(p, body->scope); lb_open_scope(p, body->scope);
lb_build_stmt_list(p, cc->stmts); lb_build_stmt_list(p, cc->stmts);
lb_close_scope(p, lbDeferExit_Default, body); lb_close_scope(p, lbDeferExit_Default, body, clause);
lb_pop_target_list(p); lb_pop_target_list(p);
lb_emit_jump(p, done); lb_emit_jump(p, done);
@@ -1570,13 +1572,13 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
lb_push_target_list(p, ss->label, done, nullptr, default_fall); lb_push_target_list(p, ss->label, done, nullptr, default_fall);
lb_open_scope(p, default_block->scope); lb_open_scope(p, default_block->scope);
lb_build_stmt_list(p, default_stmts); lb_build_stmt_list(p, default_stmts);
lb_close_scope(p, lbDeferExit_Default, default_block); lb_close_scope(p, lbDeferExit_Default, default_block, default_clause);
lb_pop_target_list(p); lb_pop_target_list(p);
} }
lb_emit_jump(p, done); lb_emit_jump(p, done);
lb_start_block(p, done); lb_start_block(p, done);
lb_close_scope(p, lbDeferExit_Default, done); lb_close_scope(p, lbDeferExit_Default, done, ss->body);
} }
gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) { gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) {
@@ -1627,7 +1629,7 @@ gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBl
lb_push_target_list(p, label, done, nullptr, nullptr); lb_push_target_list(p, label, done, nullptr, nullptr);
lb_build_stmt_list(p, cc->stmts); lb_build_stmt_list(p, cc->stmts);
lb_close_scope(p, lbDeferExit_Default, body); lb_close_scope(p, lbDeferExit_Default, body, clause);
lb_pop_target_list(p); lb_pop_target_list(p);
lb_emit_jump(p, done); lb_emit_jump(p, done);
@@ -1835,7 +1837,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
lb_emit_jump(p, done); lb_emit_jump(p, done);
lb_start_block(p, done); lb_start_block(p, done);
lb_close_scope(p, lbDeferExit_Default, done); lb_close_scope(p, lbDeferExit_Default, done, ss->body);
} }
@@ -1959,7 +1961,7 @@ gb_internal void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice
p->in_multi_assignment = prev_in_assignment; p->in_multi_assignment = prev_in_assignment;
} }
gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos) {
lbFunctionType *ft = lb_get_function_type(p->module, p->type); lbFunctionType *ft = lb_get_function_type(p->module, p->type);
bool return_by_pointer = ft->ret.kind == lbArg_Indirect; bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
bool split_returns = ft->multiple_return_original_type != nullptr; bool split_returns = ft->multiple_return_original_type != nullptr;
@@ -1982,7 +1984,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value); LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value);
} }
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
// Check for terminator in the defer stmts // Check for terminator in the defer stmts
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2012,7 +2014,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type); ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type);
} }
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
// Check for terminator in the defer stmts // Check for terminator in the defer stmts
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2021,7 +2023,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
} }
} }
} }
gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) { gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results, TokenPos pos) {
lb_ensure_abi_function_type(p->module, p); lb_ensure_abi_function_type(p->module, p);
isize return_count = p->type->Proc.result_count; isize return_count = p->type->Proc.result_count;
@@ -2029,7 +2031,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
if (return_count == 0) { if (return_count == 0) {
// No return values // No return values
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
// Check for terminator in the defer stmts // Check for terminator in the defer stmts
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2138,11 +2140,11 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
GB_ASSERT(result_values.count-1 == result_eps.count); GB_ASSERT(result_values.count-1 == result_eps.count);
lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]); lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]);
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
LLVMBuildRetVoid(p->builder); LLVMBuildRetVoid(p->builder);
return; return;
} else { } else {
return lb_build_return_stmt_internal(p, result_values[result_values.count-1]); return lb_build_return_stmt_internal(p, result_values[result_values.count-1], pos);
} }
} else { } else {
@@ -2169,7 +2171,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
} }
if (return_by_pointer) { if (return_by_pointer) {
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
LLVMBuildRetVoid(p->builder); LLVMBuildRetVoid(p->builder);
return; return;
} }
@@ -2177,13 +2179,13 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
res = lb_emit_load(p, res); res = lb_emit_load(p, res);
} }
} }
lb_build_return_stmt_internal(p, res); lb_build_return_stmt_internal(p, res, pos);
} }
gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
ast_node(is, IfStmt, node); ast_node(is, IfStmt, node);
lb_open_scope(p, is->scope); // Scope #1 lb_open_scope(p, is->scope); // Scope #1
defer (lb_close_scope(p, lbDeferExit_Default, nullptr)); defer (lb_close_scope(p, lbDeferExit_Default, nullptr, node));
lbBlock *then = lb_create_block(p, "if.then"); lbBlock *then = lb_create_block(p, "if.then");
lbBlock *done = lb_create_block(p, "if.done"); lbBlock *done = lb_create_block(p, "if.done");
@@ -2234,7 +2236,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
lb_open_scope(p, scope_of_node(is->else_stmt)); lb_open_scope(p, scope_of_node(is->else_stmt));
lb_build_stmt(p, is->else_stmt); lb_build_stmt(p, is->else_stmt);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt);
} }
lb_emit_jump(p, done); lb_emit_jump(p, done);
@@ -2251,7 +2253,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
lb_open_scope(p, scope_of_node(is->else_stmt)); lb_open_scope(p, scope_of_node(is->else_stmt));
lb_build_stmt(p, is->else_stmt); lb_build_stmt(p, is->else_stmt);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt);
lb_emit_jump(p, done); lb_emit_jump(p, done);
} }
@@ -2322,7 +2324,7 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
} }
lb_start_block(p, done); lb_start_block(p, done);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, node);
} }
gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) { gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
@@ -2588,7 +2590,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
lb_open_scope(p, bs->scope); lb_open_scope(p, bs->scope);
lb_build_stmt_list(p, bs->stmts); lb_build_stmt_list(p, bs->stmts);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr, node);
if (done != nullptr) { if (done != nullptr) {
lb_emit_jump(p, done); lb_emit_jump(p, done);
@@ -2702,7 +2704,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
case_end; case_end;
case_ast_node(rs, ReturnStmt, node); case_ast_node(rs, ReturnStmt, node);
lb_build_return_stmt(p, rs->results); lb_build_return_stmt(p, rs->results, ast_token(node).pos);
case_end; case_end;
case_ast_node(is, IfStmt, node); case_ast_node(is, IfStmt, node);
@@ -2755,7 +2757,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
} }
} }
if (block != nullptr) { if (block != nullptr) {
lb_emit_defer_stmts(p, lbDeferExit_Branch, block); lb_emit_defer_stmts(p, lbDeferExit_Branch, block, node);
} }
lb_emit_jump(p, block); lb_emit_jump(p, block);
lb_start_block(p, lb_create_block(p, "unreachable")); lb_start_block(p, lb_create_block(p, "unreachable"));
@@ -2795,7 +2797,13 @@ gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
} }
} }
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) { gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos) {
TokenPos prev_token_pos = p->branch_location_pos;
if (p->uses_branch_location) {
p->branch_location_pos = pos;
}
defer (p->branch_location_pos = prev_token_pos);
isize count = p->defer_stmts.count; isize count = p->defer_stmts.count;
isize i = count; isize i = count;
while (i --> 0) { while (i --> 0) {
@@ -2822,6 +2830,21 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo
} }
} }
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node) {
TokenPos pos = {};
if (node) {
if (node->kind == Ast_BlockStmt) {
pos = ast_end_token(node).pos;
} else if (node->kind == Ast_CaseClause) {
pos = ast_end_token(node).pos;
} else {
pos = ast_token(node).pos;
}
}
return lb_emit_defer_stmts(p, kind, block, pos);
}
gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) { gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
Type *pt = base_type(p->type); Type *pt = base_type(p->type);
GB_ASSERT(pt->kind == Type_Proc); GB_ASSERT(pt->kind == Type_Proc);
+20 -7
View File
@@ -476,8 +476,8 @@ gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, Ty
} }
} }
gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results); gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results, TokenPos pos);
gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res); gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos);
gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) { gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
lbValue lhs = {}; lbValue lhs = {};
@@ -506,10 +506,10 @@ gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue con
lbValue found = map_must_get(&p->module->values, end_entity); lbValue found = map_must_get(&p->module->values, end_entity);
lb_emit_store(p, found, rhs); lb_emit_store(p, found, rhs);
lb_build_return_stmt(p, {}); lb_build_return_stmt(p, {}, ast_token(arg).pos);
} else { } else {
GB_ASSERT(tuple->variables.count == 1); GB_ASSERT(tuple->variables.count == 1);
lb_build_return_stmt_internal(p, rhs); lb_build_return_stmt_internal(p, rhs, ast_token(arg).pos);
} }
} }
lb_start_block(p, continue_block); lb_start_block(p, continue_block);
@@ -1200,9 +1200,22 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
lbValue gep = lb_emit_struct_ep_internal(p, s, index, result_type); lbValue gep = lb_emit_struct_ep_internal(p, s, index, result_type);
Type *bt = base_type(t); Type *bt = base_type(t);
if (bt->kind == Type_Struct && bt->Struct.is_packed) { if (bt->kind == Type_Struct) {
lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1); if (bt->Struct.is_packed) {
GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1); lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1);
GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1);
}
u64 align_max = bt->Struct.custom_max_field_align;
u64 align_min = bt->Struct.custom_min_field_align;
GB_ASSERT(align_min == 0 || align_max == 0 || align_min <= align_max);
if (align_max) {
lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN, align_max);
GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN) == align_max);
}
if (align_min) {
lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN, align_min);
GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN) == align_min);
}
} }
return gep; return gep;
+3 -3
View File
@@ -1192,7 +1192,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.no_type_assert = true; build_context.no_type_assert = true;
break; break;
case BuildFlag_NoDynamicLiterals: case BuildFlag_NoDynamicLiterals:
build_context.no_dynamic_literals = true; gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n");
break; break;
case BuildFlag_NoCRT: case BuildFlag_NoCRT:
build_context.no_crt = true; build_context.no_crt = true;
@@ -2120,7 +2120,7 @@ gb_internal void export_dependencies(Checker *c) {
for_array(i, files) { for_array(i, files) {
AstFile *file = files[i]; AstFile *file = files[i];
gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath)); gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath));
if (i+1 == files.count) { if (i+1 < files.count) {
gb_fprintf(&f, ","); gb_fprintf(&f, ",");
} }
gb_fprintf(&f, "\n"); gb_fprintf(&f, "\n");
@@ -2133,7 +2133,7 @@ gb_internal void export_dependencies(Checker *c) {
for_array(i, load_files) { for_array(i, load_files) {
LoadFileCache *cache = load_files[i]; LoadFileCache *cache = load_files[i];
gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path)); gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path));
if (i+1 == load_files.count) { if (i+1 < load_files.count) {
gb_fprintf(&f, ","); gb_fprintf(&f, ",");
} }
gb_fprintf(&f, "\n"); gb_fprintf(&f, "\n");
+67 -3
View File
@@ -6265,10 +6265,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p)); syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p));
error_line("\tExpected one of the following\n"); error_line("\tExpected one of the following\n");
error_line("\tunused\n"); error_line("\tunused\n");
error_line("\tunused-variables\n");
error_line("\tunused-imports\n");
error_line("\tunused-procedures\n");
error_line("\tshadowing\n"); error_line("\tshadowing\n");
error_line("\tusing-stmt\n"); error_line("\tusing-stmt\n");
error_line("\tusing-param\n"); error_line("\tusing-param\n");
error_line("\tstyle\n");
error_line("\textra\n"); error_line("\textra\n");
error_line("\tcast\n");
error_line("\ttabs\n");
return build_context.vet_flags; return build_context.vet_flags;
} }
} }
@@ -6286,6 +6292,63 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
return vet_flags &~ vet_not_flags; return vet_flags &~ vet_not_flags;
} }
gb_internal u64 parse_feature_tag(Token token_for_pos, String s) {
String const prefix = str_lit("feature");
GB_ASSERT(string_starts_with(s, prefix));
s = string_trim_whitespace(substring(s, prefix.len, s.len));
if (s.len == 0) {
return OptInFeatureFlag_NONE;
}
u64 feature_flags = 0;
u64 feature_not_flags = 0;
while (s.len > 0) {
String p = string_trim_whitespace(vet_tag_get_token(s, &s));
if (p.len == 0) {
break;
}
bool is_notted = false;
if (p[0] == '!') {
is_notted = true;
p = substring(p, 1, p.len);
if (p.len == 0) {
syntax_error(token_for_pos, "Expected a feature flag name after '!'");
return OptInFeatureFlag_NONE;
}
}
u64 flag = get_feature_flag_from_name(p);
if (flag != OptInFeatureFlag_NONE) {
if (is_notted) {
feature_not_flags |= flag;
} else {
feature_flags |= flag;
}
} else {
ERROR_BLOCK();
syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p));
error_line("\tExpected one of the following\n");
error_line("\tdynamic-literals\n");
return OptInFeatureFlag_NONE;
}
}
if (feature_flags == 0 && feature_not_flags == 0) {
return OptInFeatureFlag_NONE;
}
if (feature_flags == 0 && feature_not_flags != 0) {
return OptInFeatureFlag_NONE &~ feature_not_flags;
}
if (feature_flags != 0 && feature_not_flags == 0) {
return feature_flags;
}
GB_ASSERT(feature_flags != 0 && feature_not_flags != 0);
return feature_flags &~ feature_not_flags;
}
gb_internal String dir_from_path(String path) { gb_internal String dir_from_path(String path) {
String base_dir = path; String base_dir = path;
for (isize i = path.len-1; i >= 0; i--) { for (isize i = path.len-1; i >= 0; i--) {
@@ -6399,6 +6462,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f)
} else if (command == "file") { } else if (command == "file") {
f->flags |= AstFile_IsPrivateFile; f->flags |= AstFile_IsPrivateFile;
} }
} else if (string_starts_with(lc, str_lit("feature"))) {
f->feature_flags |= parse_feature_tag(tok, lc);
f->feature_flags_set = true;
} else if (lc == "lazy") { } else if (lc == "lazy") {
if (build_context.ignore_lazy) { if (build_context.ignore_lazy) {
// Ignore // Ignore
@@ -6493,9 +6559,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
} }
f->package_name = package_name.string; f->package_name = package_name.string;
// TODO: Shouldn't single file only matter for build tags? no-instrumentation for example {
// should be respected even when in single file mode.
if (!f->pkg->is_single_file) {
if (docs != nullptr && docs->list.count > 0) { if (docs != nullptr && docs->list.count > 0) {
for (Token const &tok : docs->list) { for (Token const &tok : docs->list) {
GB_ASSERT(tok.kind == Token_Comment); GB_ASSERT(tok.kind == Token_Comment);
+2
View File
@@ -108,7 +108,9 @@ struct AstFile {
String package_name; String package_name;
u64 vet_flags; u64 vet_flags;
u64 feature_flags;
bool vet_flags_set; bool vet_flags_set;
bool feature_flags_set;
// >= 0: In Expression // >= 0: In Expression
// < 0: In Control Clause // < 0: In Control Clause
@@ -1,3 +1,4 @@
#+feature dynamic-literals
package test_encoding_cbor package test_encoding_cbor
import "base:intrinsics" import "base:intrinsics"
+1
View File
@@ -1,3 +1,4 @@
#+feature dynamic-literals
package test_core_fmt package test_core_fmt
import "base:runtime" import "base:runtime"
+1
View File
@@ -1,3 +1,4 @@
#+feature dynamic-literals
package test_core_hash package test_core_hash
import "core:hash/xxhash" import "core:hash/xxhash"
+1
View File
@@ -1,4 +1,5 @@
// Hash Test Vectors // Hash Test Vectors
#+feature dynamic-literals
package test_core_hash package test_core_hash
XXHASH_Test_Vectors :: struct #packed { XXHASH_Test_Vectors :: struct #packed {
+1
View File
@@ -7,6 +7,7 @@
A test suite for PNG, TGA, NetPBM, QOI and BMP. A test suite for PNG, TGA, NetPBM, QOI and BMP.
*/ */
#+feature dynamic-literals
package test_core_image package test_core_image
import "core:testing" import "core:testing"
+1
View File
@@ -12,6 +12,7 @@
*/ */
#+build !netbsd #+build !netbsd
#+build !openbsd #+build !openbsd
#+feature dynamic-literals
package test_core_net package test_core_net
import "core:testing" import "core:testing"
+99 -1
View File
@@ -1,3 +1,4 @@
#+feature dynamic-literals
package test_core_runtime package test_core_runtime
import "base:intrinsics" import "base:intrinsics"
@@ -63,4 +64,101 @@ test_init_cap_map_dynarray :: proc(t: ^testing.T) {
defer delete(d2) defer delete(d2)
testing.expect(t, cap(d2) == 0) testing.expect(t, cap(d2) == 0)
testing.expect(t, d2.allocator.procedure == ally.procedure) testing.expect(t, d2.allocator.procedure == ally.procedure)
} }
@(test)
test_map_get :: proc(t: ^testing.T) {
check :: proc(t: ^testing.T, m: map[$K]$V, loc := #caller_location) {
for k, v in m {
got_key, got_val, ok := runtime.map_get(m, k)
testing.expect_value(t, got_key, k, loc = loc)
testing.expect_value(t, got_val, v, loc = loc)
testing.expect(t, ok, loc = loc)
}
}
// small keys & values
{
m := map[int]int{
1 = 10,
2 = 20,
3 = 30,
}
defer delete(m)
check(t, m)
}
// small keys; 2 values per cell
{
m := map[int][3]int{
1 = [3]int{10, 100, 1000},
2 = [3]int{20, 200, 2000},
3 = [3]int{30, 300, 3000},
}
defer delete(m)
check(t, m)
}
// 2 keys per cell; small values
{
m := map[[3]int]int{
[3]int{10, 100, 1000} = 1,
[3]int{20, 200, 2000} = 2,
[3]int{30, 300, 3000} = 3,
}
defer delete(m)
check(t, m)
}
// small keys; 3 values per cell
{
val :: struct #packed {
a, b: int,
c: i32,
}
m := map[int]val{
1 = val{10, 100, 1000},
2 = val{20, 200, 2000},
3 = val{30, 300, 3000},
}
defer delete(m)
check(t, m)
}
// 3 keys per cell; small values
{
key :: struct #packed {
a, b: int,
c: i32,
}
m := map[key]int{
key{10, 100, 1000} = 1,
key{20, 200, 2000} = 2,
key{30, 300, 3000} = 3,
}
defer delete(m)
check(t, m)
}
// small keys; value bigger than a chacheline
{
m := map[int][9]int{
1 = [9]int{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000},
2 = [9]int{20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000},
3 = [9]int{30, 300, 3000, 30000, 300000, 3000000, 30000000, 300000000, 3000000000},
}
defer delete(m)
check(t, m)
}
// keys bigger than a chacheline; small values
{
m := map[[9]int]int{
[9]int{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000} = 1,
[9]int{20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000} = 2,
[9]int{30, 300, 3000, 30000, 300000, 3000000, 30000000, 300000000, 3000000000} = 3,
}
defer delete(m)
check(t, m)
}
}
+1
View File
@@ -1,3 +1,4 @@
#+feature dynamic-literals
package test_core_slice package test_core_slice
import "core:slice" import "core:slice"
+1
View File
@@ -16,6 +16,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style
..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b
@echo off @echo off
+1
View File
@@ -17,6 +17,7 @@ $ODIN test ../test_issue_2615.odin $COMMON
$ODIN test ../test_issue_2637.odin $COMMON $ODIN test ../test_issue_2637.odin $COMMON
$ODIN test ../test_issue_2666.odin $COMMON $ODIN test ../test_issue_2666.odin $COMMON
$ODIN test ../test_issue_4210.odin $COMMON $ODIN test ../test_issue_4210.odin $COMMON
$ODIN test ../test_issue_4584.odin $COMMON
if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then
echo "SUCCESSFUL 1/1" echo "SUCCESSFUL 1/1"
else else
+198
View File
@@ -0,0 +1,198 @@
// Tests issue #4584 https://github.com/odin-lang/Odin/issues/4584
package test_issues
import "core:testing"
import "core:log"
import "core:math/linalg"
import glm "core:math/linalg/glsl"
import hlm "core:math/linalg/hlsl"
@test
test_adjugate_2x2 :: proc(t: ^testing.T) {
I := linalg.identity(matrix[2,2]int)
m := matrix[2,2]int {
-3, 2,
-1, 0,
}
expected := matrix[2,2]int {
0, -2,
1, -3,
}
testing.expect_value(t, linalg.adjugate(m), expected)
testing.expect_value(t, linalg.determinant(m), 2)
testing.expect_value(t, linalg.adjugate(m) * m, 2 * I)
testing.expect_value(t, m * linalg.adjugate(m), 2 * I)
testing.expect_value(t, glm.adjugate(m), expected)
testing.expect_value(t, glm.determinant(m), 2)
testing.expect_value(t, glm.adjugate(m) * m, 2 * I)
testing.expect_value(t, m * glm.adjugate(m), 2 * I)
testing.expect_value(t, hlm.adjugate(m), expected)
testing.expect_value(t, hlm.determinant(m), 2)
testing.expect_value(t, hlm.adjugate(m) * m, 2 * I)
testing.expect_value(t, m * hlm.adjugate(m), 2 * I)
}
@test
test_adjugate_3x3 :: proc(t: ^testing.T) {
I := linalg.identity(matrix[3,3]int)
m := matrix[3,3]int {
-3, 2, -5,
-1, 0, -2,
3, -4, 1,
}
expected := matrix[3,3]int {
-8, 18, -4,
-5, 12, -1,
4, -6, 2,
}
testing.expect_value(t, linalg.adjugate(m), expected)
testing.expect_value(t, linalg.determinant(m), -6)
testing.expect_value(t, linalg.adjugate(m) * m, -6 * I)
testing.expect_value(t, m * linalg.adjugate(m), -6 * I)
testing.expect_value(t, glm.adjugate(m), expected)
testing.expect_value(t, glm.determinant(m), -6)
testing.expect_value(t, glm.adjugate(m) * m, -6 * I)
testing.expect_value(t, m * glm.adjugate(m), -6 * I)
testing.expect_value(t, hlm.adjugate(m), expected)
testing.expect_value(t, hlm.determinant(m), -6)
testing.expect_value(t, hlm.adjugate(m) * m, -6 * I)
testing.expect_value(t, m * hlm.adjugate(m), -6 * I)
}
@test
test_adjugate_4x4 :: proc(t: ^testing.T) {
I := linalg.identity(matrix[4,4]int)
m := matrix[4,4]int {
-3, 2, -5, 1,
-1, 0, -2, 2,
3, -4, 1, 3,
4, 5, 6, 7,
}
expected := matrix[4,4]int {
-144, 266, -92, -16,
-57, 92, -5, -16,
105, -142, 55, 2,
33, -96, 9, -6,
}
testing.expect_value(t, linalg.adjugate(m), expected)
testing.expect_value(t, linalg.determinant(m), -174)
testing.expect_value(t, linalg.adjugate(m) * m, -174 * I)
testing.expect_value(t, m * linalg.adjugate(m), -174 * I)
testing.expect_value(t, glm.adjugate(m), expected)
testing.expect_value(t, glm.determinant(m), -174)
testing.expect_value(t, glm.adjugate(m) * m, -174 * I)
testing.expect_value(t, m * glm.adjugate(m), -174 * I)
testing.expect_value(t, hlm.adjugate(m), expected)
testing.expect_value(t, hlm.determinant(m), -174)
testing.expect_value(t, hlm.adjugate(m) * m, -174 * I)
testing.expect_value(t, m * hlm.adjugate(m), -174 * I)
}
@test
test_inverse_regression_2x2 :: proc(t: ^testing.T) {
I := linalg.identity(matrix[2,2]f32)
m := matrix[2,2]f32 {
-3, 2,
-1, 0,
}
expected := matrix[2,2]f32 {
0.0, -1.0,
1.0/2.0, -3.0/2.0,
}
expect_float_matrix_value(t, linalg.inverse(m), expected)
expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected))
expect_float_matrix_value(t, linalg.inverse(m) * m, I)
expect_float_matrix_value(t, m * linalg.inverse(m), I)
expect_float_matrix_value(t, glm.inverse(m), expected)
expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected))
expect_float_matrix_value(t, glm.inverse(m) * m, I)
expect_float_matrix_value(t, m * glm.inverse(m), I)
expect_float_matrix_value(t, hlm.inverse(m), expected)
expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected))
expect_float_matrix_value(t, hlm.inverse(m) * m, I)
expect_float_matrix_value(t, m * hlm.inverse(m), I)
}
@test
test_inverse_regression_3x3 :: proc(t: ^testing.T) {
I := linalg.identity(matrix[3,3]f32)
m := matrix[3,3]f32 {
-3, 2, -5,
-1, 0, -2,
3, -4, 1,
}
expected := matrix[3,3]f32 {
4.0/3.0, -3.0, 2.0/3.0,
5.0/6.0, -2.0, 1.0/6.0,
-2.0/3.0, 1.0, -1.0/3.0,
}
expect_float_matrix_value(t, linalg.inverse(m), expected)
expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected))
expect_float_matrix_value(t, linalg.inverse(m) * m, I)
expect_float_matrix_value(t, m * linalg.inverse(m), I)
expect_float_matrix_value(t, glm.inverse(m), expected)
expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected))
expect_float_matrix_value(t, glm.inverse(m) * m, I)
expect_float_matrix_value(t, m * glm.inverse(m), I)
expect_float_matrix_value(t, hlm.inverse(m), expected)
expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected))
expect_float_matrix_value(t, hlm.inverse(m) * m, I)
expect_float_matrix_value(t, m * hlm.inverse(m), I)
}
@test
test_inverse_regression_4x4 :: proc(t: ^testing.T) {
I := linalg.identity(matrix[4,4]f32)
m := matrix[4,4]f32 {
-3, 2, -5, 1,
-1, 0, -2, 2,
3, -4, 1, 3,
4, 5, 6, 7,
}
expected := matrix[4,4]f32 {
24.0/29.0, -133.0/87.0, 46.0/87.0, 8.0/87.0,
19.0/58.0, -46.0/87.0, 5.0/174.0, 8.0/87.0,
-35.0/58.0, 71.0/87.0, -55.0/174.0, -1.0/87.0,
-11.0/58.0, 16.0/29.0, -3.0/58.0, 1.0/29.0,
}
expect_float_matrix_value(t, linalg.inverse(m), expected)
expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected))
expect_float_matrix_value(t, linalg.inverse(m) * m, I)
expect_float_matrix_value(t, m * linalg.inverse(m), I)
expect_float_matrix_value(t, glm.inverse(m), expected)
expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected))
expect_float_matrix_value(t, glm.inverse(m) * m, I)
expect_float_matrix_value(t, m * glm.inverse(m), I)
expect_float_matrix_value(t, hlm.inverse(m), expected)
expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected))
expect_float_matrix_value(t, hlm.inverse(m) * m, I)
expect_float_matrix_value(t, m * hlm.inverse(m), I)
}
@(private="file")
expect_float_matrix_value :: proc(t: ^testing.T, value, expected: $M/matrix[$N, N]f32, loc := #caller_location, value_expr := #caller_expression(value)) -> bool {
ok := true
outer: for i in 0..<N {
for j in 0..<N {
diff := abs(value[i, j] - expected[i, j])
if diff > 1e-6 {
ok = false
break outer
}
}
}
if !ok do log.errorf("expected %v to be %v, got %v", value_expr, expected, value, location=loc)
return ok
}
+1
View File
@@ -1,4 +1,5 @@
// Tests issue #829 https://github.com/odin-lang/Odin/issues/829 // Tests issue #829 https://github.com/odin-lang/Odin/issues/829
#+feature dynamic-literals
package test_issues package test_issues
import "core:testing" import "core:testing"
+3 -11
View File
@@ -24,19 +24,11 @@ when ODIN_OS == .Windows {
} }
when !#exists(LIB_PATH) { when !#exists(LIB_PATH) {
#panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`") #panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build_box2d.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`")
} }
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { foreign import lib {
when VECTOR_EXT == "_simd" { LIB_PATH,
foreign import lib "lib/box2d_wasm_simd.o"
} else {
foreign import lib "lib/box2d_wasm.o"
}
} else {
foreign import lib {
LIB_PATH,
}
} }
+5
View File
@@ -68,7 +68,12 @@ esac
cd .. cd ..
set +e
make -f wasm.Makefile make -f wasm.Makefile
if [[ $? -ne 0 ]]; then
printf "\e[30;43mwarning:\e[0m Native Box2D libraries were built successfully, the WASM build failed, likely because your default C compiler and/or linker doesn't support WASM, you can set the CC and LD environment variables to point to a compiler and linker that support it\n"
fi
set -e
rm -rf v3.0.0.tar.gz rm -rf v3.0.0.tar.gz
rm -rf box2d-3.0.0 rm -rf box2d-3.0.0
+3 -1
View File
@@ -2,6 +2,8 @@
# I tried to make a cmake toolchain file for this / use cmake but this is far easier. # I tried to make a cmake toolchain file for this / use cmake but this is far easier.
# NOTE: We are pretending to be emscripten to box2d so it takes WASM code paths, but we don't actually use emscripten. # NOTE: We are pretending to be emscripten to box2d so it takes WASM code paths, but we don't actually use emscripten.
# WARN: wasm is probably not supported by your default C compiler and linker, overwrite the CC and LD environment variables accordingly.
# Example for MacOS:
# CC = $(shell brew --prefix llvm)/bin/clang # CC = $(shell brew --prefix llvm)/bin/clang
# LD = $(shell brew --prefix llvm)/bin/wasm-ld # LD = $(shell brew --prefix llvm)/bin/wasm-ld
@@ -10,7 +12,7 @@ SRCS = $(wildcard box2d-$(VERSION)/src/*.c)
OBJS_SIMD = $(SRCS:.c=_simd.o) OBJS_SIMD = $(SRCS:.c=_simd.o)
OBJS = $(SRCS:.c=.o) OBJS = $(SRCS:.c=.o)
SYSROOT = $(shell odin root)/vendor/libc SYSROOT = $(shell odin root)/vendor/libc
CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/Extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT) CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT)
all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean
+58 -13
View File
@@ -105,6 +105,7 @@ type :: enum c.int {
} }
primitive_type :: enum c.int { primitive_type :: enum c.int {
invalid,
points, points,
lines, lines,
line_loop, line_loop,
@@ -222,15 +223,6 @@ accessor_sparse :: struct {
indices_component_type: component_type, indices_component_type: component_type,
values_buffer_view: ^buffer_view, values_buffer_view: ^buffer_view,
values_byte_offset: uint, values_byte_offset: uint,
extras: extras_t,
indices_extras: extras_t,
values_extras: extras_t,
extensions_count: uint,
extensions: [^]extension `fmt:"v,extensions_count"`,
indices_extensions_count: uint,
indices_extensions: [^]extension `fmt:"v,indices_extensions_count"`,
values_extensions_count: uint,
values_extensions: [^]extension `fmt:"v,values_extensions_count"`,
} }
accessor :: struct { accessor :: struct {
@@ -306,9 +298,6 @@ texture_view :: struct {
scale: f32, /* equivalent to strength for occlusion_texture */ scale: f32, /* equivalent to strength for occlusion_texture */
has_transform: b32, has_transform: b32,
transform: texture_transform, transform: texture_transform,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension `fmt:"v,extensions_count"`,
} }
pbr_metallic_roughness :: struct { pbr_metallic_roughness :: struct {
@@ -381,6 +370,16 @@ iridescence :: struct {
iridescence_thickness_texture: texture_view, iridescence_thickness_texture: texture_view,
} }
anisotropy :: struct {
anisotropy_strength: f32,
anisotropy_rotation: f32,
anisotropy_texture: texture_view,
}
dispersion :: struct {
dispersion: f32,
}
material :: struct { material :: struct {
name: cstring, name: cstring,
has_pbr_metallic_roughness: b32, has_pbr_metallic_roughness: b32,
@@ -393,6 +392,8 @@ material :: struct {
has_sheen: b32, has_sheen: b32,
has_emissive_strength: b32, has_emissive_strength: b32,
has_iridescence: b32, has_iridescence: b32,
has_anisotropy: b32,
has_dispersion: b32,
pbr_metallic_roughness: pbr_metallic_roughness, pbr_metallic_roughness: pbr_metallic_roughness,
pbr_specular_glossiness: pbr_specular_glossiness, pbr_specular_glossiness: pbr_specular_glossiness,
clearcoat: clearcoat, clearcoat: clearcoat,
@@ -403,6 +404,8 @@ material :: struct {
volume: volume, volume: volume,
emissive_strength: emissive_strength, emissive_strength: emissive_strength,
iridescence: iridescence, iridescence: iridescence,
anisotropy: anisotropy,
dispersion: dispersion,
normal_texture: texture_view, normal_texture: texture_view,
occlusion_texture: texture_view, occlusion_texture: texture_view,
emissive_texture: texture_view, emissive_texture: texture_view,
@@ -432,7 +435,6 @@ draco_mesh_compression :: struct {
} }
mesh_gpu_instancing :: struct { mesh_gpu_instancing :: struct {
buffer_view: ^buffer_view,
attributes: []attribute, attributes: []attribute,
} }
@@ -683,6 +685,9 @@ foreign lib {
node_transform_local :: proc(node: ^node, out_matrix: [^]f32) --- node_transform_local :: proc(node: ^node, out_matrix: [^]f32) ---
node_transform_world :: proc(node: ^node, out_matrix: [^]f32) --- node_transform_world :: proc(node: ^node, out_matrix: [^]f32) ---
@(require_results)
buffer_view_data :: proc(view: ^/*const*/buffer_view) -> [^]byte ---
@(require_results) @(require_results)
accessor_read_float :: proc(accessor: ^/*const*/accessor, index: uint, out: [^]f32, element_size: uint) -> b32 --- accessor_read_float :: proc(accessor: ^/*const*/accessor, index: uint, out: [^]f32, element_size: uint) -> b32 ---
@(require_results) @(require_results)
@@ -693,13 +698,53 @@ foreign lib {
@(require_results) @(require_results)
num_components :: proc(type: type) -> uint --- num_components :: proc(type: type) -> uint ---
@(require_results)
component_size :: proc(component_type: component_type) -> uint ---
@(require_results)
calc_size :: proc(type: type, component_type: component_type) -> uint ---
@(require_results) @(require_results)
accessor_unpack_floats :: proc(accessor: ^/*const*/accessor, out: [^]f32, float_count: uint) -> uint --- accessor_unpack_floats :: proc(accessor: ^/*const*/accessor, out: [^]f32, float_count: uint) -> uint ---
@(require_results)
accessor_unpack_indices :: proc(accessor: ^/*const*/accessor , out: rawptr, out_component_size: uint, index_count: uint) -> uint ---
/* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ /* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */
@(require_results) @(require_results)
copy_extras_json :: proc(data: ^data, extras: ^extras_t, dest: [^]byte, dest_size: ^uint) -> result --- copy_extras_json :: proc(data: ^data, extras: ^extras_t, dest: [^]byte, dest_size: ^uint) -> result ---
@(require_results)
mesh_index :: proc(data: ^/*const*/data, object: ^/*const*/mesh) -> uint ---
@(require_results)
material_index :: proc(data: ^/*const*/data, object: ^/*const*/material) -> uint ---
@(require_results)
accessor_index :: proc(data: ^/*const*/data, object: ^/*const*/accessor) -> uint ---
@(require_results)
buffer_view_index :: proc(data: ^/*const*/data, object: ^/*const*/buffer_view) -> uint ---
@(require_results)
buffer_index :: proc(data: ^/*const*/data, object: ^/*const*/buffer) -> uint ---
@(require_results)
image_index :: proc(data: ^/*const*/data, object: ^/*const*/image) -> uint ---
@(require_results)
texture_index :: proc(data: ^/*const*/data, object: ^/*const*/texture) -> uint ---
@(require_results)
sampler_index :: proc(data: ^/*const*/data, object: ^/*const*/sampler) -> uint ---
@(require_results)
skin_index :: proc(data: ^/*const*/data, object: ^/*const*/skin) -> uint ---
@(require_results)
camera_index :: proc(data: ^/*const*/data, object: ^/*const*/camera) -> uint ---
@(require_results)
light_index :: proc(data: ^/*const*/data, object: ^/*const*/light) -> uint ---
@(require_results)
node_index :: proc(data: ^/*const*/data, object: ^/*const*/node) -> uint ---
@(require_results)
scene_index :: proc(data: ^/*const*/data, object: ^/*const*/scene) -> uint ---
@(require_results)
animation_index :: proc(data: ^/*const*/data, object: ^/*const*/animation) -> uint ---
@(require_results)
animation_sampler_index :: proc(animation: ^/*const*/animation, object: ^/*const*/animation_sampler) -> uint ---
@(require_results)
animation_channel_index :: proc(animation: ^/*const*/animation, object: ^/*const*/animation_channel) -> uint ---
@(require_results) @(require_results)
write_file :: proc(#by_ptr options: options, path: cstring, data: ^data) -> result --- write_file :: proc(#by_ptr options: options, path: cstring, data: ^data) -> result ---
@(require_results) @(require_results)
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+436 -217
View File
File diff suppressed because it is too large Load Diff
+55 -12
View File
@@ -1,7 +1,7 @@
/** /**
* cgltf_write - a single-file glTF 2.0 writer written in C99. * cgltf_write - a single-file glTF 2.0 writer written in C99.
* *
* Version: 1.13 * Version: 1.14
* *
* Website: https://github.com/jkuhlmann/cgltf * Website: https://github.com/jkuhlmann/cgltf
* *
@@ -85,6 +85,8 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si
#define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13) #define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13)
#define CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING (1 << 14) #define CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING (1 << 14)
#define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15) #define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15)
#define CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY (1 << 16)
#define CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION (1 << 17)
typedef struct { typedef struct {
char* buffer; char* buffer;
@@ -152,7 +154,6 @@ typedef struct {
context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
cgltf_write_texture_transform(context, &info.transform); \ cgltf_write_texture_transform(context, &info.transform); \
} \ } \
cgltf_write_extras(context, &info.extras); \
cgltf_write_line(context, "}"); } cgltf_write_line(context, "}"); }
#define CGLTF_WRITE_NORMAL_TEXTURE_INFO(label, info) if (info.texture) { \ #define CGLTF_WRITE_NORMAL_TEXTURE_INFO(label, info) if (info.texture) { \
@@ -164,7 +165,6 @@ typedef struct {
context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
cgltf_write_texture_transform(context, &info.transform); \ cgltf_write_texture_transform(context, &info.transform); \
} \ } \
cgltf_write_extras(context, &info.extras); \
cgltf_write_line(context, "}"); } cgltf_write_line(context, "}"); }
#define CGLTF_WRITE_OCCLUSION_TEXTURE_INFO(label, info) if (info.texture) { \ #define CGLTF_WRITE_OCCLUSION_TEXTURE_INFO(label, info) if (info.texture) { \
@@ -176,12 +176,11 @@ typedef struct {
context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
cgltf_write_texture_transform(context, &info.transform); \ cgltf_write_texture_transform(context, &info.transform); \
} \ } \
cgltf_write_extras(context, &info.extras); \
cgltf_write_line(context, "}"); } cgltf_write_line(context, "}"); }
#ifndef CGLTF_CONSTS #ifndef CGLTF_CONSTS
static const cgltf_size GlbHeaderSize = 12; #define GlbHeaderSize 12
static const cgltf_size GlbChunkHeaderSize = 8; #define GlbChunkHeaderSize 8
static const uint32_t GlbVersion = 2; static const uint32_t GlbVersion = 2;
static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagic = 0x46546C67;
static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A;
@@ -360,6 +359,21 @@ static int cgltf_int_from_component_type(cgltf_component_type ctype)
} }
} }
static int cgltf_int_from_primitive_type(cgltf_primitive_type ctype)
{
switch (ctype)
{
case cgltf_primitive_type_points: return 0;
case cgltf_primitive_type_lines: return 1;
case cgltf_primitive_type_line_loop: return 2;
case cgltf_primitive_type_line_strip: return 3;
case cgltf_primitive_type_triangles: return 4;
case cgltf_primitive_type_triangle_strip: return 5;
case cgltf_primitive_type_triangle_fan: return 6;
default: return -1;
}
}
static const char* cgltf_str_from_alpha_mode(cgltf_alpha_mode alpha_mode) static const char* cgltf_str_from_alpha_mode(cgltf_alpha_mode alpha_mode)
{ {
switch (alpha_mode) switch (alpha_mode)
@@ -455,7 +469,7 @@ static void cgltf_write_asset(cgltf_write_context* context, const cgltf_asset* a
static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_primitive* prim) static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_primitive* prim)
{ {
cgltf_write_intprop(context, "mode", (int) prim->type, 4); cgltf_write_intprop(context, "mode", cgltf_int_from_primitive_type(prim->type), 4);
CGLTF_WRITE_IDXPROP("indices", prim->indices, context->data->accessors); CGLTF_WRITE_IDXPROP("indices", prim->indices, context->data->accessors);
CGLTF_WRITE_IDXPROP("material", prim->material, context->data->materials); CGLTF_WRITE_IDXPROP("material", prim->material, context->data->materials);
cgltf_write_line(context, "\"attributes\": {"); cgltf_write_line(context, "\"attributes\": {");
@@ -641,6 +655,16 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE; context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE;
} }
if (material->has_anisotropy)
{
context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY;
}
if (material->has_dispersion)
{
context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION;
}
if (material->has_pbr_metallic_roughness) if (material->has_pbr_metallic_roughness)
{ {
const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness; const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness;
@@ -656,7 +680,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
cgltf_write_line(context, "}"); cgltf_write_line(context, "}");
} }
if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence) if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence || material->has_anisotropy || material->has_dispersion)
{ {
cgltf_write_line(context, "\"extensions\": {"); cgltf_write_line(context, "\"extensions\": {");
if (material->has_clearcoat) if (material->has_clearcoat)
@@ -767,6 +791,22 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
CGLTF_WRITE_TEXTURE_INFO("iridescenceThicknessTexture", params->iridescence_thickness_texture); CGLTF_WRITE_TEXTURE_INFO("iridescenceThicknessTexture", params->iridescence_thickness_texture);
cgltf_write_line(context, "}"); cgltf_write_line(context, "}");
} }
if (material->has_anisotropy)
{
cgltf_write_line(context, "\"KHR_materials_anisotropy\": {");
const cgltf_anisotropy* params = &material->anisotropy;
cgltf_write_floatprop(context, "anisotropyFactor", params->anisotropy_strength, 0.f);
cgltf_write_floatprop(context, "anisotropyRotation", params->anisotropy_rotation, 0.f);
CGLTF_WRITE_TEXTURE_INFO("anisotropyTexture", params->anisotropy_texture);
cgltf_write_line(context, "}");
}
if (material->has_dispersion)
{
cgltf_write_line(context, "\"KHR_materials_dispersion\": {");
const cgltf_dispersion* params = &material->dispersion;
cgltf_write_floatprop(context, "dispersion", params->dispersion, 0.f);
cgltf_write_line(context, "}");
}
cgltf_write_line(context, "}"); cgltf_write_line(context, "}");
} }
@@ -977,7 +1017,6 @@ static void cgltf_write_node(cgltf_write_context* context, const cgltf_node* nod
cgltf_write_line(context, "\"EXT_mesh_gpu_instancing\": {"); cgltf_write_line(context, "\"EXT_mesh_gpu_instancing\": {");
{ {
CGLTF_WRITE_IDXPROP("bufferView", node->mesh_gpu_instancing.buffer_view, context->data->buffer_views);
cgltf_write_line(context, "\"attributes\": {"); cgltf_write_line(context, "\"attributes\": {");
{ {
for (cgltf_size i = 0; i < node->mesh_gpu_instancing.attributes_count; ++i) for (cgltf_size i = 0; i < node->mesh_gpu_instancing.attributes_count; ++i)
@@ -1044,14 +1083,11 @@ static void cgltf_write_accessor(cgltf_write_context* context, const cgltf_acces
cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0); cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0);
CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.indices_buffer_view, context->data->buffer_views); CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.indices_buffer_view, context->data->buffer_views);
cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->sparse.indices_component_type), 0); cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->sparse.indices_component_type), 0);
cgltf_write_extras(context, &accessor->sparse.indices_extras);
cgltf_write_line(context, "}"); cgltf_write_line(context, "}");
cgltf_write_line(context, "\"values\": {"); cgltf_write_line(context, "\"values\": {");
cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0); cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0);
CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.values_buffer_view, context->data->buffer_views); CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.values_buffer_view, context->data->buffer_views);
cgltf_write_extras(context, &accessor->sparse.values_extras);
cgltf_write_line(context, "}"); cgltf_write_line(context, "}");
cgltf_write_extras(context, &accessor->sparse.extras);
cgltf_write_line(context, "}"); cgltf_write_line(context, "}");
} }
cgltf_write_extras(context, &accessor->extras); cgltf_write_extras(context, &accessor->extras);
@@ -1123,6 +1159,7 @@ static void cgltf_write_light(cgltf_write_context* context, const cgltf_light* l
cgltf_write_floatprop(context, "outerConeAngle", light->spot_outer_cone_angle, 3.14159265358979323846f/4.0f); cgltf_write_floatprop(context, "outerConeAngle", light->spot_outer_cone_angle, 3.14159265358979323846f/4.0f);
cgltf_write_line(context, "}"); cgltf_write_line(context, "}");
} }
cgltf_write_extras( context, &light->extras );
cgltf_write_line(context, "}"); cgltf_write_line(context, "}");
} }
@@ -1249,9 +1286,15 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens
if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE) { if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE) {
cgltf_write_stritem(context, "KHR_materials_iridescence"); cgltf_write_stritem(context, "KHR_materials_iridescence");
} }
if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY) {
cgltf_write_stritem(context, "KHR_materials_anisotropy");
}
if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) { if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) {
cgltf_write_stritem(context, "EXT_mesh_gpu_instancing"); cgltf_write_stritem(context, "EXT_mesh_gpu_instancing");
} }
if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION) {
cgltf_write_stritem(context, "KHR_materials_dispersion");
}
} }
cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data) cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data)
+2 -2
View File
@@ -17,5 +17,5 @@ double fabs(double x);
int abs(int); int abs(int);
double ldexp(double, int); double ldexp(double, int);
double exp(double); double exp(double);
float log(float); double log(double);
float sin(float); double sin(double);
+2 -2
View File
@@ -90,11 +90,11 @@ exp :: proc "c" (x: f64) -> f64 {
} }
@(require, linkage="strong", link_name="log") @(require, linkage="strong", link_name="log")
log :: proc "c" (x: f32) -> f32 { log :: proc "c" (x: f64) -> f64 {
return math.ln(x) return math.ln(x)
} }
@(require, linkage="strong", link_name="sin") @(require, linkage="strong", link_name="sin")
sin :: proc "c" (x: f32) -> f32 { sin :: proc "c" (x: f64) -> f64 {
return math.sin(x) return math.sin(x)
} }
+1
View File
@@ -1,3 +1,4 @@
#+build !freestanding
package odin_libc package odin_libc
import "core:c" import "core:c"
+5
View File
@@ -3,6 +3,7 @@ package raylib
import "core:c" import "core:c"
RAYGUI_SHARED :: #config(RAYGUI_SHARED, false) RAYGUI_SHARED :: #config(RAYGUI_SHARED, false)
RAYGUI_WASM_LIB :: #config(RAYGUI_WASM_LIB, "wasm/libraygui.a")
when ODIN_OS == .Windows { when ODIN_OS == .Windows {
foreign import lib { foreign import lib {
@@ -22,6 +23,10 @@ when ODIN_OS == .Windows {
"macos/libraygui.dylib" when RAYGUI_SHARED else "macos/libraygui.a", "macos/libraygui.dylib" when RAYGUI_SHARED else "macos/libraygui.a",
} }
} }
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import lib {
RAYGUI_WASM_LIB,
}
} else { } else {
foreign import lib "system:raygui" foreign import lib "system:raygui"
} }
+5
View File
@@ -100,6 +100,7 @@ MAX_TEXT_BUFFER_LENGTH :: #config(RAYLIB_MAX_TEXT_BUFFER_LENGTH, 1024)
#assert(size_of(rune) == size_of(c.int)) #assert(size_of(rune) == size_of(c.int))
RAYLIB_SHARED :: #config(RAYLIB_SHARED, false) RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
RAYLIB_WASM_LIB :: #config(RAYLIB_WASM_LIB, "wasm/libraylib.a")
when ODIN_OS == .Windows { when ODIN_OS == .Windows {
@(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt")) @(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt"))
@@ -127,6 +128,10 @@ when ODIN_OS == .Windows {
"system:OpenGL.framework", "system:OpenGL.framework",
"system:IOKit.framework", "system:IOKit.framework",
} }
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import lib {
RAYLIB_WASM_LIB,
}
} else { } else {
foreign import lib "system:raylib" foreign import lib "system:raylib"
} }
+1 -1
View File
@@ -523,7 +523,7 @@ Vector3Unproject :: proc "c" (source: Vector3, projection: Matrix, view: Matrix)
quat: Quaternion quat: Quaternion
quat.x = source.x quat.x = source.x
quat.y = source.z quat.y = source.y
quat.z = source.z quat.z = source.z
quat.w = 1 quat.w = 1
+6 -1
View File
@@ -113,6 +113,7 @@ import rl "../."
VERSION :: "5.0" VERSION :: "5.0"
RAYLIB_SHARED :: #config(RAYLIB_SHARED, false) RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
RAYLIB_WASM_LIB :: #config(RAYLIB_WASM_LIB, "../wasm/libraylib.a")
// Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then: // Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then:
// - Compile a separate rlgl library and use that in the foreign import blocks below. // - Compile a separate rlgl library and use that in the foreign import blocks below.
@@ -145,6 +146,10 @@ when ODIN_OS == .Windows {
"system:OpenGL.framework", "system:OpenGL.framework",
"system:IOKit.framework", "system:IOKit.framework",
} }
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import lib {
RAYLIB_WASM_LIB,
}
} else { } else {
foreign import lib "system:raylib" foreign import lib "system:raylib"
} }
@@ -509,7 +514,7 @@ foreign lib {
UpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data UpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data
UnloadVertexArray :: proc(vaoId: c.uint) --- UnloadVertexArray :: proc(vaoId: c.uint) ---
UnloadVertexBuffer :: proc(vboId: c.uint) --- UnloadVertexBuffer :: proc(vboId: c.uint) ---
SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) --- SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, offset: c.int) ---
SetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) --- SetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) ---
SetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value SetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
DrawVertexArray :: proc(offset: c.int, count: c.int) --- DrawVertexArray :: proc(offset: c.int, count: c.int) ---
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+34 -12
View File
@@ -16,6 +16,8 @@ file_and_urls = [
("vulkan_macos.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h', False), ("vulkan_macos.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h', False),
("vulkan_ios.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h', False), ("vulkan_ios.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h', False),
("vulkan_wayland.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_wayland.h', False), ("vulkan_wayland.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_wayland.h', False),
("vulkan_xlib.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xlib.h', False),
("vulkan_xcb.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xcb.h', False),
# Vulkan Video # Vulkan Video
("vulkan_video_codec_av1std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std.h', False), ("vulkan_video_codec_av1std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std.h', False),
("vulkan_video_codec_av1std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std_decode.h', False), ("vulkan_video_codec_av1std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std_decode.h', False),
@@ -46,17 +48,18 @@ def no_vk(t):
t = t.replace('PFN_', 'Proc') t = t.replace('PFN_', 'Proc')
t = t.replace('PFN_', 'Proc') t = t.replace('PFN_', 'Proc')
t = re.sub('(?:Vk|VK_)?(\w+)', '\\1', t) t = re.sub('(?:Vk|VK_)?(\\w+)', '\\1', t)
# Vulkan Video # Vulkan Video
t = re.sub('(?:Std|STD_|VK_STD)?(\w+)', '\\1', t) t = re.sub('(?:Std|STD_|VK_STD)?(\\w+)', '\\1', t)
return t return t
OPAQUE_STRUCTS = """ OPAQUE_STRUCTS = """
wl_surface :: struct {} // Opaque struct defined by Wayland wl_surface :: struct {} // Opaque struct defined by Wayland
wl_display :: struct {} // Opaque struct defined by Wayland wl_display :: struct {} // Opaque struct defined by Wayland
IOSurfaceRef :: struct {} // Opaque struct defined by Apples CoreGraphics framework xcb_connection_t :: struct {} // Opaque struct defined by xcb
""" IOSurfaceRef :: struct {} // Opaque struct defined by Apples CoreGraphics framework
"""
def convert_type(t, prev_name, curr_name): def convert_type(t, prev_name, curr_name):
table = { table = {
@@ -91,6 +94,9 @@ def convert_type(t, prev_name, curr_name):
"struct BaseInStructure": "BaseInStructure", "struct BaseInStructure": "BaseInStructure",
"struct wl_display": "wl_display", "struct wl_display": "wl_display",
"struct wl_surface": "wl_surface", "struct wl_surface": "wl_surface",
"Display": "XlibDisplay",
"Window": "XlibWindow",
"VisualID": "XlibVisualID",
'v': '', 'v': '',
} }
@@ -106,7 +112,7 @@ def convert_type(t, prev_name, curr_name):
elif t.endswith("*"): elif t.endswith("*"):
pointer = "^" pointer = "^"
ttype = t[:len(t)-1] ttype = t[:len(t)-1]
elem = convert_type(ttype, prev_name, curr_name) elem = convert_type(ttype, prev_name, curr_name)
if curr_name.endswith("s") or curr_name.endswith("Table"): if curr_name.endswith("s") or curr_name.endswith("Table"):
if prev_name.endswith("Count") or prev_name.endswith("Counts"): if prev_name.endswith("Count") or prev_name.endswith("Counts"):
@@ -445,7 +451,7 @@ def parse_enums(f):
def parse_fake_enums(f): def parse_fake_enums(f):
data = re.findall(r"static const Vk(\w+FlagBits2) VK_(\w+?) = (\w+);", src, re.S) data = re.findall(r"static const Vk(\w+FlagBits2) VK_(\w+?) = (\w+);", src, re.S)
data.sort(key=lambda x: x[0]) data.sort(key=lambda x: x[0])
fake_enums = {} fake_enums = {}
@@ -507,7 +513,7 @@ def parse_fake_enums(f):
continue continue
ff.append((n, v)) ff.append((n, v))
max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0]) max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0])
max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0]) max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0])
if max_flag_value < max_group_value: if max_flag_value < max_group_value:
@@ -575,13 +581,13 @@ def parse_structs(f):
ffields.append(tuple([bit_field_name, bit_field_type, comment])) ffields.append(tuple([bit_field_name, bit_field_type, comment]))
prev_name = "" prev_name = ""
continue continue
# The second way has many fields that are each 1 bit # The second way has many fields that are each 1 bit
elif int(fname) == 1: elif int(fname) == 1:
bit_field_type = do_type(bit_field[0], prev_name, fname) bit_field_type = do_type(bit_field[0], prev_name, fname)
ffields.append(tuple(["bitfield", bit_field_type, comment])) ffields.append(tuple(["bitfield", bit_field_type, comment]))
break break
if '[' in fname: if '[' in fname:
@@ -894,6 +900,10 @@ import "core:c"
import win32 "core:sys/windows" import win32 "core:sys/windows"
_ :: win32 _ :: win32
import "vendor:x11/xlib"
_ :: xlib
when ODIN_OS == .Windows { when ODIN_OS == .Windows {
\tHINSTANCE :: win32.HINSTANCE \tHINSTANCE :: win32.HINSTANCE
\tHWND :: win32.HWND \tHWND :: win32.HWND
@@ -919,7 +929,19 @@ when ODIN_OS == .Windows {
\t} \t}
} }
CAMetalLayer :: struct {} when xlib.IS_SUPPORTED {
\tXlibDisplay :: xlib.Display
\tXlibWindow :: xlib.Window
\tXlibVisualID :: xlib.VisualID
} else {
\tXlibDisplay :: struct {} // Opaque struct defined by Xlib
\tXlibWindow :: c.ulong
\tXlibVisualID :: c.ulong
}
xcb_visualid_t :: u32
xcb_window_t :: u32
CAMetalLayer :: struct {}
MTLBuffer_id :: rawptr MTLBuffer_id :: rawptr
MTLTexture_id :: rawptr MTLTexture_id :: rawptr
+56
View File
@@ -0,0 +1,56 @@
#ifndef VULKAN_XCB_H_
#define VULKAN_XCB_H_ 1
/*
** Copyright 2015-2024 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
// VK_KHR_xcb_surface is a preprocessor guard. Do not pass it to API calls.
#define VK_KHR_xcb_surface 1
#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6
#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
typedef struct VkXcbSurfaceCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkXcbSurfaceCreateFlagsKHR flags;
xcb_connection_t* connection;
xcb_window_t window;
} VkXcbSurfaceCreateInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(
VkInstance instance,
const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
xcb_connection_t* connection,
xcb_visualid_t visual_id);
#endif
#ifdef __cplusplus
}
#endif
#endif
+56
View File
@@ -0,0 +1,56 @@
#ifndef VULKAN_XLIB_H_
#define VULKAN_XLIB_H_ 1
/*
** Copyright 2015-2024 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
// VK_KHR_xlib_surface is a preprocessor guard. Do not pass it to API calls.
#define VK_KHR_xlib_surface 1
#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6
#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
typedef struct VkXlibSurfaceCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkXlibSurfaceCreateFlagsKHR flags;
Display* dpy;
Window window;
} VkXlibSurfaceCreateInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR(
VkInstance instance,
const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
Display* dpy,
VisualID visualID);
#endif
#ifdef __cplusplus
}
#endif
#endif
+6
View File
@@ -1161,6 +1161,12 @@ EXT_METAL_OBJECTS_EXTENSION_NAME :: "VK_EXT_metal_objec
KHR_wayland_surface :: 1 KHR_wayland_surface :: 1
KHR_WAYLAND_SURFACE_SPEC_VERSION :: 6 KHR_WAYLAND_SURFACE_SPEC_VERSION :: 6
KHR_WAYLAND_SURFACE_EXTENSION_NAME :: "VK_KHR_wayland_surface" KHR_WAYLAND_SURFACE_EXTENSION_NAME :: "VK_KHR_wayland_surface"
KHR_xlib_surface :: 1
KHR_XLIB_SURFACE_SPEC_VERSION :: 6
KHR_XLIB_SURFACE_EXTENSION_NAME :: "VK_KHR_xlib_surface"
KHR_xcb_surface :: 1
KHR_XCB_SURFACE_SPEC_VERSION :: 6
KHR_XCB_SURFACE_EXTENSION_NAME :: "VK_KHR_xcb_surface"
// Handles types // Handles types
Instance :: distinct Handle Instance :: distinct Handle
+4
View File
@@ -4585,6 +4585,10 @@ WaylandSurfaceCreateFlagsKHR :: distinct bit_set[Wayland
WaylandSurfaceCreateFlagKHR :: enum u32 {} WaylandSurfaceCreateFlagKHR :: enum u32 {}
Win32SurfaceCreateFlagsKHR :: distinct bit_set[Win32SurfaceCreateFlagKHR; Flags] Win32SurfaceCreateFlagsKHR :: distinct bit_set[Win32SurfaceCreateFlagKHR; Flags]
Win32SurfaceCreateFlagKHR :: enum u32 {} Win32SurfaceCreateFlagKHR :: enum u32 {}
XcbSurfaceCreateFlagsKHR :: distinct bit_set[XcbSurfaceCreateFlagKHR; Flags]
XcbSurfaceCreateFlagKHR :: enum u32 {}
XlibSurfaceCreateFlagsKHR :: distinct bit_set[XlibSurfaceCreateFlagKHR; Flags]
XlibSurfaceCreateFlagKHR :: enum u32 {}
AccessFlags2 :: distinct bit_set[AccessFlag2; Flags64] AccessFlags2 :: distinct bit_set[AccessFlag2; Flags64]
AccessFlag2 :: enum Flags64 { AccessFlag2 :: enum Flags64 {
INDIRECT_COMMAND_READ = 0, INDIRECT_COMMAND_READ = 0,
+16
View File
@@ -36,6 +36,8 @@ ProcCreateMacOSSurfaceMVK :: #type pr
ProcCreateMetalSurfaceEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^MetalSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcCreateMetalSurfaceEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^MetalSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
ProcCreateWaylandSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^WaylandSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcCreateWaylandSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^WaylandSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
ProcCreateWin32SurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^Win32SurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcCreateWin32SurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^Win32SurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
ProcCreateXcbSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^XcbSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
ProcCreateXlibSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^XlibSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
ProcDebugReportMessageEXT :: #type proc "system" (instance: Instance, flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring) ProcDebugReportMessageEXT :: #type proc "system" (instance: Instance, flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring)
ProcDestroyDebugReportCallbackEXT :: #type proc "system" (instance: Instance, callback: DebugReportCallbackEXT, pAllocator: ^AllocationCallbacks) ProcDestroyDebugReportCallbackEXT :: #type proc "system" (instance: Instance, callback: DebugReportCallbackEXT, pAllocator: ^AllocationCallbacks)
ProcDestroyDebugUtilsMessengerEXT :: #type proc "system" (instance: Instance, messenger: DebugUtilsMessengerEXT, pAllocator: ^AllocationCallbacks) ProcDestroyDebugUtilsMessengerEXT :: #type proc "system" (instance: Instance, messenger: DebugUtilsMessengerEXT, pAllocator: ^AllocationCallbacks)
@@ -113,6 +115,8 @@ ProcGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR :: #type pr
ProcGetPhysicalDeviceVideoFormatPropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pVideoFormatInfo: ^PhysicalDeviceVideoFormatInfoKHR, pVideoFormatPropertyCount: ^u32, pVideoFormatProperties: [^]VideoFormatPropertiesKHR) -> Result ProcGetPhysicalDeviceVideoFormatPropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pVideoFormatInfo: ^PhysicalDeviceVideoFormatInfoKHR, pVideoFormatPropertyCount: ^u32, pVideoFormatProperties: [^]VideoFormatPropertiesKHR) -> Result
ProcGetPhysicalDeviceWaylandPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, display: ^wl_display) -> b32 ProcGetPhysicalDeviceWaylandPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, display: ^wl_display) -> b32
ProcGetPhysicalDeviceWin32PresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32 ProcGetPhysicalDeviceWin32PresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32
ProcGetPhysicalDeviceXcbPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, connection: ^xcb_connection_t, visual_id: xcb_visualid_t) -> b32
ProcGetPhysicalDeviceXlibPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, dpy: ^XlibDisplay, visualID: XlibVisualID) -> b32
ProcGetWinrtDisplayNV :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result ProcGetWinrtDisplayNV :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result
ProcReleaseDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result ProcReleaseDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result
ProcSubmitDebugUtilsMessageEXT :: #type proc "system" (instance: Instance, messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT) ProcSubmitDebugUtilsMessageEXT :: #type proc "system" (instance: Instance, messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT)
@@ -730,6 +734,8 @@ CreateMacOSSurfaceMVK: ProcCreateMacO
CreateMetalSurfaceEXT: ProcCreateMetalSurfaceEXT CreateMetalSurfaceEXT: ProcCreateMetalSurfaceEXT
CreateWaylandSurfaceKHR: ProcCreateWaylandSurfaceKHR CreateWaylandSurfaceKHR: ProcCreateWaylandSurfaceKHR
CreateWin32SurfaceKHR: ProcCreateWin32SurfaceKHR CreateWin32SurfaceKHR: ProcCreateWin32SurfaceKHR
CreateXcbSurfaceKHR: ProcCreateXcbSurfaceKHR
CreateXlibSurfaceKHR: ProcCreateXlibSurfaceKHR
DebugReportMessageEXT: ProcDebugReportMessageEXT DebugReportMessageEXT: ProcDebugReportMessageEXT
DestroyDebugReportCallbackEXT: ProcDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT: ProcDestroyDebugReportCallbackEXT
DestroyDebugUtilsMessengerEXT: ProcDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT: ProcDestroyDebugUtilsMessengerEXT
@@ -806,6 +812,8 @@ GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR: ProcGetPhysica
GetPhysicalDeviceVideoFormatPropertiesKHR: ProcGetPhysicalDeviceVideoFormatPropertiesKHR GetPhysicalDeviceVideoFormatPropertiesKHR: ProcGetPhysicalDeviceVideoFormatPropertiesKHR
GetPhysicalDeviceWaylandPresentationSupportKHR: ProcGetPhysicalDeviceWaylandPresentationSupportKHR GetPhysicalDeviceWaylandPresentationSupportKHR: ProcGetPhysicalDeviceWaylandPresentationSupportKHR
GetPhysicalDeviceWin32PresentationSupportKHR: ProcGetPhysicalDeviceWin32PresentationSupportKHR GetPhysicalDeviceWin32PresentationSupportKHR: ProcGetPhysicalDeviceWin32PresentationSupportKHR
GetPhysicalDeviceXcbPresentationSupportKHR: ProcGetPhysicalDeviceXcbPresentationSupportKHR
GetPhysicalDeviceXlibPresentationSupportKHR: ProcGetPhysicalDeviceXlibPresentationSupportKHR
GetWinrtDisplayNV: ProcGetWinrtDisplayNV GetWinrtDisplayNV: ProcGetWinrtDisplayNV
ReleaseDisplayEXT: ProcReleaseDisplayEXT ReleaseDisplayEXT: ProcReleaseDisplayEXT
SubmitDebugUtilsMessageEXT: ProcSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT: ProcSubmitDebugUtilsMessageEXT
@@ -1423,6 +1431,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {
set_proc_address(&CreateMetalSurfaceEXT, "vkCreateMetalSurfaceEXT") set_proc_address(&CreateMetalSurfaceEXT, "vkCreateMetalSurfaceEXT")
set_proc_address(&CreateWaylandSurfaceKHR, "vkCreateWaylandSurfaceKHR") set_proc_address(&CreateWaylandSurfaceKHR, "vkCreateWaylandSurfaceKHR")
set_proc_address(&CreateWin32SurfaceKHR, "vkCreateWin32SurfaceKHR") set_proc_address(&CreateWin32SurfaceKHR, "vkCreateWin32SurfaceKHR")
set_proc_address(&CreateXcbSurfaceKHR, "vkCreateXcbSurfaceKHR")
set_proc_address(&CreateXlibSurfaceKHR, "vkCreateXlibSurfaceKHR")
set_proc_address(&DebugReportMessageEXT, "vkDebugReportMessageEXT") set_proc_address(&DebugReportMessageEXT, "vkDebugReportMessageEXT")
set_proc_address(&DestroyDebugReportCallbackEXT, "vkDestroyDebugReportCallbackEXT") set_proc_address(&DestroyDebugReportCallbackEXT, "vkDestroyDebugReportCallbackEXT")
set_proc_address(&DestroyDebugUtilsMessengerEXT, "vkDestroyDebugUtilsMessengerEXT") set_proc_address(&DestroyDebugUtilsMessengerEXT, "vkDestroyDebugUtilsMessengerEXT")
@@ -1499,6 +1509,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {
set_proc_address(&GetPhysicalDeviceVideoFormatPropertiesKHR, "vkGetPhysicalDeviceVideoFormatPropertiesKHR") set_proc_address(&GetPhysicalDeviceVideoFormatPropertiesKHR, "vkGetPhysicalDeviceVideoFormatPropertiesKHR")
set_proc_address(&GetPhysicalDeviceWaylandPresentationSupportKHR, "vkGetPhysicalDeviceWaylandPresentationSupportKHR") set_proc_address(&GetPhysicalDeviceWaylandPresentationSupportKHR, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")
set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR, "vkGetPhysicalDeviceWin32PresentationSupportKHR") set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR, "vkGetPhysicalDeviceWin32PresentationSupportKHR")
set_proc_address(&GetPhysicalDeviceXcbPresentationSupportKHR, "vkGetPhysicalDeviceXcbPresentationSupportKHR")
set_proc_address(&GetPhysicalDeviceXlibPresentationSupportKHR, "vkGetPhysicalDeviceXlibPresentationSupportKHR")
set_proc_address(&GetWinrtDisplayNV, "vkGetWinrtDisplayNV") set_proc_address(&GetWinrtDisplayNV, "vkGetWinrtDisplayNV")
set_proc_address(&ReleaseDisplayEXT, "vkReleaseDisplayEXT") set_proc_address(&ReleaseDisplayEXT, "vkReleaseDisplayEXT")
set_proc_address(&SubmitDebugUtilsMessageEXT, "vkSubmitDebugUtilsMessageEXT") set_proc_address(&SubmitDebugUtilsMessageEXT, "vkSubmitDebugUtilsMessageEXT")
@@ -3879,6 +3891,8 @@ load_proc_addresses_instance :: proc(instance: Instance) {
CreateMetalSurfaceEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT") CreateMetalSurfaceEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT")
CreateWaylandSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR") CreateWaylandSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR")
CreateWin32SurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR") CreateWin32SurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR")
CreateXcbSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR")
CreateXlibSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR")
DebugReportMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkDebugReportMessageEXT") DebugReportMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkDebugReportMessageEXT")
DestroyDebugReportCallbackEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT") DestroyDebugReportCallbackEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")
DestroyDebugUtilsMessengerEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT") DestroyDebugUtilsMessengerEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT")
@@ -3955,6 +3969,8 @@ load_proc_addresses_instance :: proc(instance: Instance) {
GetPhysicalDeviceVideoFormatPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceVideoFormatPropertiesKHR") GetPhysicalDeviceVideoFormatPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceVideoFormatPropertiesKHR")
GetPhysicalDeviceWaylandPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR") GetPhysicalDeviceWaylandPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")
GetPhysicalDeviceWin32PresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR") GetPhysicalDeviceWin32PresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR")
GetPhysicalDeviceXcbPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR")
GetPhysicalDeviceXlibPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR")
GetWinrtDisplayNV = auto_cast GetInstanceProcAddr(instance, "vkGetWinrtDisplayNV") GetWinrtDisplayNV = auto_cast GetInstanceProcAddr(instance, "vkGetWinrtDisplayNV")
ReleaseDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkReleaseDisplayEXT") ReleaseDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkReleaseDisplayEXT")
SubmitDebugUtilsMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkSubmitDebugUtilsMessageEXT") SubmitDebugUtilsMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkSubmitDebugUtilsMessageEXT")
+37 -4
View File
@@ -7,6 +7,10 @@ import "core:c"
import win32 "core:sys/windows" import win32 "core:sys/windows"
_ :: win32 _ :: win32
import "vendor:x11/xlib"
_ :: xlib
when ODIN_OS == .Windows { when ODIN_OS == .Windows {
HINSTANCE :: win32.HINSTANCE HINSTANCE :: win32.HINSTANCE
HWND :: win32.HWND HWND :: win32.HWND
@@ -32,7 +36,19 @@ when ODIN_OS == .Windows {
} }
} }
CAMetalLayer :: struct {} when xlib.IS_SUPPORTED {
XlibDisplay :: xlib.Display
XlibWindow :: xlib.Window
XlibVisualID :: xlib.VisualID
} else {
XlibDisplay :: struct {} // Opaque struct defined by Xlib
XlibWindow :: c.ulong
XlibVisualID :: c.ulong
}
xcb_visualid_t :: u32
xcb_window_t :: u32
CAMetalLayer :: struct {}
MTLBuffer_id :: rawptr MTLBuffer_id :: rawptr
MTLTexture_id :: rawptr MTLTexture_id :: rawptr
@@ -8910,6 +8926,22 @@ WaylandSurfaceCreateInfoKHR :: struct {
surface: ^wl_surface, surface: ^wl_surface,
} }
XlibSurfaceCreateInfoKHR :: struct {
sType: StructureType,
pNext: rawptr,
flags: XlibSurfaceCreateFlagsKHR,
dpy: ^XlibDisplay,
window: XlibWindow,
}
XcbSurfaceCreateInfoKHR :: struct {
sType: StructureType,
pNext: rawptr,
flags: XcbSurfaceCreateFlagsKHR,
connection: ^xcb_connection_t,
window: xcb_window_t,
}
VideoAV1ColorConfigFlags :: struct { VideoAV1ColorConfigFlags :: struct {
bitfield: u32, bitfield: u32,
} }
@@ -9753,9 +9785,10 @@ VideoEncodeH265ReferenceInfo :: struct {
// Opaque structs // Opaque structs
wl_surface :: struct {} // Opaque struct defined by Wayland wl_surface :: struct {} // Opaque struct defined by Wayland
wl_display :: struct {} // Opaque struct defined by Wayland wl_display :: struct {} // Opaque struct defined by Wayland
IOSurfaceRef :: struct {} // Opaque struct defined by Apples CoreGraphics framework xcb_connection_t :: struct {} // Opaque struct defined by xcb
IOSurfaceRef :: struct {} // Opaque struct defined by Apples CoreGraphics framework
// Aliases // Aliases
PhysicalDeviceVariablePointerFeatures :: PhysicalDeviceVariablePointersFeatures PhysicalDeviceVariablePointerFeatures :: PhysicalDeviceVariablePointersFeatures
PhysicalDeviceShaderDrawParameterFeatures :: PhysicalDeviceShaderDrawParametersFeatures PhysicalDeviceShaderDrawParameterFeatures :: PhysicalDeviceShaderDrawParametersFeatures
+4
View File
@@ -0,0 +1,4 @@
package xlib
// Value, specifying whether `vendor:x11/xlib` is available on the current platform.
IS_SUPPORTED :: ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD