diff options
| -rw-r--r-- | core/container/xar/xar.odin | 484 | ||||
| -rw-r--r-- | core/odin/parser/file_tags.odin | 35 | ||||
| -rw-r--r-- | core/strings/builder.odin | 87 | ||||
| -rw-r--r-- | examples/all/all_main.odin | 1 | ||||
| -rw-r--r-- | src/check_expr.cpp | 22 | ||||
| -rw-r--r-- | src/exact_value.cpp | 19 | ||||
| -rw-r--r-- | vendor/curl/curl.odin | 4 | ||||
| -rw-r--r-- | vendor/curl/curl_multi.odin | 4 | ||||
| -rw-r--r-- | vendor/glfw/bindings/bindings.odin | 4 | ||||
| -rw-r--r-- | vendor/kb_text_shape/lib/kb_text_shape.lib | bin | 852874 -> 853396 bytes | |||
| -rw-r--r-- | vendor/kb_text_shape/src/kb_text_shape.h | 38 |
11 files changed, 667 insertions, 31 deletions
diff --git a/core/container/xar/xar.odin b/core/container/xar/xar.odin new file mode 100644 index 000000000..616a05e06 --- /dev/null +++ b/core/container/xar/xar.odin @@ -0,0 +1,484 @@ +/* + Exponential Array (Xar). + + A dynamically growing array using exponentially-sized chunks, providing stable + memory addresses for all elements. Unlike `[dynamic]T`, elements are never + moved once allocated, making it safe to hold pointers to elements. + + For more information: https://azmr.uk/dyn/#exponential-arrayxar + + Example: + + import "core:container/xar" + + example :: proc() { + x: xar.Xar(int, 4) + defer xar.destroy(&x) + + xar.push_back(&x, 10) + xar.push_back(&x, 20) + xar.push_back(&x, 30) + + ptr := xar.get_ptr(&x, 1) // ptr remains valid after more push_backs + xar.push_back(&x, 40) + fmt.println(ptr^) // prints 20 + } +*/ +package container_xar + +@(require) import "core:mem" +@(require) import "base:intrinsics" +@(require) import "base:runtime" + +PLATFORM_BITS :: 8*size_of(uint) +_LOG2_PLATFORM_BITS :: intrinsics.constant_log2(PLATFORM_BITS) + +MAX_SHIFT :: PLATFORM_BITS>>1 + +/* + An Exponential Array with stable element addresses. + + Unlike `[dynamic]T` which reallocates and moves elements when growing, `Xar` + allocates separate chunks of exponentially increasing size. This guarantees + that pointers to elements remain valid for the lifetime of the container. + + Fields: + - `chunks`: Fixed array of multi-pointers to allocated chunks + - `len`: Number of elements currently stored + - `allocator`: Allocator used for chunk allocations + + Type Parameters: + - `T`: The element type + - `SHIFT`: Controls initial chunk size (1 << SHIFT). Must be in range (0, MAX_SHIFT]. + Larger values mean fewer, bigger chunks. Recommended: 4-8. + + Chunk sizes grow as: + - `chunks[0]`: 1 << SHIFT elements + - `chunks[1]`: 1 << SHIFT elements + - `chunks[2]`: 1 << (SHIFT + 1) elements + - `chunks[3]`: 1 << (SHIFT + 2) elements + - `chunks[4]`: 1 << (SHIFT + 3) elements + - ...and so on + + Example: + + import "core:container/xar" + + example :: proc() { + // Xar with initial chunk size of 16 (1 << 4) + x: xar.Xar(My_Struct, 4) + defer xar.destroy(&x) + } +*/ +Xar :: struct($T: typeid, $SHIFT: uint) where 0 < SHIFT, SHIFT <= MAX_SHIFT { + chunks: [(1 << (_LOG2_PLATFORM_BITS - intrinsics.constant_log2(SHIFT))) + 1][^]T, + len: int, + allocator: mem.Allocator, +} + + +/* +Initializes an exponential array with the given allocator. + +**Inputs** +- `x`: Pointer to the exponential array to initialize +- `allocator`: Allocator to use for chunk allocations (defaults to context.allocator) +*/ +init :: proc(x: ^$X/Xar($T, $SHIFT), allocator := context.allocator) { + x^ = {allocator = allocator} +} + +/* +Frees all allocated chunks and resets the exponential array. + +**Inputs** +- `x`: Pointer to the exponential array to destroy +*/ +destroy :: proc(x: ^$X/Xar($T, $SHIFT)) { + #reverse for c, i in x.chunks { + if c != nil { + n := 1 << (SHIFT + uint(i if i > 0 else 1) - 1) + size_in_bytes := n * size_of(T) + mem.free_with_size(c, size_in_bytes, x.allocator) + } + } + x^ = {} +} + +/* +Resets the array's length to zero without freeing memory. +Allocated chunks are retained for reuse. +*/ +clear :: proc(x: ^$X/Xar($T, $SHIFT)) { + x.len = 0 +} + +// Returns the length of the exponential-array +@(require_results) +len :: proc(x: $X/Xar($T, $SHIFT)) -> int { + return x.len +} + +// Returns the number of allocated elements +@(require_results) +cap :: proc(x: $X/Xar($T, $SHIFT)) -> int { + #reverse for c, i in x.chunks { + if c != nil { + return 1 << (SHIFT + uint(i if i > 0 else 1)) + } + } + return 0 +} + +// Internal: computes chunk index, element index within chunk, and chunk capacity for a given index. +@(require_results) +_meta_get :: #force_inline proc($SHIFT: uint, index: uint) -> (chunk_idx, elem_idx, chunk_cap: uint) { + elem_idx = index + chunk_cap = uint(1) << SHIFT + chunk_idx = 0 + + index_shift := index >> SHIFT + if index_shift > 0 { + N :: 8*size_of(uint)-1 + CLZ :: intrinsics.count_leading_zeros + chunk_idx = N-CLZ(index_shift) // MSB(index_shift) + + chunk_cap = 1 << (chunk_idx + SHIFT) + elem_idx -= chunk_cap + chunk_idx += 1 + } + + return +} +/* +Get a copy of the element at the specified index. + +**Inputs** +- `x`: Pointer to the exponential array +- `index`: Position of the element (0-indexed) + +**Returns** +- a copy of the element +*/ +@(require_results) +get :: proc(x: ^$X/Xar($T, $SHIFT), #any_int index: int, loc := #caller_location) -> (val: T) #no_bounds_check { + runtime.bounds_check_error_loc(loc, index, x.len) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, uint(index)) + return x.chunks[chunk_idx][elem_idx] +} + +/* +Get a pointer to the element at the specified index. + +The returned pointer remains valid even after additional elements are added, +as long as the element is not removed and the array is not destroyed. + +**Inputs** +- `x`: Pointer to the exponential array +- `index`: Position of the element (0-indexed) + +**Returns** +- a stable pointer to the element + +Example: + + import "core:container/xar" + + get_ptr_example :: proc() { + x: xar.Xar(int, 4) + defer xar.destroy(&x) + + xar.push_back(&x, 100) + ptr := xar.get_ptr(&x, 0) + + // Pointer remains valid after growing + for i in 0..<1000 { + xar.push_back(&x, i) + } + + fmt.println(ptr^) // Still prints 100 + } +*/ +@(require_results) +get_ptr :: proc(x: ^$X/Xar($T, $SHIFT), #any_int index: int, loc := #caller_location) -> (val: ^T) #no_bounds_check { + runtime.bounds_check_error_loc(loc, index, x.len) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, uint(index)) + return &x.chunks[chunk_idx][elem_idx] +} + +/* +Set the element at the specified index to the given value. + +**Inputs** +- `x`: Pointer to the exponential array +- `index`: Position of the element (0-indexed) +- `value`: The value to set +*/ +set :: proc(x: ^$X/Xar($T, $SHIFT), #any_int index: int, value: T, loc := #caller_location) #no_bounds_check { + runtime.bounds_check_error_loc(loc, index, x.len) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, uint(index)) + x.chunks[chunk_idx][elem_idx] = value +} + +append :: proc{push_back_elem, push_back_elems} +push_back :: proc{push_back_elem, push_back_elems} + +/* +Append an element to the end of the exponential array. +Allocates a new chunk if necessary. Existing elements aren't moved, and their pointers remain stable. + +**Inputs** +- `x`: Pointer to the exponential array +- `value`: The element to append + +**Returns** +- number of elements added (always 1 on success) +- allocation error if chunk allocation failed + +Example: + + import "core:container/xar" + + push_back_example :: proc() { + x: xar.Xar(string, 4) + defer xar.destroy(&x) + + xar.push_back(&x, "hello") + xar.push_back(&x, "world") + + fmt.println(xar.get(&x, 0)) // hello + fmt.println(xar.get(&x, 1)) // world + } +*/ +push_back_elem :: proc(x: ^$X/Xar($T, $SHIFT), value: T, loc := #caller_location) -> (n: int, err: mem.Allocator_Error) { + if x.allocator.procedure == nil { + // to minic `[dynamic]T` behaviour + x.allocator = context.allocator + } + + chunk_idx, elem_idx, chunk_cap := _meta_get(SHIFT, uint(x.len)) + if x.chunks[chunk_idx] == nil { + x.chunks[chunk_idx] = make([^]T, chunk_cap, x.allocator) or_return + } + x.chunks[chunk_idx][elem_idx] = value + x.len += 1 + n = 1 + return +} + +/* +Append multiple elements to the end of the exponential array. + +**Inputs** +- `x`: Pointer to the exponential array +- `values`: The elements to append + +**Returns** +- number of elements successfully added +- allocation error if chunk allocation failed (partial append possible) +*/ +push_back_elems :: proc(x: ^$X/Xar($T, $SHIFT), values: ..T, loc := #caller_location) -> (n: int, err: mem.Allocator_Error) { + for value in values { + n += push_back_elem(x, value, loc) or_return + } + return +} + +append_and_get_ptr :: push_back_elem_and_get_ptr +/* +Append an element and return a stable pointer to it. +This is useful when you need to initialize a complex struct in-place or +retain a reference to the newly added element. + +**Inputs** +- `x`: Pointer to the exponential array +- `value`: The element to append + +**Returns** +- a stable pointer to the newly added element +- allocation error if chunk allocation failed + +Example: + + import "core:container/xar" + + push_back_and_get_ptr_example :: proc() { + x: xar.Xar(My_Struct, 4) + defer xar.destroy(&x) + + ptr := xar.push_back_elem_and_get_ptr(&x, My_Struct{}) or_else panic("alloc failed") + ptr.field = 42 // Initialize in-place + } +*/ +@(require_results) +push_back_elem_and_get_ptr :: proc(x: ^$X/Xar($T, $SHIFT), value: T, loc := #caller_location) -> (ptr: ^T, err: mem.Allocator_Error) { + if x.allocator.procedure == nil { + // to minic `[dynamic]T` behaviour + x.allocator = context.allocator + } + + chunk_idx, elem_idx, chunk_cap := _meta_get(SHIFT, uint(x.len)) + if x.chunks[chunk_idx] == nil { + x.chunks[chunk_idx] = make([^]T, chunk_cap, x.allocator) or_return + } + x.chunks[chunk_idx][elem_idx] = value + x.len += 1 + n = 1 + ptr = &x.chunks[chunk_idx][elem_idx] + return +} + +// `pop` will remove and return the end value of an exponential array `x` and reduces the length of the array by 1. +// +// Note: If the exponential array has no elements (`xar.len(x) == 0`), this procedure will panic. +pop :: proc(x: ^$X/Xar($T, $SHIFT), loc := #caller_location) -> (val: T) { + assert(x.len > 0, loc=loc) + index := uint(x.len-1) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, index) + x.len -= 1 + return x.chunks[chunk_idx][elem_idx] +} + +// `pop_safe` trys to remove and return the end value of dynamic array `x` and reduces the length of the array by 1. +// If the operation is not possible, it will return false. +@(require_results) +pop_safe :: proc(x: ^$X/Xar($T, $SHIFT)) -> (val: T, ok: bool) { + if x.len == 0 { + return + } + index := uint(x.len-1) + chunk_idx, elem_idx, _ := _meta_get(SHIFT, index) + x.len -= 1 + + val = x.chunks[chunk_idx][elem_idx] + ok = true + return +} + +/* + `unordered_remove` removed the element at the specified `index`. It does so by replacing the current end value + with the old value, and reducing the length of the exponential array by 1. + + Note: This is an O(1) operation. + Note: This is currently no procedure that is the equivalent of an "ordered_remove" + Note: If the index is out of bounds, this procedure will panic. + + Note: Pointers to the last element become invalid (it gets moved). Pointers to other elements remain valid. + + Example: + + import "core:encoding/xar" + + unordered_remove_example :: proc() { + x: xar.Xar(int, 4) + defer xar.destroy(&x) + + xar.push_back(&x, 10) + xar.push_back(&x, 20) + xar.push_back(&x, 30) + + xar.unordered_remove(&x, 0) // Removes 10, replaces with 30 + + // Array now contains [30, 20] + fmt.println(xar.get(&x, 0)) // 30 + fmt.println(xar.get(&x, 1)) // 20 + } +*/ +unordered_remove :: proc(x: ^$X/Xar($T, $SHIFT), #any_int index: int, loc := #caller_location) { + runtime.bounds_check_error_loc(loc, index, x.len) + n := x.len-1 + if index != n { + end := get(x, n) + set(x, index, end) + } + x.len -= 1 +} + + +/* +Iterator state for traversing a `Xar`. + +Fields: +- `xar`: Pointer to the exponential array being iterated +- `idx`: Current iteration index +*/ +Iterator :: struct($T: typeid, $SHIFT: uint) { + xar: ^Xar(T, SHIFT), + idx: int, +} + +/* +Create an iterator for traversing the exponential array. + +**Inputs** +- `xar`: Pointer to the exponential array + +**Returns** +- an iterator positioned at the start + +Example: + + import "lib:xar" + + iteration_example :: proc() { + x: xar.Xar(int, 4) + defer xar.destroy(&x) + + xar.push_back(&x, 10) + xar.push_back(&x, 20) + xar.push_back(&x, 30) + + it := xar.iterator(&x) + for val in xar.iterate_by_ptr(&it) { + fmt.println(val^) + } + } + +Output: + + 10 + 20 + 30 +*/ +iterator :: proc(xar: ^$X/Xar($T, $SHIFT)) -> Iterator(T, SHIFT) { + return {xar = auto_cast xar, idx = 0} +} + +/* +Advance the iterator and returns the next element. + +**Inputs** +- `it`: Pointer to the iterator + +**Returns** +- current element +- `true` if an element was returned, `false` if iteration is complete +*/ +iterate_by_val :: proc(it: ^Iterator($T, $SHIFT)) -> (val: T, ok: bool) { + if it.idx >= it.xar.len { + return + } + val = get(it.xar, it.idx) + it.idx += 1 + return val, true +} + + +/* +Advance the iterator and returns a pointer to the next element. + +**Inputs** +- `it`: Pointer to the iterator + +**Returns** +- pointer to the current element +- `true` if an element was returned, `false` if iteration is complete +*/ +iterate_by_ptr :: proc(it: ^Iterator($T, $SHIFT)) -> (val: ^T, ok: bool) { + if it.idx >= it.xar.len { + return + } + val = get_ptr(it.xar, it.idx) + it.idx += 1 + return val, true +} diff --git a/core/odin/parser/file_tags.odin b/core/odin/parser/file_tags.odin index 24aea3b9e..669fa5263 100644 --- a/core/odin/parser/file_tags.odin +++ b/core/odin/parser/file_tags.odin @@ -65,12 +65,6 @@ get_build_arch_from_string :: proc(str: string) -> runtime.Odin_Arch_Type { @require_results parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags: File_Tags) { - context.allocator = allocator - - if file.docs == nil && file.tags == nil { - return - } - next_char :: proc(src: string, i: ^int) -> (ch: u8) { if i^ < len(src) { ch = src[i^] @@ -102,15 +96,6 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags } } - build_kinds: [dynamic]Build_Kind - defer shrink(&build_kinds) - - build_project_name_strings: [dynamic]string - defer shrink(&build_project_name_strings) - - build_project_names: [dynamic][]string - defer shrink(&build_project_names) - parse_tag :: proc(text: string, tags: ^File_Tags, build_kinds: ^[dynamic]Build_Kind, build_project_name_strings: ^[dynamic]string, build_project_names: ^[dynamic][]string) { @@ -143,7 +128,7 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags for { skip_whitespace(text, &i) name_start := i - + switch next_char(text, &i) { case 0, '\r', '\n': i -= 1 @@ -155,7 +140,7 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags case: i -= 1 } - + scan_value(text, &i) append(build_project_name_strings, text[name_start:i]) } @@ -220,6 +205,18 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags } } + context.allocator = allocator + + if file.docs == nil && file.tags == nil { + return + } + + build_kinds: [dynamic]Build_Kind + build_project_names: [dynamic][]string + + build_project_name_strings: [dynamic]string + + if file.docs != nil { for comment in file.docs.list { if len(comment.text) < 3 || comment.text[:2] != "//" { @@ -241,6 +238,10 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags parse_tag(text, &tags, &build_kinds, &build_project_name_strings, &build_project_names) } + shrink(&build_kinds) + shrink(&build_project_names) + delete(build_project_name_strings) + tags.build = build_kinds[:] tags.build_project_name = build_project_names[:] diff --git a/core/strings/builder.odin b/core/strings/builder.odin index a6d0b24b3..da9b6df27 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -835,3 +835,90 @@ Returns: write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) { return write_i64(b, i64(i), base) } + + +/* +Replaces all instances of `old` in the string in a Builder `b` with the `new` string + +*Allocates Using The Allocator On The Builder* + +Inputs: +- b: The input `Builder` +- old: The substring to be replaced +- new: The replacement string + +Returns: +- replaced: The number of replacements +- err: if any allocation errors occurred +*/ +builder_replace_all :: proc(b: ^Builder, old, new: string) -> (replaced: int, err: mem.Allocator_Error) { + return builder_replace(b, old, new, -1) +} + +/* +Replaces n instances of `old` in the string in a Builder `b` with the `new` string + +*Allocates Using The Allocator On The Builder* + +Inputs: +- b: The input `Builder` +- old: The substring to be replaced +- new: The replacement string +- n: The number of instances to replace (if `n < 0`, no limit on the number of replacements) + +Returns: +- replaced: The number of replacements +- err: if any allocation errors occurred +*/ +builder_replace :: proc(b: ^Builder, old, new: string, n: int, loc := #caller_location) -> (replaced: int, err: mem.Allocator_Error) { + if old == new || n == 0 { + return + } + + if m := count(to_string(b^), old); m == 0 { + return + } + + if len(old) == 0 { + for i := 0; i <= len(b.buf); i += len(new)+1 { + if n > 0 && replaced == n { + break + } + + resize(&b.buf, len(b.buf)+len(new), loc) or_return + copy(b.buf[i+len(new):], b.buf[i:]) + copy(b.buf[i:], new) + replaced += 1 + } + } else { + for i := 0; i < len(b.buf); /**/ { + if n > 0 && replaced == n { + break + } + + j := index(string(b.buf[i:]), old) + if j < 0 { + break + } + + if len(new) >= len(old) { + resize(&b.buf, len(b.buf) + len(new)-len(old)) or_return + } + + cur := b.buf[i+j:] + src := cur[len(old):] + dst := cur[len(new):] + copy(dst, src) + copy(cur, new) + + i += j+len(new) + + replaced += 1 + + if len(new) < len(old) { + resize(&b.buf, len(b.buf) + len(new)-len(old)) or_return + } + } + } + return +}
\ No newline at end of file diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index cda04278e..7895b4640 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -24,6 +24,7 @@ package all @(require) import "core:container/intrusive/list" @(require) import "core:container/rbtree" @(require) import "core:container/topological_sort" +@(require) import "core:container/xar" @(require) import "core:crypto" @(require) import "core:crypto/aead" diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 470290d49..2fe6c0251 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4451,6 +4451,9 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ break; } } + } else if (is_type_array_like(x->type)) { + x->mode = Addressing_Value; + return; } else { x->value = exact_binary_operator_value(op.kind, a, b); } @@ -12100,6 +12103,25 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) { +gb_internal bool compare_exact_values_compound_lit(TokenKind op, ExactValue x, ExactValue y, bool *do_break_) { + ast_node(x_cl, CompoundLit, x.value_compound); + ast_node(y_cl, CompoundLit, y.value_compound); + + if (x_cl->elems.count != y_cl->elems.count) { + if (do_break_) *do_break_ = true; + } + + bool test = op == Token_CmpEq; + + for (isize i = 0; i < x_cl->elems.count; i++) { + Ast *lhs = x_cl->elems[i]; + Ast *rhs = y_cl->elems[i]; + if (compare_exact_values(op, lhs->tav.value, rhs->tav.value) != test) { + return !test; + } + } + return test; +} diff --git a/src/exact_value.cpp b/src/exact_value.cpp index e7077bd5b..f266b8b24 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -947,6 +947,8 @@ gb_internal gb_inline i32 cmp_f64(f64 a, f64 b) { return (a > b) - (a < b); } +gb_internal bool compare_exact_values_compound_lit(TokenKind op, ExactValue x, ExactValue y, bool *do_break_); + gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { match_exact_values(&x, &y); @@ -1055,9 +1057,24 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) case Token_NotEq: return x.value_typeid != y.value_typeid; } break; + + case ExactValue_Compound: + if (op != Token_CmpEq && op != Token_NotEq) { + break; + } + + if (x.kind != y.kind) { + break; + } + bool do_break = false; + bool res = compare_exact_values_compound_lit(op, x, y, &do_break); + if (do_break) { + break; + } + return res; } - GB_PANIC("Invalid comparison"); + GB_PANIC("Invalid comparison: %d", x.kind); return false; } diff --git a/vendor/curl/curl.odin b/vendor/curl/curl.odin index 073927dc6..ce10c443f 100644 --- a/vendor/curl/curl.odin +++ b/vendor/curl/curl.odin @@ -2502,7 +2502,7 @@ foreign lib { * Appends a string to a linked list. If no list exists, it will be created * first. Returns the new list, after appending. */ - slist_append :: proc(list: ^slist, data: [^]byte) -> ^slist --- + slist_append :: proc(list: ^slist, data: cstring) -> ^slist --- /* * NAME curl_slist_free_all() @@ -2932,4 +2932,4 @@ foreign lib { userptr: rawptr) -> code --- -}
\ No newline at end of file +} diff --git a/vendor/curl/curl_multi.odin b/vendor/curl/curl_multi.odin index 860c8dbc1..624078684 100644 --- a/vendor/curl/curl_multi.odin +++ b/vendor/curl/curl_multi.odin @@ -410,7 +410,7 @@ foreign lib { * * Returns: NULL on failure, otherwise a CURL **array pointer */ - multi_get_handles :: proc(multi_handle: ^CURLM) -> ^^CURL --- + multi_get_handles :: proc(multi_handle: ^CURLM) -> [^]^CURL --- /* * Name: curl_multi_get_offt() @@ -482,4 +482,4 @@ foreign lib { ufds: [^]waitfd, size: c.uint, fd_count: ^c.uint) -> Mcode --- -}
\ No newline at end of file +} diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index abf6c2150..3f2f08237 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -212,9 +212,9 @@ foreign glfw { // Functions added in 3.4, Linux links against system glfw so we define these as weak to be able // to check at runtime if they are available. - @(linkage="weak") + @(linkage="strong" when ODIN_OS == .Windows else "weak") GetPlatform :: proc() -> c.int --- - @(linkage="weak") + @(linkage="strong" when ODIN_OS == .Windows else "weak") PlatformSupported :: proc(platform: c.int) -> b32 --- } diff --git a/vendor/kb_text_shape/lib/kb_text_shape.lib b/vendor/kb_text_shape/lib/kb_text_shape.lib Binary files differindex 000ae09b2..6a48e9f87 100644 --- a/vendor/kb_text_shape/lib/kb_text_shape.lib +++ b/vendor/kb_text_shape/lib/kb_text_shape.lib diff --git a/vendor/kb_text_shape/src/kb_text_shape.h b/vendor/kb_text_shape/src/kb_text_shape.h index e9e2f575e..986bf3be6 100644 --- a/vendor/kb_text_shape/src/kb_text_shape.h +++ b/vendor/kb_text_shape/src/kb_text_shape.h @@ -1,4 +1,4 @@ -/* kb_text_shape - v2.03 - text segmentation and shaping +/* kb_text_shape - v2.05 - text segmentation and shaping by Jimmy Lefevre SECURITY @@ -1245,6 +1245,9 @@ See https://unicode.org/reports/tr9 for more information. VERSION HISTORY + 2.05 - Fix custom allocator initialization for kbts_shape_context.PermanentArena. + 2.04 - Fix Indic syllable logic for small/single-character syllables. + Fix wrong indirection in pointer code in Indic syllable logic. 2.03 - Fix loading blobs directly, fix a parsing edge case in GPOS format 2 subtables. 2.02 - Improve globbing of cursive attachments. 2.01 - Add kbts_InitializeGlyphStorage and kbts_ScriptDirection. @@ -23172,20 +23175,33 @@ static kbts_glyph *kbts__BeginCluster(kbts__shape_scratchpad *Scratchpad, kbts_s case KBTS__REPH_ENCODING_IMPLICIT: if((ScanGlyphIndex >= 2) && - (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && - kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Rphf, 0, FirstGlyphs[0], 2)) + (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) { - OnePastRephIndex = 2; + kbts_glyph Scratch[2]; + Scratch[0] = *FirstGlyphs[0]; + Scratch[1] = *FirstGlyphs[1]; + + if(kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Rphf, 0, Scratch, 2)) + { + OnePastRephIndex = 2; + } } break; case KBTS__REPH_ENCODING_EXPLICIT: if((ScanGlyphIndex >= 3) && (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && - (Third->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ) && - kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Rphf, 0, FirstGlyphs[0], 3)) + (Third->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) { - OnePastRephIndex = 3; + kbts_glyph Scratch[3]; + Scratch[0] = *FirstGlyphs[0]; + Scratch[1] = *FirstGlyphs[1]; + Scratch[2] = *FirstGlyphs[2]; + + if(kbts__WouldSubstitute(Scratchpad, Config, Storage, LookupList, Frames, Rphf, 0, Scratch, 3)) + { + OnePastRephIndex = 3; + } } break; } @@ -24068,6 +24084,7 @@ static void kbts__EndCluster(kbts__shape_scratchpad *Scratchpad, kbts_shape_conf kbts_glyph *First = Storage->GlyphSentinel.Next; kbts_glyph *Second = First->Next; if((First->SyllabicPosition == KBTS__SYLLABIC_POSITION_RA_TO_BECOME_REPH) && + kbts__GlyphIsValid(Storage, Second) && (Second->SyllabicPosition != KBTS__SYLLABIC_POSITION_RA_TO_BECOME_REPH)) { kbts__reph_position RephPosition = Config->IndicScriptProperties.RephPosition; @@ -25005,6 +25022,9 @@ KBTS_EXPORT kbts_shape_context *kbts_PlaceShapeContext(kbts_allocator_function * KBTS_MEMSET(Result, 0, sizeof(*Result)); + Result->PermanentArena.Allocator = Allocator; + Result->PermanentArena.AllocatorData = AllocatorData; + Result->FontArena.Allocator = Allocator; Result->FontArena.AllocatorData = AllocatorData; @@ -25014,6 +25034,9 @@ KBTS_EXPORT kbts_shape_context *kbts_PlaceShapeContext(kbts_allocator_function * Result->ScratchArena.Allocator = Allocator; Result->ScratchArena.AllocatorData = AllocatorData; + Result->GlyphStorage.Arena.Allocator = Allocator; + Result->GlyphStorage.Arena.AllocatorData = AllocatorData; + KBTS__DLLIST_SENTINEL_INIT(&Result->FeatureOverrideSentinel); KBTS__DLLIST_SENTINEL_INIT(&Result->FreeFeatureOverrideSentinel); } @@ -25055,6 +25078,7 @@ KBTS_EXPORT void kbts_DestroyShapeContext(kbts_shape_context *Context) { if(Context) { + kbts__FreeArena(&Context->PermanentArena); kbts__FreeArena(&Context->ConfigArena); kbts__FreeArena(&Context->ScratchArena); kbts__FreeArena(&Context->FontArena); |