Merge tag 'dev-2025-06'

This commit is contained in:
2025-06-07 11:48:16 -04:00
82 changed files with 3302 additions and 1597 deletions
+229 -7
View File
@@ -7,13 +7,232 @@ nil :: nil
false :: 0!=0
true :: 0==0
ODIN_OS :: ODIN_OS
ODIN_ARCH :: ODIN_ARCH
ODIN_ENDIAN :: ODIN_ENDIAN
ODIN_VENDOR :: ODIN_VENDOR
ODIN_VERSION :: ODIN_VERSION
ODIN_ROOT :: ODIN_ROOT
ODIN_DEBUG :: ODIN_DEBUG
// The following constants are added in `checker.cpp`'s `init_universal` procedure.
/*
An `enum` value indicating the target's CPU architecture.
Possible values are: `.amd64`, `.i386`, `.arm32`, `.arm64`, `.wasm32`, `.wasm64p32`, and `.riscv64`.
*/
ODIN_ARCH :: ODIN_ARCH
/*
A `string` indicating the target's CPU architecture.
Possible values are: "amd64", "i386", "arm32", "arm64", "wasm32", "wasm64p32", "riscv64".
*/
ODIN_ARCH_STRING :: ODIN_ARCH_STRING
/*
An `enum` value indicating the type of compiled output, chosen using `-build-mode`.
Possible values are: `.Executable`, `.Dynamic`, `.Static`, `.Object`, `.Assembly`, and `.LLVM_IR`.
*/
ODIN_BUILD_MODE :: ODIN_BUILD_MODE
/*
A `string` containing the name of the folder that contains the entry point,
e.g. for `%ODIN_ROOT%/examples/demo`, this would contain `demo`.
*/
ODIN_BUILD_PROJECT_NAME :: ODIN_BUILD_PROJECT_NAME
/*
An `i64` containing the time at which the executable was compiled, in nanoseconds.
This is compatible with the `time.Time` type, i.e. `time.Time{_nsec=ODIN_COMPILE_TIMESTAMP}`
*/
ODIN_COMPILE_TIMESTAMP :: ODIN_COMPILE_TIMESTAMP
/*
`true` if the `-debug` command line switch is passed, which enables debug info generation.
*/
ODIN_DEBUG :: ODIN_DEBUG
/*
`true` if the `-default-to-nil-allocator` command line switch is passed,
which sets the initial `context.allocator` to an allocator that does nothing.
*/
ODIN_DEFAULT_TO_NIL_ALLOCATOR :: ODIN_DEFAULT_TO_NIL_ALLOCATOR
/*
`true` if the `-default-to-panic-allocator` command line switch is passed,
which sets the initial `context.allocator` to an allocator that panics if allocated from.
*/
ODIN_DEFAULT_TO_PANIC_ALLOCATOR :: ODIN_DEFAULT_TO_PANIC_ALLOCATOR
/*
`true` if the `-disable-assert` command line switch is passed,
which removes all calls to `assert` from the program.
*/
ODIN_DISABLE_ASSERT :: ODIN_DISABLE_ASSERT
/*
An `enum` value indicating the endianness of the target.
Possible values are: `.Little` and `.Big`.
*/
ODIN_ENDIAN :: ODIN_ENDIAN
/*
An `string` indicating the endianness of the target.
Possible values are: "little" and "big".
*/
ODIN_ENDIAN_STRING :: ODIN_ENDIAN_STRING
/*
An `enum` value set using the `-error-pos-style` switch, indicating the source location style used for compile errors and warnings.
Possible values are: `.Default` (Odin-style) and `.Unix`.
*/
ODIN_ERROR_POS_STYLE :: ODIN_ERROR_POS_STYLE
/*
`true` if the `-foreign-error-procedures` command line switch is passed,
which inhibits generation of runtime error procedures, so that they can be in a separate compilation unit.
*/
ODIN_FOREIGN_ERROR_PROCEDURES :: ODIN_FOREIGN_ERROR_PROCEDURES
/*
A `string` describing the microarchitecture used for code generation.
If not set using the `-microarch` command line switch, the compiler will pick a default.
Possible values include, but are not limited to: "sandybridge", "x86-64-v2".
*/
ODIN_MICROARCH_STRING :: ODIN_MICROARCH_STRING
/*
An `int` value representing the minimum OS version given to the linker, calculated as `major * 10_000 + minor * 100 + revision`.
If not set using the `-minimum-os-version` command line switch, it defaults to `0`, except on Darwin, where it's `11_00_00`.
*/
ODIN_MINIMUM_OS_VERSION :: ODIN_MINIMUM_OS_VERSION
/*
`true` if the `-no-bounds-check` command line switch is passed, which disables bounds checking at runtime.
*/
ODIN_NO_BOUNDS_CHECK :: ODIN_NO_BOUNDS_CHECK
/*
`true` if the `-no-crt` command line switch is passed, which inhibits linking with the C Runtime Library, a.k.a. LibC.
*/
ODIN_NO_CRT :: ODIN_NO_CRT
/*
`true` if the `-no-entry-point` command line switch is passed, which makes the declaration of a `main` procedure optional.
*/
ODIN_NO_ENTRY_POINT :: ODIN_NO_ENTRY_POINT
/*
`true` if the `-no-rtti` command line switch is passed, which inhibits generation of full Runtime Type Information.
*/
ODIN_NO_RTTI :: ODIN_NO_RTTI
/*
`true` if the `-no-type-assert` command line switch is passed, which disables type assertion checking program wide.
*/
ODIN_NO_TYPE_ASSERT :: ODIN_NO_TYPE_ASSERT
/*
An `enum` value indicating the optimization level selected using the `-o` command line switch.
Possible values are: `.None`, `.Minimal`, `.Size`, `.Speed`, and `.Aggressive`.
If `ODIN_OPTIMIZATION_MODE` is anything other than `.None` or `.Minimal`, the compiler will also perform a unity build,
and `ODIN_USE_SEPARATE_MODULES` will be set to `false` as a result.
*/
ODIN_OPTIMIZATION_MODE :: ODIN_OPTIMIZATION_MODE
/*
An `enum` value indicating what the target operating system is.
*/
ODIN_OS :: ODIN_OS
/*
A `string` indicating what the target operating system is.
*/
ODIN_OS_STRING :: ODIN_OS_STRING
/*
An `enum` value indicating the platform subtarget, chosen using the `-subtarget` switch.
Possible values are: `.Default` `.iOS`, and `.Android`.
*/
ODIN_PLATFORM_SUBTARGET :: ODIN_PLATFORM_SUBTARGET
/*
A `string` representing the path of the folder containing the Odin compiler,
relative to which we expect to find the `base` and `core` package collections.
*/
ODIN_ROOT :: ODIN_ROOT
/*
A `bit_set` indicating the sanitizer flags set using the `-sanitize` command line switch.
Supported flags are `.Address`, `.Memory`, and `.Thread`.
*/
ODIN_SANITIZER_FLAGS :: ODIN_SANITIZER_FLAGS
/*
`true` if the code is being compiled via an invocation of `odin test`.
*/
ODIN_TEST :: ODIN_TEST
/*
`true` if built using the experimental Tilde backend.
*/
ODIN_TILDE :: ODIN_TILDE
/*
`true` by default, meaning each each package is built into its own object file, and then linked together.
`false` if the `-use-single-module` command line switch to force a unity build is provided.
If `ODIN_OPTIMIZATION_MODE` is anything other than `.None` or `.Minimal`, the compiler will also perform a unity build,
and this constant will also be set to `false`.
*/
ODIN_USE_SEPARATE_MODULES :: ODIN_USE_SEPARATE_MODULES
/*
`true` if Valgrind integration is supported on the target.
*/
ODIN_VALGRIND_SUPPORT :: ODIN_VALGRIND_SUPPORT
/*
A `string` which identifies the compiler being used. The official compiler sets this to `"odin"`.
*/
ODIN_VENDOR :: ODIN_VENDOR
/*
A `string` containing the version of the Odin compiler, typically in the format `dev-YYYY-MM`.
*/
ODIN_VERSION :: ODIN_VERSION
/*
A `string` containing the Git hash part of the Odin version.
Empty if `.git` could not be detected at the time the compiler was built.
*/
ODIN_VERSION_HASH :: ODIN_VERSION_HASH
/*
An `enum` set by the `-subsystem` flag, specifying which Windows subsystem the PE file was created for.
Possible values are:
`.Unknown` - Default and only value on non-Windows platforms
`.Console` - Default on Windows
`.Windows` - Can be used by graphical applications so Windows doesn't open an empty console
There are some other possible values for e.g. EFI applications, but only Console and Windows are supported.
See also: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64
*/
ODIN_WINDOWS_SUBSYSTEM :: ODIN_WINDOWS_SUBSYSTEM
/*
An `string` set by the `-subsystem` flag, specifying which Windows subsystem the PE file was created for.
Possible values are:
"UNKNOWN" - Default and only value on non-Windows platforms
"CONSOLE" - Default on Windows
"WINDOWS" - Can be used by graphical applications so Windows doesn't open an empty console
There are some other possible values for e.g. EFI applications, but only Console and Windows are supported.
See also: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64
*/
ODIN_WINDOWS_SUBSYSTEM_STRING :: ODIN_WINDOWS_SUBSYSTEM_STRING
/*
`true` if LLVM supports the f16 type.
*/
__ODIN_LLVM_F16_SUPPORTED :: __ODIN_LLVM_F16_SUPPORTED
byte :: u8 // alias
@@ -131,3 +350,6 @@ soa_zip :: proc(slices: ...) -> #soa[]Struct ---
soa_unzip :: proc(value: $S/#soa[]$E) -> (slices: ...) ---
unreachable :: proc() -> ! ---
// Where T is a string, slice, dynamic array, or pointer to an array type
raw_data :: proc(t: $T) -> rawptr
+209 -112
View File
@@ -16,6 +16,12 @@ RUNTIME_REQUIRE :: false // !ODIN_TILDE
@(private)
__float16 :: f16 when __ODIN_LLVM_F16_SUPPORTED else u16
HAS_HARDWARE_SIMD :: false when (ODIN_ARCH == .amd64 || ODIN_ARCH == .i386) && !intrinsics.has_target_feature("sse2") else
false when (ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32) && !intrinsics.has_target_feature("neon") else
false when (ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32) && !intrinsics.has_target_feature("simd128") else
false when (ODIN_ARCH == .riscv64) && !intrinsics.has_target_feature("v") else
true
@(private)
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check {
@@ -229,151 +235,242 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
case n == 0: return true
case x == y: return true
}
a, b := ([^]byte)(x), ([^]byte)(y)
length := uint(n)
a, b := cast([^]byte)x, cast([^]byte)y
for i := uint(0); i < length; i += 1 {
n := uint(n)
i := uint(0)
m := uint(0)
if n >= 8 {
when HAS_HARDWARE_SIMD {
// Avoid using 256-bit SIMD on platforms where its emulation is
// likely to be less than ideal.
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
m = n / 32 * 32
for /**/; i < m; i += 32 {
load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i])
load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i])
ne := intrinsics.simd_lanes_ne(load_a, load_b)
if intrinsics.simd_reduce_or(ne) != 0 {
return false
}
}
}
}
m = (n-i) / 16 * 16
for /**/; i < m; i += 16 {
load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i])
load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i])
ne := intrinsics.simd_lanes_ne(load_a, load_b)
if intrinsics.simd_reduce_or(ne) != 0 {
return false
}
}
m = (n-i) / 8 * 8
for /**/; i < m; i += 8 {
if intrinsics.unaligned_load(cast(^uintptr)&a[i]) != intrinsics.unaligned_load(cast(^uintptr)&b[i]) {
return false
}
}
}
for /**/; i < n; i += 1 {
if a[i] != b[i] {
return false
}
}
return true
/*
when size_of(uint) == 8 {
if word_length := length >> 3; word_length != 0 {
for _ in 0..<word_length {
if intrinsics.unaligned_load((^u64)(a)) != intrinsics.unaligned_load((^u64)(b)) {
return false
}
a = a[size_of(u64):]
b = b[size_of(u64):]
}
}
if length & 4 != 0 {
if intrinsics.unaligned_load((^u32)(a)) != intrinsics.unaligned_load((^u32)(b)) {
return false
}
a = a[size_of(u32):]
b = b[size_of(u32):]
}
if length & 2 != 0 {
if intrinsics.unaligned_load((^u16)(a)) != intrinsics.unaligned_load((^u16)(b)) {
return false
}
a = a[size_of(u16):]
b = b[size_of(u16):]
}
if length & 1 != 0 && a[0] != b[0] {
return false
}
return true
} else {
if word_length := length >> 2; word_length != 0 {
for _ in 0..<word_length {
if intrinsics.unaligned_load((^u32)(a)) != intrinsics.unaligned_load((^u32)(b)) {
return false
}
a = a[size_of(u32):]
b = b[size_of(u32):]
}
}
length &= 3
if length != 0 {
for i in 0..<length {
if a[i] != b[i] {
return false
}
}
}
return true
}
*/
}
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
memory_compare :: proc "contextless" (x, y: rawptr, n: int) -> int #no_bounds_check {
switch {
case a == b: return 0
case a == nil: return -1
case b == nil: return +1
case x == y: return 0
case x == nil: return -1
case y == nil: return +1
}
a, b := cast([^]byte)x, cast([^]byte)y
n := uint(n)
i := uint(0)
m := uint(0)
x := uintptr(a)
y := uintptr(b)
n := uintptr(n)
SU :: size_of(uintptr)
fast := n/SU + 1
offset := (fast-1)*SU
curr_block := uintptr(0)
if n < SU {
fast = 0
}
for /**/; curr_block < fast; curr_block += 1 {
va := (^uintptr)(x + curr_block * size_of(uintptr))^
vb := (^uintptr)(y + curr_block * size_of(uintptr))^
if va ~ vb != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
a := (^byte)(x+pos)^
b := (^byte)(y+pos)^
if a ~ b != 0 {
return -1 if (int(a) - int(b)) < 0 else +1
when HAS_HARDWARE_SIMD {
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
m = n / 32 * 32
for /**/; i < m; i += 32 {
load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i])
load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i])
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
if intrinsics.simd_reduce_or(comparison) != 0 {
sentinel: #simd[32]u8 = u8(0xFF)
indices := intrinsics.simd_indices(#simd[32]u8)
index_select := intrinsics.simd_select(comparison, indices, sentinel)
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
return -1 if a[i+index_reduce] < b[i+index_reduce] else +1
}
}
}
}
for /**/; offset < n; offset += 1 {
a := (^byte)(x+offset)^
b := (^byte)(y+offset)^
if a ~ b != 0 {
return -1 if (int(a) - int(b)) < 0 else +1
m = (n-i) / 16 * 16
for /**/; i < m; i += 16 {
load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i])
load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i])
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
if intrinsics.simd_reduce_or(comparison) != 0 {
sentinel: #simd[16]u8 = u8(0xFF)
indices := intrinsics.simd_indices(#simd[16]u8)
index_select := intrinsics.simd_select(comparison, indices, sentinel)
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
return -1 if a[i+index_reduce] < b[i+index_reduce] else +1
}
}
// 64-bit SIMD is faster than using a `uintptr` to detect a difference then
// re-iterating with the byte-by-byte loop, at least on AMD64.
m = (n-i) / 8 * 8
for /**/; i < m; i += 8 {
load_a := intrinsics.unaligned_load(cast(^#simd[8]u8)&a[i])
load_b := intrinsics.unaligned_load(cast(^#simd[8]u8)&b[i])
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
if intrinsics.simd_reduce_or(comparison) != 0 {
sentinel: #simd[8]u8 = u8(0xFF)
indices := intrinsics.simd_indices(#simd[8]u8)
index_select := intrinsics.simd_select(comparison, indices, sentinel)
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
return -1 if a[i+index_reduce] < b[i+index_reduce] else +1
}
}
for /**/; i < n; i += 1 {
if a[i] ~ b[i] != 0 {
return -1 if int(a[i]) - int(b[i]) < 0 else +1
}
}
return 0
}
memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
x := uintptr(a)
n := uintptr(n)
n := uint(n)
i := uint(0)
m := uint(0)
SU :: size_of(uintptr)
fast := n/SU + 1
offset := (fast-1)*SU
curr_block := uintptr(0)
if n < SU {
fast = 0
// Because we're comparing against zero, we never return -1, as that would
// indicate the compared value is less than zero.
//
// Note that a zero return value here means equality.
bytes := ([^]u8)(a)
if n >= 8 {
when HAS_HARDWARE_SIMD {
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
scanner32: #simd[32]u8
m = n / 32 * 32
for /**/; i < m; i += 32 {
load := intrinsics.unaligned_load(cast(^#simd[32]u8)&bytes[i])
ne := intrinsics.simd_lanes_ne(scanner32, load)
if intrinsics.simd_reduce_or(ne) > 0 {
return 1
}
}
}
}
scanner16: #simd[16]u8
m = (n-i) / 16 * 16
for /**/; i < m; i += 16 {
load := intrinsics.unaligned_load(cast(^#simd[16]u8)&bytes[i])
ne := intrinsics.simd_lanes_ne(scanner16, load)
if intrinsics.simd_reduce_or(ne) != 0 {
return 1
}
}
m = (n-i) / 8 * 8
for /**/; i < m; i += 8 {
if intrinsics.unaligned_load(cast(^uintptr)&bytes[i]) != 0 {
return 1
}
}
}
for /**/; curr_block < fast; curr_block += 1 {
va := (^uintptr)(x + curr_block * size_of(uintptr))^
if va ~ 0 != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
a := (^byte)(x+pos)^
if a ~ 0 != 0 {
return -1 if int(a) < 0 else +1
for /**/; i < n; i += 1 {
if bytes[i] != 0 {
return 1
}
}
return 0
}
memory_prefix_length :: proc "contextless" (x, y: rawptr, n: int) -> (idx: int) #no_bounds_check {
switch {
case x == y: return n
case x == nil: return 0
case y == nil: return 0
}
a, b := cast([^]byte)x, cast([^]byte)y
n := uint(n)
i := uint(0)
m := uint(0)
when HAS_HARDWARE_SIMD {
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
m = n / 32 * 32
for /**/; i < m; i += 32 {
load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i])
load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i])
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
if intrinsics.simd_reduce_or(comparison) != 0 {
sentinel: #simd[32]u8 = u8(0xFF)
indices := intrinsics.simd_indices(#simd[32]u8)
index_select := intrinsics.simd_select(comparison, indices, sentinel)
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
return int(i + index_reduce)
}
}
}
}
for /**/; offset < n; offset += 1 {
a := (^byte)(x+offset)^
if a ~ 0 != 0 {
return -1 if int(a) < 0 else +1
m = (n-i) / 16 * 16
for /**/; i < m; i += 16 {
load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i])
load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i])
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
if intrinsics.simd_reduce_or(comparison) != 0 {
sentinel: #simd[16]u8 = u8(0xFF)
indices := intrinsics.simd_indices(#simd[16]u8)
index_select := intrinsics.simd_select(comparison, indices, sentinel)
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
return int(i + index_reduce)
}
}
return 0
// 64-bit SIMD is faster than using a `uintptr` to detect a difference then
// re-iterating with the byte-by-byte loop, at least on AMD64.
m = (n-i) / 8 * 8
for /**/; i < m; i += 8 {
load_a := intrinsics.unaligned_load(cast(^#simd[8]u8)&a[i])
load_b := intrinsics.unaligned_load(cast(^#simd[8]u8)&b[i])
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
if intrinsics.simd_reduce_or(comparison) != 0 {
sentinel: #simd[8]u8 = u8(0xFF)
indices := intrinsics.simd_indices(#simd[8]u8)
index_select := intrinsics.simd_select(comparison, indices, sentinel)
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
return int(i + index_reduce)
}
}
for /**/; i < n; i += 1 {
if a[i] ~ b[i] != 0 {
return int(i)
}
}
return int(n)
}
string_eq :: proc "contextless" (lhs, rhs: string) -> bool {
+2 -2
View File
@@ -350,7 +350,7 @@ index_byte :: proc "contextless" (s: []byte, c: byte) -> (index: int) #no_bounds
}
c_vec: simd.u8x16 = c
when !simd.IS_EMULATED {
when simd.HAS_HARDWARE_SIMD {
// Note: While this is something that could also logically take
// advantage of AVX512, the various downclocking and power
// consumption related woes make premature to have a dedicated
@@ -485,7 +485,7 @@ last_index_byte :: proc "contextless" (s: []byte, c: byte) -> int #no_bounds_che
}
c_vec: simd.u8x16 = c
when !simd.IS_EMULATED {
when simd.HAS_HARDWARE_SIMD {
// Note: While this is something that could also logically take
// advantage of AVX512, the various downclocking and power
// consumption related woes make premature to have a dedicated
+1 -1
View File
@@ -6,7 +6,7 @@ import "core:sys/info"
// is_supported returns true iff hardware accelerated AES
// is supported.
is_supported :: proc "contextless" () -> bool {
features, ok := info.cpu_features.?
features, ok := info.cpu.features.?
if !ok {
return false
}
@@ -39,7 +39,7 @@ when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 {
// Some targets lack runtime feature detection, and will flat out refuse
// to load binaries that have unknown instructions. This is distinct from
// `simd.IS_EMULATED` as actually good designs support runtime feature
// `simd.HAS_HARDWARE_SIMD` as actually good designs support runtime feature
// detection and that constant establishes a baseline.
//
// See:
@@ -227,7 +227,7 @@ is_performant :: proc "contextless" () -> bool {
req_features :: info.CPU_Features{.V}
}
features, ok := info.cpu_features.?
features, ok := info.cpu.features.?
if !ok {
return false
}
@@ -41,7 +41,7 @@ _VEC_TWO: simd.u64x4 : {2, 0, 2, 0}
is_performant :: proc "contextless" () -> bool {
req_features :: info.CPU_Features{.avx, .avx2}
features, ok := info.cpu_features.?
features, ok := info.cpu.features.?
if !ok {
return false
}
+1 -1
View File
@@ -52,7 +52,7 @@ K_15 :: simd.u64x2{0xa4506ceb90befffa, 0xc67178f2bef9a3f7}
// is_hardware_accelerated_256 returns true iff hardware accelerated
// SHA-224/SHA-256 is supported.
is_hardware_accelerated_256 :: proc "contextless" () -> bool {
features, ok := info.cpu_features.?
features, ok := info.cpu.features.?
if !ok {
return false
}
-2
View File
@@ -63,8 +63,6 @@ Example:
read_csv_from_string :: proc(filename: string) {
r: csv.Reader
r.trim_leading_space = true
r.reuse_record = true // Without it you have to delete(record)
r.reuse_record_buffer = true // Without it you have to each of the fields within it
defer csv.reader_destroy(&r)
csv_data, ok := os.read_entire_file(filename)
+1 -1
View File
@@ -130,7 +130,7 @@ reader_destroy :: proc(r: ^Reader) {
for record, row_idx in csv.iterator_next(&r) { ... }
TIP: If you process the results within the loop and don't need to own the results,
you can set the Reader's `reuse_record` and `reuse_record_reuse_record_buffer` to true;
you can set the Reader's `reuse_record` and `reuse_record_buffer` to true;
you won't need to delete the record or its fields.
*/
iterator_next :: proc(r: ^Reader) -> (record: []string, idx: int, err: Error, more: bool) {
+1 -82
View File
@@ -317,85 +317,4 @@ crc32_table := [8][256]u32{
0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53,
0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6,
},
}
/*
@(optimization_mode="speed")
crc32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 {
result := ~u32(seed);
#no_bounds_check for b in data {
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
}
return ~result;
}
@private _crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
*/
}
-3
View File
@@ -1212,7 +1212,6 @@ Filter_Params :: struct #packed {
depth_scale_table :: []u8{0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01}
// @(optimization_mode="speed")
defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
using params
@@ -1273,7 +1272,6 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
return
}
// @(optimization_mode="speed")
defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check {
using params
@@ -1436,7 +1434,6 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check {
return true
}
// @(optimization_mode="speed")
defilter_16 :: proc(params: ^Filter_Params) -> bool {
using params
+1 -1
View File
@@ -280,7 +280,7 @@ int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context
}
pos := ch - '+'
if RADIX_TABLE_REVERSE_SIZE <= pos {
if RADIX_TABLE_REVERSE_SIZE <= u32(pos) {
break
}
y := RADIX_TABLE_REVERSE[pos]
+1 -1
View File
@@ -350,7 +350,7 @@ Example:
Possible Output:
6
500
13
*/
@(require_results)
+25 -5
View File
@@ -315,18 +315,38 @@ check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool {
Offset a given pointer by a given amount.
This procedure offsets the pointer `ptr` to an object of type `T`, by the amount
of bytes specified by `offset*size_of(T)`, and returns the pointer `ptr`.
of bytes specified by `offset * size_of(T)`, and returns the pointer `ptr`.
**Note**: Prefer to use multipointer types, if possible.
*/
ptr_offset :: intrinsics.ptr_offset
/*
Offset a given pointer by a given amount backwards.
Subtract two pointers of the same type, and return the number of `T` between them.
This procedure offsets the pointer `ptr` to an object of type `T`, by the amount
of bytes specified by `offset*size_of(T)` in the negative direction, and
returns the pointer `ptr`.
This procedure subtracts pointer `b` from pointer `a`, both of type `^T`,
and returns an integer count of the `T` between them.
**Inputs**
- `a`: A pointer to a type T
- `b`: A pointer to a type T
**Returns**
- `b` - `a` in items of T as an `int`.
Example:
import "core:mem"
import "core:fmt"
ptr_sub_example :: proc() {
arr: [2]int
fmt.println(mem.ptr_sub(&arr[1], &arr[0]))
}
Output:
1
*/
ptr_sub :: intrinsics.ptr_sub
+1 -1
View File
@@ -477,7 +477,7 @@ block_mark_as_free :: proc(block: ^Block_Header) {
}
@(private, no_sanitize_address)
block_mark_as_used :: proc(block: ^Block_Header, ) {
block_mark_as_used :: proc(block: ^Block_Header) {
next := block_next(block)
block_set_prev_used(next)
block_set_used(block)
+5 -8
View File
@@ -21,20 +21,17 @@ package simd
import "base:builtin"
import "base:intrinsics"
import "base:runtime"
/*
Check if SIMD is software-emulated on a target platform.
This value is `false`, when the compile-time target has the hardware support for
at 128-bit (or wider) SIMD. If the compile-time target lacks the hardware support
for 128-bit SIMD, this value is `true`, and all SIMD operations will likely be
This value is `true`, when the compile-time target has the hardware support for
at least 128-bit (or wider) SIMD. If the compile-time target lacks the hardware support
for 128-bit SIMD, this value is `false`, and all SIMD operations will likely be
emulated.
*/
IS_EMULATED :: true when (ODIN_ARCH == .amd64 || ODIN_ARCH == .i386) && !intrinsics.has_target_feature("sse2") else
true when (ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32) && !intrinsics.has_target_feature("neon") else
true when (ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32) && !intrinsics.has_target_feature("simd128") else
true when (ODIN_ARCH == .riscv64) && !intrinsics.has_target_feature("v") else
false
HAS_HARDWARE_SIMD :: runtime.HAS_HARDWARE_SIMD
/*
Vector of 16 `u8` lanes (128 bits).
+46 -17
View File
@@ -2,6 +2,7 @@
package strings
import "base:intrinsics"
import "base:runtime"
import "core:bytes"
import "core:io"
import "core:mem"
@@ -458,6 +459,7 @@ equal_fold :: proc(u, v: string) -> (res: bool) {
return s == t
}
/*
Returns the prefix length common between strings `a` and `b`
@@ -488,30 +490,57 @@ Output:
0
*/
prefix_length :: proc(a, b: string) -> (n: int) {
_len := min(len(a), len(b))
prefix_length :: proc "contextless" (a, b: string) -> (n: int) {
RUNE_ERROR :: '\ufffd'
RUNE_SELF :: 0x80
UTF_MAX :: 4
// Scan for matches including partial codepoints.
#no_bounds_check for n < _len && a[n] == b[n] {
n += 1
}
// Now scan to ignore partial codepoints.
if n > 0 {
s := a[:n]
n = 0
for {
r0, w := utf8.decode_rune(s[n:])
if r0 != utf8.RUNE_ERROR {
n += w
} else {
break
n = runtime.memory_prefix_length(raw_data(a), raw_data(b), min(len(a), len(b)))
lim := max(n - UTF_MAX + 1, 0)
for l := n; l > lim; l -= 1 {
r, _ := runtime.string_decode_rune(a[l - 1:])
if r != RUNE_ERROR {
if l > 0 && (a[l - 1] & 0xc0 == 0xc0) {
return l - 1
}
return l
}
}
return
}
/*
Returns the common prefix between strings `a` and `b`
Inputs:
- a: The first input string
- b: The second input string
Returns:
- n: The string prefix common between strings `a` and `b`
Example:
import "core:fmt"
import "core:strings"
common_prefix_example :: proc() {
fmt.println(strings.common_prefix("testing", "test"))
fmt.println(strings.common_prefix("testing", "te"))
fmt.println(strings.common_prefix("telephone", "te"))
}
Output:
test
te
te
*/
common_prefix :: proc(a, b: string) -> string {
return a[:prefix_length(a, b)]
}
/*
Determines if a string `s` starts with a given `prefix`
Inputs:
+45 -45
View File
@@ -256,7 +256,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
return nil
}
if template.applicationWillFinishLaunching != nil {
applicationWillFinishLaunching :: proc "c" (self: id, notification: ^Notification) {
applicationWillFinishLaunching :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationWillFinishLaunching(notification)
@@ -264,7 +264,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationWillFinishLaunching:"), auto_cast applicationWillFinishLaunching, "v@:@")
}
if template.applicationDidFinishLaunching != nil {
applicationDidFinishLaunching :: proc "c" (self: id, notification: ^Notification) {
applicationDidFinishLaunching :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidFinishLaunching(notification)
@@ -272,7 +272,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDidFinishLaunching:"), auto_cast applicationDidFinishLaunching, "v@:@")
}
if template.applicationWillBecomeActive != nil {
applicationWillBecomeActive :: proc "c" (self: id, notification: ^Notification) {
applicationWillBecomeActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationWillBecomeActive(notification)
@@ -280,7 +280,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationWillBecomeActive:"), auto_cast applicationWillBecomeActive, "v@:@")
}
if template.applicationDidBecomeActive != nil {
applicationDidBecomeActive :: proc "c" (self: id, notification: ^Notification) {
applicationDidBecomeActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidBecomeActive(notification)
@@ -288,7 +288,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDidBecomeActive:"), auto_cast applicationDidBecomeActive, "v@:@")
}
if template.applicationWillResignActive != nil {
applicationWillResignActive :: proc "c" (self: id, notification: ^Notification) {
applicationWillResignActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationWillResignActive(notification)
@@ -296,7 +296,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationWillResignActive:"), auto_cast applicationWillResignActive, "v@:@")
}
if template.applicationDidResignActive != nil {
applicationDidResignActive :: proc "c" (self: id, notification: ^Notification) {
applicationDidResignActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidResignActive(notification)
@@ -304,7 +304,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDidResignActive:"), auto_cast applicationDidResignActive, "v@:@")
}
if template.applicationShouldTerminate != nil {
applicationShouldTerminate :: proc "c" (self: id, sender: ^Application) -> ApplicationTerminateReply {
applicationShouldTerminate :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> ApplicationTerminateReply {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationShouldTerminate(sender)
@@ -312,7 +312,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldTerminate:"), auto_cast applicationShouldTerminate, _UINTEGER_ENCODING+"@:@")
}
if template.applicationShouldTerminateAfterLastWindowClosed != nil {
applicationShouldTerminateAfterLastWindowClosed :: proc "c" (self: id, sender: ^Application) -> BOOL {
applicationShouldTerminateAfterLastWindowClosed :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationShouldTerminateAfterLastWindowClosed(sender)
@@ -320,7 +320,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldTerminateAfterLastWindowClosed:"), auto_cast applicationShouldTerminateAfterLastWindowClosed, "B@:@")
}
if template.applicationWillTerminate != nil {
applicationWillTerminate :: proc "c" (self: id, notification: ^Notification) {
applicationWillTerminate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationWillTerminate(notification)
@@ -328,7 +328,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationWillTerminate:"), auto_cast applicationWillTerminate, "v@:@")
}
if template.applicationWillHide != nil {
applicationWillHide :: proc "c" (self: id, notification: ^Notification) {
applicationWillHide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationWillHide(notification)
@@ -336,7 +336,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationWillHide:"), auto_cast applicationWillHide, "v@:@")
}
if template.applicationDidHide != nil {
applicationDidHide :: proc "c" (self: id, notification: ^Notification) {
applicationDidHide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidHide(notification)
@@ -344,7 +344,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDidHide:"), auto_cast applicationDidHide, "v@:@")
}
if template.applicationWillUnhide != nil {
applicationWillUnhide :: proc "c" (self: id, notification: ^Notification) {
applicationWillUnhide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationWillUnhide(notification)
@@ -352,7 +352,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationWillUnhide:"), auto_cast applicationWillUnhide, "v@:@")
}
if template.applicationDidUnhide != nil {
applicationDidUnhide :: proc "c" (self: id, notification: ^Notification) {
applicationDidUnhide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidUnhide(notification)
@@ -360,7 +360,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDidUnhide:"), auto_cast applicationDidUnhide, "v@:@")
}
if template.applicationWillUpdate != nil {
applicationWillUpdate :: proc "c" (self: id, notification: ^Notification) {
applicationWillUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationWillUpdate(notification)
@@ -368,7 +368,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationWillUpdate:"), auto_cast applicationWillUpdate, "v@:@")
}
if template.applicationDidUpdate != nil {
applicationDidUpdate :: proc "c" (self: id, notification: ^Notification) {
applicationDidUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidUpdate(notification)
@@ -376,7 +376,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDidUpdate:"), auto_cast applicationDidUpdate, "v@:@")
}
if template.applicationShouldHandleReopenHasVisibleWindows != nil {
applicationShouldHandleReopenHasVisibleWindows :: proc "c" (self: id, sender: ^Application, flag: BOOL) -> BOOL {
applicationShouldHandleReopenHasVisibleWindows :: proc "c" (self: id, cmd: SEL, sender: ^Application, flag: BOOL) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationShouldHandleReopenHasVisibleWindows(sender, flag)
@@ -384,7 +384,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldHandleReopen:hasVisibleWindows:"), auto_cast applicationShouldHandleReopenHasVisibleWindows, "B@:@B")
}
if template.applicationDockMenu != nil {
applicationDockMenu :: proc "c" (self: id, sender: ^Application) -> ^Menu {
applicationDockMenu :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> ^Menu {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationDockMenu(sender)
@@ -392,7 +392,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDockMenu:"), auto_cast applicationDockMenu, "@@:@")
}
if template.applicationShouldAutomaticallyLocalizeKeyEquivalents != nil {
applicationShouldAutomaticallyLocalizeKeyEquivalents :: proc "c" (self: id, application: ^Application) -> BOOL {
applicationShouldAutomaticallyLocalizeKeyEquivalents :: proc "c" (self: id, cmd: SEL, application: ^Application) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationShouldAutomaticallyLocalizeKeyEquivalents(application)
@@ -400,7 +400,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldAutomaticallyLocalizeKeyEquivalents:"), auto_cast applicationShouldAutomaticallyLocalizeKeyEquivalents, "B@:@")
}
if template.applicationWillPresentError != nil {
applicationWillPresentError :: proc "c" (self: id, application: ^Application, error: ^Error) -> ^Error {
applicationWillPresentError :: proc "c" (self: id, cmd: SEL, application: ^Application, error: ^Error) -> ^Error {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationWillPresentError(application, error)
@@ -408,7 +408,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:willPresentError:"), auto_cast applicationWillPresentError, "@@:@@")
}
if template.applicationDidChangeScreenParameters != nil {
applicationDidChangeScreenParameters :: proc "c" (self: id, notification: ^Notification) {
applicationDidChangeScreenParameters :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidChangeScreenParameters(notification)
@@ -416,7 +416,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDidChangeScreenParameters:"), auto_cast applicationDidChangeScreenParameters, "v@:@")
}
if template.applicationWillContinueUserActivityWithType != nil {
applicationWillContinueUserActivityWithType :: proc "c" (self: id, application: ^Application, userActivityType: ^String) -> BOOL {
applicationWillContinueUserActivityWithType :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivityType: ^String) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationWillContinueUserActivityWithType(application, userActivityType)
@@ -424,7 +424,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:willContinueUserActivityWithType:"), auto_cast applicationWillContinueUserActivityWithType, "B@:@@")
}
if template.applicationContinueUserActivityRestorationHandler != nil {
applicationContinueUserActivityRestorationHandler :: proc "c" (self: id, application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL {
applicationContinueUserActivityRestorationHandler :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationContinueUserActivityRestorationHandler(application, userActivity, restorationHandler)
@@ -432,7 +432,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:continueUserActivity:restorationHandler:"), auto_cast applicationContinueUserActivityRestorationHandler, "B@:@@?")
}
if template.applicationDidFailToContinueUserActivityWithTypeError != nil {
applicationDidFailToContinueUserActivityWithTypeError :: proc "c" (self: id, application: ^Application, userActivityType: ^String, error: ^Error) {
applicationDidFailToContinueUserActivityWithTypeError :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivityType: ^String, error: ^Error) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidFailToContinueUserActivityWithTypeError(application, userActivityType, error)
@@ -440,7 +440,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:didFailToContinueUserActivityWithType:error:"), auto_cast applicationDidFailToContinueUserActivityWithTypeError, "v@:@@@")
}
if template.applicationDidUpdateUserActivity != nil {
applicationDidUpdateUserActivity :: proc "c" (self: id, application: ^Application, userActivity: ^UserActivity) {
applicationDidUpdateUserActivity :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivity: ^UserActivity) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidUpdateUserActivity(application, userActivity)
@@ -448,7 +448,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:didUpdateUserActivity:"), auto_cast applicationDidUpdateUserActivity, "v@:@@")
}
if template.applicationDidRegisterForRemoteNotificationsWithDeviceToken != nil {
applicationDidRegisterForRemoteNotificationsWithDeviceToken :: proc "c" (self: id, application: ^Application, deviceToken: ^Data) {
applicationDidRegisterForRemoteNotificationsWithDeviceToken :: proc "c" (self: id, cmd: SEL, application: ^Application, deviceToken: ^Data) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidRegisterForRemoteNotificationsWithDeviceToken(application, deviceToken)
@@ -456,7 +456,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:didRegisterForRemoteNotificationsWithDeviceToken:"), auto_cast applicationDidRegisterForRemoteNotificationsWithDeviceToken, "v@:@@")
}
if template.applicationDidFailToRegisterForRemoteNotificationsWithError != nil {
applicationDidFailToRegisterForRemoteNotificationsWithError :: proc "c" (self: id, application: ^Application, error: ^Error) {
applicationDidFailToRegisterForRemoteNotificationsWithError :: proc "c" (self: id, cmd: SEL, application: ^Application, error: ^Error) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidFailToRegisterForRemoteNotificationsWithError(application, error)
@@ -464,7 +464,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:didFailToRegisterForRemoteNotificationsWithError:"), auto_cast applicationDidFailToRegisterForRemoteNotificationsWithError, "v@:@@")
}
if template.applicationDidReceiveRemoteNotification != nil {
applicationDidReceiveRemoteNotification :: proc "c" (self: id, application: ^Application, userInfo: ^Dictionary) {
applicationDidReceiveRemoteNotification :: proc "c" (self: id, cmd: SEL, application: ^Application, userInfo: ^Dictionary) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidReceiveRemoteNotification(application, userInfo)
@@ -472,7 +472,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:didReceiveRemoteNotification:"), auto_cast applicationDidReceiveRemoteNotification, "v@:@@")
}
// if template.applicationUserDidAcceptCloudKitShareWithMetadata != nil {
// applicationUserDidAcceptCloudKitShareWithMetadata :: proc "c" (self: id, application: ^Application, metadata: ^CKShareMetadata) {
// applicationUserDidAcceptCloudKitShareWithMetadata :: proc "c" (self: id, cmd: SEL, application: ^Application, metadata: ^CKShareMetadata) {
// del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
// context = del._context
// del.applicationUserDidAcceptCloudKitShareWithMetadata(application, metadata)
@@ -480,7 +480,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
// class_addMethod(class, intrinsics.objc_find_selector("application:userDidAcceptCloudKitShareWithMetadata:"), auto_cast applicationUserDidAcceptCloudKitShareWithMetadata, "v@:@@")
// }
// if template.applicationHandlerForIntent != nil {
// applicationHandlerForIntent :: proc "c" (self: id, application: ^Application, intent: ^INIntent) -> id {
// applicationHandlerForIntent :: proc "c" (self: id, cmd: SEL, application: ^Application, intent: ^INIntent) -> id {
// del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
// context = del._context
// return del.applicationHandlerForIntent(application, intent)
@@ -488,7 +488,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
// class_addMethod(class, intrinsics.objc_find_selector("application:handlerForIntent:"), auto_cast applicationHandlerForIntent, "@@:@@")
// }
if template.applicationOpenURLs != nil {
applicationOpenURLs :: proc "c" (self: id, application: ^Application, urls: ^Array) {
applicationOpenURLs :: proc "c" (self: id, cmd: SEL, application: ^Application, urls: ^Array) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationOpenURLs(application, urls)
@@ -496,7 +496,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:openURLs:"), auto_cast applicationOpenURLs, "v@:@@")
}
if template.applicationOpenFile != nil {
applicationOpenFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL {
applicationOpenFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationOpenFile(sender, filename)
@@ -504,7 +504,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:openFile:"), auto_cast applicationOpenFile, "B@:@@")
}
if template.applicationOpenFileWithoutUI != nil {
applicationOpenFileWithoutUI :: proc "c" (self: id, sender: id, filename: ^String) -> BOOL {
applicationOpenFileWithoutUI :: proc "c" (self: id, cmd: SEL, sender: id, filename: ^String) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationOpenFileWithoutUI(sender, filename)
@@ -512,7 +512,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:openFileWithoutUI:"), auto_cast applicationOpenFileWithoutUI, "B@:@@")
}
if template.applicationOpenTempFile != nil {
applicationOpenTempFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL {
applicationOpenTempFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationOpenTempFile(sender, filename)
@@ -520,7 +520,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:openTempFile:"), auto_cast applicationOpenTempFile, "B@:@@")
}
if template.applicationOpenFiles != nil {
applicationOpenFiles :: proc "c" (self: id, sender: ^Application, filenames: ^Array) {
applicationOpenFiles :: proc "c" (self: id, cmd: SEL, sender: ^Application, filenames: ^Array) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationOpenFiles(sender, filenames)
@@ -528,7 +528,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:openFiles:"), auto_cast applicationOpenFiles, "v@:@@")
}
if template.applicationShouldOpenUntitledFile != nil {
applicationShouldOpenUntitledFile :: proc "c" (self: id, sender: ^Application) -> BOOL {
applicationShouldOpenUntitledFile :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationShouldOpenUntitledFile(sender)
@@ -536,7 +536,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldOpenUntitledFile:"), auto_cast applicationShouldOpenUntitledFile, "B@:@")
}
if template.applicationOpenUntitledFile != nil {
applicationOpenUntitledFile :: proc "c" (self: id, sender: ^Application) -> BOOL {
applicationOpenUntitledFile :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationOpenUntitledFile(sender)
@@ -544,7 +544,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationOpenUntitledFile:"), auto_cast applicationOpenUntitledFile, "B@:@")
}
if template.applicationPrintFile != nil {
applicationPrintFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL {
applicationPrintFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationPrintFile(sender, filename)
@@ -552,7 +552,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:printFile:"), auto_cast applicationPrintFile, "B@:@@")
}
if template.applicationPrintFilesWithSettingsShowPrintPanels != nil {
applicationPrintFilesWithSettingsShowPrintPanels :: proc "c" (self: id, application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply {
applicationPrintFilesWithSettingsShowPrintPanels :: proc "c" (self: id, cmd: SEL, application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationPrintFilesWithSettingsShowPrintPanels(application, fileNames, printSettings, showPrintPanels)
@@ -560,7 +560,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:printFiles:withSettings:showPrintPanels:"), auto_cast applicationPrintFilesWithSettingsShowPrintPanels, _UINTEGER_ENCODING+"@:@@@B")
}
if template.applicationSupportsSecureRestorableState != nil {
applicationSupportsSecureRestorableState :: proc "c" (self: id, app: ^Application) -> BOOL {
applicationSupportsSecureRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationSupportsSecureRestorableState(app)
@@ -568,7 +568,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationSupportsSecureRestorableState:"), auto_cast applicationSupportsSecureRestorableState, "B@:@")
}
if template.applicationProtectedDataDidBecomeAvailable != nil {
applicationProtectedDataDidBecomeAvailable :: proc "c" (self: id, notification: ^Notification) {
applicationProtectedDataDidBecomeAvailable :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationProtectedDataDidBecomeAvailable(notification)
@@ -576,7 +576,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationProtectedDataDidBecomeAvailable:"), auto_cast applicationProtectedDataDidBecomeAvailable, "v@:@")
}
if template.applicationProtectedDataWillBecomeUnavailable != nil {
applicationProtectedDataWillBecomeUnavailable :: proc "c" (self: id, notification: ^Notification) {
applicationProtectedDataWillBecomeUnavailable :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationProtectedDataWillBecomeUnavailable(notification)
@@ -584,7 +584,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationProtectedDataWillBecomeUnavailable:"), auto_cast applicationProtectedDataWillBecomeUnavailable, "v@:@")
}
if template.applicationWillEncodeRestorableState != nil {
applicationWillEncodeRestorableState :: proc "c" (self: id, app: ^Application, coder: ^Coder) {
applicationWillEncodeRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application, coder: ^Coder) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationWillEncodeRestorableState(app, coder)
@@ -592,7 +592,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:willEncodeRestorableState:"), auto_cast applicationWillEncodeRestorableState, "v@:@@")
}
if template.applicationDidDecodeRestorableState != nil {
applicationDidDecodeRestorableState :: proc "c" (self: id, app: ^Application, coder: ^Coder) {
applicationDidDecodeRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application, coder: ^Coder) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidDecodeRestorableState(app, coder)
@@ -600,7 +600,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("application:didDecodeRestorableState:"), auto_cast applicationDidDecodeRestorableState, "v@:@@")
}
if template.applicationDidChangeOcclusionState != nil {
applicationDidChangeOcclusionState :: proc "c" (self: id, notification: ^Notification) {
applicationDidChangeOcclusionState :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.applicationDidChangeOcclusionState(notification)
@@ -608,7 +608,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
class_addMethod(class, intrinsics.objc_find_selector("applicationDidChangeOcclusionState:"), auto_cast applicationDidChangeOcclusionState, "v@:@")
}
if template.applicationDelegateHandlesKey != nil {
applicationDelegateHandlesKey :: proc "c" (self: id, sender: ^Application, key: ^String) -> BOOL {
applicationDelegateHandlesKey :: proc "c" (self: id, cmd: SEL, sender: ^Application, key: ^String) -> BOOL {
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.applicationDelegateHandlesKey(sender, key)
+52 -52
View File
@@ -146,7 +146,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
return nil
}
if template.windowWillPositionSheetUsingRect != nil {
windowWillPositionSheetUsingRect :: proc "c" (self: id, window: ^Window, sheet: ^Window, rect: Rect) -> Rect {
windowWillPositionSheetUsingRect :: proc "c" (self: id, cmd: SEL, window: ^Window, sheet: ^Window, rect: Rect) -> Rect {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowWillPositionSheetUsingRect(window, sheet, rect)
@@ -154,7 +154,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:willPositionSheet:usingRect:"), auto_cast windowWillPositionSheetUsingRect, _RECT_ENCODING+"@:@@"+_RECT_ENCODING)
}
if template.windowWillBeginSheet != nil {
windowWillBeginSheet :: proc "c" (self: id, notification: ^Notification) {
windowWillBeginSheet :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillBeginSheet(notification)
@@ -162,7 +162,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillBeginSheet:"), auto_cast windowWillBeginSheet, "v@:@")
}
if template.windowDidEndSheet != nil {
windowDidEndSheet :: proc "c" (self: id, notification: ^Notification) {
windowDidEndSheet :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidEndSheet(notification)
@@ -170,7 +170,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidEndSheet:"), auto_cast windowDidEndSheet, "v@:@")
}
if template.windowWillResizeToSize != nil {
windowWillResizeToSize :: proc "c" (self: id, sender: ^Window, frameSize: Size) -> Size {
windowWillResizeToSize :: proc "c" (self: id, cmd: SEL, sender: ^Window, frameSize: Size) -> Size {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowWillResizeToSize(sender, frameSize)
@@ -178,7 +178,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillResize:toSize:"), auto_cast windowWillResizeToSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING)
}
if template.windowDidResize != nil {
windowDidResize :: proc "c" (self: id, notification: ^Notification) {
windowDidResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidResize(notification)
@@ -186,7 +186,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidResize:"), auto_cast windowDidResize, "v@:@")
}
if template.windowWillStartLiveResize != nil {
windowWillStartLiveResize :: proc "c" (self: id, notification: ^Notification) {
windowWillStartLiveResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillStartLiveResize(notification)
@@ -194,7 +194,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillStartLiveResize:"), auto_cast windowWillStartLiveResize, "v@:@")
}
if template.windowDidEndLiveResize != nil {
windowDidEndLiveResize :: proc "c" (self: id, notification: ^Notification) {
windowDidEndLiveResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidEndLiveResize(notification)
@@ -202,7 +202,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidEndLiveResize:"), auto_cast windowDidEndLiveResize, "v@:@")
}
if template.windowWillMiniaturize != nil {
windowWillMiniaturize :: proc "c" (self: id, notification: ^Notification) {
windowWillMiniaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillMiniaturize(notification)
@@ -210,7 +210,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillMiniaturize:"), auto_cast windowWillMiniaturize, "v@:@")
}
if template.windowDidMiniaturize != nil {
windowDidMiniaturize :: proc "c" (self: id, notification: ^Notification) {
windowDidMiniaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidMiniaturize(notification)
@@ -218,7 +218,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidMiniaturize:"), auto_cast windowDidMiniaturize, "v@:@")
}
if template.windowDidDeminiaturize != nil {
windowDidDeminiaturize :: proc "c" (self: id, notification: ^Notification) {
windowDidDeminiaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidDeminiaturize(notification)
@@ -226,7 +226,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidDeminiaturize:"), auto_cast windowDidDeminiaturize, "v@:@")
}
if template.windowWillUseStandardFrameDefaultFrame != nil {
windowWillUseStandardFrameDefaultFrame :: proc(self: id, window: ^Window, newFrame: Rect) -> Rect {
windowWillUseStandardFrameDefaultFrame :: proc(self: id, cmd: SEL, window: ^Window, newFrame: Rect) -> Rect {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowWillUseStandardFrameDefaultFrame(window, newFrame)
@@ -234,7 +234,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillUseStandardFrame:defaultFrame:"), auto_cast windowWillUseStandardFrameDefaultFrame, _RECT_ENCODING+"@:@"+_RECT_ENCODING)
}
if template.windowShouldZoomToFrame != nil {
windowShouldZoomToFrame :: proc "c" (self: id, window: ^Window, newFrame: Rect) -> BOOL {
windowShouldZoomToFrame :: proc "c" (self: id, cmd: SEL, window: ^Window, newFrame: Rect) -> BOOL {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowShouldZoomToFrame(window, newFrame)
@@ -242,7 +242,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowShouldZoom:toFrame:"), auto_cast windowShouldZoomToFrame, "B@:@"+_RECT_ENCODING)
}
if template.windowWillUseFullScreenContentSize != nil {
windowWillUseFullScreenContentSize :: proc "c" (self: id, window: ^Window, proposedSize: Size) -> Size {
windowWillUseFullScreenContentSize :: proc "c" (self: id, cmd: SEL, window: ^Window, proposedSize: Size) -> Size {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowWillUseFullScreenContentSize(window, proposedSize)
@@ -250,7 +250,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:willUseFullScreenContentSize:"), auto_cast windowWillUseFullScreenContentSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING)
}
if template.windowWillUseFullScreenPresentationOptions != nil {
windowWillUseFullScreenPresentationOptions :: proc(self: id, window: ^Window, proposedOptions: ApplicationPresentationOptions) -> ApplicationPresentationOptions {
windowWillUseFullScreenPresentationOptions :: proc(self: id, cmd: SEL, window: ^Window, proposedOptions: ApplicationPresentationOptions) -> ApplicationPresentationOptions {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowWillUseFullScreenPresentationOptions(window, proposedOptions)
@@ -258,7 +258,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:willUseFullScreenPresentationOptions:"), auto_cast windowWillUseFullScreenPresentationOptions, _UINTEGER_ENCODING+"@:@"+_UINTEGER_ENCODING)
}
if template.windowWillEnterFullScreen != nil {
windowWillEnterFullScreen :: proc "c" (self: id, notification: ^Notification) {
windowWillEnterFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillEnterFullScreen(notification)
@@ -266,7 +266,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillEnterFullScreen:"), auto_cast windowWillEnterFullScreen, "v@:@")
}
if template.windowDidEnterFullScreen != nil {
windowDidEnterFullScreen :: proc "c" (self: id, notification: ^Notification) {
windowDidEnterFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidEnterFullScreen(notification)
@@ -274,7 +274,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidEnterFullScreen:"), auto_cast windowDidEnterFullScreen, "v@:@")
}
if template.windowWillExitFullScreen != nil {
windowWillExitFullScreen :: proc "c" (self: id, notification: ^Notification) {
windowWillExitFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillExitFullScreen(notification)
@@ -282,7 +282,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillExitFullScreen:"), auto_cast windowWillExitFullScreen, "v@:@")
}
if template.windowDidExitFullScreen != nil {
windowDidExitFullScreen :: proc "c" (self: id, notification: ^Notification) {
windowDidExitFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidExitFullScreen(notification)
@@ -290,7 +290,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidExitFullScreen:"), auto_cast windowDidExitFullScreen, "v@:@")
}
if template.customWindowsToEnterFullScreenForWindow != nil {
customWindowsToEnterFullScreenForWindow :: proc "c" (self: id, window: ^Window) -> ^Array {
customWindowsToEnterFullScreenForWindow :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^Array {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.customWindowsToEnterFullScreenForWindow(window)
@@ -298,7 +298,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("customWindowsToEnterFullScreenForWindow:"), auto_cast customWindowsToEnterFullScreenForWindow, "@@:@")
}
if template.customWindowsToEnterFullScreenForWindowOnScreen != nil {
customWindowsToEnterFullScreenForWindowOnScreen :: proc(self: id, window: ^Window, screen: ^Screen) -> ^Array {
customWindowsToEnterFullScreenForWindowOnScreen :: proc(self: id, cmd: SEL, window: ^Window, screen: ^Screen) -> ^Array {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.customWindowsToEnterFullScreenForWindowOnScreen(window, screen)
@@ -306,7 +306,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("customWindowsToEnterFullScreenForWindow:onScreen:"), auto_cast customWindowsToEnterFullScreenForWindowOnScreen, "@@:@@")
}
if template.windowStartCustomAnimationToEnterFullScreenWithDuration != nil {
windowStartCustomAnimationToEnterFullScreenWithDuration :: proc "c" (self: id, window: ^Window, duration: TimeInterval) {
windowStartCustomAnimationToEnterFullScreenWithDuration :: proc "c" (self: id, cmd: SEL, window: ^Window, duration: TimeInterval) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowStartCustomAnimationToEnterFullScreenWithDuration(window, duration)
@@ -314,7 +314,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToEnterFullScreenWithDuration:"), auto_cast windowStartCustomAnimationToEnterFullScreenWithDuration, "v@:@@")
}
if template.windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration != nil {
windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration :: proc(self: id, window: ^Window, screen: ^Screen, duration: TimeInterval) {
windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration :: proc(self: id, cmd: SEL, window: ^Window, screen: ^Screen, duration: TimeInterval) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration(window, screen, duration)
@@ -322,7 +322,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToEnterFullScreenOnScreen:withDuration:"), auto_cast windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration, "v@:@@d")
}
if template.windowDidFailToEnterFullScreen != nil {
windowDidFailToEnterFullScreen :: proc "c" (self: id, window: ^Window) {
windowDidFailToEnterFullScreen :: proc "c" (self: id, cmd: SEL, window: ^Window) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidFailToEnterFullScreen(window)
@@ -330,7 +330,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidFailToEnterFullScreen:"), auto_cast windowDidFailToEnterFullScreen, "v@:@")
}
if template.customWindowsToExitFullScreenForWindow != nil {
customWindowsToExitFullScreenForWindow :: proc "c" (self: id, window: ^Window) -> ^Array {
customWindowsToExitFullScreenForWindow :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^Array {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.customWindowsToExitFullScreenForWindow(window)
@@ -338,7 +338,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("customWindowsToExitFullScreenForWindow:"), auto_cast customWindowsToExitFullScreenForWindow, "@@:@")
}
if template.windowStartCustomAnimationToExitFullScreenWithDuration != nil {
windowStartCustomAnimationToExitFullScreenWithDuration :: proc "c" (self: id, window: ^Window, duration: TimeInterval) {
windowStartCustomAnimationToExitFullScreenWithDuration :: proc "c" (self: id, cmd: SEL, window: ^Window, duration: TimeInterval) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowStartCustomAnimationToExitFullScreenWithDuration(window, duration)
@@ -346,7 +346,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToExitFullScreenWithDuration:"), auto_cast windowStartCustomAnimationToExitFullScreenWithDuration, "v@:@d")
}
if template.windowDidFailToExitFullScreen != nil {
windowDidFailToExitFullScreen :: proc "c" (self: id, window: ^Window) {
windowDidFailToExitFullScreen :: proc "c" (self: id, cmd: SEL, window: ^Window) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidFailToExitFullScreen(window)
@@ -354,7 +354,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidFailToExitFullScreen:"), auto_cast windowDidFailToExitFullScreen, "v@:@")
}
if template.windowWillMove != nil {
windowWillMove :: proc "c" (self: id, notification: ^Notification) {
windowWillMove :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillMove(notification)
@@ -362,7 +362,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillMove:"), auto_cast windowWillMove, "v@:@")
}
if template.windowDidMove != nil {
windowDidMove :: proc "c" (self: id, notification: ^Notification) {
windowDidMove :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidMove(notification)
@@ -370,7 +370,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidMove:"), auto_cast windowDidMove, "v@:@")
}
if template.windowDidChangeScreen != nil {
windowDidChangeScreen :: proc "c" (self: id, notification: ^Notification) {
windowDidChangeScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidChangeScreen(notification)
@@ -378,7 +378,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeScreen:"), auto_cast windowDidChangeScreen, "v@:@")
}
if template.windowDidChangeScreenProfile != nil {
windowDidChangeScreenProfile :: proc "c" (self: id, notification: ^Notification) {
windowDidChangeScreenProfile :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidChangeScreenProfile(notification)
@@ -386,7 +386,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeScreenProfile:"), auto_cast windowDidChangeScreenProfile, "v@:@")
}
if template.windowDidChangeBackingProperties != nil {
windowDidChangeBackingProperties :: proc "c" (self: id, notification: ^Notification) {
windowDidChangeBackingProperties :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidChangeBackingProperties(notification)
@@ -394,7 +394,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeBackingProperties:"), auto_cast windowDidChangeBackingProperties, "v@:@")
}
if template.windowShouldClose != nil {
windowShouldClose :: proc "c" (self:id, sender: ^Window) -> BOOL {
windowShouldClose :: proc "c" (self:id, cmd: SEL, sender: ^Window) -> BOOL {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowShouldClose(sender)
@@ -402,7 +402,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowShouldClose:"), auto_cast windowShouldClose, "B@:@")
}
if template.windowWillClose != nil {
windowWillClose :: proc "c" (self:id, notification: ^Notification) {
windowWillClose :: proc "c" (self:id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillClose(notification)
@@ -410,7 +410,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillClose:"), auto_cast windowWillClose, "v@:@")
}
if template.windowDidBecomeKey != nil {
windowDidBecomeKey :: proc "c" (self: id, notification: ^Notification) {
windowDidBecomeKey :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidBecomeKey(notification)
@@ -418,7 +418,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidBecomeKey:"), auto_cast windowDidBecomeKey, "v@:@")
}
if template.windowDidResignKey != nil {
windowDidResignKey :: proc "c" (self: id, notification: ^Notification) {
windowDidResignKey :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidResignKey(notification)
@@ -426,7 +426,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidResignKey:"), auto_cast windowDidResignKey, "v@:@")
}
if template.windowDidBecomeMain != nil {
windowDidBecomeMain :: proc "c" (self: id, notification: ^Notification) {
windowDidBecomeMain :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidBecomeMain(notification)
@@ -434,7 +434,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidBecomeMain:"), auto_cast windowDidBecomeMain, "v@:@")
}
if template.windowDidResignMain != nil {
windowDidResignMain :: proc "c" (self: id, notification: ^Notification) {
windowDidResignMain :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidResignMain(notification)
@@ -442,7 +442,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidResignMain:"), auto_cast windowDidResignMain, "v@:@")
}
if template.windowWillReturnFieldEditorToObject != nil {
windowWillReturnFieldEditorToObject :: proc "c" (self:id, sender: ^Window, client: id) -> id {
windowWillReturnFieldEditorToObject :: proc "c" (self:id, cmd: SEL, sender: ^Window, client: id) -> id {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowWillReturnFieldEditorToObject(sender, client)
@@ -450,7 +450,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillReturnFieldEditor:toObject:"), auto_cast windowWillReturnFieldEditorToObject, "@@:@@")
}
if template.windowDidUpdate != nil {
windowDidUpdate :: proc "c" (self: id, notification: ^Notification) {
windowDidUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidUpdate(notification)
@@ -458,7 +458,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidUpdate:"), auto_cast windowDidUpdate, "v@:@")
}
if template.windowDidExpose != nil {
windowDidExpose :: proc "c" (self: id, notification: ^Notification) {
windowDidExpose :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidExpose(notification)
@@ -466,7 +466,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidExpose:"), auto_cast windowDidExpose, "v@:@")
}
if template.windowDidChangeOcclusionState != nil {
windowDidChangeOcclusionState :: proc "c" (self: id, notification: ^Notification) {
windowDidChangeOcclusionState :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidChangeOcclusionState(notification)
@@ -474,7 +474,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeOcclusionState:"), auto_cast windowDidChangeOcclusionState, "v@:@")
}
if template.windowShouldDragDocumentWithEventFromWithPasteboard != nil {
windowShouldDragDocumentWithEventFromWithPasteboard :: proc "c" (self: id, window: ^Window, event: ^Event, dragImageLocation: Point, pasteboard: ^Pasteboard) -> BOOL {
windowShouldDragDocumentWithEventFromWithPasteboard :: proc "c" (self: id, cmd: SEL, window: ^Window, event: ^Event, dragImageLocation: Point, pasteboard: ^Pasteboard) -> BOOL {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowShouldDragDocumentWithEventFromWithPasteboard(window, event, dragImageLocation, pasteboard)
@@ -482,7 +482,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:shouldDragDocumentWithEvent:from:withPasteboard:"), auto_cast windowShouldDragDocumentWithEventFromWithPasteboard, "B@:@@"+_POINT_ENCODING+"@")
}
if template.windowWillReturnUndoManager != nil {
windowWillReturnUndoManager :: proc "c" (self: id, window: ^Window) -> ^UndoManager {
windowWillReturnUndoManager :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^UndoManager {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowWillReturnUndoManager(window)
@@ -490,7 +490,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillReturnUndoManager:"), auto_cast windowWillReturnUndoManager, "@@:@")
}
if template.windowShouldPopUpDocumentPathMenu != nil {
windowShouldPopUpDocumentPathMenu :: proc "c" (self: id, window: ^Window, menu: ^Menu) -> BOOL {
windowShouldPopUpDocumentPathMenu :: proc "c" (self: id, cmd: SEL, window: ^Window, menu: ^Menu) -> BOOL {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowShouldPopUpDocumentPathMenu(window, menu)
@@ -498,7 +498,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:shouldPopUpDocumentPathMenu:"), auto_cast windowShouldPopUpDocumentPathMenu, "B@:@@")
}
if template.windowWillEncodeRestorableState != nil {
windowWillEncodeRestorableState :: proc "c" (self: id, window: ^Window, state: ^Coder) {
windowWillEncodeRestorableState :: proc "c" (self: id, cmd: SEL, window: ^Window, state: ^Coder) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillEncodeRestorableState(window, state)
@@ -506,7 +506,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:willEncodeRestorableState:"), auto_cast windowWillEncodeRestorableState, "v@:@@")
}
if template.windowDidEncodeRestorableState != nil {
windowDidEncodeRestorableState :: proc "c" (self: id, window: ^Window, state: ^Coder) {
windowDidEncodeRestorableState :: proc "c" (self: id, cmd: SEL, window: ^Window, state: ^Coder) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidEncodeRestorableState(window, state)
@@ -514,7 +514,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:didDecodeRestorableState:"), auto_cast windowDidEncodeRestorableState, "v@:@@")
}
if template.windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize != nil {
windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize :: proc "c" (self: id, window: ^Window, maxPreferredFrameSize: Size, maxAllowedFrameSize: Size) -> Size {
windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize :: proc "c" (self: id, cmd: SEL, window: ^Window, maxPreferredFrameSize: Size, maxAllowedFrameSize: Size) -> Size {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
return del.windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize(window, maxPreferredFrameSize, maxPreferredFrameSize)
@@ -522,7 +522,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("window:willResizeForVersionBrowserWithMaxPreferredSize:maxAllowedSize:"), auto_cast windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING+_SIZE_ENCODING)
}
if template.windowWillEnterVersionBrowser != nil {
windowWillEnterVersionBrowser :: proc "c" (self: id, notification: ^Notification) {
windowWillEnterVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillEnterVersionBrowser(notification)
@@ -530,7 +530,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillEnterVersionBrowser:"), auto_cast windowWillEnterVersionBrowser, "v@:@")
}
if template.windowDidEnterVersionBrowser != nil {
windowDidEnterVersionBrowser :: proc "c" (self: id, notification: ^Notification) {
windowDidEnterVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidEnterVersionBrowser(notification)
@@ -538,7 +538,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowDidEnterVersionBrowser:"), auto_cast windowDidEnterVersionBrowser, "v@:@")
}
if template.windowWillExitVersionBrowser != nil {
windowWillExitVersionBrowser :: proc "c" (self: id, notification: ^Notification) {
windowWillExitVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowWillExitVersionBrowser(notification)
@@ -546,7 +546,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
class_addMethod(class, intrinsics.objc_find_selector("windowWillExitVersionBrowser:"), auto_cast windowWillExitVersionBrowser, "v@:@")
}
if template.windowDidExitVersionBrowser != nil {
windowDidExitVersionBrowser :: proc "c" (self: id, notification: ^Notification) {
windowDidExitVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
context = del._context
del.windowDidExitVersionBrowser(notification)
@@ -780,4 +780,4 @@ Window_performWindowDragWithEvent :: proc "c" (self: ^Window, event: ^Event) {
@(objc_type=Window, objc_name="setToolbar")
Window_setToolbar :: proc "c" (self: ^Window, toolbar: ^Toolbar) {
msgSend(nil, self, "setToolbar:", toolbar)
}
}
+12 -12
View File
@@ -204,21 +204,21 @@ accept_nil :: proc "contextless" (s: Fd) -> (Fd, Errno) {
accept :: proc { accept_T, accept_nil }
getsockname_or_peername :: proc "contextless" (s: Fd, sockaddr: ^$T, is_peer: bool) -> Errno {
// sockaddr must contain a valid pointer, or this will segfault because
// we're telling the syscall that there's memory available to write to.
addrlen: socklen_t = size_of(T)
// sockaddr must contain a valid pointer, or this will segfault because
// we're telling the syscall that there's memory available to write to.
addrlen: socklen_t = size_of(T)
result, ok := intrinsics.syscall_bsd(
is_peer ? SYS_getpeername : SYS_getsockname,
cast(uintptr)s,
cast(uintptr)sockaddr,
cast(uintptr)&addrlen)
result, ok := intrinsics.syscall_bsd(
is_peer ? SYS_getpeername : SYS_getsockname,
cast(uintptr)s,
cast(uintptr)sockaddr,
cast(uintptr)&addrlen)
if !ok {
return cast(Errno)result
}
if !ok {
return cast(Errno)result
}
return nil
return nil
}
// Get name of connected peer
+10 -6
View File
@@ -40,9 +40,13 @@ CPU_Feature :: enum u64 {
}
CPU_Features :: distinct bit_set[CPU_Feature; u64]
cpu_features: Maybe(CPU_Features)
cpu_name: Maybe(string)
CPU :: struct {
name: Maybe(string),
features: Maybe(CPU_Features),
physical_cores: int,
logical_cores: int,
}
cpu: CPU
@(private)
cpu_name_buf: [128]byte
@@ -53,7 +57,7 @@ init_cpu_name :: proc "contextless" () {
when ODIN_OS == .Darwin {
if unix.sysctlbyname("machdep.cpu.brand_string", &cpu_name_buf) {
cpu_name = string(cstring(rawptr(&cpu_name_buf)))
cpu.name = string(cstring(rawptr(&cpu_name_buf)))
generic = false
}
}
@@ -61,10 +65,10 @@ init_cpu_name :: proc "contextless" () {
if generic {
when ODIN_ARCH == .arm64 {
copy(cpu_name_buf[:], "ARM64")
cpu_name = string(cpu_name_buf[:len("ARM64")])
cpu.name = string(cpu_name_buf[:len("ARM64")])
} else {
copy(cpu_name_buf[:], "ARM")
cpu_name = string(cpu_name_buf[:len("ARM")])
cpu.name = string(cpu_name_buf[:len("ARM")])
}
}
}
+12
View File
@@ -0,0 +1,12 @@
package sysinfo
import "core:sys/unix"
@(init, private)
init_cpu_core_count :: proc "contextless" () {
physical, logical: i64
unix.sysctlbyname("hw.physicalcpu", &physical)
unix.sysctlbyname("hw.logicalcpu", &logical)
cpu.physical_cores = int(physical)
cpu.logical_cores = int(logical)
}
+1 -1
View File
@@ -5,7 +5,7 @@ import "core:sys/unix"
@(init, private)
init_cpu_features :: proc "contextless" () {
@(static) features: CPU_Features
defer cpu_features = features
defer cpu.features = features
try_set :: proc "contextless" (name: cstring, feature: CPU_Feature) -> (ok: bool) {
support: b32
+16 -12
View File
@@ -3,12 +3,6 @@ package sysinfo
import "base:intrinsics"
// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
cpuid :: intrinsics.x86_cpuid
// xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
xgetbv :: intrinsics.x86_xgetbv
CPU_Feature :: enum u64 {
aes, // AES hardware implementation (AES NI)
adx, // Multi-precision add-carry instruction extensions
@@ -49,9 +43,13 @@ CPU_Feature :: enum u64 {
}
CPU_Features :: distinct bit_set[CPU_Feature; u64]
cpu_features: Maybe(CPU_Features)
cpu_name: Maybe(string)
CPU :: struct {
name: Maybe(string),
features: Maybe(CPU_Features),
physical_cores: int, // Initialized by cpu_<os>.odin
logical_cores: int, // Initialized by cpu_<os>.odin
}
cpu: CPU
@(init, private)
init_cpu_features :: proc "c" () {
@@ -88,7 +86,7 @@ init_cpu_features :: proc "c" () {
when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
// xgetbv is an illegal instruction under FreeBSD 13, OpenBSD 7.1 and NetBSD 10
// return before probing further
cpu_features = set
cpu.features = set
return
}
@@ -151,7 +149,7 @@ init_cpu_features :: proc "c" () {
try_set(&set, .rdseed, 18, ebx7)
try_set(&set, .adx, 19, ebx7)
cpu_features = set
cpu.features = set
}
@(private)
@@ -179,5 +177,11 @@ init_cpu_name :: proc "c" () {
for len(brand) > 0 && brand[len(brand) - 1] == 0 || brand[len(brand) - 1] == ' ' {
brand = brand[:len(brand) - 1]
}
cpu_name = brand
cpu.name = brand
}
// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
cpuid :: intrinsics.x86_cpuid
// xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
xgetbv :: intrinsics.x86_xgetbv
+1 -1
View File
@@ -17,7 +17,7 @@ init_cpu_features :: proc() {
if rerr != .NONE || n == 0 { return }
features: CPU_Features
defer cpu_features = features
defer cpu.features = features
str := string(buf[:n])
for line in strings.split_lines_iterator(&str) {
+38
View File
@@ -0,0 +1,38 @@
#+build i386, amd64
#+build linux
package sysinfo
import "core:sys/linux"
import "core:strings"
import "core:strconv"
@(init, private)
init_cpu_core_count :: proc() {
fd, err := linux.open("/proc/cpuinfo", {})
if err != .NONE { return }
defer linux.close(fd)
// This is probably enough right?
buf: [4096]byte
n, rerr := linux.read(fd, buf[:])
if rerr != .NONE || n == 0 { return }
str := string(buf[:n])
for line in strings.split_lines_iterator(&str) {
key, _, value := strings.partition(line, ":")
key = strings.trim_space(key)
value = strings.trim_space(value)
if key == "cpu cores" {
if num_physical_cores, ok := strconv.parse_int(value); ok {
cpu.physical_cores = num_physical_cores
}
}
if key == "siblings" {
if num_logical_cores, ok := strconv.parse_int(value); ok {
cpu.logical_cores = num_logical_cores
}
}
}
}
+2 -2
View File
@@ -9,7 +9,7 @@ import "core:sys/linux"
@(init, private)
init_cpu_features :: proc() {
_features: CPU_Features
defer cpu_features = _features
defer cpu.features = _features
HWCAP_Bits :: enum u64 {
I = 'I' - 'A',
@@ -109,5 +109,5 @@ init_cpu_features :: proc() {
@(init, private)
init_cpu_name :: proc() {
cpu_name = "RISCV64"
cpu.name = "RISCV64"
}
+7 -3
View File
@@ -95,6 +95,10 @@ CPU_Feature :: enum u64 {
}
CPU_Features :: distinct bit_set[CPU_Feature; u64]
cpu_features: Maybe(CPU_Features)
cpu_name: Maybe(string)
CPU :: struct {
name: Maybe(string),
features: Maybe(CPU_Features),
physical_cores: int,
logical_cores: int,
}
cpu: CPU
+28
View File
@@ -0,0 +1,28 @@
package sysinfo
import sys "core:sys/windows"
import "base:intrinsics"
@(init, private)
init_cpu_core_count :: proc() {
infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION
defer delete(infos)
returned_length: sys.DWORD
// Query for the required buffer size.
if ok := sys.GetLogicalProcessorInformation(raw_data(infos), &returned_length); !ok {
infos = make([]sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returned_length / size_of(sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION))
}
// If it still doesn't work, return
if ok := sys.GetLogicalProcessorInformation(raw_data(infos), &returned_length); !ok {
return
}
for info in infos {
#partial switch info.Relationship {
case .RelationProcessorCore: cpu.physical_cores += 1
case .RelationNumaNode: cpu.logical_cores += int(intrinsics.count_ones(info.ProcessorMask))
}
}
}
+8 -6
View File
@@ -26,13 +26,15 @@ Example:
import si "core:sys/info"
main :: proc() {
fmt.printfln("Odin: %v", ODIN_VERSION)
fmt.printfln("OS: %v", si.os_version.as_string)
fmt.printfln("OS: %#v", si.os_version)
fmt.printfln("CPU: %v", si.cpu_name)
fmt.printfln("RAM: %#.1M", si.ram.total_ram)
fmt.printfln("Odin: %v", ODIN_VERSION)
fmt.printfln("OS: %v", si.os_version.as_string)
fmt.printfln("OS: %#v", si.os_version)
fmt.printfln("CPU: %v", si.cpu.name)
fmt.printfln("CPU: %v", si.cpu.name)
fmt.printfln("CPU cores: %vc/%vt", si.cpu.physical_cores, si.cpu.logical_cores)
fmt.printfln("RAM: %#.1M", si.ram.total_ram)
// fmt.printfln("Features: %v", si.cpu_features)
// fmt.printfln("Features: %v", si.cpu.features)
// fmt.printfln("MacOS version: %v", si.macos_version)
fmt.println()
+10 -5
View File
@@ -50,7 +50,7 @@ foreign lib {
/*
Send a signal to a thread.
As with kill, if sig is 0, only validation (of the pthread_t given) is done and no signal is sent.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html ]]
@@ -124,7 +124,7 @@ foreign lib {
sigignore :: proc(sig: Signal) -> result ---
/*
Removes sig from the signal mask of the calling process and suspend the calling process until
Removes sig from the signal mask of the calling process and suspend the calling process until
a signal is received.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html ]]
@@ -166,7 +166,7 @@ foreign lib {
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigpending.html ]]
*/
@(link_name=LSIGPENDING)
sigpending :: proc(set: ^sigset_t) -> result ---
sigpending :: proc(set: ^sigset_t) -> result ---
/*
Wait for one of the given signals.
@@ -333,7 +333,7 @@ SS_Flag_Bits :: enum c.int {
SS_Flags :: bit_set[SS_Flag_Bits; c.int]
Sig :: enum c.int {
// Resulting set is the union of the current set and the signal set and the complement of
// Resulting set is the union of the current set and the signal set and the complement of
// the signal set pointed to by the argument.
BLOCK = SIG_BLOCK,
// Resulting set is the intersection of the current set and the complement of the signal set
@@ -395,6 +395,7 @@ when ODIN_OS == .Darwin {
SIGXFSZ :: 25
SIGVTALRM :: 26
SIGPROF :: 27
SIGWINCH :: 28
SIGUSR1 :: 30
SIGUSR2 :: 31
@@ -535,6 +536,7 @@ when ODIN_OS == .Darwin {
SIGXFSZ :: 25
SIGVTALRM :: 26
SIGPROF :: 27
SIGWINCH :: 28
SIGUSR1 :: 30
SIGUSR2 :: 31
@@ -699,6 +701,7 @@ when ODIN_OS == .Darwin {
SIGXFSZ :: 25
SIGVTALRM :: 26
SIGPROF :: 27
SIGWINCH :: 28
SIGUSR1 :: 30
SIGUSR2 :: 31
@@ -876,6 +879,7 @@ when ODIN_OS == .Darwin {
SIGXFSZ :: 25
SIGVTALRM :: 26
SIGPROF :: 27
SIGWINCH :: 28
SIGUSR1 :: 30
SIGUSR2 :: 31
@@ -1036,6 +1040,7 @@ when ODIN_OS == .Darwin {
SIGXFSZ :: 25
SIGVTALRM :: 26
SIGPROF :: 27
SIGWINCH :: 28
SIGPOLL :: 29
SIGSYS :: 31
@@ -1084,7 +1089,7 @@ when ODIN_OS == .Darwin {
@(private)
__SI_MAX_SIZE :: 128
when size_of(int) == 8 {
when size_of(int) == 8 {
@(private)
_pad0 :: struct {
_pad0: c.int,
+3 -7
View File
@@ -110,16 +110,12 @@ class WasmMemoryInterface {
}
loadCstring(ptr) {
return this.loadCstringDirect(this.loadPtr(ptr));
}
loadCstringDirect(start) {
if (start == 0) {
if (ptr == 0) {
return null;
}
let len = 0;
for (; this.mem.getUint8(start+len) != 0; len += 1) {}
return this.loadString(start, len);
for (; this.mem.getUint8(ptr+len) != 0; len += 1) {}
return this.loadString(ptr, len);
}
storeU8(addr, value) { this.mem.setUint8 (addr, value); }
+1 -2
View File
@@ -857,7 +857,6 @@ MEMORY_RESOURCE_NOTIFICATION_TYPE :: enum c_int {
LowMemoryResourceNotification :: MEMORY_RESOURCE_NOTIFICATION_TYPE.LowMemoryResourceNotification
HighMemoryResourceNotification :: MEMORY_RESOURCE_NOTIFICATION_TYPE.HighMemoryResourceNotification
@(default_calling_convention="system")
foreign kernel32 {
CreateMemoryResourceNotification :: proc(
@@ -1194,7 +1193,7 @@ DUMMYUNIONNAME_u :: struct #raw_union {
SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct {
ProcessorMask: ULONG_PTR,
Relationship: LOGICAL_PROCESSOR_RELATIONSHIP,
DummyUnion: DUMMYUNIONNAME_u,
using DummyUnion: DUMMYUNIONNAME_u,
}
SYSTEM_POWER_STATUS :: struct {
+2
View File
@@ -52,6 +52,8 @@ foreign Ole32 {
ppv: ^LPVOID,
) -> HRESULT ---
CoTaskMemAlloc :: proc(cb: SIZE_T) -> rawptr ---
CoTaskMemRealloc :: proc(pv: rawptr, cb: SIZE_T) -> rawptr ---
CoTaskMemFree :: proc(pv: rawptr) ---
CLSIDFromProgID :: proc(lpszProgID: LPCOLESTR, lpclsid: LPCLSID) -> HRESULT ---
+8
View File
@@ -173,6 +173,9 @@ FACILITY :: enum DWORD {
EAS = 85,
WEB = 885,
WEB_SOCKET = 886,
XAUDIO2 = 896,
XAPO = 897,
GAMEINPUT = 906,
MOBILE = 1793,
SQLITE = 1967,
SERVICE_FABRIC = 1968,
@@ -231,6 +234,7 @@ ERROR_PIPE_BUSY : DWORD : 231
// https://learn.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values
S_OK :: 0x00000000 // Operation successful
S_FALSE :: 0x00000001
E_NOTIMPL :: 0x80004001 // Not implemented
E_NOINTERFACE :: 0x80004002 // No such interface supported
E_POINTER :: 0x80004003 // Pointer that is not valid
@@ -270,6 +274,10 @@ MAKE_HRESULT :: #force_inline proc "contextless" (#any_int sev: int, #any_int fa
return HRESULT((uint(sev)<<31) | (uint(fac)<<16) | (uint(code)))
}
HRESULT_FROM_WIN32 :: #force_inline proc "contextless" (#any_int code: int) -> HRESULT {
return HRESULT(code) <= 0 ? HRESULT(code) : HRESULT(uint(code & 0x0000FFFF) | (uint(FACILITY.WIN32) << 16) | 0x80000000)
}
DECODE_HRESULT :: #force_inline proc "contextless" (#any_int hr: int) -> (SEVERITY, FACILITY, int) {
return HRESULT_SEVERITY(hr), HRESULT_FACILITY(hr), HRESULT_CODE(hr)
}
+330 -17
View File
@@ -265,7 +265,7 @@ HWAVE :: distinct HANDLE
HWAVEIN :: distinct HANDLE
HWAVEOUT :: distinct HANDLE
LPHWAVEIN :: ^HWAVEIN
LPHWAVEIN :: ^HWAVEIN
LPHWAVEOUT :: ^HWAVEOUT
// https://learn.microsoft.com/en-us/windows/win32/multimedia/multimedia-timer-structures
@@ -311,9 +311,284 @@ MAXPNAMELEN :: 32
MAXERRORLENGTH :: 256
MMVERSION :: UINT
// Input is four characters string
// Output is little-endian u32 representation
MAKEFOURCC :: #force_inline proc "contextless" (s: [4]byte) -> DWORD {
return (DWORD(s[0])) | (DWORD(s[1]) << 8) | (DWORD(s[2]) << 16) | (DWORD(s[3]) << 24 )
}
/* flags for wFormatTag field of WAVEFORMAT */
WAVE_FORMAT_PCM :: 1
WAVE_FORMAT_UNKNOWN :: 0x0000 /* Microsoft Corporation */
WAVE_FORMAT_ADPCM :: 0x0002 /* Microsoft Corporation */
WAVE_FORMAT_IEEE_FLOAT :: 0x0003 /* Microsoft Corporation */
WAVE_FORMAT_VSELP :: 0x0004 /* Compaq Computer Corp. */
WAVE_FORMAT_IBM_CVSD :: 0x0005 /* IBM Corporation */
WAVE_FORMAT_ALAW :: 0x0006 /* Microsoft Corporation */
WAVE_FORMAT_MULAW :: 0x0007 /* Microsoft Corporation */
WAVE_FORMAT_DTS :: 0x0008 /* Microsoft Corporation */
WAVE_FORMAT_DRM :: 0x0009 /* Microsoft Corporation */
WAVE_FORMAT_WMAVOICE9 :: 0x000A /* Microsoft Corporation */
WAVE_FORMAT_WMAVOICE10 :: 0x000B /* Microsoft Corporation */
WAVE_FORMAT_OKI_ADPCM :: 0x0010 /* OKI */
WAVE_FORMAT_DVI_ADPCM :: 0x0011 /* Intel Corporation */
WAVE_FORMAT_IMA_ADPCM :: WAVE_FORMAT_DVI_ADPCM /* Intel Corporation */
WAVE_FORMAT_MEDIASPACE_ADPCM :: 0x0012 /* Videologic */
WAVE_FORMAT_SIERRA_ADPCM :: 0x0013 /* Sierra Semiconductor Corp */
WAVE_FORMAT_G723_ADPCM :: 0x0014 /* Antex Electronics Corporation */
WAVE_FORMAT_DIGISTD :: 0x0015 /* DSP Solutions, Inc. */
WAVE_FORMAT_DIGIFIX :: 0x0016 /* DSP Solutions, Inc. */
WAVE_FORMAT_DIALOGIC_OKI_ADPCM :: 0x0017 /* Dialogic Corporation */
WAVE_FORMAT_MEDIAVISION_ADPCM :: 0x0018 /* Media Vision, Inc. */
WAVE_FORMAT_CU_CODEC :: 0x0019 /* Hewlett-Packard Company */
WAVE_FORMAT_HP_DYN_VOICE :: 0x001A /* Hewlett-Packard Company */
WAVE_FORMAT_YAMAHA_ADPCM :: 0x0020 /* Yamaha Corporation of America */
WAVE_FORMAT_SONARC :: 0x0021 /* Speech Compression */
WAVE_FORMAT_DSPGROUP_TRUESPEECH :: 0x0022 /* DSP Group, Inc */
WAVE_FORMAT_ECHOSC1 :: 0x0023 /* Echo Speech Corporation */
WAVE_FORMAT_AUDIOFILE_AF36 :: 0x0024 /* Virtual Music, Inc. */
WAVE_FORMAT_APTX :: 0x0025 /* Audio Processing Technology */
WAVE_FORMAT_AUDIOFILE_AF10 :: 0x0026 /* Virtual Music, Inc. */
WAVE_FORMAT_PROSODY_1612 :: 0x0027 /* Aculab plc */
WAVE_FORMAT_LRC :: 0x0028 /* Merging Technologies S.A. */
WAVE_FORMAT_DOLBY_AC2 :: 0x0030 /* Dolby Laboratories */
WAVE_FORMAT_GSM610 :: 0x0031 /* Microsoft Corporation */
WAVE_FORMAT_MSNAUDIO :: 0x0032 /* Microsoft Corporation */
WAVE_FORMAT_ANTEX_ADPCME :: 0x0033 /* Antex Electronics Corporation */
WAVE_FORMAT_CONTROL_RES_VQLPC :: 0x0034 /* Control Resources Limited */
WAVE_FORMAT_DIGIREAL :: 0x0035 /* DSP Solutions, Inc. */
WAVE_FORMAT_DIGIADPCM :: 0x0036 /* DSP Solutions, Inc. */
WAVE_FORMAT_CONTROL_RES_CR10 :: 0x0037 /* Control Resources Limited */
WAVE_FORMAT_NMS_VBXADPCM :: 0x0038 /* Natural MicroSystems */
WAVE_FORMAT_CS_IMAADPCM :: 0x0039 /* Crystal Semiconductor IMA ADPCM */
WAVE_FORMAT_ECHOSC3 :: 0x003A /* Echo Speech Corporation */
WAVE_FORMAT_ROCKWELL_ADPCM :: 0x003B /* Rockwell International */
WAVE_FORMAT_ROCKWELL_DIGITALK :: 0x003C /* Rockwell International */
WAVE_FORMAT_XEBEC :: 0x003D /* Xebec Multimedia Solutions Limited */
WAVE_FORMAT_G721_ADPCM :: 0x0040 /* Antex Electronics Corporation */
WAVE_FORMAT_G728_CELP :: 0x0041 /* Antex Electronics Corporation */
WAVE_FORMAT_MSG723 :: 0x0042 /* Microsoft Corporation */
WAVE_FORMAT_INTEL_G723_1 :: 0x0043 /* Intel Corp. */
WAVE_FORMAT_INTEL_G729 :: 0x0044 /* Intel Corp. */
WAVE_FORMAT_SHARP_G726 :: 0x0045 /* Sharp */
WAVE_FORMAT_MPEG :: 0x0050 /* Microsoft Corporation */
WAVE_FORMAT_RT24 :: 0x0052 /* InSoft, Inc. */
WAVE_FORMAT_PAC :: 0x0053 /* InSoft, Inc. */
WAVE_FORMAT_MPEGLAYER3 :: 0x0055 /* ISO/MPEG Layer3 Format Tag */
WAVE_FORMAT_LUCENT_G723 :: 0x0059 /* Lucent Technologies */
WAVE_FORMAT_CIRRUS :: 0x0060 /* Cirrus Logic */
WAVE_FORMAT_ESPCM :: 0x0061 /* ESS Technology */
WAVE_FORMAT_VOXWARE :: 0x0062 /* Voxware Inc */
WAVE_FORMAT_CANOPUS_ATRAC :: 0x0063 /* Canopus, co., Ltd. */
WAVE_FORMAT_G726_ADPCM :: 0x0064 /* APICOM */
WAVE_FORMAT_G722_ADPCM :: 0x0065 /* APICOM */
WAVE_FORMAT_DSAT :: 0x0066 /* Microsoft Corporation */
WAVE_FORMAT_DSAT_DISPLAY :: 0x0067 /* Microsoft Corporation */
WAVE_FORMAT_VOXWARE_BYTE_ALIGNED :: 0x0069 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_AC8 :: 0x0070 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_AC10 :: 0x0071 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_AC16 :: 0x0072 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_AC20 :: 0x0073 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_RT24 :: 0x0074 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_RT29 :: 0x0075 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_RT29HW :: 0x0076 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_VR12 :: 0x0077 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_VR18 :: 0x0078 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_TQ40 :: 0x0079 /* Voxware Inc */
WAVE_FORMAT_VOXWARE_SC3 :: 0x007A /* Voxware Inc */
WAVE_FORMAT_VOXWARE_SC3_1 :: 0x007B /* Voxware Inc */
WAVE_FORMAT_SOFTSOUND :: 0x0080 /* Softsound, Ltd. */
WAVE_FORMAT_VOXWARE_TQ60 :: 0x0081 /* Voxware Inc */
WAVE_FORMAT_MSRT24 :: 0x0082 /* Microsoft Corporation */
WAVE_FORMAT_G729A :: 0x0083 /* AT&T Labs, Inc. */
WAVE_FORMAT_MVI_MVI2 :: 0x0084 /* Motion Pixels */
WAVE_FORMAT_DF_G726 :: 0x0085 /* DataFusion Systems (Pty) (Ltd) */
WAVE_FORMAT_DF_GSM610 :: 0x0086 /* DataFusion Systems (Pty) (Ltd) */
WAVE_FORMAT_ISIAUDIO :: 0x0088 /* Iterated Systems, Inc. */
WAVE_FORMAT_ONLIVE :: 0x0089 /* OnLive! Technologies, Inc. */
WAVE_FORMAT_MULTITUDE_FT_SX20 :: 0x008A /* Multitude Inc. */
WAVE_FORMAT_INFOCOM_ITS_G721_ADPCM :: 0x008B /* Infocom */
WAVE_FORMAT_CONVEDIA_G729 :: 0x008C /* Convedia Corp. */
WAVE_FORMAT_CONGRUENCY :: 0x008D /* Congruency Inc. */
WAVE_FORMAT_SBC24 :: 0x0091 /* Siemens Business Communications Sys */
WAVE_FORMAT_DOLBY_AC3_SPDIF :: 0x0092 /* Sonic Foundry */
WAVE_FORMAT_MEDIASONIC_G723 :: 0x0093 /* MediaSonic */
WAVE_FORMAT_PROSODY_8KBPS :: 0x0094 /* Aculab plc */
WAVE_FORMAT_ZYXEL_ADPCM :: 0x0097 /* ZyXEL Communications, Inc. */
WAVE_FORMAT_PHILIPS_LPCBB :: 0x0098 /* Philips Speech Processing */
WAVE_FORMAT_PACKED :: 0x0099 /* Studer Professional Audio AG */
WAVE_FORMAT_MALDEN_PHONYTALK :: 0x00A0 /* Malden Electronics Ltd. */
WAVE_FORMAT_RACAL_RECORDER_GSM :: 0x00A1 /* Racal recorders */
WAVE_FORMAT_RACAL_RECORDER_G720_A :: 0x00A2 /* Racal recorders */
WAVE_FORMAT_RACAL_RECORDER_G723_1 :: 0x00A3 /* Racal recorders */
WAVE_FORMAT_RACAL_RECORDER_TETRA_ACELP :: 0x00A4 /* Racal recorders */
WAVE_FORMAT_NEC_AAC :: 0x00B0 /* NEC Corp. */
WAVE_FORMAT_RAW_AAC1 :: 0x00FF /* For Raw AAC, with format block AudioSpecificConfig() (as defined by MPEG-4), that follows WAVEFORMATEX */
WAVE_FORMAT_RHETOREX_ADPCM :: 0x0100 /* Rhetorex Inc. */
WAVE_FORMAT_IRAT :: 0x0101 /* BeCubed Software Inc. */
WAVE_FORMAT_VIVO_G723 :: 0x0111 /* Vivo Software */
WAVE_FORMAT_VIVO_SIREN :: 0x0112 /* Vivo Software */
WAVE_FORMAT_PHILIPS_CELP :: 0x0120 /* Philips Speech Processing */
WAVE_FORMAT_PHILIPS_GRUNDIG :: 0x0121 /* Philips Speech Processing */
WAVE_FORMAT_DIGITAL_G723 :: 0x0123 /* Digital Equipment Corporation */
WAVE_FORMAT_SANYO_LD_ADPCM :: 0x0125 /* Sanyo Electric Co., Ltd. */
WAVE_FORMAT_SIPROLAB_ACEPLNET :: 0x0130 /* Sipro Lab Telecom Inc. */
WAVE_FORMAT_SIPROLAB_ACELP4800 :: 0x0131 /* Sipro Lab Telecom Inc. */
WAVE_FORMAT_SIPROLAB_ACELP8V3 :: 0x0132 /* Sipro Lab Telecom Inc. */
WAVE_FORMAT_SIPROLAB_G729 :: 0x0133 /* Sipro Lab Telecom Inc. */
WAVE_FORMAT_SIPROLAB_G729A :: 0x0134 /* Sipro Lab Telecom Inc. */
WAVE_FORMAT_SIPROLAB_KELVIN :: 0x0135 /* Sipro Lab Telecom Inc. */
WAVE_FORMAT_VOICEAGE_AMR :: 0x0136 /* VoiceAge Corp. */
WAVE_FORMAT_G726ADPCM :: 0x0140 /* Dictaphone Corporation */
WAVE_FORMAT_DICTAPHONE_CELP68 :: 0x0141 /* Dictaphone Corporation */
WAVE_FORMAT_DICTAPHONE_CELP54 :: 0x0142 /* Dictaphone Corporation */
WAVE_FORMAT_QUALCOMM_PUREVOICE :: 0x0150 /* Qualcomm, Inc. */
WAVE_FORMAT_QUALCOMM_HALFRATE :: 0x0151 /* Qualcomm, Inc. */
WAVE_FORMAT_TUBGSM :: 0x0155 /* Ring Zero Systems, Inc. */
WAVE_FORMAT_MSAUDIO1 :: 0x0160 /* Microsoft Corporation */
WAVE_FORMAT_WMAUDIO2 :: 0x0161 /* Microsoft Corporation */
WAVE_FORMAT_WMAUDIO3 :: 0x0162 /* Microsoft Corporation */
WAVE_FORMAT_WMAUDIO_LOSSLESS :: 0x0163 /* Microsoft Corporation */
WAVE_FORMAT_WMASPDIF :: 0x0164 /* Microsoft Corporation */
WAVE_FORMAT_UNISYS_NAP_ADPCM :: 0x0170 /* Unisys Corp. */
WAVE_FORMAT_UNISYS_NAP_ULAW :: 0x0171 /* Unisys Corp. */
WAVE_FORMAT_UNISYS_NAP_ALAW :: 0x0172 /* Unisys Corp. */
WAVE_FORMAT_UNISYS_NAP_16K :: 0x0173 /* Unisys Corp. */
WAVE_FORMAT_SYCOM_ACM_SYC008 :: 0x0174 /* SyCom Technologies */
WAVE_FORMAT_SYCOM_ACM_SYC701_G726L :: 0x0175 /* SyCom Technologies */
WAVE_FORMAT_SYCOM_ACM_SYC701_CELP54 :: 0x0176 /* SyCom Technologies */
WAVE_FORMAT_SYCOM_ACM_SYC701_CELP68 :: 0x0177 /* SyCom Technologies */
WAVE_FORMAT_KNOWLEDGE_ADVENTURE_ADPCM :: 0x0178 /* Knowledge Adventure, Inc. */
WAVE_FORMAT_FRAUNHOFER_IIS_MPEG2_AAC :: 0x0180 /* Fraunhofer IIS */
WAVE_FORMAT_DTS_DS :: 0x0190 /* Digital Theatre Systems, Inc. */
WAVE_FORMAT_CREATIVE_ADPCM :: 0x0200 /* Creative Labs, Inc */
WAVE_FORMAT_CREATIVE_FASTSPEECH8 :: 0x0202 /* Creative Labs, Inc */
WAVE_FORMAT_CREATIVE_FASTSPEECH10 :: 0x0203 /* Creative Labs, Inc */
WAVE_FORMAT_UHER_ADPCM :: 0x0210 /* UHER informatic GmbH */
WAVE_FORMAT_ULEAD_DV_AUDIO :: 0x0215 /* Ulead Systems, Inc. */
WAVE_FORMAT_ULEAD_DV_AUDIO_1 :: 0x0216 /* Ulead Systems, Inc. */
WAVE_FORMAT_QUARTERDECK :: 0x0220 /* Quarterdeck Corporation */
WAVE_FORMAT_ILINK_VC :: 0x0230 /* I-link Worldwide */
WAVE_FORMAT_RAW_SPORT :: 0x0240 /* Aureal Semiconductor */
WAVE_FORMAT_ESST_AC3 :: 0x0241 /* ESS Technology, Inc. */
WAVE_FORMAT_GENERIC_PASSTHRU :: 0x0249
WAVE_FORMAT_IPI_HSX :: 0x0250 /* Interactive Products, Inc. */
WAVE_FORMAT_IPI_RPELP :: 0x0251 /* Interactive Products, Inc. */
WAVE_FORMAT_CS2 :: 0x0260 /* Consistent Software */
WAVE_FORMAT_SONY_SCX :: 0x0270 /* Sony Corp. */
WAVE_FORMAT_SONY_SCY :: 0x0271 /* Sony Corp. */
WAVE_FORMAT_SONY_ATRAC3 :: 0x0272 /* Sony Corp. */
WAVE_FORMAT_SONY_SPC :: 0x0273 /* Sony Corp. */
WAVE_FORMAT_TELUM_AUDIO :: 0x0280 /* Telum Inc. */
WAVE_FORMAT_TELUM_IA_AUDIO :: 0x0281 /* Telum Inc. */
WAVE_FORMAT_NORCOM_VOICE_SYSTEMS_ADPCM :: 0x0285 /* Norcom Electronics Corp. */
WAVE_FORMAT_FM_TOWNS_SND :: 0x0300 /* Fujitsu Corp. */
WAVE_FORMAT_MICRONAS :: 0x0350 /* Micronas Semiconductors, Inc. */
WAVE_FORMAT_MICRONAS_CELP833 :: 0x0351 /* Micronas Semiconductors, Inc. */
WAVE_FORMAT_BTV_DIGITAL :: 0x0400 /* Brooktree Corporation */
WAVE_FORMAT_INTEL_MUSIC_CODER :: 0x0401 /* Intel Corp. */
WAVE_FORMAT_INDEO_AUDIO :: 0x0402 /* Ligos */
WAVE_FORMAT_QDESIGN_MUSIC :: 0x0450 /* QDesign Corporation */
WAVE_FORMAT_ON2_VP7_AUDIO :: 0x0500 /* On2 Technologies */
WAVE_FORMAT_ON2_VP6_AUDIO :: 0x0501 /* On2 Technologies */
WAVE_FORMAT_VME_VMPCM :: 0x0680 /* AT&T Labs, Inc. */
WAVE_FORMAT_TPC :: 0x0681 /* AT&T Labs, Inc. */
WAVE_FORMAT_LIGHTWAVE_LOSSLESS :: 0x08AE /* Clearjump */
WAVE_FORMAT_OLIGSM :: 0x1000 /* Ing C. Olivetti & C., S.p.A. */
WAVE_FORMAT_OLIADPCM :: 0x1001 /* Ing C. Olivetti & C., S.p.A. */
WAVE_FORMAT_OLICELP :: 0x1002 /* Ing C. Olivetti & C., S.p.A. */
WAVE_FORMAT_OLISBC :: 0x1003 /* Ing C. Olivetti & C., S.p.A. */
WAVE_FORMAT_OLIOPR :: 0x1004 /* Ing C. Olivetti & C., S.p.A. */
WAVE_FORMAT_LH_CODEC :: 0x1100 /* Lernout & Hauspie */
WAVE_FORMAT_LH_CODEC_CELP :: 0x1101 /* Lernout & Hauspie */
WAVE_FORMAT_LH_CODEC_SBC8 :: 0x1102 /* Lernout & Hauspie */
WAVE_FORMAT_LH_CODEC_SBC12 :: 0x1103 /* Lernout & Hauspie */
WAVE_FORMAT_LH_CODEC_SBC16 :: 0x1104 /* Lernout & Hauspie */
WAVE_FORMAT_NORRIS :: 0x1400 /* Norris Communications, Inc. */
WAVE_FORMAT_ISIAUDIO_2 :: 0x1401 /* ISIAudio */
WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS :: 0x1500 /* AT&T Labs, Inc. */
WAVE_FORMAT_MPEG_ADTS_AAC :: 0x1600 /* Microsoft Corporation */
WAVE_FORMAT_MPEG_RAW_AAC :: 0x1601 /* Microsoft Corporation */
WAVE_FORMAT_MPEG_LOAS :: 0x1602 /* Microsoft Corporation (MPEG-4 Audio Transport Streams (LOAS/LATM) */
WAVE_FORMAT_NOKIA_MPEG_ADTS_AAC :: 0x1608 /* Microsoft Corporation */
WAVE_FORMAT_NOKIA_MPEG_RAW_AAC :: 0x1609 /* Microsoft Corporation */
WAVE_FORMAT_VODAFONE_MPEG_ADTS_AAC :: 0x160A /* Microsoft Corporation */
WAVE_FORMAT_VODAFONE_MPEG_RAW_AAC :: 0x160B /* Microsoft Corporation */
WAVE_FORMAT_MPEG_HEAAC :: 0x1610 /* Microsoft Corporation (MPEG-2 AAC or MPEG-4 HE-AAC v1/v2 streams with any payload (ADTS, ADIF, LOAS/LATM, RAW). Format block includes MP4 AudioSpecificConfig() -- see HEAACWAVEFORMAT below */
WAVE_FORMAT_VOXWARE_RT24_SPEECH :: 0x181C /* Voxware Inc. */
WAVE_FORMAT_SONICFOUNDRY_LOSSLESS :: 0x1971 /* Sonic Foundry */
WAVE_FORMAT_INNINGS_TELECOM_ADPCM :: 0x1979 /* Innings Telecom Inc. */
WAVE_FORMAT_LUCENT_SX8300P :: 0x1C07 /* Lucent Technologies */
WAVE_FORMAT_LUCENT_SX5363S :: 0x1C0C /* Lucent Technologies */
WAVE_FORMAT_CUSEEME :: 0x1F03 /* CUSeeMe */
WAVE_FORMAT_NTCSOFT_ALF2CM_ACM :: 0x1FC4 /* NTCSoft */
WAVE_FORMAT_DVM :: 0x2000 /* FAST Multimedia AG */
WAVE_FORMAT_DTS2 :: 0x2001
WAVE_FORMAT_MAKEAVIS :: 0x3313
WAVE_FORMAT_DIVIO_MPEG4_AAC :: 0x4143 /* Divio, Inc. */
WAVE_FORMAT_NOKIA_ADAPTIVE_MULTIRATE :: 0x4201 /* Nokia */
WAVE_FORMAT_DIVIO_G726 :: 0x4243 /* Divio, Inc. */
WAVE_FORMAT_LEAD_SPEECH :: 0x434C /* LEAD Technologies */
WAVE_FORMAT_LEAD_VORBIS :: 0x564C /* LEAD Technologies */
WAVE_FORMAT_WAVPACK_AUDIO :: 0x5756 /* xiph.org */
WAVE_FORMAT_ALAC :: 0x6C61 /* Apple Lossless */
WAVE_FORMAT_OGG_VORBIS_MODE_1 :: 0x674F /* Ogg Vorbis */
WAVE_FORMAT_OGG_VORBIS_MODE_2 :: 0x6750 /* Ogg Vorbis */
WAVE_FORMAT_OGG_VORBIS_MODE_3 :: 0x6751 /* Ogg Vorbis */
WAVE_FORMAT_OGG_VORBIS_MODE_1_PLUS :: 0x676F /* Ogg Vorbis */
WAVE_FORMAT_OGG_VORBIS_MODE_2_PLUS :: 0x6770 /* Ogg Vorbis */
WAVE_FORMAT_OGG_VORBIS_MODE_3_PLUS :: 0x6771 /* Ogg Vorbis */
WAVE_FORMAT_3COM_NBX :: 0x7000 /* 3COM Corp. */
WAVE_FORMAT_OPUS :: 0x704F /* Opus */
WAVE_FORMAT_FAAD_AAC :: 0x706D
WAVE_FORMAT_AMR_NB :: 0x7361 /* AMR Narrowband */
WAVE_FORMAT_AMR_WB :: 0x7362 /* AMR Wideband */
WAVE_FORMAT_AMR_WP :: 0x7363 /* AMR Wideband Plus */
WAVE_FORMAT_GSM_AMR_CBR :: 0x7A21 /* GSMA/3GPP */
WAVE_FORMAT_GSM_AMR_VBR_SID :: 0x7A22 /* GSMA/3GPP */
WAVE_FORMAT_COMVERSE_INFOSYS_G723_1 :: 0xA100 /* Comverse Infosys */
WAVE_FORMAT_COMVERSE_INFOSYS_AVQSBC :: 0xA101 /* Comverse Infosys */
WAVE_FORMAT_COMVERSE_INFOSYS_SBC :: 0xA102 /* Comverse Infosys */
WAVE_FORMAT_SYMBOL_G729_A :: 0xA103 /* Symbol Technologies */
WAVE_FORMAT_VOICEAGE_AMR_WB :: 0xA104 /* VoiceAge Corp. */
WAVE_FORMAT_INGENIENT_G726 :: 0xA105 /* Ingenient Technologies, Inc. */
WAVE_FORMAT_MPEG4_AAC :: 0xA106 /* ISO/MPEG-4 */
WAVE_FORMAT_ENCORE_G726 :: 0xA107 /* Encore Software */
WAVE_FORMAT_ZOLL_ASAO :: 0xA108 /* ZOLL Medical Corp. */
WAVE_FORMAT_SPEEX_VOICE :: 0xA109 /* xiph.org */
WAVE_FORMAT_VIANIX_MASC :: 0xA10A /* Vianix LLC */
WAVE_FORMAT_WM9_SPECTRUM_ANALYZER :: 0xA10B /* Microsoft */
WAVE_FORMAT_WMF_SPECTRUM_ANAYZER :: 0xA10C /* Microsoft */
WAVE_FORMAT_GSM_610 :: 0xA10D
WAVE_FORMAT_GSM_620 :: 0xA10E
WAVE_FORMAT_GSM_660 :: 0xA10F
WAVE_FORMAT_GSM_690 :: 0xA110
WAVE_FORMAT_GSM_ADAPTIVE_MULTIRATE_WB :: 0xA111
WAVE_FORMAT_POLYCOM_G722 :: 0xA112 /* Polycom */
WAVE_FORMAT_POLYCOM_G728 :: 0xA113 /* Polycom */
WAVE_FORMAT_POLYCOM_G729_A :: 0xA114 /* Polycom */
WAVE_FORMAT_POLYCOM_SIREN :: 0xA115 /* Polycom */
WAVE_FORMAT_GLOBAL_IP_ILBC :: 0xA116 /* Global IP */
WAVE_FORMAT_RADIOTIME_TIME_SHIFT_RADIO :: 0xA117 /* RadioTime */
WAVE_FORMAT_NICE_ACA :: 0xA118 /* Nice Systems */
WAVE_FORMAT_NICE_ADPCM :: 0xA119 /* Nice Systems */
WAVE_FORMAT_VOCORD_G721 :: 0xA11A /* Vocord Telecom */
WAVE_FORMAT_VOCORD_G726 :: 0xA11B /* Vocord Telecom */
WAVE_FORMAT_VOCORD_G722_1 :: 0xA11C /* Vocord Telecom */
WAVE_FORMAT_VOCORD_G728 :: 0xA11D /* Vocord Telecom */
WAVE_FORMAT_VOCORD_G729 :: 0xA11E /* Vocord Telecom */
WAVE_FORMAT_VOCORD_G729_A :: 0xA11F /* Vocord Telecom */
WAVE_FORMAT_VOCORD_G723_1 :: 0xA120 /* Vocord Telecom */
WAVE_FORMAT_VOCORD_LBC :: 0xA121 /* Vocord Telecom */
WAVE_FORMAT_NICE_G728 :: 0xA122 /* Nice Systems */
WAVE_FORMAT_FRACE_TELECOM_G729 :: 0xA123 /* France Telecom */
WAVE_FORMAT_CODIAN :: 0xA124 /* CODIAN */
WAVE_FORMAT_DOLBY_AC4 :: 0xAC40 /* Dolby AC-4 */
WAVE_FORMAT_FLAC :: 0xF1AC /* flac.sourceforge.net */
WAVE_FORMAT_EXTENSIBLE :: 0xFFFE /* Microsoft */
WAVEFORMATEX :: struct {
wFormatTag: WORD,
nChannels: WORD,
@@ -325,6 +600,20 @@ WAVEFORMATEX :: struct {
}
LPCWAVEFORMATEX :: ^WAVEFORMATEX
// New wave format development should be based on the WAVEFORMATEXTENSIBLE structure.
// WAVEFORMATEXTENSIBLE allows you to avoid having to register a new format tag with Microsoft.
// Simply define a new GUID value for the WAVEFORMATEXTENSIBLE.SubFormat field and use WAVE_FORMAT_EXTENSIBLE in the WAVEFORMATEXTENSIBLE.Format.wFormatTag field.
WAVEFORMATEXTENSIBLE :: struct {
using Format: WAVEFORMATEX,
Samples: struct #raw_union {
wValidBitsPerSample: WORD, /* bits of precision */
wSamplesPerBlock: WORD, /* valid if wBitsPerSample==0 */
wReserved: WORD, /* If neither applies, set to zero. */
},
dwChannelMask: SPEAKER_FLAGS, /* which channels are present in stream */
SubFormat: GUID,
}
WAVEHDR :: struct {
lpData: LPSTR, /* pointer to locked data buffer */
dwBufferLength: DWORD, /* length of data buffer */
@@ -360,26 +649,50 @@ WAVEOUTCAPSW :: struct {
}
LPWAVEOUTCAPSW :: ^WAVEOUTCAPSW
SPEAKER_FLAGS :: distinct bit_set[SPEAKER_FLAG; DWORD]
SPEAKER_FLAG :: enum DWORD {
FRONT_LEFT = 0,
FRONT_RIGHT = 1,
FRONT_CENTER = 2,
LOW_FREQUENCY = 3,
BACK_LEFT = 4,
BACK_RIGHT = 5,
FRONT_LEFT_OF_CENTER = 6,
FRONT_RIGHT_OF_CENTER = 7,
BACK_CENTER = 8,
SIDE_LEFT = 9,
SIDE_RIGHT = 10,
TOP_CENTER = 11,
TOP_FRONT_LEFT = 12,
TOP_FRONT_CENTER = 13,
TOP_FRONT_RIGHT = 14,
TOP_BACK_LEFT = 15,
TOP_BACK_CENTER = 16,
TOP_BACK_RIGHT = 17,
//RESERVED = 0x7FFC0000, // bit mask locations reserved for future use
ALL = 31, // used to specify that any possible permutation of speaker configurations
}
// flag values for PlaySound
SND_SYNC :: 0x0000 /* play synchronously (default) */
SND_ASYNC :: 0x0001 /* play asynchronously */
SND_NODEFAULT :: 0x0002 /* silence (!default) if sound not found */
SND_MEMORY :: 0x0004 /* pszSound points to a memory file */
SND_LOOP :: 0x0008 /* loop the sound until next sndPlaySound */
SND_NOSTOP :: 0x0010 /* don't stop any currently playing sound */
SND_SYNC :: 0x0000 /* play synchronously (default) */
SND_ASYNC :: 0x0001 /* play asynchronously */
SND_NODEFAULT :: 0x0002 /* silence (!default) if sound not found */
SND_MEMORY :: 0x0004 /* pszSound points to a memory file */
SND_LOOP :: 0x0008 /* loop the sound until next sndPlaySound */
SND_NOSTOP :: 0x0010 /* don't stop any currently playing sound */
SND_NOWAIT :: 0x00002000 /* don't wait if the driver is busy */
SND_ALIAS :: 0x00010000 /* name is a registry alias */
SND_ALIAS_ID :: 0x00110000 /* alias is a predefined ID */
SND_FILENAME :: 0x00020000 /* name is file name */
SND_RESOURCE :: 0x00040004 /* name is resource name or atom */
SND_NOWAIT :: 0x00002000 /* don't wait if the driver is busy */
SND_ALIAS :: 0x00010000 /* name is a registry alias */
SND_ALIAS_ID :: 0x00110000 /* alias is a predefined ID */
SND_FILENAME :: 0x00020000 /* name is file name */
SND_RESOURCE :: 0x00040004 /* name is resource name or atom */
SND_PURGE :: 0x0040 /* purge non-static events for task */
SND_APPLICATION :: 0x0080 /* look for application specific association */
SND_PURGE :: 0x0040 /* purge non-static events for task */
SND_APPLICATION :: 0x0080 /* look for application specific association */
SND_SENTRY :: 0x00080000 /* Generate a SoundSentry event with this sound */
SND_RING :: 0x00100000 /* Treat this as a "ring" from a communications app - don't duck me */
SND_SYSTEM :: 0x00200000 /* Treat this as a system sound */
SND_SENTRY :: 0x00080000 /* Generate a SoundSentry event with this sound */
SND_RING :: 0x00100000 /* Treat this as a "ring" from a communications app - don't duck me */
SND_SYSTEM :: 0x00200000 /* Treat this as a system sound */
CALLBACK_TYPEMASK :: 0x00070000 /* callback type mask */
-3
View File
@@ -15,8 +15,6 @@ MAX_PROGRAM_SIZE :: int(max(i16))
MAX_CLASSES :: int(max(u8))
Flag :: enum u8 {
// Global: try to match the pattern anywhere in the string.
Global,
// Multiline: treat `^` and `$` as if they also match newlines.
Multiline,
// Case Insensitive: treat `a-z` as if it was also `A-Z`.
@@ -36,7 +34,6 @@ Flags :: bit_set[Flag; u8]
@(rodata)
Flag_To_Letter := #sparse[Flag]u8 {
.Global = 'g',
.Multiline = 'm',
.Case_Insensitive = 'i',
.Ignore_Whitespace = 'x',
+15 -7
View File
@@ -195,8 +195,12 @@ generate_code :: proc(c: ^Compiler, node: Node) -> (code: Program) {
case ^Node_Anchor:
if .Multiline in c.flags {
append(&code, Opcode.Multiline_Open)
append(&code, Opcode.Multiline_Close)
if specific.start {
append(&code, Opcode.Assert_Start_Multiline)
} else {
append(&code, Opcode.Multiline_Open)
append(&code, Opcode.Multiline_Close)
}
} else {
if specific.start {
append(&code, Opcode.Assert_Start)
@@ -401,7 +405,7 @@ compile :: proc(tree: Node, flags: common.Flags) -> (code: Program, class_data:
pc_open := 0
add_global: if .Global in flags {
optimize_opening: {
// Check if the opening to the pattern is predictable.
// If so, use one of the optimized Wait opcodes.
iter := virtual_machine.Opcode_Iterator{ code[:], 0 }
@@ -412,7 +416,7 @@ compile :: proc(tree: Node, flags: common.Flags) -> (code: Program, class_data:
pc_open += size_of(Opcode)
inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open]))
pc_open += size_of(u8)
break add_global
break optimize_opening
case .Rune:
operand := intrinsics.unaligned_load(cast(^rune)&code[pc+1])
@@ -420,24 +424,28 @@ compile :: proc(tree: Node, flags: common.Flags) -> (code: Program, class_data:
pc_open += size_of(Opcode)
inject_raw(&code, pc_open, operand)
pc_open += size_of(rune)
break add_global
break optimize_opening
case .Rune_Class:
inject_at(&code, pc_open, Opcode.Wait_For_Rune_Class)
pc_open += size_of(Opcode)
inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open]))
pc_open += size_of(u8)
break add_global
break optimize_opening
case .Rune_Class_Negated:
inject_at(&code, pc_open, Opcode.Wait_For_Rune_Class_Negated)
pc_open += size_of(Opcode)
inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open]))
pc_open += size_of(u8)
break add_global
break optimize_opening
case .Save:
continue
case .Assert_Start, .Assert_Start_Multiline:
break optimize_opening
case:
break seek_loop
}
+63 -13
View File
@@ -77,6 +77,8 @@ Match_Iterator :: struct {
vm: virtual_machine.Machine,
idx: int,
temp: runtime.Allocator,
threads: int,
done: bool,
}
/*
@@ -101,7 +103,6 @@ create :: proc(
permanent_allocator := context.allocator,
temporary_allocator := context.temp_allocator,
) -> (result: Regular_Expression, err: Error) {
// For the sake of speed and simplicity, we first run all the intermediate
// processes such as parsing and compilation through the temporary
// allocator.
@@ -166,7 +167,6 @@ to escape the delimiter if found in the middle of the string.
All runes after the closing delimiter will be parsed as flags:
- 'g': Global
- 'm': Multiline
- 'i': Case_Insensitive
- 'x': Ignore_Whitespace
@@ -243,7 +243,6 @@ create_by_user :: proc(
// to `end` here.
for r in pattern[start + end:] {
switch r {
case 'g': flags += { .Global }
case 'm': flags += { .Multiline }
case 'i': flags += { .Case_Insensitive }
case 'x': flags += { .Ignore_Whitespace }
@@ -282,18 +281,13 @@ create_iterator :: proc(
permanent_allocator := context.allocator,
temporary_allocator := context.temp_allocator,
) -> (result: Match_Iterator, err: Error) {
flags := flags
flags += {.Global} // We're iterating over a string, so the next match could start anywhere
if .Multiline in flags {
return {}, .Unsupported_Flag
}
result.regex = create(pattern, flags, permanent_allocator, temporary_allocator) or_return
result.capture = preallocate_capture()
result.temp = temporary_allocator
result.vm = virtual_machine.create(result.regex.program, str)
result.vm.class_data = result.regex.class_data
result.threads = max(1, virtual_machine.opcode_count(result.vm.code) - 1)
return
}
@@ -457,8 +451,27 @@ match_iterator :: proc(it: ^Match_Iterator) -> (result: Capture, index: int, ok:
assert(len(it.capture.pos) >= common.MAX_CAPTURE_GROUPS,
"Pre-allocated RegEx capture `pos` must be at least 10 elements long.")
// Guard against situations in which the iterator should finish.
if it.done {
return
}
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
if it.idx > 0 {
// Reset the state needed to `virtual_machine.run` again.
it.vm.top_thread = 0
it.vm.current_rune = rune(0)
it.vm.current_rune_size = 0
for i in 0..<it.threads {
it.vm.threads[i] = {}
it.vm.next_threads[i] = {}
}
}
// Take note of where the string pointer is before we start.
sp_before := it.vm.string_pointer
saved: ^[2 * common.MAX_CAPTURE_GROUPS]int
{
context.allocator = it.temp
@@ -469,6 +482,28 @@ match_iterator :: proc(it: ^Match_Iterator) -> (result: Capture, index: int, ok:
}
}
if !ok {
// Match failed, bail out.
return
}
if it.vm.string_pointer == sp_before {
// The string pointer did not move, but there was a match.
//
// At this point, the pattern supplied to the iterator will infinitely
// loop if we do not intervene.
it.done = true
}
if it.vm.string_pointer == len(it.vm.memory) {
// The VM hit the end of the string.
//
// We do not check at the start, because a match of pattern `$`
// against string "" is valid and must return a match.
//
// This check prevents a double-match of `$` against a non-empty string.
it.done = true
}
str := string(it.vm.memory)
num_groups: int
@@ -488,9 +523,7 @@ match_iterator :: proc(it: ^Match_Iterator) -> (result: Capture, index: int, ok:
num_groups = n
}
defer if ok {
it.idx += 1
}
defer it.idx += 1
if num_groups > 0 {
result = {it.capture.pos[:num_groups], it.capture.groups[:num_groups]}
@@ -504,8 +537,25 @@ match :: proc {
match_iterator,
}
/*
Reset an iterator, allowing it to be run again as if new.
Inputs:
- it: The iterator to reset.
*/
reset :: proc(it: ^Match_Iterator) {
it.idx = 0
it.done = false
it.idx = 0
it.vm.string_pointer = 0
it.vm.top_thread = 0
it.vm.current_rune = rune(0)
it.vm.current_rune_size = 0
it.vm.last_rune = rune(0)
for i in 0..<it.threads {
it.vm.threads[i] = {}
it.vm.next_threads[i] = {}
}
}
/*
+24 -16
View File
@@ -109,34 +109,42 @@ For more information, see: https://swtch.com/~rsc/regexp/regexp2.html
(0x0A) Assert_Start
Asserts that the thread is at the beginning of a string.
Asserts that the thread is at the beginning of the string.
(0x0B) Assert_End
(0x0B) Assert_Start_Multiline
Asserts that the thread is at the end of a string.
This opcode is compiled in only when the `Multiline` flag is present as a
replacement for the `^` text anchor.
(0x0C) Assert_Word_Boundary
Asserts that the thread is at the beginning of the string or previously
parsed either a "\n" or "\r".
(0x0C) Assert_End
Asserts that the thread is at the end of the string.
(0x0D) Assert_Word_Boundary
Asserts that the thread is on a word boundary, which can be the start or
end of the text. This examines both the current rune and the next rune.
(0x0D) Assert_Non_Word_Boundary
(0x0E) Assert_Non_Word_Boundary
A modified version of Assert_Word_Boundary that returns the opposite value.
(0x0E) Multiline_Open
(0x0F) Multiline_Open
This opcode is compiled in only when the `Multiline` flag is present, and
it replaces both `^` and `$` text anchors.
This opcode is compiled in only when the `Multiline` flag is present as a
replacement for the `$` text anchor.
It asserts that either the current thread is on one of the string
boundaries, or it consumes a `\n` or `\r` character.
It asserts that either the current thread is at the end of the string,
or it consumes a `\n` or `\r` character.
If a `\r` character is consumed, the PC will be advanced to the sibling
`Multiline_Close` opcode to optionally consume a `\n` character on the next
frame.
(0x0F) Multiline_Close
(0x10) Multiline_Close
This opcode is always present after `Multiline_Open`.
@@ -144,10 +152,10 @@ For more information, see: https://swtch.com/~rsc/regexp/regexp2.html
For example, Windows newlines are represented by the characters `\r\n`,
whereas UNIX newlines are `\n` and Macintosh newlines are `\r`.
(0x10) Wait_For_Byte
(0x11) Wait_For_Rune
(0x12) Wait_For_Rune_Class
(0x13) Wait_For_Rune_Class_Negated
(0x11) Wait_For_Byte
(0x12) Wait_For_Rune
(0x13) Wait_For_Rune_Class
(0x14) Wait_For_Rune_Class_Negated
These opcodes are an optimization around restarting threads on failed
matches when the beginning to a pattern is predictable and the Global flag
@@ -156,7 +164,7 @@ For more information, see: https://swtch.com/~rsc/regexp/regexp2.html
They will cause the VM to wait for the next rune to match before splitting,
as would happen in the un-optimized version.
(0x14) Match_All_And_Escape
(0x15) Match_All_And_Escape
This opcode is an optimized version of `.*$` or `.+$` that causes the
active thread to immediately work on escaping the program by following all
@@ -34,6 +34,7 @@ iterate_opcodes :: proc(iter: ^Opcode_Iterator) -> (opcode: Opcode, pc: int, ok:
case .Split: iter.pc += size_of(Opcode) + 2 * size_of(u16)
case .Save: iter.pc += size_of(Opcode) + size_of(u8)
case .Assert_Start: iter.pc += size_of(Opcode)
case .Assert_Start_Multiline: iter.pc += size_of(Opcode)
case .Assert_End: iter.pc += size_of(Opcode)
case .Assert_Word_Boundary: iter.pc += size_of(Opcode)
case .Assert_Non_Word_Boundary: iter.pc += size_of(Opcode)
@@ -64,6 +65,7 @@ opcode_to_name :: proc(opcode: Opcode) -> (str: string) {
case .Split: str = "Split"
case .Save: str = "Save"
case .Assert_Start: str = "Assert_Start"
case .Assert_Start_Multiline: str = "Assert_Start_Multiline"
case .Assert_End: str = "Assert_End"
case .Assert_Word_Boundary: str = "Assert_Word_Boundary"
case .Assert_Non_Word_Boundary: str = "Assert_Non_Word_Boundary"
@@ -37,16 +37,17 @@ Opcode :: enum u8 {
Split = 0x08, // | u16, u16
Save = 0x09, // | u8
Assert_Start = 0x0A, // |
Assert_End = 0x0B, // |
Assert_Word_Boundary = 0x0C, // |
Assert_Non_Word_Boundary = 0x0D, // |
Multiline_Open = 0x0E, // |
Multiline_Close = 0x0F, // |
Wait_For_Byte = 0x10, // | u8
Wait_For_Rune = 0x11, // | i32
Wait_For_Rune_Class = 0x12, // | u8
Wait_For_Rune_Class_Negated = 0x13, // | u8
Match_All_And_Escape = 0x14, // |
Assert_Start_Multiline = 0x0B, // |
Assert_End = 0x0C, // |
Assert_Word_Boundary = 0x0D, // |
Assert_Non_Word_Boundary = 0x0E, // |
Multiline_Open = 0x0F, // |
Multiline_Close = 0x10, // |
Wait_For_Byte = 0x11, // | u8
Wait_For_Rune = 0x12, // | i32
Wait_For_Rune_Class = 0x13, // | u8
Wait_For_Rune_Class_Negated = 0x14, // | u8
Match_All_And_Escape = 0x15, // |
}
Thread :: struct {
@@ -77,6 +78,8 @@ Machine :: struct {
current_rune_size: int,
next_rune: rune,
next_rune_size: int,
last_rune: rune,
}
@@ -169,6 +172,12 @@ add_thread :: proc(vm: ^Machine, saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, pc:
pc += size_of(Opcode)
continue
}
case .Assert_Start_Multiline:
sp := vm.string_pointer+vm.current_rune_size
if sp == 0 || vm.last_rune == '\n' || vm.last_rune == '\r' {
pc += size_of(Opcode)
continue
}
case .Assert_End:
sp := vm.string_pointer+vm.current_rune_size
if sp == len(vm.memory) {
@@ -177,24 +186,12 @@ add_thread :: proc(vm: ^Machine, saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, pc:
}
case .Multiline_Open:
sp := vm.string_pointer+vm.current_rune_size
if sp == 0 || sp == len(vm.memory) {
if vm.next_rune == '\r' || vm.next_rune == '\n' {
// The VM is currently on a newline at the string boundary,
// so consume the newline next frame.
when common.ODIN_DEBUG_REGEX {
io.write_string(common.debug_stream, "*** New thread added [PC:")
common.write_padded_hex(common.debug_stream, pc, 4)
io.write_string(common.debug_stream, "]\n")
}
vm.next_threads[vm.top_thread] = Thread{ pc = pc, saved = saved }
vm.top_thread += 1
} else {
// Skip the `Multiline_Close` opcode.
pc += 2 * size_of(Opcode)
continue
}
if sp == len(vm.memory) {
// Skip the `Multiline_Close` opcode.
pc += 2 * size_of(Opcode)
continue
} else {
// Not on a string boundary.
// Not at the end of the string.
// Try to consume a newline next frame in the other opcode loop.
when common.ODIN_DEBUG_REGEX {
io.write_string(common.debug_stream, "*** New thread added [PC:")
@@ -329,10 +326,10 @@ add_thread :: proc(vm: ^Machine, saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, pc:
run :: proc(vm: ^Machine, $UNICODE_MODE: bool) -> (saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, ok: bool) #no_bounds_check {
when UNICODE_MODE {
vm.next_rune, vm.next_rune_size = utf8.decode_rune_in_string(vm.memory)
vm.next_rune, vm.next_rune_size = utf8.decode_rune_in_string(vm.memory[vm.string_pointer:])
} else {
if len(vm.memory) > 0 {
vm.next_rune = cast(rune)vm.memory[0]
vm.next_rune = cast(rune)vm.memory[vm.string_pointer]
vm.next_rune_size = 1
}
}
@@ -613,6 +610,7 @@ run :: proc(vm: ^Machine, $UNICODE_MODE: bool) -> (saved: ^[2 * common.MAX_CAPTU
break
}
vm.last_rune = vm.current_rune
vm.string_pointer += vm.current_rune_size
}
@@ -652,4 +650,4 @@ destroy :: proc(vm: Machine, allocator := context.allocator) {
delete(vm.busy_map)
free(vm.threads)
free(vm.next_threads)
}
}
+4 -2
View File
@@ -285,6 +285,7 @@ scan_number :: proc(s: ^Scanner, ch: rune, seen_dot: bool) -> (rune, rune) {
case 'o': return "octal literal"
case 'z': return "dozenal literal"
case 'x': return "hexadecimal literal"
case 'h': return "hexadecimal literal"
}
return "decimal literal"
}
@@ -360,7 +361,8 @@ scan_number :: proc(s: ^Scanner, ch: rune, seen_dot: bool) -> (rune, rune) {
base, prefix = 12, 'z'
case 'h':
tok = Float
fallthrough
ch = advance(s)
base, prefix = 16, 'h'
case 'x':
ch = advance(s)
base, prefix = 16, 'x'
@@ -447,7 +449,7 @@ scan_string :: proc(s: ^Scanner, quote: rune) -> (n: int) {
ch := advance(s)
for ch != quote {
if ch == '\n' || ch < 0 {
error(s, "literal no terminated")
error(s, "literal not terminated")
return
}
if ch == '\\' {
+132 -86
View File
@@ -31,6 +31,24 @@ enum TargetOsKind : u16 {
TargetOs_COUNT,
};
gb_global String target_os_names[TargetOs_COUNT] = {
str_lit(""),
str_lit("windows"),
str_lit("darwin"),
str_lit("linux"),
str_lit("essence"),
str_lit("freebsd"),
str_lit("openbsd"),
str_lit("netbsd"),
str_lit("haiku"),
str_lit("wasi"),
str_lit("js"),
str_lit("orca"),
str_lit("freestanding"),
};
enum TargetArchKind : u16 {
TargetArch_Invalid,
@@ -45,6 +63,17 @@ enum TargetArchKind : u16 {
TargetArch_COUNT,
};
gb_global String target_arch_names[TargetArch_COUNT] = {
str_lit(""),
str_lit("amd64"),
str_lit("i386"),
str_lit("arm32"),
str_lit("arm64"),
str_lit("wasm32"),
str_lit("wasm64p32"),
str_lit("riscv64"),
};
enum TargetEndianKind : u8 {
TargetEndian_Little,
TargetEndian_Big,
@@ -52,6 +81,11 @@ enum TargetEndianKind : u8 {
TargetEndian_COUNT,
};
gb_global String target_endian_names[TargetEndian_COUNT] = {
str_lit("little"),
str_lit("big"),
};
enum TargetABIKind : u16 {
TargetABI_Default,
@@ -61,7 +95,14 @@ enum TargetABIKind : u16 {
TargetABI_COUNT,
};
gb_global String target_abi_names[TargetABI_COUNT] = {
str_lit(""),
str_lit("win64"),
str_lit("sysv"),
};
enum Windows_Subsystem : u8 {
Windows_Subsystem_UNKNOWN,
Windows_Subsystem_BOOT_APPLICATION,
Windows_Subsystem_CONSOLE, // Default,
Windows_Subsystem_EFI_APPLICATION,
@@ -75,59 +116,32 @@ enum Windows_Subsystem : u8 {
Windows_Subsystem_COUNT,
};
gb_global String windows_subsystem_names[Windows_Subsystem_COUNT] = {
str_lit(""),
str_lit("BOOT_APPLICATION"),
str_lit("CONSOLE"), // Default
str_lit("EFI_APPLICATION"),
str_lit("EFI_BOOT_SERVICE_DRIVER"),
str_lit("EFI_ROM"),
str_lit("EFI_RUNTIME_DRIVER"),
str_lit("NATIVE"),
str_lit("POSIX"),
str_lit("WINDOWS"),
str_lit("WINDOWSCE"),
};
struct MicroarchFeatureList {
String microarch;
String features;
};
gb_global String target_os_names[TargetOs_COUNT] = {
str_lit(""),
str_lit("windows"),
str_lit("darwin"),
str_lit("linux"),
str_lit("essence"),
str_lit("freebsd"),
str_lit("openbsd"),
str_lit("netbsd"),
str_lit("haiku"),
str_lit("wasi"),
str_lit("js"),
str_lit("orca"),
str_lit("freestanding"),
};
gb_global String target_arch_names[TargetArch_COUNT] = {
str_lit(""),
str_lit("amd64"),
str_lit("i386"),
str_lit("arm32"),
str_lit("arm64"),
str_lit("wasm32"),
str_lit("wasm64p32"),
str_lit("riscv64"),
};
#if defined(GB_SYSTEM_WINDOWS)
#include <llvm-c/Config/llvm-config.h>
#else
#include <llvm/Config/llvm-config.h>
#endif
#include "build_settings_microarch.cpp"
gb_global String target_endian_names[TargetEndian_COUNT] = {
str_lit("little"),
str_lit("big"),
};
gb_global String target_abi_names[TargetABI_COUNT] = {
str_lit(""),
str_lit("win64"),
str_lit("sysv"),
};
gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
TargetEndian_Little,
TargetEndian_Little,
@@ -138,19 +152,6 @@ gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
TargetEndian_Little,
};
gb_global String windows_subsystem_names[Windows_Subsystem_COUNT] = {
str_lit("BOOT_APPLICATION"),
str_lit("CONSOLE"), // Default
str_lit("EFI_APPLICATION"),
str_lit("EFI_BOOT_SERVICE_DRIVER"),
str_lit("EFI_ROM"),
str_lit("EFI_RUNTIME_DRIVER"),
str_lit("NATIVE"),
str_lit("POSIX"),
str_lit("WINDOWS"),
str_lit("WINDOWSCE"),
};
#ifndef ODIN_VERSION_RAW
#define ODIN_VERSION_RAW "dev-unknown-unknown"
#endif
@@ -287,7 +288,7 @@ enum BuildPath : u8 {
BuildPath_VS_LIB, // vs_library_path
BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`.
BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`.
BuildPath_Symbols, // Output Path for .pdb or .dSym file, can be overridden with `-pdb-name:`.
BuildPathCOUNT,
};
@@ -393,17 +394,17 @@ String linker_choices[Linker_COUNT] = {
// This stores the information for the specify architecture of this build
struct BuildContext {
// Constants
String ODIN_OS; // Target operating system
String ODIN_ARCH; // Target architecture
String ODIN_VENDOR; // Compiler vendor
String ODIN_VERSION; // Compiler version
String ODIN_ROOT; // Odin ROOT
String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
String ODIN_WINDOWS_SUBSYSTEM; // Empty string for non-Windows targets
bool ODIN_DEBUG; // Odin in debug mode
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
bool ODIN_DEFAULT_TO_PANIC_ALLOCATOR; // Whether the default allocator is a "panic" allocator or not (i.e. panics on any call to it)
String ODIN_OS; // Target operating system
String ODIN_ARCH; // Target architecture
String ODIN_VENDOR; // Compiler vendor
String ODIN_VERSION; // Compiler version
String ODIN_ROOT; // Odin ROOT
String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
Windows_Subsystem ODIN_WINDOWS_SUBSYSTEM; // .Console, .Windows
bool ODIN_DEBUG; // Odin in debug mode
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
bool ODIN_DEFAULT_TO_PANIC_ALLOCATOR; // Whether the default allocator is a "panic" allocator or not (i.e. panics on any call to it)
bool ODIN_FOREIGN_ERROR_PROCEDURES;
bool ODIN_VALGRIND_SUPPORT;
@@ -441,6 +442,7 @@ struct BuildContext {
String extra_assembler_flags;
String microarch;
BuildModeKind build_mode;
bool keep_executable;
bool generate_docs;
bool custom_optimization_level;
i32 optimization_level;
@@ -1787,8 +1789,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
}
// Default to subsystem:CONSOLE on Windows targets
if (bc->ODIN_WINDOWS_SUBSYSTEM == "" && bc->metrics.os == TargetOs_windows) {
bc->ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_CONSOLE];
if (bc->ODIN_WINDOWS_SUBSYSTEM == Windows_Subsystem_UNKNOWN && bc->metrics.os == TargetOs_windows) {
bc->ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem_CONSOLE;
}
if (subtarget == Subtarget_Android) {
@@ -2021,6 +2023,39 @@ gb_internal bool check_target_feature_is_superset_of(String const &superset, Str
return true;
}
gb_internal String infer_object_extension_from_build_context() {
String output_extension = {};
if (is_arch_wasm()) {
output_extension = STR_LIT("wasm.o");
} else {
switch (build_context.metrics.os) {
case TargetOs_windows:
output_extension = STR_LIT("obj");
break;
default:
case TargetOs_darwin:
case TargetOs_linux:
case TargetOs_essence:
output_extension = STR_LIT("o");
break;
case TargetOs_freestanding:
switch (build_context.metrics.abi) {
default:
case TargetABI_Default:
case TargetABI_SysV:
output_extension = STR_LIT("o");
break;
case TargetABI_Win64:
output_extension = STR_LIT("obj");
break;
}
break;
}
}
return output_extension;
}
// NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate.
// We've previously called `parse_build_flags`, so `out_filepath` should be set.
gb_internal bool init_build_paths(String init_filename) {
@@ -2064,10 +2099,6 @@ gb_internal bool init_build_paths(String init_filename) {
}
}
if (bc->pdb_filepath.len > 0) {
bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath);
}
if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) {
// NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
Find_Result find_result = find_visual_studio_and_windows_sdk();
@@ -2157,13 +2188,8 @@ gb_internal bool init_build_paths(String init_filename) {
if (build_context.metrics.os == TargetOs_windows) {
output_extension = STR_LIT("lib");
}
}else if (build_context.build_mode == BuildMode_Object) {
// By default use a .o object extension.
output_extension = STR_LIT("o");
if (build_context.metrics.os == TargetOs_windows) {
output_extension = STR_LIT("obj");
}
} else if (build_context.build_mode == BuildMode_Object) {
output_extension = infer_object_extension_from_build_context();
} else if (build_context.build_mode == BuildMode_Assembly) {
// By default use a .S asm extension.
output_extension = STR_LIT("S");
@@ -2183,7 +2209,7 @@ gb_internal bool init_build_paths(String init_filename) {
return false;
} else if (bc->build_paths[BuildPath_Output].ext.len == 0) {
gb_printf_err("Output path %.*s must have an appropriate extension.\n", LIT(output_file));
return false;
return false;
}
}
} else {
@@ -2266,6 +2292,26 @@ gb_internal bool init_build_paths(String init_filename) {
bc->build_paths[BuildPath_Output] = output_path;
}
if (build_context.ODIN_DEBUG) {
if (build_context.metrics.os == TargetOs_windows) {
if (bc->pdb_filepath.len > 0) {
bc->build_paths[BuildPath_Symbols] = path_from_string(ha, bc->pdb_filepath);
} else {
Path symbol_path;
symbol_path.basename = copy_string(ha, bc->build_paths[BuildPath_Output].basename);
symbol_path.name = copy_string(ha, bc->build_paths[BuildPath_Output].name);
symbol_path.ext = copy_string(ha, STR_LIT("pdb"));
bc->build_paths[BuildPath_Symbols] = symbol_path;
}
} else if (build_context.metrics.os == TargetOs_darwin) {
Path symbol_path;
symbol_path.basename = copy_string(ha, bc->build_paths[BuildPath_Output].basename);
symbol_path.name = copy_string(ha, bc->build_paths[BuildPath_Output].name);
symbol_path.ext = copy_string(ha, STR_LIT("dSYM"));
bc->build_paths[BuildPath_Symbols] = symbol_path;
}
}
// Do we have an extension? We might not if the output filename was supplied.
if (bc->build_paths[BuildPath_Output].ext.len == 0) {
if (build_context.metrics.os == TargetOs_windows || is_arch_wasm() || build_context.build_mode != BuildMode_Executable) {
@@ -2301,9 +2347,10 @@ gb_internal bool init_build_paths(String init_filename) {
case TargetOs_windows:
case TargetOs_linux:
case TargetOs_darwin:
case TargetOs_freebsd:
break;
default:
gb_printf_err("-sanitize:address is only supported on windows, linux, and darwin\n");
gb_printf_err("-sanitize:address is only supported on Windows, Linux, Darwin, and FreeBSD\n");
return false;
}
}
@@ -2311,12 +2358,10 @@ gb_internal bool init_build_paths(String init_filename) {
if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
switch (build_context.metrics.os) {
case TargetOs_linux:
case TargetOs_freebsd:
break;
default:
gb_printf_err("-sanitize:memory is only supported on linux\n");
return false;
}
if (build_context.metrics.os != TargetOs_linux) {
gb_printf_err("-sanitize:memory is only supported on Linux and FreeBSD\n");
return false;
}
}
@@ -2325,9 +2370,10 @@ gb_internal bool init_build_paths(String init_filename) {
switch (build_context.metrics.os) {
case TargetOs_linux:
case TargetOs_darwin:
case TargetOs_freebsd:
break;
default:
gb_printf_err("-sanitize:thread is only supported on linux and darwin\n");
gb_printf_err("-sanitize:thread is only supported on Linux, Darwin, and FreeBSD\n");
return false;
}
}
+14 -11
View File
@@ -2885,8 +2885,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
// quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type
Operand xyzw[4] = {};
u32 first_index = 0;
// NOTE(bill): Invalid will be the default till fixed
operand->type = t_invalid;
operand->mode = Addressing_Invalid;
@@ -2931,6 +2929,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
if (fields_set[*index]) {
error(field->field, "Previously assigned field: '%.*s'", LIT(name));
return false;
}
fields_set[*index] = style;
@@ -2947,7 +2946,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
if (!ok || index < 0) {
return false;
}
first_index = cast(u32)index;
*refs[index] = o;
}
@@ -2972,12 +2970,17 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
for (u32 i = 0; i < 4; i++ ){
u32 j = (i + first_index) % 4;
if (j == first_index) {
convert_to_typed(c, &xyzw[j], xyzw[(first_index+1)%4].type); if (xyzw[j].mode == Addressing_Invalid) return false;
} else {
convert_to_typed(c, &xyzw[j], xyzw[first_index].type); if (xyzw[j].mode == Addressing_Invalid) return false;
// The first typed value found, if any exist, will dictate the type for all untyped values.
for (u32 i = 0; i < 4; i++) {
if (is_type_typed(xyzw[i].type)) {
for (u32 j = 0; j < 4; j++) {
// `convert_to_typed` should check if it is typed already.
convert_to_typed(c, &xyzw[j], xyzw[i].type);
if (xyzw[j].mode == Addressing_Invalid) {
return false;
}
}
break;
}
}
if (xyzw[0].mode == Addressing_Constant &&
@@ -3001,7 +3004,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
gbString ty = type_to_string(xyzw[1].type);
gbString tz = type_to_string(xyzw[2].type);
gbString tw = type_to_string(xyzw[3].type);
error(call, "Mismatched types to 'quaternion', 'x=%s' vs 'y=%s' vs 'z=%s' vs 'w=%s'", tx, ty, tz, tw);
error(call, "Mismatched types to 'quaternion', 'w=%s' vs 'x=%s' vs 'y=%s' vs 'z=%s'", tw, tx, ty, tz);
gb_string_free(tw);
gb_string_free(tz);
gb_string_free(ty);
@@ -3037,7 +3040,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
operand->mode = Addressing_Constant;
}
BasicKind kind = core_type(xyzw[first_index].type)->Basic.kind;
BasicKind kind = core_type(xyzw[0].type)->Basic.kind;
switch (kind) {
case Basic_f16: operand->type = t_quaternion64; break;
case Basic_f32: operand->type = t_quaternion128; break;
+23 -1
View File
@@ -7962,7 +7962,27 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
default:
{
gbString str = type_to_string(t);
error(call, "Too many arguments in conversion to '%s'", str);
if (t->kind == Type_Basic) {
ERROR_BLOCK();
switch (t->Basic.kind) {
case Basic_complex32:
case Basic_complex64:
case Basic_complex128:
error(call, "Too many arguments in conversion to '%s'", str);
error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str);
break;
case Basic_quaternion64:
case Basic_quaternion128:
case Basic_quaternion256:
error(call, "Too many arguments in conversion to '%s'", str);
error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str);
break;
default:
error(call, "Too many arguments in conversion to '%s'", str);
}
} else {
error(call, "Too many arguments in conversion to '%s'", str);
}
gb_string_free(str);
} break;
case 1: {
@@ -8078,7 +8098,9 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) {
if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) {
ERROR_BLOCK();
error(call, "'context' has not been defined within this scope, but is required for this procedure call");
error_line("\tSuggestion: 'context = runtime.default_context()'");
}
}
+1
View File
@@ -2855,6 +2855,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
case Ast_BlockStmt:
case Ast_IfStmt:
case Ast_SwitchStmt:
case Ast_TypeSwitchStmt:
if (token.kind != Token_break) {
error(bs->label, "Label '%.*s' can only be used with 'break'", LIT(e->token.string));
}
+6 -2
View File
@@ -3805,7 +3805,11 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type)
#if 0
error(e, "Invalid type definition of '%.*s'", LIT(type->Named.name));
#endif
type->Named.base = t_invalid;
if (type->Named.type_name->TypeName.is_type_alias) {
// NOTE(laytan): keep it null, type declaration is a mini "cycle" to be filled later.
} else {
type->Named.base = t_invalid;
}
}
if (is_type_polymorphic(type)) {
@@ -3823,7 +3827,7 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type)
}
#endif
if (is_type_typed(type)) {
if (type->kind == Type_Named && type->Named.base == nullptr || is_type_typed(type)) {
add_type_and_value(ctx, e, Addressing_Type, type, empty_exact_value);
} else {
gbString name = type_to_string(type);
+25 -6
View File
@@ -1078,11 +1078,30 @@ gb_internal void init_universal(void) {
add_global_bool_constant("true", true);
add_global_bool_constant("false", false);
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME);
add_global_string_constant("ODIN_WINDOWS_SUBSYSTEM", bc->ODIN_WINDOWS_SUBSYSTEM);
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME);
{
GlobalEnumValue values[Windows_Subsystem_COUNT] = {
{"Unknown", Windows_Subsystem_UNKNOWN},
{"Boot_Application", Windows_Subsystem_BOOT_APPLICATION},
{"Console", Windows_Subsystem_CONSOLE},
{"EFI_Application", Windows_Subsystem_EFI_APPLICATION},
{"EFI_Boot_Service_Driver", Windows_Subsystem_EFI_BOOT_SERVICE_DRIVER},
{"EFI_Rom", Windows_Subsystem_EFI_ROM},
{"EFI_Runtime_Driver", Windows_Subsystem_EFI_RUNTIME_DRIVER},
{"Native", Windows_Subsystem_NATIVE},
{"Posix", Windows_Subsystem_POSIX},
{"Windows", Windows_Subsystem_WINDOWS},
{"Windows_CE", Windows_Subsystem_WINDOWSCE},
};
auto fields = add_global_enum_type(str_lit("Odin_Windows_Subsystem_Type"), values, gb_count_of(values));
add_global_enum_constant(fields, "ODIN_WINDOWS_SUBSYSTEM", bc->ODIN_WINDOWS_SUBSYSTEM);
add_global_string_constant("ODIN_WINDOWS_SUBSYSTEM_STRING", windows_subsystem_names[bc->ODIN_WINDOWS_SUBSYSTEM]);
}
{
GlobalEnumValue values[TargetOs_COUNT] = {
@@ -1102,7 +1121,7 @@ gb_internal void init_universal(void) {
};
auto fields = add_global_enum_type(str_lit("Odin_OS_Type"), values, gb_count_of(values));
add_global_enum_constant(fields, "ODIN_OS", bc->metrics.os);
add_global_enum_constant(fields, "ODIN_OS", bc->metrics.os);
add_global_string_constant("ODIN_OS_STRING", target_os_names[bc->metrics.os]);
}
+18 -6
View File
@@ -281,9 +281,9 @@ try_cross_linking:;
link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
}
if (build_context.pdb_filepath != "") {
String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]);
link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(pdb_path));
if (build_context.build_paths[BuildPath_Symbols].name != "") {
String symbol_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Symbols]);
link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(symbol_path));
}
if (build_context.build_mode != BuildMode_StaticLibrary) {
@@ -321,7 +321,7 @@ try_cross_linking:;
"",
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
link_settings,
LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -341,7 +341,7 @@ try_cross_linking:;
"",
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
link_settings,
LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -404,7 +404,7 @@ try_cross_linking:;
"",
LIT(vs_exe_path), LIT(linker_name), object_files, LIT(res_path), LIT(output_filename),
link_settings,
LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -802,6 +802,18 @@ try_cross_linking:;
link_settings = gb_string_appendc(link_settings, "-e _main ");
}
} else if (build_context.metrics.os == TargetOs_freebsd) {
if (build_context.sanitizer_flags & (SanitizerFlag_Address | SanitizerFlag_Memory)) {
// It's imperative that `pthread` is linked before `libc`,
// otherwise ASan/MSan will be unable to call `pthread_key_create`
// because FreeBSD's `libthr` implementation of `pthread`
// needs to replace the relevant stubs first.
//
// (Presumably TSan implements its own `pthread` interface,
// which is why it isn't required.)
//
// See: https://reviews.llvm.org/D39254
platform_lib_str = gb_string_appendc(platform_lib_str, "-lpthread ");
}
// FreeBSD pkg installs third-party shared libraries in /usr/local/lib.
platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-L/usr/local/lib ");
} else if (build_context.metrics.os == TargetOs_openbsd) {
+56 -66
View File
@@ -2504,7 +2504,6 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
gbString path = gb_string_make_length(heap_allocator(), basename.text, basename.len);
path = gb_string_appendc(path, "/");
path = gb_string_append_length(path, name.text, name.len);
if (USE_SEPARATE_MODULES) {
GB_ASSERT(m->module_name != nullptr);
@@ -2516,6 +2515,8 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
}
path = gb_string_append_length(path, s.text, s.len);
} else {
path = gb_string_append_length(path, name.text, name.len);
}
if (use_temporary_directory) {
@@ -2526,38 +2527,15 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
String ext = {};
if (build_context.build_mode == BuildMode_Assembly) {
ext = STR_LIT(".S");
ext = STR_LIT("S");
} else if (build_context.build_mode == BuildMode_Object) {
// Allow a user override for the object extension.
ext = build_context.build_paths[BuildPath_Output].ext;
} else {
if (is_arch_wasm()) {
ext = STR_LIT(".wasm.o");
} else {
switch (build_context.metrics.os) {
case TargetOs_windows:
ext = STR_LIT(".obj");
break;
default:
case TargetOs_darwin:
case TargetOs_linux:
case TargetOs_essence:
ext = STR_LIT(".o");
break;
case TargetOs_freestanding:
switch (build_context.metrics.abi) {
default:
case TargetABI_Default:
case TargetABI_SysV:
ext = STR_LIT(".o");
break;
case TargetABI_Win64:
ext = STR_LIT(".obj");
break;
}
break;
}
}
ext = infer_object_extension_from_build_context();
}
path = gb_string_append_length(path, ".", 1);
path = gb_string_append_length(path, ext.text, ext.len);
return make_string(cast(u8 *)path, gb_string_length(path));
@@ -3376,40 +3354,40 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
lb_add_raddbg_string(m, "type_view: {type: \"string\", expr: \"array(data, len)\"}");
// column major matrices
lb_add_raddbg_string(m, "type_view: {type: \"matrix[1, ?]?\", expr: \"table($.data, $[0])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[2, ?]?\", expr: \"table($.data, $[0], $[1])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[3, ?]?\", expr: \"table($.data, $[0], $[1], $[2])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[4, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[5, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[6, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[7, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[8, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[9, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[10, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[11, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[12, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[13, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[14, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[15, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[16, ?]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[1, ?]?\", expr: \"columns($.data, $[0])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[2, ?]?\", expr: \"columns($.data, $[0], $[1])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[3, ?]?\", expr: \"columns($.data, $[0], $[1], $[2])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[4, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[5, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[6, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[7, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[8, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[9, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[10, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[11, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[12, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[13, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[14, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[15, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"matrix[16, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}");
// row major matrices
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 1]?\", expr: \"table($.data, $[0])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 2]?\", expr: \"table($.data, $[0], $[1])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 3]?\", expr: \"table($.data, $[0], $[1], $[2])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 4]?\", expr: \"table($.data, $[0], $[1], $[2], $[3])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 5]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 6]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 7]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 8]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 9]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 10]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 11]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 12]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 13]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 14]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 15]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 16]?\", expr: \"table($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 1]?\", expr: \"columns($.data, $[0])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 2]?\", expr: \"columns($.data, $[0], $[1])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 3]?\", expr: \"columns($.data, $[0], $[1], $[2])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 4]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 5]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 6]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 7]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 8]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 9]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 10]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 11]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 12]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 13]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 14]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 15]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}");
lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 16]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}");
TEMPORARY_ALLOCATOR_GUARD();
@@ -3513,36 +3491,48 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
if (build_context.sanitizer_flags & SanitizerFlag_Address) {
if (build_context.metrics.os == TargetOs_windows) {
switch (build_context.metrics.os) {
case TargetOs_windows: {
auto paths = array_make<String>(heap_allocator(), 0, 1);
String path = concatenate_strings(permanent_allocator(), build_context.ODIN_ROOT, str_lit("\\bin\\llvm\\windows\\clang_rt.asan-x86_64.lib"));
array_add(&paths, path);
Entity *lib = alloc_entity_library_name(nullptr, make_token_ident("asan_lib"), nullptr, slice_from_array(paths), str_lit("asan_lib"));
array_add(&gen->foreign_libraries, lib);
} else if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
} break;
case TargetOs_darwin:
case TargetOs_linux:
case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=address");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=address"));
}
break;
}
}
if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
switch (build_context.metrics.os) {
case TargetOs_linux:
case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=memory");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=memory"));
}
break;
}
}
if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) {
switch (build_context.metrics.os) {
case TargetOs_darwin:
case TargetOs_linux:
case TargetOs_freebsd:
if (!build_context.extra_linker_flags.text) {
build_context.extra_linker_flags = str_lit("-fsanitize=thread");
} else {
build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=thread"));
}
break;
}
}
+39 -5
View File
@@ -312,6 +312,7 @@ enum BuildFlagKind {
BuildFlag_Collection,
BuildFlag_Define,
BuildFlag_BuildMode,
BuildFlag_KeepExecutable,
BuildFlag_Target,
BuildFlag_Subtarget,
BuildFlag_Debug,
@@ -531,6 +532,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String, Command__does_check);
add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String, Command__does_check, true);
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String, Command__does_build); // Commands_build is not used to allow for a better error message
add_flag(&build_flags, BuildFlag_KeepExecutable, str_lit("keep-executable"), BuildFlagParam_None, Command__does_build | Command_test);
add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String, Command__does_check);
add_flag(&build_flags, BuildFlag_Subtarget, str_lit("subtarget"), BuildFlagParam_String, Command__does_check);
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check);
@@ -1193,6 +1195,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
break;
}
case BuildFlag_KeepExecutable:
build_context.keep_executable = true;
break;
case BuildFlag_Debug:
build_context.ODIN_DEBUG = true;
@@ -1622,9 +1627,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
GB_ASSERT(value.kind == ExactValue_String);
String subsystem = value.value_string;
bool subsystem_found = false;
for (int i = 0; i < Windows_Subsystem_COUNT; i++) {
for (int i = 1; i < Windows_Subsystem_COUNT; i++) {
if (str_eq_ignore_case(subsystem, windows_subsystem_names[i])) {
build_context.ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[i];
build_context.ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem(i);
subsystem_found = true;
break;
}
@@ -1633,7 +1638,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
// WINDOW is a hidden alias for WINDOWS. Check it.
String subsystem_windows_alias = str_lit("WINDOW");
if (!subsystem_found && str_eq_ignore_case(subsystem, subsystem_windows_alias)) {
build_context.ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_WINDOWS];
build_context.ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem_WINDOWS;
subsystem_found = true;
break;
}
@@ -1641,8 +1646,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
if (!subsystem_found) {
gb_printf_err("Invalid -subsystem string, got %.*s. Expected one of:\n", LIT(subsystem));
gb_printf_err("\t");
for (int i = 0; i < Windows_Subsystem_COUNT; i++) {
if (i > 0) {
for (int i = 1; i < Windows_Subsystem_COUNT; i++) {
if (i > 1) {
gb_printf_err(", ");
}
gb_printf_err("%.*s", LIT(windows_subsystem_names[i]));
@@ -2381,6 +2386,12 @@ gb_internal int print_show_help(String const arg0, String command, String option
}
}
if (test_only) {
if (print_flag("-build-only")) {
print_usage_line(2, "Only builds the test executable; does not automatically run it afterwards.");
}
}
if (check) {
if (print_flag("-collection:<name>=<filepath>")) {
print_usage_line(2, "Defines a library collection used for imports.");
@@ -2543,6 +2554,14 @@ gb_internal int print_show_help(String const arg0, String command, String option
}
}
if (test_only || run_or_build) {
if (print_flag("-keep-executable")) {
print_usage_line(2, "Keep the executable generated by `odin test` or `odin run` after running it. We clean it up by default.");
print_usage_line(2, "If you build your program or test using `odin build`, the compiler does not automatically execute");
print_usage_line(2, "the resulting program, and this option is not applicable.");
}
}
if (run_or_build) {
if (print_flag("-linker:<string>")) {
print_usage_line(2, "Specify the linker to use.");
@@ -3866,6 +3885,21 @@ end_of_code_gen:;
defer (gb_free(heap_allocator(), exe_name.text));
system_must_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string));
if (!build_context.keep_executable) {
char const *filename = cast(char const *)exe_name.text;
gb_file_remove(filename);
if (build_context.ODIN_DEBUG) {
if (build_context.metrics.os == TargetOs_windows || build_context.metrics.os == TargetOs_darwin) {
String symbol_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Symbols]);
defer (gb_free(heap_allocator(), symbol_path.text));
filename = cast(char const *)symbol_path.text;
gb_file_remove(filename);
}
}
}
}
return 0;
}
+9 -1
View File
@@ -3274,6 +3274,8 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
case Token_OpenBracket: {
bool prev_allow_range = f->allow_range;
f->allow_range = false;
defer (f->allow_range = prev_allow_range);
Token open = {}, close = {}, interval = {};
Ast *indices[2] = {};
@@ -3282,6 +3284,13 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
f->expr_level++;
open = expect_token(f, Token_OpenBracket);
if (f->curr_token.kind == Token_CloseBracket) {
error(f->curr_token, "Expected an operand, got ]");
close = expect_token(f, Token_CloseBracket);
operand = ast_index_expr(f, operand, nullptr, open, close);
break;
}
switch (f->curr_token.kind) {
case Token_Ellipsis:
case Token_RangeFull:
@@ -3331,7 +3340,6 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
operand = ast_index_expr(f, operand, indices[0], open, close);
}
f->allow_range = prev_allow_range;
} break;
case Token_Pointer: // Deference
+1
View File
@@ -968,6 +968,7 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
advance_to_next_rune(t);
for (isize comment_scope = 1; comment_scope > 0; /**/) {
if (t->curr_rune == GB_RUNE_EOF) {
tokenizer_err(t, "Multi-line comment not terminated");
break;
} else if (t->curr_rune == '/') {
advance_to_next_rune(t);
+1
View File
@@ -4,3 +4,4 @@ package benchmarks
@(require) import "crypto"
@(require) import "hash"
@(require) import "text/regex"
@(require) import "strings"
+8 -7
View File
@@ -54,14 +54,15 @@ run_trial_size :: proc(p: proc "contextless" ([]u8, byte) -> int, size: int, idx
accumulator: int
for _ in 0..<runs {
start := time.now()
accumulator += p(data, 'z')
done := time.since(start)
timing += done
}
watch: time.Stopwatch
timing /= time.Duration(runs)
time.stopwatch_start(&watch)
for _ in 0..<runs {
accumulator += p(data, 'z')
}
time.stopwatch_stop(&watch)
timing = time.stopwatch_duration(watch)
log.debug(accumulator)
return
@@ -0,0 +1,227 @@
package benchmark_runtime
import "base:runtime"
import "core:fmt"
import "core:log"
import "core:testing"
import "core:strings"
import "core:text/table"
import "core:time"
RUNS_PER_SIZE :: 2500
sizes := [?]int {
7, 8, 9,
15, 16, 17,
31, 32, 33,
63, 64, 65,
95, 96, 97,
128,
256,
512,
1024,
4096,
1024 * 1024,
}
// These are the normal, unoptimized algorithms.
plain_memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
switch {
case n == 0: return true
case x == y: return true
}
a, b := ([^]byte)(x), ([^]byte)(y)
length := uint(n)
for i := uint(0); i < length; i += 1 {
if a[i] != b[i] {
return false
}
}
return true
}
plain_memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
switch {
case a == b: return 0
case a == nil: return -1
case b == nil: return +1
}
x := uintptr(a)
y := uintptr(b)
n := uintptr(n)
SU :: size_of(uintptr)
fast := n/SU + 1
offset := (fast-1)*SU
curr_block := uintptr(0)
if n < SU {
fast = 0
}
for /**/; curr_block < fast; curr_block += 1 {
va := (^uintptr)(x + curr_block * size_of(uintptr))^
vb := (^uintptr)(y + curr_block * size_of(uintptr))^
if va ~ vb != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
a := (^byte)(x+pos)^
b := (^byte)(y+pos)^
if a ~ b != 0 {
return -1 if (int(a) - int(b)) < 0 else +1
}
}
}
}
for /**/; offset < n; offset += 1 {
a := (^byte)(x+offset)^
b := (^byte)(y+offset)^
if a ~ b != 0 {
return -1 if (int(a) - int(b)) < 0 else +1
}
}
return 0
}
plain_memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
x := uintptr(a)
n := uintptr(n)
SU :: size_of(uintptr)
fast := n/SU + 1
offset := (fast-1)*SU
curr_block := uintptr(0)
if n < SU {
fast = 0
}
for /**/; curr_block < fast; curr_block += 1 {
va := (^uintptr)(x + curr_block * size_of(uintptr))^
if va ~ 0 != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
a := (^byte)(x+pos)^
if a ~ 0 != 0 {
return -1 if int(a) < 0 else +1
}
}
}
}
for /**/; offset < n; offset += 1 {
a := (^byte)(x+offset)^
if a ~ 0 != 0 {
return -1 if int(a) < 0 else +1
}
}
return 0
}
run_trial_size_cmp :: proc(p: proc "contextless" (rawptr, rawptr, int) -> $R, size: int, idx: int, runs: int, loc := #caller_location) -> (timing: time.Duration) {
left := make([]u8, size)
right := make([]u8, size)
defer {
delete(left)
delete(right)
}
right[idx] = 0x01
accumulator: int
watch: time.Stopwatch
time.stopwatch_start(&watch)
for _ in 0..<runs {
result := p(&left[0], &right[0], size)
when R == bool {
assert(result == false, loc = loc)
accumulator += 1
} else when R == int {
assert(result == -1, loc = loc)
accumulator += result
}
}
time.stopwatch_stop(&watch)
timing = time.stopwatch_duration(watch)
log.debug(accumulator)
return
}
run_trial_size_zero :: proc(p: proc "contextless" (rawptr, int) -> int, size: int, idx: int, runs: int, loc := #caller_location) -> (timing: time.Duration) {
data := make([]u8, size)
defer delete(data)
data[idx] = 0x01
accumulator: int
watch: time.Stopwatch
time.stopwatch_start(&watch)
for _ in 0..<runs {
result := p(&data[0], size)
assert(result == 1, loc = loc)
accumulator += result
}
time.stopwatch_stop(&watch)
timing = time.stopwatch_duration(watch)
log.debug(accumulator)
return
}
run_trial_size :: proc {
run_trial_size_cmp,
run_trial_size_zero,
}
bench_table :: proc(algo_name: string, plain, simd: $P) {
string_buffer := strings.builder_make()
defer strings.builder_destroy(&string_buffer)
tbl: table.Table
table.init(&tbl)
defer table.destroy(&tbl)
table.aligned_header_of_values(&tbl, .Right, "Algorithm", "Size", "Iterations", "Scalar", "SIMD", "SIMD Relative (%)", "SIMD Relative (x)")
for size in sizes {
// Place the non-zero byte somewhere in the middle.
needle_index := size / 2
plain_timing := run_trial_size(plain, size, needle_index, RUNS_PER_SIZE)
simd_timing := run_trial_size(simd, size, needle_index, RUNS_PER_SIZE)
_plain := fmt.tprintf("%8M", plain_timing)
_simd := fmt.tprintf("%8M", simd_timing)
_relp := fmt.tprintf("%.3f %%", f64(simd_timing) / f64(plain_timing) * 100.0)
_relx := fmt.tprintf("%.3f x", 1 / (f64(simd_timing) / f64(plain_timing)))
table.aligned_row_of_values(
&tbl,
.Right,
algo_name,
size, RUNS_PER_SIZE, _plain, _simd, _relp, _relx)
}
builder_writer := strings.to_writer(&string_buffer)
fmt.sbprintln(&string_buffer)
table.write_plain_table(builder_writer, &tbl)
my_table_string := strings.to_string(string_buffer)
log.info(my_table_string)
}
@test
benchmark_memory_procs :: proc(t: ^testing.T) {
bench_table("memory_equal", plain_memory_equal, runtime.memory_equal)
bench_table("memory_compare", plain_memory_compare, runtime.memory_compare)
bench_table("memory_compare_zero", plain_memory_compare_zero, runtime.memory_compare_zero)
}
@@ -0,0 +1,131 @@
package benchmark_strings
import "base:intrinsics"
import "core:fmt"
import "core:log"
import "core:testing"
import "core:strings"
import "core:text/table"
import "core:time"
import "core:unicode/utf8"
RUNS_PER_SIZE :: 2500
sizes := [?]int {
7, 8, 9,
15, 16, 17,
31, 32, 33,
63, 64, 65,
95, 96, 97,
128,
256,
512,
1024,
4096,
}
// These are the normal, unoptimized algorithms.
plain_prefix_length :: proc "contextless" (a, b: string) -> (n: int) {
_len := min(len(a), len(b))
// Scan for matches including partial codepoints.
#no_bounds_check for n < _len && a[n] == b[n] {
n += 1
}
// Now scan to ignore partial codepoints.
if n > 0 {
s := a[:n]
n = 0
for {
r0, w := utf8.decode_rune(s[n:])
if r0 != utf8.RUNE_ERROR {
n += w
} else {
break
}
}
}
return
}
run_trial_size_prefix :: proc(p: proc "contextless" (string, string) -> $R, suffix: string, size: int, idx: int, runs: int, loc := #caller_location) -> (timing: time.Duration) {
left := make([]u8, size)
right := make([]u8, size)
defer {
delete(left)
delete(right)
}
if len(suffix) > 0 {
copy(left [idx:], suffix)
copy(right[idx:], suffix)
} else {
right[idx] = 'A'
}
accumulator: int
watch: time.Stopwatch
time.stopwatch_start(&watch)
for _ in 0..<runs {
result := p(string(left[:size]), string(right[:size]))
accumulator += result
}
time.stopwatch_stop(&watch)
timing = time.stopwatch_duration(watch)
log.debug(accumulator)
return
}
run_trial_size :: proc {
run_trial_size_prefix,
}
bench_table_size :: proc(algo_name: string, plain, simd: $P, suffix := "") {
string_buffer := strings.builder_make()
defer strings.builder_destroy(&string_buffer)
tbl: table.Table
table.init(&tbl)
defer table.destroy(&tbl)
table.aligned_header_of_values(&tbl, .Right, "Algorithm", "Size", "Iterations", "Scalar", "SIMD", "SIMD Relative (%)", "SIMD Relative (x)")
for size in sizes {
// Place the non-zero byte somewhere in the middle.
needle_index := size / 2
plain_timing := run_trial_size(plain, suffix, size, needle_index, RUNS_PER_SIZE)
simd_timing := run_trial_size(simd, suffix, size, needle_index, RUNS_PER_SIZE)
_plain := fmt.tprintf("%8M", plain_timing)
_simd := fmt.tprintf("%8M", simd_timing)
_relp := fmt.tprintf("%.3f %%", f64(simd_timing) / f64(plain_timing) * 100.0)
_relx := fmt.tprintf("%.3f x", 1 / (f64(simd_timing) / f64(plain_timing)))
table.aligned_row_of_values(
&tbl,
.Right,
algo_name,
size, RUNS_PER_SIZE, _plain, _simd, _relp, _relx)
}
builder_writer := strings.to_writer(&string_buffer)
fmt.sbprintln(&string_buffer)
table.write_plain_table(builder_writer, &tbl)
my_table_string := strings.to_string(string_buffer)
log.info(my_table_string)
}
@test
benchmark_memory_procs :: proc(t: ^testing.T) {
bench_table_size("prefix_length ascii", plain_prefix_length, strings.prefix_length)
bench_table_size("prefix_length unicode", plain_prefix_length, strings.prefix_length, "🦉")
}
@@ -103,9 +103,11 @@ expensive_for_backtrackers :: proc(t: ^testing.T) {
@test
global_capture_end_word :: proc(t: ^testing.T) {
// NOTE: The previous behavior of `.Global`, which was to automatically
// insert `.*?` at the start of the pattern, is now default.
EXPR :: `Hellope World!`
rex, err := regex.create(EXPR, { .Global })
rex, err := regex.create(EXPR, { /*.Global*/ })
if !testing.expect_value(t, err, nil) {
return
}
@@ -145,7 +147,7 @@ global_capture_end_word_unicode :: proc(t: ^testing.T) {
EXPR :: `こにちは`
needle := string(EXPR)
rex, err := regex.create(EXPR, { .Global, .Unicode })
rex, err := regex.create(EXPR, { /*.Global,*/ .Unicode })
if !testing.expect_value(t, err, nil) {
return
}
@@ -185,7 +187,7 @@ global_capture_end_word_unicode :: proc(t: ^testing.T) {
alternations :: proc(t: ^testing.T) {
EXPR :: `a(?:bb|cc|dd|ee|ff)`
rex, err := regex.create(EXPR, { .No_Capture, .Global })
rex, err := regex.create(EXPR, { .No_Capture, /*.Global*/ })
if !testing.expect_value(t, err, nil) {
return
}
@@ -219,7 +221,7 @@ classes :: proc(t: ^testing.T) {
EXPR :: `[\w\d]+`
NEEDLE :: "0123456789abcdef"
rex, err := regex.create(EXPR, { .Global })
rex, err := regex.create(EXPR, { /*.Global*/ })
if !testing.expect_value(t, err, nil) {
return
}
+76
View File
@@ -4,6 +4,7 @@ package test_core_runtime
import "base:intrinsics"
import "core:mem"
import "base:runtime"
import "core:slice"
import "core:testing"
// Tests that having space for the allocation, but not for the allocation and alignment
@@ -177,3 +178,78 @@ test_map_get :: proc(t: ^testing.T) {
check(t, m)
}
}
@(test)
test_memory_equal :: proc(t: ^testing.T) {
data: [256]u8
cmp: [256]u8
slice.fill(data[:], 0xAA)
slice.fill(cmp[:], 0xAA)
for offset in 0..<len(data) {
subdata := data[offset:]
subcmp := cmp[offset:]
for idx in 0..<len(subdata) {
if !testing.expect_value(t, runtime.memory_equal(&subdata[0], &subcmp[0], len(subdata)), true) {
return
}
subcmp[idx] = 0x55
if !testing.expect_value(t, runtime.memory_equal(&subdata[0], &subcmp[0], len(subdata)), false) {
return
}
subcmp[idx] = 0xAA
}
}
}
@(test)
test_memory_compare :: proc(t: ^testing.T) {
data: [256]u8
cmp: [256]u8
for offset in 0..<len(data) {
subdata := data[offset:]
subcmp := cmp[offset:]
for idx in 0..<len(subdata) {
if !testing.expect_value(t, runtime.memory_compare(&subdata[0], &subcmp[0], len(subdata)), 0) {
return
}
subdata[idx] = 0x7F
subcmp[idx] = 0xFF
if !testing.expect_value(t, runtime.memory_compare(&subdata[0], &subcmp[0], len(subdata)), -1) {
return
}
subdata[idx] = 0xFF
subcmp[idx] = 0x7F
if !testing.expect_value(t, runtime.memory_compare(&subdata[0], &subcmp[0], len(subdata)), 1) {
return
}
subdata[idx] = 0
subcmp[idx] = 0
}
}
}
@(test)
test_memory_compare_zero :: proc(t: ^testing.T) {
data: [256]u8
for offset in 0..<len(data) {
subdata := data[offset:]
for idx in 0..<len(subdata) {
if !testing.expect_value(t, runtime.memory_compare_zero(&subdata[0], len(subdata)), 0) {
return
}
subdata[idx] = 0xFF
if !testing.expect_value(t, runtime.memory_compare_zero(&subdata[0], len(subdata)), 1) {
return
}
subdata[idx] = 0
}
}
}
+50 -1
View File
@@ -1,9 +1,10 @@
package test_core_strings
import "base:runtime"
import "core:mem"
import "core:strings"
import "core:testing"
import "base:runtime"
import "core:unicode/utf8"
@test
test_index_any_small_string_not_found :: proc(t: ^testing.T) {
@@ -218,3 +219,51 @@ test_builder_to_cstring :: proc(t: ^testing.T) {
testing.expect(t, err == .Out_Of_Memory)
}
}
@test
test_prefix_length :: proc(t: ^testing.T) {
prefix_length :: proc "contextless" (a, b: string) -> (n: int) {
_len := min(len(a), len(b))
// Scan for matches including partial codepoints.
#no_bounds_check for n < _len && a[n] == b[n] {
n += 1
}
// Now scan to ignore partial codepoints.
if n > 0 {
s := a[:n]
n = 0
for {
r0, w := utf8.decode_rune(s[n:])
if r0 != utf8.RUNE_ERROR {
n += w
} else {
break
}
}
}
return
}
cases := [][2]string{
{"Hellope, there!", "Hellope, world!"},
{"Hellope, there!", "Foozle"},
{"Hellope, there!", "Hell"},
{"Hellope! 🦉", "Hellope! 🦉"},
}
for v in cases {
p_scalar := prefix_length(v[0], v[1])
p_simd := strings.prefix_length(v[0], v[1])
testing.expect_value(t, p_simd, p_scalar)
s := v[0]
for len(s) > 0 {
p_scalar = prefix_length(v[0], s)
p_simd = strings.prefix_length(v[0], s)
testing.expect_value(t, p_simd, p_scalar)
s = s[:len(s) - 1]
}
}
}
+228 -22
View File
@@ -51,13 +51,13 @@ check_expression_with_flags :: proc(t: ^testing.T, pattern: string, flags: regex
}
check_expression :: proc(t: ^testing.T, pattern, haystack: string, needles: ..string, extra_flags := regex.Flags{}, loc := #caller_location) {
check_expression_with_flags(t, pattern, { .Global } + extra_flags,
check_expression_with_flags(t, pattern, extra_flags,
haystack, ..needles, loc = loc)
check_expression_with_flags(t, pattern, { .Global, .No_Optimization } + extra_flags,
check_expression_with_flags(t, pattern, { .No_Optimization } + extra_flags,
haystack, ..needles, loc = loc)
check_expression_with_flags(t, pattern, { .Global, .Unicode } + extra_flags,
check_expression_with_flags(t, pattern, { .Unicode } + extra_flags,
haystack, ..needles, loc = loc)
check_expression_with_flags(t, pattern, { .Global, .Unicode, .No_Optimization } + extra_flags,
check_expression_with_flags(t, pattern, { .Unicode, .No_Optimization } + extra_flags,
haystack, ..needles, loc = loc)
}
@@ -72,17 +72,18 @@ expect_error :: proc(t: ^testing.T, pattern: string, expected_error: typeid, fla
testing.expect_value(t, variant_ti, expected_ti, loc = loc)
}
check_capture :: proc(t: ^testing.T, got, expected: regex.Capture, loc := #caller_location) {
testing.expect_value(t, len(got.pos), len(got.groups), loc = loc)
testing.expect_value(t, len(got.pos), len(expected.pos), loc = loc)
testing.expect_value(t, len(got.groups), len(expected.groups), loc = loc)
check_capture :: proc(t: ^testing.T, got, expected: regex.Capture, loc := #caller_location) -> (ok: bool) {
testing.expect_value(t, len(got.pos), len(got.groups), loc = loc) or_return
testing.expect_value(t, len(got.pos), len(expected.pos), loc = loc) or_return
testing.expect_value(t, len(got.groups), len(expected.groups), loc = loc) or_return
if len(got.pos) == len(expected.pos) {
for i in 0..<len(got.pos) {
testing.expect_value(t, got.pos[i], expected.pos[i], loc = loc)
testing.expect_value(t, got.groups[i], expected.groups[i], loc = loc)
testing.expect_value(t, got.pos[i], expected.pos[i], loc = loc) or_return
testing.expect_value(t, got.groups[i], expected.groups[i], loc = loc) or_return
}
}
return true
}
@test
@@ -212,6 +213,12 @@ test_alternation :: proc(t: ^testing.T) {
check_expression(t, EXPR, "cc", "cc")
}
@test
test_alternation_order :: proc(t: ^testing.T) {
check_expression(t, "a|ab", "ab", "a")
check_expression(t, "ab|a", "ab", "ab")
}
@test
test_optional :: proc(t: ^testing.T) {
EXPR :: "a?a?a?aaa"
@@ -516,7 +523,7 @@ test_pos_index_explicitly :: proc(t: ^testing.T) {
STR :: "This is an island."
EXPR :: `\bis\b`
rex, err := regex.create(EXPR, { .Global })
rex, err := regex.create(EXPR)
if !testing.expect_value(t, err, nil) {
return
}
@@ -642,9 +649,9 @@ test_unicode_explicitly :: proc(t: ^testing.T) {
}
{
EXPR :: "こにちは!"
check_expression_with_flags(t, EXPR, { .Global, .Unicode },
check_expression_with_flags(t, EXPR, { .Unicode },
"Hello こにちは!", "こにちは!")
check_expression_with_flags(t, EXPR, { .Global, .Unicode, .No_Optimization },
check_expression_with_flags(t, EXPR, { .Unicode, .No_Optimization },
"Hello こにちは!", "こにちは!")
}
}
@@ -692,15 +699,15 @@ test_case_insensitive :: proc(t: ^testing.T) {
test_multiline :: proc(t: ^testing.T) {
{
EXPR :: `^hellope$world$`
check_expression(t, EXPR, "\nhellope\nworld\n", "\nhellope\nworld\n", extra_flags = { .Multiline })
check_expression(t, EXPR, "hellope\nworld\n", "hellope\nworld\n", extra_flags = { .Multiline })
check_expression(t, EXPR, "hellope\nworld", "hellope\nworld", extra_flags = { .Multiline })
check_expression(t, EXPR, "hellope\rworld", "hellope\rworld", extra_flags = { .Multiline })
check_expression(t, EXPR, "hellope\r\nworld", "hellope\r\nworld", extra_flags = { .Multiline })
}
{
EXPR :: `^?.$`
check_expression(t, EXPR, "\nh", "\nh", extra_flags = { .Multiline })
EXPR :: `^.$`
check_expression(t, EXPR, "h", "h", extra_flags = { .Multiline })
check_expression(t, EXPR, "h\n", "h\n", extra_flags = { .Multiline })
}
{
EXPR :: `^$`
@@ -901,12 +908,12 @@ test_everything_at_once :: proc(t: ^testing.T) {
@test
test_creation_from_user_string :: proc(t: ^testing.T) {
{
USER_EXPR :: `/^hellope$/gmixun-`
USER_EXPR :: `/^hellope$/mixun-`
STR :: "hellope"
rex, err := regex.create_by_user(USER_EXPR)
defer regex.destroy(rex)
testing.expect_value(t, err, nil)
testing.expect_value(t, rex.flags, regex.Flags{ .Global, .Multiline, .Case_Insensitive, .Ignore_Whitespace, .Unicode, .No_Capture, .No_Optimization })
testing.expect_value(t, rex.flags, regex.Flags{ .Multiline, .Case_Insensitive, .Ignore_Whitespace, .Unicode, .No_Capture, .No_Optimization })
_, ok := regex.match(rex, STR)
testing.expectf(t, ok, "expected user-provided RegEx %v to match %q", rex, STR)
@@ -1102,24 +1109,172 @@ Iterator_Test :: struct {
iterator_vectors := []Iterator_Test{
{
`xxab32ab52xx`, `(ab\d{1})`, {}, // {.Global} implicitly added by the iterator
`xxab32ab52xx`, `(ab\d{1})`, {},
{
{pos = {{2, 5}, {2, 5}}, groups = {"ab3", "ab3"}},
{pos = {{6, 9}, {6, 9}}, groups = {"ab5", "ab5"}},
},
},
{
`xxfoobarxfoobarxx`, `f(o)ob(ar)`, {.Global},
`xxfoobarxfoobarxx`, `f(o)ob(ar)`, {},
{
{pos = {{2, 8}, {3, 4}, {6, 8}}, groups = {"foobar", "o", "ar"}},
{pos = {{9, 15}, {10, 11}, {13, 15}}, groups = {"foobar", "o", "ar"}},
},
},
{
`aaa`, `a`, {},
{
{pos = {{0, 1}}, groups = {"a"}},
{pos = {{1, 2}}, groups = {"a"}},
{pos = {{2, 3}}, groups = {"a"}},
},
},
{
`aaa`, `\w`, {},
{
{pos = {{0, 1}}, groups = {"a"}},
{pos = {{1, 2}}, groups = {"a"}},
{pos = {{2, 3}}, groups = {"a"}},
},
},
{
`aかか`, `.`, {.Unicode},
{
{pos = {{0, 1}}, groups = {"a"}},
{pos = {{1, 4}}, groups = {"か"}},
{pos = {{4, 7}}, groups = {"か"}},
},
},
{
`ゆめ.`, `.`, {.Unicode},
{
{pos = {{0, 3}}, groups = {"ゆ"}},
{pos = {{3, 6}}, groups = {"め"}},
{pos = {{6, 7}}, groups = {"."}},
},
},
// This pattern is not anchored, so this is valid per the new behavior.
{
`ababa`, `(?:a|ab)`, {},
{
{pos = {{0, 1}}, groups = {"a"}},
{pos = {{2, 3}}, groups = {"a"}},
{pos = {{4, 5}}, groups = {"a"}},
},
},
// Ensure alternation follows expected ordering of left-higher priority.
{
`ababa`, `(?:ab|a)`, {},
{
{pos = {{0, 2}}, groups = {"ab"}},
{pos = {{2, 4}}, groups = {"ab"}},
{pos = {{4, 5}}, groups = {"a"}},
},
},
// This one is anchored, so only one match.
//
// This test ensures the behavior of `Assert_Start` is checking against the
// start of the string and we haven't just slid the memory string itself.
{
`ababa`, `^(?:a|b)`, {},
{
{pos = {{0, 1}}, groups = {"a"}},
},
},
{
`ababa`, `a$`, {},
{
{pos = {{4, 5}}, groups = {"a"}},
},
},
// A blank pattern on a blank string is valid and must not loop infinitely.
{
``, ``, {},
{
{pos = {{0, 0}}, groups = {""}},
},
},
// These too are valid.
//
// The iterator must bail out when it encounters any situation which would
// loop infinitely, but only after giving at least one valid match if one
// exists, as this would accord with attempting to singularly match the
// pattern against the string and provide a positive result.
{
`a`, ``, {},
{
{pos = {{0, 0}}, groups = {""}},
},
},
{
``, `$`, {},
{
{pos = {{0, 0}}, groups = {""}},
},
},
{
`aaa`, `$`, {},
{
{pos = {{3, 3}}, groups = {""}},
},
},
// Multiline iteration is supported, but it must follow the `^...$` scheme.
//
// Any usage outside of this strict syntax will produce predictable but
// unusual outputs, as `^` is defined to assert the start of a string or
// that a newline sequence was previously consumed, and `$` consumes a
// newline sequence or asserts the end of the string.
{
"foo1\nfoo2\r\nfoo3\rfoo4", `^foo.$`, {.Multiline},
{
{pos = {{0, 5}}, groups = {"foo1\n"}},
{pos = {{5, 11}}, groups = {"foo2\r\n"}},
{pos = {{11, 16}}, groups = {"foo3\r"}},
{pos = {{16, 20}}, groups = {"foo4"}},
},
},
{
"a\nb\n\r", `^$`, {.Multiline},
{},
},
{
"a\nb\n", `^$`, {.Multiline},
{},
},
{
"a\nb", `^$`, {.Multiline},
{},
},
// Multiline anchors must work within groups, as people are going to end up
// using them in there and we do not forbid it.
{
"a\nb\na\nb", `(?:^a$|^b$)`, {.Multiline},
{
{pos = {{0, 2}}, groups = {"a\n"}},
{pos = {{2, 4}}, groups = {"b\n"}},
{pos = {{4, 6}}, groups = {"a\n"}},
{pos = {{6, 7}}, groups = {"b"}},
},
},
// The following patterns are valid uses of optional anchors and must match.
{
"a\nb\na\nb", `^a(?:b|$)`, {.Multiline},
{
{pos = {{0, 2}}, groups = {"a\n"}},
},
},
{
"a\nb\na\nb", `^ab?$?`, {.Multiline},
{
{pos = {{0, 2}}, groups = {"a\n"}},
},
},
}
@test
test_match_iterator :: proc(t: ^testing.T) {
for test in iterator_vectors {
vector: for test in iterator_vectors {
it, err := regex.create_iterator(test.haystack, test.pattern, test.flags)
defer regex.destroy(it)
@@ -1128,10 +1283,61 @@ test_match_iterator :: proc(t: ^testing.T) {
for capture, idx in regex.match(&it) {
if idx >= len(test.expected) {
log.errorf("got more than expected number of captures for matching string %q against pattern %q\n\tidx %i = %v", test.haystack, test.pattern, idx, capture)
continue vector
}
if !check_capture(t, capture, test.expected[idx]) {
log.errorf("capture check failed on string %q against pattern %q", test.haystack, test.pattern)
}
}
testing.expectf(t, it.idx == len(test.expected), "expected idx to be %i, got %i on string %q against pattern %q", len(test.expected), it.idx, test.haystack, test.pattern)
}
}
@test
test_iterator_reset :: proc(t: ^testing.T) {
test := Iterator_Test{
`aaa`, `a`, {},
{
{pos = {{0, 1}}, groups = {"a"}},
{pos = {{1, 2}}, groups = {"a"}},
{pos = {{2, 3}}, groups = {"a"}},
},
}
out: {
it, err := regex.create_iterator(`aaa`, `a`)
defer regex.destroy(it)
testing.expect_value(t, err, nil)
(err == nil) or_break out
for capture, idx in regex.match(&it) {
if idx >= len(test.expected) {
log.errorf("got more than expected number of captures for matching string %q against pattern %q\n\tidx %i = %v", test.haystack, test.pattern, idx, capture)
break
}
check_capture(t, capture, test.expected[idx])
}
testing.expect_value(t, it.idx, len(test.expected))
// Do it again.
iterations := 0
regex.reset(&it)
// Mind that this loop can do nothing if it wasn't reset but leave us
// with the expected `idx` state.
//
// That's why we count iterations this time around.
for capture, idx in regex.match(&it) {
iterations += 1
if idx >= len(test.expected) {
log.errorf("got more than expected number of captures for matching string %q against pattern %q\n\tidx %i = %v", test.haystack, test.pattern, idx, capture)
break
}
check_capture(t, capture, test.expected[idx])
}
testing.expect_value(t, it.idx, len(test.expected))
testing.expect_value(t, iterations, len(test.expected))
}
}
}
+1
View File
@@ -19,6 +19,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style
..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_5043.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_5097-2.odin %COMMON% || exit /b
@echo off
+1
View File
@@ -26,6 +26,7 @@ else
fi
$ODIN build ../test_issue_5043.odin $COMMON
$ODIN build ../test_issue_5097.odin $COMMON
$ODIN build ../test_issue_5097-2.odin $COMMON
set +x
+24
View File
@@ -0,0 +1,24 @@
// Tests another variation of, this should compile #5097 https://github.com/odin-lang/Odin/issues/5097
package test_issues
Face :: ^FaceRec
GlyphSlot :: ^GlyphSlotRec
Size :: ^SizeRec
SizeRec :: struct {
face: Face,
}
GlyphSlotRec :: struct {
face: Face,
}
FaceRec :: struct {
glyph: GlyphSlot,
size: Size,
}
main :: proc() {
face: Face
_ = face
}
+4 -4
View File
@@ -163,9 +163,9 @@ foreign glfw {
SetJoystickUserPointer :: proc(jid: c.int, pointer: rawptr) ---
GetJoystickUserPointer :: proc(jid: c.int) -> rawptr ---
JoystickIsGamepad :: proc(jid: c.int) -> b32 ---
UpdateGamepadMappings :: proc(str: cstring) -> c.int ---
UpdateGamepadMappings :: proc(str: cstring) -> b32 ---
GetGamepadName :: proc(jid: c.int) -> cstring ---
GetGamepadState :: proc(jid: c.int, state: ^GamepadState) -> c.int ---
GetGamepadState :: proc(jid: c.int, state: ^GamepadState) -> b32 ---
SetClipboardString :: proc(window: WindowHandle, str: cstring) ---
@@ -177,12 +177,12 @@ foreign glfw {
MakeContextCurrent :: proc(window: WindowHandle) ---
GetCurrentContext :: proc() -> WindowHandle ---
GetProcAddress :: proc(name: cstring) -> rawptr ---
ExtensionSupported :: proc(extension: cstring) -> c.int ---
ExtensionSupported :: proc(extension: cstring) -> b32 ---
VulkanSupported :: proc() -> b32 ---
GetRequiredInstanceExtensions :: proc(count: ^u32) -> [^]cstring ---
GetInstanceProcAddress :: proc(instance: vk.Instance, procname: cstring) -> rawptr ---
GetPhysicalDevicePresentationSupport :: proc(instance: vk.Instance, device: vk.PhysicalDevice, queuefamily: u32) -> c.int ---
GetPhysicalDevicePresentationSupport :: proc(instance: vk.Instance, device: vk.PhysicalDevice, queuefamily: u32) -> b32 ---
CreateWindowSurface :: proc(instance: vk.Instance, window: WindowHandle, allocator: ^vk.AllocationCallbacks, surface: ^vk.SurfaceKHR) -> vk.Result ---
SetWindowIconifyCallback :: proc(window: WindowHandle, cbfun: WindowIconifyProc) -> WindowIconifyProc ---
+1 -1
View File
@@ -538,7 +538,7 @@ foreign lib {
ReadScreenPixels :: proc(width, height: c.int) -> [^]byte --- // Read screen pixel data (color buffer)
// Framebuffer management (fbo)
LoadFramebuffer :: proc(width, height: c.int) -> c.uint --- // Load an empty framebuffer
LoadFramebuffer :: proc() -> c.uint --- // Load an empty framebuffer
FramebufferAttach :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
FramebufferComplete :: proc(id: c.uint) -> bool --- // Verify framebuffer is complete
UnloadFramebuffer :: proc(id: c.uint) --- // Delete framebuffer from GPU
+1 -1
View File
@@ -87,7 +87,7 @@ foreign lib {
RWseek :: proc(ctx: ^RWops, offset: i64, whence: c.int) -> i64 ---
RWtell :: proc(ctx: ^RWops) -> i64 ---
RWread :: proc(ctx: ^RWops, ptr: rawptr, size: c.size_t, maxnum: c.size_t) -> c.size_t ---
RWwrite :: proc(ctx: ^RWops, size: c.size_t, num: c.size_t) -> c.size_t ---
RWwrite :: proc(ctx: ^RWops, ptr: rawptr, size: c.size_t, num: c.size_t) -> c.size_t ---
RWclose :: proc(ctx: ^RWops) -> c.int ---
LoadFile_RW :: proc(src: ^RWops, datasize: ^c.size_t, freesrc: bool) -> rawptr ---
+2 -2
View File
@@ -12,8 +12,8 @@ You can find a number of examples on [[Odin's official examples repository; http
**Getting the wgpu-native libraries**
For native support (not the browser), some libraries are required. Fortunately this is
extremely easy, just download them from the [[releases on GitHub; https://github.com/gfx-rs/wgpu-native/releases/tag/v24.0.0.2]].
the bindings are for v24.0.0.2 at the moment.
extremely easy, just download them from the [[releases on GitHub; https://github.com/gfx-rs/wgpu-native/releases/tag/v25.0.2.1]].
the bindings are for v25.0.2.1 at the moment.
These are expected in the `lib` folder under the same name as they are released (just unzipped).
By default it will look for a static release version (`wgpu-OS-ARCH-release.a|lib`),
+1 -1
View File
@@ -2033,7 +2033,7 @@ class WebGPUInterface {
addressModeW: this.enumeration("AddressMode", off(4)),
magFilter: this.enumeration("FilterMode", off(4)),
minFilter: this.enumeration("FilterMode", off(4)),
mipMapFilter: this.enumeration("MipmapFilterMode", off(4)),
mipmapFilter: this.enumeration("MipmapFilterMode", off(4)),
lodMinClamp: this.mem.loadF32(off(4)),
lodMaxClamp: this.mem.loadF32(off(4)),
compare: this.enumeration("CompareFunction", off(4)),
+5 -4
View File
@@ -13,7 +13,7 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-windows-" + ARCH + "-msvc-" + TYPE + "/lib/wgpu_native" + EXT
when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v24.0.0.2, make sure to read the README at '" + #directory + "README.md'")
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v25.0.2.1, make sure to read the README at '" + #directory + "README.md'")
}
@(export)
@@ -39,12 +39,13 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-macos-" + ARCH + "-" + TYPE + "/lib/libwgpu_native" + EXT
when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v24.0.0.2, make sure to read the README at '" + #directory + "README.md'")
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v25.0.2.1, make sure to read the README at '" + #directory + "README.md'")
}
@(export)
foreign import libwgpu {
LIB,
"system:Foundation.framework",
"system:CoreFoundation.framework",
"system:QuartzCore.framework",
"system:Metal.framework",
@@ -55,7 +56,7 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-linux-" + ARCH + "-" + TYPE + "/lib/libwgpu_native" + EXT
when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v24.0.0.2, make sure to read the README at '" + #directory + "README.md'")
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v25.0.2.1, make sure to read the README at '" + #directory + "README.md'")
}
@(export)
@@ -438,7 +439,7 @@ SType :: enum i32 {
DeviceExtras = 0x00030001,
NativeLimits,
PipelineLayoutExtras,
ShaderModuleGLSLDescriptor,
ShaderSourceGLSL,
SupportedLimitsExtras,
InstanceExtras,
BindGroupEntryExtras,
+1 -1
View File
@@ -12,7 +12,7 @@ foreign libwgpu {
RawQueueSubmitForIndex :: proc(queue: Queue, commandCount: uint, commands: [^]CommandBuffer) -> SubmissionIndex ---
// Returns true if the queue is empty, or false if there are more queue submissions still in flight.
DevicePoll :: proc(device: Device, wait: b32, /* NULLABLE */ wrappedSubmissionIndex: /* const */ ^SubmissionIndex = nil) -> b32 ---
DevicePoll :: proc(device: Device, wait: b32, /* NULLABLE */ submissionIndex: /* const */ ^SubmissionIndex = nil) -> b32 ---
DeviceCreateShaderModuleSpirV :: proc(device: Device, descriptor: ^ShaderModuleDescriptorSpirV) -> ShaderModule ---
SetLogCallback :: proc(callback: LogCallback, userdata: rawptr) ---
+21 -3
View File
@@ -2,8 +2,8 @@ package wgpu
import "base:runtime"
BINDINGS_VERSION :: [4]u8{24, 0, 0, 2}
BINDINGS_VERSION_STRING :: "24.0.0.2"
BINDINGS_VERSION :: [4]u8{25, 0, 2, 1}
BINDINGS_VERSION_STRING :: "25.0.2.1"
LogLevel :: enum i32 {
Off,
@@ -56,14 +56,32 @@ PipelineStatisticName :: enum i32 {
ComputeShaderInvocations,
}
DxcMaxShaderModel :: enum i32 {
V6_0,
V6_1,
V6_2,
V6_3,
V6_4,
V6_5,
V6_6,
V6_7,
}
GLFenceBehaviour :: enum i32 {
Normal,
AutoFinish,
}
InstanceExtras :: struct {
using chain: ChainedStruct,
backends: InstanceBackendFlags,
flags: InstanceFlags,
dx12ShaderCompiler: Dx12Compiler,
gles3MinorVersion: Gles3MinorVersion,
glFenceBehaviour: GLFenceBehaviour,
dxilPath: StringView,
dxcPath: StringView,
dcxMaxShaderModel: DxcMaxShaderModel,
}
DeviceExtras :: struct {
@@ -96,7 +114,7 @@ ShaderDefine :: struct {
value: StringView,
}
ShaderModuleGLSLDescriptor :: struct {
ShaderSourceGLSL :: struct {
using chain: ChainedStruct,
stage: ShaderStage,
code: StringView,
File diff suppressed because it is too large Load Diff
+149
View File
@@ -0,0 +1,149 @@
#+build windows
package windows_xaudio2
import win "core:sys/windows"
foreign import hrtf "system:hrtfapo.lib"
HRTF_MAX_GAIN_LIMIT :: 12.0
HRTF_MIN_GAIN_LIMIT :: -96.0
HRTF_MIN_UNITY_GAIN_DISTANCE :: 0.05
HRTF_DEFAULT_UNITY_GAIN_DISTANCE :: 1.0
HRTF_DEFAULT_CUTOFF_DISTANCE :: 3.402823466e+38
//! Represents a position in 3D space, using a right-handed coordinate system.
HrtfPosition :: struct {
x: f32,
y: f32,
z: f32,
}
//! Indicates the orientation of an HRTF directivity object. This is a row-major 3x3 rotation matrix.
HrtfOrientation :: struct {
element: [9]f32,
}
//! Indicates one of several stock directivity patterns.
HrtfDirectivityType :: enum i32 {
//! The sound emission is in all directions.
OmniDirectional = 0,
//! The sound emission is a cardiod shape.
Cardioid,
//! The sound emission is a cone.
Cone,
}
//! Indicates one of several stock environment types.
HrtfEnvironment :: enum i32 {
//! A small room.
Small = 0,
//! A medium-sized room.
Medium,
//! A large enclosed space.
Large,
//! An outdoor space.
Outdoors,
}
//! Base directivity pattern descriptor. Describes the type of directivity applied to a sound.
//! The scaling parameter is used to interpolate between directivity behavior and omnidirectional, it determines how much attenuation is applied to the source outside of the directivity pattern and controls how directional the source is.
HrtfDirectivity :: struct {
//! Indicates the type of directivity.
type: HrtfDirectivityType,
//! A normalized value between zero and one. Specifies the amount of linear interpolation between omnidirectional sound and the full directivity pattern, where 0 is fully omnidirectional and 1 is fully directional.
scaling: f32,
}
//! Describes a cardioid directivity pattern.
HrtfDirectivityCardioid :: struct {
//! Descriptor for the cardioid pattern. The type parameter must be set to HrtfDirectivityType.Cardioid.
directivity: HrtfDirectivity,
//! Order controls the shape of the cardioid. The higher order the shape, the narrower it is. Must be greater than 0 and less than or equal to 32.
order: f32,
}
//! Describes a cone directivity.
//! Attenuation is 0 inside the inner cone.
//! Attenuation is linearly interpolated between the inner cone, which is defined by innerAngle, and the outer cone, which is defined by outerAngle.
HrtfDirectivityCone :: struct {
//! Descriptor for the cone pattern. The type parameter must be set to HrtfDirectivityType.Cone.
directivity: HrtfDirectivity,
//! Angle, in radians, that defines the inner cone. Must be between 0 and TAU.
innerAngle: f32,
//! Angle, in radians, that defines the outer cone. Must be between 0 and TAU.
outerAngle: f32,
}
//! Indicates a distance-based decay type applied to a sound.
HrtfDistanceDecayType :: enum i32 {
//! Simulates natural decay with distance, as constrained by minimum and maximum gain distance limits. Drops to silence at rolloff distance.
NaturalDecay = 0,
//! Used to set up a custom gain curve, within the maximum and minimum gain limit.
CustomDecay,
}
//! Describes a distance-based decay behavior.
HrtfDistanceDecay :: struct {
//! The type of decay behavior, natural or custom.
type: HrtfDistanceDecayType,
//! The maximum gain limit applied at any distance. Applies to both natural and custom decay. This value is specified in dB, with a range from -96 to 12 inclusive. The default value is 12 dB.
maxGain: f32,
//! The minimum gain limit applied at any distance. Applies to both natural and custom decay. This value is specified in dB, with a range from -96 to 12 inclusive. The default value is -96 dB.
minGain: f32,
//! The distance at which the gain is 0dB. Applies to natural decay only. This value is specified in meters, with a range from 0.05 to infinity (max(f32)). The default value is 1 meter.
unityGainDistance: f32,
//! The distance at which output is silent. Applies to natural decay only. This value is specified in meters, with a range from zero (non-inclusive) to infinity (max(f32)). The default value is infinity.
cutoffDistance: f32,
}
//! Specifies parameters used to initialize HRTF.
//! Instances of the XAPO interface are created by using the CreateHrtfApo() API:
//! ```CreateHrtfApo :: proc(pInit: HrtfApoInit, ppXapo: ^^IXAPO) -> HRESULT```
HrtfApoInit :: struct {
//! The decay type. If you pass in nil, the default value will be used. The default is natural decay.
distanceDecay: ^HrtfDistanceDecay,
//! The directivity type. If you pass in nil, the default value will be used. The default directivity is omni-directional.
directivity: ^HrtfDirectivity,
}
//! Creates an instance of the XAPO object.
//! Format requirements:
//! * Input: mono, 48 kHz, 32-bit float PCM.
//! * Output: stereo, 48 kHz, 32-bit float PCM.
//! Audio is processed in blocks of 1024 samples.
//! Returns:
//! S_OK for success, any other value indicates failure.
//! Returns E_NOTIMPL on unsupported platforms.
@(default_calling_convention="system")
foreign hrtf {
CreateHrtfApo :: proc(
//! Pointer to an HrtfApoInit struct. Specifies parameters for XAPO interface initialization.
#by_ptr init: HrtfApoInit,
//! Returns the new instance of the XAPO interface.
xApo: ^^IXAPO,
) -> HRESULT ---
}
//! The interface used to set parameters that control how HRTF is applied to a sound.
IXAPOHrtfParameters_UUID_STRING :: "15B3CD66-E9DE-4464-B6E6-2BC3CF63D455"
IXAPOHrtfParameters_UUID := &win.IID{0x15B3CD66, 0xE9DE, 0x4464, {0xB6, 0xE6, 0x2B, 0xC3, 0xCF, 0x63, 0xD4, 0x55}}
IXAPOHrtfParameters :: struct #raw_union {
#subtype iunknown: IUnknown,
using ixapohrtfparameters_vtable: ^IXAPOHrtfParameters_VTable,
}
IXAPOHrtfParameters_VTable :: struct {
using iunknown_vtable: IUnknown_VTable,
// HRTF params
//! The position of the sound relative to the listener.
SetSourcePosition: proc "system" (this: ^IXAPOHrtfParameters, position: ^HrtfPosition) -> HRESULT,
//! The rotation matrix for the source orientation, with respect to the listener's frame of reference (the listener's coordinate system).
SetSourceOrientation: proc "system" (this: ^IXAPOHrtfParameters, orientation: ^HrtfOrientation) -> HRESULT,
//! The custom direct path gain value for the current source position. Valid only for sounds played with the HrtfDistanceDecayType. Custom decay type.
SetSourceGain: proc "system" (this: ^IXAPOHrtfParameters, gain: f32) -> HRESULT,
// Distance cue params
//! Selects the acoustic environment to simulate.
SetEnvironment: proc "system" (this: ^IXAPOHrtfParameters, environment: HrtfEnvironment) -> HRESULT,
}
+48 -71
View File
@@ -1,7 +1,7 @@
#+build windows
/* NOTES:
1. Definition of terms:
1. Definition of terms:
LFE: Low Frequency Effect -- always omnidirectional.
LPF: Low Pass Filter, divided into two classifications:
Direct -- Applied to the direct signal path,
@@ -9,15 +9,15 @@
Reverb -- Applied to the reverb signal path,
used for occlusion effects only.
2. Volume level is expressed as a linear amplitude scaler:
1.0f represents no attenuation applied to the original signal,
0.5f denotes an attenuation of 6dB, and 0.0f results in silence.
Amplification (volume > 1.0f) is also allowed, and is not clamped.
2. Volume level is expressed as a linear amplitude scaler:
1.0 represents no attenuation applied to the original signal,
0.5 denotes an attenuation of 6dB, and 0.0 results in silence.
Amplification (volume > 1.0) is also allowed, and is not clamped.
LPF values range from 1.0f representing all frequencies pass through,
to 0.0f which results in silence as all frequencies are filtered out.
LPF values range from 1.0 representing all frequencies pass through,
to 0.0 which results in silence as all frequencies are filtered out.
3. X3DAudio uses a left-handed Cartesian coordinate system with values
3. X3DAudio uses a left-handed Cartesian coordinate system with values
on the x-axis increasing from left to right, on the y-axis from
bottom to top, and on the z-axis from near to far.
Azimuths are measured clockwise from a given reference direction.
@@ -29,7 +29,7 @@
Metric constants are supplied only as a convenience.
Distance is calculated using the Euclidean norm formula.
4. Only real values are permissible with functions using 32-bit
4. Only real values are permissible with functions using 32-bit
float parameters -- NAN and infinite values are not accepted.
All computation occurs in 32-bit precision mode. */
@@ -37,34 +37,13 @@
package windows_xaudio2
import "core:math"
import win "core:sys/windows"
foreign import xa2 "system:xaudio2.lib"
SPEAKER_FLAGS :: win.SPEAKER_FLAGS
//--------------<D-E-F-I-N-I-T-I-O-N-S>-------------------------------------//
// speaker geometry configuration flags, specifies assignment of channels to speaker positions, defined as per WAVEFORMATEXTENSIBLE.dwChannelMask
SPEAKER_FLAGS :: distinct bit_set[SPEAKER_FLAG; u32]
SPEAKER_FLAG :: enum u32 {
FRONT_LEFT = 0,
FRONT_RIGHT = 1,
FRONT_CENTER = 2,
LOW_FREQUENCY = 3,
BACK_LEFT = 4,
BACK_RIGHT = 5,
FRONT_LEFT_OF_CENTER = 6,
FRONT_RIGHT_OF_CENTER = 7,
BACK_CENTER = 8,
SIDE_LEFT = 9,
SIDE_RIGHT = 10,
TOP_CENTER = 11,
TOP_FRONT_LEFT = 12,
TOP_FRONT_CENTER = 13,
TOP_FRONT_RIGHT = 14,
TOP_BACK_LEFT = 15,
TOP_BACK_CENTER = 16,
TOP_BACK_RIGHT = 17,
//RESERVED = 0x7FFC0000, // bit mask locations reserved for future use
ALL = 31, // used to specify that any possible permutation of speaker configurations
}
// standard speaker geometry configurations, used with Initialize
SPEAKER_MONO :: SPEAKER_FLAGS{.FRONT_CENTER}
@@ -100,7 +79,7 @@ CALCULATE_FLAG :: enum u32 {
}
//--------------<D-A-T-A---T-Y-P-E-S>---------------------------------------//
VECTOR :: [3]f32 // float 3D vector
VECTOR :: distinct [3]f32 // float 3D vector
// instance handle of precalculated constants
HANDLE :: distinct [HANDLE_BYTESIZE]byte
@@ -108,75 +87,74 @@ HANDLE :: distinct [HANDLE_BYTESIZE]byte
// Distance curve point:
// Defines a DSP setting at a given normalized distance.
DISTANCE_CURVE_POINT :: struct #packed {
Distance: f32, // normalized distance, must be within [0.0f, 1.0f]
Distance: f32, // normalized distance, must be within [0.0, 1.0]
DSPSetting: f32, // DSP setting
}
// Distance curve:
// A piecewise curve made up of linear segments used to define DSP behaviour with respect to normalized distance.
//
// Note that curve point distances are normalized within [0.0f, 1.0f].
// Note that curve point distances are normalized within [0.0, 1.0].
// EMITTER.CurveDistanceScaler must be used to scale the normalized distances to user-defined world units.
// For distances beyond CurveDistanceScaler * 1.0f, pPoints[PointCount-1].DSPSetting is used as the DSP setting.
// For distances beyond CurveDistanceScaler * 1.0, pPoints[PointCount-1].DSPSetting is used as the DSP setting.
//
// All distance curve spans must be such that:
// pPoints[k-1].DSPSetting + ((pPoints[k].DSPSetting-pPoints[k-1].DSPSetting) / (pPoints[k].Distance-pPoints[k-1].Distance)) * (pPoints[k].Distance-pPoints[k-1].Distance) != NAN or infinite values
// For all points in the distance curve where 1 <= k < PointCount.
DISTANCE_CURVE :: struct #packed {
pPoints: [^]DISTANCE_CURVE_POINT `fmt:"v,PointCount"`, // distance curve point array, must have at least PointCount elements with no duplicates and be sorted in ascending order with respect to Distance
PointCount: u32, // number of distance curve points, must be >= 2 as all distance curves must have at least two endpoints, defining DSP settings at 0.0f and 1.0f normalized distance
pPoints: [^]DISTANCE_CURVE_POINT `fmt:"v,PointCount"`, // distance curve point array, must have at least PointCount elements with no duplicates and be sorted in ascending order with respect to Distance
PointCount: u32, // number of distance curve points, must be >= 2 as all distance curves must have at least two endpoints, defining DSP settings at 0.0 and 1.0 normalized distance
}
Default_LinearCurvePoints := [2]DISTANCE_CURVE_POINT{{0.0, 1.0}, {1.0, 0.0}}
Default_LinearCurve := DISTANCE_CURVE{&Default_LinearCurvePoints[0], 2}
// Cone:
// Specifies directionality for a listener or single-channel emitter by modifying DSP behaviour with respect to its front orientation.
// This is modeled using two sound cones: an inner cone and an outer cone. On/within the inner cone, DSP settings are scaled by the inner values.
// On/beyond the outer cone, DSP settings are scaled by the outer values. If on both the cones, DSP settings are scaled by the inner values only.
// Between the two cones, the scaler is linearly interpolated between the inner and outer values. Set both cone angles to 0 or TAU for omnidirectionality using only the outer or inner values respectively.
CONE :: struct #packed {
InnerAngle: f32, // inner cone angle in radians, must be within [0.0f, TAU]
OuterAngle: f32, // outer cone angle in radians, must be within [InnerAngle, TAU]
InnerAngle: f32, // inner cone angle in radians, must be within [0.0, TAU]
OuterAngle: f32, // outer cone angle in radians, must be within [InnerAngle, TAU]
InnerVolume: f32, // volume level scaler on/within inner cone, used only for matrix calculations, must be within [0.0f, 2.0f] when used
OuterVolume: f32, // volume level scaler on/beyond outer cone, used only for matrix calculations, must be within [0.0f, 2.0f] when used
InnerLPF: f32, // LPF (both direct and reverb paths) coefficient subtrahend on/within inner cone, used only for LPF (both direct and reverb paths) calculations, must be within [0.0f, 1.0f] when used
OuterLPF: f32, // LPF (both direct and reverb paths) coefficient subtrahend on/beyond outer cone, used only for LPF (both direct and reverb paths) calculations, must be within [0.0f, 1.0f] when used
InnerReverb: f32, // reverb send level scaler on/within inner cone, used only for reverb calculations, must be within [0.0f, 2.0f] when used
OuterReverb: f32, // reverb send level scaler on/beyond outer cone, used only for reverb calculations, must be within [0.0f, 2.0f] when used
InnerVolume: f32, // volume level scaler on/within inner cone, used only for matrix calculations, must be within [0.0, 2.0] when used
OuterVolume: f32, // volume level scaler on/beyond outer cone, used only for matrix calculations, must be within [0.0, 2.0] when used
InnerLPF: f32, // LPF (both direct and reverb paths) coefficient subtrahend on/within inner cone, used only for LPF (both direct and reverb paths) calculations, must be within [0.0, 1.0] when used
OuterLPF: f32, // LPF (both direct and reverb paths) coefficient subtrahend on/beyond outer cone, used only for LPF (both direct and reverb paths) calculations, must be within [0.0, 1.0] when used
InnerReverb: f32, // reverb send level scaler on/within inner cone, used only for reverb calculations, must be within [0.0, 2.0] when used
OuterReverb: f32, // reverb send level scaler on/beyond outer cone, used only for reverb calculations, must be within [0.0, 2.0] when used
}
Default_DirectionalCone := CONE{math.PI / 2, math.PI, 1.0, 0.708, 0.0, 0.25, 0.708, 1.0}
// Listener:
// Defines a point of 3D audio reception.
//
// The cone is directed by the listener's front orientation.
LISTENER :: struct #packed {
OrientFront: VECTOR, // orientation of front direction, used only for matrix and delay calculations or listeners with cones for matrix, LPF (both direct and reverb paths), and reverb calculations, must be normalized when used
OrientTop: VECTOR, // orientation of top direction, used only for matrix and delay calculations, must be orthonormal with OrientFront when used
OrientFront: VECTOR, // orientation of front direction, used only for matrix and delay calculations or listeners with cones for matrix, LPF (both direct and reverb paths), and reverb calculations, must be normalized when used
OrientTop: VECTOR, // orientation of top direction, used only for matrix and delay calculations, must be orthonormal with OrientFront when used
Position: VECTOR, // position in user-defined world units, does not affect Velocity
Velocity: VECTOR, // velocity vector in user-defined world units/second, used only for doppler calculations, does not affect Position
Position: VECTOR, // position in user-defined world units, does not affect Velocity
Velocity: VECTOR, // velocity vector in user-defined world units/second, used only for doppler calculations, does not affect Position
pCone: ^CONE, // sound cone, used only for matrix, LPF (both direct and reverb paths), and reverb calculations, NULL specifies omnidirectionality
pCone: ^CONE, // sound cone, used only for matrix, LPF (both direct and reverb paths), and reverb calculations, nil specifies omnidirectionality
}
// Emitter:
// Defines a 3D audio source, divided into two classifications:
//
// Single-point -- For use with single-channel sounds.
// Positioned at the emitter base, i.e. the channel radius and azimuth are ignored if the number of channels == 1.
//
// May be omnidirectional or directional using a cone.
// The cone originates from the emitter base position, and is directed by the emitter's front orientation.
//
// Multi-point -- For use with multi-channel sounds.
// Each non-LFE channel is positioned using an azimuth along the channel radius with respect to the front orientation vector in the plane orthogonal to the top orientation vector.
// An azimuth of TAU specifies a channel is an LFE. Such channels are positioned at the emitter base and are calculated with respect to pLFECurve only, never pVolumeCurve.
//
// Multi-point emitters are always omnidirectional, i.e. the cone is ignored if the number of channels > 1.
//
// Note that many properties are shared among all channel points, locking certain behaviour with respect to the emitter base position.
// For example, doppler shift is always calculated with respect to the emitter base position and so is constant for all its channel points.
// Distance curve calculations are also with respect to the emitter base position, with the curves being calculated independently of each other.
// For instance, volume and LFE calculations do not affect one another.
EMITTER :: struct #packed {
pCone: ^CONE, // sound cone, used only with single-channel emitters for matrix, LPF (both direct and reverb paths), and reverb calculations, NULL specifies omnidirectionality
pCone: ^CONE, // sound cone, used only with single-channel emitters for matrix, LPF (both direct and reverb paths), and reverb calculations, nil specifies omnidirectionality
OrientFront: VECTOR, // orientation of front direction, used only for emitter angle calculations or with multi-channel emitters for matrix calculations or single-channel emitters with cones for matrix, LPF (both direct and reverb paths), and reverb calculations, must be normalized when used
OrientTop: VECTOR, // orientation of top direction, used only with multi-channel emitters for matrix calculations, must be orthonormal with OrientFront when used
@@ -184,26 +162,25 @@ EMITTER :: struct #packed {
Position: VECTOR, // position in user-defined world units, does not affect Velocity
Velocity: VECTOR, // velocity vector in user-defined world units/second, used only for doppler calculations, does not affect Position
InnerRadius: f32, // inner radius, must be within [0.0f, max(f32)]
InnerRadiusAngle: f32, // inner radius angle, must be within [0.0f, PI/4.0)
InnerRadius: f32, // inner radius, must be within [0.0, max(f32)]
InnerRadiusAngle: f32, // inner radius angle, must be within [0.0, PI/4.0)
ChannelCount: u32, // number of sound channels, must be > 0
ChannelRadius: f32, // channel radius, used only with multi-channel emitters for matrix calculations, must be >= 0.0f when used
pChannelAzimuths: [^]f32 `fmt:"v,ChannelCount"`, // channel azimuth array, used only with multi-channel emitters for matrix calculations, contains positions of each channel expressed in radians along the channel radius with respect to the front orientation vector in the plane orthogonal to the top orientation vector, or TAU to specify an LFE channel, must have at least ChannelCount elements, all within [0.0f, TAU] when used
ChannelCount: u32, // number of sound channels, must be > 0
ChannelRadius: f32, // channel radius, used only with multi-channel emitters for matrix calculations, must be >= 0.0 when used
pChannelAzimuths: [^]f32 `fmt:"v,ChannelCount"`, // channel azimuth array, used only with multi-channel emitters for matrix calculations, contains positions of each channel expressed in radians along the channel radius with respect to the front orientation vector in the plane orthogonal to the top orientation vector, or TAU to specify an LFE channel, must have at least ChannelCount elements, all within [0.0, TAU] when used
pVolumeCurve: ^DISTANCE_CURVE, // volume level distance curve, used only for matrix calculations, NULL specifies a default curve that conforms to the inverse square law, calculated in user-defined world units with distances <= CurveDistanceScaler clamped to no attenuation
pLFECurve: ^DISTANCE_CURVE, // LFE level distance curve, used only for matrix calculations, NULL specifies a default curve that conforms to the inverse square law, calculated in user-defined world units with distances <= CurveDistanceScaler clamped to no attenuation
pLPFDirectCurve: ^DISTANCE_CURVE, // LPF direct-path coefficient distance curve, used only for LPF direct-path calculations, NULL specifies the default curve: [0.0f,1.0f], [1.0f,0.75f]
pLPFReverbCurve: ^DISTANCE_CURVE, // LPF reverb-path coefficient distance curve, used only for LPF reverb-path calculations, NULL specifies the default curve: [0.0f,0.75f], [1.0f,0.75f]
pReverbCurve: ^DISTANCE_CURVE, // reverb send level distance curve, used only for reverb calculations, NULL specifies the default curve: [0.0f,1.0f], [1.0f,0.0f]
pVolumeCurve: ^DISTANCE_CURVE, // volume level distance curve, used only for matrix calculations, nil specifies a default curve that conforms to the inverse square law, calculated in user-defined world units with distances <= CurveDistanceScaler clamped to no attenuation
pLFECurve: ^DISTANCE_CURVE, // LFE level distance curve, used only for matrix calculations, nil specifies a default curve that conforms to the inverse square law, calculated in user-defined world units with distances <= CurveDistanceScaler clamped to no attenuation
pLPFDirectCurve: ^DISTANCE_CURVE, // LPF direct-path coefficient distance curve, used only for LPF direct-path calculations, nil specifies the default curve: [0.0,1.0], [1.0,0.75]
pLPFReverbCurve: ^DISTANCE_CURVE, // LPF reverb-path coefficient distance curve, used only for LPF reverb-path calculations, nil specifies the default curve: [0.0,0.75], [1.0,0.75]
pReverbCurve: ^DISTANCE_CURVE, // reverb send level distance curve, used only for reverb calculations, nil specifies the default curve: [0.0,1.0], [1.0,0.0]
CurveDistanceScaler: f32, // curve distance scaler, used to scale normalized distance curves to user-defined world units and/or exaggerate their effect, used only for matrix, LPF (both direct and reverb paths), and reverb calculations, must be within [min(f32), max(f32)] when used
DopplerScaler: f32, // doppler shift scaler, used to exaggerate doppler shift effect, used only for doppler calculations, must be within [0.0f, max(f32)] when used
DopplerScaler: f32, // doppler shift scaler, used to exaggerate doppler shift effect, used only for doppler calculations, must be within [0.0, max(f32)] when used
}
// DSP settings:
// Receives results from a call to Calculate to be sent to the low-level audio rendering API for 3D signal processing.
//
// The user is responsible for allocating the matrix coefficient table, delay time array, and initializing the channel counts when used.
DSP_SETTINGS :: struct #packed {
pMatrixCoefficients: [^]f32, // [inout] matrix coefficient table, receives an array representing the volume level used to send from source channel S to destination channel D, stored as pMatrixCoefficients[SrcChannelCount * D + S], must have at least SrcChannelCount*DstChannelCount elements
+60 -97
View File
@@ -1,75 +1,45 @@
#+build windows
/* NOTES:
1. Definition of terms:
1. Definition of terms:
DSP: Digital Signal Processing.
CBR: Constant BitRate -- DSP that consumes a constant number of
input samples to produce an output sample.
For example, a 22kHz to 44kHz resampler is CBR DSP.
Even though the number of input to output samples differ,
the ratio between input to output rate remains constant.
All user-defined XAPOs are assumed to be CBR as
XAudio2 only allows CBR DSP to be added to an effect chain.
CBR: Constant BitRate -- DSP that consumes a constant number of input samples to produce an output sample.
For example, a 22kHz to 44kHz resampler is CBR DSP. Even though the number of input to output samples differ, the ratio between input to output rate remains constant.
All user-defined XAPOs are assumed to be CBR as XAudio2 only allows CBR DSP to be added to an effect chain.
XAPO: Cross-platform Audio Processing Object --
a thin wrapper that manages DSP code, allowing it
to be easily plugged into an XAudio2 effect chain.
a thin wrapper that manages DSP code, allowing it to be easily plugged into an XAudio2 effect chain.
Frame: A block of samples, one per channel,
to be played simultaneously.
Frame: A block of samples, one per channel, to be played simultaneously.
E.g. a mono stream has one sample per frame.
In-Place: Processing such that the input buffer equals the
output buffer (i.e. input data modified directly).
This form of processing is generally more efficient
than using separate memory for input and output.
However, an XAPO may not perform format conversion
when processing in-place.
In-Place: Processing such that the input buffer equals the output buffer (i.e. input data modified directly).
This form of processing is generally more efficient than using separate memory for input and output.
However, an XAPO may not perform format conversion when processing in-place.
2. XAPO member variables are divided into three classifications:
Immutable: Set once via IXAPO.Initialize and remain
constant during the lifespan of the XAPO.
2. XAPO member variables are divided into three classifications:
Immutable: Set once via IXAPO.Initialize and remain constant during the lifespan of the XAPO.
Locked: May change before the XAPO is locked via
IXAPO.LockForProcess but remain constant
until IXAPO.UnlockForProcess is called.
IXAPO.LockForProcess but remain constant until IXAPO.UnlockForProcess is called.
Dynamic: May change from one processing pass to the next,
usually via IXAPOParameters.SetParameters.
XAPOs should assign reasonable defaults to their dynamic
variables during IXAPO.Initialize/LockForProcess so
that calling IXAPOParameters.SetParameters is not
required before processing begins.
Dynamic: May change from one processing pass to the next, usually via IXAPOParameters.SetParameters.
XAPOs should assign reasonable defaults to their dynamic variables during IXAPO.Initialize/LockForProcess so that calling IXAPOParameters.SetParameters is not required before processing begins.
When implementing an XAPO, determine the type of each variable and
initialize them in the appropriate method. Immutable variables are
generally preferable over locked which are preferable over dynamic.
That is, one should strive to minimize XAPO state changes for
best performance, maintainability, and ease of use.
When implementing an XAPO, determine the type of each variable and initialize them in the appropriate method. Immutable variables are generally preferable over locked which are preferable over dynamic.
That is, one should strive to minimize XAPO state changes for best performance, maintainability, and ease of use.
3. To minimize glitches, the realtime audio processing thread must
not block. XAPO methods called by the realtime thread are commented
as non-blocking and therefore should not use blocking synchronization,
allocate memory, access the disk, etc. The XAPO interfaces were
designed to allow an effect implementer to move such operations
into other methods called on an application controlled thread.
3. To minimize glitches, the realtime audio processing thread must not block. XAPO methods called by the realtime thread are commented as non-blocking and therefore should not use blocking synchronization, allocate memory, access the disk, etc.
The XAPO interfaces were designed to allow an effect implementer to move such operations into other methods called on an application controlled thread.
4. Extending functionality is accomplished through the addition of new
COM interfaces. For example, if a new member is added to a parameter
structure, a new interface using the new structure should be added,
leaving the original interface unchanged.
This ensures consistent communication between future versions of
XAudio2 and various versions of XAPOs that may exist in an application.
4. Extending functionality is accomplished through the addition of new COM interfaces. For example, if a new member is added to a parameter structure, a new interface using the new structure should be added, leaving the original interface unchanged.
This ensures consistent communication between future versions of XAudio2 and various versions of XAPOs that may exist in an application.
5. All audio data is interleaved in XAudio2.
5. All audio data is interleaved in XAudio2.
The default audio format for an effect chain is WAVE_FORMAT_IEEE_FLOAT.
6. User-defined XAPOs should assume all input and output buffers are
16-byte aligned.
7. See XAPOBase.odin for an XAPO base class which provides a default
implementation for most of the interface methods defined below. */
6. User-defined XAPOs should assume all input and output buffers are 16-byte aligned. */
package windows_xaudio2
@@ -77,8 +47,7 @@ import win "core:sys/windows"
//--------------<D-E-F-I-N-I-T-I-O-N-S>-------------------------------------//
// XAPO error codes
FORMAT_UNSUPPORTED := win.MAKE_HRESULT(win.SEVERITY.ERROR, 0x897, 0x01) // requested audio format unsupported
FORMAT_UNSUPPORTED := win.MAKE_HRESULT(win.SEVERITY.ERROR, win.FACILITY.XAPO, 0x01) // requested audio format unsupported
// supported number of channels (samples per frame) range
XAPO_MIN_CHANNELS :: 1
@@ -111,11 +80,11 @@ XAPO_FLAG :: enum u32 {
// XAPO must be run in-place. Use this flag only if your DSP implementation cannot process separate input and output buffers.
// If set, the following flags must also be set:
// XAPO_FLAG_CHANNELS_MUST_MATCH
// XAPO_FLAG_FRAMERATE_MUST_MATCH
// XAPO_FLAG_BITSPERSAMPLE_MUST_MATCH
// XAPO_FLAG_BUFFERCOUNT_MUST_MATCH
// XAPO_FLAG_INPLACE_SUPPORTED
// CHANNELS_MUST_MATCH
// FRAMERATE_MUST_MATCH
// BITSPERSAMPLE_MUST_MATCH
// BUFFERCOUNT_MUST_MATCH
// INPLACE_SUPPORTED
// Multiple input and output buffers may be used with in-place XAPOs, though the input buffer count must equal the output buffer count.
// When multiple input/output buffers are used, the XAPO may assume input buffer [N] equals output buffer [N] for in-place processing.
INPLACE_REQUIRED = 5,
@@ -139,18 +108,18 @@ XAPO_REGISTRATION_PROPERTIES :: struct #packed {
Flags: XAPO_FLAGS, // XAPO property flags, describes supported input/output configuration
MinInputBufferCount: u32, // minimum number of input buffers required for processing, can be 0
MaxInputBufferCount: u32, // maximum number of input buffers supported for processing, must be >= MinInputBufferCount
MinOutputBufferCount: u32, // minimum number of output buffers required for processing, can be 0, must match MinInputBufferCount when XAPO_FLAG_BUFFERCOUNT_MUST_MATCH used
MaxOutputBufferCount: u32, // maximum number of output buffers supported for processing, must be >= MinOutputBufferCount, must match MaxInputBufferCount when XAPO_FLAG_BUFFERCOUNT_MUST_MATCH used
MinOutputBufferCount: u32, // minimum number of output buffers required for processing, can be 0, must match MinInputBufferCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used
MaxOutputBufferCount: u32, // maximum number of output buffers supported for processing, must be >= MinOutputBufferCount, must match MaxInputBufferCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used
}
// LockForProcess buffer parameters:
// Defines buffer parameters that remain constant while an XAPO is locked.
// Used with IXAPO::LockForProcess.
// Used with IXAPO.LockForProcess.
// For CBR XAPOs, MaxFrameCount is the only number of frames
// IXAPO::Process would have to handle for the respective buffer.
// IXAPO.Process would have to handle for the respective buffer.
XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS :: struct #packed {
pFormat: ^WAVEFORMATEX, // buffer audio format
MaxFrameCount: u32, // maximum number of frames in respective buffer that IXAPO::Process would have to handle, irrespective of dynamic variable settings, can be 0
MaxFrameCount: u32, // maximum number of frames in respective buffer that IXAPO.Process would have to handle, irrespective of dynamic variable settings, can be 0
}
// Buffer flags:
@@ -161,31 +130,25 @@ XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS :: struct #packed {
// If silent, the XAPO may simply set the flag on the output buffer to silent and return, optimizing out the work of processing silent data: XAPOs that generate silence for any reason may set the buffer's flag accordingly rather than writing out silent frames to the buffer itself.
// The flags represent what should be assumed is in the respective buffer. The flags may not reflect what is actually stored in memory.
XAPO_BUFFER_FLAGS :: enum i32 {
XAPO_BUFFER_SILENT, // silent data should be assumed, respective memory may be uninitialized
XAPO_BUFFER_VALID, // arbitrary data should be assumed (may or may not be silent frames), respective memory initialized
SILENT, // silent data should be assumed, respective memory may be uninitialized
VALID, // arbitrary data should be assumed (may or may not be silent frames), respective memory initialized
}
// Process buffer parameters:
// Defines buffer parameters that may change from one
// processing pass to the next. Used with IXAPO::Process.
//
// Defines buffer parameters that may change from one processing pass to the next. Used with IXAPO.Process.
// Note the byte size of the respective buffer must be at least:
// XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount * XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat->nBlockAlign
//
// Although the audio format and maximum size of the respective
// buffer is locked (defined by XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS),
// the actual memory address of the buffer given is permitted to change
// from one processing pass to the next.
//
// For CBR XAPOs, ValidFrameCount is constant while locked and equals
// the respective XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount.
// XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount * XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat.nBlockAlign
// Although the audio format and maximum size of the respective buffer is locked (defined by XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS), the actual memory address of the buffer given is permitted to change from one processing pass to the next.
// For CBR XAPOs, ValidFrameCount is constant while locked and equals the respective XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount.
XAPO_PROCESS_BUFFER_PARAMETERS :: struct #packed {
pBuffer: rawptr, // audio data buffer, must be non-NULL
pBuffer: rawptr, // audio data buffer, must be non-nil
BufferFlags: XAPO_BUFFER_FLAGS, // describes assumed content of pBuffer, does not affect ValidFrameCount
ValidFrameCount: u32, // number of frames of valid data, must be within respective [0, XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount], always XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount for CBR/user-defined XAPOs, does not affect BufferFlags
}
XAPOFree :: win.CoTaskMemFree
// Used by IXAPO methods that must allocate arbitrary sized structures such as WAVEFORMATEX that are subsequently returned to the application.
XAPOAlloc :: win.CoTaskMemAlloc
XAPOFree :: win.CoTaskMemFree
IXAPO_UUID_STRING :: "A410B984-9839-4819-A0BE-2856AE6B3ADB"
IXAPO_UUID := &win.IID{0xA410B984, 0x9839, 0x4819, {0xA0, 0xBE, 0x28, 0x56, 0xAE, 0x6B, 0x3A, 0xDB}}
@@ -214,11 +177,11 @@ IXAPO_VTable :: struct {
// PARAMETERS:
// pOutputFormat - [in] output format known to be supported
// pRequestedInputFormat - [in] input format to examine
// ppSupportedInputFormat - [out] receives pointer to nearest input format supported if not NULL and input/output configuration unsupported, use XAPOFree to free structure, left untouched on any failure except XAPO_E_FORMAT_UNSUPPORTED
// ppSupportedInputFormat - [out] receives pointer to nearest input format supported if not nil and input/output configuration unsupported, use XAPOFree to free structure, left untouched on any failure except FORMAT_UNSUPPORTED
// RETURN VALUE:
// COM error code, including:
// S_OK - input/output configuration supported, ppSupportedInputFormat left untouched
// FORMAT_UNSUPPORTED - input/output configuration unsupported, ppSupportedInputFormat receives pointer to nearest input format supported if not NULL
// FORMAT_UNSUPPORTED - input/output configuration unsupported, ppSupportedInputFormat receives pointer to nearest input format supported if not nil
// E_INVALIDARG - either audio format invalid, ppSupportedInputFormat left untouched
IsInputFormatSupported: proc "system" (this: ^IXAPO, pOutputFormat: ^WAVEFORMATEX, pRequestedInputFormat: ^WAVEFORMATEX, ppSupportedInputFormat: ^^WAVEFORMATEX) -> HRESULT,
@@ -232,11 +195,11 @@ IXAPO_VTable :: struct {
// PARAMETERS:
// pInputFormat - [in] input format known to be supported
// pRequestedOutputFormat - [in] output format to examine
// ppSupportedOutputFormat - [out] receives pointer to nearest output format supported if not NULL and input/output configuration unsupported, use XAPOFree to free structure, left untouched on any failure except XAPO_E_FORMAT_UNSUPPORTED
// ppSupportedOutputFormat - [out] receives pointer to nearest output format supported if not nil and input/output configuration unsupported, use XAPOFree to free structure, left untouched on any failure except FORMAT_UNSUPPORTED
// RETURN VALUE:
// COM error code, including:
// S_OK - input/output configuration supported, ppSupportedOutputFormat left untouched
// FORMAT_UNSUPPORTED - input/output configuration unsupported, ppSupportedOutputFormat receives pointer to nearest output format supported if not NULL
// FORMAT_UNSUPPORTED - input/output configuration unsupported, ppSupportedOutputFormat receives pointer to nearest output format supported if not nil
// E_INVALIDARG - either audio format invalid, ppSupportedOutputFormat left untouched
IsOutputFormatSupported: proc "system" (this: ^IXAPO, pInputFormat: ^WAVEFORMATEX, pRequestedOutputFormat: ^WAVEFORMATEX, ppSupportedOutputFormat: ^^WAVEFORMATEX) -> HRESULT,
@@ -246,10 +209,10 @@ IXAPO_VTable :: struct {
// The contents of pData are defined by the XAPO.
// Immutable variables (constant during the lifespan of the XAPO) should be set once via this method.
// Once initialized, an XAPO cannot be initialized again.
// An XAPO should be initialized before passing it to XAudio2 as part of an effect chain. XAudio2 will not call this method; it exists for future content-driven initialization.
// An XAPO should be initialized before passing it to XAudio2 as part of an effect chain. XAudio2 will not call this method; it exists for future content-driven initialization.
// PARAMETERS:
// pData - [in] effect-specific initialization parameters, may be NULL if DataByteSize == 0
// DataByteSize - [in] size of pData in bytes, may be 0 if pData is NULL
// pData - [in] effect-specific initialization parameters, may be nil if DataByteSize == 0
// DataByteSize - [in] size of pData in bytes, may be 0 if pData is nil
// RETURN VALUE:
// COM error code
Initialize: proc "system" (this: ^IXAPO, pData: rawptr, DataByteSize: u32) -> HRESULT,
@@ -279,9 +242,9 @@ IXAPO_VTable :: struct {
// Once locked, an XAPO cannot be locked again until UnLockForProcess is called.
// PARAMETERS:
// InputLockedParameterCount - [in] number of input buffers, must be within [XAPO_REGISTRATION_PROPERTIES.MinInputBufferCount, XAPO_REGISTRATION_PROPERTIES.MaxInputBufferCount]
// pInputLockedParameters - [in] array of input locked buffer parameter structures, may be NULL if InputLockedParameterCount == 0, otherwise must have InputLockedParameterCount elements
// OutputLockedParameterCount - [in] number of output buffers, must be within [XAPO_REGISTRATION_PROPERTIES.MinOutputBufferCount, XAPO_REGISTRATION_PROPERTIES.MaxOutputBufferCount], must match InputLockedParameterCount when XAPO_FLAG_BUFFERCOUNT_MUST_MATCH used
// pOutputLockedParameters - [in] array of output locked buffer parameter structures, may be NULL if OutputLockedParameterCount == 0, otherwise must have OutputLockedParameterCount elements
// pInputLockedParameters - [in] array of input locked buffer parameter structures, may be nil if InputLockedParameterCount == 0, otherwise must have InputLockedParameterCount elements
// OutputLockedParameterCount - [in] number of output buffers, must be within [XAPO_REGISTRATION_PROPERTIES.MinOutputBufferCount, XAPO_REGISTRATION_PROPERTIES.MaxOutputBufferCount], must match InputLockedParameterCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used
// pOutputLockedParameters - [in] array of output locked buffer parameter structures, may be nil if OutputLockedParameterCount == 0, otherwise must have OutputLockedParameterCount elements
// RETURN VALUE:
// COM error code
LockForProcess: proc "system" (this: ^IXAPO, InputLockedParameterCount: u32, pInputLockedParameters: [^]XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS, OutputLockedParameterCount: u32, pOutputLockedParameters: [^]XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS) -> HRESULT,
@@ -303,16 +266,16 @@ IXAPO_VTable :: struct {
// ppInputProcessParameters will not necessarily be the same as ppOutputProcessParameters for in-place processing, rather the pBuffer members of each will point to the same memory.
// Multiple input/output buffers may be used with in-place XAPOs, though the input buffer count must equal the output buffer count.
// When multiple input/output buffers are used with in-place XAPOs, the XAPO may assume input buffer [N] equals output buffer [N].
// When IsEnabled is FALSE, the XAPO should process thru. Thru processing means an XAPO should not apply its normal processing to the given input/output buffers during Process.
// It should instead pass data from input to output with as little modification possible. Effects that perform format conversion should continue to do so.
// When IsEnabled is false, the XAPO should process thru. Thru processing means an XAPO should not apply its normal processing to the given input/output buffers during Process.
// It should instead pass data from input to output with as little modification possible. Effects that perform format conversion should continue to do so.
// The effect must ensure transitions between normal and thru processing do not introduce discontinuities into the signal.
// XAudio2 calls this method only if the XAPO is locked. This method should not block as it is called from the realtime thread.
// PARAMETERS:
// InputProcessParameterCount - [in] number of input buffers, matches respective InputLockedParameterCount parameter given to LockForProcess
// pInputProcessParameters - [in] array of input process buffer parameter structures, may be NULL if InputProcessParameterCount == 0, otherwise must have InputProcessParameterCount elements
// pInputProcessParameters - [in] array of input process buffer parameter structures, may be nil if InputProcessParameterCount == 0, otherwise must have InputProcessParameterCount elements
// OutputProcessParameterCount - [in] number of output buffers, matches respective OutputLockedParameterCount parameter given to LockForProcess
// pOutputProcessParameters - [in/out] array of output process buffer parameter structures, may be NULL if OutputProcessParameterCount == 0, otherwise must have OutputProcessParameterCount elements
// IsEnabled - [in] TRUE to process normally, FALSE to process thru
// pOutputProcessParameters - [in/out] array of output process buffer parameter structures, may be nil if OutputProcessParameterCount == 0, otherwise must have OutputProcessParameterCount elements
// IsEnabled - [in] true to process normally, false to process thru
// RETURN VALUE:
// void
Process: proc "system" (this: ^IXAPO, InputProcessParameterCount: u32, pInputProcessParameters: [^]XAPO_PROCESS_BUFFER_PARAMETERS, OutputProcessParameterCount: u32, pOutputProcessParameters: [^]XAPO_PROCESS_BUFFER_PARAMETERS, IsEnabled: b32),
@@ -358,7 +321,7 @@ IXAPOParameters_VTable :: struct {
// This method may only be called on the realtime thread; no synchronization between it and IXAPO.Process is necessary.
// This method should not block as it is called from the realtime thread.
// PARAMETERS:
// pParameters - [in] effect-specific parameter block, must be != NULL
// pParameters - [in] effect-specific parameter block, must be != nil
// ParameterByteSize - [in] size of pParameters in bytes, must be > 0
// RETURN VALUE:
// void
@@ -369,7 +332,7 @@ IXAPOParameters_VTable :: struct {
// REMARKS:
// Unlike SetParameters, XAudio2 does not call this method on the realtime thread. Thus, the XAPO must protect variables shared with SetParameters/Process using appropriate synchronization.
// PARAMETERS:
// pParameters - [out] receives effect-specific parameter block, must be != NULL
// pParameters - [out] receives effect-specific parameter block, must be != nil
// ParameterByteSize - [in] size of pParameters in bytes, must be > 0
// RETURN VALUE:
// void
+2 -2
View File
@@ -132,7 +132,7 @@ FXECHO_PARAMETERS :: struct #packed {
@(default_calling_convention="cdecl")
foreign xa2 {
// creates instance of requested XAPO, use Release to free instance
// pInitData - [in] effect-specific initialization parameters, may be NULL if InitDataByteSize == 0
// InitDataByteSize - [in] size of pInitData in bytes, may be 0 if pInitData is NULL
// pInitData - [in] effect-specific initialization parameters, may be nil if InitDataByteSize == 0
// InitDataByteSize - [in] size of pInitData in bytes, may be 0 if pInitData is nil
CreateFX :: proc(clsid: win.REFCLSID, pEffect: ^^IUnknown, pInitDat: rawptr = nil, InitDataByteSize: u32 = 0) -> HRESULT ---
}
+35 -57
View File
@@ -11,6 +11,8 @@ package windows_xaudio2
import win "core:sys/windows"
import "core:math"
foreign import xa2 "system:xaudio2.lib"
HRESULT :: win.HRESULT
IUnknown :: win.IUnknown
IUnknown_VTable :: win.IUnknown_VTable
@@ -93,8 +95,8 @@ DEVICE_INVALIDATED :: HRESULT(-2003435516) // 0x88960004 An audio device be
**************************************************************************/
// Used in Create, specifies which CPU(s) to use.
PROCESSOR_FLAGS :: distinct bit_set[PROCESOR_FLAG; u32]
PROCESOR_FLAG :: enum u32 {
PROCESSOR_FLAGS :: distinct bit_set[PROCESSOR_FLAG; u32]
PROCESSOR_FLAG :: enum u32 {
Processor1 = 0,
Processor2 = 1,
Processor3 = 2,
@@ -128,7 +130,7 @@ PROCESOR_FLAG :: enum u32 {
Processor31 = 30,
Processor32 = 31,
}
//ANY_PROCESSOR :: 0xffffffff
USE_DEFAULT_PROCESSOR :: PROCESSOR_FLAGS{}
// Returned by IXAudio2Voice.GetVoiceDetails
@@ -147,8 +149,8 @@ SEND_DESCRIPTOR :: struct #packed {
// Used in the voice creation functions and in IXAudio2Voice.SetOutputVoices
VOICE_SENDS :: struct #packed {
SendCount: u32, // Number of sends from this voice.
pSends: [^]SEND_DESCRIPTOR, // Array of SendCount send descriptors.
SendCount: u32, // Number of sends from this voice.
pSends: [^]SEND_DESCRIPTOR `fmt:"v,SendCount"`, // Array of SendCount send descriptors.
}
// Used in EFFECT_CHAIN below
@@ -160,8 +162,8 @@ EFFECT_DESCRIPTOR :: struct #packed {
// Used in the voice creation functions and in IXAudio2Voice.SetEffectChain
EFFECT_CHAIN :: struct #packed {
EffectCount: u32, // Number of effects in this voice's effect chain.
pEffectDescriptors: [^]EFFECT_DESCRIPTOR, // Array of effect descriptors.
EffectCount: u32, // Number of effects in this voice's effect chain.
pEffectDescriptors: [^]EFFECT_DESCRIPTOR `fmt:"v,EffectCount"`, // Array of effect descriptors.
}
// Used in FILTER_PARAMETERS below
@@ -183,28 +185,28 @@ FILTER_PARAMETERS :: struct #packed {
// Used in IXAudio2SourceVoice.SubmitSourceBuffer
BUFFER :: struct #packed {
Flags: FLAGS, // Either 0 or END_OF_STREAM.
AudioBytes: u32, // Size of the audio data buffer in bytes.
pAudioData: [^]byte, // Pointer to the audio data buffer.
PlayBegin: u32, // First sample in this buffer to be played.
PlayLength: u32, // Length of the region to be played in samples, or 0 to play the whole buffer.
LoopBegin: u32, // First sample of the region to be looped.
LoopLength: u32, // Length of the desired loop region in samples, or 0 to loop the entire buffer.
LoopCount: u32, // Number of times to repeat the loop region, or LOOP_INFINITE to loop forever.
pContext: rawptr, // Context value to be passed back in callbacks.
Flags: FLAGS, // Either 0 or END_OF_STREAM.
AudioBytes: u32, // Size of the audio data buffer in bytes.
pAudioData: [^]byte `fmt:"v,AudioBytes"`, // Pointer to the audio data buffer.
PlayBegin: u32, // First sample in this buffer to be played.
PlayLength: u32, // Length of the region to be played in samples, or 0 to play the whole buffer.
LoopBegin: u32, // First sample of the region to be looped.
LoopLength: u32, // Length of the desired loop region in samples, or 0 to loop the entire buffer.
LoopCount: u32, // Number of times to repeat the loop region, or LOOP_INFINITE to loop forever.
pContext: rawptr, // Context value to be passed back in callbacks.
}
// Used in IXAudio2SourceVoice.SubmitSourceBuffer when submitting XWMA data.
// NOTE: If an XWMA sound is submitted in more than one buffer, each buffer's pDecodedPacketCumulativeBytes[PacketCount-1] value must be subtracted from all the entries in the next buffer's pDecodedPacketCumulativeBytes array.
// And whether a sound is submitted in more than one buffer or not, the final buffer of the sound should use the END_OF_STREAM flag, or else the client must call IXAudio2SourceVoice.Discontinuity after submitting it.
BUFFER_WMA :: struct #packed {
pDecodedPacketCumulativeBytes: [^]u32, // Decoded packet's cumulative size array. Each element is the number of bytes accumulated when the corresponding XWMA packet is decoded in order. The array must have PacketCount elements.
PacketCount: u32, // Number of XWMA packets submitted. Must be >= 1 and divide evenly into BUFFER.AudioBytes.
pDecodedPacketCumulativeBytes: [^]u32 `fmt:"v,PacketCount"`, // Decoded packet's cumulative size array. Each element is the number of bytes accumulated when the corresponding XWMA packet is decoded in order. The array must have PacketCount elements.
PacketCount: u32, // Number of XWMA packets submitted. Must be >= 1 and divide evenly into BUFFER.AudioBytes.
}
// Returned by IXAudio2SourceVoice.GetState
VOICE_STATE :: struct #packed {
pCurrentBufferContext: rawptr, // The pContext value provided in the BUFFER that is currently being processed, or NULL if there are no buffers in the queue.
pCurrentBufferContext: rawptr, // The pContext value provided in the BUFFER that is currently being processed, or nil if there are no buffers in the queue.
BuffersQueued: u32, // Number of buffers currently queued on the voice (including the one that is being processed).
SamplesPlayed: u64, // Total number of samples produced by the voice since it began processing the current audio stream. If VOICE_NOSAMPLESPLAYED is specified in the call to IXAudio2SourceVoice.GetState, this member will not be calculated, saving CPU.
}
@@ -336,8 +338,7 @@ IXAudio2_VTable :: struct {
StopEngine: proc "system" (this: ^IXAudio2),
// NAME: IXAudio2.CommitChanges
// DESCRIPTION: Atomically applies a set of operations previously tagged
// with a given identifier.
// DESCRIPTION: Atomically applies a set of operations previously tagged with a given identifier.
// ARGUMENTS:
// OperationSet - Identifier of the set of operations to be applied.
CommitChanges: proc "system" (this: ^IXAudio2, OperationSet: u32) -> HRESULT,
@@ -352,7 +353,7 @@ IXAudio2_VTable :: struct {
// DESCRIPTION: Configures XAudio2's debug output (in debug builds only).
// ARGUMENTS:
// pDebugConfiguration - Structure describing the debug output behavior.
// pReserved - Optional parameter; must be NULL.
// pReserved - Optional parameter; must be nil.
SetDebugConfiguration: proc "system" (this: ^IXAudio2, pDebugConfiguration: ^DEBUG_CONFIGURATION, pReserved: rawptr = nil),
}
@@ -399,8 +400,7 @@ IXAudio2Voice_VTable :: struct {
GetVoiceDetails: proc "system" (this: ^IXAudio2Voice, pVoiceDetails: ^VOICE_DETAILS),
// NAME: IXAudio2Voice.SetOutputVoices
// DESCRIPTION: Replaces the set of submix/mastering voices that receive
// this voice's output.
// DESCRIPTION: Replaces the set of submix/mastering voices that receive this voice's output.
// ARGUMENTS:
// pSendList - Optional list of voices this voice should send audio to.
SetOutputVoices: proc "system" (this: ^IXAudio2Voice, pSendList: [^]VOICE_SENDS) -> HRESULT,
@@ -709,37 +709,15 @@ IXAudio2VoiceCallback_VTable :: struct {
*
* Flags - Flags specifying the XAudio2 object's behavior.
*
* XAudio2Processor - A PROCESSOR_FLAGS value that specifies the hardware threads (Xbox) or processors (Windows) that XAudio2 will use.
* Processor - A PROCESSOR_FLAGS value that specifies the hardware threads (Xbox) or processors (Windows) that XAudio2 will use.
* Note that XAudio2 supports concurrent processing on multiple threads, using any combination of PROCESSOR_FLAGS flags.
* The values are platform-specific; platform-independent code can use USE_DEFAULT_PROCESSOR to use the default on each platform.
*
**************************************************************************/
Create :: proc "stdcall" (ppXAudio2: ^^IXAudio2, Flags: FLAGS = {}, XAudio2Processor: PROCESSOR_FLAGS = {.Processor1}) -> HRESULT {
CreateWithVersionInfoFunc :: #type proc "c" (a0: ^^IXAudio2, a1: FLAGS, a2: PROCESSOR_FLAGS, a3: win.DWORD) -> HRESULT
CreateInfoFunc :: #type proc "c" (a0: ^^IXAudio2, a1: FLAGS, a2: PROCESSOR_FLAGS) -> HRESULT
dll_Instance: win.HMODULE
create_with_version_info: CreateWithVersionInfoFunc
create_info: CreateInfoFunc
if dll_Instance == nil {
dll_Instance = win.LoadLibraryExW(win.L("xaudio2_9.dll"), nil, {.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS})
if dll_Instance == nil {
return HRESULT(win.GetLastError())
}
create_with_version_info = cast(CreateWithVersionInfoFunc)win.GetProcAddress(dll_Instance, "XAudio2CreateWithVersionInfo")
if create_with_version_info == nil {
create_info = cast(CreateInfoFunc)win.GetProcAddress(dll_Instance, "XAudio2Create")
if create_info == nil {
return HRESULT(win.GetLastError())
}
}
}
if create_with_version_info != nil {
return create_with_version_info(ppXAudio2, Flags, XAudio2Processor, 0x0A000010)
}
return create_info(ppXAudio2, Flags, XAudio2Processor)
@(default_calling_convention="system", link_prefix="XAudio2")
foreign xa2 {
Create :: proc(ppXaudio2: ^^IXAudio2, Flags: FLAGS = {}, Processor: PROCESSOR_FLAGS = {.Processor1}) -> HRESULT ---
}
/**************************************************************************
@@ -749,12 +727,12 @@ Create :: proc "stdcall" (ppXAudio2: ^^IXAudio2, Flags: FLAGS = {}, XAudio2Proce
**************************************************************************/
// Calculate the argument to SetVolume from a decibel value
DecibelsToAmplitudeRatio :: proc "contextless" (Decibels: f32) -> f32 {
DecibelsToAmplitudeRatio :: #force_inline proc "contextless" (Decibels: f32) -> f32 {
return math.pow_f32(10.0, Decibels / 20.0)
}
// Recover a volume in decibels from an amplitude factor
AmplitudeRatioToDecibels :: proc "contextless" (Volume: f32) -> f32 {
AmplitudeRatioToDecibels :: #force_inline proc "contextless" (Volume: f32) -> f32 {
if Volume == 0 {
return min(f32)
}
@@ -762,14 +740,14 @@ AmplitudeRatioToDecibels :: proc "contextless" (Volume: f32) -> f32 {
}
// Calculate the argument to SetFrequencyRatio from a semitone value
SemitonesToFrequencyRatio :: proc "contextless" (Semitones: f32) -> f32 {
SemitonesToFrequencyRatio :: #force_inline proc "contextless" (Semitones: f32) -> f32 {
// FrequencyRatio = 2 ^ Octaves
// = 2 ^ (Semitones / 12)
return math.pow_f32(2.0, Semitones / 12.0)
}
// Recover a pitch in semitones from a frequency ratio
FrequencyRatioToSemitones :: proc "contextless" (FrequencyRatio: f32) -> f32 {
FrequencyRatioToSemitones :: #force_inline proc "contextless" (FrequencyRatio: f32) -> f32 {
// Semitones = 12 * log2(FrequencyRatio)
// = 12 * log2(10) * log10(FrequencyRatio)
return 12.0 * math.log2_f32(FrequencyRatio)
@@ -779,7 +757,7 @@ FrequencyRatioToSemitones :: proc "contextless" (FrequencyRatio: f32) -> f32 {
// Use CutoffFrequencyToOnePoleCoefficient() for one-pole filter types.
// Note that the highest CutoffFrequency supported is SampleRate/6.
// Higher values of CutoffFrequency will return MAX_FILTER_FREQUENCY.
CutoffFrequencyToRadians :: proc "contextless" (CutoffFrequency: f32, SampleRate: u32) -> f32 {
CutoffFrequencyToRadians :: #force_inline proc "contextless" (CutoffFrequency: f32, SampleRate: u32) -> f32 {
if u32(CutoffFrequency * 6.0) >= SampleRate {
return MAX_FILTER_FREQUENCY
}
@@ -787,14 +765,14 @@ CutoffFrequencyToRadians :: proc "contextless" (CutoffFrequency: f32, SampleRate
}
// Convert from radian frequencies back to absolute frequencies in Hertz
RadiansToCutoffFrequency :: proc "contextless" (Radians: f32, SampleRate: f32) -> f32 {
RadiansToCutoffFrequency :: #force_inline proc "contextless" (Radians: f32, SampleRate: f32) -> f32 {
return SampleRate * math.asin_f32(Radians / 2.0) / math.PI
}
// Convert from filter cutoff frequencies expressed in Hertz to the filter coefficients used with FILTER_PARAMETERS.Frequency,
// LowPassOnePoleFilter and HighPassOnePoleFilter filter types only.
// Use CutoffFrequencyToRadians() for state-variable filter types.
CutoffFrequencyToOnePoleCoefficient :: proc "contextless" (CutoffFrequency: f32, SampleRate: u32) -> f32 {
CutoffFrequencyToOnePoleCoefficient :: #force_inline proc "contextless" (CutoffFrequency: f32, SampleRate: u32) -> f32 {
if u32(CutoffFrequency) >= SampleRate {
return MAX_FILTER_FREQUENCY
}
+7 -8
View File
@@ -10,8 +10,7 @@ foreign import xa2 "system:xaudio2.lib"
*
* Effect creation functions.
*
* On Xbox the application can link with the debug library to use the debug
* functionality.
* On Xbox the application can link with the debug library to use the debug functionality.
*
**************************************************************************/
@@ -32,9 +31,9 @@ foreign xa2 {
// The user is responsible for allocating pPeakLevels, pRMSLevels, and initializing ChannelCount accordingly.
// The volume meter does not support SetEffectParameters().
VOLUMEMETER_LEVELS :: struct #packed {
pPeakLevels: [^]f32 `fmt:"v,ChannelCount"`, // Peak levels table: receives maximum absolute level for each channel over a processing pass, may be NULL if pRMSLevls != NULL, otherwise must have at least ChannelCount elements.
pRMSLevels: [^]f32 `fmt:"v,ChannelCount"`, // Root mean square levels table: receives RMS level for each channel over a processing pass, may be NULL if pPeakLevels != NULL, otherwise must have at least ChannelCount elements.
ChannelCount: u32, // Number of channels being processed by the volume meter APO
pPeakLevels: [^]f32 `fmt:"v,ChannelCount"`, // Peak levels table: receives maximum absolute level for each channel over a processing pass, may be nil if pRMSLevls != nil, otherwise must have at least ChannelCount elements.
pRMSLevels: [^]f32 `fmt:"v,ChannelCount"`, // Root mean square levels table: receives RMS level for each channel over a processing pass, may be nil if pPeakLevels != nil, otherwise must have at least ChannelCount elements.
ChannelCount: u32, // Number of channels being processed by the volume meter APO
}
/**************************************************************************
@@ -87,7 +86,7 @@ REVERB_PARAMETERS :: struct #packed {
Density: f32, // [0, 100] (percentage)
RoomSize: f32, // [1, 100] in feet
// component control
DisableLateField: b32, // TRUE to disable late field reflections
DisableLateField: b32, // true to disable late field reflections
}
// Maximum, minimum and default values for the parameters above
@@ -244,13 +243,13 @@ ReverbConvertI3DL2ToNative :: proc "contextless" (pI3DL2: ^REVERB_I3DL2_PARAMETE
if pI3DL2.DecayHFRatio >= 1.0 {
index := i32(-4.0 * math.log10_f32(pI3DL2.DecayHFRatio))
if index < -8 { index = -8 }
if index < -8 {index = -8}
pNative.LowEQGain = byte((index < 0) ? index + 8 : 8)
pNative.HighEQGain = 8
pNative.DecayTime = pI3DL2.DecayTime * pI3DL2.DecayHFRatio
} else {
index := i32(4.0 * math.log10_f32(pI3DL2.DecayHFRatio))
if index < -8 { index = -8 }
if index < -8 {index = -8}
pNative.LowEQGain = 8
pNative.HighEQGain = byte((index < 0) ? index + 8 : 8)
pNative.DecayTime = pI3DL2.DecayTime