Skip to content

Commit d1858ee

Browse files
authored
Merge pull request #225 from oschwald/greg/perf-improvements
feat: Performance improvements
2 parents 5fb47aa + 1218d66 commit d1858ee

File tree

4 files changed

+51
-81
lines changed

4 files changed

+51
-81
lines changed

src/decoder.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,30 @@ describe('lib/decoder', () => {
2727
});
2828
});
2929

30+
describe('decodeInt()', () => {
31+
const testCases = [
32+
{ expected: 0, input: [0x0, 0x1] },
33+
{ expected: -1, input: [0x4, 0x1, 0xff, 0xff, 0xff, 0xff] },
34+
{ expected: 255, input: [0x1, 0x1, 0xff] },
35+
{ expected: -255, input: [0x4, 0x1, 0xff, 0xff, 0xff, 0x1] },
36+
{ expected: 500, input: [0x2, 0x1, 0x1, 0xf4] },
37+
{ expected: -500, input: [0x4, 0x1, 0xff, 0xff, 0xfe, 0xc] },
38+
{ expected: 65535, input: [0x2, 0x1, 0xff, 0xff] },
39+
{ expected: -65535, input: [0x4, 0x1, 0xff, 0xff, 0x0, 0x1] },
40+
{ expected: 16777215, input: [0x3, 0x1, 0xff, 0xff, 0xff] },
41+
{ expected: -16777215, input: [0x4, 0x1, 0xff, 0x0, 0x0, 0x1] },
42+
{ expected: 2147483647, input: [0x4, 0x1, 0x7f, 0xff, 0xff, 0xff] },
43+
{ expected: -2147483647, input: [0x4, 0x1, 0x80, 0x0, 0x0, 0x1] },
44+
];
45+
46+
for (let tc of testCases) {
47+
it(`should decode to ${tc.expected}`, () => {
48+
const decoder = new Decoder(Buffer.from(tc.input));
49+
assert.deepStrictEqual(decoder.decode(0).value, tc.expected);
50+
});
51+
}
52+
});
53+
3054
describe('decode()', () => {
3155
it('should throw when extended type has wrong size', () => {
3256
const test = new Decoder(Buffer.from([0x00, 0x00]));

src/decoder.ts

Lines changed: 23 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -169,19 +169,11 @@ export default class Decoder {
169169
// At this point `size` is always 31.
170170
// If the value is 31, then the size is 65,821 + *the next three bytes after the
171171
// type specifying bytes as a single unsigned integer*.
172-
return cursor(
173-
65821 +
174-
utils.concat3(
175-
this.db[offset],
176-
this.db[offset + 1],
177-
this.db[offset + 2]
178-
),
179-
offset + 3
180-
);
172+
return cursor(65821 + this.db.readUIntBE(offset, 3), offset + 3);
181173
}
182174

183175
private decodeBytes(offset: number, size: number): Buffer {
184-
return this.db.slice(offset, offset + size);
176+
return this.db.subarray(offset, offset + size);
185177
}
186178

187179
private decodePointer(ctrlByte: number, offset: number): Cursor {
@@ -201,26 +193,17 @@ export default class Decoder {
201193
// If the size is 0, the pointer is built by appending the next byte to the last
202194
// three bits to produce an 11-bit value.
203195
if (pointerSize === 0) {
204-
packed = utils.concat2(ctrlByte & 7, this.db[offset]);
196+
packed = ((ctrlByte & 7) << 8) | this.db[offset];
205197

206198
// If the size is 1, the pointer is built by appending the next two bytes to the
207199
// last three bits to produce a 19-bit value + 2048.
208200
} else if (pointerSize === 1) {
209-
packed = utils.concat3(
210-
ctrlByte & 7,
211-
this.db[offset],
212-
this.db[offset + 1]
213-
);
201+
packed = ((ctrlByte & 7) << 16) | this.db.readUInt16BE(offset);
214202

215203
// If the size is 2, the pointer is built by appending the next three bytes to the
216204
// last three bits to produce a 27-bit value + 526336.
217205
} else if (pointerSize === 2) {
218-
packed = utils.concat4(
219-
ctrlByte & 7,
220-
this.db[offset],
221-
this.db[offset + 1],
222-
this.db[offset + 2]
223-
);
206+
packed = ((ctrlByte & 7) << 24) | this.db.readUIntBE(offset, 3);
224207

225208
// At next point `size` is always 3.
226209
// Finally, if the size is 3, the pointer's value is contained in the next four
@@ -236,12 +219,12 @@ export default class Decoder {
236219

237220
private decodeArray(size: number, offset: number): Cursor {
238221
let tmp;
239-
const array = [];
222+
const array = new Array(size);
240223

241224
for (let i = 0; i < size; i++) {
242225
tmp = this.decode(offset);
243226
offset = tmp.offset;
244-
array.push(tmp.value);
227+
array[i] = tmp.value;
245228
}
246229

247230
return cursor(array, offset);
@@ -280,40 +263,30 @@ export default class Decoder {
280263
if (size === 0) {
281264
return 0;
282265
}
266+
if (size < 4) {
267+
return this.db.readUIntBE(offset, size);
268+
}
283269
return this.db.readInt32BE(offset);
284270
}
285271

286272
private decodeUint(offset: number, size: number) {
287-
switch (size) {
288-
case 0:
289-
return 0;
290-
case 1:
291-
return this.db[offset];
292-
case 2:
293-
return utils.concat2(this.db[offset + 0], this.db[offset + 1]);
294-
case 3:
295-
return utils.concat3(
296-
this.db[offset + 0],
297-
this.db[offset + 1],
298-
this.db[offset + 2]
299-
);
300-
case 4:
301-
return utils.concat4(
302-
this.db[offset + 0],
303-
this.db[offset + 1],
304-
this.db[offset + 2],
305-
this.db[offset + 3]
306-
);
307-
case 8:
308-
return this.decodeBigUint(offset, size);
309-
case 16:
310-
return this.decodeBigUint(offset, size);
273+
if (size === 0) {
274+
return 0;
275+
}
276+
if (size <= 6) {
277+
return this.db.readUIntBE(offset, size);
278+
}
279+
if (size == 8) {
280+
return this.db.readBigInt64BE(offset).toString();
281+
}
282+
if (size > 16) {
283+
return 0;
311284
}
312-
return 0;
285+
return this.decodeBigUint(offset, size);
313286
}
314287

315288
private decodeString(offset: number, size: number) {
316-
return this.db.slice(offset, offset + size).toString();
289+
return this.db.toString('utf8', offset, offset + size);
317290
}
318291

319292
private decodeBigUint(offset: number, size: number) {

src/reader/walker.ts

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import utils from '../utils';
2-
31
type NodeReader = (offset: number) => number;
42

53
export interface Walker {
@@ -10,32 +8,22 @@ export interface Walker {
108
const readNodeRight24 =
119
(db: Buffer): NodeReader =>
1210
(offset: number): number =>
13-
utils.concat3(db[offset + 3], db[offset + 4], db[offset + 5]);
11+
db.readUIntBE(offset + 3, 3);
1412

1513
const readNodeLeft24 =
1614
(db: Buffer): NodeReader =>
1715
(offset: number): number =>
18-
utils.concat3(db[offset], db[offset + 1], db[offset + 2]);
16+
db.readUIntBE(offset, 3);
1917

2018
const readNodeLeft28 =
2119
(db: Buffer): NodeReader =>
2220
(offset: number): number =>
23-
utils.concat4(
24-
db[offset + 3] >> 4,
25-
db[offset],
26-
db[offset + 1],
27-
db[offset + 2]
28-
);
21+
((db[offset + 3] & 0xf0) << 20) | db.readUIntBE(offset, 3);
2922

3023
const readNodeRight28 =
3124
(db: Buffer): NodeReader =>
3225
(offset: number): number =>
33-
utils.concat4(
34-
db[offset + 3] & 0x0f,
35-
db[offset + 4],
36-
db[offset + 5],
37-
db[offset + 6]
38-
);
26+
((db[offset + 3] & 0x0f) << 24) | db.readUIntBE(offset + 4, 3);
3927

4028
const readNodeLeft32 =
4129
(db: Buffer): NodeReader =>

src/utils.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
const concat2 = (a: number, b: number): number => {
2-
return (a << 8) | b;
3-
};
4-
5-
const concat3 = (a: number, b: number, c: number): number => {
6-
return (a << 16) | (b << 8) | c;
7-
};
8-
9-
const concat4 = (a: number, b: number, c: number, d: number): number => {
10-
return (a << 24) | (b << 16) | (c << 8) | d;
11-
};
12-
131
const legacyErrorMessage = `Maxmind v2 module has changed API.\n\
142
Upgrade instructions can be found here: \
153
https://github.com/runk/node-maxmind/wiki/Migration-guide\n\
@@ -23,8 +11,5 @@ const assert = (condition: boolean, message: string): void => {
2311

2412
export default {
2513
assert,
26-
concat2,
27-
concat3,
28-
concat4,
2914
legacyErrorMessage,
3015
};

0 commit comments

Comments
 (0)