From c34bbc34fe3b2fd7c5660253df84e76f854b226a Mon Sep 17 00:00:00 2001 From: Mary Date: Sat, 9 Dec 2023 08:57:03 +0700 Subject: [PATCH] refactor: grapheme count fast path --- app/api/richtext/composer.ts | 6 +++--- app/api/richtext/intl.ts | 36 +++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/app/api/richtext/composer.ts b/app/api/richtext/composer.ts index 2495fbd9..562090b1 100644 --- a/app/api/richtext/composer.ts +++ b/app/api/richtext/composer.ts @@ -3,7 +3,7 @@ import { XRPCError } from '@externdefs/bluesky-client/xrpc-utils'; import { multiagent } from '../globals/agent.ts'; -import { graphemeLen } from './intl.ts'; +import { asciiLen, graphemeLen } from './intl.ts'; import { toShortUrl } from './renderer.ts'; import type { Facet, LinkFeature, MentionFeature, TagFeature, UnresolvedMentionFeature } from './types.ts'; @@ -183,13 +183,13 @@ export const getRtText = (rt: PreliminaryRichText) => { export const getRtLength = (rt: PreliminaryRichText) => { const text = getRtText(rt); - return isAscii(text) ? text.length : graphemeLen(text); + return graphemeLen(text); }; const encoder = new TextEncoder(); const getUtf8Length = (str: string): number => { - return isAscii(str) ? str.length : encoder.encode(str).byteLength; + return asciiLen(str) ?? encoder.encode(str).byteLength; }; export const finalizeRt = async (uid: DID, rt: PreliminaryRichText) => { diff --git a/app/api/richtext/intl.ts b/app/api/richtext/intl.ts index 11d6300f..04b8883f 100644 --- a/app/api/richtext/intl.ts +++ b/app/api/richtext/intl.ts @@ -1,11 +1,33 @@ -export let graphemeLen: (text: string) => number; +var _graphemeLen: (text: string) => number; + +export const graphemeLen = (text: string) => { + var length = asciiLen(text); + + if (length === undefined) { + return _graphemeLen(text); + } + + return length; +}; + +export const asciiLen = (str: string) => { + for (var idx = 0, len = str.length; idx < len; idx++) { + const char = str.charCodeAt(idx); + + if (char > 127) { + return undefined; + } + } + + return len; +}; if (Intl.Segmenter) { - const segmenter = new Intl.Segmenter(); + var segmenter = new Intl.Segmenter(); - graphemeLen = (text) => { - const iterator = segmenter.segment(text)[Symbol.iterator](); - let count = 0; + _graphemeLen = (text) => { + var iterator = segmenter.segment(text)[Symbol.iterator](); + var count = 0; while (!iterator.next().done) { count++; @@ -16,6 +38,6 @@ if (Intl.Segmenter) { } else { console.log('Intl.Segmenter API not available, falling back to polyfill...'); - const { countGraphemes } = await import('./graphemer.ts'); - graphemeLen = countGraphemes; + var { countGraphemes } = await import('./graphemer.ts'); + _graphemeLen = countGraphemes; }