Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34.3k
buffer: add swap16() and swap32() methods#5724
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| 'use strict'; | ||
| constcommon=require('../common.js'); | ||
| constbench=common.createBenchmark(main,{ | ||
| method: ['swap16','swap32','htons','htonl'], | ||
| len: [4,64,512,768,1024,1536,2056,4096,8192], | ||
| n: [1e6] | ||
| }); | ||
| // The htons and htonl methods below are used to benchmark the | ||
| // performance difference between doing the byteswap in pure | ||
| // javascript regardless of Buffer size as opposed to dropping | ||
| // down to the native layer for larger Buffer sizes. | ||
| Buffer.prototype.htons=functionhtons(){ | ||
| if(this.length%2!==0) | ||
| thrownewRangeError(); | ||
| for(vari=0,n=0;i<this.length;i+=2){ | ||
| n=this[i]; | ||
| this[i]=this[i+1]; | ||
| this[i+1]=n; | ||
| } | ||
| returnthis; | ||
| }; | ||
| Buffer.prototype.htonl=functionhtonl(){ | ||
| if(this.length%2!==0) | ||
| thrownewRangeError(); | ||
| for(vari=0,n=0;i<this.length;i+=4){ | ||
| n=this[i]; | ||
| this[i]=this[i+3]; | ||
| this[i+3]=n; | ||
| n=this[i+1]; | ||
| this[i+1]=this[i+2]; | ||
| this[i+2]=n; | ||
| } | ||
| returnthis; | ||
| }; | ||
| functioncreateBuffer(len){ | ||
| constbuf=Buffer.allocUnsafe(len); | ||
| for(vari=1;i<=len;i++) | ||
| buf[i-1]=i; | ||
| returnbuf; | ||
| } | ||
| functionbufferSwap(n,buf,method){ | ||
| for(vari=1;i<=n;i++) | ||
| buf[method](); | ||
| } | ||
| functionmain(conf){ | ||
| constmethod=conf.method; | ||
| constlen=conf.len|0; | ||
| constn=conf.n|0; | ||
| constbuf=createBuffer(len); | ||
| bench.start(); | ||
| bufferSwap(n,buf,method); | ||
| bench.end(n); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -17,6 +17,48 @@ var poolSize, poolOffset, allocPool; | ||
| binding.setupBufferJS(Buffer.prototype, bindingObj); | ||
| const swap16n = binding.swap16; | ||
| const swap32n = binding.swap32; | ||
| function swap(b, n, m){ | ||
| const i = b[n]; | ||
| b[n] = b[m]; | ||
| b[m] = i; | ||
| } | ||
| Buffer.prototype.swap16 = function swap16(){ | ||
| // For Buffer.length < 512, it's generally faster to | ||
| // do the swap in javascript. For larger buffers, | ||
| // dropping down to the native code is faster. | ||
| const len = this.length; | ||
| if (len % 2 !== 0) | ||
| throw new RangeError('Buffer length must be a multiple of 16-bits'); | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incredible nitpicking, but nonetheless I would opt for one of these:
or:
I hope you understand the nuance difference I'm getting at. MemberAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will change to | ||
| if (len < 512){ | ||
| for (var i = 0; i < len; i += 2) | ||
| swap(this, i, i + 1); | ||
| return this; | ||
| } | ||
| return swap16n.apply(this); | ||
| }; | ||
| Buffer.prototype.swap32 = function swap32(){ | ||
| // For Buffer.length < 1024, it's generally faster to | ||
| // do the swap in javascript. For larger buffers, | ||
| // dropping down to the native code is faster. | ||
| const len = this.length; | ||
| if (len % 4 !== 0) | ||
| throw new RangeError('Buffer length must be a multiple of 32-bits'); | ||
| if (len < 1024){ | ||
| for (var i = 0; i < len; i += 4){ | ||
| swap(this, i, i + 3); | ||
| swap(this, i + 1, i + 2); | ||
| } | ||
| return this; | ||
| } | ||
| return swap32n.apply(this); | ||
| }; | ||
| const flags = bindingObj.flags; | ||
| const kNoZeroFill = 0; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| 'use strict' | ||
| require('../common'); | ||
| const assert = require('assert'); | ||
| const buf = Buffer.from([0x1, 0x2, 0x3, 0x4]); | ||
| assert.strictEqual(buf, buf.swap16()); | ||
| assert.deepStrictEqual(buf, Buffer.from([0x2, 0x1, 0x4, 0x3])); | ||
| assert.strictEqual(buf, buf.swap32()); | ||
| assert.deepStrictEqual(buf, Buffer.from([0x3, 0x4, 0x1, 0x2])); | ||
| const buf_array = []; | ||
| for (var i = 1; i < 33; i++) | ||
| buf_array.push(i); | ||
| const buf2 = Buffer.from(buf_array); | ||
| buf2.swap32(); | ||
| assert.deepStrictEqual(buf2, | ||
| Buffer.from([0x04, 0x03, 0x02, 0x01, 0x08, 0x07, 0x06, 0x05, 0x0c, | ||
| 0x0b, 0x0a, 0x09, 0x10, 0x0f, 0x0e, 0x0d, 0x14, 0x13, | ||
| 0x12, 0x11, 0x18, 0x17, 0x16, 0x15, 0x1c, 0x1b, 0x1a, | ||
| 0x19, 0x20, 0x1f, 0x1e, 0x1d])); | ||
| buf2.swap16(); | ||
| assert.deepStrictEqual(buf2, | ||
| Buffer.from([0x03, 0x04, 0x01, 0x02, 0x07, 0x08, 0x05, 0x06, 0x0b, | ||
| 0x0c, 0x09, 0x0a, 0x0f, 0x10, 0x0d, 0x0e, 0x13, 0x14, | ||
| 0x11, 0x12, 0x17, 0x18, 0x15, 0x16, 0x1b, 0x1c, 0x19, | ||
| 0x1a, 0x1f, 0x20, 0x1d, 0x1e])); | ||
| const buf3 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7]); | ||
| buf3.slice(1, 5).swap32(); | ||
| assert.deepStrictEqual(buf3, Buffer.from([0x1, 0x5, 0x4, 0x3, 0x2, 0x6, 0x7])); | ||
| buf3.slice(1, 5).swap16(); | ||
| assert.deepStrictEqual(buf3, Buffer.from([0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7])); | ||
| // Force use of native code (Buffer size above threshold limit for js impl) | ||
| const buf4 = Buffer.allocUnsafe(1024).fill([0x1, 0x2, 0x3, 0x4]); | ||
| const buf5 = Buffer.allocUnsafe(1024).fill([0x2, 0x1, 0x4, 0x3]); | ||
| const buf6 = Buffer.allocUnsafe(1024) | ||
| .fill([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]); | ||
| const buf7 = Buffer.allocUnsafe(1024) | ||
| .fill([0x4, 0x3, 0x2, 0x1, 0x8, 0x7, 0x6, 0x5]); | ||
| buf4.swap16(); | ||
| assert.deepStrictEqual(buf4, buf5); | ||
| buf6.swap32(); | ||
| assert.deepStrictEqual(buf6, buf7); | ||
| const re16 = /Buffer length must be a multiple of 16-bits/; | ||
| const re32 = /Buffer length must be a multiple of 32-bits/; | ||
| assert.throws(() => Buffer.from(buf3).swap16(), re16); | ||
| assert.throws(() => Buffer.alloc(1025).swap16(), re16); | ||
| assert.throws(() => Buffer.from(buf3).swap32(), re32); | ||
| assert.throws(() => buf3.slice(1, 3).swap32(), re32); | ||
| assert.throws(() => Buffer.alloc(1025).swap32(), re32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is kinda confusing. htons is for converting between byte orders over the wire
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the term is used only in the benchmark and was selected because it's common for the operation. It's not actually used anywhere in the regular code or API.