From 8050622fe62522b694f212f06ee902de99c42363 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 28 Nov 2024 20:07:54 +0100 Subject: add `map_entry` procedure --- base/runtime/core_builtin.odin | 26 ++++++++++++++++++++++++++ base/runtime/dynamic_map_internal.odin | 23 +++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index d28dadd02..e7c2c0b1f 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -936,6 +936,32 @@ map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) return } +/* +Retrieves a pointer to the key and value for a possibly just inserted entry into the map. + +If the `key` was not in the map `m`, an entry is inserted with the zero value and `just_inserted` will be `true`. +Otherwise the existing entry is left untouched and pointers to its key and value are returned. + +If the map has to grow in order to insert the entry and the allocation fails, `err` is set and returned. + +If `err` is `nil`, `key_ptr` and `value_ptr` are valid pointers and will not be `nil`. + +WARN: User modification of the key pointed at by `key_ptr` should only be done if the new key is equal to (in hash) the old key. +If that is not the case you will corrupt the map. +*/ +@(builtin, require_results) +map_entry :: proc(m: ^$T/map[$K]$V, key: K, loc := #caller_location) -> (key_ptr: ^K, value_ptr: ^V, just_inserted: bool, err: Allocator_Error) { + key := key + zero: V + + _key_ptr, _value_ptr: rawptr + _key_ptr, _value_ptr, just_inserted, err = __dynamic_map_entry((^Raw_Map)(m), map_info(T), &key, &zero, loc) + + key_ptr = (^K)(_key_ptr) + value_ptr = (^V)(_value_ptr) + return +} + @builtin card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int { diff --git a/base/runtime/dynamic_map_internal.odin b/base/runtime/dynamic_map_internal.odin index 3dded7716..c9d264c6a 100644 --- a/base/runtime/dynamic_map_internal.odin +++ b/base/runtime/dynamic_map_internal.odin @@ -941,6 +941,29 @@ __dynamic_map_set_extra :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^ return nil, rawptr(result) } +__dynamic_map_entry :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key: rawptr, zero: rawptr, loc := #caller_location) -> (key_ptr: rawptr, value_ptr: rawptr, just_inserted: bool, err: Allocator_Error) { + hash := info.key_hasher(key, map_seed(m^)) + + if key_ptr, value_ptr = __dynamic_map_get_key_and_value(m, info, hash, key); value_ptr != nil { + return + } + + has_grown: bool + if err, has_grown = __dynamic_map_check_grow(m, info, loc); err != nil { + return + } else if has_grown { + hash = info.key_hasher(key, map_seed(m^)) + } + + value_ptr = rawptr(map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(zero))) + assert(value_ptr != nil) + key_ptr = rawptr(map_cell_index_dynamic(map_data(m^), info.ks, map_desired_position(m^, hash))) + + m.len += 1 + just_inserted = true + return +} + // IMPORTANT: USED WITHIN THE COMPILER @(private) -- cgit v1.2.3 From b73275cf423186c558e637f629a846eb21c45f24 Mon Sep 17 00:00:00 2001 From: jason Date: Thu, 19 Dec 2024 17:12:07 -0500 Subject: Get arm64 up to speed in os2 linux Readded open flags for arm64 to sys/linux/bits.odin. Make process_start name based instead of descriptor based to allow running of scripts. Fix bug in heap_linux. Fix and simplify os2.remove. --- core/os/os2/file_linux.odin | 22 ++-------- core/os/os2/heap_linux.odin | 2 +- core/os/os2/process_linux.odin | 47 +++++---------------- core/sys/linux/bits.odin | 96 ++++++++++++++++++++++++++---------------- 4 files changed, 74 insertions(+), 93 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index e9ce13447..20f179f77 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -272,28 +272,12 @@ _truncate :: proc(f: ^File, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - is_dir_fd :: proc(fd: linux.Fd) -> bool { - s: linux.Stat - if linux.fstat(fd, &s) != .NONE { - return false - } - return linux.S_ISDIR(s.mode) - } - TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - fd, errno := linux.open(name_cstr, {.NOFOLLOW}) - #partial switch (errno) { - case .ELOOP: - /* symlink */ - case .NONE: - defer linux.close(fd) - if is_dir_fd(fd) { - return _get_platform_error(linux.rmdir(name_cstr)) - } - case: - return _get_platform_error(errno) + if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS); errno == .NONE { + linux.close(fd) + return _get_platform_error(linux.rmdir(name_cstr)) } return _get_platform_error(linux.unlink(name_cstr)) diff --git a/core/os/os2/heap_linux.odin b/core/os/os2/heap_linux.odin index ede5eb2ac..8819dfac7 100644 --- a/core/os/os2/heap_linux.odin +++ b/core/os/os2/heap_linux.odin @@ -415,7 +415,7 @@ _region_resize :: proc(alloc: ^Allocation_Header, new_size: int, alloc_is_free_l back_idx := -1 idx: u16 infinite: for { - for i := 0; i < len(region_iter.hdr.free_list); i += 1 { + for i := 0; i < int(region_iter.hdr.free_list_len); i += 1 { idx = region_iter.hdr.free_list[i] if _get_block_count(region_iter.memory[idx]) >= new_block_count { break infinite diff --git a/core/os/os2/process_linux.odin b/core/os/os2/process_linux.odin index 7eb4dfa44..936fbfc40 100644 --- a/core/os/os2/process_linux.odin +++ b/core/os/os2/process_linux.odin @@ -384,14 +384,6 @@ _Sys_Process_Attributes :: struct {} @(private="package") _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { - has_executable_permissions :: proc(fd: linux.Fd) -> bool { - backing: [48]u8 - b := strings.builder_from_bytes(backing[:]) - strings.write_string(&b, "/proc/self/fd/") - strings.write_int(&b, int(fd)) - return linux.access(strings.to_cstring(&b), linux.X_OK) == .NONE - } - TEMP_ALLOCATOR_GUARD() if len(desc.command) == 0 { @@ -411,7 +403,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { } // search PATH if just a plain name is provided - exe_fd: linux.Fd + exe_path: cstring executable_name := desc.command[0] if strings.index_byte(executable_name, '/') < 0 { path_env := get_env("PATH", temp_allocator()) @@ -426,16 +418,11 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { strings.write_byte(&exe_builder, '/') strings.write_string(&exe_builder, executable_name) - exe_path := strings.to_cstring(&exe_builder) - if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { - continue - } - if !has_executable_permissions(exe_fd) { - linux.close(exe_fd) - continue + exe_path = strings.to_cstring(&exe_builder) + if linux.access(exe_path, linux.X_OK) == .NONE { + found = true + break } - found = true - break } if !found { // check in cwd to match windows behavior @@ -443,29 +430,18 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { strings.write_string(&exe_builder, "./") strings.write_string(&exe_builder, executable_name) - exe_path := strings.to_cstring(&exe_builder) - if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { + exe_path = strings.to_cstring(&exe_builder) + if linux.access(exe_path, linux.X_OK) != .NONE { return process, .Not_Exist } - if !has_executable_permissions(exe_fd) { - linux.close(exe_fd) - return process, .Permission_Denied - } } } else { - exe_path := temp_cstring(executable_name) or_return - if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { - return process, _get_platform_error(errno) - } - if !has_executable_permissions(exe_fd) { - linux.close(exe_fd) - return process, .Permission_Denied + exe_path = temp_cstring(executable_name) or_return + if linux.access(exe_path, linux.X_OK) != .NONE { + return process, .Not_Exist } } - // At this point, we have an executable. - defer linux.close(exe_fd) - // args and environment need to be a list of cstrings // that are terminated by a nil pointer. cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return @@ -492,7 +468,6 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { } defer linux.close(child_pipe_fds[READ]) - // TODO: This is the traditional textbook implementation with fork. // A more efficient implementation with vfork: // @@ -573,7 +548,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno) } - errno = linux.execveat(exe_fd, "", &cargs[0], env, {.AT_EMPTY_PATH}) + errno = linux.execveat(dir_fd, exe_path, &cargs[0], env) assert(errno != nil) write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno) } diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin index 9ce2e206e..c304397de 100644 --- a/core/sys/linux/bits.odin +++ b/core/sys/linux/bits.odin @@ -152,43 +152,65 @@ Errno :: enum i32 { RDONLY flag is not present, because it has the value of 0, i.e. it is the default, unless WRONLY or RDWR is specified. */ -Open_Flags_Bits :: enum { - WRONLY = 0, - RDWR = 1, - CREAT = 6, - EXCL = 7, - NOCTTY = 8, - TRUNC = 9, - APPEND = 10, - NONBLOCK = 11, - DSYNC = 12, - ASYNC = 13, - DIRECT = 14, - LARGEFILE = 15, - DIRECTORY = 16, - NOFOLLOW = 17, - NOATIME = 18, - CLOEXEC = 19, - PATH = 21, -} -// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19 -#assert(1 << uint(Open_Flags_Bits.WRONLY) == 0o0000000_1) -#assert(1 << uint(Open_Flags_Bits.RDWR) == 0o0000000_2) -#assert(1 << uint(Open_Flags_Bits.CREAT) == 0o00000_100) -#assert(1 << uint(Open_Flags_Bits.EXCL) == 0o00000_200) -#assert(1 << uint(Open_Flags_Bits.NOCTTY) == 0o00000_400) -#assert(1 << uint(Open_Flags_Bits.TRUNC) == 0o0000_1000) -#assert(1 << uint(Open_Flags_Bits.APPEND) == 0o0000_2000) -#assert(1 << uint(Open_Flags_Bits.NONBLOCK) == 0o0000_4000) -#assert(1 << uint(Open_Flags_Bits.DSYNC) == 0o000_10000) -#assert(1 << uint(Open_Flags_Bits.ASYNC) == 0o000_20000) -#assert(1 << uint(Open_Flags_Bits.DIRECT) == 0o000_40000) -#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000) -#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000) -#assert(1 << uint(Open_Flags_Bits.NOFOLLOW) == 0o00_400000) -#assert(1 << uint(Open_Flags_Bits.NOATIME) == 0o0_1000000) -#assert(1 << uint(Open_Flags_Bits.CLOEXEC) == 0o0_2000000) -#assert(1 << uint(Open_Flags_Bits.PATH) == 0o_10000000) +when ODIN_ARCH != .arm64 && ODIN_ARCH != .arm32 { + Open_Flags_Bits :: enum { + WRONLY = 0, + RDWR = 1, + CREAT = 6, + EXCL = 7, + NOCTTY = 8, + TRUNC = 9, + APPEND = 10, + NONBLOCK = 11, + DSYNC = 12, + ASYNC = 13, + DIRECT = 14, + LARGEFILE = 15, + DIRECTORY = 16, + NOFOLLOW = 17, + NOATIME = 18, + CLOEXEC = 19, + PATH = 21, + } + // https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19 + #assert(1 << uint(Open_Flags_Bits.WRONLY) == 0o0000000_1) + #assert(1 << uint(Open_Flags_Bits.RDWR) == 0o0000000_2) + #assert(1 << uint(Open_Flags_Bits.CREAT) == 0o00000_100) + #assert(1 << uint(Open_Flags_Bits.EXCL) == 0o00000_200) + #assert(1 << uint(Open_Flags_Bits.NOCTTY) == 0o00000_400) + #assert(1 << uint(Open_Flags_Bits.TRUNC) == 0o0000_1000) + #assert(1 << uint(Open_Flags_Bits.APPEND) == 0o0000_2000) + #assert(1 << uint(Open_Flags_Bits.NONBLOCK) == 0o0000_4000) + #assert(1 << uint(Open_Flags_Bits.DSYNC) == 0o000_10000) + #assert(1 << uint(Open_Flags_Bits.ASYNC) == 0o000_20000) + #assert(1 << uint(Open_Flags_Bits.DIRECT) == 0o000_40000) + #assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000) + #assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000) + #assert(1 << uint(Open_Flags_Bits.NOFOLLOW) == 0o00_400000) + #assert(1 << uint(Open_Flags_Bits.NOATIME) == 0o0_1000000) + #assert(1 << uint(Open_Flags_Bits.CLOEXEC) == 0o0_2000000) + #assert(1 << uint(Open_Flags_Bits.PATH) == 0o_10000000) +} else { + Open_Flags_Bits :: enum { + WRONLY = 0, + RDWR = 1, + CREAT = 6, + EXCL = 7, + NOCTTY = 8, + TRUNC = 9, + APPEND = 10, + NONBLOCK = 11, + DSYNC = 12, + ASYNC = 13, + DIRECTORY = 14, + NOFOLLOW = 15, + DIRECT = 16, + LARGEFILE = 17, + NOATIME = 18, + CLOEXEC = 19, + PATH = 21, + } +} /* Bits for FD_Flags bitset -- cgit v1.2.3 From 5f46b5ca50b48395edf08583278aa4bcd2c54ed9 Mon Sep 17 00:00:00 2001 From: Barinzaya Date: Thu, 19 Dec 2024 17:52:09 -0500 Subject: Fixed zeroing in resize_dynamic_array. When a dynamic array has unused capacity and is resized to a size greater than its capacity, the unused part of its capacity wasn't being zeroed. --- base/runtime/core_builtin.odin | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index d28dadd02..8184c0e74 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -826,10 +826,12 @@ _resize_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, return nil } + if should_zero && a.len < length { + num_reused := min(a.cap, length) - a.len + intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], num_reused*size_of_elem) + } + if length <= a.cap { - if should_zero && a.len < length { - intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], (length-a.len)*size_of_elem) - } a.len = max(length, 0) return nil } -- cgit v1.2.3 From 14216ebf5169581a738e9c235ef8119a95271b12 Mon Sep 17 00:00:00 2001 From: Barinzaya Date: Thu, 19 Dec 2024 20:07:04 -0500 Subject: Added some implicit broadcasting for #simd arrays. This covers broadcasting from untyped numbers when assigning, as well as when performing binary operations. SIMD intrinsics have not been adjusted --- src/check_expr.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cc9483187..81e33a8e8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3672,6 +3672,13 @@ gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x } } } + if (is_type_simd_vector(x->type) && !is_type_simd_vector(y->type)) { + if (check_is_assignable_to(c, y, x->type)) { + if (check_binary_op(c, x, op)) { + return true; + } + } + } return false; } @@ -4556,6 +4563,19 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar break; } + case Type_SimdVector: { + Type *elem = base_array_type(t); + if (check_is_assignable_to(c, operand, elem)) { + operand->mode = Addressing_Value; + } else { + operand->mode = Addressing_Invalid; + convert_untyped_error(c, operand, target_type); + return; + } + + break; + } + case Type_Matrix: { Type *elem = base_array_type(t); if (check_is_assignable_to(c, operand, elem)) { -- cgit v1.2.3 From c06f79bb360bc27353f5139a6c763828b3a16ba2 Mon Sep 17 00:00:00 2001 From: chris-montero Date: Sat, 21 Dec 2024 15:53:55 +0200 Subject: fixed memory leak in core/prof/spall/doc.odin example code --- core/prof/spall/doc.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/prof/spall/doc.odin b/core/prof/spall/doc.odin index c81bad05f..b007ad4cb 100644 --- a/core/prof/spall/doc.odin +++ b/core/prof/spall/doc.odin @@ -18,6 +18,8 @@ Example: defer spall.context_destroy(&spall_ctx) buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE) + defer delete(buffer_backing) + spall_buffer = spall.buffer_create(buffer_backing, u32(sync.current_thread_id())) defer spall.buffer_destroy(&spall_ctx, &spall_buffer) -- cgit v1.2.3 From f2f952b344b076c17281e0e77195a27d94f58919 Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Sun, 22 Dec 2024 01:52:57 +0100 Subject: Fix crash when proc return type is undeclared parapoly variable Disallow the declaration of new parapoly variables in return types, when the procedure's parapoly scope is itself. This happens if e.g.: `foo :: proc() -> $T`. Closes #3949, #4294, #4563 --- src/check_type.cpp | 9 ++++++++- src/checker.hpp | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 13a6125ca..44108ccbe 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2440,8 +2440,12 @@ gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc bool success = true; isize specialization_count = 0; Type *params = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands); - Type *results = check_get_results(c, c->scope, pt->results); + bool no_poly_return = c->disallow_polymorphic_return_types; + c->disallow_polymorphic_return_types = c->scope == c->polymorphic_scope; + // NOTE(zen3ger): if the parapoly scope is the current proc's scope, then the return types shall not declare new poly vars + Type *results = check_get_results(c, c->scope, pt->results); + c->disallow_polymorphic_return_types = no_poly_return; isize param_count = 0; isize result_count = 0; @@ -3383,6 +3387,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T } Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific); if (ctx->allow_polymorphic_types) { + if (ctx->disallow_polymorphic_return_types) { + error(ident, "Undeclared polymorphic parameter '%.*s' in return type", LIT(token.string)); + } Scope *ps = ctx->polymorphic_scope; Scope *s = ctx->scope; Scope *entity_scope = s; diff --git a/src/checker.hpp b/src/checker.hpp index 438156f18..a4cb47521 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -521,6 +521,7 @@ struct CheckerContext { bool in_enum_type; bool collect_delayed_decls; bool allow_polymorphic_types; + bool disallow_polymorphic_return_types; // NOTE(zen3ger): no poly type decl in return types bool no_polymorphic_errors; bool hide_polymorphic_errors; bool in_polymorphic_specialization; -- cgit v1.2.3 From 9f77f7c4175a6202b01a984a692c0288ac6077ec Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Sun, 22 Dec 2024 12:38:37 +0100 Subject: Fix crash on assignment of parapoly proc to variable --- src/check_decl.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 60eb030ff..d541426d3 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -94,12 +94,14 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o return nullptr; } if (e2->state.load() != EntityState_Resolved) { - gbString str = type_to_string(t); - defer (gb_string_free(str)); - error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name)); - e->type = t_invalid; + e->type = t; return nullptr; } + gbString str = type_to_string(t); + defer (gb_string_free(str)); + error(operand->expr, "Invalid use of a non-specialized polymorphic type '%s' in %.*s", str, LIT(context_name)); + e->type = t_invalid; + return nullptr; } else if (is_type_empty_union(t)) { gbString str = type_to_string(t); defer (gb_string_free(str)); -- cgit v1.2.3 From f07a6f463c16c3dc5cdadd6ce4e77a855ac6816d Mon Sep 17 00:00:00 2001 From: blob1807 <12388588+blob1807@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:10:42 +1000 Subject: Fix io.write_escaped_rune not writing full value --- core/io/util.odin | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/io/util.odin b/core/io/util.odin index 296be7bc0..fdbbd5b9f 100644 --- a/core/io/util.odin +++ b/core/io/util.odin @@ -132,9 +132,13 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^ buf: [2]byte s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { - case 0: write_string(w, "00", &n) or_return - case 1: write_byte(w, '0', &n) or_return - case 2: write_string(w, s, &n) or_return + case 0: + write_string(w, "00", &n) or_return + case 1: + write_byte(w, '0', &n) or_return + fallthrough + case 2: + write_string(w, s, &n) or_return } } else { write_rune(w, r, &n) or_return -- cgit v1.2.3 From fdf510b7b35119739d6e41170abd46204356d58b Mon Sep 17 00:00:00 2001 From: misomosi Date: Sat, 21 Dec 2024 19:59:31 -0500 Subject: Pack struct when needed, use field_align metadata --- src/llvm_backend.hpp | 2 ++ src/llvm_backend_general.cpp | 18 +++++++++++++++++- src/llvm_backend_utility.cpp | 19 ++++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e84ffd1cd..3bbd97e4b 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -742,3 +742,5 @@ gb_global char const *llvm_linkage_strings[] = { }; #define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed") +#define ODIN_METADATA_MIN_ALIGN str_lit("odin-min-align") +#define ODIN_METADATA_MAX_ALIGN str_lit("odin-max-align") diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index bab330da7..762256258 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -734,6 +734,17 @@ gb_internal LLVMValueRef OdinLLVMBuildLoad(lbProcedure *p, LLVMTypeRef type, LLV if (is_packed != 0) { LLVMSetAlignment(result, 1); } + u64 align = LLVMGetAlignment(result); + u64 align_min = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MIN_ALIGN); + u64 align_max = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MAX_ALIGN); + if (align_min != 0 && align < align_min) { + align = align_min; + } + if (align_max != 0 && align > align_max) { + align = align_max; + } + GB_ASSERT(align <= UINT_MAX); + LLVMSetAlignment(result, (unsigned int)align); } return result; @@ -2121,6 +2132,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } i64 prev_offset = 0; + bool requires_packing = type->Struct.is_packed; for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) { Entity *field = type->Struct.fields[field_index]; i64 offset = type->Struct.offsets[field_index]; @@ -2141,6 +2153,10 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { field_type = t_rawptr; } + // max_field_align might misalign items in a way that requires packing + // so check the alignment of all fields to see if packing is required. + requires_packing = requires_packing || ((offset % type_align_of(field_type)) != 0); + array_add(&fields, lb_type(m, field_type)); prev_offset = offset + type_size_of(field->type); @@ -2155,7 +2171,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { GB_ASSERT(fields[i] != nullptr); } - LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, type->Struct.is_packed); + LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, requires_packing); map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping); map_set(&m->struct_field_remapping, cast(void *)type, field_remapping); #if 0 diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index a2a0ba4cc..b86d0773b 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1200,9 +1200,22 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { lbValue gep = lb_emit_struct_ep_internal(p, s, index, result_type); Type *bt = base_type(t); - if (bt->kind == Type_Struct && bt->Struct.is_packed) { - lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1); - GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1); + if (bt->kind == Type_Struct) { + if (bt->Struct.is_packed) { + lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1); + GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1); + } + u64 align_max = bt->Struct.custom_max_field_align; + u64 align_min = bt->Struct.custom_min_field_align; + GB_ASSERT(align_min == 0 || align_max == 0 || align_min <= align_max); + if (align_max) { + lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN, align_max); + GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN) == align_max); + } + if (align_min) { + lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN, align_min); + GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN) == align_min); + } } return gep; -- cgit v1.2.3 From 0a2200fa12c2255d03f366fe301228a147ed79e5 Mon Sep 17 00:00:00 2001 From: Joao Fukuda Date: Sun, 22 Dec 2024 15:53:54 -0300 Subject: Fix issue #4612 --- core/sys/linux/types.odin | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 42d5cc988..dc3e4018d 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -684,6 +684,15 @@ Address_Family :: distinct Protocol_Family */ Socket_Msg :: bit_set[Socket_Msg_Bits; i32] + +/* + Struct representing a generic socket address. +*/ +Sock_Addr :: struct #packed { + sa_family: Address_Family, + sa_data: [14]u8, +} + /* Struct representing IPv4 socket address. */ @@ -691,6 +700,7 @@ Sock_Addr_In :: struct #packed { sin_family: Address_Family, sin_port: u16be, sin_addr: [4]u8, + sin_zero: [size_of(Sock_Addr) - size_of(Address_Family) - size_of(u16be) - size_of([4]u8)]u8, } /* @@ -720,6 +730,7 @@ Sock_Addr_Any :: struct #raw_union { family: Address_Family, port: u16be, }, + using generic: Sock_Addr, using ipv4: Sock_Addr_In, using ipv6: Sock_Addr_In6, using uds: Sock_Addr_Un, -- cgit v1.2.3 From 28e226381d3ebe20b70d13c0ea46a7183d59d65e Mon Sep 17 00:00:00 2001 From: Joao Fukuda Date: Sun, 22 Dec 2024 16:09:51 -0300 Subject: Remove extra white space Got in on 0a2200f without me noticing, mb. --- core/sys/linux/types.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index dc3e4018d..08a443bcc 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -684,7 +684,6 @@ Address_Family :: distinct Protocol_Family */ Socket_Msg :: bit_set[Socket_Msg_Bits; i32] - /* Struct representing a generic socket address. */ -- cgit v1.2.3 From 6ff81b6e4c1f9880d92ee5a2ccae241431afb6ee Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Mon, 23 Dec 2024 01:03:51 +0000 Subject: make -export-dependencies:json emit valid json --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4d85a9e72..0450c61ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2120,7 +2120,7 @@ gb_internal void export_dependencies(Checker *c) { for_array(i, files) { AstFile *file = files[i]; gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath)); - if (i+1 == files.count) { + if (i+1 < files.count) { gb_fprintf(&f, ","); } gb_fprintf(&f, "\n"); @@ -2133,7 +2133,7 @@ gb_internal void export_dependencies(Checker *c) { for_array(i, load_files) { LoadFileCache *cache = load_files[i]; gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path)); - if (i+1 == load_files.count) { + if (i+1 < load_files.count) { gb_fprintf(&f, ","); } gb_fprintf(&f, "\n"); -- cgit v1.2.3 From e82a0c8fc7db1f3eaa50e147c1cc0a3d2d482d9a Mon Sep 17 00:00:00 2001 From: "dmitriy.gorevoy" Date: Mon, 23 Dec 2024 09:25:18 +0100 Subject: Fixed crash in arena_free_all() for bootstrapped growing arenas. When trying to set arena.curr_block.used = 0 after mem.zero() caused a crash because if the arena is bootstrapped its memory will be zeroed out after mem.zero() thus making arena.cur_block point to zero. --- core/mem/virtual/arena.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 79407d80d..4a0fff241 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -204,8 +204,9 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { } // Zero the first block's memory if arena.curr_block != nil { - mem.zero(arena.curr_block.base, int(arena.curr_block.used)) + curr_block_used := int(arena.curr_block.used) arena.curr_block.used = 0 + mem.zero(arena.curr_block.base, curr_block_used) } arena.total_used = 0 case .Static, .Buffer: -- cgit v1.2.3 From ad99d20d292ab4708996c935315c36aef58796a8 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 23 Dec 2024 16:33:23 +0100 Subject: Remove outdated PNG save helpers --- core/image/png/helpers.odin | 130 +------------------------------------------- 1 file changed, 1 insertion(+), 129 deletions(-) diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index f094b54a9..a9495ed4d 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -396,132 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) { General helper functions */ -compute_buffer_size :: image.compute_buffer_size - -/* - PNG save helpers -*/ - -when false { - - make_chunk :: proc(c: any, t: Chunk_Type) -> (res: Chunk) { - - data: []u8 - if v, ok := c.([]u8); ok { - data = v - } else { - data = mem.any_to_bytes(c) - } - - res.header.length = u32be(len(data)) - res.header.type = t - res.data = data - - // CRC the type - crc := hash.crc32(mem.any_to_bytes(res.header.type)) - // Extend the CRC with the data - res.crc = u32be(hash.crc32(data, crc)) - return - } - - write_chunk :: proc(fd: os.Handle, chunk: Chunk) { - c := chunk - // Write length + type - os.write_ptr(fd, &c.header, 8) - // Write data - os.write_ptr(fd, mem.raw_data(c.data), int(c.header.length)) - // Write CRC32 - os.write_ptr(fd, &c.crc, 4) - } - - write_image_as_png :: proc(filename: string, image: Image) -> (err: Error) { - profiler.timed_proc() - using image - using os - flags: int = O_WRONLY|O_CREATE|O_TRUNC - - if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) { - return .Invalid_Image_Dimensions - } - - mode: int = 0 - when ODIN_OS == .Linux || ODIN_OS == .Darwin { - // NOTE(justasd): 644 (owner read, write; group read; others read) - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH - } - - fd, fderr := open(filename, flags, mode) - if fderr != nil { - return .Cannot_Open_File - } - defer close(fd) - - magic := Signature - - write_ptr(fd, &magic, 8) - - ihdr := IHDR{ - width = u32be(width), - height = u32be(height), - bit_depth = depth, - compression_method = 0, - filter_method = 0, - interlace_method = .None, - } - - switch channels { - case 1: ihdr.color_type = Color_Type{} - case 2: ihdr.color_type = Color_Type{.Alpha} - case 3: ihdr.color_type = Color_Type{.Color} - case 4: ihdr.color_type = Color_Type{.Color, .Alpha} - case:// Unhandled - return .Unknown_Color_Type - } - h := make_chunk(ihdr, .IHDR) - write_chunk(fd, h) - - bytes_needed := width * height * int(channels) + height - filter_bytes := mem.make_dynamic_array_len_cap([dynamic]u8, bytes_needed, bytes_needed, context.allocator) - defer delete(filter_bytes) - - i := 0; j := 0 - // Add a filter byte 0 per pixel row - for y := 0; y < height; y += 1 { - filter_bytes[j] = 0; j += 1 - for x := 0; x < width; x += 1 { - for z := 0; z < channels; z += 1 { - filter_bytes[j+z] = image.pixels[i+z] - } - i += channels; j += channels - } - } - assert(j == bytes_needed) - - a: []u8 = filter_bytes[:] - - out_buf: ^[dynamic]u8 - defer free(out_buf) - - ctx := zlib.ZLIB_Context{ - in_buf = &a, - out_buf = out_buf, - } - err = zlib.write_zlib_stream_from_memory(&ctx) - - b: []u8 - if err == nil { - b = ctx.out_buf[:] - } else { - return err - } - - idat := make_chunk(b, .IDAT) - - write_chunk(fd, idat) - - iend := make_chunk([]u8{}, .IEND) - write_chunk(fd, iend) - - return nil - } -} +compute_buffer_size :: image.compute_buffer_size \ No newline at end of file -- cgit v1.2.3 From 8c761627c84847bae3ec5e77a1408c542d9460b7 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 24 Dec 2024 02:17:57 +0100 Subject: encoding/base32: Replace assertions with error returns Replace assertions with proper error handling in base32.decode() to allow programs to handle invalid input gracefully rather than crashing. The function now returns ([]byte, Error) instead of just []byte. --- core/encoding/base32/base32.odin | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index f3320428d..688b27544 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -7,6 +7,15 @@ package encoding_base32 // Incase your specific version does not use padding, you may // truncate it from the encoded output. +// Error represents errors that can occur during base32 decoding operations. +// See RFC 4648 sections 3.2, 4 and 6. +Error :: enum { + None, + Invalid_Character, // Input contains characters outside of base32 alphabet (A-Z, 2-7) + Invalid_Length, // Input length is not valid for base32 (must be a multiple of 8 with proper padding) + Malformed_Input, // Input has improper structure (wrong padding position or incomplete groups) +} + ENC_TABLE := [32]byte { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -91,9 +100,9 @@ _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.al } } -decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{ +decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> ([]byte, Error) #no_bounds_check { if len(data) == 0 { - return nil + return nil, .None } outi := 0 @@ -113,16 +122,29 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato input := data[0] data = data[1:] if input == byte(PADDING) && j >= 2 && len(data) < 8 { - assert(!(len(data) + j < 8 - 1), "Corrupted input") - for k := 0; k < 8-1-j; k +=1 { - assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input") + // assert(!(len(data) + j < 8 - 1), "Corrupted input") + if len(data) + j < 8 - 1 { + return nil, .Malformed_Input + } + // assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input") + for k := 0; k < 8-1-j; k += 1 { + if len(data) < k || data[k] != byte(PADDING) { + return nil, .Malformed_Input + } } dlen, end = j, true - assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input") + // assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input") + if dlen == 1 || dlen == 3 || dlen == 6 { + return nil, .Invalid_Length + } break } - dbuf[j] = DEC_TABLE[input] - assert(dbuf[j] != 0xff, "Corrupted input") + decoded := DEC_TBL[input] + // assert(dbuf[j] != 0xff, "Corrupted input") + if decoded == 0 && input != byte(ENC_TABLE[0]) { + return nil, .Invalid_Character + } + dbuf[j] = decoded j += 1 } @@ -144,5 +166,5 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato } outi += 5 } - return out + return out, .None } -- cgit v1.2.3 From b9338777e34006b40b9315e795232e0608caa499 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 24 Dec 2024 02:20:32 +0100 Subject: encoding/base32: Fix buffer allocation and bounds checking Fix buffer allocation size calculation and add proper bounds checking to ensure output buffer has sufficient space. This fixes crashes that could occur with inputs like "AA" and other edge cases where the output buffer was too small. Remove #no_bounds_check as proper bounds checking is necessary for safe error handling. The small performance trade-off is worth the improved robustness. --- core/encoding/base32/base32.odin | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 688b27544..8e3499dce 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -100,15 +100,18 @@ _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.al } } -decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> ([]byte, Error) #no_bounds_check { +decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> ([]byte, Error) { if len(data) == 0 { return nil, .None } + // Calculate maximum possible output size and allocate buffer + out_len := (len(data) * 5 + 7) / 8 // Ceiling division to ensure enough space + out := make([]byte, out_len, allocator) + outi := 0 data := data - out := make([]byte, len(data) / 8 * 5, allocator) end := false for len(data) > 0 && !end { dbuf : [8]byte @@ -122,25 +125,22 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato input := data[0] data = data[1:] if input == byte(PADDING) && j >= 2 && len(data) < 8 { - // assert(!(len(data) + j < 8 - 1), "Corrupted input") if len(data) + j < 8 - 1 { return nil, .Malformed_Input } - // assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input") for k := 0; k < 8-1-j; k += 1 { if len(data) < k || data[k] != byte(PADDING) { return nil, .Malformed_Input } } dlen, end = j, true - // assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input") if dlen == 1 || dlen == 3 || dlen == 6 { return nil, .Invalid_Length } break } + decoded := DEC_TBL[input] - // assert(dbuf[j] != 0xff, "Corrupted input") if decoded == 0 && input != byte(ENC_TABLE[0]) { return nil, .Invalid_Character } @@ -148,23 +148,41 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato j += 1 } + // Ensure we have enough space in output buffer + needed := 5 // Each full 8-char block produces 5 bytes + if outi + needed > len(out) { + return nil, .Invalid_Length + } + + // Process complete input blocks switch dlen { case 8: + if len(dbuf) < 8 { return nil, .Invalid_Length } out[outi + 4] = dbuf[6] << 5 | dbuf[7] fallthrough case 7: + if len(dbuf) < 7 { return nil, .Invalid_Length } out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3 fallthrough case 5: + if len(dbuf) < 5 { return nil, .Invalid_Length } out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1 fallthrough case 4: + if len(dbuf) < 4 { return nil, .Invalid_Length } out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4 fallthrough case 2: + if len(dbuf) < 2 { return nil, .Invalid_Length } out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2 } outi += 5 } + + // Trim output buffer to actual size + if outi < len(out) { + out = out[:outi] + } + return out, .None } -- cgit v1.2.3 From 7672ac945a7b8e35b600a9d2a2421caf16a5a364 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 24 Dec 2024 15:28:34 +0100 Subject: encoding/base32: Add RFC 4648 test suite Add test suite based on RFC 4648 test vectors and validation rules: - Add section 10 test vectors for valid encoding/decoding - Add test cases for invalid character handling (section 3.2) - Add test cases for padding validation (section 4) - Add test cases for length requirements (section 6) The test vectors verify that: - Empty string encodes/decodes correctly - Standard cases like "foo" -> "MZXW6===" work - Invalid characters are rejected - Missing or malformed padding is detected - Invalid lengths are caught --- core/encoding/base32/base32.odin | 104 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 8e3499dce..54737c9ce 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -1,5 +1,8 @@ package encoding_base32 +import "core:testing" +import "core:bytes" + // @note(zh): Encoding utility for Base32 // A secondary param can be used to supply a custom alphabet to // @link(encode) and a matching decoding table to @link(decode). @@ -186,3 +189,104 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato return out, .None } + +@(test) +test_base32_decode_valid :: proc(t: ^testing.T) { + // RFC 4648 Section 10 - Test vectors + cases := [?]struct { + input, expected: string, + }{ + {"", ""}, + {"MY======", "f"}, + {"MZXQ====", "fo"}, + {"MZXW6===", "foo"}, + {"MZXW6YQ=", "foob"}, + {"MZXW6YTB", "fooba"}, + {"MZXW6YTBOI======", "foobar"}, + } + + + for c in cases { + output, err := decode(c.input) + testing.expect_value(t, err, Error.None) + expected := transmute([]u8)c.expected + + if output != nil { + testing.expect(t, bytes.equal(output, expected)) + } else { + testing.expect(t, len(c.expected) == 0) + } + } +} + +@(test) +test_base32_encode :: proc(t: ^testing.T) { + // RFC 4648 Section 10 - Test vectors + cases := [?]struct { + input, expected: string, + }{ + {"", ""}, + {"f", "MY======"}, + {"fo", "MZXQ===="}, + {"foo", "MZXW6==="}, + {"foob", "MZXW6YQ="}, + {"fooba", "MZXW6YTB"}, + {"foobar", "MZXW6YTBOI======"}, + } + + for c in cases { + output := encode(transmute([]byte)c.input) + testing.expect(t, output == c.expected) + } +} + +@(test) +test_base32_decode_invalid :: proc(t: ^testing.T) { + // Section 3.2 - Alphabet check + { + // Characters outside alphabet + input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7) + _, err := decode(input) + testing.expect_value(t, err, Error.Invalid_Character) + } + { + // Lowercase not allowed + input := "mzxq====" + _, err := decode(input) + testing.expect_value(t, err, Error.Invalid_Character) + } + + // Section 4 - Padding requirements + { + // Padding must only be at end + input := "MZ=Q====" + _, err := decode(input) + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Missing padding + input := "MZXQ" // Should be MZXQ==== + _, err := decode(input) + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Incorrect padding length + input := "MZXQ=" // Needs 4 padding chars + _, err := decode(input) + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Too much padding + input := "MY=========" // Extra padding chars + _, err := decode(input) + testing.expect_value(t, err, Error.Malformed_Input) + } + + // Section 6 - Block size requirements + { + // Single character (invalid block) + input := "M" + _, err := decode(input) + testing.expect_value(t, err, Error.Invalid_Length) + } +} -- cgit v1.2.3 From f1f2ed31940d02728ce55e591743834968dd5994 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 24 Dec 2024 15:52:33 +0100 Subject: encoding/base32: Fix decode implementation per RFC 4648 Rework base32.decode() to properly handle all cases per RFC 4648: - Fix error detection order: - Check minimum length first (Invalid_Length) - Check character validity (Invalid_Character) - Check padding and structure (Malformed_Input) - Fix padding validation: - Add required padding length checks (2=6, 4=4, 5=3, 7=1 chars) - Ensure padding only appears at end - Fix handling of unpadded inputs - Fix buffer handling: - Proper output buffer size calculation - Add bounds checking for buffer access - Add proper buffer validation For example: - "M" correctly returns Invalid_Length (too short) - "mzxq====" correctly returns Invalid_Character (lowercase) - "MZXQ=" correctly returns Malformed_Input (wrong padding) - Unpadded input lengths must be multiples of 8 These changes make the decode function fully compliant with RFC 4648 requirements while providing proper error handling. --- core/encoding/base32/base32.odin | 137 ++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 58 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 54737c9ce..d940c856b 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -103,88 +103,109 @@ _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.al } } -decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> ([]byte, Error) { +decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> (out: []byte, err: Error) { if len(data) == 0 { return nil, .None } - // Calculate maximum possible output size and allocate buffer - out_len := (len(data) * 5 + 7) / 8 // Ceiling division to ensure enough space - out := make([]byte, out_len, allocator) + // Check minimum length requirement first + if len(data) < 2 { + return nil, .Invalid_Length + } - outi := 0 - data := data + // Validate characters - only A-Z and 2-7 allowed before padding + for i := 0; i < len(data); i += 1 { + c := data[i] + if c == byte(PADDING) { + break + } + if !((c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7')) { + return nil, .Invalid_Character + } + } - end := false - for len(data) > 0 && !end { - dbuf : [8]byte - dlen := 8 + // Validate padding and length + data_len := len(data) + padding_count := 0 + for i := data_len - 1; i >= 0; i -= 1 { + if data[i] != byte(PADDING) { + break + } + padding_count += 1 + } - for j := 0; j < 8; { - if len(data) == 0 { - dlen, end = j, true - break - } - input := data[0] - data = data[1:] - if input == byte(PADDING) && j >= 2 && len(data) < 8 { - if len(data) + j < 8 - 1 { - return nil, .Malformed_Input - } - for k := 0; k < 8-1-j; k += 1 { - if len(data) < k || data[k] != byte(PADDING) { - return nil, .Malformed_Input - } - } - dlen, end = j, true - if dlen == 1 || dlen == 3 || dlen == 6 { - return nil, .Invalid_Length - } - break + // Check for proper padding and length combinations + if padding_count > 0 { + // Verify no padding in the middle + for i := 0; i < data_len - padding_count; i += 1 { + if data[i] == byte(PADDING) { + return nil, .Malformed_Input } + } - decoded := DEC_TBL[input] - if decoded == 0 && input != byte(ENC_TABLE[0]) { - return nil, .Invalid_Character + // Required padding for each content length mod 8 + content_len := data_len - padding_count + required_padding := map[int]int{ + 2 = 6, // 2 chars need 6 padding chars + 4 = 4, // 4 chars need 4 padding chars + 5 = 3, // 5 chars need 3 padding chars + 7 = 1, // 7 chars need 1 padding char + } + + mod8 := content_len % 8 + if req_pad, ok := required_padding[mod8]; ok { + if padding_count != req_pad { + return nil, .Malformed_Input } - dbuf[j] = decoded - j += 1 + } else if mod8 != 0 { + // If not in the map and not a multiple of 8, it's invalid + return nil, .Malformed_Input + } + } else { + // No padding - must be multiple of 8 + if data_len % 8 != 0 { + return nil, .Malformed_Input } + } - // Ensure we have enough space in output buffer - needed := 5 // Each full 8-char block produces 5 bytes - if outi + needed > len(out) { - return nil, .Invalid_Length + // Calculate decoded length: 5 bytes for every 8 input chars + input_chars := data_len - padding_count + out_len := input_chars * 5 / 8 + out = make([]byte, out_len, allocator) + defer if err != .None { + delete(out) + } + + // Process input in 8-byte blocks + outi := 0 + for i := 0; i < input_chars; i += 8 { + buf: [8]byte + block_size := min(8, input_chars - i) + + // Decode block + for j := 0; j < block_size; j += 1 { + buf[j] = DEC_TBL[data[i + j]] } - // Process complete input blocks - switch dlen { + // Convert to output bytes based on block size + bytes_to_write := block_size * 5 / 8 + switch block_size { case 8: - if len(dbuf) < 8 { return nil, .Invalid_Length } - out[outi + 4] = dbuf[6] << 5 | dbuf[7] + out[outi + 4] = (buf[6] << 5) | buf[7] fallthrough case 7: - if len(dbuf) < 7 { return nil, .Invalid_Length } - out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3 + out[outi + 3] = (buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3) fallthrough case 5: - if len(dbuf) < 5 { return nil, .Invalid_Length } - out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1 + out[outi + 2] = (buf[3] << 4) | (buf[4] >> 1) fallthrough case 4: - if len(dbuf) < 4 { return nil, .Invalid_Length } - out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4 + out[outi + 1] = (buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4) fallthrough case 2: - if len(dbuf) < 2 { return nil, .Invalid_Length } - out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2 + out[outi] = (buf[0] << 3) | (buf[1] >> 2) } - outi += 5 - } - - // Trim output buffer to actual size - if outi < len(out) { - out = out[:outi] + outi += bytes_to_write } return out, .None -- cgit v1.2.3 From 93238db202c6648d11d4a78a83b1a29751ac77a3 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 24 Dec 2024 16:00:00 +0100 Subject: encoding/base32: Use consistent allocator and add proper cleanup Fix memory handling throughout base32 package: - Make padding map package-level constant (to avoid repeated allocs) - Use passed allocator in encode's make() call - Add defer delete for allocated memory in encode - Add proper cleanup in test cases - Fix memory cleanup of output buffers The changes ensure consistent allocator usage and cleanup in both implementation and tests. --- core/encoding/base32/base32.odin | 65 ++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index d940c856b..72e20e427 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -45,11 +45,19 @@ DEC_TABLE := [?]u8 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } +REQUIRED_PADDING := map[int]int{ + 2 = 6, // 2 chars need 6 padding chars + 4 = 4, // 4 chars need 4 padding chars + 5 = 3, // 5 chars need 3 padding chars + 7 = 1, // 7 chars need 1 padding char +} + encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { out_length := (len(data) + 4) / 5 * 8 - out := make([]byte, out_length) + out := make([]byte, out_length, allocator) + defer delete(out) _encode(out, data) - return string(out) + return string(out[:]) } @private @@ -143,22 +151,13 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato } } - // Required padding for each content length mod 8 content_len := data_len - padding_count - required_padding := map[int]int{ - 2 = 6, // 2 chars need 6 padding chars - 4 = 4, // 4 chars need 4 padding chars - 5 = 3, // 5 chars need 3 padding chars - 7 = 1, // 7 chars need 1 padding char - } - mod8 := content_len % 8 - if req_pad, ok := required_padding[mod8]; ok { + if req_pad, ok := REQUIRED_PADDING[mod8]; ok { if padding_count != req_pad { return nil, .Malformed_Input } } else if mod8 != 0 { - // If not in the map and not a multiple of 8, it's invalid return nil, .Malformed_Input } } else { @@ -208,7 +207,7 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato outi += bytes_to_write } - return out, .None + return } @(test) @@ -226,12 +225,13 @@ test_base32_decode_valid :: proc(t: ^testing.T) { {"MZXW6YTBOI======", "foobar"}, } - for c in cases { output, err := decode(c.input) + if output != nil { + defer delete(output) + } testing.expect_value(t, err, Error.None) expected := transmute([]u8)c.expected - if output != nil { testing.expect(t, bytes.equal(output, expected)) } else { @@ -267,13 +267,19 @@ test_base32_decode_invalid :: proc(t: ^testing.T) { { // Characters outside alphabet input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7) - _, err := decode(input) + output, err := decode(input) + if output != nil { + defer delete(output) + } testing.expect_value(t, err, Error.Invalid_Character) } { // Lowercase not allowed input := "mzxq====" - _, err := decode(input) + output, err := decode(input) + if output != nil { + defer delete(output) + } testing.expect_value(t, err, Error.Invalid_Character) } @@ -281,25 +287,37 @@ test_base32_decode_invalid :: proc(t: ^testing.T) { { // Padding must only be at end input := "MZ=Q====" - _, err := decode(input) + output, err := decode(input) + if output != nil { + defer delete(output) + } testing.expect_value(t, err, Error.Malformed_Input) } { // Missing padding input := "MZXQ" // Should be MZXQ==== - _, err := decode(input) + output, err := decode(input) + if output != nil { + defer delete(output) + } testing.expect_value(t, err, Error.Malformed_Input) } { // Incorrect padding length input := "MZXQ=" // Needs 4 padding chars - _, err := decode(input) + output, err := decode(input) + if output != nil { + defer delete(output) + } testing.expect_value(t, err, Error.Malformed_Input) } { // Too much padding input := "MY=========" // Extra padding chars - _, err := decode(input) + output, err := decode(input) + if output != nil { + defer delete(output) + } testing.expect_value(t, err, Error.Malformed_Input) } @@ -307,7 +325,10 @@ test_base32_decode_invalid :: proc(t: ^testing.T) { { // Single character (invalid block) input := "M" - _, err := decode(input) + output, err := decode(input) + if output != nil { + defer delete(output) + } testing.expect_value(t, err, Error.Invalid_Length) } } -- cgit v1.2.3 From e75a49f095ed7ecd72b4caccf550545a980163ab Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 24 Dec 2024 16:07:01 +0100 Subject: encoding/base32: Set optimization mode for decode() --- core/encoding/base32/base32.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 72e20e427..53d31fb30 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -111,6 +111,7 @@ _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.al } } +@(optimization_mode="favor_size") decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> (out: []byte, err: Error) { if len(data) == 0 { return nil, .None -- cgit v1.2.3 From 3a5440e4eddea3735b26689e576ba4e1102a6a3a Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Mon, 23 Dec 2024 14:15:59 +0900 Subject: base/runtime: Add `ensure` and `ensure_contextless` This provides an equivalent to `assert` and `assert_contextless` that are always evaluated, ignoring `ODIN_DISABLE_ASSERT`, which is useful for enforcing API contracts or "asserting" on conditionals with side-effects. --- base/runtime/core_builtin.odin | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index d28dadd02..f06dcb478 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -964,6 +964,24 @@ assert :: proc(condition: bool, message := #caller_expression(condition), loc := } } +// Evaluates the condition and aborts the program iff the condition is +// false. This routine ignores `ODIN_DISABLE_ASSERT`, and will always +// execute. +@builtin +ensure :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) { + if !condition { + @(cold) + internal :: proc(message: string, loc: Source_Code_Location) { + p := context.assertion_failure_proc + if p == nil { + p = default_assertion_failure_proc + } + p("unsatisfied ensure", message, loc) + } + internal(message, loc) + } +} + @builtin panic :: proc(message: string, loc := #caller_location) -> ! { p := context.assertion_failure_proc @@ -999,6 +1017,17 @@ assert_contextless :: proc "contextless" (condition: bool, message := #caller_ex } } +@builtin +ensure_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) { + if !condition { + @(cold) + internal :: proc "contextless" (message: string, loc: Source_Code_Location) { + default_assertion_contextless_failure_proc("unsatisfied ensure", message, loc) + } + internal(message, loc) + } +} + @builtin panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! { default_assertion_contextless_failure_proc("panic", message, loc) -- cgit v1.2.3 From 8211a911dbf75b683da4f5c1c3f2970d56103497 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 24 Dec 2024 20:46:38 +0100 Subject: encoding/base32: Replace padding map with switch statement Replace package-level map with a simple switch statement for padding validation. This eliminates allocations we can't properly free while maintaining the same validation logic. --- core/encoding/base32/base32.odin | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 53d31fb30..68b8b7a5e 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -45,13 +45,6 @@ DEC_TABLE := [?]u8 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } -REQUIRED_PADDING := map[int]int{ - 2 = 6, // 2 chars need 6 padding chars - 4 = 4, // 4 chars need 4 padding chars - 5 = 3, // 5 chars need 3 padding chars - 7 = 1, // 7 chars need 1 padding char -} - encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { out_length := (len(data) + 4) / 5 * 8 out := make([]byte, out_length, allocator) @@ -154,8 +147,17 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato content_len := data_len - padding_count mod8 := content_len % 8 - if req_pad, ok := REQUIRED_PADDING[mod8]; ok { - if padding_count != req_pad { + required_padding: int + switch mod8 { + case 2: required_padding = 6 // 2 chars need 6 padding chars + case 4: required_padding = 4 // 4 chars need 4 padding chars + case 5: required_padding = 3 // 5 chars need 3 padding chars + case 7: required_padding = 1 // 7 chars need 1 padding char + case: required_padding = 0 + } + + if required_padding > 0 { + if padding_count != required_padding { return nil, .Malformed_Input } } else if mod8 != 0 { -- cgit v1.2.3 From e7fb02a84a24f5430199249934a3dc37b10a4d39 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Wed, 25 Dec 2024 16:15:41 +0100 Subject: encoding/base32: Add custom validation support Add support for custom alphabet validation through an optional validation function parameter. The default validation follows RFC 4648 base32 alphabet rules (A-Z, 2-7). This properly supports the documented ability to use custom alphabets. --- core/encoding/base32/base32.odin | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 68b8b7a5e..7c70b7e9a 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -7,18 +7,25 @@ import "core:bytes" // A secondary param can be used to supply a custom alphabet to // @link(encode) and a matching decoding table to @link(decode). // If none is supplied it just uses the standard Base32 alphabet. -// Incase your specific version does not use padding, you may +// In case your specific version does not use padding, you may // truncate it from the encoded output. // Error represents errors that can occur during base32 decoding operations. // See RFC 4648 sections 3.2, 4 and 6. Error :: enum { None, - Invalid_Character, // Input contains characters outside of base32 alphabet (A-Z, 2-7) + Invalid_Character, // Input contains characters outside the specified alphabet Invalid_Length, // Input length is not valid for base32 (must be a multiple of 8 with proper padding) Malformed_Input, // Input has improper structure (wrong padding position or incomplete groups) } +Validate_Proc :: #type proc(c: byte) -> bool + +@private +_validate_default :: proc(c: byte) -> bool { + return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7') +} + ENC_TABLE := [32]byte { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -105,7 +112,11 @@ _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.al } @(optimization_mode="favor_size") -decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> (out: []byte, err: Error) { +decode :: proc( + data: string, + DEC_TBL := DEC_TABLE, + validate: Validate_Proc = _validate_default, + allocator := context.allocator) -> (out: []byte, err: Error) { if len(data) == 0 { return nil, .None } @@ -115,13 +126,13 @@ decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocato return nil, .Invalid_Length } - // Validate characters - only A-Z and 2-7 allowed before padding + // Validate characters using provided validation function for i := 0; i < len(data); i += 1 { c := data[i] if c == byte(PADDING) { break } - if !((c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7')) { + if !validate(c) { return nil, .Invalid_Character } } -- cgit v1.2.3 From 88c0e62095730354d139af3b90b7d91fa19f5e1a Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Thu, 26 Dec 2024 14:48:02 +0100 Subject: encoding/base32: Use `ENC_TBL` parameter consistently in encode() Fix encoding to properly use provided encoding table parameter instead of hardcoded `ENC_TABLE`. This makes encode properly support custom alphabets as documented. --- core/encoding/base32/base32.odin | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 7c70b7e9a..ea529ed63 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -56,7 +56,7 @@ encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocato out_length := (len(data) + 4) / 5 * 8 out := make([]byte, out_length, allocator) defer delete(out) - _encode(out, data) + _encode(out, data, ENC_TBL) return string(out[:]) } @@ -69,26 +69,26 @@ _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.al carry: byte switch len(data) { case: - out[7] = ENC_TABLE[data[4] & 0x1f] + out[7] = ENC_TBL[data[4] & 0x1f] carry = data[4] >> 5 fallthrough case 4: - out[6] = ENC_TABLE[carry | (data[3] << 3) & 0x1f] - out[5] = ENC_TABLE[(data[3] >> 2) & 0x1f] + out[6] = ENC_TBL[carry | (data[3] << 3) & 0x1f] + out[5] = ENC_TBL[(data[3] >> 2) & 0x1f] carry = data[3] >> 7 fallthrough case 3: - out[4] = ENC_TABLE[carry | (data[2] << 1) & 0x1f] + out[4] = ENC_TBL[carry | (data[2] << 1) & 0x1f] carry = (data[2] >> 4) & 0x1f fallthrough case 2: - out[3] = ENC_TABLE[carry | (data[1] << 4) & 0x1f] - out[2] = ENC_TABLE[(data[1] >> 1) & 0x1f] + out[3] = ENC_TBL[carry | (data[1] << 4) & 0x1f] + out[2] = ENC_TBL[(data[1] >> 1) & 0x1f] carry = (data[1] >> 6) & 0x1f fallthrough case 1: - out[1] = ENC_TABLE[carry | (data[0] << 2) & 0x1f] - out[0] = ENC_TABLE[data[0] >> 3] + out[1] = ENC_TBL[carry | (data[0] << 2) & 0x1f] + out[0] = ENC_TBL[data[0] >> 3] } if len(data) < 5 { -- cgit v1.2.3 From 490f52700533bdda725fd90fc19cb248d38b2ff5 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Thu, 26 Dec 2024 19:20:46 +0100 Subject: encoding/base32: Expand `DEC_TABLE` to full 256 bytes The decoding table was only 224 bytes which caused type mismatches when using custom alphabets, so expand with zeroes to cover full byte range while maintaining the same decoding logic. --- core/encoding/base32/base32.odin | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index ea529ed63..12b6a426b 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -35,21 +35,23 @@ ENC_TABLE := [32]byte { PADDING :: '=' -DEC_TABLE := [?]u8 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, +DEC_TABLE := [256]u8 { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { -- cgit v1.2.3 From 8a91e0bb19c013d0b088c90f3d1a09560dffac5c Mon Sep 17 00:00:00 2001 From: Sebastian Pahnke Date: Sat, 28 Dec 2024 08:51:54 +0100 Subject: Add regression tests reproducing the issue --- tests/issues/run.bat | 1 + tests/issues/run.sh | 1 + tests/issues/test_issue_4584.odin | 56 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 tests/issues/test_issue_4584.odin diff --git a/tests/issues/run.bat b/tests/issues/run.bat index dcea3d483..7ed43205d 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -16,6 +16,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style ..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index c3bc00e24..54543980e 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -17,6 +17,7 @@ $ODIN test ../test_issue_2615.odin $COMMON $ODIN test ../test_issue_2637.odin $COMMON $ODIN test ../test_issue_2666.odin $COMMON $ODIN test ../test_issue_4210.odin $COMMON +$ODIN test ../test_issue_4584.odin $COMMON if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then echo "SUCCESSFUL 1/1" else diff --git a/tests/issues/test_issue_4584.odin b/tests/issues/test_issue_4584.odin new file mode 100644 index 000000000..b80ecb3d9 --- /dev/null +++ b/tests/issues/test_issue_4584.odin @@ -0,0 +1,56 @@ +// Tests issue #4584 https://github.com/odin-lang/Odin/issues/4584 +package test_issues + +import "core:testing" +import "core:math/linalg" + +@test +test_adjugate_2x2 :: proc(t: ^testing.T) { + m := matrix[2,2]int { + -3, 2, + -1, 0, + } + expected := matrix[2,2]int { + 0, -2, + 1, -3, + } + testing.expect_value(t, linalg.adjugate(m), expected) + testing.expect_value(t, linalg.determinant(m), 2) + testing.expect_value(t, linalg.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) +} + +@test +test_adjugate_3x3 :: proc(t: ^testing.T) { + m := matrix[3,3]int { + -3, 2, -5, + -1, 0, -2, + 3, -4, 1, + } + expected := matrix[3,3]int { + -8, 18, -4, + -5, 12, -1, + 4, -6, 2, + } + testing.expect_value(t, linalg.adjugate(m), expected) + testing.expect_value(t, linalg.determinant(m), -6) + testing.expect_value(t, linalg.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) +} + +@test +test_adjugate_4x4 :: proc(t: ^testing.T) { + m := matrix[4,4]int { + -3, 2, -5, 1, + -1, 0, -2, 2, + 3, -4, 1, 3, + 4, 5, 6, 7, + } + expected := matrix[4,4]int { + -144, 266, -92, -16, + 57, 92, -5, -16, + 105, -142, 55, 2, + 33, -96, 9, -6, + } + testing.expect_value(t, linalg.adjugate(m), expected) + testing.expect_value(t, linalg.determinant(m), -174) + testing.expect_value(t, linalg.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) +} \ No newline at end of file -- cgit v1.2.3 From e8a202f0a27256162f8fe20f4d92cdb63ec1e967 Mon Sep 17 00:00:00 2001 From: Sebastian Pahnke Date: Sat, 28 Dec 2024 08:56:09 +0100 Subject: Add tests for glsl and hlsl variants --- tests/issues/test_issue_4584.odin | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/issues/test_issue_4584.odin b/tests/issues/test_issue_4584.odin index b80ecb3d9..176daf6af 100644 --- a/tests/issues/test_issue_4584.odin +++ b/tests/issues/test_issue_4584.odin @@ -3,6 +3,8 @@ package test_issues import "core:testing" import "core:math/linalg" +import glm "core:math/linalg/glsl" +import hlm "core:math/linalg/hlsl" @test test_adjugate_2x2 :: proc(t: ^testing.T) { @@ -17,6 +19,12 @@ test_adjugate_2x2 :: proc(t: ^testing.T) { testing.expect_value(t, linalg.adjugate(m), expected) testing.expect_value(t, linalg.determinant(m), 2) testing.expect_value(t, linalg.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) + + testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) + + testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) } @test @@ -34,6 +42,12 @@ test_adjugate_3x3 :: proc(t: ^testing.T) { testing.expect_value(t, linalg.adjugate(m), expected) testing.expect_value(t, linalg.determinant(m), -6) testing.expect_value(t, linalg.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) + + testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) + + testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) } @test @@ -53,4 +67,10 @@ test_adjugate_4x4 :: proc(t: ^testing.T) { testing.expect_value(t, linalg.adjugate(m), expected) testing.expect_value(t, linalg.determinant(m), -174) testing.expect_value(t, linalg.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) + + testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) + + testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) } \ No newline at end of file -- cgit v1.2.3 From 0d955e55dbe9aaefebddde222d8bd62c59236eae Mon Sep 17 00:00:00 2001 From: Sebastian Pahnke Date: Sat, 28 Dec 2024 09:05:26 +0100 Subject: Add tests for determinants because their calculation depends on the adjugate --- tests/issues/test_issue_4584.odin | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/issues/test_issue_4584.odin b/tests/issues/test_issue_4584.odin index 176daf6af..f14f1f1d3 100644 --- a/tests/issues/test_issue_4584.odin +++ b/tests/issues/test_issue_4584.odin @@ -21,9 +21,11 @@ test_adjugate_2x2 :: proc(t: ^testing.T) { testing.expect_value(t, linalg.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.determinant(m), 2) testing.expect_value(t, glm.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.determinant(m), 2) testing.expect_value(t, hlm.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) } @@ -44,9 +46,11 @@ test_adjugate_3x3 :: proc(t: ^testing.T) { testing.expect_value(t, linalg.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.determinant(m), -6) testing.expect_value(t, glm.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.determinant(m), -6) testing.expect_value(t, hlm.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) } @@ -60,7 +64,7 @@ test_adjugate_4x4 :: proc(t: ^testing.T) { } expected := matrix[4,4]int { -144, 266, -92, -16, - 57, 92, -5, -16, + -57, 92, -5, -16, 105, -142, 55, 2, 33, -96, 9, -6, } @@ -69,8 +73,10 @@ test_adjugate_4x4 :: proc(t: ^testing.T) { testing.expect_value(t, linalg.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.determinant(m), -174) testing.expect_value(t, glm.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.determinant(m), -174) testing.expect_value(t, hlm.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) } \ No newline at end of file -- cgit v1.2.3 From f23e226854c6777a27f13f70759fb022acafd532 Mon Sep 17 00:00:00 2001 From: Sebastian Pahnke Date: Sat, 28 Dec 2024 09:23:43 +0100 Subject: Rename adjugate to cofactor to keep existing usages for inverse and determinant correct and add new adjugate procedures --- core/math/linalg/general.odin | 84 ++++++++++++++++++++++++++-------- core/math/linalg/glsl/linalg_glsl.odin | 84 ++++++++++++++++++++++++++-------- core/math/linalg/hlsl/linalg_hlsl.odin | 84 ++++++++++++++++++++++++++-------- 3 files changed, 198 insertions(+), 54 deletions(-) diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index 8c4f2954a..4a0150972 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -417,6 +417,13 @@ adjugate :: proc{ matrix4x4_adjugate, } +cofactor :: proc{ + matrix1x1_cofactor, + matrix2x2_cofactor, + matrix3x3_cofactor, + matrix4x4_cofactor, +} + inverse_transpose :: proc{ matrix1x1_inverse_transpose, matrix2x2_inverse_transpose, @@ -479,9 +486,9 @@ matrix3x3_determinant :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) # } @(require_results) matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) #no_bounds_check { - a := adjugate(m) + c := cofactor(m) for i in 0..<4 { - det += m[0, i] * a[0, i] + det += m[0, i] * c[0, i] } return } @@ -497,6 +504,47 @@ matrix1x1_adjugate :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) #no_bo @(require_results) matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check { + y[0, 0] = +x[1, 1] + y[0, 1] = -x[0, 1] + y[1, 0] = -x[1, 0] + y[1, 1] = +x[0, 0] + return +} + +@(require_results) +matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { + y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) + return +} + +@(require_results) +matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { + for i in 0..<4 { + for j in 0..<4 { + sign: T = 1 if (i + j) % 2 == 0 else -1 + y[i, j] = sign * matrix_minor(x, j, i) + } + } + return +} + + +@(require_results) +matrix1x1_cofactor :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) #no_bounds_check { + y = x + return +} + +@(require_results) +matrix2x2_cofactor :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check { y[0, 0] = +x[1, 1] y[0, 1] = -x[1, 0] y[1, 0] = -x[0, 1] @@ -505,7 +553,7 @@ matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bo } @(require_results) -matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { +matrix3x3_cofactor :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) @@ -520,7 +568,7 @@ matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bo @(require_results) -matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { +matrix4x4_cofactor :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { for i in 0..<4 { for j in 0..<4 { sign: T = 1 if (i + j) % 2 == 0 else -1 @@ -556,19 +604,19 @@ matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: @(require_results) matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -577,22 +625,22 @@ matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: @(require_results) matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -625,19 +673,19 @@ matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bou @(require_results) matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } @@ -646,22 +694,22 @@ matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou @(require_results) matrix4x4_inverse :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } diff --git a/core/math/linalg/glsl/linalg_glsl.odin b/core/math/linalg/glsl/linalg_glsl.odin index ca61891cb..bd2cf416a 100644 --- a/core/math/linalg/glsl/linalg_glsl.odin +++ b/core/math/linalg/glsl/linalg_glsl.odin @@ -1882,6 +1882,13 @@ adjugate :: proc{ adjugate_matrix4x4, } +cofactor :: proc{ + cofactor_matrix1x1, + cofactor_matrix2x2, + cofactor_matrix3x3, + cofactor_matrix4x4, +} + inverse_transpose :: proc{ inverse_transpose_matrix1x1, inverse_transpose_matrix2x2, @@ -1944,9 +1951,9 @@ determinant_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) { } @(require_results) determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) { - a := adjugate(m) + c := cofactor(m) #no_bounds_check for i in 0..<4 { - det += m[0, i] * a[0, i] + det += m[0, i] * c[0, i] } return } @@ -1962,6 +1969,47 @@ adjugate_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { @(require_results) adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { + y[0, 0] = +x[1, 1] + y[0, 1] = -x[0, 1] + y[1, 0] = -x[1, 0] + y[1, 1] = +x[0, 0] + return +} + +@(require_results) +adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { + y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) + return +} + +@(require_results) +adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { + for i in 0..<4 { + for j in 0..<4 { + sign: T = 1 if (i + j) % 2 == 0 else -1 + y[i, j] = sign * matrix_minor(x, j, i) + } + } + return +} + + +@(require_results) +cofactor_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { + y = x + return +} + +@(require_results) +cofactor_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { y[0, 0] = +x[1, 1] y[0, 1] = -x[1, 0] y[1, 0] = -x[0, 1] @@ -1970,7 +2018,7 @@ adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { } @(require_results) -adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { +cofactor_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) @@ -1985,7 +2033,7 @@ adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { @(require_results) -adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { +cofactor_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { for i in 0..<4 { for j in 0..<4 { sign: T = 1 if (i + j) % 2 == 0 else -1 @@ -2021,19 +2069,19 @@ inverse_transpose_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: @(require_results) inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -2042,22 +2090,22 @@ inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: @(require_results) inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -2090,19 +2138,19 @@ inverse_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { @(require_results) inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } @@ -2111,22 +2159,22 @@ inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou @(require_results) inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } diff --git a/core/math/linalg/hlsl/linalg_hlsl.odin b/core/math/linalg/hlsl/linalg_hlsl.odin index a89fdddd3..cca70f9c8 100644 --- a/core/math/linalg/hlsl/linalg_hlsl.odin +++ b/core/math/linalg/hlsl/linalg_hlsl.odin @@ -1514,6 +1514,13 @@ adjugate :: proc{ adjugate_matrix4x4, } +cofactor :: proc{ + cofactor_matrix1x1, + cofactor_matrix2x2, + cofactor_matrix3x3, + cofactor_matrix4x4, +} + inverse_transpose :: proc{ inverse_transpose_matrix1x1, inverse_transpose_matrix2x2, @@ -1568,9 +1575,9 @@ determinant_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) { } @(require_results) determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) { - a := adjugate(m) + c := cofactor(m) #no_bounds_check for i in 0..<4 { - det += m[0, i] * a[0, i] + det += m[0, i] * c[0, i] } return } @@ -1586,6 +1593,47 @@ adjugate_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { @(require_results) adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { + y[0, 0] = +x[1, 1] + y[0, 1] = -x[0, 1] + y[1, 0] = -x[1, 0] + y[1, 1] = +x[0, 0] + return +} + +@(require_results) +adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { + y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) + return +} + +@(require_results) +adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { + for i in 0..<4 { + for j in 0..<4 { + sign: T = 1 if (i + j) % 2 == 0 else -1 + y[i, j] = sign * matrix_minor(x, j, i) + } + } + return +} + + +@(require_results) +cofactor_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { + y = x + return +} + +@(require_results) +cofactor_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { y[0, 0] = +x[1, 1] y[0, 1] = -x[1, 0] y[1, 0] = -x[0, 1] @@ -1594,7 +1642,7 @@ adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { } @(require_results) -adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { +cofactor_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) @@ -1609,7 +1657,7 @@ adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { @(require_results) -adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { +cofactor_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { for i in 0..<4 { for j in 0..<4 { sign: T = 1 if (i + j) % 2 == 0 else -1 @@ -1645,19 +1693,19 @@ inverse_transpose_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: @(require_results) inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -1666,22 +1714,22 @@ inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: @(require_results) inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -1714,19 +1762,19 @@ inverse_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { @(require_results) inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } @@ -1735,22 +1783,22 @@ inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou @(require_results) inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } -- cgit v1.2.3 From 02a9d8560fb82471ddc89154dee1e9e30afb88ab Mon Sep 17 00:00:00 2001 From: Sebastian Pahnke Date: Sat, 28 Dec 2024 09:33:58 +0100 Subject: Test symmetry --- tests/issues/test_issue_4584.odin | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/tests/issues/test_issue_4584.odin b/tests/issues/test_issue_4584.odin index f14f1f1d3..27e5cd789 100644 --- a/tests/issues/test_issue_4584.odin +++ b/tests/issues/test_issue_4584.odin @@ -8,6 +8,7 @@ import hlm "core:math/linalg/hlsl" @test test_adjugate_2x2 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[2,2]int) m := matrix[2,2]int { -3, 2, -1, 0, @@ -18,19 +19,23 @@ test_adjugate_2x2 :: proc(t: ^testing.T) { } testing.expect_value(t, linalg.adjugate(m), expected) testing.expect_value(t, linalg.determinant(m), 2) - testing.expect_value(t, linalg.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) + testing.expect_value(t, linalg.adjugate(m) * m, 2 * I) + testing.expect_value(t, m * linalg.adjugate(m), 2 * I) testing.expect_value(t, glm.adjugate(m), expected) testing.expect_value(t, glm.determinant(m), 2) - testing.expect_value(t, glm.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) + testing.expect_value(t, glm.adjugate(m) * m, 2 * I) + testing.expect_value(t, m * glm.adjugate(m), 2 * I) testing.expect_value(t, hlm.adjugate(m), expected) testing.expect_value(t, hlm.determinant(m), 2) - testing.expect_value(t, hlm.adjugate(m) * m, 2 * linalg.identity(matrix[2,2]int)) + testing.expect_value(t, hlm.adjugate(m) * m, 2 * I) + testing.expect_value(t, m * hlm.adjugate(m), 2 * I) } @test test_adjugate_3x3 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[3,3]int) m := matrix[3,3]int { -3, 2, -5, -1, 0, -2, @@ -43,19 +48,23 @@ test_adjugate_3x3 :: proc(t: ^testing.T) { } testing.expect_value(t, linalg.adjugate(m), expected) testing.expect_value(t, linalg.determinant(m), -6) - testing.expect_value(t, linalg.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) + testing.expect_value(t, linalg.adjugate(m) * m, -6 * I) + testing.expect_value(t, m * linalg.adjugate(m), -6 * I) testing.expect_value(t, glm.adjugate(m), expected) testing.expect_value(t, glm.determinant(m), -6) - testing.expect_value(t, glm.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) + testing.expect_value(t, glm.adjugate(m) * m, -6 * I) + testing.expect_value(t, m * glm.adjugate(m), -6 * I) testing.expect_value(t, hlm.adjugate(m), expected) testing.expect_value(t, hlm.determinant(m), -6) - testing.expect_value(t, hlm.adjugate(m) * m, -6 * linalg.identity(matrix[3,3]int)) + testing.expect_value(t, hlm.adjugate(m) * m, -6 * I) + testing.expect_value(t, m * hlm.adjugate(m), -6 * I) } @test test_adjugate_4x4 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[4,4]int) m := matrix[4,4]int { -3, 2, -5, 1, -1, 0, -2, 2, @@ -70,13 +79,16 @@ test_adjugate_4x4 :: proc(t: ^testing.T) { } testing.expect_value(t, linalg.adjugate(m), expected) testing.expect_value(t, linalg.determinant(m), -174) - testing.expect_value(t, linalg.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) + testing.expect_value(t, linalg.adjugate(m) * m, -174 * I) + testing.expect_value(t, m * linalg.adjugate(m), -174 * I) testing.expect_value(t, glm.adjugate(m), expected) testing.expect_value(t, glm.determinant(m), -174) - testing.expect_value(t, glm.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) + testing.expect_value(t, glm.adjugate(m) * m, -174 * I) + testing.expect_value(t, m * glm.adjugate(m), -174 * I) testing.expect_value(t, hlm.adjugate(m), expected) testing.expect_value(t, hlm.determinant(m), -174) - testing.expect_value(t, hlm.adjugate(m) * m, -174 * linalg.identity(matrix[4,4]int)) + testing.expect_value(t, hlm.adjugate(m) * m, -174 * I) + testing.expect_value(t, m * hlm.adjugate(m), -174 * I) } \ No newline at end of file -- cgit v1.2.3 From ec5ee19c01c30e8fd01c9f04a2249c4d3d18b50d Mon Sep 17 00:00:00 2001 From: Sebastian Pahnke Date: Sat, 28 Dec 2024 10:24:37 +0100 Subject: Add regression tests for matrix inverse --- tests/issues/test_issue_4584.odin | 95 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/tests/issues/test_issue_4584.odin b/tests/issues/test_issue_4584.odin index 27e5cd789..a709926d2 100644 --- a/tests/issues/test_issue_4584.odin +++ b/tests/issues/test_issue_4584.odin @@ -2,6 +2,7 @@ package test_issues import "core:testing" +import "core:log" import "core:math/linalg" import glm "core:math/linalg/glsl" import hlm "core:math/linalg/hlsl" @@ -91,4 +92,98 @@ test_adjugate_4x4 :: proc(t: ^testing.T) { testing.expect_value(t, hlm.determinant(m), -174) testing.expect_value(t, hlm.adjugate(m) * m, -174 * I) testing.expect_value(t, m * hlm.adjugate(m), -174 * I) +} + +@test +test_inverse_regression_2x2 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[2,2]f32) + m := matrix[2,2]f32 { + -3, 2, + -1, 0, + } + expected := matrix[2,2]f32 { + 0.0, -1.0, + 1.0/2.0, -3.0/2.0, + } + expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse(m) * m, I) + expect_float_matrix_value(t, m * linalg.inverse(m), I) + + expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse(m) * m, I) + expect_float_matrix_value(t, m * glm.inverse(m), I) + + expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse(m) * m, I) + expect_float_matrix_value(t, m * hlm.inverse(m), I) +} + +@test +test_inverse_regression_3x3 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[3,3]f32) + m := matrix[3,3]f32 { + -3, 2, -5, + -1, 0, -2, + 3, -4, 1, + } + expected := matrix[3,3]f32 { + 4.0/3.0, -3.0, 2.0/3.0, + 5.0/6.0, -2.0, 1.0/6.0, + -2.0/3.0, 1.0, -1.0/3.0, + } + expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse(m) * m, I) + expect_float_matrix_value(t, m * linalg.inverse(m), I) + + expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse(m) * m, I) + expect_float_matrix_value(t, m * glm.inverse(m), I) + + expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse(m) * m, I) + expect_float_matrix_value(t, m * hlm.inverse(m), I) +} + +@test +test_inverse_regression_4x4 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[4,4]f32) + m := matrix[4,4]f32 { + -3, 2, -5, 1, + -1, 0, -2, 2, + 3, -4, 1, 3, + 4, 5, 6, 7, + } + expected := matrix[4,4]f32 { + 24.0/29.0, -133.0/87.0, 46.0/87.0, 8.0/87.0, + 19.0/58.0, -46.0/87.0, 5.0/174.0, 8.0/87.0, + -35.0/58.0, 71.0/87.0, -55.0/174.0, -1.0/87.0, + -11.0/58.0, 16.0/29.0, -3.0/58.0, 1.0/29.0, + } + expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse(m) * m, I) + expect_float_matrix_value(t, m * linalg.inverse(m), I) + + expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse(m) * m, I) + expect_float_matrix_value(t, m * glm.inverse(m), I) + + expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse(m) * m, I) + expect_float_matrix_value(t, m * hlm.inverse(m), I) +} + +@(private="file") +expect_float_matrix_value :: proc(t: ^testing.T, value, expected: $M/matrix[$N, N]f32, loc := #caller_location, value_expr := #caller_expression(value)) -> bool { + ok := true + outer: for i in 0.. 1e-6 { + ok = false + break outer + } + } + } + if !ok do log.errorf("expected %v to be %v, got %v", value_expr, expected, value, location=loc) + return ok } \ No newline at end of file -- cgit v1.2.3 From b21fc1923307602500c696e418efa951a5658ed8 Mon Sep 17 00:00:00 2001 From: Sebastian Pahnke Date: Sat, 28 Dec 2024 10:29:05 +0100 Subject: Add regression tests for inverse_transpose --- tests/issues/test_issue_4584.odin | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/issues/test_issue_4584.odin b/tests/issues/test_issue_4584.odin index a709926d2..9eea23420 100644 --- a/tests/issues/test_issue_4584.odin +++ b/tests/issues/test_issue_4584.odin @@ -106,14 +106,17 @@ test_inverse_regression_2x2 :: proc(t: ^testing.T) { 1.0/2.0, -3.0/2.0, } expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected)) expect_float_matrix_value(t, linalg.inverse(m) * m, I) expect_float_matrix_value(t, m * linalg.inverse(m), I) expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected)) expect_float_matrix_value(t, glm.inverse(m) * m, I) expect_float_matrix_value(t, m * glm.inverse(m), I) expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected)) expect_float_matrix_value(t, hlm.inverse(m) * m, I) expect_float_matrix_value(t, m * hlm.inverse(m), I) } @@ -132,14 +135,17 @@ test_inverse_regression_3x3 :: proc(t: ^testing.T) { -2.0/3.0, 1.0, -1.0/3.0, } expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected)) expect_float_matrix_value(t, linalg.inverse(m) * m, I) expect_float_matrix_value(t, m * linalg.inverse(m), I) expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected)) expect_float_matrix_value(t, glm.inverse(m) * m, I) expect_float_matrix_value(t, m * glm.inverse(m), I) expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected)) expect_float_matrix_value(t, hlm.inverse(m) * m, I) expect_float_matrix_value(t, m * hlm.inverse(m), I) } @@ -160,14 +166,17 @@ test_inverse_regression_4x4 :: proc(t: ^testing.T) { -11.0/58.0, 16.0/29.0, -3.0/58.0, 1.0/29.0, } expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected)) expect_float_matrix_value(t, linalg.inverse(m) * m, I) expect_float_matrix_value(t, m * linalg.inverse(m), I) expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected)) expect_float_matrix_value(t, glm.inverse(m) * m, I) expect_float_matrix_value(t, m * glm.inverse(m), I) expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected)) expect_float_matrix_value(t, hlm.inverse(m) * m, I) expect_float_matrix_value(t, m * hlm.inverse(m), I) } -- cgit v1.2.3 From d22cb20d85e0afeb61f6ad26434dd92b9d9b2ff7 Mon Sep 17 00:00:00 2001 From: dozn <16659513+dozn@users.noreply.github.com> Date: Sat, 28 Dec 2024 07:48:09 -0800 Subject: Use Struct Tags For Embedded (with `using`) Structs When Unmarshalling JSON A fix for https://github.com/odin-lang/Odin/issues/4539 --- core/encoding/json/unmarshal.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index c70b8d39a..e76de2747 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -470,7 +470,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm } } - if field.name == key { + if field.name == key || (field.tag != "" && reflect.struct_tag_get(field.tag, "json") == key) { offset = field.offset type = field.type found = true -- cgit v1.2.3 From 87c159c69fd699312fa014700c03f43188dd0728 Mon Sep 17 00:00:00 2001 From: dozn <16659513+dozn@users.noreply.github.com> Date: Sat, 28 Dec 2024 08:13:38 -0800 Subject: Remove unnecessary string() conversion. --- core/encoding/json/unmarshal.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index e76de2747..57371e360 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -439,7 +439,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm use_field_idx := -1 for field, field_idx in fields { - tag_value := string(reflect.struct_tag_get(field.tag, "json")) + tag_value := reflect.struct_tag_get(field.tag, "json") json_name, _ := json_name_from_tag_value(tag_value) if key == json_name { use_field_idx = field_idx -- cgit v1.2.3 From 77511da195ad83c6d8e130be7249cde53d78d69c Mon Sep 17 00:00:00 2001 From: shashank Date: Sun, 29 Dec 2024 19:58:55 +0530 Subject: update cgltf from 1.13 to 1.14 --- vendor/cgltf/cgltf.odin | 71 ++++- vendor/cgltf/src/cgltf.h | 653 +++++++++++++++++++++++++++-------------- vendor/cgltf/src/cgltf_write.h | 67 ++++- 3 files changed, 549 insertions(+), 242 deletions(-) diff --git a/vendor/cgltf/cgltf.odin b/vendor/cgltf/cgltf.odin index a24c36d64..e9dc7ef84 100644 --- a/vendor/cgltf/cgltf.odin +++ b/vendor/cgltf/cgltf.odin @@ -105,6 +105,7 @@ type :: enum c.int { } primitive_type :: enum c.int { + invalid, points, lines, line_loop, @@ -222,15 +223,6 @@ accessor_sparse :: struct { indices_component_type: component_type, values_buffer_view: ^buffer_view, values_byte_offset: uint, - extras: extras_t, - indices_extras: extras_t, - values_extras: extras_t, - extensions_count: uint, - extensions: [^]extension `fmt:"v,extensions_count"`, - indices_extensions_count: uint, - indices_extensions: [^]extension `fmt:"v,indices_extensions_count"`, - values_extensions_count: uint, - values_extensions: [^]extension `fmt:"v,values_extensions_count"`, } accessor :: struct { @@ -306,9 +298,6 @@ texture_view :: struct { scale: f32, /* equivalent to strength for occlusion_texture */ has_transform: b32, transform: texture_transform, - extras: extras_t, - extensions_count: uint, - extensions: [^]extension `fmt:"v,extensions_count"`, } pbr_metallic_roughness :: struct { @@ -381,6 +370,16 @@ iridescence :: struct { iridescence_thickness_texture: texture_view, } +anisotropy :: struct { + anisotropy_strength: f32, + anisotropy_rotation: f32, + anisotropy_texture: texture_view, +} + +dispersion :: struct { + dispersion: f32, +} + material :: struct { name: cstring, has_pbr_metallic_roughness: b32, @@ -393,6 +392,8 @@ material :: struct { has_sheen: b32, has_emissive_strength: b32, has_iridescence: b32, + has_anisotropy: b32, + has_dispersion: b32, pbr_metallic_roughness: pbr_metallic_roughness, pbr_specular_glossiness: pbr_specular_glossiness, clearcoat: clearcoat, @@ -403,6 +404,8 @@ material :: struct { volume: volume, emissive_strength: emissive_strength, iridescence: iridescence, + anisotropy: anisotropy, + dispersion: dispersion, normal_texture: texture_view, occlusion_texture: texture_view, emissive_texture: texture_view, @@ -432,7 +435,6 @@ draco_mesh_compression :: struct { } mesh_gpu_instancing :: struct { - buffer_view: ^buffer_view, attributes: []attribute, } @@ -683,6 +685,9 @@ foreign lib { node_transform_local :: proc(node: ^node, out_matrix: [^]f32) --- node_transform_world :: proc(node: ^node, out_matrix: [^]f32) --- + @(require_results) + buffer_view_data :: proc(view: ^/*const*/buffer_view) -> [^]byte --- + @(require_results) accessor_read_float :: proc(accessor: ^/*const*/accessor, index: uint, out: [^]f32, element_size: uint) -> b32 --- @(require_results) @@ -693,13 +698,53 @@ foreign lib { @(require_results) num_components :: proc(type: type) -> uint --- + @(require_results) + component_size :: proc(component_type: component_type) -> uint --- + @(require_results) + calc_size :: proc(type: type, component_type: component_type) -> uint --- + @(require_results) accessor_unpack_floats :: proc(accessor: ^/*const*/accessor, out: [^]f32, float_count: uint) -> uint --- + @(require_results) + accessor_unpack_indices :: proc(accessor: ^/*const*/accessor , out: rawptr, out_component_size: uint, index_count: uint) -> uint --- /* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ @(require_results) copy_extras_json :: proc(data: ^data, extras: ^extras_t, dest: [^]byte, dest_size: ^uint) -> result --- + @(require_results) + mesh_index :: proc(data: ^/*const*/data, object: ^/*const*/mesh) -> uint --- + @(require_results) + material_index :: proc(data: ^/*const*/data, object: ^/*const*/material) -> uint --- + @(require_results) + accessor_index :: proc(data: ^/*const*/data, object: ^/*const*/accessor) -> uint --- + @(require_results) + buffer_view_index :: proc(data: ^/*const*/data, object: ^/*const*/buffer_view) -> uint --- + @(require_results) + buffer_index :: proc(data: ^/*const*/data, object: ^/*const*/buffer) -> uint --- + @(require_results) + image_index :: proc(data: ^/*const*/data, object: ^/*const*/image) -> uint --- + @(require_results) + texture_index :: proc(data: ^/*const*/data, object: ^/*const*/texture) -> uint --- + @(require_results) + sampler_index :: proc(data: ^/*const*/data, object: ^/*const*/sampler) -> uint --- + @(require_results) + skin_index :: proc(data: ^/*const*/data, object: ^/*const*/skin) -> uint --- + @(require_results) + camera_index :: proc(data: ^/*const*/data, object: ^/*const*/camera) -> uint --- + @(require_results) + light_index :: proc(data: ^/*const*/data, object: ^/*const*/light) -> uint --- + @(require_results) + node_index :: proc(data: ^/*const*/data, object: ^/*const*/node) -> uint --- + @(require_results) + scene_index :: proc(data: ^/*const*/data, object: ^/*const*/scene) -> uint --- + @(require_results) + animation_index :: proc(data: ^/*const*/data, object: ^/*const*/animation) -> uint --- + @(require_results) + animation_sampler_index :: proc(animation: ^/*const*/animation, object: ^/*const*/animation_sampler) -> uint --- + @(require_results) + animation_channel_index :: proc(animation: ^/*const*/animation, object: ^/*const*/animation_channel) -> uint --- + @(require_results) write_file :: proc(#by_ptr options: options, path: cstring, data: ^data) -> result --- @(require_results) diff --git a/vendor/cgltf/src/cgltf.h b/vendor/cgltf/src/cgltf.h index a534cefb4..17dc0ca5d 100644 --- a/vendor/cgltf/src/cgltf.h +++ b/vendor/cgltf/src/cgltf.h @@ -1,7 +1,7 @@ /** * cgltf - a single-file glTF 2.0 parser written in C99. * - * Version: 1.13 + * Version: 1.14 * * Website: https://github.com/jkuhlmann/cgltf * @@ -63,9 +63,15 @@ * By passing null for the output pointer, users can find out how many floats are required in the * output buffer. * + * `cgltf_accessor_unpack_indices` reads in the index data from an accessor. Assumes that + * `cgltf_load_buffers` has already been called. By passing null for the output pointer, users can + * find out how many indices are required in the output buffer. Returns 0 if the accessor is + * sparse or if the output component size is less than the accessor's component size. + * * `cgltf_num_components` is a tiny utility that tells you the dimensionality of * a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate - * the necessary amount of memory. + * the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for + * similar purposes. * * `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element @@ -74,7 +80,7 @@ * * `cgltf_accessor_read_uint` is similar to its floating-point counterpart, but limited to reading * vector types and does not support matrix types. The passed-in element size is the number of uints - * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in + * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in * element_size is too small, or if the accessor is sparse. * * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t @@ -89,6 +95,7 @@ #define CGLTF_H_INCLUDED__ #include +#include /* For uint8_t, uint32_t */ #ifdef __cplusplus extern "C" { @@ -195,6 +202,7 @@ typedef enum cgltf_type typedef enum cgltf_primitive_type { + cgltf_primitive_type_invalid, cgltf_primitive_type_points, cgltf_primitive_type_lines, cgltf_primitive_type_line_loop, @@ -326,15 +334,6 @@ typedef struct cgltf_accessor_sparse cgltf_component_type indices_component_type; cgltf_buffer_view* values_buffer_view; cgltf_size values_byte_offset; - cgltf_extras extras; - cgltf_extras indices_extras; - cgltf_extras values_extras; - cgltf_size extensions_count; - cgltf_extension* extensions; - cgltf_size indices_extensions_count; - cgltf_extension* indices_extensions; - cgltf_size values_extensions_count; - cgltf_extension* values_extensions; } cgltf_accessor_sparse; typedef struct cgltf_accessor @@ -417,9 +416,6 @@ typedef struct cgltf_texture_view cgltf_float scale; /* equivalent to strength for occlusion_texture */ cgltf_bool has_transform; cgltf_texture_transform transform; - cgltf_extras extras; - cgltf_size extensions_count; - cgltf_extension* extensions; } cgltf_texture_view; typedef struct cgltf_pbr_metallic_roughness @@ -502,6 +498,18 @@ typedef struct cgltf_iridescence cgltf_texture_view iridescence_thickness_texture; } cgltf_iridescence; +typedef struct cgltf_anisotropy +{ + cgltf_float anisotropy_strength; + cgltf_float anisotropy_rotation; + cgltf_texture_view anisotropy_texture; +} cgltf_anisotropy; + +typedef struct cgltf_dispersion +{ + cgltf_float dispersion; +} cgltf_dispersion; + typedef struct cgltf_material { char* name; @@ -515,6 +523,8 @@ typedef struct cgltf_material cgltf_bool has_sheen; cgltf_bool has_emissive_strength; cgltf_bool has_iridescence; + cgltf_bool has_anisotropy; + cgltf_bool has_dispersion; cgltf_pbr_metallic_roughness pbr_metallic_roughness; cgltf_pbr_specular_glossiness pbr_specular_glossiness; cgltf_clearcoat clearcoat; @@ -525,6 +535,8 @@ typedef struct cgltf_material cgltf_volume volume; cgltf_emissive_strength emissive_strength; cgltf_iridescence iridescence; + cgltf_anisotropy anisotropy; + cgltf_dispersion dispersion; cgltf_texture_view normal_texture; cgltf_texture_view occlusion_texture; cgltf_texture_view emissive_texture; @@ -557,7 +569,6 @@ typedef struct cgltf_draco_mesh_compression { } cgltf_draco_mesh_compression; typedef struct cgltf_mesh_gpu_instancing { - cgltf_buffer_view* buffer_view; cgltf_attribute* attributes; cgltf_size attributes_count; } cgltf_mesh_gpu_instancing; @@ -829,17 +840,39 @@ void cgltf_free(cgltf_data* data); void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix); +const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view); + cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size); cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size); cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index); cgltf_size cgltf_num_components(cgltf_type type); +cgltf_size cgltf_component_size(cgltf_component_type component_type); +cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count); +cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count); /* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size); +cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object); +cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object); +cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object); +cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object); +cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object); +cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object); +cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object); +cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object); +cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object); +cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object); +cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object); +cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object); +cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object); +cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object); +cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object); +cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object); + #ifdef __cplusplus } #endif @@ -860,7 +893,7 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* #ifdef CGLTF_IMPLEMENTATION -#include /* For uint8_t, uint32_t */ +#include /* For assert */ #include /* For strncpy */ #include /* For fopen */ #include /* For UINT_MAX etc */ @@ -870,10 +903,6 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* #include /* For malloc, free, atoi, atof */ #endif -#if CGLTF_VALIDATE_ENABLE_ASSERTS -#include -#endif - /* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */ #define JSMN_PARENT_LINKS @@ -902,15 +931,15 @@ enum jsmnerr { }; typedef struct { jsmntype_t type; - int start; - int end; + ptrdiff_t start; + ptrdiff_t end; int size; #ifdef JSMN_PARENT_LINKS int parent; #endif } jsmntok_t; typedef struct { - unsigned int pos; /* offset in the JSON string */ + size_t pos; /* offset in the JSON string */ unsigned int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; @@ -922,8 +951,8 @@ static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t #ifndef CGLTF_CONSTS -static const cgltf_size GlbHeaderSize = 12; -static const cgltf_size GlbChunkHeaderSize = 8; +#define GlbHeaderSize 12 +#define GlbChunkHeaderSize 8 static const uint32_t GlbVersion = 2; static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; @@ -995,7 +1024,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m { fseek(file, 0, SEEK_END); -#ifdef _WIN32 +#ifdef _MSC_VER __int64 length = _ftelli64(file); #else long length = ftell(file); @@ -1017,7 +1046,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m fclose(file); return cgltf_result_out_of_memory; } - + cgltf_size read_size = fread(file_data, 1, file_size, file); fclose(file); @@ -1125,7 +1154,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s // JSON chunk: length uint32_t json_length; memcpy(&json_length, json_chunk, 4); - if (GlbHeaderSize + GlbChunkHeaderSize + json_length > size) + if (json_length > size - GlbHeaderSize - GlbChunkHeaderSize) { return cgltf_result_data_too_short; } @@ -1139,10 +1168,10 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s json_chunk += GlbChunkHeaderSize; - const void* bin = 0; + const void* bin = NULL; cgltf_size bin_size = 0; - if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize <= size) + if (GlbChunkHeaderSize <= size - GlbHeaderSize - GlbChunkHeaderSize - json_length) { // We can read another chunk const uint8_t* bin_chunk = json_chunk + json_length; @@ -1150,7 +1179,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s // Bin chunk: length uint32_t bin_length; memcpy(&bin_length, bin_chunk, 4); - if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize + bin_length > size) + if (bin_length > size - GlbHeaderSize - GlbChunkHeaderSize - json_length - GlbChunkHeaderSize) { return cgltf_result_data_too_short; } @@ -1486,8 +1515,6 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, return cgltf_result_success; } -static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); - static cgltf_size cgltf_calc_index_bound(cgltf_buffer_view* buffer_view, cgltf_size offset, cgltf_component_type component_type, cgltf_size count) { char* data = (char*)buffer_view->buffer->data + offset + buffer_view->offset; @@ -1538,6 +1565,9 @@ cgltf_result cgltf_validate(cgltf_data* data) { cgltf_accessor* accessor = &data->accessors[i]; + CGLTF_ASSERT_IF(data->accessors[i].component_type == cgltf_component_type_invalid, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(data->accessors[i].type == cgltf_type_invalid, cgltf_result_invalid_gltf); + cgltf_size element_size = cgltf_calc_size(accessor->type, accessor->component_type); if (accessor->buffer_view) @@ -1551,7 +1581,7 @@ cgltf_result cgltf_validate(cgltf_data* data) { cgltf_accessor_sparse* sparse = &accessor->sparse; - cgltf_size indices_component_size = cgltf_calc_size(cgltf_type_scalar, sparse->indices_component_type); + cgltf_size indices_component_size = cgltf_component_size(sparse->indices_component_type); cgltf_size indices_req_size = sparse->indices_byte_offset + indices_component_size * sparse->count; cgltf_size values_req_size = sparse->values_byte_offset + element_size * sparse->count; @@ -1617,43 +1647,48 @@ cgltf_result cgltf_validate(cgltf_data* data) for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j) { + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].type == cgltf_primitive_type_invalid, cgltf_result_invalid_gltf); CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets_count != data->meshes[i].primitives[0].targets_count, cgltf_result_invalid_gltf); - if (data->meshes[i].primitives[j].attributes_count) + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes_count == 0, cgltf_result_invalid_gltf); + + cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data; + + CGLTF_ASSERT_IF(first->count == 0, cgltf_result_invalid_gltf); + + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) { - cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data; + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf); + } - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k) + { + for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m) { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf); } + } - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k) - { - for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m) - { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf); - } - } + cgltf_accessor* indices = data->meshes[i].primitives[j].indices; - cgltf_accessor* indices = data->meshes[i].primitives[j].indices; + CGLTF_ASSERT_IF(indices && + indices->component_type != cgltf_component_type_r_8u && + indices->component_type != cgltf_component_type_r_16u && + indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf); - CGLTF_ASSERT_IF(indices && - indices->component_type != cgltf_component_type_r_8u && - indices->component_type != cgltf_component_type_r_16u && - indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(indices && indices->type != cgltf_type_scalar, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(indices && indices->stride != cgltf_component_size(indices->component_type), cgltf_result_invalid_gltf); - if (indices && indices->buffer_view && indices->buffer_view->buffer->data) - { - cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count); + if (indices && indices->buffer_view && indices->buffer_view->buffer->data) + { + cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count); - CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short); - } + CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short); + } - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) - { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf); - } + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) + { + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf); } } } @@ -1710,10 +1745,15 @@ cgltf_result cgltf_validate(cgltf_data* data) cgltf_size values = channel->sampler->interpolation == cgltf_interpolation_type_cubic_spline ? 3 : 1; - CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_data_too_short); + CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_invalid_gltf); } } + for (cgltf_size i = 0; i < data->variants_count; ++i) + { + CGLTF_ASSERT_IF(!data->variants[i].name, cgltf_result_invalid_gltf); + } + return cgltf_result_success; } @@ -1760,12 +1800,6 @@ static void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, data->memory.free_func(data->memory.user_data, extensions); } -static void cgltf_free_texture_view(cgltf_data* data, cgltf_texture_view* view) -{ - cgltf_free_extensions(data, view->extensions, view->extensions_count); - cgltf_free_extras(data, &view->extras); -} - void cgltf_free(cgltf_data* data) { if (!data) @@ -1787,15 +1821,6 @@ void cgltf_free(cgltf_data* data) { data->memory.free_func(data->memory.user_data, data->accessors[i].name); - if(data->accessors[i].is_sparse) - { - cgltf_free_extensions(data, data->accessors[i].sparse.extensions, data->accessors[i].sparse.extensions_count); - cgltf_free_extensions(data, data->accessors[i].sparse.indices_extensions, data->accessors[i].sparse.indices_extensions_count); - cgltf_free_extensions(data, data->accessors[i].sparse.values_extensions, data->accessors[i].sparse.values_extensions_count); - cgltf_free_extras(data, &data->accessors[i].sparse.extras); - cgltf_free_extras(data, &data->accessors[i].sparse.indices_extras); - cgltf_free_extras(data, &data->accessors[i].sparse.values_extras); - } cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count); cgltf_free_extras(data, &data->accessors[i].extras); } @@ -1897,57 +1922,13 @@ void cgltf_free(cgltf_data* data) { data->memory.free_func(data->memory.user_data, data->materials[i].name); - if(data->materials[i].has_pbr_metallic_roughness) - { - cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.metallic_roughness_texture); - cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.base_color_texture); - } - if(data->materials[i].has_pbr_specular_glossiness) - { - cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.diffuse_texture); - cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.specular_glossiness_texture); - } - if(data->materials[i].has_clearcoat) - { - cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_texture); - cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_roughness_texture); - cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_normal_texture); - } - if(data->materials[i].has_specular) - { - cgltf_free_texture_view(data, &data->materials[i].specular.specular_texture); - cgltf_free_texture_view(data, &data->materials[i].specular.specular_color_texture); - } - if(data->materials[i].has_transmission) - { - cgltf_free_texture_view(data, &data->materials[i].transmission.transmission_texture); - } - if (data->materials[i].has_volume) - { - cgltf_free_texture_view(data, &data->materials[i].volume.thickness_texture); - } - if(data->materials[i].has_sheen) - { - cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_color_texture); - cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_roughness_texture); - } - if(data->materials[i].has_iridescence) - { - cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_texture); - cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_thickness_texture); - } - - cgltf_free_texture_view(data, &data->materials[i].normal_texture); - cgltf_free_texture_view(data, &data->materials[i].occlusion_texture); - cgltf_free_texture_view(data, &data->materials[i].emissive_texture); - cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count); cgltf_free_extras(data, &data->materials[i].extras); } data->memory.free_func(data->memory.user_data, data->materials); - for (cgltf_size i = 0; i < data->images_count; ++i) + for (cgltf_size i = 0; i < data->images_count; ++i) { data->memory.free_func(data->memory.user_data, data->images[i].name); data->memory.free_func(data->memory.user_data, data->images[i].uri); @@ -2195,8 +2176,6 @@ static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_ return *((const uint16_t*) in); case cgltf_component_type_r_32u: return *((const uint32_t*) in); - case cgltf_component_type_r_32f: - return (cgltf_ssize)*((const float*) in); case cgltf_component_type_r_8: return *((const int8_t*) in); case cgltf_component_type_r_8u: @@ -2214,8 +2193,6 @@ static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_typ return *((const uint16_t*) in); case cgltf_component_type_r_32u: return *((const uint32_t*) in); - case cgltf_component_type_r_32f: - return (cgltf_size)*((const float*) in); case cgltf_component_type_r_8u: return *((const uint8_t*) in); default: @@ -2251,8 +2228,6 @@ static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_ty return (cgltf_float)cgltf_component_read_integer(in, component_type); } -static cgltf_size cgltf_component_size(cgltf_component_type component_type); - static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_bool normalized, cgltf_float* out, cgltf_size element_size) { cgltf_size num_components = cgltf_num_components(type); @@ -2355,21 +2330,41 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl cgltf_size element_count = float_count / floats_per_element; // First pass: convert each element in the base accessor. - cgltf_float* dest = out; - cgltf_accessor dense = *accessor; - dense.is_sparse = 0; - for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element) + if (accessor->buffer_view == NULL) { - if (!cgltf_accessor_read_float(&dense, index, dest, floats_per_element)) + memset(out, 0, element_count * floats_per_element * sizeof(cgltf_float)); + } + else + { + const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); + if (element == NULL) { return 0; } + element += accessor->offset; + + if (accessor->component_type == cgltf_component_type_r_32f && accessor->stride == floats_per_element * sizeof(cgltf_float)) + { + memcpy(out, element, element_count * floats_per_element * sizeof(cgltf_float)); + } + else + { + cgltf_float* dest = out; + + for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element, element += accessor->stride) + { + if (!cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, dest, floats_per_element)) + { + return 0; + } + } + } } // Second pass: write out each element in the sparse accessor. if (accessor->is_sparse) { - const cgltf_accessor_sparse* sparse = &dense.sparse; + const cgltf_accessor_sparse* sparse = &accessor->sparse; const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view); const uint8_t* reader_head = cgltf_buffer_view_data(sparse->values_buffer_view); @@ -2383,17 +2378,15 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl reader_head += sparse->values_byte_offset; cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type); - for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride) + for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride, reader_head += accessor->stride) { size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type); float* writer_head = out + writer_index * floats_per_element; - if (!cgltf_element_read_float(reader_head, dense.type, dense.component_type, dense.normalized, writer_head, floats_per_element)) + if (!cgltf_element_read_float(reader_head, accessor->type, accessor->component_type, accessor->normalized, writer_head, floats_per_element)) { return 0; } - - reader_head += dense.stride; } } @@ -2487,12 +2480,165 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size return cgltf_component_read_index(element, accessor->component_type); } +cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object) +{ + assert(object && (cgltf_size)(object - data->meshes) < data->meshes_count); + return (cgltf_size)(object - data->meshes); +} + +cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object) +{ + assert(object && (cgltf_size)(object - data->materials) < data->materials_count); + return (cgltf_size)(object - data->materials); +} + +cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object) +{ + assert(object && (cgltf_size)(object - data->accessors) < data->accessors_count); + return (cgltf_size)(object - data->accessors); +} + +cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object) +{ + assert(object && (cgltf_size)(object - data->buffer_views) < data->buffer_views_count); + return (cgltf_size)(object - data->buffer_views); +} + +cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object) +{ + assert(object && (cgltf_size)(object - data->buffers) < data->buffers_count); + return (cgltf_size)(object - data->buffers); +} + +cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object) +{ + assert(object && (cgltf_size)(object - data->images) < data->images_count); + return (cgltf_size)(object - data->images); +} + +cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object) +{ + assert(object && (cgltf_size)(object - data->textures) < data->textures_count); + return (cgltf_size)(object - data->textures); +} + +cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object) +{ + assert(object && (cgltf_size)(object - data->samplers) < data->samplers_count); + return (cgltf_size)(object - data->samplers); +} + +cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object) +{ + assert(object && (cgltf_size)(object - data->skins) < data->skins_count); + return (cgltf_size)(object - data->skins); +} + +cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object) +{ + assert(object && (cgltf_size)(object - data->cameras) < data->cameras_count); + return (cgltf_size)(object - data->cameras); +} + +cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object) +{ + assert(object && (cgltf_size)(object - data->lights) < data->lights_count); + return (cgltf_size)(object - data->lights); +} + +cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object) +{ + assert(object && (cgltf_size)(object - data->nodes) < data->nodes_count); + return (cgltf_size)(object - data->nodes); +} + +cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object) +{ + assert(object && (cgltf_size)(object - data->scenes) < data->scenes_count); + return (cgltf_size)(object - data->scenes); +} + +cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object) +{ + assert(object && (cgltf_size)(object - data->animations) < data->animations_count); + return (cgltf_size)(object - data->animations); +} + +cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object) +{ + assert(object && (cgltf_size)(object - animation->samplers) < animation->samplers_count); + return (cgltf_size)(object - animation->samplers); +} + +cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object) +{ + assert(object && (cgltf_size)(object - animation->channels) < animation->channels_count); + return (cgltf_size)(object - animation->channels); +} + +cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count) +{ + if (out == NULL) + { + return accessor->count; + } + + index_count = accessor->count < index_count ? accessor->count : index_count; + cgltf_size index_component_size = cgltf_component_size(accessor->component_type); + + if (accessor->is_sparse) + { + return 0; + } + if (accessor->buffer_view == NULL) + { + return 0; + } + if (index_component_size > out_component_size) + { + return 0; + } + const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); + if (element == NULL) + { + return 0; + } + element += accessor->offset; + + if (index_component_size == out_component_size && accessor->stride == out_component_size) + { + memcpy(out, element, index_count * index_component_size); + return index_count; + } + + // The component size of the output array is larger than the component size of the index data, so index data will be padded. + switch (out_component_size) + { + case 2: + for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride) + { + ((uint16_t*)out)[index] = (uint16_t)cgltf_component_read_index(element, accessor->component_type); + } + break; + case 4: + for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride) + { + ((uint32_t*)out)[index] = (uint32_t)cgltf_component_read_index(element, accessor->component_type); + } + break; + default: + break; + } + + return index_count; +} + #define CGLTF_ERROR_JSON -1 #define CGLTF_ERROR_NOMEM -2 #define CGLTF_ERROR_LEGACY -3 #define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; } -#define CGLTF_CHECK_TOKTYPE_RETTYPE(tok_, type_, ret_) if ((tok_).type != (type_)) { return (ret_)CGLTF_ERROR_JSON; } +#define CGLTF_CHECK_TOKTYPE_RET(tok_, type_, ret_) if ((tok_).type != (type_)) { return ret_; } #define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */ #define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1) @@ -2503,7 +2649,7 @@ static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, co { CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING); size_t const str_len = strlen(str); - size_t const name_length = tok->end - tok->start; + size_t const name_length = (size_t)(tok->end - tok->start); return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128; } @@ -2511,7 +2657,7 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return CGLTF_ATOI(tmp); @@ -2519,19 +2665,20 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk) static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_chunk) { - CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size); + CGLTF_CHECK_TOKTYPE_RET(*tok, JSMN_PRIMITIVE, 0); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; - return (cgltf_size)CGLTF_ATOLL(tmp); + long long res = CGLTF_ATOLL(tmp); + return res < 0 ? 0 : (cgltf_size)res; } static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return (cgltf_float)CGLTF_ATOF(tmp); @@ -2539,7 +2686,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk) { - int size = tok->end - tok->start; + int size = (int)(tok->end - tok->start); return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0; } @@ -2605,7 +2752,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke { return CGLTF_ERROR_JSON; } - int size = tokens[i].end - tokens[i].start; + int size = (int)(tokens[i].end - tokens[i].start); char* result = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); if (!result) { @@ -2706,6 +2853,11 @@ static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* o if (us && *out_type != cgltf_attribute_type_invalid) { *out_index = CGLTF_ATOI(us + 1); + if (*out_index < 0) + { + *out_type = cgltf_attribute_type_invalid; + *out_index = 0; + } } } @@ -2863,6 +3015,10 @@ static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmnt out_draco_mesh_compression->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } + else + { + i = cgltf_skip_json(tokens, i+1); + } if (i < 0) { @@ -2888,11 +3044,9 @@ static int cgltf_parse_json_mesh_gpu_instancing(cgltf_options* options, jsmntok_ { i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_mesh_gpu_instancing->attributes, &out_mesh_gpu_instancing->attributes_count); } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0) + else { - ++i; - out_mesh_gpu_instancing->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); - ++i; + i = cgltf_skip_json(tokens, i+1); } if (i < 0) @@ -3036,6 +3190,31 @@ static int cgltf_parse_json_material_mappings(cgltf_options* options, jsmntok_t return i; } +static cgltf_primitive_type cgltf_json_to_primitive_type(jsmntok_t const* tok, const uint8_t* json_chunk) +{ + int type = cgltf_json_to_int(tok, json_chunk); + + switch (type) + { + case 0: + return cgltf_primitive_type_points; + case 1: + return cgltf_primitive_type_lines; + case 2: + return cgltf_primitive_type_line_loop; + case 3: + return cgltf_primitive_type_line_strip; + case 4: + return cgltf_primitive_type_triangles; + case 5: + return cgltf_primitive_type_triangle_strip; + case 6: + return cgltf_primitive_type_triangle_fan; + default: + return cgltf_primitive_type_invalid; + } +} + static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -3052,9 +3231,7 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0) { ++i; - out_prim->type - = (cgltf_primitive_type) - cgltf_json_to_int(tokens+i, json_chunk); + out_prim->type = cgltf_json_to_primitive_type(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0) @@ -3290,7 +3467,7 @@ static cgltf_component_type cgltf_json_to_component_type(jsmntok_t const* tok, c } } -static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse) +static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -3304,7 +3481,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_sparse->count = cgltf_json_to_int(tokens + i, json_chunk); + out_sparse->count = cgltf_json_to_size(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0) @@ -3337,14 +3514,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->indices_extras); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) - { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->indices_extensions_count, &out_sparse->indices_extensions); - } else { i = cgltf_skip_json(tokens, i+1); @@ -3380,14 +3549,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->values_extras); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) - { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->values_extensions_count, &out_sparse->values_extensions); - } else { i = cgltf_skip_json(tokens, i+1); @@ -3399,14 +3560,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co } } } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->extras); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) - { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->extensions_count, &out_sparse->extensions); - } else { i = cgltf_skip_json(tokens, i+1); @@ -3464,8 +3617,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_accessor->count = - cgltf_json_to_int(tokens+i, json_chunk); + out_accessor->count = cgltf_json_to_size(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0) @@ -3520,7 +3672,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to else if (cgltf_json_strcmp(tokens + i, json_chunk, "sparse") == 0) { out_accessor->is_sparse = 1; - i = cgltf_parse_json_accessor_sparse(options, tokens, i + 1, json_chunk, &out_accessor->sparse); + i = cgltf_parse_json_accessor_sparse(tokens, i + 1, json_chunk, &out_accessor->sparse); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { @@ -3592,6 +3744,8 @@ static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, co static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_view* out_texture_view) { + (void)options; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); out_texture_view->scale = 1.0f; @@ -3616,7 +3770,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const out_texture_view->texcoord = cgltf_json_to_int(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0) { ++i; out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); @@ -3628,28 +3782,12 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture_view->extras); - } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { ++i; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - if(out_texture_view->extensions) - { - return CGLTF_ERROR_JSON; - } - int extensions_size = tokens[i].size; - out_texture_view->extensions_count = 0; - out_texture_view->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); - - if (!out_texture_view->extensions) - { - return CGLTF_ERROR_NOMEM; - } ++i; @@ -3664,7 +3802,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const } else { - i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture_view->extensions[out_texture_view->extensions_count++])); + i = cgltf_skip_json(tokens, i + 1); } if (i < 0) @@ -3701,11 +3839,11 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt if (cgltf_json_strcmp(tokens+i, json_chunk, "metallicFactor") == 0) { ++i; - out_pbr->metallic_factor = + out_pbr->metallic_factor = cgltf_json_to_float(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0) + else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0) { ++i; out_pbr->roughness_factor = @@ -3718,13 +3856,11 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt } else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorTexture") == 0) { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, - &out_pbr->base_color_texture); + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->base_color_texture); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "metallicRoughnessTexture") == 0) { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, - &out_pbr->metallic_roughness_texture); + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->metallic_roughness_texture); } else { @@ -4127,6 +4263,78 @@ static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const* return i; } +static int cgltf_parse_json_anisotropy(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_anisotropy* out_anisotropy) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + int size = tokens[i].size; + ++i; + + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyStrength") == 0) + { + ++i; + out_anisotropy->anisotropy_strength = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyRotation") == 0) + { + ++i; + out_anisotropy->anisotropy_rotation = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_anisotropy->anisotropy_texture); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_dispersion(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_dispersion* out_dispersion) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + int size = tokens[i].size; + ++i; + + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "dispersion") == 0) + { + ++i; + out_dispersion->dispersion = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -4134,11 +4342,11 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token int size = tokens[i].size; ++i; - for (int j = 0; j < size; ++j) + for (int j = 0; j < size; ++j) { CGLTF_CHECK_KEY(tokens[i]); - if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0) + if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0) { i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->uri); } @@ -4218,7 +4426,7 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok = cgltf_json_to_int(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0) { ++i; out_sampler->wrap_t @@ -4268,7 +4476,7 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok out_texture->sampler = CGLTF_PTRINDEX(cgltf_sampler, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0) { ++i; out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk)); @@ -4515,6 +4723,16 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to out_material->has_iridescence = 1; i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_anisotropy") == 0) + { + out_material->has_anisotropy = 1; + i = cgltf_parse_json_anisotropy(options, tokens, i + 1, json_chunk, &out_material->anisotropy); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_dispersion") == 0) + { + out_material->has_dispersion = 1; + i = cgltf_parse_json_dispersion(tokens, i + 1, json_chunk, &out_material->dispersion); + } else { i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++])); @@ -4674,7 +4892,7 @@ static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_ else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_meshopt_compression->count = cgltf_json_to_int(tokens+i, json_chunk); + out_meshopt_compression->count = cgltf_json_to_size(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0) @@ -5963,7 +6181,7 @@ cgltf_size cgltf_num_components(cgltf_type type) { } } -static cgltf_size cgltf_component_size(cgltf_component_type component_type) { +cgltf_size cgltf_component_size(cgltf_component_type component_type) { switch (component_type) { case cgltf_component_type_r_8: @@ -5981,7 +6199,7 @@ static cgltf_size cgltf_component_size(cgltf_component_type component_type) { } } -static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) +cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) { cgltf_size component_size = cgltf_component_size(component_type); if (type == cgltf_type_mat2 && component_size == 1) @@ -6366,6 +6584,8 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_texture.texture, data->textures, data->textures_count); CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count); + + CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count); } for (cgltf_size i = 0; i < data->buffer_views_count; ++i) @@ -6410,7 +6630,6 @@ static int cgltf_fixup_pointers(cgltf_data* data) if (data->nodes[i].has_mesh_gpu_instancing) { - CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.buffer_view, data->buffer_views, data->buffer_views_count); for (cgltf_size m = 0; m < data->nodes[i].mesh_gpu_instancing.attributes_count; ++m) { CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count); @@ -6499,7 +6718,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, * Fills token type and boundaries. */ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - int start, int end) { + ptrdiff_t start, ptrdiff_t end) { token->type = type; token->start = start; token->end = end; @@ -6512,7 +6731,7 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - int start; + ptrdiff_t start; start = parser->pos; @@ -6562,7 +6781,7 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - int start = parser->pos; + ptrdiff_t start = parser->pos; parser->pos++; diff --git a/vendor/cgltf/src/cgltf_write.h b/vendor/cgltf/src/cgltf_write.h index 033b0d1cc..aa648a479 100644 --- a/vendor/cgltf/src/cgltf_write.h +++ b/vendor/cgltf/src/cgltf_write.h @@ -1,7 +1,7 @@ /** * cgltf_write - a single-file glTF 2.0 writer written in C99. * - * Version: 1.13 + * Version: 1.14 * * Website: https://github.com/jkuhlmann/cgltf * @@ -85,6 +85,8 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si #define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13) #define CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING (1 << 14) #define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15) +#define CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY (1 << 16) +#define CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION (1 << 17) typedef struct { char* buffer; @@ -152,7 +154,6 @@ typedef struct { context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ cgltf_write_texture_transform(context, &info.transform); \ } \ - cgltf_write_extras(context, &info.extras); \ cgltf_write_line(context, "}"); } #define CGLTF_WRITE_NORMAL_TEXTURE_INFO(label, info) if (info.texture) { \ @@ -164,7 +165,6 @@ typedef struct { context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ cgltf_write_texture_transform(context, &info.transform); \ } \ - cgltf_write_extras(context, &info.extras); \ cgltf_write_line(context, "}"); } #define CGLTF_WRITE_OCCLUSION_TEXTURE_INFO(label, info) if (info.texture) { \ @@ -176,12 +176,11 @@ typedef struct { context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ cgltf_write_texture_transform(context, &info.transform); \ } \ - cgltf_write_extras(context, &info.extras); \ cgltf_write_line(context, "}"); } #ifndef CGLTF_CONSTS -static const cgltf_size GlbHeaderSize = 12; -static const cgltf_size GlbChunkHeaderSize = 8; +#define GlbHeaderSize 12 +#define GlbChunkHeaderSize 8 static const uint32_t GlbVersion = 2; static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; @@ -360,6 +359,21 @@ static int cgltf_int_from_component_type(cgltf_component_type ctype) } } +static int cgltf_int_from_primitive_type(cgltf_primitive_type ctype) +{ + switch (ctype) + { + case cgltf_primitive_type_points: return 0; + case cgltf_primitive_type_lines: return 1; + case cgltf_primitive_type_line_loop: return 2; + case cgltf_primitive_type_line_strip: return 3; + case cgltf_primitive_type_triangles: return 4; + case cgltf_primitive_type_triangle_strip: return 5; + case cgltf_primitive_type_triangle_fan: return 6; + default: return -1; + } +} + static const char* cgltf_str_from_alpha_mode(cgltf_alpha_mode alpha_mode) { switch (alpha_mode) @@ -455,7 +469,7 @@ static void cgltf_write_asset(cgltf_write_context* context, const cgltf_asset* a static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_primitive* prim) { - cgltf_write_intprop(context, "mode", (int) prim->type, 4); + cgltf_write_intprop(context, "mode", cgltf_int_from_primitive_type(prim->type), 4); CGLTF_WRITE_IDXPROP("indices", prim->indices, context->data->accessors); CGLTF_WRITE_IDXPROP("material", prim->material, context->data->materials); cgltf_write_line(context, "\"attributes\": {"); @@ -641,6 +655,16 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE; } + if (material->has_anisotropy) + { + context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY; + } + + if (material->has_dispersion) + { + context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION; + } + if (material->has_pbr_metallic_roughness) { const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness; @@ -656,7 +680,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater cgltf_write_line(context, "}"); } - if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence) + if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence || material->has_anisotropy || material->has_dispersion) { cgltf_write_line(context, "\"extensions\": {"); if (material->has_clearcoat) @@ -767,6 +791,22 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater CGLTF_WRITE_TEXTURE_INFO("iridescenceThicknessTexture", params->iridescence_thickness_texture); cgltf_write_line(context, "}"); } + if (material->has_anisotropy) + { + cgltf_write_line(context, "\"KHR_materials_anisotropy\": {"); + const cgltf_anisotropy* params = &material->anisotropy; + cgltf_write_floatprop(context, "anisotropyFactor", params->anisotropy_strength, 0.f); + cgltf_write_floatprop(context, "anisotropyRotation", params->anisotropy_rotation, 0.f); + CGLTF_WRITE_TEXTURE_INFO("anisotropyTexture", params->anisotropy_texture); + cgltf_write_line(context, "}"); + } + if (material->has_dispersion) + { + cgltf_write_line(context, "\"KHR_materials_dispersion\": {"); + const cgltf_dispersion* params = &material->dispersion; + cgltf_write_floatprop(context, "dispersion", params->dispersion, 0.f); + cgltf_write_line(context, "}"); + } cgltf_write_line(context, "}"); } @@ -977,7 +1017,6 @@ static void cgltf_write_node(cgltf_write_context* context, const cgltf_node* nod cgltf_write_line(context, "\"EXT_mesh_gpu_instancing\": {"); { - CGLTF_WRITE_IDXPROP("bufferView", node->mesh_gpu_instancing.buffer_view, context->data->buffer_views); cgltf_write_line(context, "\"attributes\": {"); { for (cgltf_size i = 0; i < node->mesh_gpu_instancing.attributes_count; ++i) @@ -1044,14 +1083,11 @@ static void cgltf_write_accessor(cgltf_write_context* context, const cgltf_acces cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0); CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.indices_buffer_view, context->data->buffer_views); cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->sparse.indices_component_type), 0); - cgltf_write_extras(context, &accessor->sparse.indices_extras); cgltf_write_line(context, "}"); cgltf_write_line(context, "\"values\": {"); cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0); CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.values_buffer_view, context->data->buffer_views); - cgltf_write_extras(context, &accessor->sparse.values_extras); cgltf_write_line(context, "}"); - cgltf_write_extras(context, &accessor->sparse.extras); cgltf_write_line(context, "}"); } cgltf_write_extras(context, &accessor->extras); @@ -1123,6 +1159,7 @@ static void cgltf_write_light(cgltf_write_context* context, const cgltf_light* l cgltf_write_floatprop(context, "outerConeAngle", light->spot_outer_cone_angle, 3.14159265358979323846f/4.0f); cgltf_write_line(context, "}"); } + cgltf_write_extras( context, &light->extras ); cgltf_write_line(context, "}"); } @@ -1249,9 +1286,15 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE) { cgltf_write_stritem(context, "KHR_materials_iridescence"); } + if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY) { + cgltf_write_stritem(context, "KHR_materials_anisotropy"); + } if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) { cgltf_write_stritem(context, "EXT_mesh_gpu_instancing"); } + if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION) { + cgltf_write_stritem(context, "KHR_materials_dispersion"); + } } cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data) -- cgit v1.2.3 From 3e63f598a0bdeb5e7a7d4adaffa019a4a6ad99c4 Mon Sep 17 00:00:00 2001 From: shashank Date: Sun, 29 Dec 2024 20:07:36 +0530 Subject: build cgltf lib --- vendor/cgltf/lib/cgltf.lib | Bin 347066 -> 376502 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/vendor/cgltf/lib/cgltf.lib b/vendor/cgltf/lib/cgltf.lib index 0d7ea6f9b..6dddf3baf 100644 Binary files a/vendor/cgltf/lib/cgltf.lib and b/vendor/cgltf/lib/cgltf.lib differ -- cgit v1.2.3 From c9c59edc646082ad9a687a80ccfd4e421d7e15d4 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Sun, 29 Dec 2024 23:35:01 +0100 Subject: encoding/base32: Move tests to base32_test.odin Move existing test procedures to a dedicated test file for better code organization and maintainability. --- core/encoding/base32/base32.odin | 126 --------------------------------- core/encoding/base32/base32_test.odin | 127 ++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 126 deletions(-) create mode 100644 core/encoding/base32/base32_test.odin diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 12b6a426b..60ece7b26 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -1,8 +1,5 @@ package encoding_base32 -import "core:testing" -import "core:bytes" - // @note(zh): Encoding utility for Base32 // A secondary param can be used to supply a custom alphabet to // @link(encode) and a matching decoding table to @link(decode). @@ -225,126 +222,3 @@ decode :: proc( return } - -@(test) -test_base32_decode_valid :: proc(t: ^testing.T) { - // RFC 4648 Section 10 - Test vectors - cases := [?]struct { - input, expected: string, - }{ - {"", ""}, - {"MY======", "f"}, - {"MZXQ====", "fo"}, - {"MZXW6===", "foo"}, - {"MZXW6YQ=", "foob"}, - {"MZXW6YTB", "fooba"}, - {"MZXW6YTBOI======", "foobar"}, - } - - for c in cases { - output, err := decode(c.input) - if output != nil { - defer delete(output) - } - testing.expect_value(t, err, Error.None) - expected := transmute([]u8)c.expected - if output != nil { - testing.expect(t, bytes.equal(output, expected)) - } else { - testing.expect(t, len(c.expected) == 0) - } - } -} - -@(test) -test_base32_encode :: proc(t: ^testing.T) { - // RFC 4648 Section 10 - Test vectors - cases := [?]struct { - input, expected: string, - }{ - {"", ""}, - {"f", "MY======"}, - {"fo", "MZXQ===="}, - {"foo", "MZXW6==="}, - {"foob", "MZXW6YQ="}, - {"fooba", "MZXW6YTB"}, - {"foobar", "MZXW6YTBOI======"}, - } - - for c in cases { - output := encode(transmute([]byte)c.input) - testing.expect(t, output == c.expected) - } -} - -@(test) -test_base32_decode_invalid :: proc(t: ^testing.T) { - // Section 3.2 - Alphabet check - { - // Characters outside alphabet - input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7) - output, err := decode(input) - if output != nil { - defer delete(output) - } - testing.expect_value(t, err, Error.Invalid_Character) - } - { - // Lowercase not allowed - input := "mzxq====" - output, err := decode(input) - if output != nil { - defer delete(output) - } - testing.expect_value(t, err, Error.Invalid_Character) - } - - // Section 4 - Padding requirements - { - // Padding must only be at end - input := "MZ=Q====" - output, err := decode(input) - if output != nil { - defer delete(output) - } - testing.expect_value(t, err, Error.Malformed_Input) - } - { - // Missing padding - input := "MZXQ" // Should be MZXQ==== - output, err := decode(input) - if output != nil { - defer delete(output) - } - testing.expect_value(t, err, Error.Malformed_Input) - } - { - // Incorrect padding length - input := "MZXQ=" // Needs 4 padding chars - output, err := decode(input) - if output != nil { - defer delete(output) - } - testing.expect_value(t, err, Error.Malformed_Input) - } - { - // Too much padding - input := "MY=========" // Extra padding chars - output, err := decode(input) - if output != nil { - defer delete(output) - } - testing.expect_value(t, err, Error.Malformed_Input) - } - - // Section 6 - Block size requirements - { - // Single character (invalid block) - input := "M" - output, err := decode(input) - if output != nil { - defer delete(output) - } - testing.expect_value(t, err, Error.Invalid_Length) - } -} diff --git a/core/encoding/base32/base32_test.odin b/core/encoding/base32/base32_test.odin new file mode 100644 index 000000000..e492f9a85 --- /dev/null +++ b/core/encoding/base32/base32_test.odin @@ -0,0 +1,127 @@ +package encoding_base32 + +import "core:testing" +import "core:bytes" + +@(test) +test_base32_decode_valid :: proc(t: ^testing.T) { + // RFC 4648 Section 10 - Test vectors + cases := [?]struct { + input, expected: string, + }{ + {"", ""}, + {"MY======", "f"}, + {"MZXQ====", "fo"}, + {"MZXW6===", "foo"}, + {"MZXW6YQ=", "foob"}, + {"MZXW6YTB", "fooba"}, + {"MZXW6YTBOI======", "foobar"}, + } + + for c in cases { + output, err := decode(c.input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.None) + expected := transmute([]u8)c.expected + if output != nil { + testing.expect(t, bytes.equal(output, expected)) + } else { + testing.expect(t, len(c.expected) == 0) + } + } +} + +@(test) +test_base32_encode :: proc(t: ^testing.T) { + // RFC 4648 Section 10 - Test vectors + cases := [?]struct { + input, expected: string, + }{ + {"", ""}, + {"f", "MY======"}, + {"fo", "MZXQ===="}, + {"foo", "MZXW6==="}, + {"foob", "MZXW6YQ="}, + {"fooba", "MZXW6YTB"}, + {"foobar", "MZXW6YTBOI======"}, + } + + for c in cases { + output := encode(transmute([]byte)c.input) + testing.expect(t, output == c.expected) + } +} + +@(test) +test_base32_decode_invalid :: proc(t: ^testing.T) { + // Section 3.2 - Alphabet check + { + // Characters outside alphabet + input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7) + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Invalid_Character) + } + { + // Lowercase not allowed + input := "mzxq====" + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Invalid_Character) + } + + // Section 4 - Padding requirements + { + // Padding must only be at end + input := "MZ=Q====" + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Missing padding + input := "MZXQ" // Should be MZXQ==== + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Incorrect padding length + input := "MZXQ=" // Needs 4 padding chars + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Too much padding + input := "MY=========" // Extra padding chars + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + + // Section 6 - Block size requirements + { + // Single character (invalid block) + input := "M" + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Invalid_Length) + } +} -- cgit v1.2.3 From 0d4c0064d961d8a50901afd8c359962b687d1cbd Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Mon, 30 Dec 2024 03:03:50 +0100 Subject: encoding/base32: Add encode->decode roundtrip test Add test_base32_roundtrip() to verify the encode->decode roundtrip preserves data integrity. This test helps ensure our base32 implementation correctly handles the full encode->decode cycle without data loss or corruption. --- core/encoding/base32/base32_test.odin | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/core/encoding/base32/base32_test.odin b/core/encoding/base32/base32_test.odin index e492f9a85..6589abc42 100644 --- a/core/encoding/base32/base32_test.odin +++ b/core/encoding/base32/base32_test.odin @@ -125,3 +125,26 @@ test_base32_decode_invalid :: proc(t: ^testing.T) { testing.expect_value(t, err, Error.Invalid_Length) } } + +@(test) +test_base32_roundtrip :: proc(t: ^testing.T) { + cases := [?]string{ + "", + "f", + "fo", + "foo", + "foob", + "fooba", + "foobar", + } + + for input in cases { + encoded := encode(transmute([]byte)input) + decoded, err := decode(encoded) + if decoded != nil { + defer delete(decoded) + } + testing.expect_value(t, err, Error.None) + testing.expect(t, bytes.equal(decoded, transmute([]byte)input)) + } +} -- cgit v1.2.3 From 591dd8765adb04ff5e0ba66c4c583ea49dbbcc87 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Mon, 30 Dec 2024 12:00:38 +0100 Subject: encoding/base32: Remove incorrect defer delete in encode() Remove premature deallocation of the output buffer which was causing use-after-free behavior. The returned string needs to take ownership of this memory, but the defer delete was freeing it before the string could be used. This fixes issues with encoding that were introduced by overly aggressive memory cleanup in 93238db2. --- core/encoding/base32/base32.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 60ece7b26..c46d4a323 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -54,7 +54,6 @@ DEC_TABLE := [256]u8 { encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { out_length := (len(data) + 4) / 5 * 8 out := make([]byte, out_length, allocator) - defer delete(out) _encode(out, data, ENC_TBL) return string(out[:]) } -- cgit v1.2.3 From 82925097699c389475c5e2d12286a447165ffa65 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Mon, 30 Dec 2024 15:18:38 +0100 Subject: encoding/base32: Add custom alphabet test case Add test case to verify custom alphabet support. The test uses a decimal-uppercase alphabet (0-9, A-V) to test both encoding and decoding with custom tables, including validation. This ensures the encode and decode functions work correctly with custom encoding tables and validation functions as documented. --- core/encoding/base32/base32_test.odin | 75 +++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/core/encoding/base32/base32_test.odin b/core/encoding/base32/base32_test.odin index 6589abc42..968c6c4df 100644 --- a/core/encoding/base32/base32_test.odin +++ b/core/encoding/base32/base32_test.odin @@ -148,3 +148,78 @@ test_base32_roundtrip :: proc(t: ^testing.T) { testing.expect(t, bytes.equal(decoded, transmute([]byte)input)) } } + +@(test) + +test_base32_custom_alphabet :: proc(t: ^testing.T) { + custom_enc_table := [32]byte{ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + } + + custom_dec_table: [256]u8 + for i := 0; i < len(custom_enc_table); i += 1 { + custom_dec_table[custom_enc_table[i]] = u8(i) + } + + /* + custom_dec_table := [256]u8{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10-0x1f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2f + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 0x30-0x3f ('0'-'9') + 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f ('A'-'O') + 25, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x5f ('P'-'V') + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x7f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0-0xaf + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0-0xbf + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0-0xcf + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0-0xdf + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0-0xef + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0-0xff + } + */ + + custom_validate :: proc(c: byte) -> bool { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'V') || c == byte(PADDING) + } + + cases := [?]struct { + input: string, + enc_expected: string, + }{ + {"f", "CO======"}, + {"fo", "CPNG===="}, + {"foo", "CPNMU==="}, + } + + for c in cases { + // Test encoding + encoded := encode(transmute([]byte)c.input, custom_enc_table) + testing.expect(t, encoded == c.enc_expected) + + // Test decoding + decoded, err := decode(encoded, custom_dec_table, custom_validate) + defer if decoded != nil { + delete(decoded) + } + + testing.expect_value(t, err, Error.None) + testing.expect(t, bytes.equal(decoded, transmute([]byte)c.input)) + } + + // Test invalid character detection + { + input := "WXY=====" // Contains chars not in our alphabet + output, err := decode(input, custom_dec_table, custom_validate) + if output != nil { + delete(output) + } + testing.expect_value(t, err, Error.Invalid_Character) + } +} -- cgit v1.2.3 From 5ce6990077bf4d88a2e9617969e610b65b223f89 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Mon, 30 Dec 2024 15:26:42 +0100 Subject: encoding/base32: Add proper cleanup for encoded strings in tests Add defer delete for encoded strings across all test procedures to ensure proper cleanup and prevent memory leaks. This completes the memory management improvements started in 591dd876. --- core/encoding/base32/base32_test.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/encoding/base32/base32_test.odin b/core/encoding/base32/base32_test.odin index 968c6c4df..b032aa122 100644 --- a/core/encoding/base32/base32_test.odin +++ b/core/encoding/base32/base32_test.odin @@ -50,6 +50,7 @@ test_base32_encode :: proc(t: ^testing.T) { for c in cases { output := encode(transmute([]byte)c.input) + defer delete(output) testing.expect(t, output == c.expected) } } @@ -140,6 +141,7 @@ test_base32_roundtrip :: proc(t: ^testing.T) { for input in cases { encoded := encode(transmute([]byte)input) + defer delete(encoded) decoded, err := decode(encoded) if decoded != nil { defer delete(decoded) @@ -150,7 +152,6 @@ test_base32_roundtrip :: proc(t: ^testing.T) { } @(test) - test_base32_custom_alphabet :: proc(t: ^testing.T) { custom_enc_table := [32]byte{ '0', '1', '2', '3', '4', '5', '6', '7', @@ -201,6 +202,7 @@ test_base32_custom_alphabet :: proc(t: ^testing.T) { for c in cases { // Test encoding encoded := encode(transmute([]byte)c.input, custom_enc_table) + defer delete(encoded) testing.expect(t, encoded == c.enc_expected) // Test decoding -- cgit v1.2.3 From 3d25128520c558a5703c478eef61bb23326afe18 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Mon, 30 Dec 2024 15:31:57 +0100 Subject: encoding/base32: Convert files to UTF-8 with Unix line endings --- core/encoding/base32/base32.odin | 447 ++++++++++++++++++++------------------- 1 file changed, 224 insertions(+), 223 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index c46d4a323..d4e4cbe03 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -1,223 +1,224 @@ -package encoding_base32 - -// @note(zh): Encoding utility for Base32 -// A secondary param can be used to supply a custom alphabet to -// @link(encode) and a matching decoding table to @link(decode). -// If none is supplied it just uses the standard Base32 alphabet. -// In case your specific version does not use padding, you may -// truncate it from the encoded output. - -// Error represents errors that can occur during base32 decoding operations. -// See RFC 4648 sections 3.2, 4 and 6. -Error :: enum { - None, - Invalid_Character, // Input contains characters outside the specified alphabet - Invalid_Length, // Input length is not valid for base32 (must be a multiple of 8 with proper padding) - Malformed_Input, // Input has improper structure (wrong padding position or incomplete groups) -} - -Validate_Proc :: #type proc(c: byte) -> bool - -@private -_validate_default :: proc(c: byte) -> bool { - return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7') -} - -ENC_TABLE := [32]byte { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '2', '3', '4', '5', '6', '7', -} - -PADDING :: '=' - -DEC_TABLE := [256]u8 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -} - -encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { - out_length := (len(data) + 4) / 5 * 8 - out := make([]byte, out_length, allocator) - _encode(out, data, ENC_TBL) - return string(out[:]) -} - -@private -_encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) { - out := out - data := data - - for len(data) > 0 { - carry: byte - switch len(data) { - case: - out[7] = ENC_TBL[data[4] & 0x1f] - carry = data[4] >> 5 - fallthrough - case 4: - out[6] = ENC_TBL[carry | (data[3] << 3) & 0x1f] - out[5] = ENC_TBL[(data[3] >> 2) & 0x1f] - carry = data[3] >> 7 - fallthrough - case 3: - out[4] = ENC_TBL[carry | (data[2] << 1) & 0x1f] - carry = (data[2] >> 4) & 0x1f - fallthrough - case 2: - out[3] = ENC_TBL[carry | (data[1] << 4) & 0x1f] - out[2] = ENC_TBL[(data[1] >> 1) & 0x1f] - carry = (data[1] >> 6) & 0x1f - fallthrough - case 1: - out[1] = ENC_TBL[carry | (data[0] << 2) & 0x1f] - out[0] = ENC_TBL[data[0] >> 3] - } - - if len(data) < 5 { - out[7] = byte(PADDING) - if len(data) < 4 { - out[6] = byte(PADDING) - out[5] = byte(PADDING) - if len(data) < 3 { - out[4] = byte(PADDING) - if len(data) < 2 { - out[3] = byte(PADDING) - out[2] = byte(PADDING) - } - } - } - break - } - data = data[5:] - out = out[8:] - } -} - -@(optimization_mode="favor_size") -decode :: proc( - data: string, - DEC_TBL := DEC_TABLE, - validate: Validate_Proc = _validate_default, - allocator := context.allocator) -> (out: []byte, err: Error) { - if len(data) == 0 { - return nil, .None - } - - // Check minimum length requirement first - if len(data) < 2 { - return nil, .Invalid_Length - } - - // Validate characters using provided validation function - for i := 0; i < len(data); i += 1 { - c := data[i] - if c == byte(PADDING) { - break - } - if !validate(c) { - return nil, .Invalid_Character - } - } - - // Validate padding and length - data_len := len(data) - padding_count := 0 - for i := data_len - 1; i >= 0; i -= 1 { - if data[i] != byte(PADDING) { - break - } - padding_count += 1 - } - - // Check for proper padding and length combinations - if padding_count > 0 { - // Verify no padding in the middle - for i := 0; i < data_len - padding_count; i += 1 { - if data[i] == byte(PADDING) { - return nil, .Malformed_Input - } - } - - content_len := data_len - padding_count - mod8 := content_len % 8 - required_padding: int - switch mod8 { - case 2: required_padding = 6 // 2 chars need 6 padding chars - case 4: required_padding = 4 // 4 chars need 4 padding chars - case 5: required_padding = 3 // 5 chars need 3 padding chars - case 7: required_padding = 1 // 7 chars need 1 padding char - case: required_padding = 0 - } - - if required_padding > 0 { - if padding_count != required_padding { - return nil, .Malformed_Input - } - } else if mod8 != 0 { - return nil, .Malformed_Input - } - } else { - // No padding - must be multiple of 8 - if data_len % 8 != 0 { - return nil, .Malformed_Input - } - } - - // Calculate decoded length: 5 bytes for every 8 input chars - input_chars := data_len - padding_count - out_len := input_chars * 5 / 8 - out = make([]byte, out_len, allocator) - defer if err != .None { - delete(out) - } - - // Process input in 8-byte blocks - outi := 0 - for i := 0; i < input_chars; i += 8 { - buf: [8]byte - block_size := min(8, input_chars - i) - - // Decode block - for j := 0; j < block_size; j += 1 { - buf[j] = DEC_TBL[data[i + j]] - } - - // Convert to output bytes based on block size - bytes_to_write := block_size * 5 / 8 - switch block_size { - case 8: - out[outi + 4] = (buf[6] << 5) | buf[7] - fallthrough - case 7: - out[outi + 3] = (buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3) - fallthrough - case 5: - out[outi + 2] = (buf[3] << 4) | (buf[4] >> 1) - fallthrough - case 4: - out[outi + 1] = (buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4) - fallthrough - case 2: - out[outi] = (buf[0] << 3) | (buf[1] >> 2) - } - outi += bytes_to_write - } - - return -} +package encoding_base32 + +// @note(zh): Encoding utility for Base32 +// A secondary param can be used to supply a custom alphabet to +// @link(encode) and a matching decoding table to @link(decode). +// If none is supplied it just uses the standard Base32 alphabet. +// In case your specific version does not use padding, you may +// truncate it from the encoded output. + +// Error represents errors that can occur during base32 decoding operations. +// See RFC 4648 sections 3.2, 4 and 6. +Error :: enum { + None, + Invalid_Character, // Input contains characters outside the specified alphabet + Invalid_Length, // Input length is not valid for base32 (must be a multiple of 8 with proper padding) + Malformed_Input, // Input has improper structure (wrong padding position or incomplete groups) +} + +Validate_Proc :: #type proc(c: byte) -> bool + +@private +_validate_default :: proc(c: byte) -> bool { + return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7') +} + +ENC_TABLE := [32]byte { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '2', '3', '4', '5', '6', '7', +} + +PADDING :: '=' + +DEC_TABLE := [256]u8 { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +} + +encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { + out_length := (len(data) + 4) / 5 * 8 + out := make([]byte, out_length, allocator) + _encode(out, data, ENC_TBL) + return string(out[:]) +} + +@private +_encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) { + out := out + data := data + + for len(data) > 0 { + carry: byte + switch len(data) { + case: + out[7] = ENC_TBL[data[4] & 0x1f] + carry = data[4] >> 5 + fallthrough + case 4: + out[6] = ENC_TBL[carry | (data[3] << 3) & 0x1f] + out[5] = ENC_TBL[(data[3] >> 2) & 0x1f] + carry = data[3] >> 7 + fallthrough + case 3: + out[4] = ENC_TBL[carry | (data[2] << 1) & 0x1f] + carry = (data[2] >> 4) & 0x1f + fallthrough + case 2: + out[3] = ENC_TBL[carry | (data[1] << 4) & 0x1f] + out[2] = ENC_TBL[(data[1] >> 1) & 0x1f] + carry = (data[1] >> 6) & 0x1f + fallthrough + case 1: + out[1] = ENC_TBL[carry | (data[0] << 2) & 0x1f] + out[0] = ENC_TBL[data[0] >> 3] + } + + if len(data) < 5 { + out[7] = byte(PADDING) + if len(data) < 4 { + out[6] = byte(PADDING) + out[5] = byte(PADDING) + if len(data) < 3 { + out[4] = byte(PADDING) + if len(data) < 2 { + out[3] = byte(PADDING) + out[2] = byte(PADDING) + } + } + } + break + } + data = data[5:] + out = out[8:] + } +} + +@(optimization_mode="favor_size") +decode :: proc( + data: string, + DEC_TBL := DEC_TABLE, + validate: Validate_Proc = _validate_default, + allocator := context.allocator) -> (out: []byte, err: Error) +{ + if len(data) == 0 { + return nil, .None + } + + // Check minimum length requirement first + if len(data) < 2 { + return nil, .Invalid_Length + } + + // Validate characters using provided validation function + for i := 0; i < len(data); i += 1 { + c := data[i] + if c == byte(PADDING) { + break + } + if !validate(c) { + return nil, .Invalid_Character + } + } + + // Validate padding and length + data_len := len(data) + padding_count := 0 + for i := data_len - 1; i >= 0; i -= 1 { + if data[i] != byte(PADDING) { + break + } + padding_count += 1 + } + + // Check for proper padding and length combinations + if padding_count > 0 { + // Verify no padding in the middle + for i := 0; i < data_len - padding_count; i += 1 { + if data[i] == byte(PADDING) { + return nil, .Malformed_Input + } + } + + content_len := data_len - padding_count + mod8 := content_len % 8 + required_padding: int + switch mod8 { + case 2: required_padding = 6 // 2 chars need 6 padding chars + case 4: required_padding = 4 // 4 chars need 4 padding chars + case 5: required_padding = 3 // 5 chars need 3 padding chars + case 7: required_padding = 1 // 7 chars need 1 padding char + case: required_padding = 0 + } + + if required_padding > 0 { + if padding_count != required_padding { + return nil, .Malformed_Input + } + } else if mod8 != 0 { + return nil, .Malformed_Input + } + } else { + // No padding - must be multiple of 8 + if data_len % 8 != 0 { + return nil, .Malformed_Input + } + } + + // Calculate decoded length: 5 bytes for every 8 input chars + input_chars := data_len - padding_count + out_len := input_chars * 5 / 8 + out = make([]byte, out_len, allocator) + defer if err != .None { + delete(out) + } + + // Process input in 8-byte blocks + outi := 0 + for i := 0; i < input_chars; i += 8 { + buf: [8]byte + block_size := min(8, input_chars - i) + + // Decode block + for j := 0; j < block_size; j += 1 { + buf[j] = DEC_TBL[data[i + j]] + } + + // Convert to output bytes based on block size + bytes_to_write := block_size * 5 / 8 + switch block_size { + case 8: + out[outi + 4] = (buf[6] << 5) | buf[7] + fallthrough + case 7: + out[outi + 3] = (buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3) + fallthrough + case 5: + out[outi + 2] = (buf[3] << 4) | (buf[4] >> 1) + fallthrough + case 4: + out[outi + 1] = (buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4) + fallthrough + case 2: + out[outi] = (buf[0] << 3) | (buf[1] >> 2) + } + outi += bytes_to_write + } + + return +} -- cgit v1.2.3 From 0d0a202a78032a55be40b3bd08fbb67ce202a612 Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Mon, 30 Dec 2024 22:09:27 +0000 Subject: vendor:vulkan Add support for xlib and xcb --- vendor/vulkan/_gen/create_vulkan_odin_wrapper.py | 35 ++++++++++----- vendor/vulkan/_gen/vulkan_xcb.h | 56 ++++++++++++++++++++++++ vendor/vulkan/_gen/vulkan_xlib.h | 56 ++++++++++++++++++++++++ vendor/vulkan/core.odin | 6 +++ vendor/vulkan/enums.odin | 4 ++ vendor/vulkan/procedures.odin | 16 +++++++ vendor/vulkan/structs.odin | 30 +++++++++++-- 7 files changed, 187 insertions(+), 16 deletions(-) create mode 100644 vendor/vulkan/_gen/vulkan_xcb.h create mode 100644 vendor/vulkan/_gen/vulkan_xlib.h diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index 1a4f96901..a0154328b 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -16,6 +16,8 @@ file_and_urls = [ ("vulkan_macos.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h', False), ("vulkan_ios.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h', False), ("vulkan_wayland.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_wayland.h', False), + ("vulkan_xlib.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xlib.h', False), + ("vulkan_xcb.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xcb.h', False), # Vulkan Video ("vulkan_video_codec_av1std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std.h', False), ("vulkan_video_codec_av1std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std_decode.h', False), @@ -46,17 +48,19 @@ def no_vk(t): t = t.replace('PFN_', 'Proc') t = t.replace('PFN_', 'Proc') - t = re.sub('(?:Vk|VK_)?(\w+)', '\\1', t) + t = re.sub('(?:Vk|VK_)?(\\w+)', '\\1', t) # Vulkan Video - t = re.sub('(?:Std|STD_|VK_STD)?(\w+)', '\\1', t) + t = re.sub('(?:Std|STD_|VK_STD)?(\\w+)', '\\1', t) return t OPAQUE_STRUCTS = """ -wl_surface :: struct {} // Opaque struct defined by Wayland -wl_display :: struct {} // Opaque struct defined by Wayland -IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework -""" +wl_surface :: struct {} // Opaque struct defined by Wayland +wl_display :: struct {} // Opaque struct defined by Wayland +xcb_connection_t :: struct {} // Opaque struct defined by xcb +XlibDisplay :: struct {} // Opaque struct defined by Xlib +IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework +""" def convert_type(t, prev_name, curr_name): table = { @@ -91,6 +95,9 @@ def convert_type(t, prev_name, curr_name): "struct BaseInStructure": "BaseInStructure", "struct wl_display": "wl_display", "struct wl_surface": "wl_surface", + "Display": "XlibDisplay", + "Window": "XlibWindow", + "VisualID": "XlibVisualID", 'v': '', } @@ -106,7 +113,7 @@ def convert_type(t, prev_name, curr_name): elif t.endswith("*"): pointer = "^" ttype = t[:len(t)-1] - elem = convert_type(ttype, prev_name, curr_name) + elem = convert_type(ttype, prev_name, curr_name) if curr_name.endswith("s") or curr_name.endswith("Table"): if prev_name.endswith("Count") or prev_name.endswith("Counts"): @@ -445,7 +452,7 @@ def parse_enums(f): def parse_fake_enums(f): data = re.findall(r"static const Vk(\w+FlagBits2) VK_(\w+?) = (\w+);", src, re.S) - + data.sort(key=lambda x: x[0]) fake_enums = {} @@ -507,7 +514,7 @@ def parse_fake_enums(f): continue ff.append((n, v)) - + max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0]) max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0]) if max_flag_value < max_group_value: @@ -575,13 +582,13 @@ def parse_structs(f): ffields.append(tuple([bit_field_name, bit_field_type, comment])) prev_name = "" continue - + # The second way has many fields that are each 1 bit elif int(fname) == 1: bit_field_type = do_type(bit_field[0], prev_name, fname) ffields.append(tuple(["bitfield", bit_field_type, comment])) break - + if '[' in fname: @@ -919,7 +926,11 @@ when ODIN_OS == .Windows { \t} } -CAMetalLayer :: struct {} +xcb_visualid_t :: u32 +xcb_window_t :: u32 +XlibWindow :: uint +XlibVisualID :: uint +CAMetalLayer :: struct {} MTLBuffer_id :: rawptr MTLTexture_id :: rawptr diff --git a/vendor/vulkan/_gen/vulkan_xcb.h b/vendor/vulkan/_gen/vulkan_xcb.h new file mode 100644 index 000000000..cdf6b5269 --- /dev/null +++ b/vendor/vulkan/_gen/vulkan_xcb.h @@ -0,0 +1,56 @@ +#ifndef VULKAN_XCB_H_ +#define VULKAN_XCB_H_ 1 + +/* +** Copyright 2015-2024 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_xcb_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_xcb_surface 1 +#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( + VkInstance instance, + const VkXcbSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/vulkan/_gen/vulkan_xlib.h b/vendor/vulkan/_gen/vulkan_xlib.h new file mode 100644 index 000000000..b3c3e27d7 --- /dev/null +++ b/vendor/vulkan/_gen/vulkan_xlib.h @@ -0,0 +1,56 @@ +#ifndef VULKAN_XLIB_H_ +#define VULKAN_XLIB_H_ 1 + +/* +** Copyright 2015-2024 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_xlib_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_xlib_surface 1 +#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( + VkInstance instance, + const VkXlibSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + Display* dpy, + VisualID visualID); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/vulkan/core.odin b/vendor/vulkan/core.odin index a335018f9..f90b65008 100644 --- a/vendor/vulkan/core.odin +++ b/vendor/vulkan/core.odin @@ -1161,6 +1161,12 @@ EXT_METAL_OBJECTS_EXTENSION_NAME :: "VK_EXT_metal_objec KHR_wayland_surface :: 1 KHR_WAYLAND_SURFACE_SPEC_VERSION :: 6 KHR_WAYLAND_SURFACE_EXTENSION_NAME :: "VK_KHR_wayland_surface" +KHR_xlib_surface :: 1 +KHR_XLIB_SURFACE_SPEC_VERSION :: 6 +KHR_XLIB_SURFACE_EXTENSION_NAME :: "VK_KHR_xlib_surface" +KHR_xcb_surface :: 1 +KHR_XCB_SURFACE_SPEC_VERSION :: 6 +KHR_XCB_SURFACE_EXTENSION_NAME :: "VK_KHR_xcb_surface" // Handles types Instance :: distinct Handle diff --git a/vendor/vulkan/enums.odin b/vendor/vulkan/enums.odin index 5ac8d1612..a55ba9e58 100644 --- a/vendor/vulkan/enums.odin +++ b/vendor/vulkan/enums.odin @@ -4585,6 +4585,10 @@ WaylandSurfaceCreateFlagsKHR :: distinct bit_set[Wayland WaylandSurfaceCreateFlagKHR :: enum u32 {} Win32SurfaceCreateFlagsKHR :: distinct bit_set[Win32SurfaceCreateFlagKHR; Flags] Win32SurfaceCreateFlagKHR :: enum u32 {} +XcbSurfaceCreateFlagsKHR :: distinct bit_set[XcbSurfaceCreateFlagKHR; Flags] +XcbSurfaceCreateFlagKHR :: enum u32 {} +XlibSurfaceCreateFlagsKHR :: distinct bit_set[XlibSurfaceCreateFlagKHR; Flags] +XlibSurfaceCreateFlagKHR :: enum u32 {} AccessFlags2 :: distinct bit_set[AccessFlag2; Flags64] AccessFlag2 :: enum Flags64 { INDIRECT_COMMAND_READ = 0, diff --git a/vendor/vulkan/procedures.odin b/vendor/vulkan/procedures.odin index dc03275a2..19f70fc85 100644 --- a/vendor/vulkan/procedures.odin +++ b/vendor/vulkan/procedures.odin @@ -36,6 +36,8 @@ ProcCreateMacOSSurfaceMVK :: #type pr ProcCreateMetalSurfaceEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^MetalSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcCreateWaylandSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^WaylandSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcCreateWin32SurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^Win32SurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateXcbSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^XcbSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateXlibSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^XlibSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcDebugReportMessageEXT :: #type proc "system" (instance: Instance, flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring) ProcDestroyDebugReportCallbackEXT :: #type proc "system" (instance: Instance, callback: DebugReportCallbackEXT, pAllocator: ^AllocationCallbacks) ProcDestroyDebugUtilsMessengerEXT :: #type proc "system" (instance: Instance, messenger: DebugUtilsMessengerEXT, pAllocator: ^AllocationCallbacks) @@ -113,6 +115,8 @@ ProcGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR :: #type pr ProcGetPhysicalDeviceVideoFormatPropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pVideoFormatInfo: ^PhysicalDeviceVideoFormatInfoKHR, pVideoFormatPropertyCount: ^u32, pVideoFormatProperties: [^]VideoFormatPropertiesKHR) -> Result ProcGetPhysicalDeviceWaylandPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, display: ^wl_display) -> b32 ProcGetPhysicalDeviceWin32PresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32 +ProcGetPhysicalDeviceXcbPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, connection: ^xcb_connection_t, visual_id: xcb_visualid_t) -> b32 +ProcGetPhysicalDeviceXlibPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, dpy: ^XlibDisplay, visualID: XlibVisualID) -> b32 ProcGetWinrtDisplayNV :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result ProcReleaseDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result ProcSubmitDebugUtilsMessageEXT :: #type proc "system" (instance: Instance, messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT) @@ -730,6 +734,8 @@ CreateMacOSSurfaceMVK: ProcCreateMacO CreateMetalSurfaceEXT: ProcCreateMetalSurfaceEXT CreateWaylandSurfaceKHR: ProcCreateWaylandSurfaceKHR CreateWin32SurfaceKHR: ProcCreateWin32SurfaceKHR +CreateXcbSurfaceKHR: ProcCreateXcbSurfaceKHR +CreateXlibSurfaceKHR: ProcCreateXlibSurfaceKHR DebugReportMessageEXT: ProcDebugReportMessageEXT DestroyDebugReportCallbackEXT: ProcDestroyDebugReportCallbackEXT DestroyDebugUtilsMessengerEXT: ProcDestroyDebugUtilsMessengerEXT @@ -806,6 +812,8 @@ GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR: ProcGetPhysica GetPhysicalDeviceVideoFormatPropertiesKHR: ProcGetPhysicalDeviceVideoFormatPropertiesKHR GetPhysicalDeviceWaylandPresentationSupportKHR: ProcGetPhysicalDeviceWaylandPresentationSupportKHR GetPhysicalDeviceWin32PresentationSupportKHR: ProcGetPhysicalDeviceWin32PresentationSupportKHR +GetPhysicalDeviceXcbPresentationSupportKHR: ProcGetPhysicalDeviceXcbPresentationSupportKHR +GetPhysicalDeviceXlibPresentationSupportKHR: ProcGetPhysicalDeviceXlibPresentationSupportKHR GetWinrtDisplayNV: ProcGetWinrtDisplayNV ReleaseDisplayEXT: ProcReleaseDisplayEXT SubmitDebugUtilsMessageEXT: ProcSubmitDebugUtilsMessageEXT @@ -1423,6 +1431,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CreateMetalSurfaceEXT, "vkCreateMetalSurfaceEXT") set_proc_address(&CreateWaylandSurfaceKHR, "vkCreateWaylandSurfaceKHR") set_proc_address(&CreateWin32SurfaceKHR, "vkCreateWin32SurfaceKHR") + set_proc_address(&CreateXcbSurfaceKHR, "vkCreateXcbSurfaceKHR") + set_proc_address(&CreateXlibSurfaceKHR, "vkCreateXlibSurfaceKHR") set_proc_address(&DebugReportMessageEXT, "vkDebugReportMessageEXT") set_proc_address(&DestroyDebugReportCallbackEXT, "vkDestroyDebugReportCallbackEXT") set_proc_address(&DestroyDebugUtilsMessengerEXT, "vkDestroyDebugUtilsMessengerEXT") @@ -1499,6 +1509,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&GetPhysicalDeviceVideoFormatPropertiesKHR, "vkGetPhysicalDeviceVideoFormatPropertiesKHR") set_proc_address(&GetPhysicalDeviceWaylandPresentationSupportKHR, "vkGetPhysicalDeviceWaylandPresentationSupportKHR") set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR, "vkGetPhysicalDeviceWin32PresentationSupportKHR") + set_proc_address(&GetPhysicalDeviceXcbPresentationSupportKHR, "vkGetPhysicalDeviceXcbPresentationSupportKHR") + set_proc_address(&GetPhysicalDeviceXlibPresentationSupportKHR, "vkGetPhysicalDeviceXlibPresentationSupportKHR") set_proc_address(&GetWinrtDisplayNV, "vkGetWinrtDisplayNV") set_proc_address(&ReleaseDisplayEXT, "vkReleaseDisplayEXT") set_proc_address(&SubmitDebugUtilsMessageEXT, "vkSubmitDebugUtilsMessageEXT") @@ -3879,6 +3891,8 @@ load_proc_addresses_instance :: proc(instance: Instance) { CreateMetalSurfaceEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT") CreateWaylandSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR") CreateWin32SurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR") + CreateXcbSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR") + CreateXlibSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR") DebugReportMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkDebugReportMessageEXT") DestroyDebugReportCallbackEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT") DestroyDebugUtilsMessengerEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT") @@ -3955,6 +3969,8 @@ load_proc_addresses_instance :: proc(instance: Instance) { GetPhysicalDeviceVideoFormatPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceVideoFormatPropertiesKHR") GetPhysicalDeviceWaylandPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR") GetPhysicalDeviceWin32PresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR") + GetPhysicalDeviceXcbPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR") + GetPhysicalDeviceXlibPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR") GetWinrtDisplayNV = auto_cast GetInstanceProcAddr(instance, "vkGetWinrtDisplayNV") ReleaseDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkReleaseDisplayEXT") SubmitDebugUtilsMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkSubmitDebugUtilsMessageEXT") diff --git a/vendor/vulkan/structs.odin b/vendor/vulkan/structs.odin index 3c41d1923..b8ed60d22 100644 --- a/vendor/vulkan/structs.odin +++ b/vendor/vulkan/structs.odin @@ -32,7 +32,11 @@ when ODIN_OS == .Windows { } } -CAMetalLayer :: struct {} +xcb_visualid_t :: u32 +xcb_window_t :: u32 +XlibWindow :: uint +XlibVisualID :: uint +CAMetalLayer :: struct {} MTLBuffer_id :: rawptr MTLTexture_id :: rawptr @@ -8910,6 +8914,22 @@ WaylandSurfaceCreateInfoKHR :: struct { surface: ^wl_surface, } +XlibSurfaceCreateInfoKHR :: struct { + sType: StructureType, + pNext: rawptr, + flags: XlibSurfaceCreateFlagsKHR, + dpy: ^XlibDisplay, + window: XlibWindow, +} + +XcbSurfaceCreateInfoKHR :: struct { + sType: StructureType, + pNext: rawptr, + flags: XcbSurfaceCreateFlagsKHR, + connection: ^xcb_connection_t, + window: xcb_window_t, +} + VideoAV1ColorConfigFlags :: struct { bitfield: u32, } @@ -9753,9 +9773,11 @@ VideoEncodeH265ReferenceInfo :: struct { // Opaque structs -wl_surface :: struct {} // Opaque struct defined by Wayland -wl_display :: struct {} // Opaque struct defined by Wayland -IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework +wl_surface :: struct {} // Opaque struct defined by Wayland +wl_display :: struct {} // Opaque struct defined by Wayland +xcb_connection_t :: struct {} // Opaque struct defined by xcb +XlibDisplay :: struct {} // Opaque struct defined by Xlib +IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework // Aliases PhysicalDeviceVariablePointerFeatures :: PhysicalDeviceVariablePointersFeatures PhysicalDeviceShaderDrawParameterFeatures :: PhysicalDeviceShaderDrawParametersFeatures -- cgit v1.2.3 From bddca04b25bfce0f5bfa80c344ca66e4952d1302 Mon Sep 17 00:00:00 2001 From: CodingChris Date: Mon, 30 Dec 2024 23:20:08 +0100 Subject: added IsZoomed to user32 bindings in sys/windows --- core/sys/windows/user32.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 957d6ab70..da979a3e3 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -51,6 +51,7 @@ foreign user32 { IsWindowVisible :: proc(hwnd: HWND) -> BOOL --- IsWindowEnabled :: proc(hwnd: HWND) -> BOOL --- IsIconic :: proc(hwnd: HWND) -> BOOL --- + IsZoomed :: proc(hwnd: HWND) -> BOOL --- BringWindowToTop :: proc(hWnd: HWND) -> BOOL --- GetTopWindow :: proc(hWnd: HWND) -> HWND --- SetForegroundWindow :: proc(hWnd: HWND) -> BOOL --- -- cgit v1.2.3 From 98967aad7454a1b25e9230b696e4c949d4ac7e27 Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Tue, 31 Dec 2024 02:44:42 +0000 Subject: vendor:vulkan Use vendor:x11/xlib types when available --- vendor/vulkan/_gen/create_vulkan_odin_wrapper.py | 18 +++++++++++++++--- vendor/vulkan/structs.odin | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index a0154328b..b8d7b9464 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -58,7 +58,6 @@ OPAQUE_STRUCTS = """ wl_surface :: struct {} // Opaque struct defined by Wayland wl_display :: struct {} // Opaque struct defined by Wayland xcb_connection_t :: struct {} // Opaque struct defined by xcb -XlibDisplay :: struct {} // Opaque struct defined by Xlib IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework """ @@ -901,6 +900,10 @@ import "core:c" import win32 "core:sys/windows" _ :: win32 + +import "vendor:x11/xlib" +_ :: xlib + when ODIN_OS == .Windows { \tHINSTANCE :: win32.HINSTANCE \tHWND :: win32.HWND @@ -926,10 +929,19 @@ when ODIN_OS == .Windows { \t} } +// We want to use `vendor:x11/xlib` types so we need to match their build constraints. +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { +\tXlibDisplay :: xlib.Display +\tXlibWindow :: xlib.Window +\tXlibVisualID :: xlib.VisualID +} else { +\tXlibDisplay :: struct {} // Opaque struct defined by Xlib +\tXlibWindow :: c.ulong +\tXlibVisualID :: c.ulong +} + xcb_visualid_t :: u32 xcb_window_t :: u32 -XlibWindow :: uint -XlibVisualID :: uint CAMetalLayer :: struct {} MTLBuffer_id :: rawptr diff --git a/vendor/vulkan/structs.odin b/vendor/vulkan/structs.odin index b8ed60d22..3bab29f4e 100644 --- a/vendor/vulkan/structs.odin +++ b/vendor/vulkan/structs.odin @@ -7,6 +7,10 @@ import "core:c" import win32 "core:sys/windows" _ :: win32 + +import "vendor:x11/xlib" +_ :: xlib + when ODIN_OS == .Windows { HINSTANCE :: win32.HINSTANCE HWND :: win32.HWND @@ -32,10 +36,19 @@ when ODIN_OS == .Windows { } } +// We want to use `vendor:x11/xlib` types so we need to match their build constraints. +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { + XlibDisplay :: xlib.Display + XlibWindow :: xlib.Window + XlibVisualID :: xlib.VisualID +} else { + XlibDisplay :: struct {} // Opaque struct defined by Xlib + XlibWindow :: c.ulong + XlibVisualID :: c.ulong +} + xcb_visualid_t :: u32 xcb_window_t :: u32 -XlibWindow :: uint -XlibVisualID :: uint CAMetalLayer :: struct {} MTLBuffer_id :: rawptr @@ -9776,7 +9789,6 @@ VideoEncodeH265ReferenceInfo :: struct { wl_surface :: struct {} // Opaque struct defined by Wayland wl_display :: struct {} // Opaque struct defined by Wayland xcb_connection_t :: struct {} // Opaque struct defined by xcb -XlibDisplay :: struct {} // Opaque struct defined by Xlib IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework // Aliases PhysicalDeviceVariablePointerFeatures :: PhysicalDeviceVariablePointersFeatures -- cgit v1.2.3 From d6f4412dc33bf21607fe97ebfcbd2ba2c81368f1 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 31 Dec 2024 18:18:23 +0100 Subject: encoding/base32: Fix style issues for CI --- core/encoding/base32/base32.odin | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index d4e4cbe03..b6af279ec 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -48,7 +48,7 @@ DEC_TABLE := [256]u8 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { @@ -66,7 +66,7 @@ _encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.al for len(data) > 0 { carry: byte switch len(data) { - case: + case: out[7] = ENC_TBL[data[4] & 0x1f] carry = data[4] >> 5 fallthrough @@ -114,8 +114,7 @@ decode :: proc( data: string, DEC_TBL := DEC_TABLE, validate: Validate_Proc = _validate_default, - allocator := context.allocator) -> (out: []byte, err: Error) -{ + allocator := context.allocator) -> (out: []byte, err: Error) { if len(data) == 0 { return nil, .None } @@ -163,7 +162,7 @@ decode :: proc( case 4: required_padding = 4 // 4 chars need 4 padding chars case 5: required_padding = 3 // 5 chars need 3 padding chars case 7: required_padding = 1 // 7 chars need 1 padding char - case: required_padding = 0 + case: required_padding = 0 } if required_padding > 0 { -- cgit v1.2.3 From fe88c22b1fa3b5090ae74dc358896ef784446469 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Tue, 31 Dec 2024 23:47:33 +0100 Subject: encoding/base32: Fix RFC 4648 references and add RFC reference URL Fix incorrect RFC 4648 section references: - Add RFC URL reference at package level - Update Error enum documentation to reference correct sections: - Invalid_Character: Section 3.3 (non-alphabet characters) - Invalid_Length: Section 6 (base32 block size requirements) - Malformed_Input: Section 3.2 (padding) - Fix test file section references to match correct sections This ensures all RFC references are accurate and adds a link to the source RFC for reference. --- core/encoding/base32/base32.odin | 7 ++++++- core/encoding/base32/base32_test.odin | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index b6af279ec..0b8ec95c4 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -1,3 +1,5 @@ +// Base32 encoding/decoding implementation as specified in RFC 4648. +// [[ More; https://www.rfc-editor.org/rfc/rfc4648.html ]] package encoding_base32 // @note(zh): Encoding utility for Base32 @@ -8,7 +10,10 @@ package encoding_base32 // truncate it from the encoded output. // Error represents errors that can occur during base32 decoding operations. -// See RFC 4648 sections 3.2, 4 and 6. +// As per RFC 4648: +// - Section 3.3: Invalid character handling +// - Section 3.2: Padding requirements +// - Section 6: Base32 encoding specifics (including block size requirements) Error :: enum { None, Invalid_Character, // Input contains characters outside the specified alphabet diff --git a/core/encoding/base32/base32_test.odin b/core/encoding/base32/base32_test.odin index b032aa122..ea41ae36f 100644 --- a/core/encoding/base32/base32_test.odin +++ b/core/encoding/base32/base32_test.odin @@ -57,7 +57,7 @@ test_base32_encode :: proc(t: ^testing.T) { @(test) test_base32_decode_invalid :: proc(t: ^testing.T) { - // Section 3.2 - Alphabet check + // Section 3.3 - Non-alphabet characters { // Characters outside alphabet input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7) @@ -77,7 +77,7 @@ test_base32_decode_invalid :: proc(t: ^testing.T) { testing.expect_value(t, err, Error.Invalid_Character) } - // Section 4 - Padding requirements + // Section 3.2 - Padding requirements { // Padding must only be at end input := "MZ=Q====" @@ -115,7 +115,7 @@ test_base32_decode_invalid :: proc(t: ^testing.T) { testing.expect_value(t, err, Error.Malformed_Input) } - // Section 6 - Block size requirements + // Section 6 - Base32 block size requirements { // Single character (invalid block) input := "M" -- cgit v1.2.3 From c8ad2a4245fb9f0f5a0975e394693333299eb2a7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Jan 2025 15:12:54 +0000 Subject: Support multiple paths for wasm in `foreign import` --- src/check_decl.cpp | 88 ++++++++++++++++++++++++++---------------------------- src/checker.cpp | 34 +++++++++++++++++++++ src/checker.hpp | 1 + 3 files changed, 77 insertions(+), 46 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 60eb030ff..ced886bc9 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -971,6 +971,43 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon } } +gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) { + GB_ASSERT(e != nullptr); + GB_ASSERT(e->kind == Entity_Procedure); + String name = e->Procedure.link_name; + + mutex_lock(&ctx->info->foreign_mutex); + + auto *fp = &ctx->info->foreigns; + StringHashKey key = string_hash_string(name); + Entity **found = string_map_get(fp, key); + if (found && e != *found) { + Entity *f = *found; + TokenPos pos = f->token.pos; + Type *this_type = base_type(e->type); + Type *other_type = base_type(f->type); + if (is_type_proc(this_type) && is_type_proc(other_type)) { + if (!are_signatures_similar_enough(this_type, other_type)) { + error(d->proc_lit, + "Redeclaration of foreign procedure '%.*s' with different type signatures\n" + "\tat %s", + LIT(name), token_pos_to_string(pos)); + } + } else if (!signature_parameter_similar_enough(this_type, other_type)) { + error(d->proc_lit, + "Foreign entity '%.*s' previously declared elsewhere with a different type\n" + "\tat %s", + LIT(name), token_pos_to_string(pos)); + } + } else if (name == "main") { + error(d->proc_lit, "The link name 'main' is reserved for internal use"); + } else { + string_map_set(fp, key, e); + } + + mutex_unlock(&ctx->info->foreign_mutex); +} + gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { GB_ASSERT(e->type == nullptr); if (d->proc_lit->kind != Ast_ProcLit) { @@ -1307,57 +1344,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { name = e->Procedure.link_name; } Entity *foreign_library = init_entity_foreign_library(ctx, e); - - if (is_arch_wasm() && foreign_library != nullptr) { - String module_name = str_lit("env"); - GB_ASSERT (foreign_library->kind == Entity_LibraryName); - if (foreign_library->LibraryName.paths.count != 1) { - error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td", - LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count); - } - - if (foreign_library->LibraryName.paths.count >= 1) { - module_name = foreign_library->LibraryName.paths[0]; - } - - if (!string_ends_with(module_name, str_lit(".o"))) { - name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name); - } - } - e->Procedure.is_foreign = true; e->Procedure.link_name = name; + e->Procedure.foreign_library = foreign_library; - mutex_lock(&ctx->info->foreign_mutex); - - auto *fp = &ctx->info->foreigns; - StringHashKey key = string_hash_string(name); - Entity **found = string_map_get(fp, key); - if (found && e != *found) { - Entity *f = *found; - TokenPos pos = f->token.pos; - Type *this_type = base_type(e->type); - Type *other_type = base_type(f->type); - if (is_type_proc(this_type) && is_type_proc(other_type)) { - if (!are_signatures_similar_enough(this_type, other_type)) { - error(d->proc_lit, - "Redeclaration of foreign procedure '%.*s' with different type signatures\n" - "\tat %s", - LIT(name), token_pos_to_string(pos)); - } - } else if (!signature_parameter_similar_enough(this_type, other_type)) { - error(d->proc_lit, - "Foreign entity '%.*s' previously declared elsewhere with a different type\n" - "\tat %s", - LIT(name), token_pos_to_string(pos)); - } - } else if (name == "main") { - error(d->proc_lit, "The link name 'main' is reserved for internal use"); + if (is_arch_wasm() && foreign_library != nullptr) { + // NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later + mpsc_enqueue(&ctx->info->foreign_decls_to_check, e); } else { - string_map_set(fp, key, e); + check_foreign_procedure(ctx, e, d); } - - mutex_unlock(&ctx->info->foreign_mutex); } else { String name = e->token.string; if (e->Procedure.link_name.len > 0) { diff --git a/src/checker.cpp b/src/checker.cpp index b7cf343f8..7e0a64d75 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1356,6 +1356,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { mpsc_init(&i->required_global_variable_queue, a); // 1<<10); mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10); mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10); + mpsc_init(&i->foreign_decls_to_check, a); // 1<<10); mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used string_map_init(&i->load_directory_cache); @@ -1382,6 +1383,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { mpsc_destroy(&i->required_global_variable_queue); mpsc_destroy(&i->required_foreign_imports_through_force_queue); mpsc_destroy(&i->foreign_imports_to_check_fullpaths); + mpsc_destroy(&i->foreign_decls_to_check); map_destroy(&i->objc_msgSend_types); string_map_destroy(&i->load_file_cache); @@ -5094,6 +5096,38 @@ gb_internal void check_foreign_import_fullpaths(Checker *c) { e->LibraryName.paths = fl->fullpaths; } + + for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_decls_to_check, &e); /**/) { + GB_ASSERT(e != nullptr); + if (e->kind != Entity_Procedure) { + continue; + } + if (!is_arch_wasm()) { + continue; + } + Entity *foreign_library = e->Procedure.foreign_library; + GB_ASSERT(foreign_library != nullptr); + + String name = e->Procedure.link_name; + + String module_name = str_lit("env"); + GB_ASSERT (foreign_library->kind == Entity_LibraryName); + if (foreign_library->LibraryName.paths.count != 1) { + error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td", + LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count); + } + + if (foreign_library->LibraryName.paths.count >= 1) { + module_name = foreign_library->LibraryName.paths[0]; + } + + if (!string_ends_with(module_name, str_lit(".o"))) { + name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name); + } + e->Procedure.link_name = name; + + check_foreign_procedure(&ctx, e, e->decl_info); + } } gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { diff --git a/src/checker.hpp b/src/checker.hpp index 438156f18..036990f29 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -461,6 +461,7 @@ struct CheckerInfo { MPSCQueue required_global_variable_queue; MPSCQueue required_foreign_imports_through_force_queue; MPSCQueue foreign_imports_to_check_fullpaths; + MPSCQueue foreign_decls_to_check; MPSCQueue intrinsics_entry_point_usage; -- cgit v1.2.3 From 049359cae46c1280dc14ea45914638dfb9cb21e0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Jan 2025 15:13:07 +0000 Subject: Clean up box2d `foreign import` --- vendor/box2d/box2d.odin | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/vendor/box2d/box2d.odin b/vendor/box2d/box2d.odin index e7da34a45..83c43800b 100644 --- a/vendor/box2d/box2d.odin +++ b/vendor/box2d/box2d.odin @@ -27,16 +27,8 @@ when !#exists(LIB_PATH) { #panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`") } -when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { - when VECTOR_EXT == "_simd" { - foreign import lib "lib/box2d_wasm_simd.o" - } else { - foreign import lib "lib/box2d_wasm.o" - } -} else { - foreign import lib { - LIB_PATH, - } +foreign import lib { + LIB_PATH, } -- cgit v1.2.3 From 6383fddb59cfcd3f0c8eefb2c700381d14488691 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Jan 2025 15:13:36 +0000 Subject: Disable the os-specific code in `libc` so that non-OS specific platforms still work with it --- vendor/libc/stdio.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/libc/stdio.odin b/vendor/libc/stdio.odin index 10b95b96b..97667a5c8 100644 --- a/vendor/libc/stdio.odin +++ b/vendor/libc/stdio.odin @@ -1,3 +1,4 @@ +#+build !freestanding package odin_libc import "core:c" -- cgit v1.2.3 From 1cf7a56ba700b8a20b4fe94459db416679501793 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Jan 2025 15:13:46 +0000 Subject: General clean up of code --- core/math/rand/rand.odin | 24 ------------------------ core/mem/allocators.odin | 23 ----------------------- core/mem/mem.odin | 9 +-------- core/os/os2/process.odin | 11 ++++++++++- 4 files changed, 11 insertions(+), 56 deletions(-) diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 474277e84..72d9400d7 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -29,30 +29,6 @@ Reset the seed used by the context.random_generator. Inputs: - seed: The seed value -Example: - import "core:math/rand" - import "core:fmt" - - set_global_seed_example :: proc() { - rand.set_global_seed(1) - fmt.println(rand.uint64()) - } - -Possible Output: - - 10 -*/ -@(deprecated="Prefer `rand.reset`") -set_global_seed :: proc(seed: u64) { - runtime.random_generator_reset_u64(context.random_generator, seed) -} - -/* -Reset the seed used by the context.random_generator. - -Inputs: -- seed: The seed value - Example: import "core:math/rand" import "core:fmt" diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 13d509f1e..028be58e3 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -140,14 +140,6 @@ arena_init :: proc(a: ^Arena, data: []byte) { a.temp_count = 0 } -@(deprecated="prefer 'mem.arena_init'") -init_arena :: proc(a: ^Arena, data: []byte) { - a.data = data - a.offset = 0 - a.peak_used = 0 - a.temp_count = 0 -} - /* Allocate memory from an arena. @@ -786,14 +778,6 @@ stack_init :: proc(s: ^Stack, data: []byte) { s.peak_used = 0 } -@(deprecated="prefer 'mem.stack_init'") -init_stack :: proc(s: ^Stack, data: []byte) { - s.data = data - s.prev_offset = 0 - s.curr_offset = 0 - s.peak_used = 0 -} - /* Allocate memory from stack. @@ -1162,13 +1146,6 @@ small_stack_init :: proc(s: ^Small_Stack, data: []byte) { s.peak_used = 0 } -@(deprecated="prefer 'small_stack_init'") -init_small_stack :: proc(s: ^Small_Stack, data: []byte) { - s.data = data - s.offset = 0 - s.peak_used = 0 -} - /* Small stack allocator. diff --git a/core/mem/mem.odin b/core/mem/mem.odin index ccbc77798..b2a7158a1 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -685,11 +685,4 @@ calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, he } } return int(padding) -} - -@(require_results, deprecated="prefer 'slice.clone'") -clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) { - new_slice, _ = make(T, len(slice), allocator, loc) - runtime.copy(new_slice, slice) - return new_slice -} +} \ No newline at end of file diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index 5b5a6e844..c90e3add2 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -290,12 +290,21 @@ process_open :: proc(pid: int, flags := Process_Open_Flags {}) -> (Process, Erro return _process_open(pid, flags) } + +/* +OS-specific process attributes. +*/ +Process_Attributes :: struct { + sys_attr: _Sys_Process_Attributes, +} + /* The description of how a process should be created. */ Process_Desc :: struct { // OS-specific attributes. - sys_attr: _Sys_Process_Attributes, + sys_attr: Process_Attributes, + // The working directory of the process. If the string has length 0, the // working directory is assumed to be the current working directory of the // current process. -- cgit v1.2.3 From 7b334d2bd9e881b450fb19e394d6d71840a62cf9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Jan 2025 17:26:15 +0000 Subject: Add `#branch_location` --- src/check_expr.cpp | 12 +++++++ src/entity.cpp | 1 + src/llvm_backend.hpp | 7 +++- src/llvm_backend_expr.cpp | 12 +++++-- src/llvm_backend_proc.cpp | 6 +++- src/llvm_backend_stmt.cpp | 81 ++++++++++++++++++++++++++++---------------- src/llvm_backend_utility.cpp | 8 ++--- 7 files changed, 89 insertions(+), 38 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cc9483187..fba9b8dad 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8725,6 +8725,18 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A error(node, "#caller_expression may only be used as a default argument parameter"); o->type = t_string; o->mode = Addressing_Value; + } else if (name == "branch_location") { + if (!c->in_defer) { + error(node, "#branch_location may only be used within a 'defer' statement"); + } else if (c->curr_proc_decl) { + Entity *e = c->curr_proc_decl->entity; + if (e != nullptr) { + GB_ASSERT(e->kind == Entity_Procedure); + e->Procedure.uses_branch_location = true; + } + } + o->type = t_source_code_location; + o->mode = Addressing_Value; } else { if (name == "location") { init_core_source_code_location(c->checker); diff --git a/src/entity.cpp b/src/entity.cpp index 0c4a20df4..802b381f9 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -256,6 +256,7 @@ struct Entity { bool entry_point_only : 1; bool has_instrumentation : 1; bool is_memcpy_like : 1; + bool uses_branch_location : 1; } Procedure; struct { Array entities; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e84ffd1cd..8ca11bf28 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -359,6 +359,10 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; + bool uses_branch_location; + TokenPos branch_location_pos; + TokenPos curr_token_pos; + Array variadic_reuses; lbAddr variadic_reuse_base_array_ptr; @@ -444,7 +448,8 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type); gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type); -gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block); +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos); +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node); gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t); gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right); gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining = ProcInlining_none); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 9c325e088..3b238bcd8 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3502,7 +3502,13 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { case_ast_node(bd, BasicDirective, expr); TokenPos pos = bd->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); + String name = bd->name.string; + if (name == "branch_location") { + GB_ASSERT(p->uses_branch_location); + String proc_name = p->entity->token.string; + return lb_emit_source_code_location_as_global(p, proc_name, p->branch_location_pos); + } + GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(name)); case_end; case_ast_node(i, Implicit, expr); @@ -3668,7 +3674,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_start_block(p, else_); - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr); lb_emit_jump(p, block); lb_start_block(p, then); @@ -5493,7 +5499,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_start_block(p, else_); - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr); lb_emit_jump(p, block); lb_start_block(p, then); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 712e13592..7e44a0046 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -125,6 +125,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i // map_init(&p->selector_addr, 0); // map_init(&p->tuple_fix_map, 0); + if (p->entity != nullptr && p->entity->Procedure.uses_branch_location) { + p->uses_branch_location = true; + } + if (p->is_foreign) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); } @@ -757,7 +761,7 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) { if (p->type->Proc.result_count == 0) { instr = LLVMGetLastInstruction(p->curr_block->block); if (!lb_is_instr_terminating(instr)) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, p->body); lb_set_debug_position_to_procedure_end(p); LLVMBuildRetVoid(p->builder); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9a5f25712..a2f0d2f4a 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -208,8 +208,8 @@ gb_internal void lb_open_scope(lbProcedure *p, Scope *s) { } -gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) { - lb_emit_defer_stmts(p, kind, block); +gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node, bool pop_stack=true) { + lb_emit_defer_stmts(p, kind, block, node); GB_ASSERT(p->scope_index > 0); // NOTE(bill): Remove `context`s made in that scope @@ -721,7 +721,7 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node->left); lb_pop_target_list(p); if (check != nullptr) { @@ -854,7 +854,7 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -976,7 +976,7 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1192,7 +1192,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1363,7 +1363,7 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * } - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); } gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) { @@ -1433,6 +1433,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * ast_node(body, BlockStmt, ss->body); isize case_count = body->stmts.count; + Ast *default_clause = nullptr; Slice default_stmts = {}; lbBlock *default_fall = nullptr; lbBlock *default_block = nullptr; @@ -1482,6 +1483,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * if (cc->list.count == 0) { // default case + default_clause = clause; default_stmts = cc->stmts; default_fall = fall; if (switch_instr == nullptr) { @@ -1552,7 +1554,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lb_push_target_list(p, ss->label, done, nullptr, fall); lb_open_scope(p, body->scope); lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); + lb_close_scope(p, lbDeferExit_Default, body, clause); lb_pop_target_list(p); lb_emit_jump(p, done); @@ -1570,13 +1572,13 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lb_push_target_list(p, ss->label, done, nullptr, default_fall); lb_open_scope(p, default_block->scope); lb_build_stmt_list(p, default_stmts); - lb_close_scope(p, lbDeferExit_Default, default_block); + lb_close_scope(p, lbDeferExit_Default, default_block, default_clause); lb_pop_target_list(p); } lb_emit_jump(p, done); lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, done); + lb_close_scope(p, lbDeferExit_Default, done, ss->body); } gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) { @@ -1627,7 +1629,7 @@ gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBl lb_push_target_list(p, label, done, nullptr, nullptr); lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); + lb_close_scope(p, lbDeferExit_Default, body, clause); lb_pop_target_list(p); lb_emit_jump(p, done); @@ -1835,7 +1837,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss lb_emit_jump(p, done); lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, done); + lb_close_scope(p, lbDeferExit_Default, done, ss->body); } @@ -1959,7 +1961,7 @@ gb_internal void lb_build_assignment(lbProcedure *p, Array &lvals, Slice p->in_multi_assignment = prev_in_assignment; } -gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { +gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos) { lbFunctionType *ft = lb_get_function_type(p->module, p->type); bool return_by_pointer = ft->ret.kind == lbArg_Indirect; bool split_returns = ft->multiple_return_original_type != nullptr; @@ -1982,7 +1984,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value); } - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2012,7 +2014,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type); } - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2021,7 +2023,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { } } } -gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results) { +gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results, TokenPos pos) { lb_ensure_abi_function_type(p->module, p); isize return_count = p->type->Proc.result_count; @@ -2029,7 +2031,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return if (return_count == 0) { // No return values - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2138,11 +2140,11 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return GB_ASSERT(result_values.count-1 == result_eps.count); lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]); - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } else { - return lb_build_return_stmt_internal(p, result_values[result_values.count-1]); + return lb_build_return_stmt_internal(p, result_values[result_values.count-1], pos); } } else { @@ -2169,7 +2171,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return } if (return_by_pointer) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } @@ -2177,13 +2179,13 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return res = lb_emit_load(p, res); } } - lb_build_return_stmt_internal(p, res); + lb_build_return_stmt_internal(p, res, pos); } gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { ast_node(is, IfStmt, node); lb_open_scope(p, is->scope); // Scope #1 - defer (lb_close_scope(p, lbDeferExit_Default, nullptr)); + defer (lb_close_scope(p, lbDeferExit_Default, nullptr, node)); lbBlock *then = lb_create_block(p, "if.then"); lbBlock *done = lb_create_block(p, "if.done"); @@ -2234,7 +2236,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt); } lb_emit_jump(p, done); @@ -2251,7 +2253,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt); lb_emit_jump(p, done); } @@ -2322,7 +2324,7 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) { } lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node); } gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) { @@ -2588,7 +2590,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, bs->scope); lb_build_stmt_list(p, bs->stmts); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node); if (done != nullptr) { lb_emit_jump(p, done); @@ -2702,7 +2704,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { case_end; case_ast_node(rs, ReturnStmt, node); - lb_build_return_stmt(p, rs->results); + lb_build_return_stmt(p, rs->results, ast_token(node).pos); case_end; case_ast_node(is, IfStmt, node); @@ -2755,7 +2757,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { } } if (block != nullptr) { - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, node); } lb_emit_jump(p, block); lb_start_block(p, lb_create_block(p, "unreachable")); @@ -2795,7 +2797,13 @@ gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) { } } -gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) { +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos) { + TokenPos prev_token_pos = p->branch_location_pos; + if (p->uses_branch_location) { + p->branch_location_pos = pos; + } + defer (p->branch_location_pos = prev_token_pos); + isize count = p->defer_stmts.count; isize i = count; while (i --> 0) { @@ -2822,6 +2830,21 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo } } +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node) { + TokenPos pos = {}; + if (node) { + if (node->kind == Ast_BlockStmt) { + pos = ast_end_token(node).pos; + } else if (node->kind == Ast_CaseClause) { + pos = ast_end_token(node).pos; + } else { + pos = ast_token(node).pos; + } + } + return lb_emit_defer_stmts(p, kind, block, pos); +} + + gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) { Type *pt = base_type(p->type); GB_ASSERT(pt->kind == Type_Proc); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index a2a0ba4cc..3e4393a8f 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -476,8 +476,8 @@ gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, Ty } } -gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results); -gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res); +gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results, TokenPos pos); +gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos); gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) { lbValue lhs = {}; @@ -506,10 +506,10 @@ gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue con lbValue found = map_must_get(&p->module->values, end_entity); lb_emit_store(p, found, rhs); - lb_build_return_stmt(p, {}); + lb_build_return_stmt(p, {}, ast_token(arg).pos); } else { GB_ASSERT(tuple->variables.count == 1); - lb_build_return_stmt_internal(p, rhs); + lb_build_return_stmt_internal(p, rhs, ast_token(arg).pos); } } lb_start_block(p, continue_block); -- cgit v1.2.3 From 51e90e5e96d409086f96a9c3e1b5fbbdbb44eecc Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 1 Jan 2025 21:07:44 +0100 Subject: Fix for vendor:libc using wrong types for log and sin procs. --- vendor/libc/include/math.h | 4 ++-- vendor/libc/math.odin | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vendor/libc/include/math.h b/vendor/libc/include/math.h index 3f60d698f..9d486da11 100644 --- a/vendor/libc/include/math.h +++ b/vendor/libc/include/math.h @@ -17,5 +17,5 @@ double fabs(double x); int abs(int); double ldexp(double, int); double exp(double); -float log(float); -float sin(float); +double log(double); +double sin(double); diff --git a/vendor/libc/math.odin b/vendor/libc/math.odin index 59f42dd67..af319ac6d 100644 --- a/vendor/libc/math.odin +++ b/vendor/libc/math.odin @@ -90,11 +90,11 @@ exp :: proc "c" (x: f64) -> f64 { } @(require, linkage="strong", link_name="log") -log :: proc "c" (x: f32) -> f32 { +log :: proc "c" (x: f64) -> f64 { return math.ln(x) } @(require, linkage="strong", link_name="sin") -sin :: proc "c" (x: f32) -> f32 { +sin :: proc "c" (x: f64) -> f64 { return math.sin(x) } -- cgit v1.2.3 From f80c33727ca4920e8ffe809c1c79abb093595c76 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 1 Jan 2025 21:15:44 +0100 Subject: Fix for casing error in box2d/wasm.Makefile --- vendor/box2d/wasm.Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/box2d/wasm.Makefile b/vendor/box2d/wasm.Makefile index 929b61aea..c3e3ed25a 100644 --- a/vendor/box2d/wasm.Makefile +++ b/vendor/box2d/wasm.Makefile @@ -10,7 +10,7 @@ SRCS = $(wildcard box2d-$(VERSION)/src/*.c) OBJS_SIMD = $(SRCS:.c=_simd.o) OBJS = $(SRCS:.c=.o) SYSROOT = $(shell odin root)/vendor/libc -CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/Extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT) +CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT) all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean -- cgit v1.2.3 From dc1b75b6c3f493faa4d5ad79770a55c2595a33da Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 1 Jan 2025 22:02:41 +0100 Subject: Added WASM libs for raylib and raygui. Added them to the foreign import blocks, with optional ways to override them. These overrides can be used to use alterantive libs when using for example emscripten. --- vendor/raylib/raygui.odin | 5 +++++ vendor/raylib/raylib.odin | 5 +++++ vendor/raylib/rlgl/rlgl.odin | 5 +++++ vendor/raylib/wasm/libraygui.a | Bin 0 -> 188456 bytes vendor/raylib/wasm/libraylib.a | Bin 0 -> 1388436 bytes 5 files changed, 15 insertions(+) create mode 100644 vendor/raylib/wasm/libraygui.a create mode 100644 vendor/raylib/wasm/libraylib.a diff --git a/vendor/raylib/raygui.odin b/vendor/raylib/raygui.odin index a15467ae8..559437a60 100644 --- a/vendor/raylib/raygui.odin +++ b/vendor/raylib/raygui.odin @@ -3,6 +3,7 @@ package raylib import "core:c" RAYGUI_SHARED :: #config(RAYGUI_SHARED, false) +RAYGUI_WASM_LIB :: #config(RAYGUI_WASM_LIB, "wasm/libraygui.a") when ODIN_OS == .Windows { foreign import lib { @@ -22,6 +23,10 @@ when ODIN_OS == .Windows { "macos/libraygui.dylib" when RAYGUI_SHARED else "macos/libraygui.a", } } +} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { + foreign import lib { + RAYGUI_WASM_LIB, + } } else { foreign import lib "system:raygui" } diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 34a803b99..bb51f105f 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -100,6 +100,7 @@ MAX_TEXT_BUFFER_LENGTH :: #config(RAYLIB_MAX_TEXT_BUFFER_LENGTH, 1024) #assert(size_of(rune) == size_of(c.int)) RAYLIB_SHARED :: #config(RAYLIB_SHARED, false) +RAYLIB_WASM_LIB :: #config(RAYLIB_WASM_LIB, "wasm/libraylib.a") when ODIN_OS == .Windows { @(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt")) @@ -127,6 +128,10 @@ when ODIN_OS == .Windows { "system:OpenGL.framework", "system:IOKit.framework", } +} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { + foreign import lib { + RAYLIB_WASM_LIB, + } } else { foreign import lib "system:raylib" } diff --git a/vendor/raylib/rlgl/rlgl.odin b/vendor/raylib/rlgl/rlgl.odin index 40913cd50..340a983de 100644 --- a/vendor/raylib/rlgl/rlgl.odin +++ b/vendor/raylib/rlgl/rlgl.odin @@ -113,6 +113,7 @@ import rl "../." VERSION :: "5.0" RAYLIB_SHARED :: #config(RAYLIB_SHARED, false) +RAYLIB_WASM_LIB :: #config(RAYLIB_WASM_LIB, "../wasm/libraylib.a") // Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then: // - Compile a separate rlgl library and use that in the foreign import blocks below. @@ -145,6 +146,10 @@ when ODIN_OS == .Windows { "system:OpenGL.framework", "system:IOKit.framework", } +} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { + foreign import lib { + RAYLIB_WASM_LIB, + } } else { foreign import lib "system:raylib" } diff --git a/vendor/raylib/wasm/libraygui.a b/vendor/raylib/wasm/libraygui.a new file mode 100644 index 000000000..cfde78a93 Binary files /dev/null and b/vendor/raylib/wasm/libraygui.a differ diff --git a/vendor/raylib/wasm/libraylib.a b/vendor/raylib/wasm/libraylib.a new file mode 100644 index 000000000..4cdbfa694 Binary files /dev/null and b/vendor/raylib/wasm/libraylib.a differ -- cgit v1.2.3 From ce1f3b34c077f22fd7b929b55d09479002a5ce65 Mon Sep 17 00:00:00 2001 From: jason Date: Thu, 2 Jan 2025 11:03:24 -0500 Subject: Minor fixes + cleanup in os2 and sys/linux Add NOFOLLOW to os2.remove Change Dev from int to u64 and make relavant casts Fix compat64_arg_pair --- core/os/os2/file_linux.odin | 2 +- core/os/os2/path_linux.odin | 2 -- core/sys/linux/helpers.odin | 2 +- core/sys/linux/sys.odin | 6 +++--- core/sys/linux/types.odin | 3 ++- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 20f179f77..a1e3c4afd 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -275,7 +275,7 @@ _remove :: proc(name: string) -> Error { TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS); errno == .NONE { + if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS + {.NOFOLLOW}); errno == .NONE { linux.close(fd) return _get_platform_error(linux.rmdir(name_cstr)) } diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index 7be4121ae..bfdb645ef 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -77,8 +77,6 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { } _remove_all :: proc(path: string) -> Error { - DT_DIR :: 4 - remove_all_dir :: proc(dfd: linux.Fd) -> Error { n := 64 buf := make([]u8, n) diff --git a/core/sys/linux/helpers.odin b/core/sys/linux/helpers.odin index aefc1179e..5273426d8 100644 --- a/core/sys/linux/helpers.odin +++ b/core/sys/linux/helpers.odin @@ -139,7 +139,7 @@ when size_of(int) == 4 { // xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer @(private) compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (hi: uint, lo: uint) { - no_sign := uint(a) + no_sign := u64(a) hi = uint(no_sign >> 32) lo = uint(no_sign & 0xffff_ffff) return diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index 690902f07..88753a788 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -1952,10 +1952,10 @@ sigaltstack :: proc "contextless" (stack: ^Sig_Stack, old_stack: ^Sig_Stack) -> */ mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) { when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { - ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, dev) + ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, cast(uint) dev) return Errno(-ret) } else { - ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, dev) + ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, cast(uint) dev) return Errno(-ret) } } @@ -2586,7 +2586,7 @@ mkdirat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode) -> (Errno) Available since Linux 2.6.16. */ mknodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, dev: Dev) -> (Errno) { - ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, dev) + ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, cast(uint) dev) return Errno(-ret) } diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 08a443bcc..2c01d072d 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -3,7 +3,7 @@ package linux /* Type for storage device handle. */ -Dev :: distinct int +Dev :: distinct u64 /* Type for 32-bit User IDs. @@ -153,6 +153,7 @@ when ODIN_ARCH == .amd64 { uid: Uid, gid: Gid, rdev: Dev, + _: [4]u8, size: i64, blksize: uint, blocks: u64, -- cgit v1.2.3 From 4815d95128ed0a03544b9d89af4cf709b73e1d96 Mon Sep 17 00:00:00 2001 From: Leo Zurbriggen Date: Thu, 2 Jan 2025 18:08:06 +0100 Subject: move GetCommPorts to correct foreign block --- core/sys/windows/kernel32.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 8be50bceb..ff9d84959 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -109,7 +109,6 @@ foreign kernel32 { ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL --- GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- - GetCommPorts :: proc(lpPortNumbers: PULONG, uPortNumbersCount: ULONG, puPortNumbersFound: PULONG) -> ULONG --- GetCommandLineW :: proc() -> LPCWSTR --- GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- GetCurrentProcess :: proc() -> HANDLE --- @@ -1068,6 +1067,7 @@ foreign one_core { PageProtection: ULONG, PreferredNode: ULONG, ) -> PVOID --- + GetCommPorts :: proc(lpPortNumbers: PULONG, uPortNumbersCount: ULONG, puPortNumbersFound: PULONG) -> ULONG --- } -- cgit v1.2.3 From 074bef7bafbf4b111ca1bc245dda21ac86810b13 Mon Sep 17 00:00:00 2001 From: jason Date: Thu, 2 Jan 2025 14:50:45 -0500 Subject: Fix sys/linux 64 bit arguments on 32 bit systems Reverese return values of compat64_arg_pair Add register alignment to specific arm32 system calls --- core/os/os2/file_linux.odin | 3 +++ core/sys/linux/helpers.odin | 2 +- core/sys/linux/sys.odin | 25 ++++++++++++++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index a1e3c4afd..ad2892f40 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -80,6 +80,9 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err // terminal would be incredibly rare. This has no effect on files while // allowing us to open serial devices. sys_flags: linux.Open_Flags = {.NOCTTY, .CLOEXEC} + when size_of(rawptr) == 4 { + sys_flags += {.LARGEFILE} + } switch flags & (O_RDONLY|O_WRONLY|O_RDWR) { case O_RDONLY: case O_WRONLY: sys_flags += {.WRONLY} diff --git a/core/sys/linux/helpers.odin b/core/sys/linux/helpers.odin index 5273426d8..9a7550d57 100644 --- a/core/sys/linux/helpers.odin +++ b/core/sys/linux/helpers.odin @@ -138,7 +138,7 @@ errno_unwrap :: proc {errno_unwrap2, errno_unwrap3} when size_of(int) == 4 { // xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer @(private) - compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (hi: uint, lo: uint) { + compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (lo: uint, hi: uint) { no_sign := u64(a) hi = uint(no_sign >> 32) lo = uint(no_sign & 0xffff_ffff) diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index 88753a788..2117d7d43 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -151,7 +151,8 @@ lseek :: proc "contextless" (fd: Fd, off: i64, whence: Seek_Whence) -> (i64, Err return errno_unwrap(ret, i64) } else { result: i64 = --- - ret := syscall(SYS__llseek, fd, compat64_arg_pair(off), &result, whence) + lo, hi := compat64_arg_pair(off) + ret := syscall(SYS__llseek, fd, hi, lo, &result, whence) return result, Errno(-ret) } } @@ -251,7 +252,11 @@ ioctl :: proc "contextless" (fd: Fd, request: u32, arg: uintptr) -> (uintptr) { Available since Linux 2.2. */ pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) { - ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) + when ODIN_ARCH == .arm32 { + ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), 0, compat64_arg_pair(offset)) + } else { + ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) + } return errno_unwrap(ret, int) } @@ -261,7 +266,11 @@ pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) { Available since Linux 2.2. */ pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) { - ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) + when ODIN_ARCH == .arm32 { + ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), 0, compat64_arg_pair(offset)) + } else { + ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) + } return errno_unwrap(ret, int) } @@ -1127,7 +1136,10 @@ fdatasync :: proc "contextless" (fd: Fd) -> (Errno) { On 32-bit architectures available since Linux 2.4. */ truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) { - when size_of(int) == 4 { + when ODIN_ARCH == .arm32 { + ret := syscall(SYS_truncate64, cast(rawptr) name, 0, compat64_arg_pair(length)) + return Errno(-ret) + } else when size_of(int) == 4 { ret := syscall(SYS_truncate64, cast(rawptr) name, compat64_arg_pair(length)) return Errno(-ret) } else { @@ -1141,7 +1153,10 @@ truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) { On 32-bit architectures available since 2.4. */ ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) { - when size_of(int) == 4 { + when ODIN_ARCH == .arm32 { + ret := syscall(SYS_ftruncate64, fd, 0, compat64_arg_pair(length)) + return Errno(-ret) + } else when size_of(int) == 4 { ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length)) return Errno(-ret) } else { -- cgit v1.2.3 From 0b0ae52be539ae195c0ee70674a0e87581bc9696 Mon Sep 17 00:00:00 2001 From: Despereaux Polacre Date: Thu, 2 Jan 2025 21:31:34 +0100 Subject: add default -I and -L paths for OpenBSD --- build_odin.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_odin.sh b/build_odin.sh index 3547689d5..d909de5c8 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -110,8 +110,8 @@ Linux) LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN" ;; OpenBSD) - CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" - LDFLAGS="$LDFLAGS -liconv" + CXXFLAGS="$CXXFLAGS -I/usr/local/include $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS -L/usr/local/lib -liconv" LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" ;; Haiku) -- cgit v1.2.3 From 1221e393f7e1ab5efaafdc4c168f2b3467efd2d2 Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 3 Jan 2025 09:29:39 -0500 Subject: add 32 bit Sig_Info and remove ppoll_time64 call --- core/sys/linux/sys.odin | 9 +- core/sys/linux/types.odin | 219 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 156 insertions(+), 72 deletions(-) diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index 2117d7d43..fee385fe8 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -2699,13 +2699,8 @@ faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) -> Available since Linux 2.6.16. */ ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (i32, Errno) { - when size_of(int) == 8 { - ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) - return errno_unwrap(ret, i32) - } else { - ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) - return errno_unwrap(ret, i32) - } + ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) + return errno_unwrap(ret, i32) } // TODO(flysand): unshare diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 2c01d072d..dcc72f72b 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -517,79 +517,79 @@ Pid_FD_Flags :: bit_set[Pid_FD_Flags_Bits; i32] Sig_Set :: [_SIGSET_NWORDS]uint @private SI_MAX_SIZE :: 128 -@private SI_ARCH_PREAMBLE :: 4 * size_of(i32) +@private SI_ARCH_PREAMBLE :: 4 * size_of(i32) when size_of(rawptr) == 8 else 3 * size_of(i32) @private SI_PAD_SIZE :: SI_MAX_SIZE - SI_ARCH_PREAMBLE Sig_Handler_Fn :: #type proc "c" (sig: Signal) Sig_Restore_Fn :: #type proc "c" () -> ! -Sig_Info :: struct #packed { - signo: Signal, - errno: Errno, - code: i32, - _pad0: i32, - using _union: struct #raw_union { - _pad1: [SI_PAD_SIZE]u8, - using _kill: struct { - pid: Pid, /* sender's pid */ - uid: Uid, /* sender's uid */ - }, - using _timer: struct { - timerid: i32, /* timer id */ - overrun: i32, /* overrun count */ - value: Sig_Val, /* timer value */ - }, - /* POSIX.1b signals */ - using _rt: struct { - _pid0: Pid, /* sender's pid */ - _uid0: Uid, /* sender's uid */ - }, - /* SIGCHLD */ - using _sigchld: struct { - _pid1: Pid, /* which child */ - _uid1: Uid, /* sender's uid */ - status: i32, /* exit code */ - utime: uint, - stime: uint, //clock_t - }, - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - using _sigfault: struct { - addr: rawptr, /* faulting insn/memory ref. */ - using _: struct #raw_union { - trapno: i32, /* Trap number that caused signal */ - addr_lsb: i16, /* LSB of the reported address */ - using _addr_bnd: struct { - _pad2: u64, - lower: rawptr, /* lower bound during fault */ - upper: rawptr, /* upper bound during fault */ - }, - using _addr_pkey: struct { - _pad3: u64, - pkey: u32, /* protection key on PTE that faulted */ - }, - using _perf: struct { - perf_data: u64, - perf_type: u32, - perf_flags: u32, +when size_of(rawptr) == 8 { + Sig_Info :: struct #packed { + signo: Signal, + errno: Errno, + code: i32, + _pad0: i32, + using _union: struct #raw_union { + _pad1: [SI_PAD_SIZE]u8, + using _kill: struct { + pid: Pid, /* sender's pid */ + uid: Uid, /* sender's uid */ + }, + using _timer: struct { + timerid: i32, /* timer id */ + overrun: i32, /* overrun count */ + value: Sig_Val, /* timer value */ + }, + /* POSIX.1b signals */ + using _rt: struct { + _pid0: Pid, /* sender's pid */ + _uid0: Uid, /* sender's uid */ + }, + /* SIGCHLD */ + using _sigchld: struct { + _pid1: Pid, /* which child */ + _uid1: Uid, /* sender's uid */ + status: i32, /* exit code */ + utime: uint, + stime: uint, //clock_t + }, + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + using _sigfault: struct { + addr: rawptr, /* faulting insn/memory ref. */ + using _: struct #raw_union { + trapno: i32, /* Trap number that caused signal */ + addr_lsb: i16, /* LSB of the reported address */ + using _addr_bnd: struct { + _pad2: u64, + lower: rawptr, /* lower bound during fault */ + upper: rawptr, /* upper bound during fault */ + }, + using _addr_pkey: struct { + _pad3: u64, + pkey: u32, /* protection key on PTE that faulted */ + }, + using _perf: struct { + perf_data: u64, + perf_type: u32, + perf_flags: u32, + }, }, }, + /* SIGPOLL */ + using _sigpoll: struct { + band: int, /* POLL_IN, POLL_OUT, POLL_MSG */ + fd: Fd, + }, + /* SIGSYS */ + using _sigsys: struct { + call_addr: rawptr, /* calling user insn */ + syscall: i32, /* triggering system call number */ + arch: u32, /* AUDIT_ARCH_* of syscall */ + }, }, - /* SIGPOLL */ - using _sigpoll: struct { - band: int, /* POLL_IN, POLL_OUT, POLL_MSG */ - fd: Fd, - }, - /* SIGSYS */ - using _sigsys: struct { - call_addr: rawptr, /* calling user insn */ - syscall: i32, /* triggering system call number */ - arch: u32, /* AUDIT_ARCH_* of syscall */ - }, - }, -} + } -#assert(size_of(Sig_Info) == 128) -when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + #assert(size_of(Sig_Info) == 128) #assert(offset_of(Sig_Info, signo) == 0x00) #assert(offset_of(Sig_Info, errno) == 0x04) #assert(offset_of(Sig_Info, code) == 0x08) @@ -616,7 +616,96 @@ when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { #assert(offset_of(Sig_Info, syscall) == 0x18) #assert(offset_of(Sig_Info, arch) == 0x1C) } else { - // TODO + Sig_Info :: struct { + signo: Signal, + errno: Errno, + code: i32, + using _union: struct #raw_union { + _pad1: [SI_PAD_SIZE]u8, + using _kill: struct { + pid: Pid, /* sender's pid */ + uid: Uid, /* sender's uid */ + }, + using _timer: struct { + timerid: i32, /* timer id */ + overrun: i32, /* overrun count */ + value: Sig_Val, /* timer value */ + }, + /* POSIX.1b signals */ + using _rt: struct { + _pid0: Pid, /* sender's pid */ + _uid0: Uid, /* sender's uid */ + }, + /* SIGCHLD */ + using _sigchld: struct { + _pid1: Pid, /* which child */ + _uid1: Uid, /* sender's uid */ + status: i32, /* exit code */ + utime: uint, + stime: uint, //clock_t + }, + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + using _sigfault: struct { + addr: rawptr, /* faulting insn/memory ref. */ + using _: struct #raw_union { + trapno: i32, /* Trap number that caused signal */ + addr_lsb: i16, /* LSB of the reported address */ + using _addr_bnd: struct { + _pad2: u32, + lower: rawptr, /* lower bound during fault */ + upper: rawptr, /* upper bound during fault */ + }, + using _addr_pkey: struct { + _pad3: u32, + pkey: u32, /* protection key on PTE that faulted */ + }, + using _perf: struct { + perf_data: u32, + perf_type: u32, + perf_flags: u32, + }, + }, + }, + /* SIGPOLL */ + using _sigpoll: struct { + band: int, /* POLL_IN, POLL_OUT, POLL_MSG */ + fd: Fd, + }, + /* SIGSYS */ + using _sigsys: struct { + call_addr: rawptr, /* calling user insn */ + syscall: i32, /* triggering system call number */ + arch: u32, /* AUDIT_ARCH_* of syscall */ + }, + }, + } + + #assert(size_of(Sig_Info) == 128) + #assert(offset_of(Sig_Info, signo) == 0x00) + #assert(offset_of(Sig_Info, errno) == 0x04) + #assert(offset_of(Sig_Info, code) == 0x08) + #assert(offset_of(Sig_Info, pid) == 0x0c) + #assert(offset_of(Sig_Info, uid) == 0x10) + #assert(offset_of(Sig_Info, timerid) == 0x0c) + #assert(offset_of(Sig_Info, overrun) == 0x10) + #assert(offset_of(Sig_Info, value) == 0x14) + #assert(offset_of(Sig_Info, status) == 0x14) + #assert(offset_of(Sig_Info, utime) == 0x18) + #assert(offset_of(Sig_Info, stime) == 0x1c) + #assert(offset_of(Sig_Info, addr) == 0x0c) + #assert(offset_of(Sig_Info, addr_lsb) == 0x10) + #assert(offset_of(Sig_Info, trapno) == 0x10) + #assert(offset_of(Sig_Info, lower) == 0x14) + #assert(offset_of(Sig_Info, upper) == 0x18) + #assert(offset_of(Sig_Info, pkey) == 0x14) + #assert(offset_of(Sig_Info, perf_data) == 0x10) + #assert(offset_of(Sig_Info, perf_type) == 0x14) + #assert(offset_of(Sig_Info, perf_flags) == 0x18) + #assert(offset_of(Sig_Info, band) == 0x0c) + #assert(offset_of(Sig_Info, fd) == 0x10) + #assert(offset_of(Sig_Info, call_addr) == 0x0c) + #assert(offset_of(Sig_Info, syscall) == 0x10) + #assert(offset_of(Sig_Info, arch) == 0x14) } SIGEV_MAX_SIZE :: 64 -- cgit v1.2.3 From e3de02eaa8b69ae615c3df1177f44f326ca5ac44 Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:33:34 +0000 Subject: runtime: map_cell_index_static produced wrong results when the number of elements per cell was a power of 2 --- base/runtime/dynamic_map_internal.odin | 10 +++++----- tests/core/runtime/test_core_runtime.odin | 26 +++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/base/runtime/dynamic_map_internal.odin b/base/runtime/dynamic_map_internal.odin index 3dded7716..281d4b88e 100644 --- a/base/runtime/dynamic_map_internal.odin +++ b/base/runtime/dynamic_map_internal.odin @@ -161,11 +161,11 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T // Compute the integer log 2 of N, this is the shift amount to index the // correct cell. Odin's intrinsics.count_leading_zeros does not produce a // constant, hence this approach. We only need to check up to N = 64. - SHIFT :: 1 when N < 2 else - 2 when N < 4 else - 3 when N < 8 else - 4 when N < 16 else - 5 when N < 32 else 6 + SHIFT :: 1 when N == 2 else + 2 when N == 4 else + 3 when N == 8 else + 4 when N == 16 else + 5 when N == 32 else 6 #assert(SHIFT <= MAP_CACHE_LINE_LOG2) // Unique case, no need to index data here since only one element. when N == 1 { diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin index 84fd044cf..bd641ab3a 100644 --- a/tests/core/runtime/test_core_runtime.odin +++ b/tests/core/runtime/test_core_runtime.odin @@ -63,4 +63,28 @@ test_init_cap_map_dynarray :: proc(t: ^testing.T) { defer delete(d2) testing.expect(t, cap(d2) == 0) testing.expect(t, d2.allocator.procedure == ally.procedure) -} \ No newline at end of file +} + +@(test) +test_map_get :: proc(t: ^testing.T) { + m := map[int][3]int{ + 1 = {10, 100, 1000}, + 2 = {20, 200, 2000}, + 3 = {30, 300, 3000}, + } + + k1, v1, ok1 := runtime.map_get(m, 1) + testing.expect_value(t, k1, 1) + testing.expect_value(t, v1, [3]int{10, 100, 1000}) + testing.expect_value(t, ok1, true) + + k2, v2, ok2 := runtime.map_get(m, 2) + testing.expect_value(t, k2, 2) + testing.expect_value(t, v2, [3]int{20, 200, 2000}) + testing.expect_value(t, ok2, true) + + k3, v3, ok3 := runtime.map_get(m, 3) + testing.expect_value(t, k3, 3) + testing.expect_value(t, v3, [3]int{30, 300, 3000}) + testing.expect_value(t, ok3, true) +} -- cgit v1.2.3 From 555bca2cb4adf964c97b333646c432cd8fa9392a Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:46:02 +0000 Subject: fix test leaks --- tests/core/runtime/test_core_runtime.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin index bd641ab3a..ccadcec27 100644 --- a/tests/core/runtime/test_core_runtime.odin +++ b/tests/core/runtime/test_core_runtime.odin @@ -72,6 +72,7 @@ test_map_get :: proc(t: ^testing.T) { 2 = {20, 200, 2000}, 3 = {30, 300, 3000}, } + defer delete(m) k1, v1, ok1 := runtime.map_get(m, 1) testing.expect_value(t, k1, 1) -- cgit v1.2.3 From c93e096d8f39cc97739e15a32f48ecfe83829593 Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Fri, 3 Jan 2025 16:50:05 +0000 Subject: fix N=1 and cleanup tests --- base/runtime/dynamic_map_internal.odin | 12 ++--- tests/core/runtime/test_core_runtime.odin | 81 +++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/base/runtime/dynamic_map_internal.odin b/base/runtime/dynamic_map_internal.odin index 281d4b88e..4e22aa25c 100644 --- a/base/runtime/dynamic_map_internal.odin +++ b/base/runtime/dynamic_map_internal.odin @@ -158,6 +158,11 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T } else when (N & (N - 1)) == 0 && N <= 8*size_of(uintptr) { // Likely case, N is a power of two because T is a power of two. + // Unique case, no need to index data here since only one element. + when N == 1 { + return &cells[index].data[0] + } + // Compute the integer log 2 of N, this is the shift amount to index the // correct cell. Odin's intrinsics.count_leading_zeros does not produce a // constant, hence this approach. We only need to check up to N = 64. @@ -167,12 +172,7 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T 4 when N == 16 else 5 when N == 32 else 6 #assert(SHIFT <= MAP_CACHE_LINE_LOG2) - // Unique case, no need to index data here since only one element. - when N == 1 { - return &cells[index >> SHIFT].data[0] - } else { - return &cells[index >> SHIFT].data[index & (N - 1)] - } + return &cells[index >> SHIFT].data[index & (N - 1)] } else { // Least likely (and worst case), we pay for a division operation but we // assume the compiler does not actually generate a division. N will be in the diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin index ccadcec27..d2ced2504 100644 --- a/tests/core/runtime/test_core_runtime.odin +++ b/tests/core/runtime/test_core_runtime.odin @@ -67,25 +67,66 @@ test_init_cap_map_dynarray :: proc(t: ^testing.T) { @(test) test_map_get :: proc(t: ^testing.T) { - m := map[int][3]int{ - 1 = {10, 100, 1000}, - 2 = {20, 200, 2000}, - 3 = {30, 300, 3000}, + check :: proc(t: ^testing.T, m: map[$K]$V, loc := #caller_location) { + for k, v in m { + got_key, got_val, ok := runtime.map_get(m, k) + testing.expect_value(t, got_key, k, loc = loc) + testing.expect_value(t, got_val, v, loc = loc) + testing.expect(t, ok, loc = loc) + } + } + + // small keys & values + { + m := map[int]int{ + 1 = 10, + 2 = 20, + 3 = 30, + } + defer delete(m) + check(t, m) + } + + // small keys; 2 values per cell + { + m := map[int][3]int{ + 1 = [3]int{10, 100, 1000}, + 2 = [3]int{20, 200, 2000}, + 3 = [3]int{30, 300, 3000}, + } + defer delete(m) + check(t, m) + } + + // 2 keys per cell; small values + { + m := map[[3]int]int{ + [3]int{10, 100, 1000} = 1, + [3]int{20, 200, 2000} = 2, + [3]int{30, 300, 3000} = 3, + } + defer delete(m) + check(t, m) + } + + // small keys; value bigger than a chacheline + { + m := map[int][9]int{ + 1 = [9]int{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}, + 2 = [9]int{20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000}, + 3 = [9]int{30, 300, 3000, 30000, 300000, 3000000, 30000000, 300000000, 3000000000}, + } + defer delete(m) + check(t, m) + } + // keys bigger than a chacheline; small values + { + m := map[[9]int]int{ + [9]int{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000} = 1, + [9]int{20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000} = 2, + [9]int{30, 300, 3000, 30000, 300000, 3000000, 30000000, 300000000, 3000000000} = 3, + } + defer delete(m) + check(t, m) } - defer delete(m) - - k1, v1, ok1 := runtime.map_get(m, 1) - testing.expect_value(t, k1, 1) - testing.expect_value(t, v1, [3]int{10, 100, 1000}) - testing.expect_value(t, ok1, true) - - k2, v2, ok2 := runtime.map_get(m, 2) - testing.expect_value(t, k2, 2) - testing.expect_value(t, v2, [3]int{20, 200, 2000}) - testing.expect_value(t, ok2, true) - - k3, v3, ok3 := runtime.map_get(m, 3) - testing.expect_value(t, k3, 3) - testing.expect_value(t, v3, [3]int{30, 300, 3000}) - testing.expect_value(t, ok3, true) } -- cgit v1.2.3 From 36b5ca9176990617c938e2b070981895be311bb0 Mon Sep 17 00:00:00 2001 From: VladPavliuk Date: Fri, 3 Jan 2025 18:52:39 +0200 Subject: Extend win32 types --- core/sys/windows/kernel32.odin | 4 ++++ core/sys/windows/types.odin | 28 +++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 8be50bceb..219b6b4fe 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -239,6 +239,10 @@ foreign kernel32 { hThread: HANDLE, lpContext: LPCONTEXT, ) -> BOOL --- + SetThreadContext :: proc( + hThread: HANDLE, + lpContext: LPCONTEXT, + ) -> BOOL --- CreateProcessW :: proc( lpApplicationName: LPCWSTR, lpCommandLine: LPWSTR, diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index e1ace4133..15b24a094 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -143,6 +143,7 @@ LPWSAPROTOCOL_INFO :: ^WSAPROTOCOL_INFO LPSTR :: ^CHAR LPWSTR :: ^WCHAR OLECHAR :: WCHAR +BSTR :: ^OLECHAR LPOLESTR :: ^OLECHAR LPCOLESTR :: LPCSTR LPFILETIME :: ^FILETIME @@ -2694,12 +2695,24 @@ EXCEPTION_MAXIMUM_PARAMETERS :: 15 EXCEPTION_DATATYPE_MISALIGNMENT :: 0x80000002 EXCEPTION_BREAKPOINT :: 0x80000003 +EXCEPTION_SINGLE_STEP :: 0x80000004 EXCEPTION_ACCESS_VIOLATION :: 0xC0000005 EXCEPTION_ILLEGAL_INSTRUCTION :: 0xC000001D EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C +EXCEPTION_FLT_DENORMAL_OPERAND :: 0xC000008D +EXCEPTION_FLT_DIVIDE_BY_ZERO :: 0xC000008E +EXCEPTION_FLT_INEXACT_RESULT :: 0xC000008F +EXCEPTION_FLT_INVALID_OPERATION :: 0xC0000090 +EXCEPTION_FLT_OVERFLOW :: 0xC0000091 +EXCEPTION_FLT_STACK_CHECK :: 0xC0000092 +EXCEPTION_FLT_UNDERFLOW :: 0xC0000093 EXCEPTION_INT_DIVIDE_BY_ZERO :: 0xC0000094 EXCEPTION_INT_OVERFLOW :: 0xC0000095 +EXCEPTION_PRIV_INSTRUCTION :: 0xC0000096 +EXCEPTION_IN_PAGE_ERROR :: 0xC0000006 +EXCEPTION_NONCONTINUABLE_EXCEPTION :: 0xC0000025 EXCEPTION_STACK_OVERFLOW :: 0xC00000FD +EXCEPTION_INVALID_DISPOSITION :: 0xC0000026 STATUS_PRIVILEGED_INSTRUCTION :: 0xC0000096 @@ -3416,7 +3429,7 @@ TIME_ZONE_INFORMATION :: struct { } -@(private="file") +// @(private="file") IMAGE_DOS_HEADER :: struct { e_magic: WORD, e_cblp: WORD, @@ -3534,6 +3547,19 @@ IMAGE_EXPORT_DIRECTORY :: struct { AddressOfNameOrdinals: DWORD, // RVA from base of image } +IMAGE_DEBUG_DIRECTORY :: struct { + Characteristics: DWORD, + TimeDateStamp: DWORD, + MajorVersion: WORD, + MinorVersion: WORD, + Type: DWORD, + SizeOfData: DWORD, + AddressOfRawData: DWORD, + PointerToRawData: DWORD, +} + +IMAGE_DEBUG_TYPE_CODEVIEW :: 2 + SICHINTF :: DWORD SHCONTF :: DWORD SFGAOF :: ULONG -- cgit v1.2.3 From 1550eced046c61fed1121fa6245af6d564ba3149 Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Fri, 3 Jan 2025 16:58:03 +0000 Subject: also add a test for non power of 2 N for good measure --- tests/core/runtime/test_core_runtime.odin | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin index d2ced2504..c1a3ed718 100644 --- a/tests/core/runtime/test_core_runtime.odin +++ b/tests/core/runtime/test_core_runtime.odin @@ -109,6 +109,37 @@ test_map_get :: proc(t: ^testing.T) { check(t, m) } + + // small keys; 3 values per cell + { + val :: struct #packed { + a, b: int, + c: i32, + } + m := map[int]val{ + 1 = val{10, 100, 1000}, + 2 = val{20, 200, 2000}, + 3 = val{30, 300, 3000}, + } + defer delete(m) + check(t, m) + } + + // 3 keys per cell; small values + { + key :: struct #packed { + a, b: int, + c: i32, + } + m := map[key]int{ + key{10, 100, 1000} = 1, + key{20, 200, 2000} = 2, + key{30, 300, 3000} = 3, + } + defer delete(m) + check(t, m) + } + // small keys; value bigger than a chacheline { m := map[int][9]int{ -- cgit v1.2.3 From 1733a50678c548d74386dc3acbbbb9c7d21eb763 Mon Sep 17 00:00:00 2001 From: VladPavliuk Date: Fri, 3 Jan 2025 18:58:08 +0200 Subject: Refactor changes. --- core/sys/windows/types.odin | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index a625d053d..aece4dc43 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -2697,7 +2697,10 @@ EXCEPTION_DATATYPE_MISALIGNMENT :: 0x80000002 EXCEPTION_BREAKPOINT :: 0x80000003 EXCEPTION_SINGLE_STEP :: 0x80000004 EXCEPTION_ACCESS_VIOLATION :: 0xC0000005 +EXCEPTION_IN_PAGE_ERROR :: 0xC0000006 EXCEPTION_ILLEGAL_INSTRUCTION :: 0xC000001D +EXCEPTION_NONCONTINUABLE_EXCEPTION :: 0xC0000025 +EXCEPTION_INVALID_DISPOSITION :: 0xC0000026 EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C EXCEPTION_FLT_DENORMAL_OPERAND :: 0xC000008D EXCEPTION_FLT_DIVIDE_BY_ZERO :: 0xC000008E @@ -2709,10 +2712,7 @@ EXCEPTION_FLT_UNDERFLOW :: 0xC0000093 EXCEPTION_INT_DIVIDE_BY_ZERO :: 0xC0000094 EXCEPTION_INT_OVERFLOW :: 0xC0000095 EXCEPTION_PRIV_INSTRUCTION :: 0xC0000096 -EXCEPTION_IN_PAGE_ERROR :: 0xC0000006 -EXCEPTION_NONCONTINUABLE_EXCEPTION :: 0xC0000025 EXCEPTION_STACK_OVERFLOW :: 0xC00000FD -EXCEPTION_INVALID_DISPOSITION :: 0xC0000026 STATUS_PRIVILEGED_INSTRUCTION :: 0xC0000096 @@ -3428,8 +3428,6 @@ TIME_ZONE_INFORMATION :: struct { DaylightBias: LONG, } - -// @(private="file") IMAGE_DOS_HEADER :: struct { e_magic: WORD, e_cblp: WORD, -- cgit v1.2.3 From a4a156290589751a741060c4a2e33e72f0ef21a8 Mon Sep 17 00:00:00 2001 From: Zoltán Kéri Date: Fri, 3 Jan 2025 19:16:56 +0100 Subject: encoding/base32: Add `@(rodata)` attribute to default tables Add `@(rodata)` attribute to `ENC_TABLE` and `DEC_TABLE` to mark them as read-only data. This places these tables in the read-only section of the executable, protecting them from modification during program execution. --- core/encoding/base32/base32.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index 0b8ec95c4..8629491b1 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -28,6 +28,7 @@ _validate_default :: proc(c: byte) -> bool { return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7') } +@(rodata) ENC_TABLE := [32]byte { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -37,6 +38,7 @@ ENC_TABLE := [32]byte { PADDING :: '=' +@(rodata) DEC_TABLE := [256]u8 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -- cgit v1.2.3 From 6edb061061ab5287ac1b64fd38c8ced12b15e353 Mon Sep 17 00:00:00 2001 From: Antonino Simone Di Stefano Date: Sat, 30 Nov 2024 10:19:46 +0100 Subject: Import "base:runtime" to make type references valid --- base/intrinsics/intrinsics.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 744a899c0..438c8f71d 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -2,6 +2,7 @@ #+build ignore package intrinsics +import "base:runtime" // Package-Related is_package_imported :: proc(package_name: string) -> bool --- -- cgit v1.2.3 From d9165727f59924fb63eea84c2bbdc984173cdf18 Mon Sep 17 00:00:00 2001 From: Antonino Simone Di Stefano Date: Sat, 30 Nov 2024 10:20:37 +0100 Subject: Make expect parameter polymorphic --- base/intrinsics/intrinsics.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 438c8f71d..502f25df3 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -73,7 +73,7 @@ prefetch_write_instruction :: proc(address: rawptr, #const locality: i32 /* 0..= prefetch_write_data :: proc(address: rawptr, #const locality: i32 /* 0..=3 */) --- // Compiler Hints -expect :: proc(val, expected_val: T) -> T --- +expect :: proc(val, expected_val: $T) -> T --- // Linux and Darwin Only syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr --- -- cgit v1.2.3 From 630b1c5cdfa36e2d82f2c510e5766967330ad9e9 Mon Sep 17 00:00:00 2001 From: Antonino Simone Di Stefano Date: Sat, 30 Nov 2024 10:21:10 +0100 Subject: Remove typeid seems to be a typo --- base/intrinsics/intrinsics.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 502f25df3..79bd3964f 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -220,7 +220,7 @@ type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) --- -type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) --- +type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) --- constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- -- cgit v1.2.3 From ec1fefb3f538b5342c0ce52d35aed89ac93c4eef Mon Sep 17 00:00:00 2001 From: Antonino Simone Di Stefano Date: Sun, 1 Dec 2024 08:50:07 +0100 Subject: Import "base:runtime" to resolve reference to type info correctly --- base/builtin/builtin.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base/builtin/builtin.odin b/base/builtin/builtin.odin index c4a9b141f..227ceeb49 100644 --- a/base/builtin/builtin.odin +++ b/base/builtin/builtin.odin @@ -1,6 +1,8 @@ // This is purely for documentation package builtin +import "base:runtime" + nil :: nil false :: 0!=0 true :: 0==0 -- cgit v1.2.3 From 247384574aa743656e2646abad86f878be83153f Mon Sep 17 00:00:00 2001 From: Hisham Aburaqibah Date: Sun, 5 Jan 2025 13:01:58 +0200 Subject: fix(core/image): off-by-one index when detecting certain JPEG images --- core/image/general.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/image/general.odin b/core/image/general.odin index c4a884071..e92b54f18 100644 --- a/core/image/general.odin +++ b/core/image/general.odin @@ -146,7 +146,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type { case s[6:10] == "JFIF", s[6:10] == "Exif": return .JPEG case s[:3] == "\xff\xd8\xff": - switch s[4] { + switch s[3] { case 0xdb, 0xee, 0xe1, 0xe0: return .JPEG } -- cgit v1.2.3 From 5957ff369948af13950d58c49a01dcde51833996 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 5 Jan 2025 13:45:01 +0100 Subject: vendor/raylib: fix Vector3Unproject wrong assignment Fixes #4646 --- vendor/raylib/raymath.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/raylib/raymath.odin b/vendor/raylib/raymath.odin index c66498e41..c8420d60a 100644 --- a/vendor/raylib/raymath.odin +++ b/vendor/raylib/raymath.odin @@ -523,7 +523,7 @@ Vector3Unproject :: proc "c" (source: Vector3, projection: Matrix, view: Matrix) quat: Quaternion quat.x = source.x - quat.y = source.z + quat.y = source.y quat.z = source.z quat.w = 1 -- cgit v1.2.3 From 1bf33fe3735aeca1beecf9b1a3b648bae35aea3d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 12:53:20 +0000 Subject: Use static global memory for std handles instead of allocating. --- core/os/os2/allocators.odin | 1 + core/os/os2/file.odin | 2 +- core/os/os2/file_linux.odin | 56 ++++++++++++++++--------------------------- core/os/os2/file_posix.odin | 49 +++++++++++++++++++++---------------- core/os/os2/file_windows.odin | 53 +++++++++++++++++++++++++++------------- core/os/os2/pipe_linux.odin | 4 ++-- core/os/os2/pipe_posix.odin | 4 ++-- 7 files changed, 93 insertions(+), 76 deletions(-) diff --git a/core/os/os2/allocators.odin b/core/os/os2/allocators.odin index 864532850..61b3ec25a 100644 --- a/core/os/os2/allocators.odin +++ b/core/os/os2/allocators.odin @@ -2,6 +2,7 @@ package os2 import "base:runtime" +import "core:mem" @(require_results) file_allocator :: proc() -> runtime.Allocator { diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index eedf8570c..1a25472a1 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -115,7 +115,7 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, @(require_results) new_file :: proc(handle: uintptr, name: string) -> ^File { - file, err := _new_file(handle, name) + file, err := _new_file(handle, name, file_allocator()) if err != nil { panic(error_string(err)) } diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index ad2892f40..f8e4026da 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -39,37 +39,23 @@ _stderr := File{ @init _standard_stream_init :: proc() { - @static stdin_impl := File_Impl { - name = "/proc/self/fd/0", - fd = 0, - } - - @static stdout_impl := File_Impl { - name = "/proc/self/fd/1", - fd = 1, - } - - @static stderr_impl := File_Impl { - name = "/proc/self/fd/2", - fd = 2, + new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File { + impl.file.impl = impl + impl.fd = linux.Fd(fd) + impl.allocator = runtime.nil_allocator() + impl.name = name + impl.file.stream = { + data = impl, + procedure = _file_stream_proc, + } + impl.file.fstat = _fstat + return &impl.file } - stdin_impl.allocator = file_allocator() - stdout_impl.allocator = file_allocator() - stderr_impl.allocator = file_allocator() - - _stdin.impl = &stdin_impl - _stdout.impl = &stdout_impl - _stderr.impl = &stderr_impl - - // cannot define these initially because cyclic reference - _stdin.stream.data = &stdin_impl - _stdout.stream.data = &stdout_impl - _stderr.stream.data = &stderr_impl - - stdin = &_stdin - stdout = &_stdout - stderr = &_stderr + @(static) files: [3]File_Impl + stdin = new_std(&files[0], 0, "/proc/self/fd/0") + stdout = new_std(&files[1], 1, "/proc/self/fd/1") + stderr = new_std(&files[2], 2, "/proc/self/fd/2") } _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { @@ -100,18 +86,18 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err return nil, _get_platform_error(errno) } - return _new_file(uintptr(fd), name) + return _new_file(uintptr(fd), name, file_allocator()) } -_new_file :: proc(fd: uintptr, _: string = "") -> (f: ^File, err: Error) { - impl := new(File_Impl, file_allocator()) or_return +_new_file :: proc(fd: uintptr, _: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) { + impl := new(File_Impl, allocator) or_return defer if err != nil { - free(impl, file_allocator()) + free(impl, allocator) } impl.file.impl = impl impl.fd = linux.Fd(fd) - impl.allocator = file_allocator() - impl.name = _get_full_path(impl.fd, file_allocator()) or_return + impl.allocator = allocator + impl.name = _get_full_path(impl.fd, impl.allocator) or_return impl.file.stream = { data = impl, procedure = _file_stream_proc, diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin index b7dc43287..184c89368 100644 --- a/core/os/os2/file_posix.odin +++ b/core/os/os2/file_posix.odin @@ -21,23 +21,29 @@ File_Impl :: struct { name: string, cname: cstring, fd: posix.FD, + allocator: runtime.Allocator, } @(init) init_std_files :: proc() { - // NOTE: is this (paths) also the case on non darwin? - - stdin = __new_file(posix.STDIN_FILENO) - (^File_Impl)(stdin.impl).name = "/dev/stdin" - (^File_Impl)(stdin.impl).cname = "/dev/stdin" - - stdout = __new_file(posix.STDIN_FILENO) - (^File_Impl)(stdout.impl).name = "/dev/stdout" - (^File_Impl)(stdout.impl).cname = "/dev/stdout" + new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File { + impl.file.impl = impl + impl.fd = fd + impl.allocator = runtime.nil_allocator() + impl.cname = name + impl.name = string(name) + impl.file.stream = { + data = impl, + procedure = _file_stream_proc, + } + impl.file.fstat = _fstat + return &impl.file + } - stderr = __new_file(posix.STDIN_FILENO) - (^File_Impl)(stderr.impl).name = "/dev/stderr" - (^File_Impl)(stderr.impl).cname = "/dev/stderr" + @(static) files: [3]File_Impl + stdin = new_std(&files[0], posix.STDIN_FILENO, "/dev/stdin") + stdout = new_std(&files[1], posix.STDOUT_FILENO, "/dev/stdout") + stderr = new_std(&files[2], posix.STDERR_FILENO, "/dev/stderr") } _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { @@ -72,10 +78,10 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err return } - return _new_file(uintptr(fd), name) + return _new_file(uintptr(fd), name, file_allocator()) } -_new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { +_new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) { if name == "" { err = .Invalid_Path return @@ -84,10 +90,10 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { return } - crname := _posix_absolute_path(posix.FD(handle), name, file_allocator()) or_return + crname := _posix_absolute_path(posix.FD(handle), name, allocator) or_return rname := string(crname) - f = __new_file(posix.FD(handle)) + f = __new_file(posix.FD(handle), allocator) impl := (^File_Impl)(f.impl) impl.name = rname impl.cname = crname @@ -95,10 +101,11 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { return f, nil } -__new_file :: proc(handle: posix.FD) -> ^File { - impl := new(File_Impl, file_allocator()) +__new_file :: proc(handle: posix.FD, allocator: runtime.Allocator) -> ^File { + impl := new(File_Impl, allocator) impl.file.impl = impl impl.fd = posix.FD(handle) + impl.allocator = allocator impl.file.stream = { data = impl, procedure = _file_stream_proc, @@ -114,8 +121,10 @@ _close :: proc(f: ^File_Impl) -> (err: Error) { err = _get_platform_error() } - delete(f.cname, file_allocator()) - free(f, file_allocator()) + allocator := f.allocator + + delete(f.cname, allocator) + free(f, allocator) return } diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index b91a1bc3b..f594cc72f 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -44,17 +44,38 @@ File_Impl :: struct { @(init) init_std_files :: proc() { - stdin = new_file(uintptr(win32.GetStdHandle(win32.STD_INPUT_HANDLE)), "") - stdout = new_file(uintptr(win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)), "") - stderr = new_file(uintptr(win32.GetStdHandle(win32.STD_ERROR_HANDLE)), "") -} -@(fini) -fini_std_files :: proc() { - _destroy((^File_Impl)(stdin.impl)) - _destroy((^File_Impl)(stdout.impl)) - _destroy((^File_Impl)(stderr.impl)) -} + new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File { + impl.file.impl = impl + + impl.allocator = runtime.nil_allocator() + impl.fd = win32.GetStdHandle(code) + impl.name = name + impl.wname = nil + + handle := _handle(&impl.file) + kind := File_Impl_Kind.File + if m: u32; win32.GetConsoleMode(handle, &m) { + kind = .Console + } + if win32.GetFileType(handle) == win32.FILE_TYPE_PIPE { + kind = .Pipe + } + impl.kind = kind + impl.file.stream = { + data = impl, + procedure = _file_stream_proc, + } + impl.file.fstat = _fstat + + return &impl.file + } + + @(static) files: [3]File_Impl + stdin = new_std(&files[0], win32.STD_INPUT_HANDLE, "") + stdout = new_std(&files[1], win32.STD_OUTPUT_HANDLE, "") + stderr = new_std(&files[2], win32.STD_ERROR_HANDLE, "") +} _handle :: proc(f: ^File) -> win32.HANDLE { return win32.HANDLE(_fd(f)) @@ -132,21 +153,21 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { flags := flags if flags != nil else {.Read} handle := _open_internal(name, flags, perm) or_return - return _new_file(handle, name) + return _new_file(handle, name, file_allocator()) } -_new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { +_new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) { if handle == INVALID_HANDLE { return } - impl := new(File_Impl, file_allocator()) or_return + impl := new(File_Impl, allocator) or_return defer if err != nil { - free(impl, file_allocator()) + free(impl, allocator) } impl.file.impl = impl - impl.allocator = file_allocator() + impl.allocator = allocator impl.fd = rawptr(handle) impl.name = clone_string(name, impl.allocator) or_return impl.wname = win32_utf8_to_wstring(name, impl.allocator) or_return @@ -180,7 +201,7 @@ _open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Rea } _new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> (f: ^File, err: Error) { - f, err = _new_file(handle, name) + f, err = _new_file(handle, name, file_allocator()) if f != nil && err == nil { impl := (^File_Impl)(f.impl) impl.r_buf = make([]byte, buffer_size, file_allocator()) diff --git a/core/os/os2/pipe_linux.odin b/core/os/os2/pipe_linux.odin index 852674c69..bb4456e1c 100644 --- a/core/os/os2/pipe_linux.odin +++ b/core/os/os2/pipe_linux.odin @@ -10,8 +10,8 @@ _pipe :: proc() -> (r, w: ^File, err: Error) { return nil, nil,_get_platform_error(errno) } - r = _new_file(uintptr(fds[0])) or_return - w = _new_file(uintptr(fds[1])) or_return + r = _new_file(uintptr(fds[0]), "", file_allocator()) or_return + w = _new_file(uintptr(fds[1]), "", file_allocator()) or_return return } diff --git a/core/os/os2/pipe_posix.odin b/core/os/os2/pipe_posix.odin index df9425339..edead2ab3 100644 --- a/core/os/os2/pipe_posix.odin +++ b/core/os/os2/pipe_posix.odin @@ -21,7 +21,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) { return } - r = __new_file(fds[0]) + r = __new_file(fds[0], file_allocator()) ri := (^File_Impl)(r.impl) rname := strings.builder_make(file_allocator()) @@ -31,7 +31,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) { ri.name = strings.to_string(rname) ri.cname = strings.to_cstring(&rname) - w = __new_file(fds[1]) + w = __new_file(fds[1], file_allocator()) wi := (^File_Impl)(w.impl) wname := strings.builder_make(file_allocator()) -- cgit v1.2.3 From 4d63ee0794000d4455cbc18b9365677708cbc96e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 12:55:35 +0000 Subject: Remove unused import --- core/os/os2/allocators.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/os/os2/allocators.odin b/core/os/os2/allocators.odin index 61b3ec25a..864532850 100644 --- a/core/os/os2/allocators.odin +++ b/core/os/os2/allocators.odin @@ -2,7 +2,6 @@ package os2 import "base:runtime" -import "core:mem" @(require_results) file_allocator :: proc() -> runtime.Allocator { -- cgit v1.2.3 From d718db473c8d2c13f569b3c7e69951c7c845d8c3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:08:01 +0000 Subject: Use array with linear search rather than a hash map. --- core/time/timezone/tz_windows.odin | 294 +++++++++++++++++++------------------ 1 file changed, 153 insertions(+), 141 deletions(-) diff --git a/core/time/timezone/tz_windows.odin b/core/time/timezone/tz_windows.odin index 238c4c933..835f98d28 100644 --- a/core/time/timezone/tz_windows.odin +++ b/core/time/timezone/tz_windows.odin @@ -11,146 +11,147 @@ TZ_Abbrev :: struct { dst: string, } -tz_abbrevs := map[string]TZ_Abbrev { - "Egypt Standard Time" = {"EET", "EEST"}, // Africa/Cairo - "Morocco Standard Time" = {"+00", "+01"}, // Africa/Casablanca - "South Africa Standard Time" = {"SAST", "SAST"}, // Africa/Johannesburg - "South Sudan Standard Time" = {"CAT", "CAT"}, // Africa/Juba - "Sudan Standard Time" = {"CAT", "CAT"}, // Africa/Khartoum - "W. Central Africa Standard Time" = {"WAT", "WAT"}, // Africa/Lagos - "E. Africa Standard Time" = {"EAT", "EAT"}, // Africa/Nairobi - "Sao Tome Standard Time" = {"GMT", "GMT"}, // Africa/Sao_Tome - "Libya Standard Time" = {"EET", "EET"}, // Africa/Tripoli - "Namibia Standard Time" = {"CAT", "CAT"}, // Africa/Windhoek - "Aleutian Standard Time" = {"HST", "HDT"}, // America/Adak - "Alaskan Standard Time" = {"AKST", "AKDT"}, // America/Anchorage - "Tocantins Standard Time" = {"-03", "-03"}, // America/Araguaina - "Paraguay Standard Time" = {"-04", "-03"}, // America/Asuncion - "Bahia Standard Time" = {"-03", "-03"}, // America/Bahia - "SA Pacific Standard Time" = {"-05", "-05"}, // America/Bogota - "Argentina Standard Time" = {"-03", "-03"}, // America/Buenos_Aires - "Eastern Standard Time (Mexico)" = {"EST", "EST"}, // America/Cancun - "Venezuela Standard Time" = {"-04", "-04"}, // America/Caracas - "SA Eastern Standard Time" = {"-03", "-03"}, // America/Cayenne - "Central Standard Time" = {"CST", "CDT"}, // America/Chicago - "Central Brazilian Standard Time" = {"-04", "-04"}, // America/Cuiaba - "Mountain Standard Time" = {"MST", "MDT"}, // America/Denver - "Greenland Standard Time" = {"-03", "-02"}, // America/Godthab - "Turks And Caicos Standard Time" = {"EST", "EDT"}, // America/Grand_Turk - "Central America Standard Time" = {"CST", "CST"}, // America/Guatemala - "Atlantic Standard Time" = {"AST", "ADT"}, // America/Halifax - "Cuba Standard Time" = {"CST", "CDT"}, // America/Havana - "US Eastern Standard Time" = {"EST", "EDT"}, // America/Indianapolis - "SA Western Standard Time" = {"-04", "-04"}, // America/La_Paz - "Pacific Standard Time" = {"PST", "PDT"}, // America/Los_Angeles - "Mountain Standard Time (Mexico)" = {"MST", "MST"}, // America/Mazatlan - "Central Standard Time (Mexico)" = {"CST", "CST"}, // America/Mexico_City - "Saint Pierre Standard Time" = {"-03", "-02"}, // America/Miquelon - "Montevideo Standard Time" = {"-03", "-03"}, // America/Montevideo - "Eastern Standard Time" = {"EST", "EDT"}, // America/New_York - "US Mountain Standard Time" = {"MST", "MST"}, // America/Phoenix - "Haiti Standard Time" = {"EST", "EDT"}, // America/Port-au-Prince - "Magallanes Standard Time" = {"-03", "-03"}, // America/Punta_Arenas - "Canada Central Standard Time" = {"CST", "CST"}, // America/Regina - "Pacific SA Standard Time" = {"-04", "-03"}, // America/Santiago - "E. South America Standard Time" = {"-03", "-03"}, // America/Sao_Paulo - "Newfoundland Standard Time" = {"NST", "NDT"}, // America/St_Johns - "Pacific Standard Time (Mexico)" = {"PST", "PDT"}, // America/Tijuana - "Yukon Standard Time" = {"MST", "MST"}, // America/Whitehorse - "Central Asia Standard Time" = {"+06", "+06"}, // Asia/Almaty - "Jordan Standard Time" = {"+03", "+03"}, // Asia/Amman - "Arabic Standard Time" = {"+03", "+03"}, // Asia/Baghdad - "Azerbaijan Standard Time" = {"+04", "+04"}, // Asia/Baku - "SE Asia Standard Time" = {"+07", "+07"}, // Asia/Bangkok - "Altai Standard Time" = {"+07", "+07"}, // Asia/Barnaul - "Middle East Standard Time" = {"EET", "EEST"}, // Asia/Beirut - "India Standard Time" = {"IST", "IST"}, // Asia/Calcutta - "Transbaikal Standard Time" = {"+09", "+09"}, // Asia/Chita - "Sri Lanka Standard Time" = {"+0530", "+0530"}, // Asia/Colombo - "Syria Standard Time" = {"+03", "+03"}, // Asia/Damascus - "Bangladesh Standard Time" = {"+06", "+06"}, // Asia/Dhaka - "Arabian Standard Time" = {"+04", "+04"}, // Asia/Dubai - "West Bank Standard Time" = {"EET", "EEST"}, // Asia/Hebron - "W. Mongolia Standard Time" = {"+07", "+07"}, // Asia/Hovd - "North Asia East Standard Time" = {"+08", "+08"}, // Asia/Irkutsk - "Israel Standard Time" = {"IST", "IDT"}, // Asia/Jerusalem - "Afghanistan Standard Time" = {"+0430", "+0430"}, // Asia/Kabul - "Russia Time Zone 11" = {"+12", "+12"}, // Asia/Kamchatka - "Pakistan Standard Time" = {"PKT", "PKT"}, // Asia/Karachi - "Nepal Standard Time" = {"+0545", "+0545"}, // Asia/Katmandu - "North Asia Standard Time" = {"+07", "+07"}, // Asia/Krasnoyarsk - "Magadan Standard Time" = {"+11", "+11"}, // Asia/Magadan - "N. Central Asia Standard Time" = {"+07", "+07"}, // Asia/Novosibirsk - "Omsk Standard Time" = {"+06", "+06"}, // Asia/Omsk - "North Korea Standard Time" = {"KST", "KST"}, // Asia/Pyongyang - "Qyzylorda Standard Time" = {"+05", "+05"}, // Asia/Qyzylorda - "Myanmar Standard Time" = {"+0630", "+0630"}, // Asia/Rangoon - "Arab Standard Time" = {"+03", "+03"}, // Asia/Riyadh - "Sakhalin Standard Time" = {"+11", "+11"}, // Asia/Sakhalin - "Korea Standard Time" = {"KST", "KST"}, // Asia/Seoul - "China Standard Time" = {"CST", "CST"}, // Asia/Shanghai - "Singapore Standard Time" = {"+08", "+08"}, // Asia/Singapore - "Russia Time Zone 10" = {"+11", "+11"}, // Asia/Srednekolymsk - "Taipei Standard Time" = {"CST", "CST"}, // Asia/Taipei - "West Asia Standard Time" = {"+05", "+05"}, // Asia/Tashkent - "Georgian Standard Time" = {"+04", "+04"}, // Asia/Tbilisi - "Iran Standard Time" = {"+0330", "+0330"}, // Asia/Tehran - "Tokyo Standard Time" = {"JST", "JST"}, // Asia/Tokyo - "Tomsk Standard Time" = {"+07", "+07"}, // Asia/Tomsk - "Ulaanbaatar Standard Time" = {"+08", "+08"}, // Asia/Ulaanbaatar - "Vladivostok Standard Time" = {"+10", "+10"}, // Asia/Vladivostok - "Yakutsk Standard Time" = {"+09", "+09"}, // Asia/Yakutsk - "Ekaterinburg Standard Time" = {"+05", "+05"}, // Asia/Yekaterinburg - "Caucasus Standard Time" = {"+04", "+04"}, // Asia/Yerevan - "Azores Standard Time" = {"-01", "+00"}, // Atlantic/Azores - "Cape Verde Standard Time" = {"-01", "-01"}, // Atlantic/Cape_Verde - "Greenwich Standard Time" = {"GMT", "GMT"}, // Atlantic/Reykjavik - "Cen. Australia Standard Time" = {"ACST", "ACDT"}, // Australia/Adelaide - "E. Australia Standard Time" = {"AEST", "AEST"}, // Australia/Brisbane - "AUS Central Standard Time" = {"ACST", "ACST"}, // Australia/Darwin - "Aus Central W. Standard Time" = {"+0845", "+0845"}, // Australia/Eucla - "Tasmania Standard Time" = {"AEST", "AEDT"}, // Australia/Hobart - "Lord Howe Standard Time" = {"+1030", "+11"}, // Australia/Lord_Howe - "W. Australia Standard Time" = {"AWST", "AWST"}, // Australia/Perth - "AUS Eastern Standard Time" = {"AEST", "AEDT"}, // Australia/Sydney - "UTC-11" = {"-11", "-11"}, // Etc/GMT+11 - "Dateline Standard Time" = {"-12", "-12"}, // Etc/GMT+12 - "UTC-02" = {"-02", "-02"}, // Etc/GMT+2 - "UTC-08" = {"-08", "-08"}, // Etc/GMT+8 - "UTC-09" = {"-09", "-09"}, // Etc/GMT+9 - "UTC+12" = {"+12", "+12"}, // Etc/GMT-12 - "UTC+13" = {"+13", "+13"}, // Etc/GMT-13 - "UTC" = {"UTC", "UTC"}, // Etc/UTC - "Astrakhan Standard Time" = {"+04", "+04"}, // Europe/Astrakhan - "W. Europe Standard Time" = {"CET", "CEST"}, // Europe/Berlin - "GTB Standard Time" = {"EET", "EEST"}, // Europe/Bucharest - "Central Europe Standard Time" = {"CET", "CEST"}, // Europe/Budapest - "E. Europe Standard Time" = {"EET", "EEST"}, // Europe/Chisinau - "Turkey Standard Time" = {"+03", "+03"}, // Europe/Istanbul - "Kaliningrad Standard Time" = {"EET", "EET"}, // Europe/Kaliningrad - "FLE Standard Time" = {"EET", "EEST"}, // Europe/Kiev - "GMT Standard Time" = {"GMT", "BST"}, // Europe/London - "Belarus Standard Time" = {"+03", "+03"}, // Europe/Minsk - "Russian Standard Time" = {"MSK", "MSK"}, // Europe/Moscow - "Romance Standard Time" = {"CET", "CEST"}, // Europe/Paris - "Russia Time Zone 3" = {"+04", "+04"}, // Europe/Samara - "Saratov Standard Time" = {"+04", "+04"}, // Europe/Saratov - "Volgograd Standard Time" = {"MSK", "MSK"}, // Europe/Volgograd - "Central European Standard Time" = {"CET", "CEST"}, // Europe/Warsaw - "Mauritius Standard Time" = {"+04", "+04"}, // Indian/Mauritius - "Samoa Standard Time" = {"+13", "+13"}, // Pacific/Apia - "New Zealand Standard Time" = {"NZST", "NZDT"}, // Pacific/Auckland - "Bougainville Standard Time" = {"+11", "+11"}, // Pacific/Bougainville - "Chatham Islands Standard Time" = {"+1245", "+1345"}, // Pacific/Chatham - "Easter Island Standard Time" = {"-06", "-05"}, // Pacific/Easter - "Fiji Standard Time" = {"+12", "+12"}, // Pacific/Fiji - "Central Pacific Standard Time" = {"+11", "+11"}, // Pacific/Guadalcanal - "Hawaiian Standard Time" = {"HST", "HST"}, // Pacific/Honolulu - "Line Islands Standard Time" = {"+14", "+14"}, // Pacific/Kiritimati - "Marquesas Standard Time" = {"-0930", "-0930"}, // Pacific/Marquesas - "Norfolk Standard Time" = {"+11", "+12"}, // Pacific/Norfolk - "West Pacific Standard Time" = {"+10", "+10"}, // Pacific/Port_Moresby - "Tonga Standard Time" = {"+13", "+13"}, // Pacific/Tongatapu +@(rodata) +tz_abbrevs := [?]struct{key: string, value: TZ_Abbrev}{ + {"Egypt Standard Time", {"EET", "EEST"}}, // Africa/Cairo + {"Morocco Standard Time", {"+00", "+01"}}, // Africa/Casablanca + {"South Africa Standard Time", {"SAST", "SAST"}}, // Africa/Johannesburg + {"South Sudan Standard Time", {"CAT", "CAT"}}, // Africa/Juba + {"Sudan Standard Time", {"CAT", "CAT"}}, // Africa/Khartoum + {"W. Central Africa Standard Time", {"WAT", "WAT"}}, // Africa/Lagos + {"E. Africa Standard Time", {"EAT", "EAT"}}, // Africa/Nairobi + {"Sao Tome Standard Time", {"GMT", "GMT"}}, // Africa/Sao_Tome + {"Libya Standard Time", {"EET", "EET"}}, // Africa/Tripoli + {"Namibia Standard Time", {"CAT", "CAT"}}, // Africa/Windhoek + {"Aleutian Standard Time", {"HST", "HDT"}}, // America/Adak + {"Alaskan Standard Time", {"AKST", "AKDT"}}, // America/Anchorage + {"Tocantins Standard Time", {"-03", "-03"}}, // America/Araguaina + {"Paraguay Standard Time", {"-04", "-03"}}, // America/Asuncion + {"Bahia Standard Time", {"-03", "-03"}}, // America/Bahia + {"SA Pacific Standard Time", {"-05", "-05"}}, // America/Bogota + {"Argentina Standard Time", {"-03", "-03"}}, // America/Buenos_Aires + {"Eastern Standard Time (Mexico)", {"EST", "EST"}}, // America/Cancun + {"Venezuela Standard Time", {"-04", "-04"}}, // America/Caracas + {"SA Eastern Standard Time", {"-03", "-03"}}, // America/Cayenne + {"Central Standard Time", {"CST", "CDT"}}, // America/Chicago + {"Central Brazilian Standard Time", {"-04", "-04"}}, // America/Cuiaba + {"Mountain Standard Time", {"MST", "MDT"}}, // America/Denver + {"Greenland Standard Time", {"-03", "-02"}}, // America/Godthab + {"Turks And Caicos Standard Time", {"EST", "EDT"}}, // America/Grand_Turk + {"Central America Standard Time", {"CST", "CST"}}, // America/Guatemala + {"Atlantic Standard Time", {"AST", "ADT"}}, // America/Halifax + {"Cuba Standard Time", {"CST", "CDT"}}, // America/Havana + {"US Eastern Standard Time", {"EST", "EDT"}}, // America/Indianapolis + {"SA Western Standard Time", {"-04", "-04"}}, // America/La_Paz + {"Pacific Standard Time", {"PST", "PDT"}}, // America/Los_Angeles + {"Mountain Standard Time (Mexico)", {"MST", "MST"}}, // America/Mazatlan + {"Central Standard Time (Mexico)", {"CST", "CST"}}, // America/Mexico_City + {"Saint Pierre Standard Time", {"-03", "-02"}}, // America/Miquelon + {"Montevideo Standard Time", {"-03", "-03"}}, // America/Montevideo + {"Eastern Standard Time", {"EST", "EDT"}}, // America/New_York + {"US Mountain Standard Time", {"MST", "MST"}}, // America/Phoenix + {"Haiti Standard Time", {"EST", "EDT"}}, // America/Port-au-Prince + {"Magallanes Standard Time", {"-03", "-03"}}, // America/Punta_Arenas + {"Canada Central Standard Time", {"CST", "CST"}}, // America/Regina + {"Pacific SA Standard Time", {"-04", "-03"}}, // America/Santiago + {"E. South America Standard Time", {"-03", "-03"}}, // America/Sao_Paulo + {"Newfoundland Standard Time", {"NST", "NDT"}}, // America/St_Johns + {"Pacific Standard Time (Mexico)", {"PST", "PDT"}}, // America/Tijuana + {"Yukon Standard Time", {"MST", "MST"}}, // America/Whitehorse + {"Central Asia Standard Time", {"+06", "+06"}}, // Asia/Almaty + {"Jordan Standard Time", {"+03", "+03"}}, // Asia/Amman + {"Arabic Standard Time", {"+03", "+03"}}, // Asia/Baghdad + {"Azerbaijan Standard Time", {"+04", "+04"}}, // Asia/Baku + {"SE Asia Standard Time", {"+07", "+07"}}, // Asia/Bangkok + {"Altai Standard Time", {"+07", "+07"}}, // Asia/Barnaul + {"Middle East Standard Time", {"EET", "EEST"}}, // Asia/Beirut + {"India Standard Time", {"IST", "IST"}}, // Asia/Calcutta + {"Transbaikal Standard Time", {"+09", "+09"}}, // Asia/Chita + {"Sri Lanka Standard Time", {"+0530", "+0530"}}, // Asia/Colombo + {"Syria Standard Time", {"+03", "+03"}}, // Asia/Damascus + {"Bangladesh Standard Time", {"+06", "+06"}}, // Asia/Dhaka + {"Arabian Standard Time", {"+04", "+04"}}, // Asia/Dubai + {"West Bank Standard Time", {"EET", "EEST"}}, // Asia/Hebron + {"W. Mongolia Standard Time", {"+07", "+07"}}, // Asia/Hovd + {"North Asia East Standard Time", {"+08", "+08"}}, // Asia/Irkutsk + {"Israel Standard Time", {"IST", "IDT"}}, // Asia/Jerusalem + {"Afghanistan Standard Time", {"+0430", "+0430"}}, // Asia/Kabul + {"Russia Time Zone 11", {"+12", "+12"}}, // Asia/Kamchatka + {"Pakistan Standard Time", {"PKT", "PKT"}}, // Asia/Karachi + {"Nepal Standard Time", {"+0545", "+0545"}}, // Asia/Katmandu + {"North Asia Standard Time", {"+07", "+07"}}, // Asia/Krasnoyarsk + {"Magadan Standard Time", {"+11", "+11"}}, // Asia/Magadan + {"N. Central Asia Standard Time", {"+07", "+07"}}, // Asia/Novosibirsk + {"Omsk Standard Time", {"+06", "+06"}}, // Asia/Omsk + {"North Korea Standard Time", {"KST", "KST"}}, // Asia/Pyongyang + {"Qyzylorda Standard Time", {"+05", "+05"}}, // Asia/Qyzylorda + {"Myanmar Standard Time", {"+0630", "+0630"}}, // Asia/Rangoon + {"Arab Standard Time", {"+03", "+03"}}, // Asia/Riyadh + {"Sakhalin Standard Time", {"+11", "+11"}}, // Asia/Sakhalin + {"Korea Standard Time", {"KST", "KST"}}, // Asia/Seoul + {"China Standard Time", {"CST", "CST"}}, // Asia/Shanghai + {"Singapore Standard Time", {"+08", "+08"}}, // Asia/Singapore + {"Russia Time Zone 10", {"+11", "+11"}}, // Asia/Srednekolymsk + {"Taipei Standard Time", {"CST", "CST"}}, // Asia/Taipei + {"West Asia Standard Time", {"+05", "+05"}}, // Asia/Tashkent + {"Georgian Standard Time", {"+04", "+04"}}, // Asia/Tbilisi + {"Iran Standard Time", {"+0330", "+0330"}}, // Asia/Tehran + {"Tokyo Standard Time", {"JST", "JST"}}, // Asia/Tokyo + {"Tomsk Standard Time", {"+07", "+07"}}, // Asia/Tomsk + {"Ulaanbaatar Standard Time", {"+08", "+08"}}, // Asia/Ulaanbaatar + {"Vladivostok Standard Time", {"+10", "+10"}}, // Asia/Vladivostok + {"Yakutsk Standard Time", {"+09", "+09"}}, // Asia/Yakutsk + {"Ekaterinburg Standard Time", {"+05", "+05"}}, // Asia/Yekaterinburg + {"Caucasus Standard Time", {"+04", "+04"}}, // Asia/Yerevan + {"Azores Standard Time", {"-01", "+00"}}, // Atlantic/Azores + {"Cape Verde Standard Time", {"-01", "-01"}}, // Atlantic/Cape_Verde + {"Greenwich Standard Time", {"GMT", "GMT"}}, // Atlantic/Reykjavik + {"Cen. Australia Standard Time", {"ACST", "ACDT"}}, // Australia/Adelaide + {"E. Australia Standard Time", {"AEST", "AEST"}}, // Australia/Brisbane + {"AUS Central Standard Time", {"ACST", "ACST"}}, // Australia/Darwin + {"Aus Central W. Standard Time", {"+0845", "+0845"}}, // Australia/Eucla + {"Tasmania Standard Time", {"AEST", "AEDT"}}, // Australia/Hobart + {"Lord Howe Standard Time", {"+1030", "+11"}}, // Australia/Lord_Howe + {"W. Australia Standard Time", {"AWST", "AWST"}}, // Australia/Perth + {"AUS Eastern Standard Time", {"AEST", "AEDT"}}, // Australia/Sydney + {"UTC-11", {"-11", "-11"}}, // Etc/GMT+11 + {"Dateline Standard Time", {"-12", "-12"}}, // Etc/GMT+12 + {"UTC-02", {"-02", "-02"}}, // Etc/GMT+2 + {"UTC-08", {"-08", "-08"}}, // Etc/GMT+8 + {"UTC-09", {"-09", "-09"}}, // Etc/GMT+9 + {"UTC+12", {"+12", "+12"}}, // Etc/GMT-12 + {"UTC+13", {"+13", "+13"}}, // Etc/GMT-13 + {"UTC", {"UTC", "UTC"}}, // Etc/UTC + {"Astrakhan Standard Time", {"+04", "+04"}}, // Europe/Astrakhan + {"W. Europe Standard Time", {"CET", "CEST"}}, // Europe/Berlin + {"GTB Standard Time", {"EET", "EEST"}}, // Europe/Bucharest + {"Central Europe Standard Time", {"CET", "CEST"}}, // Europe/Budapest + {"E. Europe Standard Time", {"EET", "EEST"}}, // Europe/Chisinau + {"Turkey Standard Time", {"+03", "+03"}}, // Europe/Istanbul + {"Kaliningrad Standard Time", {"EET", "EET"}}, // Europe/Kaliningrad + {"FLE Standard Time", {"EET", "EEST"}}, // Europe/Kiev + {"GMT Standard Time", {"GMT", "BST"}}, // Europe/London + {"Belarus Standard Time", {"+03", "+03"}}, // Europe/Minsk + {"Russian Standard Time", {"MSK", "MSK"}}, // Europe/Moscow + {"Romance Standard Time", {"CET", "CEST"}}, // Europe/Paris + {"Russia Time Zone 3", {"+04", "+04"}}, // Europe/Samara + {"Saratov Standard Time", {"+04", "+04"}}, // Europe/Saratov + {"Volgograd Standard Time", {"MSK", "MSK"}}, // Europe/Volgograd + {"Central European Standard Time", {"CET", "CEST"}}, // Europe/Warsaw + {"Mauritius Standard Time", {"+04", "+04"}}, // Indian/Mauritius + {"Samoa Standard Time", {"+13", "+13"}}, // Pacific/Apia + {"New Zealand Standard Time", {"NZST", "NZDT"}}, // Pacific/Auckland + {"Bougainville Standard Time", {"+11", "+11"}}, // Pacific/Bougainville + {"Chatham Islands Standard Time", {"+1245", "+1345"}}, // Pacific/Chatham + {"Easter Island Standard Time", {"-06", "-05"}}, // Pacific/Easter + {"Fiji Standard Time", {"+12", "+12"}}, // Pacific/Fiji + {"Central Pacific Standard Time", {"+11", "+11"}}, // Pacific/Guadalcanal + {"Hawaiian Standard Time", {"HST", "HST"}}, // Pacific/Honolulu + {"Line Islands Standard Time", {"+14", "+14"}}, // Pacific/Kiritimati + {"Marquesas Standard Time", {"-0930", "-0930"}}, // Pacific/Marquesas + {"Norfolk Standard Time", {"+11", "+12"}}, // Pacific/Norfolk + {"West Pacific Standard Time", {"+10", "+10"}}, // Pacific/Port_Moresby + {"Tonga Standard Time", {"+13", "+13"}}, // Pacific/Tongatapu } iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) -> (name: string, success: bool) { @@ -269,7 +270,18 @@ _region_load :: proc(reg_str: string, allocator := context.allocator) -> (out_re defer delete(wintz_name, allocator) defer delete(iana_name, allocator) - abbrevs := tz_abbrevs[wintz_name] or_return + abbrevs: TZ_Abbrev + abbrevs_ok: bool + for pair in tz_abbrevs { + if pair.key == wintz_name { + abbrevs = pair.value + abbrevs_ok = true + break + } + } + if abbrevs_ok { + return + } if abbrevs.std == "UTC" && abbrevs.dst == abbrevs.std { return nil, true } -- cgit v1.2.3 From acbb14d87e136d771cbd70c12a14deb9cace48bd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:10:29 +0000 Subject: Fix typo --- core/time/timezone/tz_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/time/timezone/tz_windows.odin b/core/time/timezone/tz_windows.odin index 835f98d28..8dc5f533c 100644 --- a/core/time/timezone/tz_windows.odin +++ b/core/time/timezone/tz_windows.odin @@ -279,7 +279,7 @@ _region_load :: proc(reg_str: string, allocator := context.allocator) -> (out_re break } } - if abbrevs_ok { + if !abbrevs_ok { return } if abbrevs.std == "UTC" && abbrevs.dst == abbrevs.std { -- cgit v1.2.3 From 2efe4c2d68f486006e405ba7d30be03ec121ae6c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:19:10 +0000 Subject: Add `#+feature dynamic-literals` --- src/build_settings.cpp | 12 +++++++++ src/check_expr.cpp | 10 ++++++-- src/parser.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/parser.hpp | 2 ++ 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 4c3f4b782..a8261612e 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -324,6 +324,18 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_NONE; } +enum OptInFeatureFlags : u64 { + OptInFeatureFlag_NONE = 0, + OptInFeatureFlag_DynamicLiterals = 1u<<0, +}; + +u64 get_feature_flag_from_name(String const &name) { + if (name == "dynamic-literals") { + return OptInFeatureFlag_DynamicLiterals; + } + return OptInFeatureFlag_NONE; +} + enum SanitizerFlags : u32 { SanitizerFlag_NONE = 0, diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fba9b8dad..fb3040e71 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9730,8 +9730,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (t->kind == Type_DynamicArray) { - if (build_context.no_dynamic_literals && cl->elems.count) { + if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { + ERROR_BLOCK(); error(node, "Compound literals of dynamic types have been disabled"); + error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); } } @@ -10120,8 +10123,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } - if (build_context.no_dynamic_literals && cl->elems.count) { + if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { + ERROR_BLOCK(); error(node, "Compound literals of dynamic types have been disabled"); + error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); } else { add_map_reserve_dependencies(c); add_map_set_dependencies(c); diff --git a/src/parser.cpp b/src/parser.cpp index aa90651d3..01ed46ebc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6265,10 +6265,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p)); error_line("\tExpected one of the following\n"); error_line("\tunused\n"); + error_line("\tunused-variables\n"); + error_line("\tunused-imports\n"); + error_line("\tunused-procedures\n"); error_line("\tshadowing\n"); error_line("\tusing-stmt\n"); error_line("\tusing-param\n"); + error_line("\tstyle\n"); error_line("\textra\n"); + error_line("\tcast\n"); + error_line("\ttabs\n"); return build_context.vet_flags; } } @@ -6286,6 +6292,63 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { return vet_flags &~ vet_not_flags; } +gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { + String const prefix = str_lit("feature"); + GB_ASSERT(string_starts_with(s, prefix)); + s = string_trim_whitespace(substring(s, prefix.len, s.len)); + + if (s.len == 0) { + return OptInFeatureFlag_NONE; + } + + u64 feature_flags = 0; + u64 feature_not_flags = 0; + + while (s.len > 0) { + String p = string_trim_whitespace(vet_tag_get_token(s, &s)); + if (p.len == 0) { + break; + } + + bool is_notted = false; + if (p[0] == '!') { + is_notted = true; + p = substring(p, 1, p.len); + if (p.len == 0) { + syntax_error(token_for_pos, "Expected a feature flag name after '!'"); + return OptInFeatureFlag_NONE; + } + } + + u64 flag = get_vet_flag_from_name(p); + if (flag != OptInFeatureFlag_NONE) { + if (is_notted) { + feature_not_flags |= flag; + } else { + feature_flags |= flag; + } + } else { + ERROR_BLOCK(); + syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p)); + error_line("\tExpected one of the following\n"); + error_line("\tdynamic-literals\n"); + return OptInFeatureFlag_NONE; + } + } + + if (feature_flags == 0 && feature_not_flags == 0) { + return OptInFeatureFlag_NONE; + } + if (feature_flags == 0 && feature_not_flags != 0) { + return OptInFeatureFlag_NONE &~ feature_not_flags; + } + if (feature_flags != 0 && feature_not_flags == 0) { + return feature_flags; + } + GB_ASSERT(feature_flags != 0 && feature_not_flags != 0); + return feature_flags &~ feature_not_flags; +} + gb_internal String dir_from_path(String path) { String base_dir = path; for (isize i = path.len-1; i >= 0; i--) { @@ -6409,6 +6472,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; + } else if (string_starts_with(lc, str_lit("feature"))) { + f->feature_flags = parse_feature_tag(tok, lc); + f->feature_flags_set = true; } else { error(tok, "Unknown tag '%.*s'", LIT(lc)); } diff --git a/src/parser.hpp b/src/parser.hpp index e332fed50..bbf70d03e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -108,7 +108,9 @@ struct AstFile { String package_name; u64 vet_flags; + u64 feature_flags; bool vet_flags_set; + bool feature_flags_set; // >= 0: In Expression // < 0: In Control Clause -- cgit v1.2.3 From bca08d3b85f59c35f4eb43731099bc96730b12cd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:22:27 +0000 Subject: Make `-no-dynamic-literals` the default now --- examples/demo/demo.odin | 1 + src/build_settings.cpp | 6 ------ src/check_expr.cpp | 37 +++++++++++++++++++++---------------- src/checker.cpp | 18 +++++++++++++++++- src/llvm_backend.cpp | 2 -- src/llvm_backend_expr.cpp | 4 ++-- src/main.cpp | 2 +- src/parser.cpp | 4 ++-- 8 files changed, 44 insertions(+), 30 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 36d1359ca..82b047103 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1,4 +1,5 @@ #+vet !using-stmt !using-param +#+feature dynamic-literals package main import "core:fmt" diff --git a/src/build_settings.cpp b/src/build_settings.cpp index a8261612e..93168cf77 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -441,7 +441,6 @@ struct BuildContext { bool ignore_unknown_attributes; bool no_bounds_check; bool no_type_assert; - bool no_dynamic_literals; bool no_output_files; bool no_crt; bool no_rpath; @@ -1867,11 +1866,6 @@ gb_internal bool init_build_paths(String init_filename) { produces_output_file = true; } - if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR || - build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { - bc->no_dynamic_literals = true; - } - if (!produces_output_file) { // Command doesn't produce output files. We're done. return true; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fb3040e71..ba021a98c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9351,6 +9351,23 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { return false; } +gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) { + if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) { + ERROR_BLOCK(); + error(node, "Compound literals of dynamic types are disabled by default"); + error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); + if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) { + error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); + } else if (build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { + error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); + } + return false; + } + + return cl->elems.count > 0; +} + gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(cl, CompoundLit, node); @@ -9551,11 +9568,6 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * elem_type = t->DynamicArray.elem; context_name = str_lit("dynamic array literal"); is_constant = false; - - if (!build_context.no_dynamic_literals) { - add_package_dependency(c, "runtime", "__dynamic_array_reserve"); - add_package_dependency(c, "runtime", "__dynamic_array_append"); - } } else if (t->kind == Type_SimdVector) { elem_type = t->SimdVector.elem; context_name = str_lit("simd vector literal"); @@ -9730,11 +9742,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (t->kind == Type_DynamicArray) { - if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { - ERROR_BLOCK(); - error(node, "Compound literals of dynamic types have been disabled"); - error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); - error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); + if (check_for_dynamic_literals(c, node, cl)) { + add_package_dependency(c, "runtime", "__dynamic_array_reserve"); + add_package_dependency(c, "runtime", "__dynamic_array_append"); } } @@ -10123,12 +10133,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } - if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { - ERROR_BLOCK(); - error(node, "Compound literals of dynamic types have been disabled"); - error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); - error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); - } else { + if (check_for_dynamic_literals(c, node, cl)) { add_map_reserve_dependencies(c); add_map_set_dependencies(c); } diff --git a/src/checker.cpp b/src/checker.cpp index 7e0a64d75..5d3263789 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -542,6 +542,23 @@ gb_internal u64 check_vet_flags(Ast *node) { return ast_file_vet_flags(file); } +gb_internal u64 check_feature_flags(CheckerContext *c, Ast *node) { + AstFile *file = c->file; + if (file == nullptr && + c->curr_proc_decl && + c->curr_proc_decl->proc_lit) { + file = c->curr_proc_decl->proc_lit->file(); + } + if (file == nullptr) { + file = node->file(); + } + if (file != nullptr && file->feature_flags_set) { + return file->feature_flags; + } + return 0; +} + + enum VettedEntityKind { VettedEntity_Invalid, @@ -1164,7 +1181,6 @@ gb_internal void init_universal(void) { add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check); add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert); add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR); - add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals); add_global_bool_constant("ODIN_NO_CRT", bc->no_crt); add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules); add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 01ded321e..696ced0df 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1096,8 +1096,6 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ } gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) { - GB_ASSERT(!build_context.no_dynamic_literals); - TEMPORARY_ALLOCATOR_GUARD(); String proc_name = {}; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 3b238bcd8..df9dca801 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4813,7 +4813,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(!build_context.no_dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); gb_unused(err); @@ -4902,7 +4902,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(!build_context.no_dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); Type *et = bt->DynamicArray.elem; lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); diff --git a/src/main.cpp b/src/main.cpp index 0450c61ec..41c7170f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1192,7 +1192,7 @@ gb_internal bool parse_build_flags(Array args) { build_context.no_type_assert = true; break; case BuildFlag_NoDynamicLiterals: - build_context.no_dynamic_literals = true; + gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n"); break; case BuildFlag_NoCRT: build_context.no_crt = true; diff --git a/src/parser.cpp b/src/parser.cpp index 01ed46ebc..e190bc5a5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6320,7 +6320,7 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { } } - u64 flag = get_vet_flag_from_name(p); + u64 flag = get_feature_flag_from_name(p); if (flag != OptInFeatureFlag_NONE) { if (is_notted) { feature_not_flags |= flag; @@ -6473,7 +6473,7 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; } else if (string_starts_with(lc, str_lit("feature"))) { - f->feature_flags = parse_feature_tag(tok, lc); + f->feature_flags |= parse_feature_tag(tok, lc); f->feature_flags_set = true; } else { error(tok, "Unknown tag '%.*s'", LIT(lc)); -- cgit v1.2.3 From a300a860ec53b0085ef46774e7b6e96a09dc9f0f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:46:58 +0000 Subject: Add `#+feature dynamic-literals` to tests --- tests/core/encoding/cbor/test_core_cbor.odin | 1 + tests/core/fmt/test_core_fmt.odin | 1 + tests/core/net/test_core_net.odin | 1 + tests/core/runtime/test_core_runtime.odin | 1 + tests/core/slice/test_core_slice.odin | 1 + 5 files changed, 5 insertions(+) diff --git a/tests/core/encoding/cbor/test_core_cbor.odin b/tests/core/encoding/cbor/test_core_cbor.odin index c614727b9..ee853ebac 100644 --- a/tests/core/encoding/cbor/test_core_cbor.odin +++ b/tests/core/encoding/cbor/test_core_cbor.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_encoding_cbor import "base:intrinsics" diff --git a/tests/core/fmt/test_core_fmt.odin b/tests/core/fmt/test_core_fmt.odin index 3a1eb37e7..c79a15e85 100644 --- a/tests/core/fmt/test_core_fmt.odin +++ b/tests/core/fmt/test_core_fmt.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_core_fmt import "base:runtime" diff --git a/tests/core/net/test_core_net.odin b/tests/core/net/test_core_net.odin index bc3ff5c46..0d57bd94a 100644 --- a/tests/core/net/test_core_net.odin +++ b/tests/core/net/test_core_net.odin @@ -12,6 +12,7 @@ */ #+build !netbsd #+build !openbsd +#+feature dynamic-literals package test_core_net import "core:testing" diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin index c1a3ed718..be6c24c72 100644 --- a/tests/core/runtime/test_core_runtime.odin +++ b/tests/core/runtime/test_core_runtime.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_core_runtime import "base:intrinsics" diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 9c77f872d..98cb8dbac 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_core_slice import "core:slice" -- cgit v1.2.3 From 3d984d75cc626a86c10a090facce8ea156295bbf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 14:00:23 +0000 Subject: Add `#+feature dynamic-literals` to tests --- tests/core/hash/test_core_hash.odin | 1 + tests/core/hash/test_vectors_xxhash.odin | 1 + tests/core/image/test_core_image.odin | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index c3f0bee91..adb55d2d8 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_core_hash import "core:hash/xxhash" diff --git a/tests/core/hash/test_vectors_xxhash.odin b/tests/core/hash/test_vectors_xxhash.odin index f72e2699a..04e2d4f1f 100644 --- a/tests/core/hash/test_vectors_xxhash.odin +++ b/tests/core/hash/test_vectors_xxhash.odin @@ -1,4 +1,5 @@ // Hash Test Vectors +#+feature dynamic-literals package test_core_hash XXHASH_Test_Vectors :: struct #packed { diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 899596229..8f6091481 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -7,6 +7,7 @@ A test suite for PNG, TGA, NetPBM, QOI and BMP. */ +#+feature dynamic-literals package test_core_image import "core:testing" -- cgit v1.2.3 From 5df699abf2c15b90a914d7769a05ec644afbb81a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 14:03:08 +0000 Subject: Add `#+feature dynamic-literals` to test --- tests/issues/test_issue_829.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/issues/test_issue_829.odin b/tests/issues/test_issue_829.odin index 229d8e9b4..3287c49fe 100644 --- a/tests/issues/test_issue_829.odin +++ b/tests/issues/test_issue_829.odin @@ -1,4 +1,5 @@ // Tests issue #829 https://github.com/odin-lang/Odin/issues/829 +#+feature dynamic-literals package test_issues import "core:testing" -- cgit v1.2.3 From 7da7d4e4103d20d757a371f614d3343f8fd15c85 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 15:41:51 +0000 Subject: Allow `#+` tags on single files --- src/parser.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index e190bc5a5..03c5a5962 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6462,6 +6462,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (command == "file") { f->flags |= AstFile_IsPrivateFile; } + } else if (string_starts_with(lc, str_lit("feature"))) { + f->feature_flags |= parse_feature_tag(tok, lc); + f->feature_flags_set = true; } else if (lc == "lazy") { if (build_context.ignore_lazy) { // Ignore @@ -6472,9 +6475,6 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; - } else if (string_starts_with(lc, str_lit("feature"))) { - f->feature_flags |= parse_feature_tag(tok, lc); - f->feature_flags_set = true; } else { error(tok, "Unknown tag '%.*s'", LIT(lc)); } @@ -6559,9 +6559,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->package_name = package_name.string; - // TODO: Shouldn't single file only matter for build tags? no-instrumentation for example - // should be respected even when in single file mode. - if (!f->pkg->is_single_file) { + { if (docs != nullptr && docs->list.count > 0) { for (Token const &tok : docs->list) { GB_ASSERT(tok.kind == Token_Comment); -- cgit v1.2.3 From 252b80771476657035b47fcd9e687d3d7fb0b9fe Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 5 Jan 2025 18:22:38 +0100 Subject: update wasm blob --- vendor/cgltf/lib/cgltf_wasm.o | Bin 112327 -> 118286 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/vendor/cgltf/lib/cgltf_wasm.o b/vendor/cgltf/lib/cgltf_wasm.o index 54346d176..077d480a8 100644 Binary files a/vendor/cgltf/lib/cgltf_wasm.o and b/vendor/cgltf/lib/cgltf_wasm.o differ -- cgit v1.2.3 From 834209194f8a770ed0a71450e1f6e4671357bada Mon Sep 17 00:00:00 2001 From: laytan Date: Sun, 5 Jan 2025 17:35:40 +0100 Subject: rebuild windows lib --- vendor/cgltf/lib/cgltf.lib | Bin 376502 -> 376686 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/vendor/cgltf/lib/cgltf.lib b/vendor/cgltf/lib/cgltf.lib index 6dddf3baf..b14f79142 100644 Binary files a/vendor/cgltf/lib/cgltf.lib and b/vendor/cgltf/lib/cgltf.lib differ -- cgit v1.2.3 From c60492659527fdf383eb8bcc730f5f38dec48e26 Mon Sep 17 00:00:00 2001 From: Leo Zurbriggen Date: Sun, 5 Jan 2025 18:04:36 +0100 Subject: add SetCommMask, GetCommMask, WaitCommEvent, GetCommPorts, communication event constants --- core/sys/windows/kernel32.odin | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index ff9d84959..e3bbb9a10 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -21,6 +21,16 @@ COMMON_LVB_REVERSE_VIDEO :: WORD(0x4000) COMMON_LVB_UNDERSCORE :: WORD(0x8000) COMMON_LVB_SBCSDBCS :: WORD(0x0300) +EV_BREAK :: DWORD(0x0040) +EV_CTS :: DWORD(0x0008) +EV_DSR :: DWORD(0x0010) +EV_ERR :: DWORD(0x0080) +EV_RING :: DWORD(0x0100) +EV_RLSD :: DWORD(0x0020) +EV_RXCHAR :: DWORD(0x0001) +EV_RXFLAG :: DWORD(0x0002) +EV_TXEMPTY :: DWORD(0x0004) + @(default_calling_convention="system") foreign kernel32 { OutputDebugStringA :: proc(lpOutputString: LPCSTR) --- // The only A thing that is allowed @@ -109,6 +119,9 @@ foreign kernel32 { ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL --- GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- + SetCommMask :: proc(handle: HANDLE, dwEvtMap: DWORD) -> BOOL --- + GetCommMask :: proc(handle: HANDLE, lpEvtMask: LPDWORD) -> BOOL --- + WaitCommEvent ::proc(handle: HANDLE, lpEvtMask: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL --- GetCommandLineW :: proc() -> LPCWSTR --- GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- GetCurrentProcess :: proc() -> HANDLE --- @@ -1067,7 +1080,11 @@ foreign one_core { PageProtection: ULONG, PreferredNode: ULONG, ) -> PVOID --- - GetCommPorts :: proc(lpPortNumbers: PULONG, uPortNumbersCount: ULONG, puPortNumbersFound: PULONG) -> ULONG --- + GetCommPorts :: proc( + lpPortNumbers: PULONG, + uPortNumbersCount: ULONG, + puPortNumbersFound: PULONG, + ) -> ULONG --- } -- cgit v1.2.3 From b98833ce04d06bd38c9fb1bcf8fe884fc38d819a Mon Sep 17 00:00:00 2001 From: Laytan Date: Sun, 5 Jan 2025 18:42:48 +0100 Subject: spacing --- base/intrinsics/intrinsics.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 79bd3964f..ee0d357e4 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -3,6 +3,7 @@ package intrinsics import "base:runtime" + // Package-Related is_package_imported :: proc(package_name: string) -> bool --- -- cgit v1.2.3 From 823740c7a4f9a6bcee28137aca9ee35c3bb87655 Mon Sep 17 00:00:00 2001 From: Leo Zurbriggen Date: Sun, 5 Jan 2025 18:43:16 +0100 Subject: formatting --- core/sys/windows/kernel32.odin | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index e3bbb9a10..e280b3c29 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -20,16 +20,15 @@ COMMON_LVB_GRID_RVERTICAL :: WORD(0x1000) COMMON_LVB_REVERSE_VIDEO :: WORD(0x4000) COMMON_LVB_UNDERSCORE :: WORD(0x8000) COMMON_LVB_SBCSDBCS :: WORD(0x0300) - -EV_BREAK :: DWORD(0x0040) -EV_CTS :: DWORD(0x0008) -EV_DSR :: DWORD(0x0010) -EV_ERR :: DWORD(0x0080) -EV_RING :: DWORD(0x0100) -EV_RLSD :: DWORD(0x0020) -EV_RXCHAR :: DWORD(0x0001) -EV_RXFLAG :: DWORD(0x0002) -EV_TXEMPTY :: DWORD(0x0004) +EV_BREAK :: DWORD(0x0040) +EV_CTS :: DWORD(0x0008) +EV_DSR :: DWORD(0x0010) +EV_ERR :: DWORD(0x0080) +EV_RING :: DWORD(0x0100) +EV_RLSD :: DWORD(0x0020) +EV_RXCHAR :: DWORD(0x0001) +EV_RXFLAG :: DWORD(0x0002) +EV_TXEMPTY :: DWORD(0x0004) @(default_calling_convention="system") foreign kernel32 { @@ -121,7 +120,7 @@ foreign kernel32 { SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- SetCommMask :: proc(handle: HANDLE, dwEvtMap: DWORD) -> BOOL --- GetCommMask :: proc(handle: HANDLE, lpEvtMask: LPDWORD) -> BOOL --- - WaitCommEvent ::proc(handle: HANDLE, lpEvtMask: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL --- + WaitCommEvent :: proc(handle: HANDLE, lpEvtMask: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL --- GetCommandLineW :: proc() -> LPCWSTR --- GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- GetCurrentProcess :: proc() -> HANDLE --- -- cgit v1.2.3 From 25cdc3736edd5283514e4de5083a0612040fc13f Mon Sep 17 00:00:00 2001 From: fleandro <3987005+flga@users.noreply.github.com> Date: Sun, 5 Jan 2025 17:50:52 +0000 Subject: vendor:x11/xlib add IS_SUPPORTED constant to match core:time and friends --- vendor/vulkan/_gen/create_vulkan_odin_wrapper.py | 3 +-- vendor/vulkan/structs.odin | 3 +-- vendor/x11/xlib/xlib.odin | 4 ++++ 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 vendor/x11/xlib/xlib.odin diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index b8d7b9464..407e6371c 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -929,8 +929,7 @@ when ODIN_OS == .Windows { \t} } -// We want to use `vendor:x11/xlib` types so we need to match their build constraints. -when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { +when xlib.IS_SUPPORTED { \tXlibDisplay :: xlib.Display \tXlibWindow :: xlib.Window \tXlibVisualID :: xlib.VisualID diff --git a/vendor/vulkan/structs.odin b/vendor/vulkan/structs.odin index 3bab29f4e..611a99ed7 100644 --- a/vendor/vulkan/structs.odin +++ b/vendor/vulkan/structs.odin @@ -36,8 +36,7 @@ when ODIN_OS == .Windows { } } -// We want to use `vendor:x11/xlib` types so we need to match their build constraints. -when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { +when xlib.IS_SUPPORTED { XlibDisplay :: xlib.Display XlibWindow :: xlib.Window XlibVisualID :: xlib.VisualID diff --git a/vendor/x11/xlib/xlib.odin b/vendor/x11/xlib/xlib.odin new file mode 100644 index 000000000..bd9ba3b59 --- /dev/null +++ b/vendor/x11/xlib/xlib.odin @@ -0,0 +1,4 @@ +package xlib + +// Value, specifying whether `vendor:x11/xlib` is available on the current platform. +IS_SUPPORTED :: ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD -- cgit v1.2.3 From bf0e6eaf606df2448a83916ca35b21eda1b3c287 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 5 Jan 2025 19:21:39 +0100 Subject: vendor/raylib: fix SetVertexAttribute definition Fixes #4596 --- vendor/raylib/rlgl/rlgl.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/raylib/rlgl/rlgl.odin b/vendor/raylib/rlgl/rlgl.odin index 340a983de..6ac19695d 100644 --- a/vendor/raylib/rlgl/rlgl.odin +++ b/vendor/raylib/rlgl/rlgl.odin @@ -514,7 +514,7 @@ foreign lib { UpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data UnloadVertexArray :: proc(vaoId: c.uint) --- UnloadVertexBuffer :: proc(vboId: c.uint) --- - SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) --- + SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, offset: c.int) --- SetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) --- SetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value DrawVertexArray :: proc(offset: c.int, count: c.int) --- -- cgit v1.2.3 From 0cc1dbb092fad6024f3258dd97c3371332a30134 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 5 Jan 2025 19:35:37 +0100 Subject: vendor/box2d: clarify wasm building --- vendor/box2d/box2d.odin | 2 +- vendor/box2d/build_box2d.sh | 5 +++++ vendor/box2d/wasm.Makefile | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/vendor/box2d/box2d.odin b/vendor/box2d/box2d.odin index 83c43800b..8abf6ce03 100644 --- a/vendor/box2d/box2d.odin +++ b/vendor/box2d/box2d.odin @@ -24,7 +24,7 @@ when ODIN_OS == .Windows { } when !#exists(LIB_PATH) { - #panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`") + #panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build_box2d.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`") } foreign import lib { diff --git a/vendor/box2d/build_box2d.sh b/vendor/box2d/build_box2d.sh index 0c5ff999d..74d75eb57 100755 --- a/vendor/box2d/build_box2d.sh +++ b/vendor/box2d/build_box2d.sh @@ -68,7 +68,12 @@ esac cd .. +set +e make -f wasm.Makefile +if [[ $? -ne 0 ]]; then + printf "\e[30;43mwarning:\e[0m Native Box2D libraries were built successfully, the WASM build failed, likely because your default C compiler and/or linker doesn't support WASM, you can set the CC and LD environment variables to point to a compiler and linker that support it\n" +fi +set -e rm -rf v3.0.0.tar.gz rm -rf box2d-3.0.0 diff --git a/vendor/box2d/wasm.Makefile b/vendor/box2d/wasm.Makefile index c3e3ed25a..e8ecb485e 100644 --- a/vendor/box2d/wasm.Makefile +++ b/vendor/box2d/wasm.Makefile @@ -2,6 +2,8 @@ # I tried to make a cmake toolchain file for this / use cmake but this is far easier. # NOTE: We are pretending to be emscripten to box2d so it takes WASM code paths, but we don't actually use emscripten. +# WARN: wasm is probably not supported by your default C compiler and linker, overwrite the CC and LD environment variables accordingly. +# Example for MacOS: # CC = $(shell brew --prefix llvm)/bin/clang # LD = $(shell brew --prefix llvm)/bin/wasm-ld -- cgit v1.2.3