const _win: any = globalThis
const reverseUrlAlphabet = 'tcirzywvqlkjhgfbZQG_FLOWHSUBDNIMYREVKCAJxp57XP043891T62-modnaesu'
const urlAlphabet: string = reverseUrlAlphabet.split('').reverse().join('')
let buffer: Uint8Array
let bufferOffset: number
const allocBuffer = (bytes: number): Uint8Array => new Uint8Array(new ArrayBuffer(bytes))
const randomFill = (buffer: Uint8Array): Uint8Array => _win.crypto.getRandomValues(buffer)
const defFillPool = (bytes: number) => {
if (!buffer || buffer.length < bytes) {
buffer = allocBuffer(bytes * 128)
randomFill(buffer)
bufferOffset = 0
} else if (bufferOffset + bytes > buffer.length) {
randomFill(buffer)
bufferOffset = 0
}
bufferOffset += bytes
}
const nanoid = (size = 21) => {
defFillPool((size -= 0))
let uniq = ''
for (let i: number = bufferOffset - size; i < bufferOffset; i++) {
uniq += urlAlphabet[buffer[i] & 63]
}
return uniq
}
const defRandomFunc = (bytes: number) => {
defFillPool((bytes -= 0))
return buffer.subarray(bufferOffset - bytes, bufferOffset)
}
const defCustomRandom = (alphabet: string, defaultSize: number, randomFunc: (bytes: number) => Uint8Array) => {
const mask: number = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1
const step: number = Math.ceil((1.6 * mask * defaultSize) / alphabet.length)
return (size: number = defaultSize) => {
let uniq = ''
while (true) {
const bytes: Uint8Array = randomFunc(step)
let i: number = step
while (i--) {
uniq += alphabet[bytes[i] & mask] || ''
if (uniq.length === size) return uniq
}
}
}
}
const customAlphabet = (alphabet: string, defaultSize = 21) => defCustomRandom(alphabet, defaultSize, defRandomFunc)
export { urlAlphabet, nanoid, customAlphabet }