Skip to content

Commit 6fb5672

Browse files
committed
perf(unicode): index common combining classes
1 parent 24ff956 commit 6fb5672

7 files changed

Lines changed: 27 additions & 1 deletion

File tree

docs/changelog/799.feature.24.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use direct combining-class lookup for common marks in :func:`~turbohtml.detect.normalize`.

src/turbohtml/_c/data/normalize_table.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ typedef struct {
1919
} th_norm_ccc_row;
2020

2121
static const int th_norm_ccc_count = 934;
22+
static const uint8_t th_norm_ccc_dense[] = {
23+
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 232,
24+
220, 220, 220, 220, 232, 216, 220, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220,
25+
220, 220, 220, 220, 220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220, 220, 230, 230, 230, 230, 230, 230, 230,
26+
230, 240, 230, 220, 220, 220, 230, 230, 230, 220, 220, 0, 230, 230, 230, 220, 220, 220, 220, 230, 232, 220, 220,
27+
230, 233, 234, 234, 233, 234, 234, 233, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0,
28+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32+
};
33+
2234
static const th_norm_ccc_row th_norm_ccc[] = {
2335
{0x300, 230}, {0x301, 230}, {0x302, 230}, {0x303, 230}, {0x304, 230}, {0x305, 230}, {0x306, 230}, {0x307, 230},
2436
{0x308, 230}, {0x309, 230}, {0x30A, 230}, {0x30B, 230}, {0x30C, 230}, {0x30D, 230}, {0x30E, 230}, {0x30F, 230},

src/turbohtml/_c/unicode/normalize.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ static uint8_t ccc_of(Py_UCS4 cp) {
3535
if (cp < th_norm_ccc[0].code) {
3636
return 0;
3737
}
38+
Py_UCS4 offset = cp - th_norm_ccc[0].code;
39+
if (offset < sizeof(th_norm_ccc_dense)) {
40+
return th_norm_ccc_dense[offset];
41+
}
3842
int lo = 0;
3943
int hi = th_norm_ccc_count;
4044
while (lo < hi) {

tools/bench/ci.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,9 @@ def _book_html() -> str:
426426
"select-default-many-forms": ("select-default", 3),
427427
"select-default-tag-control": ("select-default", 4),
428428
"select-default-explicit-submit": ("select-default", 5),
429+
"normalize-marks-large": ("normalize-marks", 2),
430+
"normalize-marks-small": ("normalize-marks", 0),
431+
"normalize-hebrew-marks": ("normalize", 8),
429432
}
430433

431434

tools/bench/competitors/unicodedata.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ def normalize(text: str) -> None:
1212
unicodedata.normalize("NFC", text)
1313

1414

15-
OPERATIONS = {"normalize": (normalize, "unicodedata")}
15+
OPERATIONS = {
16+
"normalize": (normalize, "unicodedata"),
17+
"normalize-marks": (normalize, "unicodedata"),
18+
}

tools/bench/operations.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,7 @@ def _normalize_cases() -> tuple[tuple[str, object], ...]:
14711471
("small ASCII prefix, composable suffix", "abc e\u0301"),
14721472
("4,096 composable combining pairs", "e\u0301" * 4096),
14731473
("4,096 Hangul jamo triples", "\u1100\u1161\u11a8" * 4096),
1474+
("10,000 Hebrew combining marks", "\u05d0" + "\u05b1" * 5000 + "\u05b0" * 5000),
14741475
)
14751476

14761477

tools/generate_normalize.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ def _emit(
285285
canon_text = _decomp_block("canon", canonical)
286286
compat_text = _decomp_block("compat", compatibility)
287287
max_expansion = max(len(run) for run in (*canonical.values(), *compatibility.values()))
288+
ccc_dense: Final = _wrap(str(combining.get(code, 0)) for code in range(ccc_items[0][0], ccc_items[0][0] + 256))
288289
return (
289290
"/* Auto-generated by tools/generate_normalize.py - do not edit. */\n"
290291
f"/* Unicode {UNICODE_VERSION} normalization (UAX #15): the canonical combining classes, the full canonical\n"
@@ -302,6 +303,7 @@ def _emit(
302303
" uint8_t ccc;\n"
303304
"} th_norm_ccc_row;\n\n"
304305
f"static const int th_norm_ccc_count = {len(ccc_items)};\n"
306+
f"static const uint8_t th_norm_ccc_dense[] = {{\n{ccc_dense}\n}};\n\n"
305307
f"static const th_norm_ccc_row th_norm_ccc[] = {{\n{ccc_rows}\n}};\n\n"
306308
"/* Full decomposition, sorted by code point: pool[offset, offset+length) is the run. The compatibility table\n"
307309
" holds only code points whose NFKD differs from their NFD; the canonical table covers the rest. */\n"

0 commit comments

Comments
 (0)