From dfc137fe1070e9807d30be6d88d8c0b34ceb2d67 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Wed, 22 Jul 2026 19:16:15 +0900 Subject: [PATCH 1/7] fuse the state transition become more compact --- README.md | 8 ++--- src/grapheme.js | 77 +++++++++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index bf84219..bee908a 100644 --- a/README.md +++ b/README.md @@ -237,8 +237,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Unicode® | ESM? | Size | Size (min) | Size (min+gzip) | Size (min+br) | Size (min+zstd) | |--------------------------------------|----------|------|--------:|-----------:|----------------:|--------------:|----------------:| -| `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,782 | 5,069 | 2,462 | 2,218 | 2,508 | -| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 11,182 | 5,927 | 2,820 | 2,492 | 2,865 | +| `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,593 | 5,097 | 2,474 | 2,253 | 2,531 | +| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,815 | 5,871 | 2,810 | 2,479 | 2,872 | | `graphemer` | 15.0.0 | ✖️ | 410,435 | 95,104 | 15,752 | 10,660 | 15,911 | | `grapheme-splitter` | 10.0.0 | ✖️ | 122,254 | 23,682 | 7,852 | 4,802 | 6,753 | | `@formatjs/intl-segmenter`* | 17.0.0 | ✖️ | 268,301 | 176,759 | 45,988 | 31,701 | 45,370 | @@ -255,8 +255,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Bytecode size | Bytecode size (gzip)* | |-------------------------------------|--------------:|----------------------:| -| `unicode-segmenter/grapheme` | 20,203 | 11,224 | -| `unicode-segmenter/grapheme` (full) | 20,408 | 11,356 | +| `unicode-segmenter/grapheme` | 20,376 | 11,327 | +| `unicode-segmenter/grapheme` (full) | 20,581 | 11,462 | | `graphemer` | 134,085 | 31,770 | | `grapheme-splitter` | 63,942 | 19,165 | | `@formatjs/intl-segmenter` | 329,547 | 136,751 | diff --git a/src/grapheme.js b/src/grapheme.js index bf73724..b6d958b 100644 --- a/src/grapheme.js +++ b/src/grapheme.js @@ -163,6 +163,36 @@ function isLinker(cp) { || cp === 0x11F42; // Kawi Conjoiner } +// Next-state table for the four cp-independent transitions +// (Extended_Pictographic, Regional_Indicator, ZWJ, InCB=Consonant). +// Index: `NEXT[(cat << 5) | st]`; only rows for cats 4, 10, 14, 15 are populated. +// Extend (cat 3) is cp-dependent (ZWNJ vs `isLinker`) and is handled by `nextExtend` directly. +const NEXT = new Uint8Array(16 << 5); +for (let st = 0; st < 32; st++) { + NEXT[(4 << 5) | st] = 2; // Extended_Pictographic + NEXT[(10 << 5) | st] = (st & 1) ^ 1; // Regional_Indicator + NEXT[(14 << 5) | st] = (st & 2) << 1 | (st & 24); // ZWJ + NEXT[(15 << 5) | st] = 8; // InCB=Consonant +} + +/** + * State transition on consuming an Extend code point (category 3). + * The cp-dependent ZWNJ / `isLinker` branches; the cp-independent + * transitions live in {@link NEXT}. + * + * @param {number} st packed state + * @param {number} cp the consumed Extend code point + * @return {number} next packed state + */ +function nextExtend(st, cp) { + if (st & 24) { + if (cp === 0x200C) return st & 6; // ZWNJ has InCB=None + if ((st & 24) === 16 || isLinker(cp)) return (st & 6) | 16; + return (st & 6) | 8; + } + return st & 6; +} + // Sequence state, packed in a small int: // // bit 0 : odd run of Regional_Indicator immediately precedes (GB12, GB13) @@ -179,34 +209,19 @@ function isLinker(cp) { /** * State transition on consuming a code point. * + * Extend (cat 3) is cp-dependent and goes through {@link nextExtend}; + * other stateful categories use the {@link NEXT} table; + * everything else resets to 0. + * * @param {number} st packed state * @param {number} c category of the consumed code point * @param {number} cp the consumed code point * @return {number} next packed state */ export function nextState(st, c, cp) { - switch (c) { - // Extend; keeps picto bits, advances InCB run - case 3: - if (st & 24) { - if (cp === 0x200C) return st & 6; // ZWNJ has InCB=None - if ((st & 24) === 16 || isLinker(cp)) return (st & 6) | 16; - return (st & 6) | 8; - } - return st & 6; - // Extended_Pictographic - case 4: - return 2; - // Regional_Indicator; toggles parity - case 10: - return (st & 1) ^ 1; - // ZWJ; captures the picto bit, advances InCB run - case 14: - return (st & 2) << 1 | (st & 24); - // InCB=Consonant (15); callers never pass other categories - default: - return 8; - } + if (c === 3) return st ? nextExtend(st, cp) : 0; + if ((0xC418 >> c) & 1) return NEXT[(c << 5) | st]; + return 0; } /** @@ -229,7 +244,7 @@ export function* graphemeSegments(input) { let catBefore = cat(cp); /** Packed sequence state */ - let st = (0xC418 >> catBefore) & 1 ? nextState(0, catBefore, cp) : 0; + let st = nextState(0, catBefore, cp); /** Start index of the current segment */ let index = 0; @@ -251,9 +266,7 @@ export function* graphemeSegments(input) { else if (d === 3) boundary = !(st & 4); else boundary = (st & 24) !== 16; - st = (0xC418 >> catAfter) & 1 && (st !== 0 || catAfter !== 3) - ? nextState(st, catAfter, cp) - : 0; + st = nextState(st, catAfter, cp); if (boundary) { yield { @@ -309,7 +322,7 @@ export function countGraphemes(input) { let catBefore = cat(cp); /** Packed sequence state */ - let st = (0xC418 >> catBefore) & 1 ? nextState(0, catBefore, cp) : 0; + let st = nextState(0, catBefore, cp); /** The segment being scanned counts, whether or not a boundary follows */ let count = 1; @@ -325,9 +338,7 @@ export function countGraphemes(input) { else if (d === 3) boundary = !(st & 4); else boundary = (st & 24) !== 16; - st = (0xC418 >> catAfter) & 1 && (st !== 0 || catAfter !== 3) - ? nextState(st, catAfter, cp) - : 0; + st = nextState(st, catAfter, cp); if (boundary) count += 1; cursor += cp > 0xFFFF ? 2 : 1; @@ -387,7 +398,7 @@ export function collectGraphemes(input) { let catBefore = cat(cp); /** Packed sequence state */ - let st = (0xC418 >> catBefore) & 1 ? nextState(0, catBefore, cp) : 0; + let st = nextState(0, catBefore, cp); /** Start index of the current segment */ let index = 0; @@ -403,9 +414,7 @@ export function collectGraphemes(input) { else if (d === 3) boundary = !(st & 4); else boundary = (st & 24) !== 16; - st = (0xC418 >> catAfter) & 1 && (st !== 0 || catAfter !== 3) - ? nextState(st, catAfter, cp) - : 0; + st = nextState(st, catAfter, cp); if (boundary) { result.push(input.slice(index, cursor)); From ab1456c1b5ce43209348daffc5092e389d1b5e33 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Wed, 22 Jul 2026 19:30:31 +0900 Subject: [PATCH 2/7] avoid abusing more array buffers --- README.md | 8 ++++---- src/grapheme.js | 36 ++++++++++++++---------------------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index bee908a..54cca02 100644 --- a/README.md +++ b/README.md @@ -237,8 +237,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Unicode® | ESM? | Size | Size (min) | Size (min+gzip) | Size (min+br) | Size (min+zstd) | |--------------------------------------|----------|------|--------:|-----------:|----------------:|--------------:|----------------:| -| `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,593 | 5,097 | 2,474 | 2,253 | 2,531 | -| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,815 | 5,871 | 2,810 | 2,479 | 2,872 | +| `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,628 | 5,078 | 2,451 | 2,228 | 2,505 | +| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,850 | 5,852 | 2,791 | 2,452 | 2,854 | | `graphemer` | 15.0.0 | ✖️ | 410,435 | 95,104 | 15,752 | 10,660 | 15,911 | | `grapheme-splitter` | 10.0.0 | ✖️ | 122,254 | 23,682 | 7,852 | 4,802 | 6,753 | | `@formatjs/intl-segmenter`* | 17.0.0 | ✖️ | 268,301 | 176,759 | 45,988 | 31,701 | 45,370 | @@ -255,8 +255,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Bytecode size | Bytecode size (gzip)* | |-------------------------------------|--------------:|----------------------:| -| `unicode-segmenter/grapheme` | 20,376 | 11,327 | -| `unicode-segmenter/grapheme` (full) | 20,581 | 11,462 | +| `unicode-segmenter/grapheme` | 20,118 | 11,192 | +| `unicode-segmenter/grapheme` (full) | 20,323 | 11,332 | | `graphemer` | 134,085 | 31,770 | | `grapheme-splitter` | 63,942 | 19,165 | | `@formatjs/intl-segmenter` | 329,547 | 136,751 | diff --git a/src/grapheme.js b/src/grapheme.js index b6d958b..894d0e8 100644 --- a/src/grapheme.js +++ b/src/grapheme.js @@ -163,22 +163,10 @@ function isLinker(cp) { || cp === 0x11F42; // Kawi Conjoiner } -// Next-state table for the four cp-independent transitions -// (Extended_Pictographic, Regional_Indicator, ZWJ, InCB=Consonant). -// Index: `NEXT[(cat << 5) | st]`; only rows for cats 4, 10, 14, 15 are populated. -// Extend (cat 3) is cp-dependent (ZWNJ vs `isLinker`) and is handled by `nextExtend` directly. -const NEXT = new Uint8Array(16 << 5); -for (let st = 0; st < 32; st++) { - NEXT[(4 << 5) | st] = 2; // Extended_Pictographic - NEXT[(10 << 5) | st] = (st & 1) ^ 1; // Regional_Indicator - NEXT[(14 << 5) | st] = (st & 2) << 1 | (st & 24); // ZWJ - NEXT[(15 << 5) | st] = 8; // InCB=Consonant -} - /** * State transition on consuming an Extend code point (category 3). - * The cp-dependent ZWNJ / `isLinker` branches; the cp-independent - * transitions live in {@link NEXT}. + * The cp-dependent ZWNJ / `isLinker` branches are extracted here so + * that {@link nextState} stays a compact switch. * * @param {number} st packed state * @param {number} cp the consumed Extend code point @@ -202,15 +190,14 @@ function nextExtend(st, cp) { // 10 = it also contains a Linker (GB9c) // // It is a pure function of the consumed code point sequence, so it carries -// across segment boundaries without any reset. Callers skip the transition -// (resetting state to 0) unless the category can arm or keep state; -// see the `0xC418` masks (categories 3, 4, 10, 14, and 15) on call sites. +// across segment boundaries without any reset. Non-stateful categories +// reset the state to 0 inside {@link nextState}. /** * State transition on consuming a code point. * - * Extend (cat 3) is cp-dependent and goes through {@link nextExtend}; - * other stateful categories use the {@link NEXT} table; + * Extend (cat 3) is cp-dependent and delegates to {@link nextExtend}; + * the remaining stateful categories (4, 10, 14, 15) are inline; * everything else resets to 0. * * @param {number} st packed state @@ -219,9 +206,14 @@ function nextExtend(st, cp) { * @return {number} next packed state */ export function nextState(st, c, cp) { - if (c === 3) return st ? nextExtend(st, cp) : 0; - if ((0xC418 >> c) & 1) return NEXT[(c << 5) | st]; - return 0; + switch (c) { + case 3: return st ? nextExtend(st, cp) : 0; + case 4: return 2; // Extended_Pictographic + case 10: return (st & 1) ^ 1; // Regional_Indicator + case 14: return (st & 2) << 1 | (st & 24); // ZWJ + case 15: return 8; // InCB=Consonant + default: return 0; + } } /** From 49fc6f93cc605bcdece980bb7585deaeb98f7064 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Wed, 22 Jul 2026 19:47:36 +0900 Subject: [PATCH 3/7] don't export unnecessarily --- README.md | 4 ++-- src/grapheme.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 54cca02..b81e12c 100644 --- a/README.md +++ b/README.md @@ -255,8 +255,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Bytecode size | Bytecode size (gzip)* | |-------------------------------------|--------------:|----------------------:| -| `unicode-segmenter/grapheme` | 20,118 | 11,192 | -| `unicode-segmenter/grapheme` (full) | 20,323 | 11,332 | +| `unicode-segmenter/grapheme` | 20,042 | 11,128 | +| `unicode-segmenter/grapheme` (full) | 20,247 | 11,274 | | `graphemer` | 134,085 | 31,770 | | `grapheme-splitter` | 63,942 | 19,165 | | `@formatjs/intl-segmenter` | 329,547 | 136,751 | diff --git a/src/grapheme.js b/src/grapheme.js index 894d0e8..342794b 100644 --- a/src/grapheme.js +++ b/src/grapheme.js @@ -90,7 +90,7 @@ let TAIL_E; * @param {number} cp * @return {number} category number, {@link GraphemeCategoryNum} or 15 (`InCB=Consonant`) */ -export function cat(cp) { +function cat(cp) { if (cp < 0x3000) return T0[cp]; // CJK: 0x3000-0x9FFF if (cp < T1_MIN) { @@ -131,7 +131,7 @@ export function cat(cp) { // - 2: GB12/GB13, no boundary iff odd run of RI precedes // - 3: GB11, no boundary iff the ZWJ was preceded by ExtPic Extend* // - 4: GB9c, no boundary iff InCB Consonant [Extend Linker]* Linker [Extend Linker]* precedes -export const PAIR = Uint8Array.from(grapheme_pairs, Number); +const PAIR = Uint8Array.from(grapheme_pairs, Number); /** * The Unicode `Indic_Conjunct_Break=Linker` set @@ -205,7 +205,7 @@ function nextExtend(st, cp) { * @param {number} cp the consumed code point * @return {number} next packed state */ -export function nextState(st, c, cp) { +function nextState(st, c, cp) { switch (c) { case 3: return st ? nextExtend(st, cp) : 0; case 4: return 2; // Extended_Pictographic From 0cb4b7483e3e3c90efd4c943d31a2c5eaf824a6b Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Wed, 22 Jul 2026 20:00:54 +0900 Subject: [PATCH 4/7] extract the boundary check to share --- README.md | 8 ++++---- src/grapheme.js | 53 +++++++++++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index b81e12c..e8792c9 100644 --- a/README.md +++ b/README.md @@ -237,8 +237,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Unicode® | ESM? | Size | Size (min) | Size (min+gzip) | Size (min+br) | Size (min+zstd) | |--------------------------------------|----------|------|--------:|-----------:|----------------:|--------------:|----------------:| -| `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,628 | 5,078 | 2,451 | 2,228 | 2,505 | -| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,850 | 5,852 | 2,791 | 2,452 | 2,854 | +| `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,692 | 5,140 | 2,460 | 2,215 | 2,511 | +| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,500 | 5,788 | 2,743 | 2,422 | 2,806 | | `graphemer` | 15.0.0 | ✖️ | 410,435 | 95,104 | 15,752 | 10,660 | 15,911 | | `grapheme-splitter` | 10.0.0 | ✖️ | 122,254 | 23,682 | 7,852 | 4,802 | 6,753 | | `@formatjs/intl-segmenter`* | 17.0.0 | ✖️ | 268,301 | 176,759 | 45,988 | 31,701 | 45,370 | @@ -255,8 +255,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Bytecode size | Bytecode size (gzip)* | |-------------------------------------|--------------:|----------------------:| -| `unicode-segmenter/grapheme` | 20,042 | 11,128 | -| `unicode-segmenter/grapheme` (full) | 20,247 | 11,274 | +| `unicode-segmenter/grapheme` | 20,044 | 11,088 | +| `unicode-segmenter/grapheme` (full) | 20,249 | 11,224 | | `graphemer` | 134,085 | 31,770 | | `grapheme-splitter` | 63,942 | 19,165 | | `@formatjs/intl-segmenter` | 329,547 | 136,751 | diff --git a/src/grapheme.js b/src/grapheme.js index 342794b..fecad26 100644 --- a/src/grapheme.js +++ b/src/grapheme.js @@ -193,6 +193,35 @@ function nextExtend(st, cp) { // across segment boundaries without any reset. Non-stateful categories // reset the state to 0 inside {@link nextState}. +/** + * Resolve a pair rule to a boundary decision. + * + * Each entry in {@link PAIR} encodes *how* to decide a boundary between + * two adjacent categories, not the decision itself: + * + * 0 -> always a boundary (break) + * 1 -> never a boundary (no-break) + * 2 -> boundary unless an odd number of Regional_Indicators precede (GB12/GB13) + * 3 -> boundary unless preceded by ExtPic Extend* (GB11) + * 4 -> boundary unless an InCB Linker has been seen in the run (GB9c) + * + * Rules 2-4 consult the packed sequence state `st` that was captured + * *before* the state transition on `catAfter`. + * + * @param {number} st packed state + * @param {number} pairRule the pair-rule value from {@link PAIR} + * @return {boolean} whether a boundary exists + */ +function isBoundary(st, pairRule) { + switch (pairRule) { + case 0: return true; + case 1: return false; + case 2: return !(st & 1); + case 3: return !(st & 4); + default: return (st & 24) !== 16; + } +} + /** * State transition on consuming a code point. * @@ -250,13 +279,7 @@ export function* graphemeSegments(input) { while (cursor < len) { cp = /** @type {number} */ (input.codePointAt(cursor)); let catAfter = cat(cp); - let d = PAIR[catBefore << 4 | catAfter]; - let boundary; - if (d === 0) boundary = true; - else if (d === 1) boundary = false; - else if (d === 2) boundary = !(st & 1); - else if (d === 3) boundary = !(st & 4); - else boundary = (st & 24) !== 16; + let boundary = isBoundary(st, PAIR[catBefore << 4 | catAfter]); st = nextState(st, catAfter, cp); @@ -322,13 +345,7 @@ export function countGraphemes(input) { while (cursor < len) { cp = /** @type {number} */ (input.codePointAt(cursor)); let catAfter = cat(cp); - let d = PAIR[catBefore << 4 | catAfter]; - let boundary; - if (d === 0) boundary = true; - else if (d === 1) boundary = false; - else if (d === 2) boundary = !(st & 1); - else if (d === 3) boundary = !(st & 4); - else boundary = (st & 24) !== 16; + let boundary = isBoundary(st, PAIR[catBefore << 4 | catAfter]); st = nextState(st, catAfter, cp); @@ -398,13 +415,7 @@ export function collectGraphemes(input) { while (cursor < len) { cp = /** @type {number} */ (input.codePointAt(cursor)); let catAfter = cat(cp); - let d = PAIR[catBefore << 4 | catAfter]; - let boundary; - if (d === 0) boundary = true; - else if (d === 1) boundary = false; - else if (d === 2) boundary = !(st & 1); - else if (d === 3) boundary = !(st & 4); - else boundary = (st & 24) !== 16; + let boundary = isBoundary(st, PAIR[catBefore << 4 | catAfter]); st = nextState(st, catAfter, cp); From 8c214b8d9daa58d50dd885c2d22afd0b32693303 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Wed, 22 Jul 2026 20:04:29 +0900 Subject: [PATCH 5/7] tidy --- README.md | 8 ++++---- src/grapheme.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e8792c9..abb16ff 100644 --- a/README.md +++ b/README.md @@ -237,8 +237,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Unicode® | ESM? | Size | Size (min) | Size (min+gzip) | Size (min+br) | Size (min+zstd) | |--------------------------------------|----------|------|--------:|-----------:|----------------:|--------------:|----------------:| -| `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,692 | 5,140 | 2,460 | 2,215 | 2,511 | -| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,500 | 5,788 | 2,743 | 2,422 | 2,806 | +| `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,684 | 5,133 | 2,453 | 2,220 | 2,505 | +| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,492 | 5,781 | 2,738 | 2,450 | 2,800 | | `graphemer` | 15.0.0 | ✖️ | 410,435 | 95,104 | 15,752 | 10,660 | 15,911 | | `grapheme-splitter` | 10.0.0 | ✖️ | 122,254 | 23,682 | 7,852 | 4,802 | 6,753 | | `@formatjs/intl-segmenter`* | 17.0.0 | ✖️ | 268,301 | 176,759 | 45,988 | 31,701 | 45,370 | @@ -255,8 +255,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Bytecode size | Bytecode size (gzip)* | |-------------------------------------|--------------:|----------------------:| -| `unicode-segmenter/grapheme` | 20,044 | 11,088 | -| `unicode-segmenter/grapheme` (full) | 20,249 | 11,224 | +| `unicode-segmenter/grapheme` | 20,019 | 11,068 | +| `unicode-segmenter/grapheme` (full) | 20,224 | 11,206 | | `graphemer` | 134,085 | 31,770 | | `grapheme-splitter` | 63,942 | 19,165 | | `@formatjs/intl-segmenter` | 329,547 | 136,751 | diff --git a/src/grapheme.js b/src/grapheme.js index fecad26..48e204a 100644 --- a/src/grapheme.js +++ b/src/grapheme.js @@ -131,7 +131,7 @@ function cat(cp) { // - 2: GB12/GB13, no boundary iff odd run of RI precedes // - 3: GB11, no boundary iff the ZWJ was preceded by ExtPic Extend* // - 4: GB9c, no boundary iff InCB Consonant [Extend Linker]* Linker [Extend Linker]* precedes -const PAIR = Uint8Array.from(grapheme_pairs, Number); +const PAIR = Uint8Array.from(grapheme_pairs); /** * The Unicode `Indic_Conjunct_Break=Linker` set From fed1c72c37988a517d559c2ed9c16f7e2974429f Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Wed, 22 Jul 2026 20:07:01 +0900 Subject: [PATCH 6/7] tidy --- README.md | 6 +++--- src/grapheme.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index abb16ff..a1a346a 100644 --- a/README.md +++ b/README.md @@ -238,7 +238,7 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Unicode® | ESM? | Size | Size (min) | Size (min+gzip) | Size (min+br) | Size (min+zstd) | |--------------------------------------|----------|------|--------:|-----------:|----------------:|--------------:|----------------:| | `unicode-segmenter/grapheme` | 17.0.0 | ✔️ | 8,684 | 5,133 | 2,453 | 2,220 | 2,505 | -| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,492 | 5,781 | 2,738 | 2,450 | 2,800 | +| `unicode-segmenter/grapheme` (full*) | 17.0.0 | ✔️ | 10,494 | 5,777 | 2,732 | 2,435 | 2,796 | | `graphemer` | 15.0.0 | ✖️ | 410,435 | 95,104 | 15,752 | 10,660 | 15,911 | | `grapheme-splitter` | 10.0.0 | ✖️ | 122,254 | 23,682 | 7,852 | 4,802 | 6,753 | | `@formatjs/intl-segmenter`* | 17.0.0 | ✖️ | 268,301 | 176,759 | 45,988 | 31,701 | 45,370 | @@ -255,8 +255,8 @@ Since [Hermes doesn't support the `Intl.Segmenter` API](https://github.com/faceb | Name | Bytecode size | Bytecode size (gzip)* | |-------------------------------------|--------------:|----------------------:| -| `unicode-segmenter/grapheme` | 20,019 | 11,068 | -| `unicode-segmenter/grapheme` (full) | 20,224 | 11,206 | +| `unicode-segmenter/grapheme` | 20,015 | 11,075 | +| `unicode-segmenter/grapheme` (full) | 20,224 | 11,213 | | `graphemer` | 134,085 | 31,770 | | `grapheme-splitter` | 63,942 | 19,165 | | `@formatjs/intl-segmenter` | 329,547 | 136,751 | diff --git a/src/grapheme.js b/src/grapheme.js index 48e204a..874df02 100644 --- a/src/grapheme.js +++ b/src/grapheme.js @@ -350,7 +350,7 @@ export function countGraphemes(input) { st = nextState(st, catAfter, cp); if (boundary) count += 1; - cursor += cp > 0xFFFF ? 2 : 1; + cursor += cp > BMP_MAX ? 2 : 1; catBefore = catAfter; } From dfaf4274ac5382039fa3a2794ac48054a12e6db9 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Wed, 22 Jul 2026 20:13:39 +0900 Subject: [PATCH 7/7] remove outdated note --- src/grapheme.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/grapheme.js b/src/grapheme.js index 874df02..dec4434 100644 --- a/src/grapheme.js +++ b/src/grapheme.js @@ -313,16 +313,6 @@ export function* graphemeSegments(input) { /** * Count number of extended grapheme clusters in given text. * - * NOTE: - * - * This function is a small wrapper around {@link graphemeSegments}. - * - * If you call it more than once at a time, consider memoization - * or use {@link graphemeSegments} or {@link splitGraphemes} once instead - * - * Or if you need fast counting, use the standalone - * `unicode-segmenter/grapheme-counter` entry instead. - * * @param {string} input * @return {number} count of grapheme clusters */