Skip to content

Commit 1b08899

Browse files
committed
feat: single-byte encoder never returns pooled Uint8Arrays
Also, this is a performance improvement
1 parent ddaf7f7 commit 1b08899

File tree

3 files changed

+22
-10
lines changed

3 files changed

+22
-10
lines changed

single-byte.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { assertU8, E_STRING } from './fallback/_utils.js'
22
import { nativeDecoderLatin1, nativeEncoder } from './fallback/platform.js'
3-
import { encodeAscii, encodeAsciiPrefix, encodeLatin1 } from './fallback/latin1.js'
3+
import { encodeAsciiPrefix, encodeLatin1 } from './fallback/latin1.js'
44
import { assertEncoding, encodingDecoder, encodeMap, E_STRICT } from './fallback/single-byte.js'
55

66
const { TextDecoder, btoa } = globalThis
@@ -120,9 +120,8 @@ export function createSinglebyteEncoder(encoding, { mode = 'fatal' } = {}) {
120120
// Instead of an ASCII regex check, encode optimistically - this is faster
121121
// Check for 8-bit string with a regex though, this is instant on 8-bit strings so doesn't hurt the ASCII fast path
122122
if (nativeEncoder && !NON_LATIN.test(s)) {
123-
try {
124-
return encodeAscii(s, E_STRICT)
125-
} catch {}
123+
const u8 = nativeEncoder.encode(str)
124+
if (u8.length === str.length) return codes
126125
}
127126

128127
const res = encode(s, m)

single-byte.node.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,13 @@ export function createSinglebyteEncoder(encoding, { mode = 'fatal' } = {}) {
107107
// Instead of an ASCII regex check, encode optimistically - this is faster
108108
// Check for 8-bit string with a regex though, this is instant on 8-bit strings so doesn't hurt the ASCII fast path
109109
if (!NON_LATIN.test(s)) {
110-
const b = Buffer.from(s, 'utf8') // ascii/latin1 coerces, we need to check
111-
if (b.length === s.length) return new Uint8Array(b.buffer, b.byteOffset, b.byteLength)
110+
const byteLength = Buffer.byteLength(s)
111+
// ascii/latin1 coerces, we need to check
112+
if (byteLength === s.length) {
113+
const ab = new ArrayBuffer(byteLength)
114+
Buffer.from(ab).latin1Write(s)
115+
return new Uint8Array(ab)
116+
}
112117
}
113118

114119
const res = encode(s, m)

tests/single-byte.test.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ describe('single-byte encodings index: Unicode', () => {
159159
t.assert.strictEqual(decoderLoose(Uint8Array.of(byte)), str)
160160
t.assert.strictEqual(decoder(toShared(Uint8Array.of(byte))), str)
161161
t.assert.strictEqual(decoderLoose(toShared(Uint8Array.of(byte))), str)
162-
t.assert.deepStrictEqual(encoder(str), Uint8Array.of(byte))
162+
const u8 = encoder(str)
163+
t.assert.deepStrictEqual(u8, Uint8Array.of(byte))
164+
t.assert.strictEqual(u8.byteLength, u8.buffer.byteLength)
163165
}
164166
}
165167
})
@@ -214,7 +216,9 @@ describe('single-byte encodings index: WHATWG', () => {
214216
t.assert.strictEqual(str, decoderLoose(Uint8Array.of(byte)))
215217
t.assert.strictEqual(decoder(toShared(Uint8Array.of(byte))), str)
216218
t.assert.strictEqual(decoderLoose(toShared(Uint8Array.of(byte))), str)
217-
t.assert.deepStrictEqual(encoder(str), Uint8Array.of(byte))
219+
const u8 = encoder(str)
220+
t.assert.deepStrictEqual(u8, Uint8Array.of(byte))
221+
t.assert.strictEqual(u8.byteLength, u8.buffer.byteLength)
218222
} else {
219223
t.assert.throws(() => decoder(Uint8Array.of(byte)))
220224
t.assert.throws(() => decoder(toShared(Uint8Array.of(byte))))
@@ -263,7 +267,9 @@ describe('single-byte encodings index: WHATWG non-normative indexes.json', () =>
263267
t.assert.strictEqual(decoderLoose(Uint8Array.of(byte)), str)
264268
t.assert.strictEqual(decoder(toShared(Uint8Array.of(byte))), str)
265269
t.assert.strictEqual(decoderLoose(toShared(Uint8Array.of(byte))), str)
266-
t.assert.deepStrictEqual(encoder(str), Uint8Array.of(byte))
270+
const u8 = encoder(str)
271+
t.assert.deepStrictEqual(u8, Uint8Array.of(byte))
272+
t.assert.strictEqual(u8.byteLength, u8.buffer.byteLength)
267273
} else {
268274
t.assert.throws(() => decoder(Uint8Array.of(byte)))
269275
t.assert.throws(() => decoder(toShared(Uint8Array.of(byte))))
@@ -294,7 +300,9 @@ describe('x-user-defined', () => {
294300
const encoder = createSinglebyteEncoder(encoding)
295301
for (let byte = 0; byte < 256; byte++) {
296302
const str = String.fromCodePoint(byte >= 0x80 ? 0xf7_80 + byte - 0x80 : byte)
297-
t.assert.deepStrictEqual(encoder(str), Uint8Array.of(byte), byte)
303+
const u8 = encoder(str)
304+
t.assert.deepStrictEqual(u8, Uint8Array.of(byte))
305+
t.assert.strictEqual(u8.byteLength, u8.buffer.byteLength)
298306
}
299307

300308
for (let i = 128; i < 512; i++) {

0 commit comments

Comments
 (0)