@cloudpss/ubjson 0.4.15 → 0.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/benchmark-string-size-caculation.js +50 -0
- package/benchmark-string.js +3 -3
- package/benchmark.js +3 -3
- package/dist/common/decoder.js +3 -3
- package/dist/common/decoder.js.map +1 -1
- package/dist/common/encoder.d.ts +0 -1
- package/dist/common/encoder.js +26 -23
- package/dist/common/encoder.js.map +1 -1
- package/dist/common/string-decoder.js +3 -3
- package/dist/common/string-decoder.js.map +1 -1
- package/dist/common/string-encoder.d.ts +2 -0
- package/dist/common/string-encoder.js +51 -0
- package/dist/common/string-encoder.js.map +1 -1
- package/dist/decoder.d.ts +1 -2
- package/dist/decoder.js +1 -2
- package/dist/decoder.js.map +1 -1
- package/dist/encoder.js.map +1 -1
- package/dist/stream-helper/decoder.d.ts +2 -2
- package/dist/stream-helper/decoder.js +2 -2
- package/dist/stream-helper/decoder.js.map +1 -1
- package/dist/utils.js +3 -0
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/common/decoder.ts +3 -3
- package/src/common/encoder.ts +27 -25
- package/src/common/string-decoder.ts +3 -4
- package/src/common/string-encoder.ts +63 -0
- package/src/decoder.ts +1 -3
- package/src/encoder.ts +2 -4
- package/src/stream-helper/decoder.ts +3 -3
- package/src/utils.ts +3 -0
- package/tests/decode.js +12 -44
- package/tests/e2e.js +20 -21
- package/tests/encode.js +31 -53
- package/tests/huge-string.js +122 -0
- package/tests/rxjs/decode.js +18 -50
- package/tests/rxjs/encode.js +17 -61
- package/tests/stream/decode.js +17 -49
- package/tests/stream/encode.js +17 -61
- package/tests/string-encoding.js +4 -7
|
@@ -1,3 +1,58 @@
|
|
|
1
|
+
// https://github.com/ehmicky/string-byte-length/blob/main/src/char_code.js
|
|
2
|
+
|
|
3
|
+
// Last ASCII character (1 byte)
|
|
4
|
+
const LAST_ASCII_CODEPOINT = 0x7f;
|
|
5
|
+
// Last 2-bytes character
|
|
6
|
+
const LAST_TWO_BYTES_CODEPOINT = 0x7ff;
|
|
7
|
+
// Others are 3 bytes characters
|
|
8
|
+
// However, U+d800 to U+dbff:
|
|
9
|
+
// - Followed by U+dc00 to U+dfff -> 4 bytes together (astral character)
|
|
10
|
+
// - Otherwise -> 3 bytes (like above)
|
|
11
|
+
const FIRST_HIGH_SURROGATE = 0xd800;
|
|
12
|
+
const LAST_HIGH_SURROGATE = 0xdbff;
|
|
13
|
+
const FIRST_LOW_SURROGATE = 0xdc00;
|
|
14
|
+
const LAST_LOW_SURROGATE = 0xdfff;
|
|
15
|
+
/** 计算使用的空间 */
|
|
16
|
+
function getCharCodeByteLength(string: string): number {
|
|
17
|
+
const charLength = string.length;
|
|
18
|
+
let byteLength = charLength;
|
|
19
|
+
|
|
20
|
+
for (let charIndex = 0; charIndex < charLength; charIndex += 1) {
|
|
21
|
+
const codepoint = string.charCodeAt(charIndex);
|
|
22
|
+
|
|
23
|
+
if (codepoint <= LAST_ASCII_CODEPOINT) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (codepoint <= LAST_TWO_BYTES_CODEPOINT) {
|
|
28
|
+
byteLength += 1;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
byteLength += 2;
|
|
33
|
+
|
|
34
|
+
if (codepoint < FIRST_HIGH_SURROGATE || codepoint > LAST_HIGH_SURROGATE) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// When out-of-bound, this returns NaN, which is `false` with the
|
|
39
|
+
// next condition
|
|
40
|
+
const nextCodepoint = string.charCodeAt(charIndex + 1);
|
|
41
|
+
|
|
42
|
+
// High surrogates should be followed by low surrogates.
|
|
43
|
+
// However, JavaScript strings allow invalid surrogates, which are counted
|
|
44
|
+
// as a normal 3-byte character. This should not happen often in real code
|
|
45
|
+
// though.
|
|
46
|
+
if (nextCodepoint < FIRST_LOW_SURROGATE || nextCodepoint > LAST_LOW_SURROGATE) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
charIndex += 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return byteLength;
|
|
54
|
+
}
|
|
55
|
+
|
|
1
56
|
/** 字符串编码器 */
|
|
2
57
|
export class StringEncoder extends TextEncoder {
|
|
3
58
|
private readonly cache = new Map<string, Uint8Array>();
|
|
@@ -31,4 +86,12 @@ export class StringEncoder extends TextEncoder {
|
|
|
31
86
|
}
|
|
32
87
|
return buf;
|
|
33
88
|
}
|
|
89
|
+
|
|
90
|
+
/** 计算使用的空间 */
|
|
91
|
+
byteLength(value: string): number {
|
|
92
|
+
if (typeof Buffer == 'function' && typeof Buffer.byteLength == 'function') {
|
|
93
|
+
return Buffer.byteLength(value, 'utf8');
|
|
94
|
+
}
|
|
95
|
+
return getCharCodeByteLength(value);
|
|
96
|
+
}
|
|
34
97
|
}
|
package/src/decoder.ts
CHANGED
package/src/encoder.ts
CHANGED
|
@@ -38,7 +38,7 @@ export class Encoder extends EncoderBase {
|
|
|
38
38
|
// 为根 typed array 优化,减少不必要的分配
|
|
39
39
|
if (this.value.byteLength < 128) this.ensureCapacity(6 + this.value.byteLength);
|
|
40
40
|
else if (this.value.byteLength < 32768) this.ensureCapacity(7 + this.value.byteLength);
|
|
41
|
-
else if (this.value.byteLength <
|
|
41
|
+
else if (this.value.byteLength < 2_147_483_648) this.ensureCapacity(9 + this.value.byteLength);
|
|
42
42
|
else this.ensureCapacity(13 + this.value.byteLength);
|
|
43
43
|
this.writeTypedArray(this.value);
|
|
44
44
|
// 取消注释后运行测试
|
|
@@ -60,9 +60,7 @@ export class Encoder extends EncoderBase {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// 合并缓冲区
|
|
63
|
-
const result = new Uint8Array(
|
|
64
|
-
this.length + this.flushedBuffers.reduce((sum, buffer) => sum + buffer.byteLength, 0),
|
|
65
|
-
);
|
|
63
|
+
const result = new Uint8Array(this.length + this.flushedBuffers.reduce((sum, buffer) => sum + buffer.byteLength, 0));
|
|
66
64
|
let offset = 0;
|
|
67
65
|
for (const buffer of this.flushedBuffers) {
|
|
68
66
|
result.set(buffer, offset);
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { Decoder
|
|
2
|
-
|
|
3
|
-
export { UnexpectedEof };
|
|
1
|
+
import { Decoder } from '../common/decoder.js';
|
|
4
2
|
|
|
5
3
|
/** 流式解码 UBJSON */
|
|
6
4
|
export class StreamDecoderHelper extends Decoder {
|
|
@@ -13,3 +11,5 @@ export class StreamDecoderHelper extends Decoder {
|
|
|
13
11
|
return this.offset;
|
|
14
12
|
}
|
|
15
13
|
}
|
|
14
|
+
|
|
15
|
+
export { UnexpectedEof } from '../common/decoder.js';
|
package/src/utils.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** 支持的数据转为 Uint8Array */
|
|
2
2
|
export function toUint8Array(data: BinaryData): Uint8Array {
|
|
3
|
+
if (data == null || typeof data != 'object' || typeof data.byteLength != 'number') {
|
|
4
|
+
throw new TypeError('Invalid data');
|
|
5
|
+
}
|
|
3
6
|
if (ArrayBuffer.isView(data)) {
|
|
4
7
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
5
8
|
}
|
package/tests/decode.js
CHANGED
|
@@ -51,7 +51,7 @@ test('decode int16', () => {
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
test('decode int32', () => {
|
|
54
|
-
expect(decode(toBuffer('l', 0x12, 0x34, 0x56, 0x78))).toBe(
|
|
54
|
+
expect(decode(toBuffer('l', 0x12, 0x34, 0x56, 0x78))).toBe(0x1234_5678);
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
test('decode int64 [error]', () => {
|
|
@@ -59,11 +59,11 @@ test('decode int64 [error]', () => {
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
test('decode float32', () => {
|
|
62
|
-
expect(decode(toBuffer('d', 0x3f, 0x80, 0x80, 0x00))).toBe(1.
|
|
62
|
+
expect(decode(toBuffer('d', 0x3f, 0x80, 0x80, 0x00))).toBe(1.003_906_25);
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
test('decode float64', () => {
|
|
66
|
-
expect(decode(toBuffer('D', 0x40, 0xf8, 0x6a, 0x00, 0x10, 0x00, 0x00, 0x00))).toBe(
|
|
66
|
+
expect(decode(toBuffer('D', 0x40, 0xf8, 0x6a, 0x00, 0x10, 0x00, 0x00, 0x00))).toBe(100_000.003_906_25);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
test('decode high-precision number [error]', () => {
|
|
@@ -109,9 +109,7 @@ test('decode huge string', () => {
|
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
test('decode huge string [error]', () => {
|
|
112
|
-
expect(() => decode(toBuffer('S', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 'x'))).toThrow(
|
|
113
|
-
/Unsupported type int64/,
|
|
114
|
-
);
|
|
112
|
+
expect(() => decode(toBuffer('S', 'L', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 'x'))).toThrow(/Unsupported type int64/);
|
|
115
113
|
});
|
|
116
114
|
|
|
117
115
|
test('decode array', () => {
|
|
@@ -147,9 +145,10 @@ test('decode array (strongly typed, empty, optimized)', () => {
|
|
|
147
145
|
});
|
|
148
146
|
|
|
149
147
|
test('decode N-D array (strongly typed, optimized)', () => {
|
|
150
|
-
expect(
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
expect(decode(toBuffer('[', '$', '[', '#', 'i', 2, '$', 'i', '#', 'i', 3, 1, 2, 3, '$', 'i', '#', 'i', 3, 4, 5, 6))).toEqual([
|
|
149
|
+
new Int8Array([1, 2, 3]),
|
|
150
|
+
new Int8Array([4, 5, 6]),
|
|
151
|
+
]);
|
|
153
152
|
});
|
|
154
153
|
|
|
155
154
|
test('decode array of objects (optimized)', () => {
|
|
@@ -321,13 +320,11 @@ test('decode array (int16, strongly typed, optimized) [use typed array]', () =>
|
|
|
321
320
|
test('decode array (int32, strongly typed, optimized) [use typed array]', () => {
|
|
322
321
|
const actual = decode(toBuffer('[', '$', 'l', '#', 'i', 2, 0x12, 0x34, 0x56, 0x78, 0xfe, 0xdc, 0xba, 0x98));
|
|
323
322
|
expect(actual).toBeInstanceOf(Int32Array);
|
|
324
|
-
expect(actual).toEqual(Int32Array.from([
|
|
323
|
+
expect(actual).toEqual(Int32Array.from([305_419_896, -19_088_744]));
|
|
325
324
|
});
|
|
326
325
|
|
|
327
326
|
test('decode array (int64, strongly typed, optimized) [use typed array]', () => {
|
|
328
|
-
expect(() =>
|
|
329
|
-
decode(toBuffer('[', '$', 'L', '#', 'i', 1, 0x12, 0x34, 0x56, 0x78, 0xfe, 0xdc, 0xba, 0x98)),
|
|
330
|
-
).toThrow();
|
|
327
|
+
expect(() => decode(toBuffer('[', '$', 'L', '#', 'i', 1, 0x12, 0x34, 0x56, 0x78, 0xfe, 0xdc, 0xba, 0x98))).toThrow();
|
|
331
328
|
});
|
|
332
329
|
|
|
333
330
|
test('decode array (float32, strongly typed, optimized) [use typed array]', () => {
|
|
@@ -337,32 +334,7 @@ test('decode array (float32, strongly typed, optimized) [use typed array]', () =
|
|
|
337
334
|
});
|
|
338
335
|
|
|
339
336
|
test('decode array (float64, strongly typed, optimized) [use typed array]', () => {
|
|
340
|
-
const actual = decode(
|
|
341
|
-
toBuffer(
|
|
342
|
-
'[',
|
|
343
|
-
'$',
|
|
344
|
-
'D',
|
|
345
|
-
'#',
|
|
346
|
-
'i',
|
|
347
|
-
2,
|
|
348
|
-
0x3f,
|
|
349
|
-
0xd0,
|
|
350
|
-
0x00,
|
|
351
|
-
0x00,
|
|
352
|
-
0x00,
|
|
353
|
-
0x00,
|
|
354
|
-
0x00,
|
|
355
|
-
0x00,
|
|
356
|
-
0x3f,
|
|
357
|
-
0xc0,
|
|
358
|
-
0x00,
|
|
359
|
-
0x00,
|
|
360
|
-
0x00,
|
|
361
|
-
0x00,
|
|
362
|
-
0x00,
|
|
363
|
-
0x00,
|
|
364
|
-
),
|
|
365
|
-
);
|
|
337
|
+
const actual = decode(toBuffer('[', '$', 'D', '#', 'i', 2, 0x3f, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
|
|
366
338
|
expect(actual).toBeInstanceOf(Float64Array);
|
|
367
339
|
expect(actual).toEqual(Float64Array.from([0.25, 0.125]));
|
|
368
340
|
});
|
|
@@ -376,11 +348,7 @@ test('decode object', () => {
|
|
|
376
348
|
});
|
|
377
349
|
|
|
378
350
|
test('decode object (with no-op)', () => {
|
|
379
|
-
expect(
|
|
380
|
-
decode(
|
|
381
|
-
toBuffer('N', '{', 'N', 'i', 1, 'a', 'i', 1, 'i', 1, 'b', 'N', 'i', 2, 'i', 1, 'c', 'i', 3, 'N', '}', 'N'),
|
|
382
|
-
),
|
|
383
|
-
).toEqual({ a: 1, b: 2, c: 3 });
|
|
351
|
+
expect(decode(toBuffer('N', '{', 'N', 'i', 1, 'a', 'i', 1, 'i', 1, 'b', 'N', 'i', 2, 'i', 1, 'c', 'i', 3, 'N', '}', 'N'))).toEqual({ a: 1, b: 2, c: 3 });
|
|
384
352
|
});
|
|
385
353
|
|
|
386
354
|
test('decode array (empty, optimized)', () => {
|
package/tests/e2e.js
CHANGED
|
@@ -19,14 +19,14 @@ test('encode/decode complex object', () => {
|
|
|
19
19
|
id: 1,
|
|
20
20
|
name: 'test',
|
|
21
21
|
content: null,
|
|
22
|
-
timestamp:
|
|
22
|
+
timestamp: 1_532_432_408.008,
|
|
23
23
|
published: false,
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
id: 2,
|
|
27
27
|
name: 'lorem',
|
|
28
28
|
content: 'Lorem ipsum...',
|
|
29
|
-
timestamp:
|
|
29
|
+
timestamp: 1_532_432_416.346,
|
|
30
30
|
published: true,
|
|
31
31
|
},
|
|
32
32
|
],
|
|
@@ -34,12 +34,12 @@ test('encode/decode complex object', () => {
|
|
|
34
34
|
traces: [
|
|
35
35
|
{
|
|
36
36
|
name: 'test',
|
|
37
|
-
x: new Float64Array([1, 2, 3,
|
|
37
|
+
x: new Float64Array([1, 2, 3, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, Number.MAX_VALUE, Number.MIN_VALUE]),
|
|
38
38
|
y: new Int8Array([0, 4, 5, 6, -128, -1, 127]),
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
name: 'test2',
|
|
42
|
-
x: new Float32Array([1, 2, 3,
|
|
42
|
+
x: new Float32Array([1, 2, 3, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, Number.MAX_VALUE, Number.MIN_VALUE]),
|
|
43
43
|
y: new Int16Array([4, 5, 6, -32768, 32767]),
|
|
44
44
|
},
|
|
45
45
|
{
|
|
@@ -52,7 +52,7 @@ test('encode/decode complex object', () => {
|
|
|
52
52
|
description1: 'medium text'.repeat(100),
|
|
53
53
|
description2: 'medium text'.repeat(1000),
|
|
54
54
|
document1: 'long text'.repeat(10000),
|
|
55
|
-
document2: 'long text'.repeat(
|
|
55
|
+
document2: 'long text'.repeat(100_000),
|
|
56
56
|
};
|
|
57
57
|
const encoded = encode(expected);
|
|
58
58
|
const actual = decode(Buffer.from(encoded));
|
|
@@ -78,7 +78,7 @@ test('encode/decode model', () => {
|
|
|
78
78
|
pins: {
|
|
79
79
|
input: {
|
|
80
80
|
position: {
|
|
81
|
-
x: 0.
|
|
81
|
+
x: 0.999_999_9,
|
|
82
82
|
y: 0.5,
|
|
83
83
|
},
|
|
84
84
|
},
|
|
@@ -90,7 +90,7 @@ test('encode/decode model', () => {
|
|
|
90
90
|
},
|
|
91
91
|
electrical: {
|
|
92
92
|
position: {
|
|
93
|
-
x: 0.
|
|
93
|
+
x: 0.999_999_9,
|
|
94
94
|
y: 0.5,
|
|
95
95
|
},
|
|
96
96
|
},
|
|
@@ -102,7 +102,7 @@ test('encode/decode model', () => {
|
|
|
102
102
|
refPath: {
|
|
103
103
|
d: 'm90000 0h-60000a10000 10000 0 0 0 0 20000h60000zm0 10000h20000',
|
|
104
104
|
h: 20000,
|
|
105
|
-
w:
|
|
105
|
+
w: 110_000,
|
|
106
106
|
},
|
|
107
107
|
fillOpacity: 'var(--fill-opacity)',
|
|
108
108
|
strokeWidth: 'var(--stroke-width)',
|
|
@@ -114,7 +114,7 @@ test('encode/decode model', () => {
|
|
|
114
114
|
refPath: {
|
|
115
115
|
d: 'm90000 0h-60000a10000 10000 0 0 0 0 20000h60000zm0 10000h20000',
|
|
116
116
|
h: 20000,
|
|
117
|
-
w:
|
|
117
|
+
w: 110_000,
|
|
118
118
|
},
|
|
119
119
|
fillOpacity: 'var(--fill-opacity)',
|
|
120
120
|
strokeWidth: 'var(--stroke-width)',
|
|
@@ -126,7 +126,7 @@ test('encode/decode model', () => {
|
|
|
126
126
|
refPath: {
|
|
127
127
|
d: 'm20000 10000m-5000 -5000l5000 5000l-5000 5000',
|
|
128
128
|
h: 20000,
|
|
129
|
-
w:
|
|
129
|
+
w: 110_000,
|
|
130
130
|
},
|
|
131
131
|
fillOpacity: 'var(--fill-opacity)',
|
|
132
132
|
strokeWidth: 'var(--stroke-width)',
|
|
@@ -138,7 +138,7 @@ test('encode/decode model', () => {
|
|
|
138
138
|
refPath: {
|
|
139
139
|
d: 'm20000 0h60000a10000 10000 0 0 1 0 20000h-60000zm0 10000h-20000',
|
|
140
140
|
h: 20000,
|
|
141
|
-
w:
|
|
141
|
+
w: 110_000,
|
|
142
142
|
},
|
|
143
143
|
fillOpacity: 'var(--fill-opacity)',
|
|
144
144
|
strokeWidth: 'var(--stroke-width)',
|
|
@@ -150,7 +150,7 @@ test('encode/decode model', () => {
|
|
|
150
150
|
refPath: {
|
|
151
151
|
d: 'm110000 10000m-5000 -5000l5000 5000l-5000 5000',
|
|
152
152
|
h: 20000,
|
|
153
|
-
w:
|
|
153
|
+
w: 110_000,
|
|
154
154
|
},
|
|
155
155
|
fillOpacity: 'var(--fill-opacity)',
|
|
156
156
|
strokeWidth: 'var(--stroke-width)',
|
|
@@ -219,8 +219,7 @@ test('encode/decode model', () => {
|
|
|
219
219
|
name: 'Pin Key',
|
|
220
220
|
type: 'choice',
|
|
221
221
|
value: '',
|
|
222
|
-
choices:
|
|
223
|
-
'=mapper(p,index,array) = {key: p.key, name: p.key, description: p.description};\n$$.revision.pins.map(mapper)',
|
|
222
|
+
choices: '=mapper(p,index,array) = {key: p.key, name: p.key, description: p.description};\n$$.revision.pins.map(mapper)',
|
|
224
223
|
condition: 'true',
|
|
225
224
|
description: '绑定端口',
|
|
226
225
|
},
|
|
@@ -298,14 +297,14 @@ test('encode/decode complex object (no encodeInto)', () => {
|
|
|
298
297
|
id: 1,
|
|
299
298
|
name: 'test',
|
|
300
299
|
content: null,
|
|
301
|
-
timestamp:
|
|
300
|
+
timestamp: 1_532_432_408.008,
|
|
302
301
|
published: false,
|
|
303
302
|
},
|
|
304
303
|
{
|
|
305
304
|
id: 2,
|
|
306
305
|
name: 'lorem',
|
|
307
306
|
content: 'Lorem ipsum...',
|
|
308
|
-
timestamp:
|
|
307
|
+
timestamp: 1_532_432_416.346,
|
|
309
308
|
published: true,
|
|
310
309
|
},
|
|
311
310
|
],
|
|
@@ -313,12 +312,12 @@ test('encode/decode complex object (no encodeInto)', () => {
|
|
|
313
312
|
traces: [
|
|
314
313
|
{
|
|
315
314
|
name: 'test',
|
|
316
|
-
x: new Float64Array([1, 2, 3,
|
|
315
|
+
x: new Float64Array([1, 2, 3, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, Number.MAX_VALUE, Number.MIN_VALUE]),
|
|
317
316
|
y: new Int8Array([0, 4, 5, 6, -128, -1, 127]),
|
|
318
317
|
},
|
|
319
318
|
{
|
|
320
319
|
name: 'test2',
|
|
321
|
-
x: new Float32Array([1, 2, 3,
|
|
320
|
+
x: new Float32Array([1, 2, 3, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN, Number.MAX_VALUE, Number.MIN_VALUE]),
|
|
322
321
|
y: new Int16Array([4, 5, 6, -32768, 32767]),
|
|
323
322
|
},
|
|
324
323
|
{
|
|
@@ -331,7 +330,7 @@ test('encode/decode complex object (no encodeInto)', () => {
|
|
|
331
330
|
description1: 'medium text'.repeat(100),
|
|
332
331
|
description2: 'medium text'.repeat(1000),
|
|
333
332
|
document1: 'long text'.repeat(10000),
|
|
334
|
-
document2: 'long text'.repeat(
|
|
333
|
+
document2: 'long text'.repeat(100_000),
|
|
335
334
|
};
|
|
336
335
|
const encoded = encode(expected);
|
|
337
336
|
const actual = decode(encoded);
|
|
@@ -340,10 +339,10 @@ test('encode/decode complex object (no encodeInto)', () => {
|
|
|
340
339
|
});
|
|
341
340
|
|
|
342
341
|
test('encode/decode large array', () => {
|
|
343
|
-
const array =
|
|
342
|
+
const array = Array.from({ length: 100_000 });
|
|
344
343
|
array[12345] = 'item';
|
|
345
344
|
|
|
346
|
-
const expected = Array.from({ length:
|
|
345
|
+
const expected = Array.from({ length: 100_000 }).fill(null);
|
|
347
346
|
expected[12345] = 'item';
|
|
348
347
|
|
|
349
348
|
expect(decode(encode(array))).toEqual(expected);
|
package/tests/encode.js
CHANGED
|
@@ -50,19 +50,19 @@ test('encode int16', () => {
|
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
test('encode int32', () => {
|
|
53
|
-
expect(toArray(encode(
|
|
53
|
+
expect(toArray(encode(0x1234_5678))).toEqual(toArray('l', 0x12, 0x34, 0x56, 0x78));
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
test('encode float32', () => {
|
|
57
|
-
expect(toArray(encode(1.
|
|
57
|
+
expect(toArray(encode(1.003_906_25))).toEqual(toArray('d', 0x3f, 0x80, 0x80, 0x00));
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
test('encode float32 (too large integer)', () => {
|
|
61
|
-
expect(toArray(encode(
|
|
61
|
+
expect(toArray(encode(2_147_483_648))).toEqual(toArray('d', 0x4f, 0x00, 0x00, 0x00));
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
test('encode float64', () => {
|
|
65
|
-
expect(toArray(encode(
|
|
65
|
+
expect(toArray(encode(100_000.003_906_25))).toEqual(toArray('D', 0x40, 0xf8, 0x6a, 0x00, 0x10, 0x00, 0x00, 0x00));
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
test('encode char', () => {
|
|
@@ -70,7 +70,7 @@ test('encode char', () => {
|
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
test('encode char 128', () => {
|
|
73
|
-
expect(toArray(encode('\
|
|
73
|
+
expect(toArray(encode('\u00CC'))).toEqual(toArray('C', '\u00CC'));
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
test('encode char 257', () => {
|
|
@@ -109,7 +109,7 @@ test('encode array (undefined)', () => {
|
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
test('encode array (spares)', () => {
|
|
112
|
-
const array =
|
|
112
|
+
const array = Array.from({ length: 3 });
|
|
113
113
|
array[1] = true;
|
|
114
114
|
expect(toArray(encode(array))).toEqual(toArray('[', 'Z', 'T', 'Z', ']'));
|
|
115
115
|
});
|
|
@@ -185,49 +185,22 @@ test('encode array (buffer array)', () => {
|
|
|
185
185
|
});
|
|
186
186
|
|
|
187
187
|
test('encode array (int16 typed array)', () => {
|
|
188
|
-
expect(toArray(encode(Int16Array.from([4660, -292])))).toEqual(
|
|
189
|
-
toArray('[', '$', 'I', '#', 'i', 2, 0x12, 0x34, 0xfe, 0xdc),
|
|
190
|
-
);
|
|
188
|
+
expect(toArray(encode(Int16Array.from([4660, -292])))).toEqual(toArray('[', '$', 'I', '#', 'i', 2, 0x12, 0x34, 0xfe, 0xdc));
|
|
191
189
|
});
|
|
192
190
|
|
|
193
191
|
test('encode array (int32 typed array)', () => {
|
|
194
|
-
expect(toArray(encode(Int32Array.from([
|
|
192
|
+
expect(toArray(encode(Int32Array.from([305_419_896, -19_088_744])))).toEqual(
|
|
195
193
|
toArray('[', '$', 'l', '#', 'i', 2, 0x12, 0x34, 0x56, 0x78, 0xfe, 0xdc, 0xba, 0x98),
|
|
196
194
|
);
|
|
197
195
|
});
|
|
198
196
|
|
|
199
197
|
test('encode array (float32 typed array)', () => {
|
|
200
|
-
expect(toArray(encode(Float32Array.from([0.25, 0.125])))).toEqual(
|
|
201
|
-
toArray('[', '$', 'd', '#', 'i', 2, 0x3e, 0x80, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00),
|
|
202
|
-
);
|
|
198
|
+
expect(toArray(encode(Float32Array.from([0.25, 0.125])))).toEqual(toArray('[', '$', 'd', '#', 'i', 2, 0x3e, 0x80, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00));
|
|
203
199
|
});
|
|
204
200
|
|
|
205
201
|
test('encode array (float64 typed array)', () => {
|
|
206
202
|
expect(toArray(encode(Float64Array.from([0.25, 0.125])))).toEqual(
|
|
207
|
-
toArray(
|
|
208
|
-
'[',
|
|
209
|
-
'$',
|
|
210
|
-
'D',
|
|
211
|
-
'#',
|
|
212
|
-
'i',
|
|
213
|
-
2,
|
|
214
|
-
0x3f,
|
|
215
|
-
0xd0,
|
|
216
|
-
0x00,
|
|
217
|
-
0x00,
|
|
218
|
-
0x00,
|
|
219
|
-
0x00,
|
|
220
|
-
0x00,
|
|
221
|
-
0x00,
|
|
222
|
-
0x3f,
|
|
223
|
-
0xc0,
|
|
224
|
-
0x00,
|
|
225
|
-
0x00,
|
|
226
|
-
0x00,
|
|
227
|
-
0x00,
|
|
228
|
-
0x00,
|
|
229
|
-
0x00,
|
|
230
|
-
),
|
|
203
|
+
toArray('[', '$', 'D', '#', 'i', 2, 0x3f, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
|
|
231
204
|
);
|
|
232
205
|
});
|
|
233
206
|
|
|
@@ -252,9 +225,7 @@ test('encode array (int64 typed array)', () => {
|
|
|
252
225
|
});
|
|
253
226
|
|
|
254
227
|
test('encode object', () => {
|
|
255
|
-
expect(toArray(encode({ a: 1, b: 2, c: 3 }))).toEqual(
|
|
256
|
-
toArray('{', 'i', 1, 'a', 'U', 1, 'i', 1, 'b', 'U', 2, 'i', 1, 'c', 'U', 3, '}'),
|
|
257
|
-
);
|
|
228
|
+
expect(toArray(encode({ a: 1, b: 2, c: 3 }))).toEqual(toArray('{', 'i', 1, 'a', 'U', 1, 'i', 1, 'b', 'U', 2, 'i', 1, 'c', 'U', 3, '}'));
|
|
258
229
|
});
|
|
259
230
|
|
|
260
231
|
test('encode object (empty)', () => {
|
|
@@ -266,15 +237,11 @@ test('encode object (empty key)', () => {
|
|
|
266
237
|
});
|
|
267
238
|
|
|
268
239
|
test('encode object (mixed)', () => {
|
|
269
|
-
expect(toArray(encode({ a: 1, b: 'a', c: true }))).toEqual(
|
|
270
|
-
toArray('{', 'i', 1, 'a', 'U', 1, 'i', 1, 'b', 'C', 'a', 'i', 1, 'c', 'T', '}'),
|
|
271
|
-
);
|
|
240
|
+
expect(toArray(encode({ a: 1, b: 'a', c: true }))).toEqual(toArray('{', 'i', 1, 'a', 'U', 1, 'i', 1, 'b', 'C', 'a', 'i', 1, 'c', 'T', '}'));
|
|
272
241
|
});
|
|
273
242
|
|
|
274
243
|
test('encode object (only null values)', () => {
|
|
275
|
-
expect(toArray(encode({ a: null, b: null, c: null }))).toEqual(
|
|
276
|
-
toArray('{', 'i', 1, 'a', 'Z', 'i', 1, 'b', 'Z', 'i', 1, 'c', 'Z', '}'),
|
|
277
|
-
);
|
|
244
|
+
expect(toArray(encode({ a: null, b: null, c: null }))).toEqual(toArray('{', 'i', 1, 'a', 'Z', 'i', 1, 'b', 'Z', 'i', 1, 'c', 'Z', '}'));
|
|
278
245
|
});
|
|
279
246
|
|
|
280
247
|
test('encode object (skip prototype)', () => {
|
|
@@ -282,9 +249,7 @@ test('encode object (skip prototype)', () => {
|
|
|
282
249
|
obj.a = 1;
|
|
283
250
|
obj.b = 'a';
|
|
284
251
|
obj.c = true;
|
|
285
|
-
expect(toArray(encode(obj))).toEqual(
|
|
286
|
-
toArray('{', 'i', 1, 'a', 'U', 1, 'i', 1, 'b', 'C', 'a', 'i', 1, 'c', 'T', '}'),
|
|
287
|
-
);
|
|
252
|
+
expect(toArray(encode(obj))).toEqual(toArray('{', 'i', 1, 'a', 'U', 1, 'i', 1, 'b', 'C', 'a', 'i', 1, 'c', 'T', '}'));
|
|
288
253
|
});
|
|
289
254
|
|
|
290
255
|
test('encode object (skip symbol)', () => {
|
|
@@ -347,19 +312,32 @@ test('encode huge data (~128M)', () => {
|
|
|
347
312
|
const obj = [new Uint8Array(128 * 1024 * 1024 - 20)];
|
|
348
313
|
obj[0][0] = 0x12;
|
|
349
314
|
obj[0][1] = 0x34;
|
|
350
|
-
expect(toArray(encode(obj).slice(0, 12))).toEqual(
|
|
351
|
-
toArray('[', '[', '$', 'U', '#', 'l', 0x7, 0xff, 0xff, 0xec, 0x12, 0x34),
|
|
352
|
-
);
|
|
315
|
+
expect(toArray(encode(obj).slice(0, 12))).toEqual(toArray('[', '[', '$', 'U', '#', 'l', 0x7, 0xff, 0xff, 0xec, 0x12, 0x34));
|
|
353
316
|
});
|
|
354
317
|
|
|
355
318
|
test('encode huge data (128M)', () => {
|
|
356
319
|
const obj = [new Uint8Array(128 * 1024 * 1024)];
|
|
357
320
|
obj[0][0] = 0x12;
|
|
358
321
|
obj[0][1] = 0x34;
|
|
359
|
-
|
|
322
|
+
const encoded = encode(obj);
|
|
323
|
+
expect(encoded.length).toBe(128 * 1024 * 1024 + 9 + 2);
|
|
324
|
+
expect(toArray(encoded.slice(0, 12))).toEqual(toArray('[', '[', '$', 'U', '#', 'l', 0x8, 0, 0, 0, 0x12, 0x34));
|
|
360
325
|
});
|
|
361
326
|
|
|
362
327
|
test('encode huge data (128M + 1) [error]', () => {
|
|
363
328
|
const obj = [new Uint8Array(128 * 1024 * 1024 + 1)];
|
|
364
329
|
expect(() => encode(obj)).toThrow(/Buffer has exceed max size/);
|
|
365
330
|
});
|
|
331
|
+
|
|
332
|
+
test('encode huge data (256M)', () => {
|
|
333
|
+
const obj = [new Uint8Array(128 * 1024 * 1024), new Uint8Array(128 * 1024 * 1024)];
|
|
334
|
+
obj[0][0] = 0x12;
|
|
335
|
+
obj[0][1] = 0x34;
|
|
336
|
+
obj[1][0] = 0x56;
|
|
337
|
+
obj[1][1] = 0x78;
|
|
338
|
+
const encoded = encode(obj);
|
|
339
|
+
expect(encoded.length).toBe(128 * 1024 * 1024 * 2 + 9 * 2 + 2);
|
|
340
|
+
expect(toArray(encoded.slice(0, 12))).toEqual(toArray('[', '[', '$', 'U', '#', 'l', 0x8, 0, 0, 0, 0x12, 0x34));
|
|
341
|
+
expect(toArray(encoded.slice(128 * 1024 * 1024 + 10, 128 * 1024 * 1024 + 10 + 11))).toEqual(toArray('[', '$', 'U', '#', 'l', 0x8, 0, 0, 0, 0x56, 0x78));
|
|
342
|
+
expect(toArray(encoded.slice(-1))).toEqual(toArray(']'));
|
|
343
|
+
});
|