Skip to content

Commit 3a033f6

Browse files
authored
feat: optimize uuid.v1 by 1.3x uuid.v4 by 4.3x (430%) (#597)
This skips input validation when stringifying UUIDs that we _know_ are valid.
1 parent aa11485 commit 3a033f6

File tree

5 files changed

+45
-34
lines changed

5 files changed

+45
-34
lines changed

src/stringify.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ for (let i = 0; i < 256; ++i) {
1010
byteToHex.push((i + 0x100).toString(16).substr(1));
1111
}
1212

13-
function stringify(arr, offset = 0) {
13+
export function unsafeStringify(arr, offset = 0) {
1414
// Note: Be careful editing this code! It's been tuned for performance
1515
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
16-
const uuid = (
16+
return (
1717
byteToHex[arr[offset + 0]] +
1818
byteToHex[arr[offset + 1]] +
1919
byteToHex[arr[offset + 2]] +
@@ -35,7 +35,10 @@ function stringify(arr, offset = 0) {
3535
byteToHex[arr[offset + 14]] +
3636
byteToHex[arr[offset + 15]]
3737
).toLowerCase();
38+
}
3839

40+
function stringify(arr, offset = 0) {
41+
const uuid = unsafeStringify(arr, offset);
3942
// Consistency check for valid UUID. If this throws, it's likely due to one
4043
// of the following:
4144
// - One or more input array values don't map to a hex octet (leading to

src/v1.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import rng from './rng.js';
2-
import stringify from './stringify.js';
2+
import { unsafeStringify } from './stringify.js';
33

44
// **`v1()` - Generate time-based UUID**
55
//
@@ -109,7 +109,7 @@ function v1(options, buf, offset) {
109109
b[i + n] = node[n];
110110
}
111111

112-
return buf || stringify(b);
112+
return buf || unsafeStringify(b);
113113
}
114114

115115
export default v1;

src/v35.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import stringify from './stringify.js';
1+
import { unsafeStringify } from './stringify.js';
22
import parse from './parse.js';
33

44
function stringToBytes(str) {
@@ -51,7 +51,7 @@ export default function v35(name, version, hashfunc) {
5151
return buf;
5252
}
5353

54-
return stringify(bytes);
54+
return unsafeStringify(bytes);
5555
}
5656

5757
// Function#name is not settable on some platforms (#270)

src/v4.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import native from './native.js';
22
import rng from './rng.js';
3-
import stringify from './stringify.js';
3+
import { unsafeStringify } from './stringify.js';
44

55
function v4(options, buf, offset) {
66
if (native.randomUUID && !buf && !options) {
@@ -26,7 +26,7 @@ function v4(options, buf, offset) {
2626
return buf;
2727
}
2828

29-
return stringify(rnds);
29+
return unsafeStringify(rnds);
3030
}
3131

3232
export default v4;

test/unit/stringify.test.js

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,48 @@
11
import assert from 'assert';
2-
import stringify from '../../src/stringify.js';
2+
import stringify, { unsafeStringify } from '../../src/stringify.js';
33

44
const BYTES = [
55
0x0f, 0x5a, 0xbc, 0xd1, 0xc1, 0x94, 0x47, 0xf3, 0x90, 0x5b, 0x2d, 0xf7, 0x26, 0x3a, 0x08, 0x4b,
66
];
77

8-
describe('stringify', () => {
9-
test('Stringify Array', () => {
10-
assert.equal(stringify(BYTES), '0f5abcd1-c194-47f3-905b-2df7263a084b');
11-
});
8+
describe('unsafeStringify', () => {
9+
describe('default', () => {
10+
test('Stringify Array', () => {
11+
assert.equal(unsafeStringify(BYTES), '0f5abcd1-c194-47f3-905b-2df7263a084b');
12+
});
1213

13-
test('Stringify TypedArray', () => {
14-
assert.equal(stringify(Uint8Array.from(BYTES)), '0f5abcd1-c194-47f3-905b-2df7263a084b');
15-
assert.equal(stringify(Int32Array.from(BYTES)), '0f5abcd1-c194-47f3-905b-2df7263a084b');
16-
});
14+
test('Stringify TypedArray', () => {
15+
assert.equal(unsafeStringify(Uint8Array.from(BYTES)), '0f5abcd1-c194-47f3-905b-2df7263a084b');
16+
assert.equal(unsafeStringify(Int32Array.from(BYTES)), '0f5abcd1-c194-47f3-905b-2df7263a084b');
17+
});
1718

18-
test('Stringify w/ offset', () => {
19-
assert.equal(stringify([0, 0, 0, ...BYTES], 3), '0f5abcd1-c194-47f3-905b-2df7263a084b');
19+
test('Stringify w/ offset', () => {
20+
assert.equal(unsafeStringify([0, 0, 0, ...BYTES], 3), '0f5abcd1-c194-47f3-905b-2df7263a084b');
21+
});
2022
});
2123

22-
test('Throws on not enough values', () => {
23-
const bytes = [...BYTES];
24-
bytes.length = 15;
25-
assert.throws(() => stringify(bytes));
26-
});
24+
describe('safe', () => {
25+
test('Stringify Array', () => {
26+
assert.equal(stringify(BYTES), '0f5abcd1-c194-47f3-905b-2df7263a084b');
27+
});
2728

28-
test('Throws on undefined value', () => {
29-
const bytes = [...BYTES];
30-
delete bytes[3];
31-
bytes.length = 15;
32-
assert.throws(() => stringify(bytes));
33-
});
29+
test('Throws on not enough values', () => {
30+
const bytes = [...BYTES];
31+
bytes.length = 15;
32+
assert.throws(() => stringify(bytes));
33+
});
34+
35+
test('Throws on undefined value', () => {
36+
const bytes = [...BYTES];
37+
delete bytes[3];
38+
bytes.length = 15;
39+
assert.throws(() => stringify(bytes));
40+
});
3441

35-
test('Throws on invalid value', () => {
36-
const bytes = [...BYTES];
37-
bytes[3] = 256;
38-
assert.throws(() => stringify(bytes));
42+
test('Throws on invalid value', () => {
43+
const bytes = [...BYTES];
44+
bytes[3] = 256;
45+
assert.throws(() => stringify(bytes));
46+
});
3947
});
4048
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy