Skip to content

Commit 29851d5

Browse files
committed
feat: add swap methods.
1 parent b6ff2fa commit 29851d5

File tree

3 files changed

+236
-1
lines changed

3 files changed

+236
-1
lines changed

src/dynamicBuffer.ts

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { constants } from 'buffer';
22

33
import { DynamicBufferIterator } from './iterator';
4-
import { rangeCheck } from './utils';
4+
import { rangeCheck, swap } from './utils';
55

66
/**
77
* The character encoding that is supported by Node.js, copy from Node.js Buffer module.
@@ -737,6 +737,106 @@ export class DynamicBuffer {
737737
return this.buffer.copy(target, targetStart, sourceStart, sourceEnd);
738738
}
739739

740+
/**
741+
* Interprets buf as an array of unsigned 16-bit integers and swaps the byte order in-place.
742+
*
743+
* ```ts
744+
* const buf = new DynamicBuffer('ABCDEFGH');
745+
* buf.swap16();
746+
* console.log(buf.toString());
747+
* // BADCFEHG
748+
* ```
749+
*
750+
* @returns A reference to this buffer.
751+
*/
752+
swap16(): DynamicBuffer {
753+
if (this.length % 2 !== 0) {
754+
throw new RangeError('Buffer size must be a multiple of 2');
755+
}
756+
757+
if (this.length === 0 || !this.buffer) {
758+
return this;
759+
}
760+
761+
if (this.length < 128 || typeof this.buffer.swap16 !== 'function') {
762+
for (let i = 0; i < this.length; i += 2) {
763+
swap(this.buffer, i, i + 1);
764+
}
765+
} else {
766+
this.buffer.subarray(0, this.length).swap16();
767+
}
768+
769+
return this;
770+
}
771+
772+
/**
773+
* Interprets buf as an array of unsigned 32-bit integers and swaps the byte order in-place.
774+
*
775+
* ```ts
776+
* const buf = new DynamicBuffer('ABCDEFGH');
777+
* buf.swap32();
778+
* console.log(buf.toString());
779+
* // DCBAHGFE
780+
* ```
781+
*
782+
* @returns A reference to this buffer.
783+
*/
784+
swap32(): DynamicBuffer {
785+
if (this.length % 4 !== 0) {
786+
throw new RangeError('Buffer size must be a multiple of 4');
787+
}
788+
789+
if (this.length === 0 || !this.buffer) {
790+
return this;
791+
}
792+
793+
if (this.length < 192 || typeof this.buffer.swap32 !== 'function') {
794+
for (let i = 0; i < this.length; i += 4) {
795+
swap(this.buffer, i, i + 3);
796+
swap(this.buffer, i + 1, i + 2);
797+
}
798+
} else {
799+
this.buffer.subarray(0, this.length).swap32();
800+
}
801+
802+
return this;
803+
}
804+
805+
/**
806+
* Interprets buf as an array of unsigned 64-bit integers and swaps the byte order in-place.
807+
*
808+
* ```ts
809+
* const buf = new DynamicBuffer('ABCDEFGH');
810+
* buf.swap64();
811+
* console.log(buf.toString());
812+
* // HGFEDCBA
813+
* ```
814+
*
815+
* @returns A reference to this buffer.
816+
*/
817+
swap64(): DynamicBuffer {
818+
if (this.length % 8 !== 0) {
819+
throw new RangeError('Buffer size must be a multiple of 8');
820+
}
821+
822+
if (this.length === 0 || !this.buffer) {
823+
return this;
824+
}
825+
826+
if (this.length < 192 || typeof this.buffer.swap32 !== 'function') {
827+
for (let i = 0; i < this.length; i += 8) {
828+
swap(this.buffer, i, i + 7);
829+
swap(this.buffer, i + 1, i + 6);
830+
swap(this.buffer, i + 2, i + 5);
831+
swap(this.buffer, i + 3, i + 4);
832+
}
833+
} else {
834+
this.buffer.subarray(0, this.length).swap64();
835+
}
836+
837+
return this;
838+
}
839+
740840
/**
741841
* Write data into internal buffer with the specified offset.
742842
*

src/utils.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,14 @@ export const rangeCheck = (field: string, value: number, min?: number, max?: num
2323
* ```
2424
*/
2525
export const isDynamicBuffer = (val: any) => val instanceof DynamicBuffer;
26+
27+
/**
28+
* Swap two element in the buffer.
29+
*/
30+
export const swap = (buf: Buffer, i: number, j: number) => {
31+
const t = buf[i];
32+
// eslint-disable-next-line no-param-reassign
33+
buf[i] = buf[j];
34+
// eslint-disable-next-line no-param-reassign
35+
buf[j] = t;
36+
};

test/swap.spec.ts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import assert from 'assert';
2+
import { describe, it } from 'mocha';
3+
4+
import { DynamicBuffer } from '../src';
5+
6+
describe('Swap16 tests', () => {
7+
it('Test swap16.', () => {
8+
const buf = new DynamicBuffer('abcd');
9+
10+
buf.swap16();
11+
12+
assert.equal(buf.toString(), 'badc');
13+
});
14+
15+
it('Test swap16 with empty buffer.', () => {
16+
const buf = new DynamicBuffer();
17+
18+
buf.swap16();
19+
20+
assert.equal(buf.toString(), '');
21+
});
22+
23+
it('Test swap16 with invalid length.', () => {
24+
const buf = new DynamicBuffer('abc');
25+
26+
assert.throws(() => {
27+
buf.swap16();
28+
});
29+
});
30+
31+
it('Test swap16 with long string.', () => {
32+
const buf1 = new DynamicBuffer({ size: 512 });
33+
const buf2 = new DynamicBuffer({ size: 512 });
34+
35+
for (let i = 0; i < 512; i += 2) {
36+
buf1.append('AB');
37+
buf2.append('BA');
38+
}
39+
40+
buf1.swap16();
41+
42+
assert.equal(buf1.toString(), buf2.toString());
43+
});
44+
});
45+
46+
describe('Swap32 tests', () => {
47+
it('Test swap32.', () => {
48+
const buf = new DynamicBuffer('abcdefgh');
49+
50+
buf.swap32();
51+
52+
assert.equal(buf.toString(), 'dcbahgfe');
53+
});
54+
55+
it('Test swap32 with empty buffer.', () => {
56+
const buf = new DynamicBuffer();
57+
58+
buf.swap32();
59+
60+
assert.equal(buf.toString(), '');
61+
});
62+
63+
it('Test swap32 with invalid length.', () => {
64+
const buf = new DynamicBuffer('abc');
65+
66+
assert.throws(() => {
67+
buf.swap32();
68+
});
69+
});
70+
71+
it('Test swap32 with long string.', () => {
72+
const buf1 = new DynamicBuffer({ size: 512 });
73+
const buf2 = new DynamicBuffer({ size: 512 });
74+
75+
for (let i = 0; i < 512; i += 4) {
76+
buf1.append('ABCD');
77+
buf2.append('DCBA');
78+
}
79+
80+
buf1.swap32();
81+
82+
assert.equal(buf1.toString(), buf2.toString());
83+
});
84+
});
85+
86+
describe('Swap64 tests', () => {
87+
it('Test swap64.', () => {
88+
const buf = new DynamicBuffer('abcdefghijklmnop');
89+
90+
buf.swap64();
91+
92+
assert.equal(buf.toString(), 'hgfedcbaponmlkji');
93+
});
94+
95+
it('Test swap64 with empty buffer.', () => {
96+
const buf = new DynamicBuffer();
97+
98+
buf.swap64();
99+
100+
assert.equal(buf.toString(), '');
101+
});
102+
103+
it('Test swap64 with invalid length.', () => {
104+
const buf = new DynamicBuffer('abc');
105+
106+
assert.throws(() => {
107+
buf.swap64();
108+
});
109+
});
110+
111+
it('Test swap64 with long string.', () => {
112+
const buf1 = new DynamicBuffer({ size: 512 });
113+
const buf2 = new DynamicBuffer({ size: 512 });
114+
115+
for (let i = 0; i < 512; i += 8) {
116+
buf1.append('ABCDEFGH');
117+
buf2.append('HGFEDCBA');
118+
}
119+
120+
buf1.swap64();
121+
122+
assert.equal(buf1.toString(), buf2.toString());
123+
});
124+
});

0 commit comments

Comments
 (0)