xid-js
Version:
unique id generator for Node.js
128 lines (116 loc) • 2.77 kB
JavaScript
;
const crockford = '0123456789abcdefghjkmnpqrstvwxyz';
const padding = '='.charCodeAt(0);
const codebook = new Array(32);
for (let i = 0; i < 32; i += 1) {
codebook[i] = crockford.charCodeAt(i);
}
function pad(buff, ptr, trailing) {
let len = 8;
buff[ptr + 7] = padding;
if (trailing < 4) {
buff[ptr + 6] = padding;
buff[ptr + 5] = padding;
len -= 2;
if (trailing < 3) {
buff[ptr + 4] = padding;
len -= 1;
if (trailing < 2) {
buff[ptr + 3] = padding;
buff[ptr + 2] = padding;
len -= 2;
}
}
}
return len;
}
function encodeLength(n) {
const len = n / 5;
const precise = len | 0;
if (len === precise) {
return len * 8;
}
return (precise + 1) * 8;
}
function wrap(input) {
if (Buffer.isBuffer(input)) {
return input;
}
return Buffer.from(input);
}
/**
* Convert an input to an base32 encoded Buffer output.
*
* @param {Buffer|ArrayBuffer|Array|string} input
* @returns {Buffer}
*/
function encode(input) {
const src = wrap(input);
const len = src.length;
if (len === 0) {
return Buffer.alloc(0);
}
const dst = Buffer.allocUnsafe(encodeLength(len));
let offset = 0;
let written = 0;
while (offset < len) {
let b0;
let b1;
let b2;
let b3;
let b4;
let b5;
let b6;
let b7;
const remain = len - offset;
switch (remain) {
default:
b7 = src[offset + 4] & 0x1f;
b6 = src[offset + 3] >> 5;
// fallthrough
case 4:
b6 |= (src[offset + 3] << 3) & 0x1f;
b5 = (src[offset + 3] >> 2) & 0x1f;
b4 = src[offset + 3] >> 7;
// fallthrough
case 3:
b4 |= (src[offset + 2] << 1) & 0x1f;
b3 = (src[offset + 2] >> 4) & 0x1f;
// fallthrough
case 2:
b3 |= (src[offset + 1] << 4) & 0x1f;
b2 = (src[offset + 1] >> 1) & 0x1f;
b1 = (src[offset + 1] >> 6) & 0x1f;
// fallthrough
case 1:
b1 |= (src[offset] << 2) & 0x1f;
b0 = src[offset] >> 3;
}
dst[written] = codebook[b0];
dst[written + 1] = codebook[b1];
dst[written + 2] = codebook[b2];
dst[written + 3] = codebook[b3];
dst[written + 4] = codebook[b4];
dst[written + 5] = codebook[b5];
dst[written + 6] = codebook[b6];
dst[written + 7] = codebook[b7];
if (remain < 5) {
written += pad(dst, written, remain);
break;
}
written += 8;
offset += 5;
}
return dst.slice(0, written);
}
/**
* Convert an input to base32 encoded string output.
*
* @param {Buffer|ArrayBuffer|Array|string} input
* @returns {string|String}
*/
function encodeString(input) {
return encode(input).toString('ascii');
}
module.exports.encode = encode;
module.exports.encodeString = encodeString;