aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/container/xar/xar.odin484
-rw-r--r--core/odin/parser/file_tags.odin35
-rw-r--r--core/strings/builder.odin87
-rw-r--r--examples/all/all_main.odin1
-rw-r--r--src/check_expr.cpp22
-rw-r--r--src/exact_value.cpp19
-rw-r--r--vendor/curl/curl.odin4
-rw-r--r--vendor/curl/curl_multi.odin4
-rw-r--r--vendor/glfw/bindings/bindings.odin4
-rw-r--r--vendor/kb_text_shape/lib/kb_text_shape.libbin852874 -> 853396 bytes
-rw-r--r--vendor/kb_text_shape/src/kb_text_shape.h38
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
index 000ae09b2..6a48e9f87 100644
--- a/vendor/kb_text_shape/lib/kb_text_shape.lib
+++ b/vendor/kb_text_shape/lib/kb_text_shape.lib
Binary files differ
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);