Skip to content

Instantly share code, notes, and snippets.

@yanislav-igonin
Created March 13, 2024 10:45
Show Gist options
  • Save yanislav-igonin/8b6f179dc3da3dbcf10b47557d2f0141 to your computer and use it in GitHub Desktop.
Save yanislav-igonin/8b6f179dc3da3dbcf10b47557d2f0141 to your computer and use it in GitHub Desktop.
const encoder = new TextEncoder();
const decoder = new TextDecoder('utf-8', { ignoreBOM: true });
const U8 = {
/** @param {string} data */
encode: (data) => {
return encoder.encode(data);
},
/** @param {Uint8Array} data */
decode: (data) => {
return decoder.decode(data);
},
};
const Uint1Array = {
/* API */
encode: (bytes) => {
const bits = new Uint8Array(bytes.length * 8);
for (let cursor = 0, i = 0, l = bytes.length; i < l; i++) {
const byte = bytes[i];
bits[cursor++] = (byte >> 7) & 1;
bits[cursor++] = (byte >> 6) & 1;
bits[cursor++] = (byte >> 5) & 1;
bits[cursor++] = (byte >> 4) & 1;
bits[cursor++] = (byte >> 3) & 1;
bits[cursor++] = (byte >> 2) & 1;
bits[cursor++] = (byte >> 1) & 1;
bits[cursor++] = byte & 1;
}
return bits;
},
decode: (bits) => {
const bytes = new Uint8Array(Math.ceil(bits.length / 8));
for (let cursor = 0, i = 0, l = bits.length; i < l; i += 8) {
const b1 = bits[i];
const b2 = bits[i + 1] | 0;
const b3 = bits[i + 2] | 0;
const b4 = bits[i + 3] | 0;
const b5 = bits[i + 4] | 0;
const b6 = bits[i + 5] | 0;
const b7 = bits[i + 6] | 0;
const b8 = bits[i + 7] | 0;
bytes[cursor++] =
(b1 << 7) |
(b2 << 6) |
(b3 << 5) |
(b4 << 4) |
(b5 << 3) |
(b6 << 2) |
(b7 << 1) |
b8;
}
return bytes;
},
};
const Uint7Array = {
/* API */
encode: (bits) => {
const uint7 = new Uint8Array(Math.ceil(bits.length / 7) + 1);
for (let cursor = 0, i = 0, l = bits.length; i < l; i += 7) {
const b1 = bits[i];
const b2 = bits[i + 1] | 0;
const b3 = bits[i + 2] | 0;
const b4 = bits[i + 3] | 0;
const b5 = bits[i + 4] | 0;
const b6 = bits[i + 5] | 0;
const b7 = bits[i + 6] | 0;
uint7[cursor++] =
(b1 << 6) | (b2 << 5) | (b3 << 4) | (b4 << 3) | (b5 << 2) | (b6 << 1) | b7;
}
uint7[uint7.length - 1] = 7 - (bits.length % 7 || 7); // The last item contains the number of extra bits used for padding, that should be trimmed when decoding
return uint7;
},
decode: (uint7) => {
const bits = new Uint8Array(
Math.max(0, (uint7.length - 1) * 7 - (uint7[uint7.length - 1] || 0))
);
for (let cursor = 0, i = 0, l = uint7.length - 1; i < l; i++) {
const byte = uint7[i];
bits[cursor++] = (byte >> 6) & 1;
bits[cursor++] = (byte >> 5) & 1;
bits[cursor++] = (byte >> 4) & 1;
bits[cursor++] = (byte >> 3) & 1;
bits[cursor++] = (byte >> 2) & 1;
bits[cursor++] = (byte >> 1) & 1;
bits[cursor++] = byte & 1;
}
return bits;
},
};
const MAX_ARGUMENTS_LENGTH = 8192; // Above this threshold we risk a "call stack size exceeded" error
/** @param {ArrayLike<number> | Uint8Array | Uint16Array | Uint32Array} charCodes @returns {string} */
const fromCharCodes = (charCodes) => {
if (!Array.isArray(charCodes)) return fromCharCodes(Array.from(charCodes));
const { length } = charCodes;
if (length <= MAX_ARGUMENTS_LENGTH) {
// Small-enough length, no need to use chunks
return String.fromCharCode.apply(String, charCodes);
} else {
// Large-enough length, encoding in chunks
const chunks = [];
for (let ci = 0, i = 0; i < length; ci++) {
const slice = charCodes.slice(i, (i += MAX_ARGUMENTS_LENGTH));
chunks[ci] = String.fromCharCode.apply(String, slice);
}
return chunks.join('');
}
};
const Base128 = {
/* API */
encode: (data) => {
return fromCharCodes(Uint7Array.encode(Uint1Array.encode(data)));
},
encodeStr: (data) => {
return Base128.encode(U8.encode(data));
},
decode: (data) => {
const uint7 = new Uint8Array(data.length);
for (let i = 0, l = data.length; i < l; i++) {
uint7[i] = data.charCodeAt(i);
}
return Uint1Array.decode(Uint7Array.decode(uint7));
},
decodeStr: (data) => {
return U8.decode(Base128.decode(data));
},
};
const message = '201873|720489|123qweas|123qweas';
const encoded = Base128.encodeStr(message);
const decoded = Base128.decodeStr(encoded);
console.log(encoded);
console.log(decoded);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment