Buckets:
| const objectToString = Object.prototype.toString; | |
| const uint8ArrayStringified = '[object Uint8Array]'; | |
| const arrayBufferStringified = '[object ArrayBuffer]'; | |
| function isType(value, typeConstructor, typeStringified) { | |
| if (!value) { | |
| return false; | |
| } | |
| if (value.constructor === typeConstructor) { | |
| return true; | |
| } | |
| return objectToString.call(value) === typeStringified; | |
| } | |
| export function isUint8Array(value) { | |
| return isType(value, Uint8Array, uint8ArrayStringified); | |
| } | |
| function isArrayBuffer(value) { | |
| return isType(value, ArrayBuffer, arrayBufferStringified); | |
| } | |
| function isUint8ArrayOrArrayBuffer(value) { | |
| return isUint8Array(value) || isArrayBuffer(value); | |
| } | |
| export function assertUint8Array(value) { | |
| if (!isUint8Array(value)) { | |
| throw new TypeError(`Expected \`Uint8Array\`, got \`${typeof value}\``); | |
| } | |
| } | |
| export function assertUint8ArrayOrArrayBuffer(value) { | |
| if (!isUint8ArrayOrArrayBuffer(value)) { | |
| throw new TypeError(`Expected \`Uint8Array\` or \`ArrayBuffer\`, got \`${typeof value}\``); | |
| } | |
| } | |
| export function toUint8Array(value) { | |
| if (value instanceof ArrayBuffer) { | |
| return new Uint8Array(value); | |
| } | |
| if (ArrayBuffer.isView(value)) { | |
| return new Uint8Array(value.buffer, value.byteOffset, value.byteLength); | |
| } | |
| throw new TypeError(`Unsupported value, got \`${typeof value}\`.`); | |
| } | |
| export function concatUint8Arrays(arrays, totalLength) { | |
| if (arrays.length === 0) { | |
| return new Uint8Array(0); | |
| } | |
| totalLength ??= arrays.reduce((accumulator, currentValue) => accumulator + currentValue.length, 0); | |
| const returnValue = new Uint8Array(totalLength); | |
| let offset = 0; | |
| for (const array of arrays) { | |
| assertUint8Array(array); | |
| returnValue.set(array, offset); | |
| offset += array.length; | |
| } | |
| return returnValue; | |
| } | |
| export function areUint8ArraysEqual(a, b) { | |
| assertUint8Array(a); | |
| assertUint8Array(b); | |
| if (a === b) { | |
| return true; | |
| } | |
| if (a.length !== b.length) { | |
| return false; | |
| } | |
| // eslint-disable-next-line unicorn/no-for-loop | |
| for (let index = 0; index < a.length; index++) { | |
| if (a[index] !== b[index]) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| export function compareUint8Arrays(a, b) { | |
| assertUint8Array(a); | |
| assertUint8Array(b); | |
| const length = Math.min(a.length, b.length); | |
| for (let index = 0; index < length; index++) { | |
| const diff = a[index] - b[index]; | |
| if (diff !== 0) { | |
| return Math.sign(diff); | |
| } | |
| } | |
| // At this point, all the compared elements are equal. | |
| // The shorter array should come first if the arrays are of different lengths. | |
| return Math.sign(a.length - b.length); | |
| } | |
| const cachedDecoders = { | |
| utf8: new globalThis.TextDecoder('utf8'), | |
| }; | |
| export function uint8ArrayToString(array, encoding = 'utf8') { | |
| assertUint8ArrayOrArrayBuffer(array); | |
| cachedDecoders[encoding] ??= new globalThis.TextDecoder(encoding); | |
| return cachedDecoders[encoding].decode(array); | |
| } | |
| function assertString(value) { | |
| if (typeof value !== 'string') { | |
| throw new TypeError(`Expected \`string\`, got \`${typeof value}\``); | |
| } | |
| } | |
| const cachedEncoder = new globalThis.TextEncoder(); | |
| export function stringToUint8Array(string) { | |
| assertString(string); | |
| return cachedEncoder.encode(string); | |
| } | |
| function base64ToBase64Url(base64) { | |
| return base64.replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, ''); | |
| } | |
| function base64UrlToBase64(base64url) { | |
| const base64 = base64url.replaceAll('-', '+').replaceAll('_', '/'); | |
| const padding = (4 - (base64.length % 4)) % 4; | |
| return base64 + '='.repeat(padding); | |
| } | |
| // Reference: https://phuoc.ng/collection/this-vs-that/concat-vs-push/ | |
| // Important: Keep this value divisible by 3 so intermediate chunks produce no Base64 padding. | |
| const MAX_BLOCK_SIZE = 65_535; | |
| export function uint8ArrayToBase64(array, {urlSafe = false} = {}) { | |
| assertUint8Array(array); | |
| let base64 = ''; | |
| for (let index = 0; index < array.length; index += MAX_BLOCK_SIZE) { | |
| const chunk = array.subarray(index, index + MAX_BLOCK_SIZE); | |
| // Required as `btoa` and `atob` don't properly support Unicode: https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem | |
| base64 += globalThis.btoa(String.fromCodePoint.apply(undefined, chunk)); | |
| } | |
| return urlSafe ? base64ToBase64Url(base64) : base64; | |
| } | |
| export function base64ToUint8Array(base64String) { | |
| assertString(base64String); | |
| return Uint8Array.from(globalThis.atob(base64UrlToBase64(base64String)), x => x.codePointAt(0)); | |
| } | |
| export function stringToBase64(string, {urlSafe = false} = {}) { | |
| assertString(string); | |
| return uint8ArrayToBase64(stringToUint8Array(string), {urlSafe}); | |
| } | |
| export function base64ToString(base64String) { | |
| assertString(base64String); | |
| return uint8ArrayToString(base64ToUint8Array(base64String)); | |
| } | |
| const byteToHexLookupTable = Array.from({length: 256}, (_, index) => index.toString(16).padStart(2, '0')); | |
| export function uint8ArrayToHex(array) { | |
| assertUint8Array(array); | |
| // Concatenating a string is faster than using an array. | |
| let hexString = ''; | |
| // eslint-disable-next-line unicorn/no-for-loop -- Max performance is critical. | |
| for (let index = 0; index < array.length; index++) { | |
| hexString += byteToHexLookupTable[array[index]]; | |
| } | |
| return hexString; | |
| } | |
| const hexToDecimalLookupTable = { | |
| 0: 0, | |
| 1: 1, | |
| 2: 2, | |
| 3: 3, | |
| 4: 4, | |
| 5: 5, | |
| 6: 6, | |
| 7: 7, | |
| 8: 8, | |
| 9: 9, | |
| a: 10, | |
| b: 11, | |
| c: 12, | |
| d: 13, | |
| e: 14, | |
| f: 15, | |
| A: 10, | |
| B: 11, | |
| C: 12, | |
| D: 13, | |
| E: 14, | |
| F: 15, | |
| }; | |
| export function hexToUint8Array(hexString) { | |
| assertString(hexString); | |
| if (hexString.length % 2 !== 0) { | |
| throw new Error('Invalid Hex string length.'); | |
| } | |
| const resultLength = hexString.length / 2; | |
| const bytes = new Uint8Array(resultLength); | |
| for (let index = 0; index < resultLength; index++) { | |
| const highNibble = hexToDecimalLookupTable[hexString[index * 2]]; | |
| const lowNibble = hexToDecimalLookupTable[hexString[(index * 2) + 1]]; | |
| if (highNibble === undefined || lowNibble === undefined) { | |
| throw new Error(`Invalid Hex character encountered at position ${index * 2}`); | |
| } | |
| bytes[index] = (highNibble << 4) | lowNibble; // eslint-disable-line no-bitwise | |
| } | |
| return bytes; | |
| } | |
| /** | |
| @param {DataView} view | |
| @returns {number} | |
| */ | |
| export function getUintBE(view) { | |
| const {byteLength} = view; | |
| if (byteLength === 6) { | |
| return (view.getUint16(0) * (2 ** 32)) + view.getUint32(2); | |
| } | |
| if (byteLength === 5) { | |
| return (view.getUint8(0) * (2 ** 32)) + view.getUint32(1); | |
| } | |
| if (byteLength === 4) { | |
| return view.getUint32(0); | |
| } | |
| if (byteLength === 3) { | |
| return (view.getUint8(0) * (2 ** 16)) + view.getUint16(1); | |
| } | |
| if (byteLength === 2) { | |
| return view.getUint16(0); | |
| } | |
| if (byteLength === 1) { | |
| return view.getUint8(0); | |
| } | |
| } | |
| /** | |
| @param {Uint8Array} array | |
| @param {Uint8Array} value | |
| @returns {number} | |
| */ | |
| export function indexOf(array, value) { | |
| const arrayLength = array.length; | |
| const valueLength = value.length; | |
| if (valueLength === 0) { | |
| return -1; | |
| } | |
| if (valueLength > arrayLength) { | |
| return -1; | |
| } | |
| const validOffsetLength = arrayLength - valueLength; | |
| for (let index = 0; index <= validOffsetLength; index++) { | |
| let isMatch = true; | |
| for (let index2 = 0; index2 < valueLength; index2++) { | |
| if (array[index + index2] !== value[index2]) { | |
| isMatch = false; | |
| break; | |
| } | |
| } | |
| if (isMatch) { | |
| return index; | |
| } | |
| } | |
| return -1; | |
| } | |
| /** | |
| @param {Uint8Array} array | |
| @param {Uint8Array} value | |
| @returns {boolean} | |
| */ | |
| export function includes(array, value) { | |
| return indexOf(array, value) !== -1; | |
| } | |
Xet Storage Details
- Size:
- 7.37 kB
- Xet hash:
- 6c7519fcbff330696d05687c6d4d54466f48d2568e7b6681bf40bd47e569c642
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.