Skip to content

StrLen

Description

Get string length in characters.

Parameters

Name Direction Description
str in String to query.

Success

Length of string.

Failure

Function cannot fail.

Usage example (Cross-references)

Usage examples (Cross-references)
    
        File out = (type == LOG_MESSAGE_TYPE_INFO) ? FileFromFd(1) : FileFromFd(2);
        (void)FileWrite(&out, StrBegin(&full), StrLen(&full));
    
    #if FEATURE_SYS_BACKTRACE && (!defined(LOG_NO_BACKTRACE) || !LOG_NO_BACKTRACE)
            // boundary; pass at the call site, no intermediate variable.
            FormatStackTrace(&trace, frames, n, ALLOCATOR_OF(&h));
            (void)FileWrite(&out, StrBegin(&trace), StrLen(&trace));
            StrDeinit(&trace);
        }
        bool             ok      = str_append_fmt(&tmp, fmt, args, argc);
        if (ok) {
            if (offset > StrLen(o) || StrLen(&tmp) > StrLen(o) - offset) {
                LOG_ERROR(
                    "StrPatchFmt: write of {} bytes at offset {} exceeds str length {}",
                LOG_ERROR(
                    "StrPatchFmt: write of {} bytes at offset {} exceeds str length {}",
                    StrLen(&tmp),
                    offset,
                    StrLen(o)
                    StrLen(&tmp),
                    offset,
                    StrLen(o)
                );
                ok = false;
                );
                ok = false;
            } else if (StrLen(&tmp)) {
                MemCopy(StrBegin(o) + offset, StrBegin(&tmp), StrLen(&tmp));
            }
                ok = false;
            } else if (StrLen(&tmp)) {
                MemCopy(StrBegin(o) + offset, StrBegin(&tmp), StrLen(&tmp));
            }
        }
        }
    
        if (ok && StrLen(&out) > 0 && FileWrite(stream, StrBegin(&out), StrLen(&out)) != (i64)StrLen(&out)) {
            LOG_ERROR("Failed to write formatted output");
            ok = false;
        bool             ok      = render_binary_fmt(&tmp, fmtstr, argv, argc);
        if (ok) {
            if (offset > BufLength(out) || StrLen(&tmp) > BufLength(out) - offset) {
                LOG_ERROR(
                    "BufPatchFmt: write of {} bytes at offset {} exceeds buf length {}",
                LOG_ERROR(
                    "BufPatchFmt: write of {} bytes at offset {} exceeds buf length {}",
                    StrLen(&tmp),
                    offset,
                    BufLength(out)
                );
                ok = false;
            } else if (StrLen(&tmp)) {
                MemCopy(BufData(out) + offset, StrBegin(&tmp), StrLen(&tmp));
            }
                ok = false;
            } else if (StrLen(&tmp)) {
                MemCopy(BufData(out) + offset, StrBegin(&tmp), StrLen(&tmp));
            }
        }
            }
    
            if (StrLen(&buffer)) {
                Zstr new_pos = str_read_fmt(StrBegin(&buffer), fmtstr, argv, argc);
                if (!new_pos) {
        }
    
        exponent = value->exponent + (i64)StrLen(&digits) - 1;
        if (!StrPushBackR(&result, StrBegin(&digits)[0])) {
            goto fail;
        }
    
        frac_digits = has_precision ? precision : (StrLen(&digits) > 0 ? StrLen(&digits) - 1 : 0);
        if (frac_digits > 0) {
            if (!StrPushBackR(&result, '.')) {
            }
            for (u64 i = 0; i < frac_digits; i++) {
                if (i + 1 < StrLen(&digits)) {
                    if (!StrPushBackR(&result, StrBegin(&digits)[i + 1])) {
                        goto fail;
        // can compute "how much content did we just emit" without
        // accounting for prior contents.
        size start_len = StrLen(o);
    
        if (StrLen(s)) {
        size start_len = StrLen(o);
    
        if (StrLen(s)) {
            if (fmt_info->flags & FMT_FLAG_HEX) {
                // `{x}` over a Str renders each byte as `0xNN` with a
                        return false;
                    }
                    if (StrLen(&hex) == 1) {
                        if (!StrPushFrontR(&hex, '0')) {
                            StrDeinit(&hex);
                // `{:.Ns}`); precision 0 is the explicit "render nothing"
                // case, not an error.
                size len = StrLen(s);
                if (fmt_info->flags & FMT_FLAG_HAS_PRECISION) {
                    if (fmt_info->precision == 0) {
    
        if (fmt_info->width > 0) {
            size content_len = StrLen(o) - start_len;
            if (!StrPad(o, fmt_info->width, fmt_info->align, content_len)) {
                return false;
        // Snapshot the pre-render length so post-render padding sees the
        // size of just-this-field, not the accumulated buffer.
        size start_len = StrLen(o);
        Zstr xs        = *s;
                        return false;
                    }
                    if (StrLen(&hex) == 1) {
                        if (!StrPushFrontR(&hex, '0')) {
                            StrDeinit(&hex);
    
        if (fmt_info->width > 0) {
            size content_len = StrLen(o) - start_len;
            if (!StrPad(o, fmt_info->width, fmt_info->align, content_len)) {
                return false;
        // Snapshot the pre-render length so post-render padding sees the
        // size of just-this-field, not the accumulated buffer.
        size start_len = StrLen(o);
    
        // Format into a scratch Str first, then merge into `o`: keeps the
    
        if (fmt_info->width > 0) {
            size content_len = StrLen(o) - start_len;
            if (zero_pad) {
                if (!pad_numeric_zeros(o, start_len, fmt_info->width, content_len)) {
        // Snapshot the pre-render length so post-render padding sees the
        // size of just-this-field, not the accumulated buffer.
        size start_len = StrLen(o);
    
        // Format into a scratch Str first, then merge into `o`: keeps the
    
        if (fmt_info->width > 0) {
            size content_len = StrLen(o) - start_len;
            if (zero_pad) {
                if (!pad_numeric_zeros(o, start_len, fmt_info->width, content_len)) {
        // Snapshot the pre-render length so post-render padding sees the
        // size of just-this-field, not the accumulated buffer.
        size start_len = StrLen(o);
    
        // NaN / +/-inf bypass `StrFromF64` so the rendered token stays
    
        if (fmt_info->width > 0) {
            size content_len = StrLen(o) - start_len;
            if (!StrPad(o, fmt_info->width, fmt_info->align, content_len)) {
                return false;
        }
    
        start_len = StrLen(o);
        if (fmt_info->flags & FMT_FLAG_SCIENTIFIC) {
            if (!float_try_to_scientific_str(
    
        if (fmt_info->width > 0) {
            size content_len = StrLen(o) - start_len;
            if (!StrPad(o, fmt_info->width, fmt_info->align, content_len)) {
                return false;
            return false;
    
        size        len  = StrLen(str);
        const char *data = StrBegin(str);
        // a malformed integer; the parser proper would accept the leading
        // '0' and silently lose the prefix, so reject early.
        if (StrLen(&temp) == 2 && StrBegin(&temp)[0] == '0' &&
            (StrBegin(&temp)[1] == 'x' || StrBegin(&temp)[1] == 'X' || StrBegin(&temp)[1] == 'b' ||
             StrBegin(&temp)[1] == 'B' || StrBegin(&temp)[1] == 'o' || StrBegin(&temp)[1] == 'O')) {
            Str  temp  = StrInitFromCstr(start, pos, &scratch);                                                            \
                                                                                                                           \
            if (StrLen(&temp) == 2 && StrBegin(&temp)[0] == '0' &&                                                         \
                (StrBegin(&temp)[1] == 'x' || StrBegin(&temp)[1] == 'X' || StrBegin(&temp)[1] == 'b' ||                    \
                 StrBegin(&temp)[1] == 'B' || StrBegin(&temp)[1] == 'o' || StrBegin(&temp)[1] == 'O')) {                   \
        // the caller owns and may mutate the returned buffer. ZstrDupN's Zstr
        // return is just the project-wide convention for fresh allocations.
        result = (char *)ZstrDupN(StrBegin(&temp), StrLen(&temp), allocator_ptr);
        if (!result) {
            LOG_ERROR("Failed to allocate memory for string");
        // Snapshot the pre-render length so post-render padding sees the
        // size of just-this-field, not the accumulated buffer.
        size start_len = StrLen(o);
    
        if (fmt_info->flags & FMT_FLAG_HEX) {
    
        if (fmt_info->width > 0) {
            size content_len = StrLen(o) - start_len;
            if (!StrPad(o, fmt_info->width, fmt_info->align, content_len)) {
                return false;
        }
    
        size start_len = StrLen(o);
        Str  temp;
        u8   radix = int_fmt_radix_from_flags(fmt_info);
    
        if (fmt_info->width > 0) {
            size content_len = StrLen(o) - start_len;
            if (!StrPad(o, fmt_info->width, fmt_info->align, content_len)) {
                return false;
    // the visible width so the caller can pad to a shared right margin.
    static u64 spec_format_left(const ArgSpec *sp, Str *out) {
        u64 start = StrLen(out);
        StrPushBackMany(out, "  ");
        if (sp->role == ARG_ROLE_POSITIONAL) {
            }
        }
        return StrLen(out) - start;
    }
        bool result = false;
    
        if (ZstrFindSubstringN(StrBegin(&bv_str), StrBegin(pattern), StrLen(pattern)) != NULL) {
            result = true;
        }
            LOG_FATAL("Invalid arguments");
        }
        return float_try_from_str_impl(out, StrBegin(text), StrLen(text));
    }
            }
        } else {
            i64 split = (i64)StrLen(&digits) + value->exponent;
    
            if (split > 0) {
                }
    
                for (u64 i = (u64)split; i < StrLen(&digits); i++) {
                    if (!StrPushBackR(&result, StrCharAt(&digits, i))) {
                        goto fail;
        ValidateStr(str);
    
        for (idx = 0; idx < StrLen(str); idx++) {
            hash ^= (u64)(unsigned char)StrCharAt(str, idx);
            hash *= 1099511628211ULL;
        ValidateStr(b);
    
        min = StrLen(a) < StrLen(b) ? StrLen(a) : StrLen(b);
        cmp = MemCompare(StrBegin(a), StrBegin(b), min);
            return cmp;
        }
        if (StrLen(a) < StrLen(b)) {
            return -1;
        }
            return -1;
        }
        if (StrLen(a) > StrLen(b)) {
            return 1;
        }
        ValidateStr(s);
        ValidateStr(key);
        return ZstrFindSubstringN(StrBegin(s), StrBegin(key), StrLen(key));
    }
        }
    
        if (StrLen(decimal) > 0 && StrCharAt(decimal, 0) == '+') {
            start = 1;
        }
        }
    
        return int_try_from_str_radix_impl(out, StrBegin(decimal), StrLen(decimal), start, 10, true);
    }
            LOG_FATAL("Invalid arguments");
        }
        if (StrLen(digits) > 0 && StrCharAt(digits, 0) == '+') {
            start = 1;
        }
        }
    
        return int_try_from_str_radix_impl(out, StrBegin(digits), StrLen(digits), start, radix, true);
    }
        }
    
        for (u64 i = 0; i < StrLen(&result) / 2; i++) {
            char *lhs = StrCharPtrAt(&result, i);
            char *rhs = StrCharPtrAt(&result, StrLen(&result) - 1 - i);
        for (u64 i = 0; i < StrLen(&result) / 2; i++) {
            char *lhs = StrCharPtrAt(&result, i);
            char *rhs = StrCharPtrAt(&result, StrLen(&result) - 1 - i);
            char  tmp = *lhs;
            *lhs      = *rhs;
        }
    
        if (StrLen(binary) >= 2 && StrCharAt(binary, 0) == '0' &&
            (StrCharAt(binary, 1) == 'b' || StrCharAt(binary, 1) == 'B')) {
            start = 2;
        }
    
        return int_try_from_str_radix_impl(out, StrBegin(binary), StrLen(binary), start, 2, true);
    }
        }
    
        if (StrLen(octal) >= 2 && StrCharAt(octal, 0) == '0' &&
            (StrCharAt(octal, 1) == 'o' || StrCharAt(octal, 1) == 'O')) {
            start = 2;
        }
    
        return int_try_from_str_radix_impl(out, StrBegin(octal), StrLen(octal), start, 8, true);
    }
        }
    
        return int_try_from_str_radix_impl(out, StrBegin(hex), StrLen(hex), 0, 16, false);
    }
        StrResize(out_path, 0);
        sys_append_dirname(out_path, pe_path);
        if (StrLen(out_path) > 0)
            StrPushBackR(out_path, '/');
        StrPushBackMany(out_path, pdb_base);
    
    #if PLATFORM_UNIX
        return direct_sys3(MISRA_SYS_write, (long)(proc->_stdin_fd), (long)(u64)(StrBegin(buf)), (long)(StrLen(buf)));
    #else
        DWORD written = 0;
    #else
        DWORD written = 0;
        if (!WriteFile(proc->_hStdinWrite, StrBegin(buf), StrLen(buf), &written, NULL))
            return -1;
        return (int)written;
        };
        while (true) {
            u64 grown_to = StrLen(&out->raw) + CHUNK + 1;
            if (!StrReserve(&out->raw, grown_to)) {
                LOG_ERROR("ProcMapsLoad: failed to grow buffer");
                return false;
            }
            StrResize(&out->raw, StrLen(&out->raw) + (u64)n);
            if (n < (i64)CHUNK)
                break; // EOF
        }
        FileClose(&f);
        if (StrLen(&out->raw) == 0) {
            LOG_ERROR("ProcMapsLoad: /proc/self/maps was empty");
            ProcMapsDeinit(out);
                HostsEntry e = {0};
                e.name       = StrInitFromCstr((Zstr)StrIterDataAt(&si, nm_start), nm_len, alloc);
                ascii_lower((u8 *)StrBegin(&e.name), StrLen(&e.name));
                if (got_v4) {
                    MemCopy(e.ip, v4, 4);
            // 1. /etc/hosts fast path.
            VecForeachPtr(&self->hosts, e) {
                if (StrLen(&e->name) > 0 && ZstrCompare(StrBegin(&e->name), nq) == 0) {
                    SocketAddr a = e->is_ipv6 ? sockaddr_v6(e->ip, port) : sockaddr_v4(e->ip, port);
                    VecPushBackR(out, a);
            return HTTP_REQUEST_METHOD_UNKNOWN;
        }
        if (0 == ZstrCompareN(StrBegin(mstr), "GET", 3) && StrLen(mstr) == 3)
            return HTTP_REQUEST_METHOD_GET;
        if (0 == ZstrCompareN(StrBegin(mstr), "POST", 4) && StrLen(mstr) == 4)
        if (0 == ZstrCompareN(StrBegin(mstr), "GET", 3) && StrLen(mstr) == 3)
            return HTTP_REQUEST_METHOD_GET;
        if (0 == ZstrCompareN(StrBegin(mstr), "POST", 4) && StrLen(mstr) == 4)
            return HTTP_REQUEST_METHOD_POST;
        if (0 == ZstrCompareN(StrBegin(mstr), "DELETE", 6) && StrLen(mstr) == 6)
        if (0 == ZstrCompareN(StrBegin(mstr), "POST", 4) && StrLen(mstr) == 4)
            return HTTP_REQUEST_METHOD_POST;
        if (0 == ZstrCompareN(StrBegin(mstr), "DELETE", 6) && StrLen(mstr) == 6)
            return HTTP_REQUEST_METHOD_DELETE;
        if (0 == ZstrCompareN(StrBegin(mstr), "PUT", 3) && StrLen(mstr) == 3)
        if (0 == ZstrCompareN(StrBegin(mstr), "DELETE", 6) && StrLen(mstr) == 6)
            return HTTP_REQUEST_METHOD_DELETE;
        if (0 == ZstrCompareN(StrBegin(mstr), "PUT", 3) && StrLen(mstr) == 3)
            return HTTP_REQUEST_METHOD_PUT;
        if (0 == ZstrCompareN(StrBegin(mstr), "PATCH", 5) && StrLen(mstr) == 5)
        if (0 == ZstrCompareN(StrBegin(mstr), "PUT", 3) && StrLen(mstr) == 3)
            return HTTP_REQUEST_METHOD_PUT;
        if (0 == ZstrCompareN(StrBegin(mstr), "PATCH", 5) && StrLen(mstr) == 5)
            return HTTP_REQUEST_METHOD_PATCH;
        if (0 == ZstrCompareN(StrBegin(mstr), "HEAD", 4) && StrLen(mstr) == 4)
        if (0 == ZstrCompareN(StrBegin(mstr), "PATCH", 5) && StrLen(mstr) == 5)
            return HTTP_REQUEST_METHOD_PATCH;
        if (0 == ZstrCompareN(StrBegin(mstr), "HEAD", 4) && StrLen(mstr) == 4)
            return HTTP_REQUEST_METHOD_HEAD;
        if (0 == ZstrCompareN(StrBegin(mstr), "OPTIONS", 7) && StrLen(mstr) == 7)
        if (0 == ZstrCompareN(StrBegin(mstr), "HEAD", 4) && StrLen(mstr) == 4)
            return HTTP_REQUEST_METHOD_HEAD;
        if (0 == ZstrCompareN(StrBegin(mstr), "OPTIONS", 7) && StrLen(mstr) == 7)
            return HTTP_REQUEST_METHOD_OPTIONS;
        if (0 == ZstrCompareN(StrBegin(mstr), "CONNECT", 7) && StrLen(mstr) == 7)
        if (0 == ZstrCompareN(StrBegin(mstr), "OPTIONS", 7) && StrLen(mstr) == 7)
            return HTTP_REQUEST_METHOD_OPTIONS;
        if (0 == ZstrCompareN(StrBegin(mstr), "CONNECT", 7) && StrLen(mstr) == 7)
            return HTTP_REQUEST_METHOD_CONNECT;
        if (0 == ZstrCompareN(StrBegin(mstr), "TRACE", 5) && StrLen(mstr) == 5)
        if (0 == ZstrCompareN(StrBegin(mstr), "CONNECT", 7) && StrLen(mstr) == 7)
            return HTTP_REQUEST_METHOD_CONNECT;
        if (0 == ZstrCompareN(StrBegin(mstr), "TRACE", 5) && StrLen(mstr) == 5)
            return HTTP_REQUEST_METHOD_TRACE;
        return HTTP_REQUEST_METHOD_UNKNOWN;
            response_code,
            content_type,
            StrLen(&response->body)
        );
        StrAppendFmt(&out, "\r\n");
    
        if (StrLen(&response->body)) {
            if (!StrPushBackMany(&out, StrBegin(&response->body), StrLen(&response->body))) {
                LOG_ERROR("HttpResponseSerialize: failed to append body");
    
        if (StrLen(&response->body)) {
            if (!StrPushBackMany(&out, StrBegin(&response->body), StrLen(&response->body))) {
                LOG_ERROR("HttpResponseSerialize: failed to append body");
                StrDeinit(&out);
        }
    
        if (StrLen(key) == 0) {
            LOG_ERROR("Expected config key");
            StrClear(key);
    
        while (StrIterPeek(&si, &c) && c != '\n') {
            if (kvconfig_is_comment_start(c) && StrLen(value) > 0 &&
                kvconfig_is_space(StrCharAt(value, StrLen(value) - 1))) {
                while (StrLen(value) > 0 && kvconfig_is_space(StrCharAt(value, StrLen(value) - 1))) {
        while (StrIterPeek(&si, &c) && c != '\n') {
            if (kvconfig_is_comment_start(c) && StrLen(value) > 0 &&
                kvconfig_is_space(StrCharAt(value, StrLen(value) - 1))) {
                while (StrLen(value) > 0 && kvconfig_is_space(StrCharAt(value, StrLen(value) - 1))) {
                    char dropped = '\0';
            if (kvconfig_is_comment_start(c) && StrLen(value) > 0 &&
                kvconfig_is_space(StrCharAt(value, StrLen(value) - 1))) {
                while (StrLen(value) > 0 && kvconfig_is_space(StrCharAt(value, StrLen(value) - 1))) {
                    char dropped = '\0';
                    StrPopBack(value, &dropped);
            }
    
            if (kvconfig_is_comment_start(c) && StrLen(value) == 0) {
                return si;
            }
        }
    
        if (StrLen(value) > 0) {
            Str stripped = StrStrip(value, NULL);
            StrDeinit(value);
        }
    
        return StrInitFromCstr(StrBegin(value), StrLen(value), MapAllocator(cfg));
    }
        }
    
        return StrInitFromCstr(StrBegin(value), StrLen(value), MapAllocator(cfg));
    }
        }
    
        if (!StrLen(&ns)) {
            LOG_ERROR("Failed to parse number. '{.8}'", LVAL(StrIterDataAt(&saved_si, StrIterIndex(&saved_si))));
            StrDeinit(&ns);
    // return the offset at which it was inserted.
    static bool pool_append(Str *pool, Zstr s, u64 *out_offset) {
        u64 start = StrLen(pool);
        if (!StrPushBackMany(pool, s))
            return false;
                        ++nlen;
                    if (nlen > 0 && nlen < src_max) {
                        u64 offset = StrLen(pool);
                        for (u64 i = 0; i < nlen; ++i) {
                            if (!StrPushBackR(pool, src[i]))
    // pass after the walk completes.
    static bool pool_append_cstr(Str *pool, Zstr s, u64 *out_offset) {
        *out_offset = StrLen(pool);
        if (!StrPushBackMany(pool, s))
            return false;
                // Strip the trailing ":0" since we resolve with port=0; keep
                // bracket form on v6 to round-trip through SocketAddrParse.
                size n = StrLen(&s);
                Zstr p = StrBegin(&s);
                if (n >= 2 && p[n - 1] == '0' && p[n - 2] == ':') {
        // treats as a fatal arg violation. An empty source clones to an
        // empty fresh Str.
        Str copy = (StrLen(src) == 0) ? StrInit((Allocator *)alloc) :
                                        StrInitFromCstr(StrBegin(src), StrLen(src), (Allocator *)alloc);
        *(Str *)dst_ptr = copy;
        // empty fresh Str.
        Str copy = (StrLen(src) == 0) ? StrInit((Allocator *)alloc) :
                                        StrInitFromCstr(StrBegin(src), StrLen(src), (Allocator *)alloc);
        *(Str *)dst_ptr = copy;
        return true;
                    size_t total_len = 0;
                    VecForeach(vec, str) {
                        total_len += StrLen(&str);
                    }
                    (void)total_len; // Suppress unused variable warning
                    size_t total_len = 0;
                    VecForeachIdx(vec, str, idx) {
                        total_len += StrLen(&str) + idx;
                    }
                    (void)total_len; // Suppress unused variable warning
                    size_t total_len = 0;
                    VecForeachPtr(vec, str_ptr) {
                        total_len += StrLen(str_ptr);
                    }
                    (void)total_len; // Suppress unused variable warning
                    size_t total_len = 0;
                    VecForeachPtrIdx(vec, str_ptr, idx) {
                        total_len += StrLen(str_ptr) + idx;
                    }
                    (void)total_len; // Suppress unused variable warning
                    size_t total_len = 0;
                    VecForeachReverse(vec, str) {
                        total_len += StrLen(&str);
                    }
                    (void)total_len; // Suppress unused variable warning
                    size_t total_len = 0;
                    VecForeachReverseIdx(vec, str, idx) {
                        total_len += StrLen(&str) + idx;
                    }
                    (void)total_len; // Suppress unused variable warning
                    size_t total_len = 0;
                    VecForeachPtrReverse(vec, str_ptr) {
                        total_len += StrLen(str_ptr);
                    }
                    (void)total_len; // Suppress unused variable warning
                    size_t total_len = 0;
                    VecForeachPtrReverseIdx(vec, str_ptr, idx) {
                        total_len += StrLen(str_ptr) + idx;
                    }
                    (void)total_len; // Suppress unused variable warning
                        size_t total_len = 0;
                        VecForeachInRange(vec, str, start, end) {
                            total_len += StrLen(&str);
                        }
                        (void)total_len; // Suppress unused variable warning
                        size_t total_len = 0;
                        VecForeachInRangeIdx(vec, str, idx, start, end) {
                            total_len += StrLen(&str) + idx;
                        }
                        (void)total_len; // Suppress unused variable warning
                        size_t total_len = 0;
                        VecForeachPtrInRange(vec, str_ptr, start, end) {
                            total_len += StrLen(str_ptr);
                        }
                        (void)total_len; // Suppress unused variable warning
                        size_t total_len = 0;
                        VecForeachPtrInRangeIdx(vec, str_ptr, idx, start, end) {
                            total_len += StrLen(str_ptr) + idx;
                        }
                        (void)total_len; // Suppress unused variable warning
        });
    
        if (StrLen(&obj.name) == 0 && StrLen(&obj.description) == 0) {
            WriteFmt("[DEBUG] Empty string test passed - both strings empty\n");
        } else {
            WriteFmt(
                "[DEBUG] Empty string test FAILED - name len: {}, desc len: {}\n",
                StrLen(&obj.name),
                StrLen(&obj.description)
            );
                "[DEBUG] Empty string test FAILED - name len: {}, desc len: {}\n",
                StrLen(&obj.name),
                StrLen(&obj.description)
            );
            success = false;
    
        // Check if strings were parsed (exact content may vary based on escape handling)
        if (StrLen(&obj.path) > 0 && StrLen(&obj.message) > 0 && StrLen(&obj.data) > 0) {
            WriteFmt("[DEBUG] Special characters test passed - all strings parsed\n");
        } else {
        WriteFmtLn("[DEBUG] Escape sequences - escaped: '{}'\n", obj.escaped);
        WriteFmtLn("[DEBUG] Escape sequences - backslash: '{}'\n", obj.backslash);
        WriteFmtLn("[DEBUG] Escape sequences - newline length: {}\n", StrLen(&obj.newline));
        WriteFmtLn("[DEBUG] Escape sequences - tab length: {}\n", StrLen(&obj.tab));
        WriteFmtLn("[DEBUG] Escape sequences - backslash: '{}'\n", obj.backslash);
        WriteFmtLn("[DEBUG] Escape sequences - newline length: {}\n", StrLen(&obj.newline));
        WriteFmtLn("[DEBUG] Escape sequences - tab length: {}\n", StrLen(&obj.tab));
    
        // Basic validation that strings were parsed
    
        // Basic validation that strings were parsed
        if (StrLen(&obj.escaped) > 0 && StrLen(&obj.backslash) > 0 && StrLen(&obj.newline) > 0 && StrLen(&obj.tab) > 0) {
            WriteFmt("[DEBUG] Escape sequences test passed\n");
        } else {
    
        // Remove whitespace from both strings for comparison
        for (u64 i = 0; i < StrLen(output); i++) {
            char c = StrBegin(output)[i];
            if (c != ' ' && c != '\n' && c != '\r' && c != '\t') {
        }
    
        for (u64 i = 0; i < StrLen(&expected_str); i++) {
            char c = StrBegin(&expected_str)[i];
            if (c != ' ' && c != '\n' && c != '\r' && c != '\t') {
            WriteFmt("[DEBUG] JSON comparison failed\n");
            WriteFmt("[DEBUG] Expected: '");
            for (u64 i = 0; i < StrLen(&expected_clean); i++) {
                WriteFmt("{c}", StrBegin(&expected_clean)[i]);
            }
            WriteFmt("'\n");
            WriteFmt("[DEBUG] Got: '");
            for (u64 i = 0; i < StrLen(&output_clean); i++) {
                WriteFmt("%c", StrBegin(&output_clean)[i]);
            }
    
        // Remove spaces and newlines from both strings for comparison
        for (size i = 0; i < StrLen(output); i++) {
            char c = StrBegin(output)[i];
            if (c != ' ' && c != '\n' && c != '\r' && c != '\t') {
        }
    
        for (size i = 0; i < StrLen(&expected_str); i++) {
            char c = StrBegin(&expected_str)[i];
            if (c != ' ' && c != '\n' && c != '\r' && c != '\t') {
            WriteFmt("[DEBUG] JSON comparison failed\n");
            WriteFmt("[DEBUG] Expected: '");
            for (size i = 0; i < StrLen(&expected_clean); i++) {
                WriteFmt("{c}", StrBegin(&expected_clean)[i]);
            }
            WriteFmt("'\n");
            WriteFmt("[DEBUG] Got: '");
            for (size i = 0; i < StrLen(&output_clean); i++) {
                WriteFmt("{c}", StrBegin(&output_clean)[i]);
            }
    
        // Remove spaces and newlines from both strings for comparison
        for (size i = 0; i < StrLen(output); i++) {
            char c = StrBegin(output)[i];
            if (c != ' ' && c != '\n' && c != '\r' && c != '\t') {
        }
    
        for (size i = 0; i < StrLen(&expected_str); i++) {
            char c = StrBegin(&expected_str)[i];
            if (c != ' ' && c != '\n' && c != '\r' && c != '\t') {
            WriteFmtLn("[DEBUG] JSON comparison failed");
            WriteFmt("[DEBUG] Expected: '");
            for (u64 i = 0; i < StrLen(&expected_clean); i++) {
                WriteFmt("{c}", StrBegin(&expected_clean)[i]);
            }
    
            WriteFmt("[DEBUG] Got: '");
            for (u64 i = 0; i < StrLen(&output_clean); i++) {
                WriteFmt("{c}", StrBegin(&output_clean)[i]);
            }
    
        // For large numbers, just check that valid JSON was produced
        if (StrLen(&json) > 0 && StrBegin(&json)[0] == '{' && StrBegin(&json)[StrLen(&json) - 1] == '}') {
            WriteFmtLn("[DEBUG] Large numbers test passed - produced valid JSON structure");
        } else {
    
        // Just verify that valid JSON structure was produced
        if (StrLen(&json) > 0 && StrBegin(&json)[0] == '{' && StrBegin(&json)[StrLen(&json) - 1] == '}') {
            WriteFmtLn("[DEBUG] Special characters test passed - produced valid JSON");
        } else {
    
        // Verify valid JSON structure was produced
        if (StrLen(&json) > 0 && StrBegin(&json)[0] == '{' && StrBegin(&json)[StrLen(&json) - 1] == '}') {
            WriteFmtLn("[DEBUG] Escape sequences test passed - produced valid JSON");
        } else {
    
        // Check for reasonable float formatting (exact precision may vary)
        if (StrLen(&json) > 0 && StrBegin(&json)[0] == '{' && StrBegin(&json)[StrLen(&json) - 1] == '}') {
            WriteFmtLn("[DEBUG] Boundary floats test passed - JSON: {}", json);
        } else {
        if (StrCmp(&data.name, "test", 4) != 0) {
            WriteFmt("[DEBUG] Name check failed: expected 'test', got '");
            for (size i = 0; i < StrLen(&data.name); i++) {
                WriteFmt("{c}", StrBegin(&data.name)[i]);
            }
        if (StrCmp(&data.user.profile.name, "Alice", 5) != 0) {
            WriteFmt("[DEBUG] Profile name check failed: expected 'Alice', got '");
            for (u64 i = 0; i < StrLen(&data.user.profile.name); i++) {
                WriteFmt("{}", StrBegin(&data.user.profile.name)[i]);
            }
        if (StrCmp(&data.status, "active", 6) != 0) {
            WriteFmt("[DEBUG] Status check failed: expected 'active', got '");
            for (size i = 0; i < StrLen(&data.status); i++) {
                WriteFmt("{}", StrBegin(&data.status)[i]);
            }
        if (StrCmp(&data.company.departments.engineering.head, "John", 4) != 0) {
            WriteFmt("[DEBUG] Engineering head check failed: expected 'John', got '");
            for (size i = 0; i < StrLen(&data.company.departments.engineering.head); i++) {
                WriteFmt("{c}", StrBegin(&data.company.departments.engineering.head)[i]);
            }
        if (StrCmp(&data.company.name, "TechCorp", 8) != 0) {
            WriteFmt("[DEBUG] Company name check failed: expected 'TechCorp', got '");
            for (size i = 0; i < StrLen(&data.company.name); i++) {
                WriteFmt("{c}", StrBegin(&data.company.name)[i]);
            }
        if (StrCmp(&response.message, "Success", 7) != 0) {
            WriteFmt("[DEBUG] Message check failed: expected 'Success', got '");
            for (size i = 0; i < StrLen(&response.message); i++) {
                WriteFmt("{c}", StrBegin(&response.message)[i]);
            }
            if (StrCmp(&sym->analysis_name, "test_analysis", 13) != 0) {
                WriteFmt("[DEBUG] Analysis name check failed: expected 'test_analysis', got '");
                for (size i = 0; i < StrLen(&sym->analysis_name); i++) {
                    WriteFmt("{c}", StrBegin(&sym->analysis_name)[i]);
                }
                WriteFmt(
                    "[DEBUG] Function name check failed: expected 'main_func', got string of length {}\n",
                    StrLen(&sym->function_name)
                );
                success = false;
            if (StrCmp(&sym->sha256, "abc123", 6) != 0) {
                WriteFmt("[DEBUG] SHA256 check failed: expected 'abc123', got '");
                for (size i = 0; i < StrLen(&sym->sha256); i++) {
                    WriteFmt("{c}", StrBegin(&sym->sha256)[i]);
                }
            if (StrCmp(&sym->function_mangled_name, "_Z4main", 7) != 0) {
                WriteFmt("[DEBUG] Mangled name check failed: expected '_Z4main', got '");
                for (size i = 0; i < StrLen(&sym->function_mangled_name); i++) {
                    WriteFmt("{c}", StrBegin(&sym->function_mangled_name)[i]);
                }
        if (StrCmp(&info.name, "test_func", 9) != 0) {
            WriteFmt("[DEBUG] Function name check failed: expected 'test_func', got '");
            for (size i = 0; i < StrLen(&info.name); i++) {
                WriteFmt("{}", StrBegin(&info.name)[i]);
            }
        if (StrCmp(&info.name, "test_model", 10) != 0) {
            WriteFmt("[DEBUG] Model name check failed: expected 'test_model', got '");
            for (size i = 0; i < StrLen(&info.name); i++) {
                WriteFmt("{}", StrBegin(&info.name)[i]);
            }
        if (StrCmp(&result.binary_name, "test_binary", 11) != 0) {
            WriteFmt("[DEBUG] Binary name check failed: expected 'test_binary', got '");
            for (size i = 0; i < StrLen(&result.binary_name); i++) {
                WriteFmt("{c}", StrBegin(&result.binary_name)[i]);
            }
        if (StrCmp(&result.sha256, "abc123", 6) != 0) {
            WriteFmt("[DEBUG] SHA256 check failed: expected 'abc123', got '");
            for (size i = 0; i < StrLen(&result.sha256); i++) {
                WriteFmt("{c}", StrBegin(&result.sha256)[i]);
            }
        if (StrCmp(&result.model_name, "test_model", 10) != 0) {
            WriteFmt("[DEBUG] Model name check failed: expected 'test_model', got '");
            for (size i = 0; i < StrLen(&result.model_name); i++) {
                WriteFmt("{c}", StrBegin(&result.model_name)[i]);
            }
        if (StrCmp(&result.owned_by, "user1", 5) != 0) {
            WriteFmt("[DEBUG] Owned by check failed: expected 'user1', got '");
            for (size i = 0; i < StrLen(&result.owned_by); i++) {
                WriteFmt("{c}", StrBegin(&result.owned_by)[i]);
            }
    
            WriteFmt("[DEBUG] Parsed status: {}, message: '", response.status ? "true" : "false");
            for (size i = 0; i < StrLen(&response.message); i++) {
                WriteFmt("{c}", StrBegin(&response.message)[i]);
            }
        if (StrCmp(&response.message, "Success", 7) != 0) {
            WriteFmt("[DEBUG] Message check failed: expected 'Success', got '");
            for (size i = 0; i < StrLen(&response.message); i++) {
                WriteFmt("{c}", StrBegin(&response.message)[i]);
            }
            if (StrCmp(&sym->analysis_name, "test_analysis", 13) != 0) {
                WriteFmt("[DEBUG] Analysis name check failed: expected 'test_analysis', got '");
                for (size i = 0; i < StrLen(&sym->analysis_name); i++) {
                    WriteFmt("{c}", StrBegin(&sym->analysis_name)[i]);
                }
                WriteFmt(
                    "[DEBUG] Function name check failed: expected 'main_func', got string of length {}\n",
                    StrLen(&sym->function_name)
                );
                success = false;
            if (StrCmp(&sym->sha256, "abc123", 6) != 0) {
                WriteFmt("[DEBUG] SHA256 check failed: expected 'abc123', got '");
                for (size i = 0; i < StrLen(&sym->sha256); i++) {
                    WriteFmt("{c}", StrBegin(&sym->sha256)[i]);
                }
            if (StrCmp(&sym->function_mangled_name, "_Z4main", 7) != 0) {
                WriteFmt("[DEBUG] Mangled name check failed: expected '_Z4main', got '");
                for (size i = 0; i < StrLen(&sym->function_mangled_name); i++) {
                    WriteFmt("{c}", StrBegin(&sym->function_mangled_name)[i]);
                }
    
            WriteFmt("[DEBUG] Parsed status: {}, message: '", response.status ? "true" : "false");
            for (size i = 0; i < StrLen(&response.message); i++) {
                WriteFmt("{c}", StrBegin(&response.message)[i]);
            }
        if (StrCmp(&response.message, "Success", 7) != 0) {
            WriteFmt("[DEBUG] Message check failed: expected 'Success', got '");
            for (u64 i = 0; i < StrLen(&response.message); i++) {
                WriteFmt("{c}", StrBegin(&response.message)[i]);
            }
            if (StrCmp(&sym->analysis_name, "test_analysis", 13) != 0) {
                WriteFmt("[DEBUG] Analysis name check failed: expected 'test_analysis', got '");
                for (size i = 0; i < StrLen(&sym->analysis_name); i++) {
                    WriteFmt("{}", StrBegin(&sym->analysis_name)[i]);
                }
            if (StrCmp(&sym->function_name, "main_func", 9) != 0) {
                WriteFmt("[DEBUG] Function name check failed: expected 'main_func', got '");
                for (size i = 0; i < StrLen(&sym->function_name); i++) {
                    WriteFmt("{c}", StrBegin(&sym->function_name)[i]);
                }
            if (StrCmp(&sym->sha256, "abc123", 6) != 0) {
                WriteFmt("[DEBUG] SHA256 check failed: expected 'abc123', got '");
                for (size i = 0; i < StrLen(&sym->sha256); i++) {
                    WriteFmt("{}", StrBegin(&sym->sha256)[i]);
                }
            if (StrCmp(&sym->function_mangled_name, "_Z4main", 7) != 0) {
                WriteFmt("[DEBUG] Mangled name check failed: expected '_Z4main', got '");
                for (size i = 0; i < StrLen(&sym->function_mangled_name); i++) {
                    WriteFmt("{c}", StrBegin(&sym->function_mangled_name)[i]);
                }
        if (StrCmp(&name, "Alice", 5) != 0) {
            WriteFmt("[DEBUG] Name check failed: expected 'Alice', got '");
            for (size i = 0; i < StrLen(&name); i++) {
                WriteFmt("{c}", StrBegin(&name)[i]);
            }
        if (StrCmp(&city, "New York", 8) != 0) {
            WriteFmt("[DEBUG] City check failed: expected 'New York', got '");
            for (size i = 0; i < StrLen(&city); i++) {
                WriteFmt("{c}", StrBegin(&city)[i]);
            }
        if (StrCmp(&person.name, "Bob", 3) != 0) {
            WriteFmt("[DEBUG] Person name check failed: expected 'Bob', got '");
            for (size i = 0; i < StrLen(&person.name); i++) {
                WriteFmt("{c}", StrBegin(&person.name)[i]);
            }
        if (StrCmp(&config.log_level, "INFO", 4) != 0) {
            WriteFmt("[DEBUG] Log level check failed: expected 'INFO', got '");
            for (size i = 0; i < StrLen(&config.log_level); i++) {
                WriteFmt("{c}", StrBegin(&config.log_level)[i]);
            }
            if (StrCmp(lang1, "C", 1) != 0) {
                WriteFmt("[DEBUG] Language 1 check failed: expected 'C', got '");
                for (size i = 0; i < StrLen(lang1); i++) {
                    WriteFmt("{c}", StrBegin(lang1)[i]);
                }
            if (StrCmp(lang2, "Python", 6) != 0) {
                WriteFmt("[DEBUG] Language 2 check failed: expected 'Python', got '");
                for (size i = 0; i < StrLen(lang2); i++) {
                    WriteFmt("{c}", StrBegin(lang2)[i]);
                }
            if (StrCmp(lang3, "Rust", 4) != 0) {
                WriteFmt("[DEBUG] Language 3 check failed: expected 'Rust', got '");
                for (size i = 0; i < StrLen(lang3); i++) {
                    WriteFmt("{c}", StrBegin(lang3)[i]);
                }
        if (StrCmp(&data.user.name, "Charlie", 7) != 0) {
            WriteFmt("[DEBUG] User name check failed: expected 'Charlie', got '");
            for (size i = 0; i < StrLen(&data.user.name); i++) {
                WriteFmt("{c}", StrBegin(&data.user.name)[i]);
            }
        if (StrCmp(&data.user.email, "charlie@example.com", 19) != 0) {
            WriteFmt("[DEBUG] User email check failed: expected 'charlie@example.com', got '");
            for (size i = 0; i < StrLen(&data.user.email); i++) {
                WriteFmt("{c}", StrBegin(&data.user.email)[i]);
            }
        if (StrCmp(&product.name, "Laptop", 6) != 0) {
            WriteFmt("[DEBUG] Product name check failed: expected 'Laptop', got '");
            for (size i = 0; i < StrLen(&product.name); i++) {
                WriteFmt("{c}", StrBegin(&product.name)[i]);
            }
            if (StrCmp(tag1, "electronics", 11) != 0) {
                WriteFmt("[DEBUG] Tag 1 check failed: expected 'electronics', got '");
                for (size i = 0; i < StrLen(tag1); i++) {
                    WriteFmt("{c}", StrBegin(tag1)[i]);
                }
            if (StrCmp(tag2, "computers", 9) != 0) {
                WriteFmt("[DEBUG] Tag 2 check failed: expected 'computers', got '");
                for (size i = 0; i < StrLen(tag2); i++) {
                    WriteFmt("{c}", StrBegin(tag2)[i]);
                }
            if (StrCmp(tag3, "portable", 8) != 0) {
                WriteFmt("[DEBUG] Tag 3 check failed: expected 'portable', got '");
                for (size i = 0; i < StrLen(tag3); i++) {
                    WriteFmt("{c}", StrBegin(tag3)[i]);
                }
    
        // Compare values
        if (StrLen(&parsed.empty) == StrLen(&original.empty) && StrCmp(&original.simple, &parsed.simple) == 0 &&
            StrCmp(&original.with_spaces, &parsed.with_spaces) == 0 &&
            StrCmp(&original.with_special, &parsed.with_special) == 0) {
        if (strings_match) {
            for (size i = 0; i < VecLen(&original_strings); i++) {
                if (StrLen(VecPtrAt(&original_strings, i)) != StrLen(VecPtrAt(&parsed_strings, i)) ||
                    (StrLen(VecPtrAt(&original_strings, i)) &&
                     StrCmp(VecPtrAt(&original_strings, i), VecPtrAt(&parsed_strings, i)) != 0)) {
            for (size i = 0; i < VecLen(&original_strings); i++) {
                if (StrLen(VecPtrAt(&original_strings, i)) != StrLen(VecPtrAt(&parsed_strings, i)) ||
                    (StrLen(VecPtrAt(&original_strings, i)) &&
                     StrCmp(VecPtrAt(&original_strings, i), VecPtrAt(&parsed_strings, i)) != 0)) {
                    strings_match = false;
    
        // Compare empty containers
        if (StrLen(&parsed_str) == 0 && VecLen(&parsed_numbers) == 0 && VecLen(&parsed_strings) == 0 &&
            !found_empty_object) { // Empty object should not execute the content
            WriteFmtLn("[DEBUG] Empty containers round-trip test passed");
            WriteFmtLn(
                "[DEBUG] String length: {}, numbers: {}, strings: {}, found_obj: {}\n",
                StrLen(&parsed_str),
                VecLen(&parsed_numbers),
                VecLen(&parsed_strings),
        result = result && user && StrCmp(user, "root") == 0;
        result = result && greet && StrCmp(greet, "hello world") == 0;
        result = result && empty && (StrLen(empty) == 0);
    
        StrDeinit(&src);
        result = result && stored_host;
        result = result && (StrBegin(&host_copy) != NULL);
        result = result && (StrLen(&host_copy) > 0);
        result = result && (StrBegin(&host_copy) != StrBegin(stored_host));
        result = result && (StrCmp(&host_copy, "localhost") == 0);
        Zstr next = HttpRequestParse(&req, raw);
    
        bool ok = (next != raw) && (req.method == HTTP_REQUEST_METHOD_GET) && (StrLen(&req.url) == 11) &&
                  (ZstrCompare(StrBegin(&req.url), "/index.html") == 0) && (VecLen(&req.headers) == 2) &&
                  (ZstrCompare(next, "body-bytes") == 0);
        //   - includes a Content-Length: 11 (length of "<h1>hi</h1>")
        //   - ends with the body
        bool ok = StrLen(&wire) > 0 && ZstrFindSubstring(StrBegin(&wire), "HTTP/1.1 200 OK\r\n") == StrBegin(&wire) &&
                  ZstrFindSubstring(StrBegin(&wire), "Content-Type: text/html\r\n") != NULL &&
                  ZstrFindSubstring(StrBegin(&wire), "Content-Length: 11\r\n") != NULL &&
    
        // Capacity should now be closer to the actual length
        result = result && (StrCapacity(&s) < 100) && (StrCapacity(&s) >= StrLen(&s));
    
        StrDeinit(&s);
    
        // Initial length should be 5
        bool result = (StrLen(&s) == 5);
    
        // Resize to a smaller length
    
        // Length should now be 3 and content should be "Hel"
        result = result && (StrLen(&s) == 3) && (ZstrCompareN(StrBegin(&s), "Hel", 3) == 0);
    
        // Resize to a larger length
        // Length should now be 8, and the first 3 characters should still be "Hel"
        // The rest will be filled with zeros
        result = result && (StrLen(&s) == 8) && (ZstrCompareN(StrBegin(&s), "Hel", 3) == 0);
    
        StrDeinit(&s);
    
        // Length should still be 0
        result = result && (StrLen(&s) == 0);
    
        // Reserve less space (should be a no-op)
    
        // Initial length should be 13
        bool result = (StrLen(&s) == 13);
    
        // Clear the string
    
        // Length should now be 0, but capacity should remain
        result = result && (StrLen(&s) == 0) && (StrCapacity(&s) >= 13);
    
        // Data pointer should still be valid
    
        // Check that the string is still empty
        result = result && (StrLen(&s) == 0);
    
        StrDeinit(&s);
        Str text  = IntToStrRadix(&value, 37, false);
    
        bool result = StrLen(&text) == 0;
    
        StrDeinit(&text);
        // (Apple's C mangling prepends `_`; substring search matches both
        // "bt_capture_with_helper" and "_bt_capture_with_helper".)
        bool ok = StrLen(&rendered) > 0 && ZstrFindSubstring(StrBegin(&rendered), "bt_capture_with_helper") != NULL &&
                  ZstrFindSubstring(StrBegin(&rendered), "bt_capture_outer") != NULL;
        FormatStackTrace(&rendered, &frames, alloc_base);
    
        ok = ok && StrLen(&rendered) > 0;
        ok = ok && ZstrFindSubstring(StrBegin(&rendered), "bt_vec_capture_with_helper") != NULL;
        ok = ok && ZstrFindSubstring(StrBegin(&rendered), "bt_vec_capture_outer") != NULL;
    
        // Should also contain the helper name through the shared resolver.
        bool ok = StrLen(&out) > 0 && ZstrFindSubstring(StrBegin(&out), "bt_capture_with_helper") != NULL;
    
        StrDeinit(&out);
        // unwound across at least two real-code frames.
        bool ok = n >= 2;
        ok      = ok && StrLen(&rendered) > 0;
        ok      = ok && ZstrFindSubstring(StrBegin(&rendered), "cfi_capture_inner") != NULL;
        ok      = ok && ZstrFindSubstring(StrBegin(&rendered), "cfi_capture_outer") != NULL;
    // Test StrLen and StrEmpty functions
    bool test_str_len_empty(void) {
        WriteFmt("Testing StrLen and StrEmpty\n");
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str s = StrInit(&alloc);
    
        bool result = (StrLen(&s) == 0);
        result      = result && StrEmpty(&s);
        StrPushBackR(&s, 'i');
    
        result = result && (StrLen(&s) == 2);
        result = result && !StrEmpty(&s);
    
        StrClear(&s);
        result = result && (StrLen(&s) == 0);
        result = result && StrEmpty(&s);
            }
            Str rendered = SocketAddrFormat(&addr, alloc_base);
            ok           = ok && StrLen(&rendered) > 0 && ZstrCompare(StrBegin(&rendered), "127.0.0.1:8080") == 0;
            StrDeinit(&rendered);
        }
            }
            Str rendered = SocketAddrFormat(&addr, alloc_base);
            ok           = ok && StrLen(&rendered) > 0 && ZstrCompare(StrBegin(&rendered), "[::1]:8080") == 0;
            StrDeinit(&rendered);
        }
        if (ok) {
            Str s = SocketAddrFormat(VecPtrAt(&out, 0), a);
            ok    = (StrLen(&s) > 0) && ZstrCompare(StrBegin(&s), "203.0.113.7:9999") == 0;
            StrDeinit(&s);
        }
            Str s = SocketAddrFormat(VecPtrAt(&out, 0), a);
            // SocketAddrFormat emits the bracketed form for IPv6.
            ok = (StrLen(&s) > 0) && ZstrCompare(StrBegin(&s), "[::1]:443") == 0;
            StrDeinit(&s);
        }
            VecForeachPtr(&out, ad) {
                Str s = SocketAddrFormat(ad, a);
                u64 L = StrLen(&s);
                if (L < 3 || StrBegin(&s)[L - 1] != '3' || StrBegin(&s)[L - 2] != '5' || StrBegin(&s)[L - 3] != ':') {
                    ok = false;
        if (ok) {
            Str s = SocketAddrFormat(&one, a);
            ok    = (StrLen(&s) > 0) && ZstrCompare(StrBegin(&s), "127.0.0.1:80") == 0;
            StrDeinit(&s);
        }
        DebugAllocatorReportLeaks(&dbg, &out);
    
        bool ok = StrLen(&out) > 0;
        ok      = ok && (ZstrFindSubstring(StrBegin(&out), "leak:") != NULL);
        ok      = ok && (ZstrFindSubstring(StrBegin(&out), "24 bytes") != NULL);
            WriteFmt("Test 1 - :a (lowercase)\n");
            WriteFmt("Input: '{}', Output: '", in);
            for (size i = 0; i < StrLen(&result); i++) {
                WriteFmt("{c}", StrBegin(&result)[i]);
            }
            WriteFmt("Test 1.1 - :as (lowercase string single word)\n");
            WriteFmt("Input: '{}', Output: '", in);
            for (size i = 0; i < StrLen(&result); i++) {
                WriteFmt("{c}", StrBegin(&result)[i]);
            }
            WriteFmt("Test 2 - :A (uppercase)\n");
            WriteFmt("Input: '{}', Output: '", in);
            for (size i = 0; i < StrLen(&result); i++) {
                WriteFmt("{c}", StrBegin(&result)[i]);
            }
            WriteFmt("Test 3 - :a with quoted string\n");
            WriteFmt("Input: '{}', Output: '", in);
            for (size i = 0; i < StrLen(&result); i++) {
                WriteFmt("{c}", StrBegin(&result)[i]);
            }
            WriteFmt("Test 4 - :A with mixed alphanumeric\n");
            WriteFmt("Input: '{}', Output: '", in);
            for (size i = 0; i < StrLen(&result); i++) {
                WriteFmt("{c}", StrBegin(&result)[i]);
            }
            WriteFmt("Test 5 - :c (no case conversion)\n");
            WriteFmt("Input: '{}', Output: '", in);
            for (size i = 0; i < StrLen(&result); i++) {
                WriteFmt("{c}", StrBegin(&result)[i]);
            }
    
        StrAppendFmt(&output, "");
        success = success && (StrLen(&output) == 0);
        StrClear(&output);
        Zstr empty = "";
        StrAppendFmt(&output, "{}", empty);
        success = success && (StrLen(&output) == 0);
        StrClear(&output);
    
        StrAppendFmt(&output, "{c}", u16_value);
        success = success && (StrLen(&output) == 2 && StrBegin(&output)[0] == 'A' && StrBegin(&output)[1] == 'B');
        StrClear(&output);
    
        StrAppendFmt(&output, "{a}", u16_value);
        success = success && (StrLen(&output) == 2 && StrBegin(&output)[0] == 'a' && StrBegin(&output)[1] == 'b');
        StrClear(&output);
    
        StrAppendFmt(&output, "{A}", u16_value);
        success = success && (StrLen(&output) == 2 && StrBegin(&output)[0] == 'A' && StrBegin(&output)[1] == 'B');
        StrClear(&output);
    
        StrAppendFmt(&output, "{c}", i16_value);
        success = success && (StrLen(&output) == 2 && StrBegin(&output)[0] == 'C' && StrBegin(&output)[1] == 'd');
        StrClear(&output);
    
        StrAppendFmt(&output, "{a}", i16_value);
        success = success && (StrLen(&output) == 2 && StrBegin(&output)[0] == 'c' && StrBegin(&output)[1] == 'd');
        StrClear(&output);
    
        StrAppendFmt(&output, "{A}", i16_value);
        success = success && (StrLen(&output) == 2 && StrBegin(&output)[0] == 'C' && StrBegin(&output)[1] == 'D');
        StrClear(&output);
    
        StrAppendFmt(&output, "{c}", u32_value);
        success = success && (StrLen(&output) == 4 && StrBegin(&output)[0] == 'E' && StrBegin(&output)[1] == 'f' &&
                              StrBegin(&output)[2] == 'G' && StrBegin(&output)[3] == 'h');
        StrClear(&output);
    
        StrAppendFmt(&output, "{a}", u32_value);
        success = success && (StrLen(&output) == 4 && StrBegin(&output)[0] == 'e' && StrBegin(&output)[1] == 'f' &&
                              StrBegin(&output)[2] == 'g' && StrBegin(&output)[3] == 'h');
        StrClear(&output);
    
        StrAppendFmt(&output, "{A}", u32_value);
        success = success && (StrLen(&output) == 4 && StrBegin(&output)[0] == 'E' && StrBegin(&output)[1] == 'F' &&
                              StrBegin(&output)[2] == 'G' && StrBegin(&output)[3] == 'H');
        StrClear(&output);
    
        StrAppendFmt(&output, "{c}", i32_value);
        success = success && (StrLen(&output) == 4 && StrBegin(&output)[0] == 'I' && StrBegin(&output)[1] == 'j' &&
                              StrBegin(&output)[2] == 'K' && StrBegin(&output)[3] == 'l');
        StrClear(&output);
    
        StrAppendFmt(&output, "{a}", i32_value);
        success = success && (StrLen(&output) == 4 && StrBegin(&output)[0] == 'i' && StrBegin(&output)[1] == 'j' &&
                              StrBegin(&output)[2] == 'k' && StrBegin(&output)[3] == 'l');
        StrClear(&output);
    
        StrAppendFmt(&output, "{A}", i32_value);
        success = success && (StrLen(&output) == 4 && StrBegin(&output)[0] == 'I' && StrBegin(&output)[1] == 'J' &&
                              StrBegin(&output)[2] == 'K' && StrBegin(&output)[3] == 'L');
        StrClear(&output);
    
        StrAppendFmt(&output, "{c}", u64_value);
        success = success && (StrLen(&output) == 8 && StrBegin(&output)[0] == 'M' && StrBegin(&output)[1] == 'n' &&
                              StrBegin(&output)[2] == 'O' && StrBegin(&output)[3] == 'p' && StrBegin(&output)[4] == 'Q' &&
                              StrBegin(&output)[5] == 'r' && StrBegin(&output)[6] == 'S' && StrBegin(&output)[7] == 't');
    
        StrAppendFmt(&output, "{a}", u64_value);
        success = success && (StrLen(&output) == 8 && StrBegin(&output)[0] == 'm' && StrBegin(&output)[1] == 'n' &&
                              StrBegin(&output)[2] == 'o' && StrBegin(&output)[3] == 'p' && StrBegin(&output)[4] == 'q' &&
                              StrBegin(&output)[5] == 'r' && StrBegin(&output)[6] == 's' && StrBegin(&output)[7] == 't');
    
        StrAppendFmt(&output, "{A}", u64_value);
        success = success && (StrLen(&output) == 8 && StrBegin(&output)[0] == 'M' && StrBegin(&output)[1] == 'N' &&
                              StrBegin(&output)[2] == 'O' && StrBegin(&output)[3] == 'P' && StrBegin(&output)[4] == 'Q' &&
                              StrBegin(&output)[5] == 'R' && StrBegin(&output)[6] == 'S' && StrBegin(&output)[7] == 'T');
    
        StrAppendFmt(&output, "{c}", i64_value);
        success = success && (StrLen(&output) == 8 && StrBegin(&output)[0] == 'U' && StrBegin(&output)[1] == 'v' &&
                              StrBegin(&output)[2] == 'W' && StrBegin(&output)[3] == 'x' && StrBegin(&output)[4] == 'Y' &&
                              StrBegin(&output)[5] == 'z' && StrBegin(&output)[6] == '1' && StrBegin(&output)[7] == '2');
    
        StrAppendFmt(&output, "{a}", i64_value);
        success = success && (StrLen(&output) == 8 && StrBegin(&output)[0] == 'u' && StrBegin(&output)[1] == 'v' &&
                              StrBegin(&output)[2] == 'w' && StrBegin(&output)[3] == 'x' && StrBegin(&output)[4] == 'y' &&
                              StrBegin(&output)[5] == 'z' && StrBegin(&output)[6] == '1' && StrBegin(&output)[7] == '2');
    
        StrAppendFmt(&output, "{A}", i64_value);
        success = success && (StrLen(&output) == 8 && StrBegin(&output)[0] == 'U' && StrBegin(&output)[1] == 'V' &&
                              StrBegin(&output)[2] == 'W' && StrBegin(&output)[3] == 'X' && StrBegin(&output)[4] == 'Y' &&
                              StrBegin(&output)[5] == 'Z' && StrBegin(&output)[6] == '1' && StrBegin(&output)[7] == '2');
        BitVec bv_empty = BitVecInit(alloc_base);
        StrAppendFmt(&output, "{}", bv_empty);
        success = success && (StrLen(&output) == 0);
        StrClear(&output);
        StrAppendFmt(&s, "old prefix ");
        StrWriteFmt(&s, "fresh {}", LVAL(42));
        bool ok = (StrLen(&s) == 8) && (StrBegin(&s)[0] == 'f') && (StrBegin(&s)[StrLen(&s) - 1] == '2');
        StrDeinit(&s);
        DefaultAllocatorDeinit(&alloc);
        Str              s     = StrInit(&alloc);
        StrAppendFmt(&s, "AAAAAAAA");
        size before_length = StrLen(&s);
        bool ok            = StrPatchFmt(&s, 2, "{}", LVAL(1234));
        ok                 = ok && StrLen(&s) == before_length;
        size before_length = StrLen(&s);
        bool ok            = StrPatchFmt(&s, 2, "{}", LVAL(1234));
        ok                 = ok && StrLen(&s) == before_length;
        ok                 = ok && StrBegin(&s)[0] == 'A' && StrBegin(&s)[1] == 'A';
        ok = ok && StrBegin(&s)[2] == '1' && StrBegin(&s)[3] == '2' && StrBegin(&s)[4] == '3' && StrBegin(&s)[5] == '4';
        // Patch that would extend past the end must fail.
        ok = ok && !StrPatchFmt(&s, 6, "{}", LVAL(9999));
        ok = ok && StrLen(&s) == before_length;
        ok = ok && StrBegin(&s)[6] == 'A' && StrBegin(&s)[7] == 'A';
    
        // Insert a character at the end
        StrInsertR(&s, '.', StrLen(&s));
    
        // Check that the character was inserted correctly
    
        // Check that s2 was reset - data should be NULL, length should be 0
        result = result && (StrLen(&s2) == 0 && StrBegin(&s2) == NULL);
    
        StrDeinit(&s1);
    
        // Check that s2 was not reset
        result = result && (StrLen(&s2) == 6 && ZstrCompare(StrBegin(&s2), " World") == 0);
    
        StrDeinit(&s1);
    
        // s2 was zeroed on take per L-form contract
        result = result && (StrLen(&s2) == 0 && StrBegin(&s2) == NULL);
    
        StrDeinit(&s1);
        FileClose(&f);
    
        bool result = (got == (i64)ZstrLen("hello from file")) && (StrLen(&body) == (size)ZstrLen("hello from file")) &&
                      ZstrCompare(StrBegin(&body), "hello from file") == 0;
    
        Zstr expected = "this is longer than the initial buffer";
        bool result   = (got == (i64)ZstrLen(expected)) && (StrLen(&body) == (size)ZstrLen(expected)) &&
                      ZstrCompare(StrBegin(&body), expected) == 0 && StrCapacity(&body) >= StrLen(&body) + 1;
        Zstr expected = "this is longer than the initial buffer";
        bool result   = (got == (i64)ZstrLen(expected)) && (StrLen(&body) == (size)ZstrLen(expected)) &&
                      ZstrCompare(StrBegin(&body), expected) == 0 && StrCapacity(&body) >= StrLen(&body) + 1;
    
        StrDeinit(&body);
        StrPushBackR(&s, 'o');
    
        bool result = (StrLen(&s) == 5 && ZstrCompare(StrBegin(&s), "Hello") == 0);
    
        StrDeinit(&s);
    
        // Check result
        bool result = ok && (StrLen(&str) == 4);
        result      = result && (StrBegin(&str)[0] == '1');
        result      = result && (StrBegin(&str)[1] == '0');
        // Test converting empty bitvec
        Str str_obj = BitVecToStr(&bv);
        result      = result && (StrLen(&str_obj) == 0);
        StrDeinit(&str_obj);
        BitVecPush(&bv, true);
        str_obj = BitVecToStr(&bv);
        result  = result && (StrLen(&str_obj) == 1);
        result  = result && (StrCmp(&str_obj, "1", 1) == 0);
        StrDeinit(&str_obj);
        }
        str_obj = BitVecToStr(&bv);
        result  = result && (StrLen(&str_obj) == 1000);
        StrDeinit(&str_obj);
    
        Str empty_str = BitVecToStr(&empty);
        result        = result && (StrLen(&empty_str) == 0);
        StrDeinit(&empty_str);
        // Test string conversion
        Str large_str = BitVecToStr(&large_bv);
        result        = result && (StrLen(&large_str) == 1000);
    
        // Verify pattern consistency
        // Verify pattern consistency
        bool pattern_correct = true;
        for (u64 i = 0; i < StrLen(&large_str); i++) {
            bool expected = (i % 3) == 0;
            bool actual   = (StrBegin(&large_str)[i] == '1');
    
    static GraphNodeId city_add_intersection(CityGraph *graph, CityIndex *index, const Str *name, DefaultAllocator *alloc) {
        GraphNodeId id = GraphAddNodeR(graph, StrInitFromCstr(StrBegin(name), StrLen(name), alloc));
    
        Str key_copy = StrInitFromCstr(StrBegin(name), StrLen(name), alloc);
        GraphNodeId id = GraphAddNodeR(graph, StrInitFromCstr(StrBegin(name), StrLen(name), alloc));
    
        Str key_copy = StrInitFromCstr(StrBegin(name), StrLen(name), alloc);
        MapInsertR(index, key_copy, id);
        return id;
            DnsRecord *r0 = VecPtrAt(&resp.answers, 0);
            match         = r0->type == DNS_TYPE_A && r0->ttl == 300 && r0->ipv4[0] == 93 && r0->ipv4[1] == 184 &&
                    r0->ipv4[2] == 216 && r0->ipv4[3] == 34 && StrLen(&r0->name) > 0 &&
                    ZstrCompare(StrBegin(&r0->name), "example.com") == 0;
        }
        if (match) {
            DnsRecord *r = VecPtrAt(&resp.answers, 0);
            match        = r->type == DNS_TYPE_CNAME && StrLen(&r->target) > 0 &&
                    ZstrCompare(StrBegin(&r->target), "example.com") == 0;
        }
        // Check that it's initialized correctly
        // A newly initialized string may have NULL data if capacity is 0
        bool result = (StrLen(&s) == 0);
    
        StrDeinit(&s);
    
        // Check that it's initialized correctly
        bool result = (StrLen(&s) == len && ZstrCompareN(StrBegin(&s), test_str, len) == 0 && StrBegin(&s)[len] == '\0');
    
        StrDeinit(&s);
    
        // Check that it's initialized correctly
        bool result = (StrLen(&s) == ZstrLen(test_str) && ZstrCompare(StrBegin(&s), test_str) == 0);
    
        StrDeinit(&s);
        ValidateStr(&s);
    
        bool result = (StrLen(&s) == ZstrLen(test_str) && ZstrCompare(StrBegin(&s), test_str) == 0);
    
        StrDeinit(&s);
    
        // Check that dst is initialized correctly
        bool result = (StrLen(&dst) == StrLen(&src) && ZstrCompare(StrBegin(&dst), StrBegin(&src)) == 0);
    
        StrDeinit(&src);
    
        // Check that dst is initialized correctly
        bool result = (StrLen(&dst) == StrLen(&src) && ZstrCompare(StrBegin(&dst), StrBegin(&src)) == 0);
    
        StrDeinit(&src);
    
        // Check that the copy was successful
        bool result = (success && StrLen(&dst) == StrLen(&src) && ZstrCompare(StrBegin(&dst), StrBegin(&src)) == 0);
    
        StrDeinit(&src);
        bool dst_allocator_matches = copied && (StrAllocator(&dst) == StrAllocator(&src));
    
        bool result = copied && StrLen(&dup) == StrLen(&src) && StrLen(&dst) == StrLen(&src) &&
                      ZstrCompare(StrBegin(&dup), StrBegin(&src)) == 0 &&
                      ZstrCompare(StrBegin(&dst), StrBegin(&src)) == 0 && dup_allocator_matches && dst_allocator_matches;
        // The expected result depends on whether all characters are processed
        bool success = false;
        if (char_count == StrLen(&s)) {
            success = (ZstrCompare(StrBegin(&result), "olleH") == 0);
            WriteFmt("  (All characters were processed)\n");
        // The expected result depends on whether all characters are processed
        bool success = false;
        if (char_count == StrLen(&s)) {
            success = (ZstrCompare(StrBegin(&result), "olleH") == 0);
            success = success && (ZstrCompare(StrBegin(&s), "HELLO") == 0); // All uppercase
    
        // The empty_result should remain empty
        success = success && (StrLen(&empty_result) == 0);
    
        StrDeinit(&s);
        // Use StrForeachInRangeIdx which captures the 'end' parameter at the start
        // Even if we shrink the string, the loop will continue until idx reaches the fixed end
        size original_length = StrLen(&s); // Capture this as 12
        StrForeachInRangeIdx(&s, chr, idx, 0, original_length) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), chr);
        size original_length = StrLen(&s); // Capture this as 12
        StrForeachInRangeIdx(&s, chr, idx, 0, original_length) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), chr);
    
            // When we reach idx=4, drastically shrink the string to length 3
            if (idx == 4) {
                StrResize(&s, 3); // Shrink to only 3 characters
                WriteFmt("String resized to length {}, idx={}...\n", StrLen(&s), idx);
            }
        // Use StrForeachInRangeIdx with a fixed range that will become invalid
        // when we delete characters during iteration
        size original_length = StrLen(&s); // Capture this as 11
        StrForeachInRangeIdx(&s, chr, idx, 0, original_length) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), chr);
        size original_length = StrLen(&s); // Capture this as 11
        StrForeachInRangeIdx(&s, chr, idx, 0, original_length) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), chr);
    
            // When we reach idx=3, delete several characters from the beginning
            if (idx == 3) {
                StrDeleteRange(&s, 0, 6); // Remove first 6 characters
                WriteFmt("Deleted first 6 characters, new length={}, idx={}...\n", StrLen(&s), idx);
            }
        // StrForeachReverseIdx (VecForeachReverseIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...)
        StrForeachReverseIdx(&s, chr, idx) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), chr);
    
            // When we reach idx=10, drastically shrink the string
            if (idx == 10) {
                StrResize(&s, 4); // Shrink to only 4 characters
                WriteFmt("String resized to length {} during reverse iteration... idx = {}\n", StrLen(&s), idx);
            }
        // StrForeachPtrIdx (VecForeachPtrIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...)
        StrForeachPtrIdx(&s, chr_ptr, idx) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), *chr_ptr);
    
            // When we reach idx=4, delete most characters from the string
            if (idx == 4) {
                StrResize(&s, 4); // Shrink to only 4 characters (valid indices: 0,1,2,3)
                WriteFmt("String resized to length {}, current idx={} is now out of bounds...\n", StrLen(&s), idx);
            }
        // StrForeachReversePtrIdx (VecForeachPtrReverseIdx) has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...)
        StrForeachReversePtrIdx(&s, chr_ptr, idx) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), *chr_ptr);
    
            // When we reach idx=12, shrink the string significantly
            if (idx == 12) {
                StrResize(&s, 5); // Shrink to only 5 characters
                WriteFmt("String resized to length {} during reverse ptr iteration... idx = {}\n", StrLen(&s), idx);
            }
    
        // Use StrForeachPtrInRangeIdx with a fixed range that becomes invalid when we modify the string
        size original_length = StrLen(&s); // Capture this as 32
        StrForeachPtrInRangeIdx(&s, chr_ptr, idx, 0, original_length) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), *chr_ptr);
        size original_length = StrLen(&s); // Capture this as 32
        StrForeachPtrInRangeIdx(&s, chr_ptr, idx, 0, original_length) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), *chr_ptr);
    
            // When we reach idx=8, delete several characters
            if (idx == 8) {
                StrDeleteRange(&s, 0, 20); // Remove first 20 characters
                WriteFmt("Deleted first 20 characters, new length={}, idx = {}...\n", StrLen(&s), idx);
            }
            // loop will terminate automatically
    
            if (idx >= StrLen(&s)) {
                LOG_ERROR("Should've terminated");
                StrDeinit(&s);
        // Basic StrForeachIdx (VecForeachIdx) now has explicit bounds checking: if ((idx) >= (v)->length) LOG_FATAL(...)
        StrForeachIdx(&s, chr, idx) {
            WriteFmt("Accessing idx {} (s.length={}): '{c}'\n", idx, StrLen(&s), chr);
    
            // When we reach idx=3, drastically shrink the string
                WriteFmt(
                    "String resized to length {}, but basic foreach iteration continues... idx = {}\n",
                    StrLen(&s),
                    idx
                );
        ArgRun rc     = ArgParseRun(&p, 3, argv);
    
        bool ok = (rc == ARG_RUN_OK) && StrLen(&name) == 5 && StrBegin(&name)[0] == 'a' && StrBegin(&name)[4] == 'e';
        ArgParseDeinit(&p);
        StrDeinit(&name);
    ///
    #define StrInitFromStr(...)      OVERLOAD(StrInitFromStr, __VA_ARGS__)
    #define StrInitFromStr_1(str)    StrInitFromCstr_2(StrBegin(str), StrLen(str))
    #define StrInitFromStr_2(str, a) StrInitFromCstr_3(StrBegin(str), StrLen(str), (a))
    #define StrInitFromStr(...)      OVERLOAD(StrInitFromStr, __VA_ARGS__)
    #define StrInitFromStr_1(str)    StrInitFromCstr_2(StrBegin(str), StrLen(str))
    #define StrInitFromStr_2(str, a) StrInitFromCstr_3(StrBegin(str), StrLen(str), (a))
    
    ///
    /// TAGS: Str, Empty, Query
    ///
    #define StrEmpty(str) (StrLen(str) == 0)
    
    ///
        do {                                                                                                               \
            const Str *UNPL(jw_s)   = &(s);                                                                                \
            u64        UNPL(jw_len) = StrLen(UNPL(jw_s));                                                                  \
            StrAppendFmt(&(j), "\"{}\"", UNPL(jw_len) ? (Zstr)StrBegin(UNPL(jw_s)) : (Zstr) "");                           \
        } while (0)
Last updated on