Last active
April 13, 2023 10:53
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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