lib/strings+test: re-port index str-arm to dual-iterator rune walk
Old shape ran byteindex then rewound to count runes — two passes, different algorithm from Hare. New `indexstring` mirrors ref/hare/strings/index.ha:59-81: one outer iterator over the haystack, an inner iterator re-seated from it for each candidate match, both walking rune-by-rune. Returns the rune-index of the first match, or void. Rest-iterator copy is field-wise rather than `let rest_iter = s_iter;` because the local-to-local copy of the 3-field iterator struct diverges between stages today (#41 — 993_ww_ww and 995_self_rebuild byte-diverge when written the natural way). WHY-comment cites #41 with the precise failing tests. Tests pin the rune-vs-byte distinction at i=2 and i=4 with 3-byte kana, plus self-match, empty-needle, empty-haystack, and a no-match multibyte row from ref/hare/strings/index.ha:119.
This commit is contained in:
@@ -371,6 +371,56 @@ fn streq(a: str, b: str) bool = {
|
||||
case let i: i32 => { fail(); };
|
||||
case void => void;
|
||||
};
|
||||
// str-arm: rune-index ≠ byte-index again, mid-string match.
|
||||
// "あった" starts at rune 2 (byte 6) in "またあったね"
|
||||
// (each kana is 3 bytes; ref/hare/strings/index.ha:60). Pins
|
||||
// the dual-iterator walk against the discarded byteindex-and-walk
|
||||
// shape (#10).
|
||||
signalled = 1411;
|
||||
match (strings.index("またあったね", "あった")) {
|
||||
case let i: i32 => { if (i != 2) { fail(); }; };
|
||||
case void => { fail(); };
|
||||
};
|
||||
// str-arm: tail-anchored multibyte needle. "は" is at rune 4
|
||||
// (byte 12) in "こんにちは".
|
||||
signalled = 1412;
|
||||
match (strings.index("こんにちは", "は")) {
|
||||
case let i: i32 => { if (i != 4) { fail(); }; };
|
||||
case void => { fail(); };
|
||||
};
|
||||
// Empty needle hits at rune 0 — Hare's `index_string` falls into
|
||||
// the `needle_rune is done` branch on the very first inner step
|
||||
// (ref/hare/strings/index.ha:70).
|
||||
signalled = 1413;
|
||||
match (strings.index("hello", "")) {
|
||||
case let i: i32 => { if (i != 0) { fail(); }; };
|
||||
case void => { fail(); };
|
||||
};
|
||||
signalled = 1414;
|
||||
match (strings.index("", "")) {
|
||||
case let i: i32 => { if (i != 0) { fail(); }; };
|
||||
case void => { fail(); };
|
||||
};
|
||||
// Empty haystack, non-empty needle — absent.
|
||||
signalled = 1415;
|
||||
match (strings.index("", "x")) {
|
||||
case let i: i32 => { fail(); };
|
||||
case void => void;
|
||||
};
|
||||
// Multibyte haystack, multibyte absent needle — exercises the
|
||||
// inner-loop mismatch-break across runes (#10, Hare row
|
||||
// ref/hare/strings/index.ha:119).
|
||||
signalled = 1416;
|
||||
match (strings.index("こんにちは", "きょうは")) {
|
||||
case let i: i32 => { fail(); };
|
||||
case void => void;
|
||||
};
|
||||
// Self-match: haystack == needle, Hare row index.ha:113.
|
||||
signalled = 1417;
|
||||
match (strings.index("hello", "hello")) {
|
||||
case let i: i32 => { if (i != 0) { fail(); }; };
|
||||
case void => { fail(); };
|
||||
};
|
||||
};
|
||||
|
||||
// ---- rindex -----------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user