Skip to content

Instantly share code, notes, and snippets.

@c7x43t
Last active April 13, 2023 10:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save c7x43t/8bb7d5292ce03bc0c318b1c538942af6 to your computer and use it in GitHub Desktop.
Save c7x43t/8bb7d5292ce03bc0c318b1c538942af6 to your computer and use it in GitHub Desktop.
Serialize a javascript BigInt space efficient and fast to an UInt8Array and back.
const big_zero = BigInt(0);
const big_16 = BigInt(16);
const big_2p16m1 = BigInt(2**16-1); // 0xFFFFn
function bigIntToUint16Array(bigInt) {
const bitLength = Math.ceil(Math.log2(Number(bigInt) + 1));
const arrayLength = (bitLength + 15) >>> 4;
const uint16Array = new Uint16Array(arrayLength);
let tempValue = bigInt;
for (let i = 0; i < arrayLength; i++) {
uint16Array[i] = Number(tempValue & big_2p16m1);
tempValue >>= big_16;
}
return uint16Array;
}
function uint16ArrayToBigInt(uint16Array) {
let bigInt = big_zero;
for (let i = uint16Array.length - 1; i >= 0; i--) {
bigInt = (bigInt << big_16) + BigInt(uint16Array[i]);
}
return bigInt;
}
const big_zero = BigInt(0);
const big_32 = BigInt(32);
const big_2p32m1 = BigInt(2**32-1); // 0xFFFFFFFFn
function bigIntToUint32Array(bigInt) {
const bitLength = Math.ceil(Math.log2(Number(bigInt) + 1));
const arrayLength = (bitLength + 31) >>> 5;
const uint32Array = new Uint32Array(arrayLength);
let tempValue = bigInt;
for (let i = 0; i < arrayLength; i++) {
uint32Array[i] = Number(tempValue & big_2p32m1);
tempValue >>= big_32;
}
return uint32Array;
}
function uint32ArrayToBigInt(uint32Array) {
let bigInt = big_zero;
for (let i = uint32Array.length - 1; i >= 0; i--) {
bigInt = (bigInt << big_32) + BigInt(uint32Array[i]);
}
return bigInt;
}
// https://jsben.ch/zsvOx
const big_zero = BigInt(0)
const big_one = BigInt(1)
const big_8 = BigInt(8);
const big2p8m1 = BigInt(2**8-1); // 0xFFn
function bigIntToUint8Array(bigInt) {
const sign = bigInt < big_zero ? 1 : 0;
const absoluteValue = bigInt < big_zero ? -bigInt : bigInt;
const bitLength = Math.ceil(Math.log2(Number(absoluteValue) + 1));
const byteLength = (bitLength + 7) >>> 3;
const bytes = new Uint8Array(byteLength + 1);
bytes[0] = sign;
let tempValue = absoluteValue;
for (let i = byteLength; i > 0; i--) {
bytes[i] = Number(tempValue & big2p8m1);
tempValue >>= big_8;
}
return bytes;
}
function uint8ArrayToBigInt(bytes) {
const sign = bytes[0] === 1 ? -big_one : big_one;
let bigInt = big_zero;
for (let i = 1; i < bytes.length; i++) {
bigInt = (bigInt << big_8) + BigInt(bytes[i]);
}
return bigInt * sign;
}
// Test:
// var bigInt = 2345234523234523452345234523452345234523536456345634563456345644234523421341245523452345232345234523452345234523452345235364563456345634563456442345234213412455n
// var uint8Array = bigIntToUint8Array(bigInt);
// var restoredBigInt = uint8ArrayToBigInt(uint8Array);
// bigInt === restoredBigInt
// How to determine which encoding to use:
var bigint = 123;
var big_max_safe = BigInt(Number.MAX_SAFE_INTEGER);
if(bigint<big_max_safe){
switch(~~(Math.log2(Number(bigint)) / 8)):
case 0:
var buf = new ArrayBuffer(1);
buf[0] = Number(BigInt)
case 1:
// to uint16
case 2:
// to uint32
}else{
bigIntToUint32Array
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment