Skip to content

Instantly share code, notes, and snippets.

@graup
Created November 12, 2018 20:18
Show Gist options
  • Save graup/815c9ac65c2bac8a56391f0ca23636fc to your computer and use it in GitHub Desktop.
Save graup/815c9ac65c2bac8a56391f0ca23636fc to your computer and use it in GitHub Desktop.
import JSBI from 'jsbi';
const useNativeBigIntsIfAvailable = true;
if (useNativeBigIntsIfAvailable) JSBI.useNativeBigIntsIfAvailable();
const BigInt = JSBI.BigInt
DataView.prototype._setBigUint64 = DataView.prototype.setBigUint64;
DataView.prototype.setBigUint64 = function(byteOffset, value, littleEndian) {
if (typeof value === 'bigint' && typeof this._setBigUint64 !== 'undefined') {
// the original native implementation for bigint
this._setBigUint64(byteOffset, value, littleEndian);
} else if (value.constructor === JSBI && typeof value.sign === 'bigint' && typeof this._setBigUint64 !== 'undefined') {
// JSBI wrapping a native bigint
this._setBigUint64(byteOffset, value.sign, littleEndian);
} else if (value.constructor === JSBI) {
// JSBI polyfill implementation
let lowWord = value[0], highWord = 0;
if (value.length >= 2) {
highWord = value[1];
}
this.setUint32(littleEndian ? 0 : 4, lowWord, littleEndian);
this.setUint32(littleEndian ? 4 : 0, highWord, littleEndian);
} else {
throw TypeError('Value needs to be BigInt ot JSBI');
}
}
DataView.prototype._getBigUint64 = DataView.prototype.getBigUint64;
DataView.prototype.getBigUint64 = function(byteOffset, littleEndian) {
if (typeof this._setBigUint64 !== 'undefined' && useNativeBigIntsIfAvailable) {
return BigInt(this._getBigUint64(byteOffset, littleEndian));
} else {
let lowWord = 0, highWord = 0;
lowWord = this.getUint32(littleEndian ? 0 : 4, littleEndian);
highWord = this.getUint32(littleEndian ? 4 : 0, littleEndian);
const result = new JSBI(2, false);
result.__setDigit(0, lowWord);
result.__setDigit(1, highWord);
return result;
}
}
const number = BigInt(String(2n ** 63n - 1n)); // '9223372036854775807'
console.log(number, String(number));
function toUint8Array(bigint, littleEndian = false) {
const arr = new ArrayBuffer(8);
const view = new DataView(arr);
view.setBigUint64(0, bigint, littleEndian);
return new Uint8Array(arr);
}
function fromUint8Array(uint8arr, littleEndian = false) {
const view = new DataView(uint8arr.buffer);
return view.getBigUint64(0, littleEndian);
}
const arr = toUint8Array(number, false);
console.log(arr);
console.log(fromUint8Array(arr, false), String(fromUint8Array(arr, false)));
const arr2 = toUint8Array(number, true);
console.log(arr2);
console.log(fromUint8Array(arr2, true), String(fromUint8Array(arr2, true)));
/*
Output for polyfilled implementation:
JSBI [ -1, 2147483647, sign: false ] '9223372036854775807'
Uint8Array [ 127, 255, 255, 255, 255, 255, 255, 255 ]
JSBI [ -1, 2147483647, sign: false ] '9223372036854775807'
Uint8Array [ 255, 255, 255, 255, 255, 255, 255, 127 ]
JSBI [ -1, 2147483647, sign: false ] '9223372036854775807'
Output for native implementation:
JSBI [ sign: 9223372036854775807n ] '9223372036854775807'
Uint8Array [ 127, 255, 255, 255, 255, 255, 255, 255 ]
JSBI [ sign: 9223372036854775807n ] '9223372036854775807'
Uint8Array [ 255, 255, 255, 255, 255, 255, 255, 127 ]
JSBI [ sign: 9223372036854775807n ] '9223372036854775807'
*/
@glr0221
Copy link

glr0221 commented Sep 10, 2020

Hello Paul,

First off, thank you so much for sharing this. It helped me a lot.

Having said that, I tried the above code when I had to polyfill the above functions for use with IE11. In my test runs, the above code had some issues originally, so I had to modify it.

My modifications on your code were referred from this : elk-chat

Here is the resulting code :

DataView.prototype._setBigUint64 = DataView.prototype.setBigUint64
DataView.prototype.setBigUint64 = function(byteOffset, value, littleEndian) {
    if (typeof value === 'bigint' && typeof this._setBigUint64 !== 'undefined') {
        // the original native implementation for bigint
        this._setBigUint64(byteOffset, value, littleEndian);
    } else if (value.constructor === JSBI && typeof value.sign === 'bigint' && typeof this._setBigUint64 !== 'undefined') {
        // JSBI wrapping a native bigint
        this._setBigUint64(byteOffset, value.sign, littleEndian);
    } else if (value.constructor === JSBI) {
        // JSBI polyfill implementation
        const lowWord = value[0];
        let highWord = 0;
        if (value.length >= 2) {
          highWord = value[1];
        }
        this.setUint32(byteOffset + (littleEndian ? 0 : 4), lowWord, littleEndian);
        this.setUint32(byteOffset + (littleEndian ? 4 : 0), highWord, littleEndian);
    } else {
        throw TypeError('Value needs to be BigInt ot JSBI');
    }
}

DataView.prototype._getBigUint64 = DataView.prototype.getBigUint64
DataView.prototype.getBigUint64 = function(byteOffset, littleEndian) {
    if (typeof this._setBigUint64 !== 'undefined' && useNativeBigIntsIfAvailable) {
        return BigInt(this._getBigUint64(byteOffset, littleEndian))
    } else {
        let lowWord = 0;
        let highWord = 0;
        lowWord = this.getUint32(byteOffset + (littleEndian ? 0 : 4), littleEndian);
        highWord = this.getUint32(byteOffset + (littleEndian ? 4 : 0), littleEndian);
        const result = new JSBI(2, false);
        result.__setDigit(0, lowWord);
        result.__setDigit(1, highWord);
        return result;
    }
}

I hope this helps.

@graup
Copy link
Author

graup commented Sep 10, 2020

Hi @glr0221, thanks for your comment! I see the original issue is still open. I tried to make this into a PR which didn't go anywhere, maybe you could try to contribute there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment