diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index 4172e9c0f..0fa46975b 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -97,12 +97,12 @@ private fn void*! DynamicArenaAllocator._alloc_new(DynamicArenaAllocator* this, } page.memory = mem; void* mem_start = mem::aligned_pointer(mem + offset + DynamicArenaChunk.sizeof, alignment) - offset; - assert(mem_start + DynamicArenaChunk.sizeof + size < mem + page_size); + assert(mem_start + size < mem + page_size); DynamicArenaChunk* chunk = (DynamicArenaChunk*)mem_start - 1; chunk.size = size; page.prev_arena = this.page; page.total = page_size; - page.used = size + offset; + page.used = mem_start + size - page.memory; this.page = page; page.last_ptr = mem_start; return mem_start; @@ -144,6 +144,7 @@ private fn void*! DynamicArenaAllocator._alloc(DynamicArenaAllocator* this, usiz } page.used = new_used; + assert(start + size == page.memory + page.used); void* mem = start; DynamicArenaChunk* chunk = (DynamicArenaChunk*)mem - 1; chunk.size = size; diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index bd352d73f..e41ccba09 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -50,6 +50,58 @@ macro void clear(void* dst, usize len, usize $dst_align = 0, bool $is_volatile = $$memset(dst, (char)0, len, $is_volatile, $dst_align); } +/** + * @require $typeof(a).kind == TypeKind.SUBARRAY || $typeof(a).kind == TypeKind.POINTER + * @require $typeof(b).kind == TypeKind.SUBARRAY || $typeof(b).kind == TypeKind.POINTER + * @require $typeof(a).kind != TypeKind.SUBARRAY || len == -1 + * @require $typeof(a).kind != TypeKind.POINTER || len > -1 + * @checked (a = b), (b = a) + **/ +macro bool equals(a, b, isize len = -1, usize $alignment = 0) +{ + var $align = $alignment; + $if (!$alignment): + $align = $alignof($typeof(a[0])); + $endif; + void* x = void; + void* y = void; + $if ($typeof(a).kind == TypeKind.SUBARRAY): + len = a.len; + if (len != b.len) return false; + x = a.ptr; + y = b.ptr; + $else: + x = a; + y = b; + assert(len >= 0, "A zero or positive length must be given when comparing pointers."); + $endif; + + if (!len) return true; + $switch ($align): + $case 1: + var $Type = char; + $case 2: + var $Type = ushort; + $case 4: + var $Type = uint; + $case 8: + $default: + var $Type = ulong; + $endswitch; + var $step = $Type.sizeof; + usize end = len / $step; + for (usize i = 0; i < end; i++) + { + if ((($Type*)x)[i] != (($Type*)y)[i]) return false; + } + usize last = len % $align; + for (usize i = len - last; i < len; i++) + { + if (((char*)x)[i] != ((char*)y)[i]) return false; + } + return true; +} + macro @clone(&value) @builtin { $typeof(value)* x = malloc($typeof(value)); diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 20cdb0527..07682747e 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -109,6 +109,18 @@ macro bool is_comparable($Type) $endif; } +macro bool is_subarray_convertable($Type) +{ + $switch ($Type.kind): + $case SUBARRAY: + return true; + $case POINTER: + return $Type.inner.kind == TypeKind.ARRAY; + $default: + return false; + $endswitch; +} + macro bool is_equatable_value(value) { $if ($defined(value.less) || $defined(value.compare_to) || $defined(value.equals)): diff --git a/resources/examples/contextfree/boolerr.c3 b/resources/examples/contextfree/boolerr.c3 index 690c38068..d4f4c4868 100644 --- a/resources/examples/contextfree/boolerr.c3 +++ b/resources/examples/contextfree/boolerr.c3 @@ -34,7 +34,7 @@ fn bool contains(char[] haystack, char[] needle) len -= needle_len - 1; for (usize i = 0; i < len; i++) { - if (libc::memcmp(&haystack[i], needle.ptr, needle_len) == 0) + if (mem::equals(haystack[i..], needle)) { return true; } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 30a6b1b8b..1ab56a0f3 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2226,7 +2226,7 @@ static inline bool type_info_poison(TypeInfo *type) static inline bool type_is_arraylike(Type *type) { DECL_TYPE_KIND_REAL(kind, type); - return kind == TYPE_ARRAY || kind == TYPE_VECTOR; + return kind == TYPE_ARRAY || kind == TYPE_VECTOR || kind == TYPE_FLEXIBLE_ARRAY; } static inline CanonicalType *type_pointer_type(Type *type) diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index c71ffd0d7..5111877b9 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1977,10 +1977,7 @@ static bool sema_analyse_ct_switch_body(SemaContext *context, Ast *statement) statement->ast_kind = AST_NOP_STMT; return true; } - if (!sema_analyse_statement(context, body)) return false; - - *statement = *body; - return true; + return sema_analyse_then_overwrite(context, statement, body->compound_stmt.first_stmt); } static bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statement) diff --git a/test/test_suite/stdlib/memcomp.c3t b/test/test_suite/stdlib/memcomp.c3t new file mode 100644 index 000000000..4a8cfb9a3 --- /dev/null +++ b/test/test_suite/stdlib/memcomp.c3t @@ -0,0 +1,16 @@ +// #target: macos-x64 +module test; +import std::io; +import libc; + +fn void main() +{ + int[] ab = { 3, 5, 6, 10, 0x0b2399 }; + int[] cd = { 3, 5, 6, 10, 0x0b2399 }; + char[] x = "hello world!"; + char[] y = "hello world?"; + io::printfln("is matching: %s", mem::equals(ab, cd)); + io::printfln("is matching: %s", mem::equals(x, y)); + io::printfln("is matching: %s", mem::equals(x.ptr, y.ptr, x.len)); + io::printfln("is matching: %s", mem::equals(ab.ptr, cd.ptr, ab.len * 4, 4)); +} \ No newline at end of file diff --git a/test/test_suite2/stdlib/memcomp.c3t b/test/test_suite2/stdlib/memcomp.c3t new file mode 100644 index 000000000..4a8cfb9a3 --- /dev/null +++ b/test/test_suite2/stdlib/memcomp.c3t @@ -0,0 +1,16 @@ +// #target: macos-x64 +module test; +import std::io; +import libc; + +fn void main() +{ + int[] ab = { 3, 5, 6, 10, 0x0b2399 }; + int[] cd = { 3, 5, 6, 10, 0x0b2399 }; + char[] x = "hello world!"; + char[] y = "hello world?"; + io::printfln("is matching: %s", mem::equals(ab, cd)); + io::printfln("is matching: %s", mem::equals(x, y)); + io::printfln("is matching: %s", mem::equals(x.ptr, y.ptr, x.len)); + io::printfln("is matching: %s", mem::equals(ab.ptr, cd.ptr, ab.len * 4, 4)); +} \ No newline at end of file