Last active
September 18, 2020 13:39
-
-
Save farzher/c8cd8c1354a53c054b09c1dd509a3336 to your computer and use it in GitHub Desktop.
for writing data to a compact custom binary format. serialize / save / send data over the network using the minimal amount of bits.
This file contains 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
function bitpacker(bytes=[]) { | |
return { | |
bytes: bytes, | |
bitcursor: 0, | |
write(bitcount, value) { | |
if(typeof value === 'string') value = value.charCodeAt(0) | |
else if(typeof value === 'boolean') value = value?1:0 | |
else if(value > 2**bitcount-1) value = 2**bitcount-1 // overflow will stay at max value instead of wrapping | |
for(let i=0;i<bitcount;i++) { | |
const bytesi = Math.floor(this.bitcursor/8) | |
if(this.bytes[bytesi] === undefined) this.bytes[bytesi] = 0 | |
this.bytes[bytesi] |= ((value>>>i)&1) << (this.bitcursor%8) | |
//this.bytes[bytesi] |= (value&(1<<i)?1:0) << this.bitcursor%8 | |
this.bitcursor++ | |
} | |
}, | |
read(bitcount, loopcount=1) { | |
const values = new Array(loopcount) | |
for(let l=0;l<loopcount;l++) { | |
let value = 0 | |
for(let i=0;i<bitcount;i++) { | |
const bytesi = Math.floor(this.bitcursor/8) | |
//value |= (this.bytes[bytesi]>>>(this.bitcursor%8) & 1) << i | |
value |= (this.bytes[bytesi]&(1<<(this.bitcursor%8))?1:0) << i | |
this.bitcursor++ | |
} | |
values[l] = value | |
} | |
return loopcount===1 ? values[0] : values | |
}, | |
} | |
} | |
;(() => { | |
// my data | |
const events = [{char:'h', ms:0, err:false}, {char:'i', ms:100, err:false}] | |
console.log('events', events) | |
// standard JSON.stringify | |
console.log('json', JSON.stringify(events)) // 67 bytes | |
function serialize(events) { | |
const bits = bitpacker() | |
events.forEach(e => bits.write(8, e.char)) | |
events.forEach(e => bits.write(13, e.ms)) | |
events.forEach(e => bits.write(1, e.err)) | |
return bits.bytes | |
} | |
console.log('bitpacker', serialize(events)) // 6 bytes | |
function deserialize(bytes) { | |
const bits = bitpacker(bytes) | |
const events = new Array(Math.floor(bytes.length*8 / (8+13+1))) | |
const chararr = bits.read(8, events.length) | |
const msarr = bits.read(13, events.length) | |
const errarr = bits.read(1, events.length) | |
for(let i=0;i<events.length;i++) events[i] = {char:String.fromCharCode(chararr[i]), ms:msarr[i], err:!!errarr[i]} | |
return events | |
} | |
console.log('serialize | deserialize', deserialize(serialize(events))) | |
ms = Date.now() | |
for(let i=0;i<1000000;i++) JSON.stringify(events) | |
console.log('json stringify took', Date.now() - ms, 'ms') | |
serial = JSON.stringify(events) | |
ms = Date.now() | |
for(let i=0;i<1000000;i++) JSON.parse(serial) | |
console.log('json parse took', Date.now() - ms, 'ms') | |
ms = Date.now() | |
for(let i=0;i<1000000;i++) serialize(events) | |
console.log('bitpacker serialize took', Date.now() - ms, 'ms') | |
serial = serialize(events) | |
ms = Date.now() | |
for(let i=0;i<1000000;i++) deserialize(serial) | |
console.log('bitpacker deserialize took', Date.now() - ms, 'ms') | |
})() | |
// copy paste into the browser console for a demo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment