Skip to content

Instantly share code, notes, and snippets.

@farzher
Last active September 18, 2020 13:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save farzher/c8cd8c1354a53c054b09c1dd509a3336 to your computer and use it in GitHub Desktop.
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.
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