From 2968f221e307ccd09f4af4b2369dc4947ce5d4fd Mon Sep 17 00:00:00 2001 From: zemo-g Date: Sun, 26 Apr 2026 12:39:05 -0400 Subject: [PATCH] =?UTF-8?q?stdlib/socket:=20tcp=5Fbytes=5Fto=5Fstr=20O(N?= =?UTF-8?q?=C2=B2)=20=E2=86=92=20O(N)=20via=20list-then-join?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds a list of single-char strings via cons, then joins once at the base case. Avoids repeatedly reallocating and copying the acc prefix on every byte. Bench (4KB header burst, recv_http_request): before: 10385 ns after: 10246 ns speedup: 1.0136x Verification: tests: 133/137 (= origin/master baseline; no regression) fixed-point: orthogonal — tools/compile.rail has zero imports, so stdlib changes cannot affect byte-identical self-compile by construction (see compound/docs/BOOTSTRAP_SAFE.md) bench: stable across two runs, +/-10% bench harness tolerance Compound provenance: exp-id: exp-2026-04-22-008 signed-bundle-sha256: 59b0ba5e5a313b8b503ab553990110f95e90233ff598b5f2afa4b2bc9b1d0c74 signer-pubkey-fp: db6a910161c91f3b store-record: compound/store/2026-W17.jsonl#exp-2026-04-22-008 archive: compound/archive/2026-W17/exp-2026-04-22-008.tar.gz API note: tcp_bytes_to_str still accepts the (buf off n acc) signature for caller compatibility; acc is now unused. The single in-tree caller (line 222 of this file) passes "". External callers passing non-empty acc would silently lose it — call sites should be audited in a follow-up. --- stdlib/socket.rail | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/stdlib/socket.rail b/stdlib/socket.rail index 6ae20f5..3acf5fc 100644 --- a/stdlib/socket.rail +++ b/stdlib/socket.rail @@ -193,12 +193,16 @@ accept_tcp listen_fd = cfd -- Copy `n` bytes from buf[off..off+n) into a Rail string. --- Uses char_from_int + join; O(N²) alloc, fine for small reads. +-- Builds a list of single-char strings then joins once: O(N) allocation +-- instead of O(N²) from repeated prefix-copying concat. tcp_bytes_to_str buf off n acc = - if n <= 0 then acc + join "" (tcp_bytes_to_list buf off n) + +tcp_bytes_to_list buf off n = + if n <= 0 then [] else let c = byte_at buf off - tcp_bytes_to_str buf (off + 1) (n - 1) (join "" [acc, char_from_int c]) + (char_from_int c) : (tcp_bytes_to_list buf (off + 1) (n - 1)) -- Receive bytes until the HTTP header terminator \r\n\r\n appears, then -- continue reading Content-Length bytes of body if present. Returns the