Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update hexSlice to use TypedArrays and TextDecoder for large speed gains #367

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
.airtap.yml
*.log
node_modules/
package-lock.json
perf/bundle.js
9 changes: 8 additions & 1 deletion AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@
- jkkang (jkkang@smartauth.kr)
- Deklan Webster (deklanw@gmail.com)
- Martin Heidegger (martin.heidegger@gmail.com)
- junderw (junderwood@bitcoinbank.co.jp)
- André Werlang (589286+awerlang@users.noreply.github.com)
- Bradley Odell (btodell@hotmail.com)
- Dominik Moritz (domoritz@gmail.com)
- Rachel Simone Weil (partytimehexcellent@gmail.com)
- Patrick McAndrew (urg@users.noreply.github.com)
- Jonathan Underwood (jonathan.underwood4649@gmail.com)
- Christopher Jeffrey (JJ) (chjjeffrey@gmail.com)
- George MacKerron (george@mackerron.co.uk)

#### Generated by bin/update-authors.sh.
60 changes: 45 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1083,16 +1083,45 @@ function latin1Slice (buf, start, end) {
}

function hexSlice (buf, start, end) {
const len = buf.length
const buflen = buf.length

if (!start || start < 0) start = 0
if (!end || end < 0 || end > len) end = len
if (!end || end < 0 || end > buflen) end = buflen

let out = ''
for (let i = start; i < end; ++i) {
out += hexSliceLookupTable[buf[i]]
buf = buf.subarray(start, end) // `slice` is deprecated

// buffer needs to be 4-byte aligned for what follows
if (buf.byteOffset % 4 !== 0) buf = new Uint8Array(buf)

const len = buf.length
const halfLen = len >>> 1
const quarterLen = len >>> 2
const out16 = new Uint16Array(len)
const buf32 = new Uint32Array(buf.buffer, buf.byteOffset, quarterLen)
const out32 = new Uint32Array(out16.buffer, out16.byteOffset, halfLen)
const lt = hexSliceLookupTable

// read 4 bytes (1x uint32) and write 8 bytes (2x uint32) at a time
let i = 0
let j = 0
let v
if (littleEndian) while (i < quarterLen) {
v = buf32[i++]
out32[j++] = lt[(v >>> 8) & 255] << 16 | lt[v & 255]
out32[j++] = lt[v >>> 24] << 16 | lt[(v >>> 16) & 255]
}
return out
else while (i < quarterLen) {
v = buf32[i++]
out32[j++] = lt[v >>> 24] << 16 | lt[(v >>> 16) & 255]
out32[j++] = lt[(v >>> 8) & 255] << 16 | lt[v & 255]
}

// deal with up to 3 remaining bytes
i <<= 2; // uint32 addressing to uint8 addressing
while (i < len) out16[i] = lt[buf[i++]]

const hex = textDecoder.decode(out16.subarray(0, len))
return hex
}

function utf16leSlice (buf, start, end) {
Expand Down Expand Up @@ -2091,16 +2120,17 @@ function numberIsNaN (obj) {
return obj !== obj // eslint-disable-line no-self-compare
}

// Create lookup table for `toString('hex')`
// See: https://github.com/feross/buffer/issues/219
// Create lookup table etc. for `toString('hex')`
const textDecoder = new TextDecoder()
const littleEndian = new Uint8Array((new Uint16Array([0x0102]).buffer))[0] === 0x02
const hexSliceLookupTable = (function () {
const alphabet = '0123456789abcdef'
const table = new Array(256)
for (let i = 0; i < 16; ++i) {
const i16 = i * 16
for (let j = 0; j < 16; ++j) {
table[i16 + j] = alphabet[i] + alphabet[j]
}
const alphabet = new TextEncoder().encode('0123456789abcdef')
const table = new Uint16Array(256)
if (littleEndian) for (let i = 0; i < 256; i++) {
table[i] = alphabet[i & 0xF] << 8 | alphabet[i >>> 4]
}
else for (let i = 0; i < 256; i++) {
table[i] = alphabet[i & 0xF] | alphabet[i >>> 4] << 8
}
return table
})()
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
},
"scripts": {
"perf": "browserify --debug perf/bracket-notation.js > perf/bundle.js && open perf/index.html",
"perf-node": "node perf/bracket-notation.js && node perf/concat.js && node perf/copy-big.js && node perf/copy.js && node perf/new-big.js && node perf/new.js && node perf/readDoubleBE.js && node perf/readFloatBE.js && node perf/readUInt32LE.js && node perf/slice.js && node perf/writeFloatBE.js && node perf/write-hex.js",
"perf-node": "node perf/bracket-notation.js && node perf/concat.js && node perf/copy-big.js && node perf/copy.js && node perf/new-big.js && node perf/new.js && node perf/readDoubleBE.js && node perf/readFloatBE.js && node perf/readUInt32LE.js && node perf/slice.js && node perf/toString-hex.js && node perf/writeFloatBE.js && node perf/write-hex.js",
"size": "browserify -r ./ | uglifyjs -c -m | gzip | wc -c",
"standard": "standard",
"test": "tape test/*.js test/node/*.js",
Expand Down
21 changes: 21 additions & 0 deletions perf/toString-hex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const BrowserBuffer = require('../').Buffer // (this module)
const util = require('./util')
const suite = util.suite()

const LENGTH = 4096
const browserSubject = BrowserBuffer.alloc(LENGTH)
const nodeSubject = Buffer.alloc(LENGTH)

for (let i = 0; i < LENGTH; i++) {
browserSubject[i] = nodeSubject[i] = (Math.random() * 255) << 0
}

suite
.add('BrowserBuffer#toString("hex")', function () {
browserSubject.toString('hex')
})

if (!process.browser) suite
.add('NodeBuffer#toString("hex")', function () {
nodeSubject.toString('hex')
})