mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-31 07:23:06 +08:00
fix: retain sparse anchors for long ascii prefixes
Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>
This commit is contained in:
@@ -555,6 +555,21 @@ static void scr_sidx_extend_to_u16(const ScrStr *s, ScrSidx *e, size_t u16) {
|
||||
scr_sidx_finish(s, e);
|
||||
}
|
||||
|
||||
/* A large, not-yet-complete string can have a long proven-ASCII prefix
|
||||
* before its first non-ASCII byte. That prefix is an exact identity map, but
|
||||
* merely advancing indexed_{cu,cb} through it leaves alternating on-demand
|
||||
* lookups with only the hot cursor and therefore linear backtracks. Once an
|
||||
* indexed conversion reaches such a prefix, retain its arithmetic stride
|
||||
* anchors too. A later full scan still drops them if the whole string proves
|
||||
* ASCII, so the all-ASCII steady state remains the allocation-free identity
|
||||
* fast path. */
|
||||
static void scr_sidx_materialize_identity_prefix(const ScrStr *s, ScrSidx *e) {
|
||||
if (e->npoints == 0 && e->indexed_cb != 0 &&
|
||||
e->indexed_cb == e->indexed_cu) {
|
||||
(void)scr_sidx_prepare_points(s, e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cached UTF-16 length. Large strings extend from their exact previously
|
||||
* indexed prefix, retaining sparse start/end anchors; short strings keep the
|
||||
* historical single word-wise scan. `u16len == byte len` proves ASCII and
|
||||
@@ -660,6 +675,7 @@ static size_t scr_u16_to_byte_c(const ScrStr *s, ScrSidx *e, size_t u16,
|
||||
return u16 < s->len ? u16 : s->len;
|
||||
}
|
||||
scr_sidx_extend_to_u16(s, e, u16);
|
||||
scr_sidx_materialize_identity_prefix(s, e);
|
||||
ScrSidxPoint near = scr_sidx_near_u16(s, e, u16);
|
||||
size_t cu = near.cu, cb = near.cb;
|
||||
while (cu > u16) scr_sidx_back(s, &cu, &cb);
|
||||
@@ -692,6 +708,7 @@ static size_t scr_byte_to_u16_c(const ScrStr *s, ScrSidx *e,
|
||||
while (e->indexed_cb < byte_off) scr_sidx_extend_one(s, e);
|
||||
scr_sidx_finish(s, e);
|
||||
}
|
||||
scr_sidx_materialize_identity_prefix(s, e);
|
||||
ScrSidxPoint near = scr_sidx_near_byte(s, e, byte_off);
|
||||
size_t cu = near.cu, cb = near.cb;
|
||||
while (cb > byte_off) scr_sidx_back(s, &cu, &cb);
|
||||
|
||||
@@ -341,6 +341,38 @@ static void sparse_index_asserts(void) {
|
||||
scr_str_release(s);
|
||||
scr_sidx_test_reset_cache();
|
||||
}
|
||||
|
||||
/* Do not wait for the first non-ASCII byte before proving this access shape.
|
||||
* A string can have megabytes of ordinary ASCII followed by one emoji: no
|
||||
* `.length` prime is involved here, and alternating distant reads in that
|
||||
* prefix must retain identity checkpoints instead of repeatedly walking the
|
||||
* distance between the two hot-cursor positions. */
|
||||
static void sparse_ascii_prefix_asserts(void) {
|
||||
enum { PREFIX = 4 * 1024 * 1024, QUERIES = 8 };
|
||||
const size_t first = (size_t)1024 * 1024 + 137;
|
||||
const size_t second = (size_t)3 * 1024 * 1024 + 271;
|
||||
char *raw = malloc((size_t)PREFIX + 4);
|
||||
if (!raw) { sidx_fail("ASCII-prefix test allocation"); return; }
|
||||
memset(raw, 'a', PREFIX);
|
||||
memcpy(raw + PREFIX, "\xF0\x9F\x98\x80", 4); /* terminal emoji */
|
||||
ScrStr *s = scr_str_new(raw, (size_t)PREFIX + 4);
|
||||
free(raw);
|
||||
|
||||
scr_sidx_test_reset_cache();
|
||||
scr_sidx_test_reset_steps();
|
||||
for (size_t q = 0; q < QUERIES; q++) {
|
||||
size_t at = q & 1 ? second : first;
|
||||
if (scr_str_char_code_at(s, (double)at) != 97.0)
|
||||
sidx_fail("ASCII-prefix charCodeAt result");
|
||||
}
|
||||
if (scr_sidx_test_points() == 0)
|
||||
sidx_fail("ASCII-prefix identity checkpoints were not retained");
|
||||
if (scr_sidx_test_walk_steps() > (size_t)QUERIES * 4200)
|
||||
sidx_fail("ASCII-prefix lookup exceeded sparse stride bound");
|
||||
|
||||
scr_str_release(s);
|
||||
scr_sidx_test_reset_cache();
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -507,6 +539,7 @@ int main(int argc, char **argv) {
|
||||
accumulation_asserts();
|
||||
#ifdef SCR_SIDX_TEST
|
||||
sparse_index_asserts();
|
||||
sparse_ascii_prefix_asserts();
|
||||
#endif
|
||||
|
||||
#ifdef SCR_RC_AUDIT
|
||||
|
||||
Reference in New Issue
Block a user