|
1 | 1 | 'use strict'; |
2 | 2 |
|
3 | 3 | const { |
| 4 | + Array, |
4 | 5 | BigInt, |
5 | 6 | FunctionPrototypeBind, |
6 | 7 | FunctionPrototypeCall, |
7 | 8 | MathMin, |
8 | 9 | NumberIsNaN, |
9 | 10 | NumberIsSafeInteger, |
| 11 | + NumberPrototypeToString, |
| 12 | + StringPrototypePadStart, |
10 | 13 | } = primordials; |
11 | 14 |
|
12 | 15 | const { |
@@ -291,104 +294,79 @@ function getRandomValues(data) { |
291 | 294 | // Implements an RFC 4122 version 4 random UUID. |
292 | 295 | // To improve performance, random data is generated in batches |
293 | 296 | // large enough to cover kBatchSize UUID's at a time. The uuidData |
294 | | -// and uuid buffers are reused. Each call to randomUUID() consumes |
295 | | -// 16 bytes from the buffer. |
296 | | - |
297 | | -const kHexDigits = [ |
298 | | - 48, 49, 50, 51, 52, 53, 54, 55, |
299 | | - 56, 57, 97, 98, 99, 100, 101, 102, |
300 | | -]; |
| 297 | +// buffer is reused. Each call to randomUUID() consumes 16 bytes |
| 298 | +// from the buffer. |
301 | 299 |
|
302 | 300 | const kBatchSize = 128; |
303 | 301 | let uuidData; |
304 | 302 | let uuidNotBuffered; |
305 | | -let uuid; |
306 | 303 | let uuidBatch = 0; |
307 | 304 |
|
308 | | -function getBufferedUUID() { |
309 | | - if (uuidData === undefined) { |
310 | | - uuidData = secureBuffer(16 * kBatchSize); |
311 | | - if (uuidData === undefined) |
312 | | - throw new ERR_OPERATION_FAILED('Out of memory'); |
| 305 | +let hexBytesCache; |
| 306 | +function getHexBytes() { |
| 307 | + if (hexBytesCache === undefined) { |
| 308 | + hexBytesCache = new Array(256); |
| 309 | + for (let i = 0; i < hexBytesCache.length; i++) { |
| 310 | + const hex = NumberPrototypeToString(i, 16); |
| 311 | + hexBytesCache[i] = StringPrototypePadStart(hex, 2, '0'); |
| 312 | + } |
313 | 313 | } |
| 314 | + return hexBytesCache; |
| 315 | +} |
| 316 | + |
| 317 | +function serializeUUID(buf, offset = 0) { |
| 318 | + const kHexBytes = getHexBytes(); |
| 319 | + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
| 320 | + return kHexBytes[buf[offset]] + |
| 321 | + kHexBytes[buf[offset + 1]] + |
| 322 | + kHexBytes[buf[offset + 2]] + |
| 323 | + kHexBytes[buf[offset + 3]] + |
| 324 | + '-' + |
| 325 | + kHexBytes[buf[offset + 4]] + |
| 326 | + kHexBytes[buf[offset + 5]] + |
| 327 | + '-' + |
| 328 | + kHexBytes[(buf[offset + 6] & 0x0f) | 0x40] + |
| 329 | + kHexBytes[buf[offset + 7]] + |
| 330 | + '-' + |
| 331 | + kHexBytes[(buf[offset + 8] & 0x3f) | 0x80] + |
| 332 | + kHexBytes[buf[offset + 9]] + |
| 333 | + '-' + |
| 334 | + kHexBytes[buf[offset + 10]] + |
| 335 | + kHexBytes[buf[offset + 11]] + |
| 336 | + kHexBytes[buf[offset + 12]] + |
| 337 | + kHexBytes[buf[offset + 13]] + |
| 338 | + kHexBytes[buf[offset + 14]] + |
| 339 | + kHexBytes[buf[offset + 15]]; |
| 340 | +} |
| 341 | + |
| 342 | +function getBufferedUUID() { |
| 343 | + uuidData ??= secureBuffer(16 * kBatchSize); |
| 344 | + if (uuidData === undefined) |
| 345 | + throw new ERR_OPERATION_FAILED('Out of memory'); |
314 | 346 |
|
315 | 347 | if (uuidBatch === 0) randomFillSync(uuidData); |
316 | 348 | uuidBatch = (uuidBatch + 1) % kBatchSize; |
317 | | - return uuidData.slice(uuidBatch * 16, (uuidBatch * 16) + 16); |
| 349 | + return serializeUUID(uuidData, uuidBatch * 16); |
| 350 | +} |
| 351 | + |
| 352 | +function getUnbufferedUUID() { |
| 353 | + uuidNotBuffered ??= secureBuffer(16); |
| 354 | + if (uuidNotBuffered === undefined) |
| 355 | + throw new ERR_OPERATION_FAILED('Out of memory'); |
| 356 | + randomFillSync(uuidNotBuffered); |
| 357 | + return serializeUUID(uuidNotBuffered); |
318 | 358 | } |
319 | 359 |
|
320 | 360 | function randomUUID(options) { |
321 | 361 | if (options !== undefined) |
322 | 362 | validateObject(options, 'options'); |
323 | 363 | const { |
324 | 364 | disableEntropyCache = false, |
325 | | - } = { ...options }; |
| 365 | + } = options || {}; |
326 | 366 |
|
327 | 367 | validateBoolean(disableEntropyCache, 'options.disableEntropyCache'); |
328 | 368 |
|
329 | | - if (uuid === undefined) { |
330 | | - uuid = Buffer.alloc(36, '-'); |
331 | | - uuid[14] = 52; // '4', identifies the UUID version |
332 | | - } |
333 | | - |
334 | | - let uuidBuf; |
335 | | - if (!disableEntropyCache) { |
336 | | - uuidBuf = getBufferedUUID(); |
337 | | - } else { |
338 | | - uuidBuf = uuidNotBuffered; |
339 | | - if (uuidBuf === undefined) |
340 | | - uuidBuf = uuidNotBuffered = secureBuffer(16); |
341 | | - if (uuidBuf === undefined) |
342 | | - throw new ERR_OPERATION_FAILED('Out of memory'); |
343 | | - randomFillSync(uuidBuf); |
344 | | - } |
345 | | - |
346 | | - // Variant byte: 10xxxxxx (variant 1) |
347 | | - uuidBuf[8] = (uuidBuf[8] & 0x3f) | 0x80; |
348 | | - |
349 | | - // This function is structured the way it is for performance. |
350 | | - // The uuid buffer stores the serialization of the random |
351 | | - // bytes from uuidData. |
352 | | - // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
353 | | - let n = 0; |
354 | | - uuid[0] = kHexDigits[uuidBuf[n] >> 4]; |
355 | | - uuid[1] = kHexDigits[uuidBuf[n++] & 0xf]; |
356 | | - uuid[2] = kHexDigits[uuidBuf[n] >> 4]; |
357 | | - uuid[3] = kHexDigits[uuidBuf[n++] & 0xf]; |
358 | | - uuid[4] = kHexDigits[uuidBuf[n] >> 4]; |
359 | | - uuid[5] = kHexDigits[uuidBuf[n++] & 0xf]; |
360 | | - uuid[6] = kHexDigits[uuidBuf[n] >> 4]; |
361 | | - uuid[7] = kHexDigits[uuidBuf[n++] & 0xf]; |
362 | | - // - |
363 | | - uuid[9] = kHexDigits[uuidBuf[n] >> 4]; |
364 | | - uuid[10] = kHexDigits[uuidBuf[n++] & 0xf]; |
365 | | - uuid[11] = kHexDigits[uuidBuf[n] >> 4]; |
366 | | - uuid[12] = kHexDigits[uuidBuf[n++] & 0xf]; |
367 | | - // - |
368 | | - // 4, uuid[14] is set already... |
369 | | - uuid[15] = kHexDigits[uuidBuf[n++] & 0xf]; |
370 | | - uuid[16] = kHexDigits[uuidBuf[n] >> 4]; |
371 | | - uuid[17] = kHexDigits[uuidBuf[n++] & 0xf]; |
372 | | - // - |
373 | | - uuid[19] = kHexDigits[uuidBuf[n] >> 4]; |
374 | | - uuid[20] = kHexDigits[uuidBuf[n++] & 0xf]; |
375 | | - uuid[21] = kHexDigits[uuidBuf[n] >> 4]; |
376 | | - uuid[22] = kHexDigits[uuidBuf[n++] & 0xf]; |
377 | | - // - |
378 | | - uuid[24] = kHexDigits[uuidBuf[n] >> 4]; |
379 | | - uuid[25] = kHexDigits[uuidBuf[n++] & 0xf]; |
380 | | - uuid[26] = kHexDigits[uuidBuf[n] >> 4]; |
381 | | - uuid[27] = kHexDigits[uuidBuf[n++] & 0xf]; |
382 | | - uuid[28] = kHexDigits[uuidBuf[n] >> 4]; |
383 | | - uuid[29] = kHexDigits[uuidBuf[n++] & 0xf]; |
384 | | - uuid[30] = kHexDigits[uuidBuf[n] >> 4]; |
385 | | - uuid[31] = kHexDigits[uuidBuf[n++] & 0xf]; |
386 | | - uuid[32] = kHexDigits[uuidBuf[n] >> 4]; |
387 | | - uuid[33] = kHexDigits[uuidBuf[n++] & 0xf]; |
388 | | - uuid[34] = kHexDigits[uuidBuf[n] >> 4]; |
389 | | - uuid[35] = kHexDigits[uuidBuf[n] & 0xf]; |
390 | | - |
391 | | - return uuid.latin1Slice(0, 36); |
| 369 | + return disableEntropyCache ? getUnbufferedUUID() : getBufferedUUID(); |
392 | 370 | } |
393 | 371 |
|
394 | 372 | function createRandomPrimeJob(type, size, options) { |
|
0 commit comments