gpt-tokenizer 4.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/BytePairEncodingCore.js +75 -31
- package/cjs/BytePairEncodingCore.js.map +1 -1
- package/cjs/GptEncoding.d.ts +2 -2
- package/cjs/encoding/cl100k_base.d.ts +1 -1
- package/cjs/encoding/o200k_base.d.ts +1 -1
- package/cjs/encoding/o200k_harmony.d.ts +1 -1
- package/cjs/encoding/p50k_edit.d.ts +1 -1
- package/cjs/encodingParams/constants.js +3 -3
- package/cjs/encodingParams/constants.js.map +1 -1
- package/cjs/model/chat-latest.d.ts +1 -1
- package/cjs/model/chatgpt-4o-latest.d.ts +1 -1
- package/cjs/model/codex-mini-latest.d.ts +1 -1
- package/cjs/model/computer-use-preview-2025-03-11.d.ts +1 -1
- package/cjs/model/computer-use-preview.d.ts +1 -1
- package/cjs/model/daybreak-blue-latest.d.ts +1 -1
- package/cjs/model/daybreak-red-latest.d.ts +1 -1
- package/cjs/model/gpt-3.5-0301.d.ts +1 -1
- package/cjs/model/gpt-3.5-turbo-0125.d.ts +1 -1
- package/cjs/model/gpt-3.5-turbo-0613.d.ts +1 -1
- package/cjs/model/gpt-3.5-turbo-1106.d.ts +1 -1
- package/cjs/model/gpt-3.5-turbo-16k-0613.d.ts +1 -1
- package/cjs/model/gpt-3.5-turbo-instruct.d.ts +1 -1
- package/cjs/model/gpt-3.5-turbo.d.ts +1 -1
- package/cjs/model/gpt-3.5.d.ts +1 -1
- package/cjs/model/gpt-4-0125-preview.d.ts +1 -1
- package/cjs/model/gpt-4-0314.d.ts +1 -1
- package/cjs/model/gpt-4-0613.d.ts +1 -1
- package/cjs/model/gpt-4-1106-preview.d.ts +1 -1
- package/cjs/model/gpt-4-1106-vision-preview.d.ts +1 -1
- package/cjs/model/gpt-4-32k.d.ts +1 -1
- package/cjs/model/gpt-4-turbo-2024-04-09.d.ts +1 -1
- package/cjs/model/gpt-4-turbo-preview.d.ts +1 -1
- package/cjs/model/gpt-4-turbo.d.ts +1 -1
- package/cjs/model/gpt-4.1-2025-04-14.d.ts +1 -1
- package/cjs/model/gpt-4.1-mini-2025-04-14.d.ts +1 -1
- package/cjs/model/gpt-4.1-mini.d.ts +1 -1
- package/cjs/model/gpt-4.1-nano-2025-04-14.d.ts +1 -1
- package/cjs/model/gpt-4.1-nano.d.ts +1 -1
- package/cjs/model/gpt-4.1.d.ts +1 -1
- package/cjs/model/gpt-4.5-preview-2025-02-27.d.ts +1 -1
- package/cjs/model/gpt-4.5-preview.d.ts +1 -1
- package/cjs/model/gpt-4.d.ts +1 -1
- package/cjs/model/gpt-4o-2024-05-13.d.ts +1 -1
- package/cjs/model/gpt-4o-2024-08-06.d.ts +1 -1
- package/cjs/model/gpt-4o-2024-11-20.d.ts +1 -1
- package/cjs/model/gpt-4o-audio-preview-2024-10-01.d.ts +1 -1
- package/cjs/model/gpt-4o-audio-preview-2024-12-17.d.ts +1 -1
- package/cjs/model/gpt-4o-audio-preview-2025-06-03.d.ts +1 -1
- package/cjs/model/gpt-4o-audio-preview.d.ts +1 -1
- package/cjs/model/gpt-4o-mini-2024-07-18.d.ts +1 -1
- package/cjs/model/gpt-4o-mini-audio-preview-2024-12-17.d.ts +1 -1
- package/cjs/model/gpt-4o-mini-audio-preview.d.ts +1 -1
- package/cjs/model/gpt-4o-mini-search-preview-2025-03-11.d.ts +1 -1
- package/cjs/model/gpt-4o-mini-search-preview.d.ts +1 -1
- package/cjs/model/gpt-4o-mini.d.ts +1 -1
- package/cjs/model/gpt-4o-search-preview-2025-03-11.d.ts +1 -1
- package/cjs/model/gpt-4o-search-preview.d.ts +1 -1
- package/cjs/model/gpt-4o.d.ts +1 -1
- package/cjs/model/gpt-5-2025-08-07.d.ts +1 -1
- package/cjs/model/gpt-5-chat-latest.d.ts +1 -1
- package/cjs/model/gpt-5-codex.d.ts +1 -1
- package/cjs/model/gpt-5-mini-2025-08-07.d.ts +1 -1
- package/cjs/model/gpt-5-mini.d.ts +1 -1
- package/cjs/model/gpt-5-nano-2025-08-07.d.ts +1 -1
- package/cjs/model/gpt-5-nano.d.ts +1 -1
- package/cjs/model/gpt-5-pro-2025-10-06.d.ts +1 -1
- package/cjs/model/gpt-5-pro.d.ts +1 -1
- package/cjs/model/gpt-5.1-2025-11-13.d.ts +1 -1
- package/cjs/model/gpt-5.1-chat-latest.d.ts +1 -1
- package/cjs/model/gpt-5.1-codex-max.d.ts +1 -1
- package/cjs/model/gpt-5.1-codex-mini.d.ts +1 -1
- package/cjs/model/gpt-5.1-codex.d.ts +1 -1
- package/cjs/model/gpt-5.1.d.ts +1 -1
- package/cjs/model/gpt-5.2-2025-12-11.d.ts +1 -1
- package/cjs/model/gpt-5.2-chat-latest.d.ts +1 -1
- package/cjs/model/gpt-5.2-codex.d.ts +1 -1
- package/cjs/model/gpt-5.2-pro-2025-12-11.d.ts +1 -1
- package/cjs/model/gpt-5.2-pro.d.ts +1 -1
- package/cjs/model/gpt-5.2.d.ts +1 -1
- package/cjs/model/gpt-5.3-chat-latest.d.ts +1 -1
- package/cjs/model/gpt-5.3-codex.d.ts +1 -1
- package/cjs/model/gpt-5.4-2026-03-05.d.ts +1 -1
- package/cjs/model/gpt-5.4-mini-2026-03-17.d.ts +1 -1
- package/cjs/model/gpt-5.4-mini.d.ts +1 -1
- package/cjs/model/gpt-5.4-nano-2026-03-17.d.ts +1 -1
- package/cjs/model/gpt-5.4-nano.d.ts +1 -1
- package/cjs/model/gpt-5.4-pro-2026-03-05.d.ts +1 -1
- package/cjs/model/gpt-5.4-pro.d.ts +1 -1
- package/cjs/model/gpt-5.4.d.ts +1 -1
- package/cjs/model/gpt-5.5-2026-04-23.d.ts +1 -1
- package/cjs/model/gpt-5.5-pro-2026-04-23.d.ts +1 -1
- package/cjs/model/gpt-5.5-pro.d.ts +1 -1
- package/cjs/model/gpt-5.5.d.ts +1 -1
- package/cjs/model/gpt-5.6-cyber.d.ts +1 -1
- package/cjs/model/gpt-5.6-luna.d.ts +1 -1
- package/cjs/model/gpt-5.6-sol.d.ts +1 -1
- package/cjs/model/gpt-5.6-terra.d.ts +1 -1
- package/cjs/model/gpt-5.d.ts +1 -1
- package/cjs/model/gpt-audio-1.5.d.ts +1 -1
- package/cjs/model/gpt-audio-2025-08-28.d.ts +1 -1
- package/cjs/model/gpt-audio-mini-2025-10-06.d.ts +1 -1
- package/cjs/model/gpt-audio-mini-2025-12-15.d.ts +1 -1
- package/cjs/model/gpt-audio-mini.d.ts +1 -1
- package/cjs/model/gpt-audio.d.ts +1 -1
- package/cjs/model/gpt-image-1.d.ts +1 -1
- package/cjs/model/gpt-oss-120b.d.ts +1 -1
- package/cjs/model/gpt-oss-20b.d.ts +1 -1
- package/cjs/model/o1-2024-12-17.d.ts +1 -1
- package/cjs/model/o1-mini-2024-09-12.d.ts +1 -1
- package/cjs/model/o1-mini.d.ts +1 -1
- package/cjs/model/o1-preview-2024-09-12.d.ts +1 -1
- package/cjs/model/o1-preview.d.ts +1 -1
- package/cjs/model/o1-pro-2025-03-19.d.ts +1 -1
- package/cjs/model/o1-pro.d.ts +1 -1
- package/cjs/model/o1.d.ts +1 -1
- package/cjs/model/o3-2025-04-16.d.ts +1 -1
- package/cjs/model/o3-deep-research-2025-06-26.d.ts +1 -1
- package/cjs/model/o3-deep-research.d.ts +1 -1
- package/cjs/model/o3-mini-2025-01-31.d.ts +1 -1
- package/cjs/model/o3-mini.d.ts +1 -1
- package/cjs/model/o3-pro-2025-06-10.d.ts +1 -1
- package/cjs/model/o3-pro.d.ts +1 -1
- package/cjs/model/o3.d.ts +1 -1
- package/cjs/model/o4-mini-2025-04-16.d.ts +1 -1
- package/cjs/model/o4-mini-deep-research-2025-06-26.d.ts +1 -1
- package/cjs/model/o4-mini-deep-research.d.ts +1 -1
- package/cjs/model/o4-mini.d.ts +1 -1
- package/cjs/utfUtil.d.ts +2 -1
- package/cjs/utfUtil.js +8 -1
- package/cjs/utfUtil.js.map +1 -1
- package/esm/BytePairEncodingCore.js +76 -32
- package/esm/BytePairEncodingCore.js.map +1 -1
- package/esm/encodingParams/constants.js +3 -3
- package/esm/encodingParams/constants.js.map +1 -1
- package/esm/utfUtil.d.ts +2 -1
- package/esm/utfUtil.js +8 -2
- package/esm/utfUtil.js.map +1 -1
- package/package.json +1 -1
- package/src/BytePairEncodingCore.test.ts +13 -0
- package/src/BytePairEncodingCore.ts +107 -69
- package/src/encodingParams/constants.ts +7 -3
- package/src/unicodeWhiteSpace.test.ts +247 -0
- package/src/utfUtil.ts +12 -1
package/cjs/utfUtil.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utfUtil.js","names":[],"sources":["../src/utfUtil.ts"],"sourcesContent":["export const isAscii = (codePoint: number) => codePoint <= 0x7f\n\nconst HIGH_SURROGATE_START = 55_296\nconst HIGH_SURROGATE_END = 56_319\n\nexport function endsWithIncompleteUtfPairSurrogate(string: string): boolean {\n if (string.length === 0) return false\n // Check if the last character is a high surrogate\n const lastCharCode = string.charCodeAt(string.length - 1)\n return (\n lastCharCode >= HIGH_SURROGATE_START && lastCharCode <= HIGH_SURROGATE_END\n )\n}\n\nfunction isValidUTF8(bytes: Uint8Array): boolean {\n let i = 0\n while (i < bytes.length) {\n const byte1 = bytes[i]!\n\n let numBytes = 0\n let codePoint = 0\n\n // Determine the number of bytes in the current UTF-8 character\n if (byte1 <= 0x7f) {\n // 1-byte character (ASCII)\n numBytes = 1\n codePoint = byte1\n } else if ((byte1 & 0xe0) === 0xc0) {\n // 2-byte character\n numBytes = 2\n codePoint = byte1 & 0x1f\n if (byte1 <= 0xc1) return false // Overlong encoding not allowed\n } else if ((byte1 & 0xf0) === 0xe0) {\n // 3-byte character\n numBytes = 3\n codePoint = byte1 & 0x0f\n } else if ((byte1 & 0xf8) === 0xf0) {\n // 4-byte character\n numBytes = 4\n codePoint = byte1 & 0x07\n if (byte1 > 0xf4) return false // Code points above U+10FFFF not allowed\n } else {\n // Invalid first byte of UTF-8 character\n return false\n }\n\n // Ensure there are enough continuation bytes\n if (i + numBytes > bytes.length) return false\n\n // Process the continuation bytes\n for (let j = 1; j < numBytes; j++) {\n const byte = bytes[i + j]\n if (byte === undefined || (byte & 0xc0) !== 0x80) return false // Continuation bytes must start with '10'\n codePoint = (codePoint << 6) | (byte & 0x3f)\n }\n\n // Check for overlong encodings\n if (numBytes === 2 && codePoint < 0x80) return false // Overlong 2-byte sequence\n if (numBytes === 3 && codePoint < 2_048) return false // Overlong 3-byte sequence\n if (numBytes === 4 && codePoint < 65_536) return false // Overlong 4-byte sequence\n\n // Check for surrogate halves (U+D800 to U+DFFF)\n if (codePoint >= 55_296 && codePoint <= 57_343) return false\n\n // Check for code points above U+10FFFF\n if (codePoint > 1_114_111) return false\n\n // Move to the next character\n i += numBytes\n }\n return true\n}\n\nconst textDecoder = new TextDecoder('utf8', { fatal: false })\n\nexport function tryConvertToString(arr: Uint8Array): string | undefined {\n if (!isValidUTF8(arr)) {\n return undefined\n }\n return textDecoder.decode(arr)\n}\n\n// Helper function to compare two Uint8Arrays lexicographically\nexport function compareUint8Arrays(a: Uint8Array, b: Uint8Array): number {\n const len = Math.min(a.length, b.length)\n for (let i = 0; i < len; i++) {\n if (a[i] !== b[i]) {\n return a[i]! - b[i]!\n }\n }\n return a.length - b.length\n}\n"],"mappings":";;AAAA,MAAa,WAAW,cAAsB,aAAa;AAE3D,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAE3B,SAAgB,mCAAmC,QAAyB;CAC1E,IAAI,OAAO,WAAW,GAAG,OAAO;CAEhC,MAAM,eAAe,OAAO,WAAW,OAAO,SAAS,CAAC;CACxD,OACE,gBAAgB,wBAAwB,gBAAgB;AAE5D;AAEA,SAAS,YAAY,OAA4B;CAC/C,IAAI,IAAI;CACR,OAAO,IAAI,MAAM,QAAQ;EACvB,MAAM,QAAQ,MAAM;EAEpB,IAAI,WAAW;EACf,IAAI,YAAY;EAGhB,IAAI,SAAS,KAAM;GAEjB,WAAW;GACX,YAAY;EACd,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;GACpB,IAAI,SAAS,KAAM,OAAO;EAC5B,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;EACtB,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;GACpB,IAAI,QAAQ,KAAM,OAAO;EAC3B,OAEE,OAAO;EAIT,IAAI,IAAI,WAAW,MAAM,QAAQ,OAAO;EAGxC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;GACjC,MAAM,OAAO,MAAM,IAAI;GACvB,IAAI,SAAS,KAAA,MAAc,OAAO,SAAU,KAAM,OAAO;GACzD,YAAa,aAAa,IAAM,OAAO;EACzC;EAGA,IAAI,aAAa,KAAK,YAAY,KAAM,OAAO;EAC/C,IAAI,aAAa,KAAK,YAAY,MAAO,OAAO;EAChD,IAAI,aAAa,KAAK,YAAY,OAAQ,OAAO;EAGjD,IAAI,aAAa,SAAU,aAAa,OAAQ,OAAO;EAGvD,IAAI,YAAY,SAAW,OAAO;EAGlC,KAAK;CACP;CACA,OAAO;AACT;AAEA,MAAM,cAAc,IAAI,YAAY,QAAQ,
|
|
1
|
+
{"version":3,"file":"utfUtil.js","names":[],"sources":["../src/utfUtil.ts"],"sourcesContent":["export const isAscii = (codePoint: number) => codePoint <= 0x7f\n\nconst HIGH_SURROGATE_START = 55_296\nconst HIGH_SURROGATE_END = 56_319\n\nexport function endsWithIncompleteUtfPairSurrogate(string: string): boolean {\n if (string.length === 0) return false\n // Check if the last character is a high surrogate\n const lastCharCode = string.charCodeAt(string.length - 1)\n return (\n lastCharCode >= HIGH_SURROGATE_START && lastCharCode <= HIGH_SURROGATE_END\n )\n}\n\nfunction isValidUTF8(bytes: Uint8Array): boolean {\n let i = 0\n while (i < bytes.length) {\n const byte1 = bytes[i]!\n\n let numBytes = 0\n let codePoint = 0\n\n // Determine the number of bytes in the current UTF-8 character\n if (byte1 <= 0x7f) {\n // 1-byte character (ASCII)\n numBytes = 1\n codePoint = byte1\n } else if ((byte1 & 0xe0) === 0xc0) {\n // 2-byte character\n numBytes = 2\n codePoint = byte1 & 0x1f\n if (byte1 <= 0xc1) return false // Overlong encoding not allowed\n } else if ((byte1 & 0xf0) === 0xe0) {\n // 3-byte character\n numBytes = 3\n codePoint = byte1 & 0x0f\n } else if ((byte1 & 0xf8) === 0xf0) {\n // 4-byte character\n numBytes = 4\n codePoint = byte1 & 0x07\n if (byte1 > 0xf4) return false // Code points above U+10FFFF not allowed\n } else {\n // Invalid first byte of UTF-8 character\n return false\n }\n\n // Ensure there are enough continuation bytes\n if (i + numBytes > bytes.length) return false\n\n // Process the continuation bytes\n for (let j = 1; j < numBytes; j++) {\n const byte = bytes[i + j]\n if (byte === undefined || (byte & 0xc0) !== 0x80) return false // Continuation bytes must start with '10'\n codePoint = (codePoint << 6) | (byte & 0x3f)\n }\n\n // Check for overlong encodings\n if (numBytes === 2 && codePoint < 0x80) return false // Overlong 2-byte sequence\n if (numBytes === 3 && codePoint < 2_048) return false // Overlong 3-byte sequence\n if (numBytes === 4 && codePoint < 65_536) return false // Overlong 4-byte sequence\n\n // Check for surrogate halves (U+D800 to U+DFFF)\n if (codePoint >= 55_296 && codePoint <= 57_343) return false\n\n // Check for code points above U+10FFFF\n if (codePoint > 1_114_111) return false\n\n // Move to the next character\n i += numBytes\n }\n return true\n}\n\nexport function startsWithByteOrderMark(bytes: Uint8Array): boolean {\n return (\n bytes.length >= 3 &&\n bytes[0] === 0xef &&\n bytes[1] === 0xbb &&\n bytes[2] === 0xbf\n )\n}\n\n// `ignoreBOM: true` keeps a leading U+FEFF in the output instead of silently\n// stripping it, so the bytes EF BB BF map to U+FEFF rather than to an empty string.\nconst textDecoder = new TextDecoder('utf8', { fatal: false, ignoreBOM: true })\n\nexport function tryConvertToString(arr: Uint8Array): string | undefined {\n if (!isValidUTF8(arr)) {\n return undefined\n }\n return textDecoder.decode(arr)\n}\n\n// Helper function to compare two Uint8Arrays lexicographically\nexport function compareUint8Arrays(a: Uint8Array, b: Uint8Array): number {\n const len = Math.min(a.length, b.length)\n for (let i = 0; i < len; i++) {\n if (a[i] !== b[i]) {\n return a[i]! - b[i]!\n }\n }\n return a.length - b.length\n}\n"],"mappings":";;AAAA,MAAa,WAAW,cAAsB,aAAa;AAE3D,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAE3B,SAAgB,mCAAmC,QAAyB;CAC1E,IAAI,OAAO,WAAW,GAAG,OAAO;CAEhC,MAAM,eAAe,OAAO,WAAW,OAAO,SAAS,CAAC;CACxD,OACE,gBAAgB,wBAAwB,gBAAgB;AAE5D;AAEA,SAAS,YAAY,OAA4B;CAC/C,IAAI,IAAI;CACR,OAAO,IAAI,MAAM,QAAQ;EACvB,MAAM,QAAQ,MAAM;EAEpB,IAAI,WAAW;EACf,IAAI,YAAY;EAGhB,IAAI,SAAS,KAAM;GAEjB,WAAW;GACX,YAAY;EACd,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;GACpB,IAAI,SAAS,KAAM,OAAO;EAC5B,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;EACtB,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;GACpB,IAAI,QAAQ,KAAM,OAAO;EAC3B,OAEE,OAAO;EAIT,IAAI,IAAI,WAAW,MAAM,QAAQ,OAAO;EAGxC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;GACjC,MAAM,OAAO,MAAM,IAAI;GACvB,IAAI,SAAS,KAAA,MAAc,OAAO,SAAU,KAAM,OAAO;GACzD,YAAa,aAAa,IAAM,OAAO;EACzC;EAGA,IAAI,aAAa,KAAK,YAAY,KAAM,OAAO;EAC/C,IAAI,aAAa,KAAK,YAAY,MAAO,OAAO;EAChD,IAAI,aAAa,KAAK,YAAY,OAAQ,OAAO;EAGjD,IAAI,aAAa,SAAU,aAAa,OAAQ,OAAO;EAGvD,IAAI,YAAY,SAAW,OAAO;EAGlC,KAAK;CACP;CACA,OAAO;AACT;AAEA,SAAgB,wBAAwB,OAA4B;CAClE,OACE,MAAM,UAAU,KAChB,MAAM,OAAO,OACb,MAAM,OAAO,OACb,MAAM,OAAO;AAEjB;AAIA,MAAM,cAAc,IAAI,YAAY,QAAQ;CAAE,OAAO;CAAO,WAAW;AAAK,CAAC;AAE7E,SAAgB,mBAAmB,KAAqC;CACtE,IAAI,CAAC,YAAY,GAAG,GAClB;CAEF,OAAO,YAAY,OAAO,GAAG;AAC/B;AAGA,SAAgB,mBAAmB,GAAe,GAAuB;CACvE,MAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CACvC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KACvB,IAAI,EAAE,OAAO,EAAE,IACb,OAAO,EAAE,KAAM,EAAE;CAGrB,OAAO,EAAE,SAAS,EAAE;AACtB"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DEFAULT_MERGE_CACHE_SIZE } from "./constants.js";
|
|
2
|
-
import { compareUint8Arrays, isAscii, tryConvertToString } from "./utfUtil.js";
|
|
2
|
+
import { compareUint8Arrays, isAscii, startsWithByteOrderMark, tryConvertToString } from "./utfUtil.js";
|
|
3
3
|
import { escapeRegExp } from "./util.js";
|
|
4
4
|
//#region src/BytePairEncodingCore.ts
|
|
5
5
|
const emptyBuffer = /* @__PURE__ */ new Uint8Array(0);
|
|
6
|
-
const decoder = new TextDecoder("utf8");
|
|
6
|
+
const decoder = new TextDecoder("utf8", { ignoreBOM: true });
|
|
7
7
|
var BytePairEncodingCore = class {
|
|
8
8
|
mergeableBytePairRankCount;
|
|
9
9
|
/**
|
|
@@ -42,6 +42,10 @@ var BytePairEncodingCore = class {
|
|
|
42
42
|
const byteArray = new Uint8Array(value);
|
|
43
43
|
binaryLookup.push([byteArray, rank]);
|
|
44
44
|
this.bytePairNonUtfRankDecoder.set(rank, byteArray);
|
|
45
|
+
if (startsWithByteOrderMark(byteArray)) {
|
|
46
|
+
const asString = tryConvertToString(byteArray);
|
|
47
|
+
if (asString !== void 0) this.bytePairStringRankEncoder.set(asString, rank);
|
|
48
|
+
}
|
|
45
49
|
});
|
|
46
50
|
this.bytePairNonUtfSortedEncoder = binaryLookup.sort((a, b) => compareUint8Arrays(a[0], b[0]));
|
|
47
51
|
this.specialTokensEncoder = specialTokensEncoder ?? /* @__PURE__ */ new Map();
|
|
@@ -258,41 +262,81 @@ var BytePairEncodingCore = class {
|
|
|
258
262
|
return result;
|
|
259
263
|
}
|
|
260
264
|
bytePairMerge(piece) {
|
|
261
|
-
const
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
const { length } = piece;
|
|
266
|
+
const next = new Int32Array(length + 1);
|
|
267
|
+
const previous = new Int32Array(length + 1);
|
|
268
|
+
const pairRanks = new Float64Array(length + 1);
|
|
269
|
+
const live = new Uint8Array(length + 1);
|
|
270
|
+
const getPairRank = (startIndex) => {
|
|
271
|
+
const middle = next[startIndex];
|
|
272
|
+
if (middle >= length) return Number.POSITIVE_INFINITY;
|
|
273
|
+
return this.getBpeRankFromBytes(piece.subarray(startIndex, next[middle])) ?? Number.POSITIVE_INFINITY;
|
|
274
|
+
};
|
|
275
|
+
const heap = [];
|
|
276
|
+
const isLower = (a, b) => heap[a] < heap[b] || heap[a] === heap[b] && heap[a + 1] < heap[b + 1];
|
|
277
|
+
const swap = (a, b) => {
|
|
278
|
+
const rank = heap[a];
|
|
279
|
+
const startIndex = heap[a + 1];
|
|
280
|
+
heap[a] = heap[b];
|
|
281
|
+
heap[a + 1] = heap[b + 1];
|
|
282
|
+
heap[b] = rank;
|
|
283
|
+
heap[b + 1] = startIndex;
|
|
267
284
|
};
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
285
|
+
const push = (rank, startIndex) => {
|
|
286
|
+
heap.push(rank, startIndex);
|
|
287
|
+
let index = heap.length - 2;
|
|
288
|
+
while (index > 0) {
|
|
289
|
+
const parent = (index >> 1) - 1 >> 1 << 1;
|
|
290
|
+
if (!isLower(index, parent)) break;
|
|
291
|
+
swap(index, parent);
|
|
292
|
+
index = parent;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
const pop = () => {
|
|
296
|
+
const last = heap.length - 2;
|
|
297
|
+
swap(0, last);
|
|
298
|
+
const rank = heap[last];
|
|
299
|
+
const startIndex = heap[last + 1];
|
|
300
|
+
heap.length = last;
|
|
301
|
+
let index = 0;
|
|
302
|
+
while (true) {
|
|
303
|
+
const left = index * 2 + 2;
|
|
304
|
+
const right = left + 2;
|
|
305
|
+
let lowest = index;
|
|
306
|
+
if (left < heap.length && isLower(left, lowest)) lowest = left;
|
|
307
|
+
if (right < heap.length && isLower(right, lowest)) lowest = right;
|
|
308
|
+
if (lowest === index) break;
|
|
309
|
+
swap(index, lowest);
|
|
310
|
+
index = lowest;
|
|
311
|
+
}
|
|
312
|
+
return [rank, startIndex];
|
|
313
|
+
};
|
|
314
|
+
for (let i = 0; i <= length; i++) {
|
|
315
|
+
next[i] = i + 1;
|
|
316
|
+
previous[i] = i - 1;
|
|
317
|
+
live[i] = 1;
|
|
272
318
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
319
|
+
for (let i = 0; i < length - 1; i++) {
|
|
320
|
+
pairRanks[i] = getPairRank(i);
|
|
321
|
+
if (pairRanks[i] !== Number.POSITIVE_INFINITY) push(pairRanks[i], i);
|
|
322
|
+
}
|
|
323
|
+
while (heap.length > 0) {
|
|
324
|
+
const [rank, startIndex] = pop();
|
|
325
|
+
if (!live[startIndex] || pairRanks[startIndex] !== rank) continue;
|
|
326
|
+
const merged = next[startIndex];
|
|
327
|
+
live[merged] = 0;
|
|
328
|
+
next[startIndex] = next[merged];
|
|
329
|
+
previous[next[merged]] = startIndex;
|
|
330
|
+
pairRanks[startIndex] = getPairRank(startIndex);
|
|
331
|
+
if (pairRanks[startIndex] !== Number.POSITIVE_INFINITY) push(pairRanks[startIndex], startIndex);
|
|
332
|
+
const before = previous[startIndex];
|
|
333
|
+
if (before >= 0) {
|
|
334
|
+
pairRanks[before] = getPairRank(before);
|
|
335
|
+
if (pairRanks[before] !== Number.POSITIVE_INFINITY) push(pairRanks[before], before);
|
|
282
336
|
}
|
|
283
|
-
if (lowestRank === Number.POSITIVE_INFINITY || lowestPartitionIndex === -1) break;
|
|
284
|
-
starts.splice(lowestPartitionIndex + 1, 1);
|
|
285
|
-
ranks.splice(lowestPartitionIndex, 1);
|
|
286
|
-
ranks[lowestPartitionIndex] = getRank(lowestPartitionIndex);
|
|
287
|
-
if (lowestPartitionIndex > 0) ranks[lowestPartitionIndex - 1] = getRank(lowestPartitionIndex - 1);
|
|
288
337
|
}
|
|
289
338
|
const output = [];
|
|
290
|
-
for (let i = 0; i <
|
|
291
|
-
const pairStart = starts[i];
|
|
292
|
-
const pairEnd = starts[i + 1];
|
|
293
|
-
const bpeValue = this.getBpeRankFromBytesOrThrow(piece.subarray(pairStart, pairEnd));
|
|
294
|
-
output.push(bpeValue);
|
|
295
|
-
}
|
|
339
|
+
for (let i = 0; i < length; i = next[i]) output.push(this.getBpeRankFromBytesOrThrow(piece.subarray(i, next[i])));
|
|
296
340
|
return output;
|
|
297
341
|
}
|
|
298
342
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BytePairEncodingCore.js","names":[],"sources":["../src/BytePairEncodingCore.ts"],"sourcesContent":["import { DEFAULT_MERGE_CACHE_SIZE } from './constants.js'\nimport { compareUint8Arrays, isAscii, tryConvertToString } from './utfUtil.js'\nimport { escapeRegExp } from './util.js'\n\nexport type RawBytePairRanks = readonly (string | readonly number[])[]\n\nexport interface BytePairEncodingConfig {\n bytePairRankDecoder: RawBytePairRanks\n specialTokensEncoder?: Map<string, number>\n tokenSplitRegex: RegExp\n /**\n * LRU cache for merged tokens pairs.\n * Increasing this value should make encoding similar strings faster,\n * but will consume more memory.\n * @default 100000\n */\n mergeCacheSize?: number\n}\n\nconst emptyBuffer = new Uint8Array(0)\n\nexport const decoder = new TextDecoder('utf8')\n\nexport class BytePairEncodingCore {\n readonly mergeableBytePairRankCount: number\n /**\n * an array where the index is the BPE rank,\n * and the value is the string or the array of bytes that it decodes to\n * it may contain holes if token is unused\n */\n private bytePairRankDecoder: RawBytePairRanks\n private bytePairNonUtfRankDecoder = new Map<number, Uint8Array>()\n private bytePairNonUtfSortedEncoder: readonly [Uint8Array, number][]\n /**\n * a reverse map of the bytePairRankDecoder,\n * where the key is the string and the value is the rank\n * values that cannot be represented as a string are present in `bytePairNonUtfSortedEncoder`\n */\n private bytePairStringRankEncoder: Map<string, number>\n private tokenSplitRegex: RegExp\n private specialTokensEncoder: Map<string, number>\n private specialTokensDecoder: Map<number, string>\n private specialTokenPatternRegex: RegExp\n private textEncoder = new TextEncoder()\n private mergeCache?: Map<string, number[]>\n private mergeCacheSize: number\n\n constructor({\n bytePairRankDecoder,\n specialTokensEncoder,\n tokenSplitRegex,\n mergeCacheSize = DEFAULT_MERGE_CACHE_SIZE,\n }: BytePairEncodingConfig) {\n this.bytePairRankDecoder = bytePairRankDecoder\n this.bytePairStringRankEncoder = new Map<string, number>()\n this.mergeCacheSize = mergeCacheSize\n if (mergeCacheSize > 0) {\n this.mergeCache = new Map()\n }\n\n // size without array holes (which may be present in the encoder)\n this.mergeableBytePairRankCount = Object.keys(bytePairRankDecoder).length\n const binaryLookup: [Uint8Array, number][] = []\n // forEach skips array holes:\n bytePairRankDecoder.forEach((value, rank) => {\n if (typeof value === 'string') {\n this.bytePairStringRankEncoder.set(value, rank)\n return\n }\n const byteArray = new Uint8Array(value)\n binaryLookup.push([byteArray, rank])\n this.bytePairNonUtfRankDecoder.set(rank, byteArray)\n })\n this.bytePairNonUtfSortedEncoder = binaryLookup.sort((a, b) =>\n compareUint8Arrays(a[0], b[0]),\n )\n this.specialTokensEncoder =\n specialTokensEncoder ?? new Map<string, number>()\n this.specialTokensDecoder = specialTokensEncoder\n ? new Map([...specialTokensEncoder].map(([key, value]) => [value, key]))\n : new Map<number, string>()\n this.tokenSplitRegex = tokenSplitRegex\n\n const escapedSpecialTokens = [...this.specialTokensEncoder.keys()].map(\n escapeRegExp,\n )\n const allSpecialTokensRegex = escapedSpecialTokens.join('|')\n try {\n this.specialTokenPatternRegex = new RegExp(allSpecialTokensRegex, 'y')\n } catch {\n throw new Error('Invalid regular expression pattern.')\n }\n }\n\n setMergeCacheSize(newSize: number): void {\n if (this.mergeCacheSize === 0 && newSize > 0) {\n this.mergeCache = new Map()\n }\n this.mergeCacheSize = newSize\n if (newSize === 0) {\n this.mergeCache = undefined\n }\n }\n\n clearMergeCache(): void {\n this.mergeCache?.clear()\n }\n\n *encodeNativeGenerator(\n text: string,\n allowedSpecial?: Set<string>,\n ): Generator<number[], number, undefined> {\n let startIndex = 0\n let lastTokenLength = 0\n\n while (true) {\n const nextSpecialMatch = this.findNextSpecialToken(\n text,\n allowedSpecial,\n startIndex,\n )\n const nextSpecialStartIndex = nextSpecialMatch?.[0]\n\n const endIndex = nextSpecialStartIndex ?? text.length\n\n const textBeforeSpecial =\n startIndex === 0 && endIndex === text.length\n ? text\n : text.slice(startIndex, endIndex)\n\n for (const [match] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {\n const token = this.getBpeRankFromString(match)\n if (token !== undefined) {\n lastTokenLength = 1\n yield [token]\n\n continue\n }\n\n const tokens = this.bytePairEncode(match)\n lastTokenLength = tokens.length\n yield tokens\n }\n\n if (nextSpecialStartIndex !== undefined) {\n const specialToken = nextSpecialMatch![1]\n const specialTokenValue = this.specialTokensEncoder.get(specialToken)\n if (specialTokenValue === undefined) {\n throw new Error(\n `Special token \"${specialToken}\" is not in the special token encoder.`,\n )\n }\n yield [specialTokenValue]\n startIndex = nextSpecialStartIndex + specialToken.length\n lastTokenLength = 1\n } else {\n break\n }\n }\n\n return lastTokenLength\n }\n\n encodeNative(text: string, allowedSpecial?: Set<string>): number[] {\n let startIndex = 0\n const tokensArray: number[] = [] // Flat list to collect the tokens\n\n while (true) {\n const nextSpecialMatch = this.findNextSpecialToken(\n text,\n allowedSpecial,\n startIndex,\n )\n const nextSpecialStartIndex = nextSpecialMatch?.[0]\n\n const endIndex = nextSpecialStartIndex ?? text.length\n\n const textBeforeSpecial =\n startIndex === 0 && endIndex === text.length\n ? text\n : text.slice(startIndex, endIndex)\n\n for (const [match] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {\n const token = this.getBpeRankFromString(match)\n if (token !== undefined) {\n tokensArray.push(token)\n\n continue\n }\n\n const tokens = this.bytePairEncode(match)\n tokensArray.push(...tokens)\n }\n\n if (nextSpecialStartIndex !== undefined) {\n const specialToken = nextSpecialMatch![1]\n const specialTokenValue = this.specialTokensEncoder.get(specialToken)\n if (specialTokenValue === undefined) {\n throw new Error(\n `Special token \"${specialToken}\" is not in the special token encoder.`,\n )\n }\n tokensArray.push(specialTokenValue)\n startIndex = nextSpecialStartIndex + specialToken.length\n } else {\n break\n }\n }\n\n return tokensArray\n }\n\n countNative(text: string, allowedSpecial?: Set<string>): number {\n let startIndex = 0\n let tokensCount = 0\n\n while (true) {\n const nextSpecialMatch = this.findNextSpecialToken(\n text,\n allowedSpecial,\n startIndex,\n )\n const nextSpecialStartIndex = nextSpecialMatch?.[0]\n\n const endIndex = nextSpecialStartIndex ?? text.length\n\n const textBeforeSpecial =\n startIndex === 0 && endIndex === text.length\n ? text\n : text.slice(startIndex, endIndex)\n\n for (const [match] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {\n const token = this.getBpeRankFromString(match)\n if (token !== undefined) {\n tokensCount++\n\n continue\n }\n\n const tokens = this.bytePairEncode(match)\n tokensCount += tokens.length\n }\n\n if (nextSpecialStartIndex !== undefined) {\n const specialToken = nextSpecialMatch![1]\n const specialTokenValue = this.specialTokensEncoder.get(specialToken)\n if (specialTokenValue === undefined) {\n throw new Error(\n `Special token \"${specialToken}\" is not in the special token encoder.`,\n )\n }\n tokensCount++\n startIndex = nextSpecialStartIndex + specialToken.length\n } else {\n break\n }\n }\n\n return tokensCount\n }\n\n *decodeNativeGenerator(\n tokens: Iterable<number>,\n ): Generator<Uint8Array | string, void, void> {\n for (const token of tokens) {\n const tokenBytes = this.tryDecodeToken(token)\n if (tokenBytes) {\n yield tokenBytes\n }\n }\n }\n\n decodeNative(tokens: Iterable<number>): string {\n let decoded = ''\n let intBuffer = emptyBuffer\n\n for (const token of tokens) {\n const tokenBytes = this.tryDecodeToken(token)\n if (tokenBytes === undefined) {\n throw new Error(`Token ${token} is not in the byte pair encoder.`)\n }\n if (typeof tokenBytes === 'string') {\n if (intBuffer !== emptyBuffer) {\n decoded += decoder.decode(intBuffer, { stream: true })\n intBuffer = emptyBuffer\n }\n decoded += tokenBytes\n } else {\n const newBuffer = new Uint8Array(intBuffer.length + tokenBytes.length)\n newBuffer.set(intBuffer)\n newBuffer.set(tokenBytes, intBuffer.length)\n intBuffer = newBuffer\n }\n }\n\n if (intBuffer !== emptyBuffer) {\n decoded += decoder.decode(intBuffer, { stream: true })\n }\n return decoded\n }\n\n async *decodeNativeAsyncIterable(\n tokens: AsyncIterable<number>,\n ): AsyncGenerator<Uint8Array | string> {\n for await (const token of tokens) {\n const tokenBytesOrString = this.tryDecodeToken(token)\n if (tokenBytesOrString) {\n yield tokenBytesOrString\n }\n }\n }\n\n private getBpeRankFromString(key: string): number | undefined {\n return this.bytePairStringRankEncoder.get(key)\n }\n\n private getBpeRankFromStringOrThrow(key: string): number {\n const value = this.getBpeRankFromString(key)\n if (value === undefined) {\n throw new Error(\n `The byte-pair encoding does not contain a value for: ${key}`,\n )\n }\n return value\n }\n\n private getBpeRankFromBytes(key: Uint8Array): number | undefined {\n const keyAsString = tryConvertToString(key)\n\n if (keyAsString !== undefined) {\n return this.getBpeRankFromString(keyAsString)\n }\n\n // Perform binary search on the binary keys\n const index = this.binarySearch(key)\n if (index !== -1) {\n return this.bytePairNonUtfSortedEncoder[index]![1]\n }\n\n return undefined\n }\n\n private getBpeRankFromBytesOrThrow(key: Uint8Array): number {\n const value = this.getBpeRankFromBytes(key)\n if (value === undefined) {\n throw new Error(\n `The byte-pair encoding does not contain a value for: ${key.toString()}`,\n )\n }\n return value\n }\n\n // Binary search on the binary keys\n private binarySearch(key: Uint8Array): number {\n let low = 0\n let high = this.bytePairNonUtfSortedEncoder.length - 1\n\n while (low <= high) {\n const mid = (low + high) >>> 1\n const midKey = this.bytePairNonUtfSortedEncoder[mid]![0]\n let cmp = 0\n const maxLength = Math.min(midKey.length, key.length)\n for (let i = 0; i < maxLength; i++) {\n cmp = midKey[i]! - key[i]!\n if (cmp !== 0) break\n }\n if (cmp === 0) {\n cmp = midKey.length - key.length\n }\n if (cmp === 0) {\n return mid\n }\n if (cmp < 0) {\n low = mid + 1\n } else {\n high = mid - 1\n }\n }\n return -1\n }\n\n private findNextSpecialToken(\n text: string,\n allowedSpecial: Set<string> | undefined,\n startIndex: number,\n ): [startIndex: number, token: string] | undefined {\n let searchIndex = startIndex\n\n while (true) {\n this.specialTokenPatternRegex.lastIndex = searchIndex\n const nextSpecialMatch = this.specialTokenPatternRegex.exec(text)\n\n if (!nextSpecialMatch) {\n return undefined\n }\n\n const specialToken = nextSpecialMatch[0]\n\n if (allowedSpecial?.has(specialToken)) {\n const specialTokenStartIndex = nextSpecialMatch.index + searchIndex\n return [specialTokenStartIndex, specialToken]\n }\n\n searchIndex = nextSpecialMatch.index + searchIndex + 1\n }\n }\n\n private tryDecodeToken(tokenRank: number): Uint8Array | string | undefined {\n const value = this.bytePairRankDecoder[tokenRank]\n if (typeof value === 'string') {\n return value\n }\n if (typeof value === 'object') {\n const fromBinary = this.bytePairNonUtfRankDecoder.get(tokenRank)\n if (fromBinary) {\n return fromBinary\n }\n }\n return this.specialTokensDecoder.get(tokenRank)\n }\n\n private addToMergeCache(key: string, value: number[]): void {\n if (!this.mergeCache) return\n\n if (this.mergeCache.size >= this.mergeCacheSize) {\n // Remove least recently used item (first item)\n const firstKey = this.mergeCache.keys().next().value!\n this.mergeCache.delete(firstKey)\n }\n this.mergeCache.set(key, value)\n }\n\n private bytePairEncode(input: string): number[] {\n if (input.length === 1 && isAscii(input.codePointAt(0)!)) {\n return [this.getBpeRankFromStringOrThrow(input)]\n }\n\n if (this.mergeCache?.has(input)) {\n const result = this.mergeCache.get(input)!\n // Move to end to mark as recently used\n this.mergeCache.delete(input)\n this.mergeCache.set(input, result)\n return result\n }\n\n const inputBytes = this.textEncoder.encode(input)\n const result = this.bytePairMerge(inputBytes)\n this.addToMergeCache(input, result)\n return result\n }\n\n private bytePairMerge(\n // Input array of bytes to process\n piece: Uint8Array,\n ): number[] {\n // 'starts' holds the start indices of each partition\n const starts: number[] = []\n // 'ranks' holds the BPE ranks of each partition pair\n const ranks: number[] = []\n\n // Helper function to get the rank of a byte pair starting at 'startIndex'\n const getRank = (\n startIndex: number,\n pairStart = starts[startIndex],\n pairEnd = starts[startIndex + 2],\n ): number => {\n if (pairEnd === undefined) {\n // No valid pair exists\n return Number.POSITIVE_INFINITY\n }\n\n // Extract the byte pair\n const key = piece.subarray(pairStart, pairEnd)\n\n // Retrieve the BPE rank of this byte pair (if it exists)\n const rank = this.getBpeRankFromBytes(key)\n return rank ?? Number.POSITIVE_INFINITY\n }\n\n // Initialize the 'starts' array with all possible start indices\n for (let i = 0; i <= piece.length; i++) {\n starts.push(i)\n if (i < piece.length - 1) {\n // Initialize the BPE values for all adjacent pairs\n ranks.push(getRank(i, i, i + 2))\n } else {\n // Initialize BPE values to infinity for the last pair\n ranks.push(Number.POSITIVE_INFINITY)\n }\n }\n\n // Iteratively merge byte pairs until no more useful merges can be done\n while (starts.length > 1) {\n let lowestRank = Number.POSITIVE_INFINITY\n let lowestPartitionIndex = -1\n\n // Find the partition with the minimum rank\n for (let i = 0; i < ranks.length - 1; i++) {\n const rank = ranks[i]!\n if (rank < lowestRank) {\n lowestRank = rank\n lowestPartitionIndex = i\n }\n }\n\n // If no valid pair is left to merge, exit the loop\n if (\n lowestRank === Number.POSITIVE_INFINITY ||\n lowestPartitionIndex === -1\n ) {\n break\n }\n\n // Merge the pair at 'lowestPartitionIndex' by removing the next start index\n starts.splice(lowestPartitionIndex + 1, 1)\n // Remove the BPE value of the merged pair\n ranks.splice(lowestPartitionIndex, 1)\n\n // Update the current merged pair's rank\n ranks[lowestPartitionIndex] = getRank(lowestPartitionIndex)\n\n // Update the rank of the previous pair, if it exists\n if (lowestPartitionIndex > 0) {\n ranks[lowestPartitionIndex - 1] = getRank(lowestPartitionIndex - 1)\n }\n }\n\n // Create the final output by applying the transform function to each partitioned range\n const output: number[] = []\n for (let i = 0; i < starts.length - 1; i++) {\n const pairStart = starts[i]\n const pairEnd = starts[i + 1]\n const bpeValue = this.getBpeRankFromBytesOrThrow(\n piece.subarray(pairStart, pairEnd),\n )\n output.push(bpeValue)\n }\n return output\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BytePairEncodingCore.js","names":[],"sources":["../src/BytePairEncodingCore.ts"],"sourcesContent":["import { DEFAULT_MERGE_CACHE_SIZE } from './constants.js'\nimport {\n compareUint8Arrays,\n isAscii,\n startsWithByteOrderMark,\n tryConvertToString,\n} from './utfUtil.js'\nimport { escapeRegExp } from './util.js'\n\nexport type RawBytePairRanks = readonly (string | readonly number[])[]\n\nexport interface BytePairEncodingConfig {\n bytePairRankDecoder: RawBytePairRanks\n specialTokensEncoder?: Map<string, number>\n tokenSplitRegex: RegExp\n /**\n * LRU cache for merged tokens pairs.\n * Increasing this value should make encoding similar strings faster,\n * but will consume more memory.\n * @default 100000\n */\n mergeCacheSize?: number\n}\n\nconst emptyBuffer = new Uint8Array(0)\n\n// `ignoreBOM: true` keeps a leading U+FEFF in the decoded output.\nexport const decoder = new TextDecoder('utf8', { ignoreBOM: true })\n\nexport class BytePairEncodingCore {\n readonly mergeableBytePairRankCount: number\n /**\n * an array where the index is the BPE rank,\n * and the value is the string or the array of bytes that it decodes to\n * it may contain holes if token is unused\n */\n private bytePairRankDecoder: RawBytePairRanks\n private bytePairNonUtfRankDecoder = new Map<number, Uint8Array>()\n private bytePairNonUtfSortedEncoder: readonly [Uint8Array, number][]\n /**\n * a reverse map of the bytePairRankDecoder,\n * where the key is the string and the value is the rank\n * values that cannot be represented as a string are present in `bytePairNonUtfSortedEncoder`\n */\n private bytePairStringRankEncoder: Map<string, number>\n private tokenSplitRegex: RegExp\n private specialTokensEncoder: Map<string, number>\n private specialTokensDecoder: Map<number, string>\n private specialTokenPatternRegex: RegExp\n private textEncoder = new TextEncoder()\n private mergeCache?: Map<string, number[]>\n private mergeCacheSize: number\n\n constructor({\n bytePairRankDecoder,\n specialTokensEncoder,\n tokenSplitRegex,\n mergeCacheSize = DEFAULT_MERGE_CACHE_SIZE,\n }: BytePairEncodingConfig) {\n this.bytePairRankDecoder = bytePairRankDecoder\n this.bytePairStringRankEncoder = new Map<string, number>()\n this.mergeCacheSize = mergeCacheSize\n if (mergeCacheSize > 0) {\n this.mergeCache = new Map()\n }\n\n // size without array holes (which may be present in the encoder)\n this.mergeableBytePairRankCount = Object.keys(bytePairRankDecoder).length\n const binaryLookup: [Uint8Array, number][] = []\n // forEach skips array holes:\n bytePairRankDecoder.forEach((value, rank) => {\n if (typeof value === 'string') {\n this.bytePairStringRankEncoder.set(value, rank)\n return\n }\n const byteArray = new Uint8Array(value)\n binaryLookup.push([byteArray, rank])\n this.bytePairNonUtfRankDecoder.set(rank, byteArray)\n if (startsWithByteOrderMark(byteArray)) {\n // The rank tables keep tokens that start with a UTF-8 byte order mark\n // (EF BB BF) as raw bytes, because a plain decode would strip the mark.\n // They are still valid UTF-8, so they must also be reachable through\n // the string lookup that getBpeRankFromBytes uses for valid UTF-8.\n const asString = tryConvertToString(byteArray)\n if (asString !== undefined) {\n this.bytePairStringRankEncoder.set(asString, rank)\n }\n }\n })\n this.bytePairNonUtfSortedEncoder = binaryLookup.sort((a, b) =>\n compareUint8Arrays(a[0], b[0]),\n )\n this.specialTokensEncoder =\n specialTokensEncoder ?? new Map<string, number>()\n this.specialTokensDecoder = specialTokensEncoder\n ? new Map([...specialTokensEncoder].map(([key, value]) => [value, key]))\n : new Map<number, string>()\n this.tokenSplitRegex = tokenSplitRegex\n\n const escapedSpecialTokens = [...this.specialTokensEncoder.keys()].map(\n escapeRegExp,\n )\n const allSpecialTokensRegex = escapedSpecialTokens.join('|')\n try {\n this.specialTokenPatternRegex = new RegExp(allSpecialTokensRegex, 'y')\n } catch {\n throw new Error('Invalid regular expression pattern.')\n }\n }\n\n setMergeCacheSize(newSize: number): void {\n if (this.mergeCacheSize === 0 && newSize > 0) {\n this.mergeCache = new Map()\n }\n this.mergeCacheSize = newSize\n if (newSize === 0) {\n this.mergeCache = undefined\n }\n }\n\n clearMergeCache(): void {\n this.mergeCache?.clear()\n }\n\n *encodeNativeGenerator(\n text: string,\n allowedSpecial?: Set<string>,\n ): Generator<number[], number, undefined> {\n let startIndex = 0\n let lastTokenLength = 0\n\n while (true) {\n const nextSpecialMatch = this.findNextSpecialToken(\n text,\n allowedSpecial,\n startIndex,\n )\n const nextSpecialStartIndex = nextSpecialMatch?.[0]\n\n const endIndex = nextSpecialStartIndex ?? text.length\n\n const textBeforeSpecial =\n startIndex === 0 && endIndex === text.length\n ? text\n : text.slice(startIndex, endIndex)\n\n for (const [match] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {\n const token = this.getBpeRankFromString(match)\n if (token !== undefined) {\n lastTokenLength = 1\n yield [token]\n\n continue\n }\n\n const tokens = this.bytePairEncode(match)\n lastTokenLength = tokens.length\n yield tokens\n }\n\n if (nextSpecialStartIndex !== undefined) {\n const specialToken = nextSpecialMatch![1]\n const specialTokenValue = this.specialTokensEncoder.get(specialToken)\n if (specialTokenValue === undefined) {\n throw new Error(\n `Special token \"${specialToken}\" is not in the special token encoder.`,\n )\n }\n yield [specialTokenValue]\n startIndex = nextSpecialStartIndex + specialToken.length\n lastTokenLength = 1\n } else {\n break\n }\n }\n\n return lastTokenLength\n }\n\n encodeNative(text: string, allowedSpecial?: Set<string>): number[] {\n let startIndex = 0\n const tokensArray: number[] = [] // Flat list to collect the tokens\n\n while (true) {\n const nextSpecialMatch = this.findNextSpecialToken(\n text,\n allowedSpecial,\n startIndex,\n )\n const nextSpecialStartIndex = nextSpecialMatch?.[0]\n\n const endIndex = nextSpecialStartIndex ?? text.length\n\n const textBeforeSpecial =\n startIndex === 0 && endIndex === text.length\n ? text\n : text.slice(startIndex, endIndex)\n\n for (const [match] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {\n const token = this.getBpeRankFromString(match)\n if (token !== undefined) {\n tokensArray.push(token)\n\n continue\n }\n\n const tokens = this.bytePairEncode(match)\n tokensArray.push(...tokens)\n }\n\n if (nextSpecialStartIndex !== undefined) {\n const specialToken = nextSpecialMatch![1]\n const specialTokenValue = this.specialTokensEncoder.get(specialToken)\n if (specialTokenValue === undefined) {\n throw new Error(\n `Special token \"${specialToken}\" is not in the special token encoder.`,\n )\n }\n tokensArray.push(specialTokenValue)\n startIndex = nextSpecialStartIndex + specialToken.length\n } else {\n break\n }\n }\n\n return tokensArray\n }\n\n countNative(text: string, allowedSpecial?: Set<string>): number {\n let startIndex = 0\n let tokensCount = 0\n\n while (true) {\n const nextSpecialMatch = this.findNextSpecialToken(\n text,\n allowedSpecial,\n startIndex,\n )\n const nextSpecialStartIndex = nextSpecialMatch?.[0]\n\n const endIndex = nextSpecialStartIndex ?? text.length\n\n const textBeforeSpecial =\n startIndex === 0 && endIndex === text.length\n ? text\n : text.slice(startIndex, endIndex)\n\n for (const [match] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {\n const token = this.getBpeRankFromString(match)\n if (token !== undefined) {\n tokensCount++\n\n continue\n }\n\n const tokens = this.bytePairEncode(match)\n tokensCount += tokens.length\n }\n\n if (nextSpecialStartIndex !== undefined) {\n const specialToken = nextSpecialMatch![1]\n const specialTokenValue = this.specialTokensEncoder.get(specialToken)\n if (specialTokenValue === undefined) {\n throw new Error(\n `Special token \"${specialToken}\" is not in the special token encoder.`,\n )\n }\n tokensCount++\n startIndex = nextSpecialStartIndex + specialToken.length\n } else {\n break\n }\n }\n\n return tokensCount\n }\n\n *decodeNativeGenerator(\n tokens: Iterable<number>,\n ): Generator<Uint8Array | string, void, void> {\n for (const token of tokens) {\n const tokenBytes = this.tryDecodeToken(token)\n if (tokenBytes) {\n yield tokenBytes\n }\n }\n }\n\n decodeNative(tokens: Iterable<number>): string {\n let decoded = ''\n let intBuffer = emptyBuffer\n\n for (const token of tokens) {\n const tokenBytes = this.tryDecodeToken(token)\n if (tokenBytes === undefined) {\n throw new Error(`Token ${token} is not in the byte pair encoder.`)\n }\n if (typeof tokenBytes === 'string') {\n if (intBuffer !== emptyBuffer) {\n decoded += decoder.decode(intBuffer, { stream: true })\n intBuffer = emptyBuffer\n }\n decoded += tokenBytes\n } else {\n const newBuffer = new Uint8Array(intBuffer.length + tokenBytes.length)\n newBuffer.set(intBuffer)\n newBuffer.set(tokenBytes, intBuffer.length)\n intBuffer = newBuffer\n }\n }\n\n if (intBuffer !== emptyBuffer) {\n decoded += decoder.decode(intBuffer, { stream: true })\n }\n return decoded\n }\n\n async *decodeNativeAsyncIterable(\n tokens: AsyncIterable<number>,\n ): AsyncGenerator<Uint8Array | string> {\n for await (const token of tokens) {\n const tokenBytesOrString = this.tryDecodeToken(token)\n if (tokenBytesOrString) {\n yield tokenBytesOrString\n }\n }\n }\n\n private getBpeRankFromString(key: string): number | undefined {\n return this.bytePairStringRankEncoder.get(key)\n }\n\n private getBpeRankFromStringOrThrow(key: string): number {\n const value = this.getBpeRankFromString(key)\n if (value === undefined) {\n throw new Error(\n `The byte-pair encoding does not contain a value for: ${key}`,\n )\n }\n return value\n }\n\n private getBpeRankFromBytes(key: Uint8Array): number | undefined {\n const keyAsString = tryConvertToString(key)\n\n if (keyAsString !== undefined) {\n return this.getBpeRankFromString(keyAsString)\n }\n\n // Perform binary search on the binary keys\n const index = this.binarySearch(key)\n if (index !== -1) {\n return this.bytePairNonUtfSortedEncoder[index]![1]\n }\n\n return undefined\n }\n\n private getBpeRankFromBytesOrThrow(key: Uint8Array): number {\n const value = this.getBpeRankFromBytes(key)\n if (value === undefined) {\n throw new Error(\n `The byte-pair encoding does not contain a value for: ${key.toString()}`,\n )\n }\n return value\n }\n\n // Binary search on the binary keys\n private binarySearch(key: Uint8Array): number {\n let low = 0\n let high = this.bytePairNonUtfSortedEncoder.length - 1\n\n while (low <= high) {\n const mid = (low + high) >>> 1\n const midKey = this.bytePairNonUtfSortedEncoder[mid]![0]\n let cmp = 0\n const maxLength = Math.min(midKey.length, key.length)\n for (let i = 0; i < maxLength; i++) {\n cmp = midKey[i]! - key[i]!\n if (cmp !== 0) break\n }\n if (cmp === 0) {\n cmp = midKey.length - key.length\n }\n if (cmp === 0) {\n return mid\n }\n if (cmp < 0) {\n low = mid + 1\n } else {\n high = mid - 1\n }\n }\n return -1\n }\n\n private findNextSpecialToken(\n text: string,\n allowedSpecial: Set<string> | undefined,\n startIndex: number,\n ): [startIndex: number, token: string] | undefined {\n let searchIndex = startIndex\n\n while (true) {\n this.specialTokenPatternRegex.lastIndex = searchIndex\n const nextSpecialMatch = this.specialTokenPatternRegex.exec(text)\n\n if (!nextSpecialMatch) {\n return undefined\n }\n\n const specialToken = nextSpecialMatch[0]\n\n if (allowedSpecial?.has(specialToken)) {\n const specialTokenStartIndex = nextSpecialMatch.index + searchIndex\n return [specialTokenStartIndex, specialToken]\n }\n\n searchIndex = nextSpecialMatch.index + searchIndex + 1\n }\n }\n\n private tryDecodeToken(tokenRank: number): Uint8Array | string | undefined {\n const value = this.bytePairRankDecoder[tokenRank]\n if (typeof value === 'string') {\n return value\n }\n if (typeof value === 'object') {\n const fromBinary = this.bytePairNonUtfRankDecoder.get(tokenRank)\n if (fromBinary) {\n return fromBinary\n }\n }\n return this.specialTokensDecoder.get(tokenRank)\n }\n\n private addToMergeCache(key: string, value: number[]): void {\n if (!this.mergeCache) return\n\n if (this.mergeCache.size >= this.mergeCacheSize) {\n // Remove least recently used item (first item)\n const firstKey = this.mergeCache.keys().next().value!\n this.mergeCache.delete(firstKey)\n }\n this.mergeCache.set(key, value)\n }\n\n private bytePairEncode(input: string): number[] {\n if (input.length === 1 && isAscii(input.codePointAt(0)!)) {\n return [this.getBpeRankFromStringOrThrow(input)]\n }\n\n if (this.mergeCache?.has(input)) {\n const result = this.mergeCache.get(input)!\n // Move to end to mark as recently used\n this.mergeCache.delete(input)\n this.mergeCache.set(input, result)\n return result\n }\n\n const inputBytes = this.textEncoder.encode(input)\n const result = this.bytePairMerge(inputBytes)\n this.addToMergeCache(input, result)\n return result\n }\n\n private bytePairMerge(\n // Input array of bytes to process\n piece: Uint8Array,\n ): number[] {\n const { length } = piece\n // Partitions form a linked list over byte offsets: a live partition starting at\n // offset 'i' spans [i, next[i]). 'pairRanks[i]' is the rank of merging it with\n // the partition after it. Merges come off a min-heap ordered by (rank, offset),\n // which picks the same pair as scanning for the lowest rank, leftmost first,\n // without rescanning the piece after every merge.\n const next = new Int32Array(length + 1)\n const previous = new Int32Array(length + 1)\n const pairRanks = new Float64Array(length + 1)\n const live = new Uint8Array(length + 1)\n\n const getPairRank = (startIndex: number): number => {\n const middle = next[startIndex]!\n if (middle >= length) return Number.POSITIVE_INFINITY\n const rank = this.getBpeRankFromBytes(\n piece.subarray(startIndex, next[middle]!),\n )\n return rank ?? Number.POSITIVE_INFINITY\n }\n\n // Heap entries are packed as [rank, startIndex] pairs in a flat array\n const heap: number[] = []\n const isLower = (a: number, b: number) =>\n heap[a]! < heap[b]! ||\n (heap[a] === heap[b] && heap[a + 1]! < heap[b + 1]!)\n const swap = (a: number, b: number) => {\n const rank = heap[a]!\n const startIndex = heap[a + 1]!\n heap[a] = heap[b]!\n heap[a + 1] = heap[b + 1]!\n heap[b] = rank\n heap[b + 1] = startIndex\n }\n const push = (rank: number, startIndex: number) => {\n heap.push(rank, startIndex)\n let index = heap.length - 2\n while (index > 0) {\n const parent = (((index >> 1) - 1) >> 1) << 1\n if (!isLower(index, parent)) break\n swap(index, parent)\n index = parent\n }\n }\n const pop = () => {\n const last = heap.length - 2\n swap(0, last)\n const rank = heap[last]!\n const startIndex = heap[last + 1]!\n heap.length = last\n let index = 0\n while (true) {\n const left = index * 2 + 2\n const right = left + 2\n let lowest = index\n if (left < heap.length && isLower(left, lowest)) lowest = left\n if (right < heap.length && isLower(right, lowest)) lowest = right\n if (lowest === index) break\n swap(index, lowest)\n index = lowest\n }\n return [rank, startIndex] as const\n }\n\n for (let i = 0; i <= length; i++) {\n next[i] = i + 1\n previous[i] = i - 1\n live[i] = 1\n }\n for (let i = 0; i < length - 1; i++) {\n pairRanks[i] = getPairRank(i)\n if (pairRanks[i] !== Number.POSITIVE_INFINITY) push(pairRanks[i]!, i)\n }\n\n // Iteratively merge byte pairs until no more useful merges can be done\n while (heap.length > 0) {\n const [rank, startIndex] = pop()\n // Skip entries made stale by an earlier merge\n if (!live[startIndex] || pairRanks[startIndex] !== rank) continue\n\n // Merge the partition at 'startIndex' with the one after it\n const merged = next[startIndex]!\n live[merged] = 0\n next[startIndex] = next[merged]!\n previous[next[merged]!] = startIndex\n\n pairRanks[startIndex] = getPairRank(startIndex)\n if (pairRanks[startIndex] !== Number.POSITIVE_INFINITY) {\n push(pairRanks[startIndex]!, startIndex)\n }\n\n const before = previous[startIndex]!\n if (before >= 0) {\n pairRanks[before] = getPairRank(before)\n if (pairRanks[before] !== Number.POSITIVE_INFINITY) {\n push(pairRanks[before]!, before)\n }\n }\n }\n\n // Create the final output by applying the transform function to each partitioned range\n const output: number[] = []\n for (let i = 0; i < length; i = next[i]!) {\n output.push(this.getBpeRankFromBytesOrThrow(piece.subarray(i, next[i]!)))\n }\n return output\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
//#region src/encodingParams/constants.ts
|
|
2
|
-
const R50K_TOKEN_SPLIT_REGEX = /'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\
|
|
2
|
+
const R50K_TOKEN_SPLIT_REGEX = /'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\p{White_Space}\p{L}\p{N}]+|\p{White_Space}+(?!\P{White_Space})|\p{White_Space}+/gu;
|
|
3
3
|
const CONTRACTION_SUFFIX_PATTERN = String.raw`'(?:[sS]|[dD]|[mM]|[tT]|[lL][lL]|[vV][eE]|[rR][eE])`;
|
|
4
4
|
const OPTIONAL_CONTRACTION_SUFFIX = String.raw`(?:${CONTRACTION_SUFFIX_PATTERN})?`;
|
|
5
|
-
const CL100K_TOKEN_SPLIT_PATTERN = String.raw`${CONTRACTION_SUFFIX_PATTERN}|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\
|
|
5
|
+
const CL100K_TOKEN_SPLIT_PATTERN = String.raw`${CONTRACTION_SUFFIX_PATTERN}|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\p{White_Space}\p{L}\p{N}]+[\r\n]*|\p{White_Space}+$|\p{White_Space}*[\r\n]|\p{White_Space}+(?!\P{White_Space})|\p{White_Space}`;
|
|
6
6
|
const CL100K_TOKEN_SPLIT_REGEX = new RegExp(CL100K_TOKEN_SPLIT_PATTERN, "gu");
|
|
7
|
-
const O200K_TOKEN_SPLIT_PATTERN = String.raw`[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]*[\p{Ll}\p{Lm}\p{Lo}\p{M}]+${OPTIONAL_CONTRACTION_SUFFIX}|[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]+[\p{Ll}\p{Lm}\p{Lo}\p{M}]*${OPTIONAL_CONTRACTION_SUFFIX}|\p{N}{1,3}| ?[^\
|
|
7
|
+
const O200K_TOKEN_SPLIT_PATTERN = String.raw`[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]*[\p{Ll}\p{Lm}\p{Lo}\p{M}]+${OPTIONAL_CONTRACTION_SUFFIX}|[^\r\n\p{L}\p{N}]?[\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{M}]+[\p{Ll}\p{Lm}\p{Lo}\p{M}]*${OPTIONAL_CONTRACTION_SUFFIX}|\p{N}{1,3}| ?[^\p{White_Space}\p{L}\p{N}]+[\r\n/]*|\p{White_Space}*[\r\n]+|\p{White_Space}+(?!\P{White_Space})|\p{White_Space}+`;
|
|
8
8
|
const O200K_TOKEN_SPLIT_REGEX = new RegExp(O200K_TOKEN_SPLIT_PATTERN, "gu");
|
|
9
9
|
//#endregion
|
|
10
10
|
export { CL100K_TOKEN_SPLIT_REGEX, O200K_TOKEN_SPLIT_REGEX, R50K_TOKEN_SPLIT_REGEX };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","names":[],"sources":["../../src/encodingParams/constants.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"constants.js","names":[],"sources":["../../src/encodingParams/constants.ts"],"sourcesContent":["// The split patterns below use `\\p{White_Space}` / `\\P{White_Space}` where\n// tiktoken's patterns use `\\s` / `\\S`: the regex engine behind tiktoken treats\n// `\\s` as the Unicode White_Space property, whereas JavaScript's `\\s` differs\n// from it on exactly two code points (U+0085 and U+FEFF).\nexport const R50K_TOKEN_SPLIT_REGEX =\n /'s|'t|'re|'ve|'m|'ll|'d| ?\\p{L}+| ?\\p{N}+| ?[^\\p{White_Space}\\p{L}\\p{N}]+|\\p{White_Space}+(?!\\P{White_Space})|\\p{White_Space}+/gu\n\nconst CONTRACTION_SUFFIX_PATTERN = String.raw`'(?:[sS]|[dD]|[mM]|[tT]|[lL][lL]|[vV][eE]|[rR][eE])`\n\nconst OPTIONAL_CONTRACTION_SUFFIX = String.raw`(?:${CONTRACTION_SUFFIX_PATTERN})?`\n\nconst CL100K_TOKEN_SPLIT_PATTERN = String.raw`${CONTRACTION_SUFFIX_PATTERN}|[^\\r\\n\\p{L}\\p{N}]?\\p{L}+|\\p{N}{1,3}| ?[^\\p{White_Space}\\p{L}\\p{N}]+[\\r\\n]*|\\p{White_Space}+$|\\p{White_Space}*[\\r\\n]|\\p{White_Space}+(?!\\P{White_Space})|\\p{White_Space}`\n\nexport const CL100K_TOKEN_SPLIT_REGEX = new RegExp(\n CL100K_TOKEN_SPLIT_PATTERN,\n 'gu',\n)\n\nconst O200K_TOKEN_SPLIT_PATTERN = String.raw`[^\\r\\n\\p{L}\\p{N}]?[\\p{Lu}\\p{Lt}\\p{Lm}\\p{Lo}\\p{M}]*[\\p{Ll}\\p{Lm}\\p{Lo}\\p{M}]+${OPTIONAL_CONTRACTION_SUFFIX}|[^\\r\\n\\p{L}\\p{N}]?[\\p{Lu}\\p{Lt}\\p{Lm}\\p{Lo}\\p{M}]+[\\p{Ll}\\p{Lm}\\p{Lo}\\p{M}]*${OPTIONAL_CONTRACTION_SUFFIX}|\\p{N}{1,3}| ?[^\\p{White_Space}\\p{L}\\p{N}]+[\\r\\n/]*|\\p{White_Space}*[\\r\\n]+|\\p{White_Space}+(?!\\P{White_Space})|\\p{White_Space}+`\n\nexport const O200K_TOKEN_SPLIT_REGEX = new RegExp(\n O200K_TOKEN_SPLIT_PATTERN,\n 'gu',\n)\n"],"mappings":";AAIA,MAAa,yBACX;AAEF,MAAM,6BAA6B,OAAO,GAAG;AAE7C,MAAM,8BAA8B,OAAO,GAAG,MAAM,2BAA2B;AAE/E,MAAM,6BAA6B,OAAO,GAAG,GAAG,2BAA2B;AAE3E,MAAa,2BAA2B,IAAI,OAC1C,4BACA,IACF;AAEA,MAAM,4BAA4B,OAAO,GAAG,+EAA+E,4BAA4B,+EAA+E,4BAA4B;AAElQ,MAAa,0BAA0B,IAAI,OACzC,2BACA,IACF"}
|
package/esm/utfUtil.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//#region src/utfUtil.d.ts
|
|
2
2
|
declare const isAscii: (codePoint: number) => boolean;
|
|
3
3
|
declare function endsWithIncompleteUtfPairSurrogate(string: string): boolean;
|
|
4
|
+
declare function startsWithByteOrderMark(bytes: Uint8Array): boolean;
|
|
4
5
|
declare function tryConvertToString(arr: Uint8Array): string | undefined;
|
|
5
6
|
declare function compareUint8Arrays(a: Uint8Array, b: Uint8Array): number;
|
|
6
7
|
//#endregion
|
|
7
|
-
export { compareUint8Arrays, endsWithIncompleteUtfPairSurrogate, isAscii, tryConvertToString };
|
|
8
|
+
export { compareUint8Arrays, endsWithIncompleteUtfPairSurrogate, isAscii, startsWithByteOrderMark, tryConvertToString };
|
|
8
9
|
//# sourceMappingURL=utfUtil.d.ts.map
|
package/esm/utfUtil.js
CHANGED
|
@@ -43,7 +43,13 @@ function isValidUTF8(bytes) {
|
|
|
43
43
|
}
|
|
44
44
|
return true;
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
function startsWithByteOrderMark(bytes) {
|
|
47
|
+
return bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191;
|
|
48
|
+
}
|
|
49
|
+
const textDecoder = new TextDecoder("utf8", {
|
|
50
|
+
fatal: false,
|
|
51
|
+
ignoreBOM: true
|
|
52
|
+
});
|
|
47
53
|
function tryConvertToString(arr) {
|
|
48
54
|
if (!isValidUTF8(arr)) return;
|
|
49
55
|
return textDecoder.decode(arr);
|
|
@@ -54,6 +60,6 @@ function compareUint8Arrays(a, b) {
|
|
|
54
60
|
return a.length - b.length;
|
|
55
61
|
}
|
|
56
62
|
//#endregion
|
|
57
|
-
export { compareUint8Arrays, endsWithIncompleteUtfPairSurrogate, isAscii, tryConvertToString };
|
|
63
|
+
export { compareUint8Arrays, endsWithIncompleteUtfPairSurrogate, isAscii, startsWithByteOrderMark, tryConvertToString };
|
|
58
64
|
|
|
59
65
|
//# sourceMappingURL=utfUtil.js.map
|
package/esm/utfUtil.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utfUtil.js","names":[],"sources":["../src/utfUtil.ts"],"sourcesContent":["export const isAscii = (codePoint: number) => codePoint <= 0x7f\n\nconst HIGH_SURROGATE_START = 55_296\nconst HIGH_SURROGATE_END = 56_319\n\nexport function endsWithIncompleteUtfPairSurrogate(string: string): boolean {\n if (string.length === 0) return false\n // Check if the last character is a high surrogate\n const lastCharCode = string.charCodeAt(string.length - 1)\n return (\n lastCharCode >= HIGH_SURROGATE_START && lastCharCode <= HIGH_SURROGATE_END\n )\n}\n\nfunction isValidUTF8(bytes: Uint8Array): boolean {\n let i = 0\n while (i < bytes.length) {\n const byte1 = bytes[i]!\n\n let numBytes = 0\n let codePoint = 0\n\n // Determine the number of bytes in the current UTF-8 character\n if (byte1 <= 0x7f) {\n // 1-byte character (ASCII)\n numBytes = 1\n codePoint = byte1\n } else if ((byte1 & 0xe0) === 0xc0) {\n // 2-byte character\n numBytes = 2\n codePoint = byte1 & 0x1f\n if (byte1 <= 0xc1) return false // Overlong encoding not allowed\n } else if ((byte1 & 0xf0) === 0xe0) {\n // 3-byte character\n numBytes = 3\n codePoint = byte1 & 0x0f\n } else if ((byte1 & 0xf8) === 0xf0) {\n // 4-byte character\n numBytes = 4\n codePoint = byte1 & 0x07\n if (byte1 > 0xf4) return false // Code points above U+10FFFF not allowed\n } else {\n // Invalid first byte of UTF-8 character\n return false\n }\n\n // Ensure there are enough continuation bytes\n if (i + numBytes > bytes.length) return false\n\n // Process the continuation bytes\n for (let j = 1; j < numBytes; j++) {\n const byte = bytes[i + j]\n if (byte === undefined || (byte & 0xc0) !== 0x80) return false // Continuation bytes must start with '10'\n codePoint = (codePoint << 6) | (byte & 0x3f)\n }\n\n // Check for overlong encodings\n if (numBytes === 2 && codePoint < 0x80) return false // Overlong 2-byte sequence\n if (numBytes === 3 && codePoint < 2_048) return false // Overlong 3-byte sequence\n if (numBytes === 4 && codePoint < 65_536) return false // Overlong 4-byte sequence\n\n // Check for surrogate halves (U+D800 to U+DFFF)\n if (codePoint >= 55_296 && codePoint <= 57_343) return false\n\n // Check for code points above U+10FFFF\n if (codePoint > 1_114_111) return false\n\n // Move to the next character\n i += numBytes\n }\n return true\n}\n\nconst textDecoder = new TextDecoder('utf8', { fatal: false })\n\nexport function tryConvertToString(arr: Uint8Array): string | undefined {\n if (!isValidUTF8(arr)) {\n return undefined\n }\n return textDecoder.decode(arr)\n}\n\n// Helper function to compare two Uint8Arrays lexicographically\nexport function compareUint8Arrays(a: Uint8Array, b: Uint8Array): number {\n const len = Math.min(a.length, b.length)\n for (let i = 0; i < len; i++) {\n if (a[i] !== b[i]) {\n return a[i]! - b[i]!\n }\n }\n return a.length - b.length\n}\n"],"mappings":";AAAA,MAAa,WAAW,cAAsB,aAAa;AAE3D,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAE3B,SAAgB,mCAAmC,QAAyB;CAC1E,IAAI,OAAO,WAAW,GAAG,OAAO;CAEhC,MAAM,eAAe,OAAO,WAAW,OAAO,SAAS,CAAC;CACxD,OACE,gBAAgB,wBAAwB,gBAAgB;AAE5D;AAEA,SAAS,YAAY,OAA4B;CAC/C,IAAI,IAAI;CACR,OAAO,IAAI,MAAM,QAAQ;EACvB,MAAM,QAAQ,MAAM;EAEpB,IAAI,WAAW;EACf,IAAI,YAAY;EAGhB,IAAI,SAAS,KAAM;GAEjB,WAAW;GACX,YAAY;EACd,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;GACpB,IAAI,SAAS,KAAM,OAAO;EAC5B,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;EACtB,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;GACpB,IAAI,QAAQ,KAAM,OAAO;EAC3B,OAEE,OAAO;EAIT,IAAI,IAAI,WAAW,MAAM,QAAQ,OAAO;EAGxC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;GACjC,MAAM,OAAO,MAAM,IAAI;GACvB,IAAI,SAAS,KAAA,MAAc,OAAO,SAAU,KAAM,OAAO;GACzD,YAAa,aAAa,IAAM,OAAO;EACzC;EAGA,IAAI,aAAa,KAAK,YAAY,KAAM,OAAO;EAC/C,IAAI,aAAa,KAAK,YAAY,MAAO,OAAO;EAChD,IAAI,aAAa,KAAK,YAAY,OAAQ,OAAO;EAGjD,IAAI,aAAa,SAAU,aAAa,OAAQ,OAAO;EAGvD,IAAI,YAAY,SAAW,OAAO;EAGlC,KAAK;CACP;CACA,OAAO;AACT;AAEA,MAAM,cAAc,IAAI,YAAY,QAAQ,
|
|
1
|
+
{"version":3,"file":"utfUtil.js","names":[],"sources":["../src/utfUtil.ts"],"sourcesContent":["export const isAscii = (codePoint: number) => codePoint <= 0x7f\n\nconst HIGH_SURROGATE_START = 55_296\nconst HIGH_SURROGATE_END = 56_319\n\nexport function endsWithIncompleteUtfPairSurrogate(string: string): boolean {\n if (string.length === 0) return false\n // Check if the last character is a high surrogate\n const lastCharCode = string.charCodeAt(string.length - 1)\n return (\n lastCharCode >= HIGH_SURROGATE_START && lastCharCode <= HIGH_SURROGATE_END\n )\n}\n\nfunction isValidUTF8(bytes: Uint8Array): boolean {\n let i = 0\n while (i < bytes.length) {\n const byte1 = bytes[i]!\n\n let numBytes = 0\n let codePoint = 0\n\n // Determine the number of bytes in the current UTF-8 character\n if (byte1 <= 0x7f) {\n // 1-byte character (ASCII)\n numBytes = 1\n codePoint = byte1\n } else if ((byte1 & 0xe0) === 0xc0) {\n // 2-byte character\n numBytes = 2\n codePoint = byte1 & 0x1f\n if (byte1 <= 0xc1) return false // Overlong encoding not allowed\n } else if ((byte1 & 0xf0) === 0xe0) {\n // 3-byte character\n numBytes = 3\n codePoint = byte1 & 0x0f\n } else if ((byte1 & 0xf8) === 0xf0) {\n // 4-byte character\n numBytes = 4\n codePoint = byte1 & 0x07\n if (byte1 > 0xf4) return false // Code points above U+10FFFF not allowed\n } else {\n // Invalid first byte of UTF-8 character\n return false\n }\n\n // Ensure there are enough continuation bytes\n if (i + numBytes > bytes.length) return false\n\n // Process the continuation bytes\n for (let j = 1; j < numBytes; j++) {\n const byte = bytes[i + j]\n if (byte === undefined || (byte & 0xc0) !== 0x80) return false // Continuation bytes must start with '10'\n codePoint = (codePoint << 6) | (byte & 0x3f)\n }\n\n // Check for overlong encodings\n if (numBytes === 2 && codePoint < 0x80) return false // Overlong 2-byte sequence\n if (numBytes === 3 && codePoint < 2_048) return false // Overlong 3-byte sequence\n if (numBytes === 4 && codePoint < 65_536) return false // Overlong 4-byte sequence\n\n // Check for surrogate halves (U+D800 to U+DFFF)\n if (codePoint >= 55_296 && codePoint <= 57_343) return false\n\n // Check for code points above U+10FFFF\n if (codePoint > 1_114_111) return false\n\n // Move to the next character\n i += numBytes\n }\n return true\n}\n\nexport function startsWithByteOrderMark(bytes: Uint8Array): boolean {\n return (\n bytes.length >= 3 &&\n bytes[0] === 0xef &&\n bytes[1] === 0xbb &&\n bytes[2] === 0xbf\n )\n}\n\n// `ignoreBOM: true` keeps a leading U+FEFF in the output instead of silently\n// stripping it, so the bytes EF BB BF map to U+FEFF rather than to an empty string.\nconst textDecoder = new TextDecoder('utf8', { fatal: false, ignoreBOM: true })\n\nexport function tryConvertToString(arr: Uint8Array): string | undefined {\n if (!isValidUTF8(arr)) {\n return undefined\n }\n return textDecoder.decode(arr)\n}\n\n// Helper function to compare two Uint8Arrays lexicographically\nexport function compareUint8Arrays(a: Uint8Array, b: Uint8Array): number {\n const len = Math.min(a.length, b.length)\n for (let i = 0; i < len; i++) {\n if (a[i] !== b[i]) {\n return a[i]! - b[i]!\n }\n }\n return a.length - b.length\n}\n"],"mappings":";AAAA,MAAa,WAAW,cAAsB,aAAa;AAE3D,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAE3B,SAAgB,mCAAmC,QAAyB;CAC1E,IAAI,OAAO,WAAW,GAAG,OAAO;CAEhC,MAAM,eAAe,OAAO,WAAW,OAAO,SAAS,CAAC;CACxD,OACE,gBAAgB,wBAAwB,gBAAgB;AAE5D;AAEA,SAAS,YAAY,OAA4B;CAC/C,IAAI,IAAI;CACR,OAAO,IAAI,MAAM,QAAQ;EACvB,MAAM,QAAQ,MAAM;EAEpB,IAAI,WAAW;EACf,IAAI,YAAY;EAGhB,IAAI,SAAS,KAAM;GAEjB,WAAW;GACX,YAAY;EACd,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;GACpB,IAAI,SAAS,KAAM,OAAO;EAC5B,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;EACtB,OAAO,KAAK,QAAQ,SAAU,KAAM;GAElC,WAAW;GACX,YAAY,QAAQ;GACpB,IAAI,QAAQ,KAAM,OAAO;EAC3B,OAEE,OAAO;EAIT,IAAI,IAAI,WAAW,MAAM,QAAQ,OAAO;EAGxC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;GACjC,MAAM,OAAO,MAAM,IAAI;GACvB,IAAI,SAAS,KAAA,MAAc,OAAO,SAAU,KAAM,OAAO;GACzD,YAAa,aAAa,IAAM,OAAO;EACzC;EAGA,IAAI,aAAa,KAAK,YAAY,KAAM,OAAO;EAC/C,IAAI,aAAa,KAAK,YAAY,MAAO,OAAO;EAChD,IAAI,aAAa,KAAK,YAAY,OAAQ,OAAO;EAGjD,IAAI,aAAa,SAAU,aAAa,OAAQ,OAAO;EAGvD,IAAI,YAAY,SAAW,OAAO;EAGlC,KAAK;CACP;CACA,OAAO;AACT;AAEA,SAAgB,wBAAwB,OAA4B;CAClE,OACE,MAAM,UAAU,KAChB,MAAM,OAAO,OACb,MAAM,OAAO,OACb,MAAM,OAAO;AAEjB;AAIA,MAAM,cAAc,IAAI,YAAY,QAAQ;CAAE,OAAO;CAAO,WAAW;AAAK,CAAC;AAE7E,SAAgB,mBAAmB,KAAqC;CACtE,IAAI,CAAC,YAAY,GAAG,GAClB;CAEF,OAAO,YAAY,OAAO,GAAG;AAC/B;AAGA,SAAgB,mBAAmB,GAAe,GAAuB;CACvE,MAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CACvC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KACvB,IAAI,EAAE,OAAO,EAAE,IACb,OAAO,EAAE,KAAM,EAAE;CAGrB,OAAO,EAAE,SAAS,EAAE;AACtB"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vite-plus/test'
|
|
2
|
+
import { encode as encodeCl100k } from './encoding/cl100k_base.js'
|
|
3
|
+
import { encode as encodeO200k } from './encoding/o200k_base.js'
|
|
4
|
+
|
|
5
|
+
// A long run without whitespace becomes a single piece for the merge step.
|
|
6
|
+
// Rescanning the piece after every merge made this quadratic (minutes for a
|
|
7
|
+
// few hundred thousand characters), so this guards the heap-based merge.
|
|
8
|
+
describe('long runs without whitespace', () => {
|
|
9
|
+
test('encodes a 200,000-character run', () => {
|
|
10
|
+
expect(encodeCl100k('='.repeat(200_000))).toHaveLength(3125)
|
|
11
|
+
expect(encodeO200k('a'.repeat(200_000))).toHaveLength(25_000)
|
|
12
|
+
})
|
|
13
|
+
})
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_MERGE_CACHE_SIZE } from './constants.js'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
compareUint8Arrays,
|
|
4
|
+
isAscii,
|
|
5
|
+
startsWithByteOrderMark,
|
|
6
|
+
tryConvertToString,
|
|
7
|
+
} from './utfUtil.js'
|
|
3
8
|
import { escapeRegExp } from './util.js'
|
|
4
9
|
|
|
5
10
|
export type RawBytePairRanks = readonly (string | readonly number[])[]
|
|
@@ -19,7 +24,8 @@ export interface BytePairEncodingConfig {
|
|
|
19
24
|
|
|
20
25
|
const emptyBuffer = new Uint8Array(0)
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
// `ignoreBOM: true` keeps a leading U+FEFF in the decoded output.
|
|
28
|
+
export const decoder = new TextDecoder('utf8', { ignoreBOM: true })
|
|
23
29
|
|
|
24
30
|
export class BytePairEncodingCore {
|
|
25
31
|
readonly mergeableBytePairRankCount: number
|
|
@@ -70,6 +76,16 @@ export class BytePairEncodingCore {
|
|
|
70
76
|
const byteArray = new Uint8Array(value)
|
|
71
77
|
binaryLookup.push([byteArray, rank])
|
|
72
78
|
this.bytePairNonUtfRankDecoder.set(rank, byteArray)
|
|
79
|
+
if (startsWithByteOrderMark(byteArray)) {
|
|
80
|
+
// The rank tables keep tokens that start with a UTF-8 byte order mark
|
|
81
|
+
// (EF BB BF) as raw bytes, because a plain decode would strip the mark.
|
|
82
|
+
// They are still valid UTF-8, so they must also be reachable through
|
|
83
|
+
// the string lookup that getBpeRankFromBytes uses for valid UTF-8.
|
|
84
|
+
const asString = tryConvertToString(byteArray)
|
|
85
|
+
if (asString !== undefined) {
|
|
86
|
+
this.bytePairStringRankEncoder.set(asString, rank)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
73
89
|
})
|
|
74
90
|
this.bytePairNonUtfSortedEncoder = binaryLookup.sort((a, b) =>
|
|
75
91
|
compareUint8Arrays(a[0], b[0]),
|
|
@@ -453,87 +469,109 @@ export class BytePairEncodingCore {
|
|
|
453
469
|
// Input array of bytes to process
|
|
454
470
|
piece: Uint8Array,
|
|
455
471
|
): number[] {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
// '
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
//
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const key = piece.subarray(pairStart, pairEnd)
|
|
474
|
-
|
|
475
|
-
// Retrieve the BPE rank of this byte pair (if it exists)
|
|
476
|
-
const rank = this.getBpeRankFromBytes(key)
|
|
472
|
+
const { length } = piece
|
|
473
|
+
// Partitions form a linked list over byte offsets: a live partition starting at
|
|
474
|
+
// offset 'i' spans [i, next[i]). 'pairRanks[i]' is the rank of merging it with
|
|
475
|
+
// the partition after it. Merges come off a min-heap ordered by (rank, offset),
|
|
476
|
+
// which picks the same pair as scanning for the lowest rank, leftmost first,
|
|
477
|
+
// without rescanning the piece after every merge.
|
|
478
|
+
const next = new Int32Array(length + 1)
|
|
479
|
+
const previous = new Int32Array(length + 1)
|
|
480
|
+
const pairRanks = new Float64Array(length + 1)
|
|
481
|
+
const live = new Uint8Array(length + 1)
|
|
482
|
+
|
|
483
|
+
const getPairRank = (startIndex: number): number => {
|
|
484
|
+
const middle = next[startIndex]!
|
|
485
|
+
if (middle >= length) return Number.POSITIVE_INFINITY
|
|
486
|
+
const rank = this.getBpeRankFromBytes(
|
|
487
|
+
piece.subarray(startIndex, next[middle]!),
|
|
488
|
+
)
|
|
477
489
|
return rank ?? Number.POSITIVE_INFINITY
|
|
478
490
|
}
|
|
479
491
|
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
492
|
+
// Heap entries are packed as [rank, startIndex] pairs in a flat array
|
|
493
|
+
const heap: number[] = []
|
|
494
|
+
const isLower = (a: number, b: number) =>
|
|
495
|
+
heap[a]! < heap[b]! ||
|
|
496
|
+
(heap[a] === heap[b] && heap[a + 1]! < heap[b + 1]!)
|
|
497
|
+
const swap = (a: number, b: number) => {
|
|
498
|
+
const rank = heap[a]!
|
|
499
|
+
const startIndex = heap[a + 1]!
|
|
500
|
+
heap[a] = heap[b]!
|
|
501
|
+
heap[a + 1] = heap[b + 1]!
|
|
502
|
+
heap[b] = rank
|
|
503
|
+
heap[b + 1] = startIndex
|
|
490
504
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
const rank = ranks[i]!
|
|
500
|
-
if (rank < lowestRank) {
|
|
501
|
-
lowestRank = rank
|
|
502
|
-
lowestPartitionIndex = i
|
|
503
|
-
}
|
|
505
|
+
const push = (rank: number, startIndex: number) => {
|
|
506
|
+
heap.push(rank, startIndex)
|
|
507
|
+
let index = heap.length - 2
|
|
508
|
+
while (index > 0) {
|
|
509
|
+
const parent = (((index >> 1) - 1) >> 1) << 1
|
|
510
|
+
if (!isLower(index, parent)) break
|
|
511
|
+
swap(index, parent)
|
|
512
|
+
index = parent
|
|
504
513
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
514
|
+
}
|
|
515
|
+
const pop = () => {
|
|
516
|
+
const last = heap.length - 2
|
|
517
|
+
swap(0, last)
|
|
518
|
+
const rank = heap[last]!
|
|
519
|
+
const startIndex = heap[last + 1]!
|
|
520
|
+
heap.length = last
|
|
521
|
+
let index = 0
|
|
522
|
+
while (true) {
|
|
523
|
+
const left = index * 2 + 2
|
|
524
|
+
const right = left + 2
|
|
525
|
+
let lowest = index
|
|
526
|
+
if (left < heap.length && isLower(left, lowest)) lowest = left
|
|
527
|
+
if (right < heap.length && isLower(right, lowest)) lowest = right
|
|
528
|
+
if (lowest === index) break
|
|
529
|
+
swap(index, lowest)
|
|
530
|
+
index = lowest
|
|
512
531
|
}
|
|
532
|
+
return [rank, startIndex] as const
|
|
533
|
+
}
|
|
513
534
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
535
|
+
for (let i = 0; i <= length; i++) {
|
|
536
|
+
next[i] = i + 1
|
|
537
|
+
previous[i] = i - 1
|
|
538
|
+
live[i] = 1
|
|
539
|
+
}
|
|
540
|
+
for (let i = 0; i < length - 1; i++) {
|
|
541
|
+
pairRanks[i] = getPairRank(i)
|
|
542
|
+
if (pairRanks[i] !== Number.POSITIVE_INFINITY) push(pairRanks[i]!, i)
|
|
543
|
+
}
|
|
518
544
|
|
|
519
|
-
|
|
520
|
-
|
|
545
|
+
// Iteratively merge byte pairs until no more useful merges can be done
|
|
546
|
+
while (heap.length > 0) {
|
|
547
|
+
const [rank, startIndex] = pop()
|
|
548
|
+
// Skip entries made stale by an earlier merge
|
|
549
|
+
if (!live[startIndex] || pairRanks[startIndex] !== rank) continue
|
|
550
|
+
|
|
551
|
+
// Merge the partition at 'startIndex' with the one after it
|
|
552
|
+
const merged = next[startIndex]!
|
|
553
|
+
live[merged] = 0
|
|
554
|
+
next[startIndex] = next[merged]!
|
|
555
|
+
previous[next[merged]!] = startIndex
|
|
556
|
+
|
|
557
|
+
pairRanks[startIndex] = getPairRank(startIndex)
|
|
558
|
+
if (pairRanks[startIndex] !== Number.POSITIVE_INFINITY) {
|
|
559
|
+
push(pairRanks[startIndex]!, startIndex)
|
|
560
|
+
}
|
|
521
561
|
|
|
522
|
-
|
|
523
|
-
if (
|
|
524
|
-
|
|
562
|
+
const before = previous[startIndex]!
|
|
563
|
+
if (before >= 0) {
|
|
564
|
+
pairRanks[before] = getPairRank(before)
|
|
565
|
+
if (pairRanks[before] !== Number.POSITIVE_INFINITY) {
|
|
566
|
+
push(pairRanks[before]!, before)
|
|
567
|
+
}
|
|
525
568
|
}
|
|
526
569
|
}
|
|
527
570
|
|
|
528
571
|
// Create the final output by applying the transform function to each partitioned range
|
|
529
572
|
const output: number[] = []
|
|
530
|
-
for (let i = 0; i <
|
|
531
|
-
|
|
532
|
-
const pairEnd = starts[i + 1]
|
|
533
|
-
const bpeValue = this.getBpeRankFromBytesOrThrow(
|
|
534
|
-
piece.subarray(pairStart, pairEnd),
|
|
535
|
-
)
|
|
536
|
-
output.push(bpeValue)
|
|
573
|
+
for (let i = 0; i < length; i = next[i]!) {
|
|
574
|
+
output.push(this.getBpeRankFromBytesOrThrow(piece.subarray(i, next[i]!)))
|
|
537
575
|
}
|
|
538
576
|
return output
|
|
539
577
|
}
|