You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
add grapheme-counter entry for fast counting (#135)
* add grapheme-counter entry for fast counting
extracted the shared category tables and pair-rule machine into an
internal grapheme-core module, and adds `unicode-segmenter/grapheme-counter`
* udpate bundle stats using UPDATE_README skill
Add `unicode-segmenter/grapheme-counter`, a standalone fast counter for extended grapheme clusters.
6
+
7
+
`countGraphemes()` from the new entry returns exactly the same result as the one in `unicode-segmenter/grapheme`, but runs the boundary rules directly without allocating segment objects or slicing strings:
8
+
9
+
- 4\~7x faster counting on V8, ~4x on Hermes, with zero allocation
10
+
- Standalone entry (4,852 bytes minified, 2,353 bytes gzipped); doesn't carry the segmenter code, and the segmenter entry doesn't carry the counter - even without tree-shaking
11
+
- The `countGraphemes()` wrapper in `unicode-segmenter/grapheme` is unchanged and stays as the convenience API
Copy file name to clipboardExpand all lines: .claude/skills/benchmark/SKILL.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,6 +21,8 @@ This library's priorities, in order: bundle size, runtime perf, memory footprint
21
21
22
22
Benchmarks import `src/*.js` directly — no build step needed, current checkout state is what gets measured.
23
23
24
+
Bundle-stats env options: `PRINT_FORMAT=markdown` prints a README-ready markdown table instead of `console.table`; `UPDATE_README=true` rewrites the matching README comparison table in place (rows/columns matched by name ignoring `*` footnote marks, which are preserved; hand-maintained cells like Unicode®/ESM? and the `Intl.Segmenter` row are untouched).
25
+
24
26
## Interpreting results
25
27
26
28
-**Compare ratios within a run, not absolute ns across runs.** Apple Silicon clock scaling (3.7–4.5 GHz observed on M4 Pro) swings absolute numbers ±20% between runs. Each perf run includes the competitors, so the `summary` "x faster than" lines are the stable signal.
> `countGraphemes()` is a small wrapper around `graphemeSegments()`.
94
95
>
95
96
> If you need it more than once at a time, consider memoization or use `graphemeSegments()` or `splitGraphemes()` once instead.
97
+
>
98
+
> If counting is on your hot path, use the standalone [`unicode-segmenter/grapheme-counter`](#export-unicode-segmentergrapheme-counter) entry instead.
96
99
97
100
#### Example: Build an advanced grapheme matcher
98
101
@@ -122,6 +125,31 @@ function* matchEmoji(str) {
122
125
123
126
Or build even more advanced one like an Unicode-aware [TTY string width](https://github.com/cometkim/unicode-string-width) utility.
124
127
128
+
### Export `unicode-segmenter/grapheme-counter`
129
+
130
+
A standalone counter for extended grapheme clusters.
131
+
132
+
The result is identical to `countGraphemes()` of `unicode-segmenter/grapheme`, but it runs the boundary rules directly without allocating segment objects or slicing strings, so counting is 4+ times faster and zero heap usage.
133
+
134
+
It is a separate entry so that counting doesn't have to carry the segmenter code, and vice versa.
0 commit comments