json-as 1.3.7 → 1.3.9
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/CHANGELOG.md +36 -0
- package/README.md +1 -1
- package/assembly/deserialize/index/arbitrary.ts +2 -2
- package/assembly/deserialize/index/array.ts +29 -14
- package/assembly/deserialize/index/bool.ts +1 -1
- package/assembly/deserialize/index/date.ts +1 -1
- package/assembly/deserialize/index/float.ts +40 -1
- package/assembly/deserialize/index/integer.ts +3 -3
- package/assembly/deserialize/index/map.ts +1 -1
- package/assembly/deserialize/index/object.ts +1 -1
- package/assembly/deserialize/index/raw.ts +1 -1
- package/assembly/deserialize/index/set.ts +1 -1
- package/assembly/deserialize/index/staticarray.ts +4 -1
- package/assembly/deserialize/index/string.ts +28 -3
- package/assembly/deserialize/index/struct.ts +1 -1
- package/assembly/deserialize/index/typedarray.ts +25 -15
- package/assembly/deserialize/index/unsigned.ts +3 -3
- package/assembly/deserialize/index.ts +1 -0
- package/assembly/deserialize/naive/array/bool.ts +68 -0
- package/assembly/deserialize/naive/array/float.ts +63 -0
- package/assembly/deserialize/{simple → naive}/array/generic.ts +1 -2
- package/assembly/deserialize/naive/array/integer.ts +86 -0
- package/assembly/deserialize/{simple → naive}/array/map.ts +0 -1
- package/assembly/deserialize/{simple → naive}/array/object.ts +0 -1
- package/assembly/deserialize/naive/array/string.ts +69 -0
- package/assembly/deserialize/{simple → naive}/array/struct.ts +0 -1
- package/assembly/deserialize/{simple → naive}/array.ts +6 -11
- package/assembly/deserialize/naive/float.ts +135 -0
- package/assembly/deserialize/{simple → naive}/integer.ts +2 -2
- package/assembly/deserialize/{simple → naive}/map.ts +12 -6
- package/assembly/deserialize/{simple → naive}/object.ts +4 -7
- package/assembly/deserialize/{simple → naive}/set.ts +12 -27
- package/assembly/deserialize/{simple → naive}/staticarray/array.ts +1 -1
- package/assembly/deserialize/{simple → naive}/staticarray/bool.ts +1 -1
- package/assembly/deserialize/{simple → naive}/staticarray/float.ts +1 -1
- package/assembly/deserialize/{simple → naive}/staticarray/integer.ts +1 -1
- package/assembly/deserialize/{simple → naive}/staticarray/struct.ts +1 -2
- package/assembly/deserialize/{simple → naive}/staticarray.ts +4 -4
- package/assembly/deserialize/naive/string.ts +199 -0
- package/assembly/deserialize/{simple → naive}/typedarray.ts +4 -4
- package/assembly/deserialize/{simple → naive}/unsigned.ts +2 -2
- package/assembly/deserialize/simd/array/integer.ts +19 -19
- package/assembly/deserialize/simd/float.ts +303 -0
- package/assembly/deserialize/simd/string.ts +233 -108
- package/assembly/deserialize/swar/array/arbitrary.ts +6 -2
- package/assembly/deserialize/swar/array/array.ts +14 -7
- package/assembly/deserialize/swar/array/bool.ts +8 -3
- package/assembly/deserialize/swar/array/box.ts +6 -2
- package/assembly/deserialize/swar/array/float.ts +282 -6
- package/assembly/deserialize/swar/array/generic.ts +6 -2
- package/assembly/deserialize/swar/array/integer.ts +81 -74
- package/assembly/deserialize/swar/array/map.ts +6 -2
- package/assembly/deserialize/swar/array/object.ts +24 -32
- package/assembly/deserialize/swar/array/raw.ts +6 -2
- package/assembly/deserialize/swar/array/shared.ts +32 -8
- package/assembly/deserialize/swar/array/string.ts +127 -10
- package/assembly/deserialize/swar/array/struct.ts +45 -11
- package/assembly/deserialize/swar/array.ts +2 -56
- package/assembly/deserialize/swar/float.ts +304 -0
- package/assembly/deserialize/swar/string.ts +119 -104
- package/assembly/deserialize/swar/typedarray.ts +224 -0
- package/assembly/index.ts +203 -293
- package/assembly/serialize/index/array.ts +1 -1
- package/assembly/serialize/index/bool.ts +1 -1
- package/assembly/serialize/index/date.ts +1 -1
- package/assembly/serialize/index/float.ts +1 -1
- package/assembly/serialize/index/integer.ts +1 -1
- package/assembly/serialize/index/map.ts +1 -1
- package/assembly/serialize/index/raw.ts +1 -1
- package/assembly/serialize/index/set.ts +1 -1
- package/assembly/serialize/index/staticarray.ts +1 -1
- package/assembly/serialize/index/string.ts +1 -1
- package/assembly/serialize/index/struct.ts +1 -1
- package/assembly/serialize/index/typedarray.ts +2 -11
- package/assembly/serialize/index.ts +1 -0
- package/assembly/serialize/{simple → naive}/array.ts +87 -0
- package/assembly/serialize/{simple → naive}/string.ts +1 -1
- package/assembly/serialize/swar/string.ts +0 -139
- package/assembly/util/dragonbox.ts +10 -3
- package/assembly/util/itoa-fast.ts +29 -18
- package/assembly/util/scanValueEnd.ts +78 -0
- package/assembly/util/scientific.ts +132 -0
- package/lib/as-bs.ts +14 -1
- package/package.json +14 -13
- package/transform/lib/index.d.ts +4 -0
- package/transform/lib/index.d.ts.map +1 -1
- package/transform/lib/index.js +155 -238
- package/transform/lib/index.js.map +1 -1
- package/assembly/deserialize/simple/arbitrary.ts +0 -30
- package/assembly/deserialize/simple/array/bool.ts +0 -48
- package/assembly/deserialize/simple/array/float.ts +0 -55
- package/assembly/deserialize/simple/array/integer.ts +0 -33
- package/assembly/deserialize/simple/array/string.ts +0 -29
- package/assembly/deserialize/simple/float.ts +0 -206
- package/assembly/deserialize/simple/string.ts +0 -45
- package/assembly/serialize/simple/arbitrary.ts +0 -79
- package/assembly/serialize/simple/object.ts +0 -42
- /package/assembly/deserialize/{simple → naive}/array/arbitrary.ts +0 -0
- /package/assembly/deserialize/{simple → naive}/array/array.ts +0 -0
- /package/assembly/deserialize/{simple → naive}/array/box.ts +0 -0
- /package/assembly/deserialize/{simple → naive}/array/raw.ts +0 -0
- /package/assembly/deserialize/{simple → naive}/bool.ts +0 -0
- /package/assembly/deserialize/{simple → naive}/date.ts +0 -0
- /package/assembly/deserialize/{simple → naive}/raw.ts +0 -0
- /package/assembly/deserialize/{simple → naive}/staticarray/string.ts +0 -0
- /package/assembly/deserialize/{simple → naive}/struct.ts +0 -0
- /package/assembly/serialize/{simple → naive}/bool.ts +0 -0
- /package/assembly/serialize/{simple → naive}/date.ts +0 -0
- /package/assembly/serialize/{simple → naive}/float.ts +0 -0
- /package/assembly/serialize/{simple → naive}/integer.ts +0 -0
- /package/assembly/serialize/{simple → naive}/map.ts +0 -0
- /package/assembly/serialize/{simple → naive}/raw.ts +0 -0
- /package/assembly/serialize/{simple → naive}/set.ts +0 -0
- /package/assembly/serialize/{simple → naive}/staticarray.ts +0 -0
- /package/assembly/serialize/{simple → naive}/struct.ts +0 -0
- /package/assembly/serialize/{simple → naive}/typedarray.ts +0 -0
|
@@ -1,27 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { deserializeUnsignedField } from "../../index/unsigned";
|
|
3
|
-
import { deserializeIntegerArray as deserializeIntegerArray_NAIVE } from "../../simple/array/integer";
|
|
1
|
+
import { deserializeIntegerArray_NAIVE } from "../../naive/array/integer";
|
|
4
2
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
5
3
|
import { isSpace } from "../../../util";
|
|
6
4
|
import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@inline function
|
|
5
|
+
import { parse4Digits_PairMul } from "../../../util/swar-int";
|
|
6
|
+
|
|
7
|
+
// Store helpers parameterised on the element type `E` directly, so they
|
|
8
|
+
// serve both `Array<E>` and `TypedArray<E>` callers. The integer-array
|
|
9
|
+
// callers below all pass `valueof<T>` and AS folds the resulting tower of
|
|
10
|
+
// `sizeof<E>` comparisons at compile time — same codegen as the prior
|
|
11
|
+
// `T extends number[]` version, but reusable from `swar/typedarray.ts`.
|
|
12
|
+
@inline function storeSignedIntegerE<E extends number>(
|
|
15
13
|
slot: usize,
|
|
16
14
|
value: i64,
|
|
17
15
|
): void {
|
|
18
|
-
if (sizeof<
|
|
16
|
+
if (sizeof<E>() == sizeof<i8>()) {
|
|
19
17
|
store<i8>(slot, <i8>value);
|
|
20
|
-
} else if (sizeof<
|
|
18
|
+
} else if (sizeof<E>() == sizeof<i16>()) {
|
|
21
19
|
store<i16>(slot, <i16>value);
|
|
22
|
-
} else if (sizeof<
|
|
20
|
+
} else if (sizeof<E>() == sizeof<i32>()) {
|
|
23
21
|
store<i32>(slot, <i32>value);
|
|
24
|
-
} else if (sizeof<
|
|
22
|
+
} else if (sizeof<E>() == sizeof<isize>()) {
|
|
25
23
|
store<isize>(slot, <isize>value);
|
|
26
24
|
} else {
|
|
27
25
|
store<i64>(slot, value);
|
|
@@ -29,45 +27,33 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
|
|
32
|
-
@inline function
|
|
30
|
+
@inline function storeUnsignedIntegerE<E extends number>(
|
|
33
31
|
slot: usize,
|
|
34
32
|
value: u64,
|
|
35
33
|
): void {
|
|
36
|
-
if (sizeof<
|
|
34
|
+
if (sizeof<E>() == sizeof<u8>()) {
|
|
37
35
|
store<u8>(slot, <u8>value);
|
|
38
|
-
} else if (sizeof<
|
|
36
|
+
} else if (sizeof<E>() == sizeof<u16>()) {
|
|
39
37
|
store<u16>(slot, <u16>value);
|
|
40
|
-
} else if (sizeof<
|
|
38
|
+
} else if (sizeof<E>() == sizeof<u32>()) {
|
|
41
39
|
store<u32>(slot, <u32>value);
|
|
42
|
-
} else if (sizeof<
|
|
40
|
+
} else if (sizeof<E>() == sizeof<usize>()) {
|
|
43
41
|
store<usize>(slot, <usize>value);
|
|
44
42
|
} else {
|
|
45
43
|
store<u64>(slot, value);
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
@inline function parse4DigitsASCII(block: u64): u32 {
|
|
51
|
-
const digits = (block & ASCII_LANE_MASK_4) - ASCII_ZERO_4;
|
|
52
|
-
if (((digits | (digits + ASCII_RANGE_ADD_4)) & ASCII_RANGE_MASK_4) != 0)
|
|
53
|
-
return U32.MAX_VALUE;
|
|
54
|
-
|
|
55
|
-
return <u32>(
|
|
56
|
-
(<u32>(digits & 0xffff) * 1000 +
|
|
57
|
-
<u32>((digits >> 16) & 0xffff) * 100 +
|
|
58
|
-
<u32>((digits >> 32) & 0xffff) * 10 +
|
|
59
|
-
<u32>(digits >> 48))
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
47
|
// The four parse helpers below take a `slot` pointer (`writePtr`) and store
|
|
64
48
|
// the value directly via `store<valueof<T>>(slot, ...)`. The outer dispatcher
|
|
65
49
|
// owns the array's `out.length = maxElements` pre-allocation and the
|
|
66
50
|
// `writePtr` advance, so the per-element `Array.push` capacity check and
|
|
67
51
|
// length write are eliminated for every integer width, not just the u8/i8
|
|
68
52
|
// narrow-lane path.
|
|
69
|
-
|
|
70
|
-
|
|
53
|
+
// Parsers are also E-parameterised so they're shareable with
|
|
54
|
+
// `swar/typedarray.ts`. The body is byte-identical to the prior version
|
|
55
|
+
// modulo s/valueof<T>/E/.
|
|
56
|
+
@inline export function parseSignedIntegerScalar<E extends number>(
|
|
71
57
|
srcStart: usize,
|
|
72
58
|
srcEnd: usize,
|
|
73
59
|
slot: usize,
|
|
@@ -93,12 +79,12 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
93
79
|
srcStart += 2;
|
|
94
80
|
}
|
|
95
81
|
|
|
96
|
-
|
|
82
|
+
storeSignedIntegerE<E>(slot, negative ? -(<i64>value) : <i64>value);
|
|
97
83
|
return srcStart;
|
|
98
84
|
}
|
|
99
85
|
|
|
100
86
|
|
|
101
|
-
@inline function parseUnsignedIntegerScalar<
|
|
87
|
+
@inline export function parseUnsignedIntegerScalar<E extends number>(
|
|
102
88
|
srcStart: usize,
|
|
103
89
|
srcEnd: usize,
|
|
104
90
|
slot: usize,
|
|
@@ -115,12 +101,12 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
115
101
|
srcStart += 2;
|
|
116
102
|
}
|
|
117
103
|
|
|
118
|
-
|
|
104
|
+
storeUnsignedIntegerE<E>(slot, value);
|
|
119
105
|
return srcStart;
|
|
120
106
|
}
|
|
121
107
|
|
|
122
108
|
|
|
123
|
-
@inline function parseSignedIntegerSWAR<
|
|
109
|
+
@inline export function parseSignedIntegerSWAR<E extends number>(
|
|
124
110
|
srcStart: usize,
|
|
125
111
|
srcEnd: usize,
|
|
126
112
|
slot: usize,
|
|
@@ -140,12 +126,17 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
140
126
|
let value: u64 = digit;
|
|
141
127
|
srcStart += 2;
|
|
142
128
|
|
|
129
|
+
// Signed scan uses parse4 + scalar only (matches the asymmetric tuning in
|
|
130
|
+
// swar/integer.ts:deserializeIntegerField_SWAR). The leading minus shifts
|
|
131
|
+
// the digit run into parse8's "terminator-in-load" zone where validate-fail
|
|
132
|
+
// is common, so parse4's smaller failure unit wins.
|
|
133
|
+
//
|
|
143
134
|
// i8 tops out at 3 digits (-128..127), so the 4-digit kernel can never fire
|
|
144
135
|
// and the failing load + range check just burns cycles. Gate on the lane
|
|
145
136
|
// width so AS folds the loop away at compile time.
|
|
146
|
-
if (sizeof<
|
|
137
|
+
if (sizeof<E>() > 1) {
|
|
147
138
|
while (srcStart + 6 < srcEnd) {
|
|
148
|
-
const parsed =
|
|
139
|
+
const parsed = parse4Digits_PairMul(load<u64>(srcStart));
|
|
149
140
|
if (parsed == U32.MAX_VALUE) break;
|
|
150
141
|
value = value * 10000 + parsed;
|
|
151
142
|
srcStart += 8;
|
|
@@ -159,12 +150,12 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
159
150
|
srcStart += 2;
|
|
160
151
|
}
|
|
161
152
|
|
|
162
|
-
|
|
153
|
+
storeSignedIntegerE<E>(slot, negative ? -(<i64>value) : <i64>value);
|
|
163
154
|
return srcStart;
|
|
164
155
|
}
|
|
165
156
|
|
|
166
157
|
|
|
167
|
-
@inline function parseUnsignedIntegerSWAR<
|
|
158
|
+
@inline export function parseUnsignedIntegerSWAR<E extends number>(
|
|
168
159
|
srcStart: usize,
|
|
169
160
|
srcEnd: usize,
|
|
170
161
|
slot: usize,
|
|
@@ -173,7 +164,7 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
173
164
|
// the element terminator, then a fixed-count fold with no per-digit break.
|
|
174
165
|
// TurboFan tends to schedule this better than a single combined
|
|
175
166
|
// scan-and-fold loop because the fold has no data-dependent exit.
|
|
176
|
-
if (sizeof<
|
|
167
|
+
if (sizeof<E>() <= 2) {
|
|
177
168
|
const first = <u32>load<u16>(srcStart) - 48;
|
|
178
169
|
if (first > 9) return 0;
|
|
179
170
|
const lastIndex = srcStart;
|
|
@@ -189,7 +180,7 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
189
180
|
value = value * 10 + (<u32>load<u16>(p) - 48);
|
|
190
181
|
p += 2;
|
|
191
182
|
}
|
|
192
|
-
|
|
183
|
+
storeUnsignedIntegerE<E>(slot, value);
|
|
193
184
|
return srcStart;
|
|
194
185
|
}
|
|
195
186
|
|
|
@@ -199,8 +190,14 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
199
190
|
let value: u64 = digit;
|
|
200
191
|
srcStart += 2;
|
|
201
192
|
|
|
193
|
+
// Array unsigned path uses parse4 + scalar (not parse8 + scalar as in the
|
|
194
|
+
// struct-field path swar/integer.ts:deserializeUnsignedField_SWAR). The
|
|
195
|
+
// bench corpus for arrays mixes element widths (e.g. 1/4/7/10 digits in
|
|
196
|
+
// u32-64mib), so most parse8 strides hit the `,` separator mid-load and
|
|
197
|
+
// pay the load+validate cost for a guaranteed miss. parse4 has a smaller
|
|
198
|
+
// failure unit and matches the typical 1-4 digit run between separators.
|
|
202
199
|
while (srcStart + 6 < srcEnd) {
|
|
203
|
-
const parsed =
|
|
200
|
+
const parsed = parse4Digits_PairMul(load<u64>(srcStart));
|
|
204
201
|
if (parsed == U32.MAX_VALUE) break;
|
|
205
202
|
value = value * 10000 + parsed;
|
|
206
203
|
srcStart += 8;
|
|
@@ -213,7 +210,7 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
213
210
|
srcStart += 2;
|
|
214
211
|
}
|
|
215
212
|
|
|
216
|
-
|
|
213
|
+
storeUnsignedIntegerE<E>(slot, value);
|
|
217
214
|
return srcStart;
|
|
218
215
|
}
|
|
219
216
|
|
|
@@ -240,7 +237,6 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
240
237
|
let index = 0;
|
|
241
238
|
|
|
242
239
|
out.length = 0;
|
|
243
|
-
srcStart = skipIntegerArrayWhitespace(srcStart, srcEnd);
|
|
244
240
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) {
|
|
245
241
|
throw new Error("Failed to parse JSON!");
|
|
246
242
|
}
|
|
@@ -274,7 +270,7 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
274
270
|
srcStart += 2;
|
|
275
271
|
}
|
|
276
272
|
|
|
277
|
-
|
|
273
|
+
storeSignedIntegerE<valueof<T>>(
|
|
278
274
|
ensureArrayElementSlot<T>(out, index),
|
|
279
275
|
negative ? -(<i64>value) : <i64>value,
|
|
280
276
|
);
|
|
@@ -291,7 +287,10 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
291
287
|
srcStart += 2;
|
|
292
288
|
}
|
|
293
289
|
|
|
294
|
-
|
|
290
|
+
storeUnsignedIntegerE<valueof<T>>(
|
|
291
|
+
ensureArrayElementSlot<T>(out, index),
|
|
292
|
+
value,
|
|
293
|
+
);
|
|
295
294
|
}
|
|
296
295
|
|
|
297
296
|
index++;
|
|
@@ -355,7 +354,7 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
355
354
|
|
|
356
355
|
if (sizeof<valueof<T>>() > 1) {
|
|
357
356
|
while (srcStart + 6 < srcEnd) {
|
|
358
|
-
const parsed =
|
|
357
|
+
const parsed = parse4Digits_PairMul(load<u64>(srcStart));
|
|
359
358
|
if (parsed == U32.MAX_VALUE) break;
|
|
360
359
|
value = value * 10000 + parsed;
|
|
361
360
|
srcStart += 8;
|
|
@@ -370,7 +369,7 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
370
369
|
}
|
|
371
370
|
|
|
372
371
|
if (index >= reusableLength) break;
|
|
373
|
-
|
|
372
|
+
storeSignedIntegerE<valueof<T>>(
|
|
374
373
|
dataStart + <usize>index * sizeof<valueof<T>>(),
|
|
375
374
|
negative ? -(<i64>value) : <i64>value,
|
|
376
375
|
);
|
|
@@ -398,7 +397,7 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
398
397
|
|
|
399
398
|
if (sizeof<valueof<T>>() > 1) {
|
|
400
399
|
while (srcStart + 6 < srcEnd) {
|
|
401
|
-
const parsed =
|
|
400
|
+
const parsed = parse4Digits_PairMul(load<u64>(srcStart));
|
|
402
401
|
if (parsed == U32.MAX_VALUE) break;
|
|
403
402
|
value = value * 10000 + parsed;
|
|
404
403
|
srcStart += 8;
|
|
@@ -413,7 +412,7 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
413
412
|
}
|
|
414
413
|
|
|
415
414
|
if (index >= reusableLength) break;
|
|
416
|
-
|
|
415
|
+
storeUnsignedIntegerE<valueof<T>>(
|
|
417
416
|
dataStart + <usize>index * sizeof<valueof<T>>(),
|
|
418
417
|
value,
|
|
419
418
|
);
|
|
@@ -462,8 +461,8 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
462
461
|
if (isSigned<valueof<T>>()) {
|
|
463
462
|
while (srcStart < srcEnd) {
|
|
464
463
|
const next = useSWAR
|
|
465
|
-
? parseSignedIntegerSWAR<T
|
|
466
|
-
: parseSignedIntegerScalar<T
|
|
464
|
+
? parseSignedIntegerSWAR<valueof<T>>(srcStart, srcEnd, writePtr)
|
|
465
|
+
: parseSignedIntegerScalar<valueof<T>>(srcStart, srcEnd, writePtr);
|
|
467
466
|
if (!next) break;
|
|
468
467
|
writePtr += elementSize;
|
|
469
468
|
srcStart = next;
|
|
@@ -483,8 +482,8 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
483
482
|
} else {
|
|
484
483
|
while (srcStart < srcEnd) {
|
|
485
484
|
const next = useSWAR
|
|
486
|
-
? parseUnsignedIntegerSWAR<T
|
|
487
|
-
: parseUnsignedIntegerScalar<T
|
|
485
|
+
? parseUnsignedIntegerSWAR<valueof<T>>(srcStart, srcEnd, writePtr)
|
|
486
|
+
: parseUnsignedIntegerScalar<valueof<T>>(srcStart, srcEnd, writePtr);
|
|
488
487
|
if (!next) break;
|
|
489
488
|
writePtr += elementSize;
|
|
490
489
|
srcStart = next;
|
|
@@ -515,15 +514,6 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
|
515
514
|
);
|
|
516
515
|
}
|
|
517
516
|
|
|
518
|
-
// @ts-ignore: Decorator valid here
|
|
519
|
-
export function deserializeIntegerArray<T extends number[]>(
|
|
520
|
-
srcStart: usize,
|
|
521
|
-
srcEnd: usize,
|
|
522
|
-
dst: usize,
|
|
523
|
-
): T {
|
|
524
|
-
return deserializeIntegerArrayImpl<T>(srcStart, srcEnd, dst, false);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
517
|
// @ts-ignore: Decorator valid here
|
|
528
518
|
export function deserializeIntegerArray_SWAR<T extends number[]>(
|
|
529
519
|
srcStart: usize,
|
|
@@ -655,7 +645,7 @@ function deserializeNarrowIntegerArray_SWAR<T extends number[]>(
|
|
|
655
645
|
}
|
|
656
646
|
|
|
657
647
|
|
|
658
|
-
@inline
|
|
648
|
+
@inline function deserializeIntegerArrayBody<T extends number[]>(
|
|
659
649
|
srcStart: usize,
|
|
660
650
|
srcEnd: usize,
|
|
661
651
|
out: T,
|
|
@@ -665,6 +655,7 @@ function deserializeNarrowIntegerArray_SWAR<T extends number[]>(
|
|
|
665
655
|
do {
|
|
666
656
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
667
657
|
srcStart += 2;
|
|
658
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
668
659
|
if (srcStart >= srcEnd) break;
|
|
669
660
|
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
670
661
|
out.length = 0;
|
|
@@ -673,19 +664,35 @@ function deserializeNarrowIntegerArray_SWAR<T extends number[]>(
|
|
|
673
664
|
|
|
674
665
|
while (srcStart < srcEnd) {
|
|
675
666
|
const slot = ensureArrayElementSlot<T>(out, index);
|
|
667
|
+
// Inline the array-optimized SWAR parser directly. The top-level
|
|
668
|
+
// (`deserializeIntegerArrayImpl`) and the typed-array path
|
|
669
|
+
// (`swar/typedarray.ts`) already call these — having the field path
|
|
670
|
+
// call them too means the per-element parser is identical across all
|
|
671
|
+
// three call sites (parse4 + scalar fold for both signed and
|
|
672
|
+
// unsigned, narrow-lane special case for i8/u8/i16/u16).
|
|
673
|
+
//
|
|
674
|
+
// Why not `deserializeUnsignedField_SWAR` (which uses parse8 + scalar)?
|
|
675
|
+
// That tuning targets the struct-single-field path where the digit
|
|
676
|
+
// run is one aligned token. In an array, mixed element widths cause
|
|
677
|
+
// parse8 to fail-and-retry at element boundaries — see u32-64mib's
|
|
678
|
+
// 23% regression when parse8 was tried in the array path.
|
|
676
679
|
srcStart = isSigned<valueof<T>>()
|
|
677
|
-
?
|
|
678
|
-
:
|
|
679
|
-
if (!srcStart
|
|
680
|
+
? parseSignedIntegerSWAR<valueof<T>>(srcStart, srcEnd, slot)
|
|
681
|
+
: parseUnsignedIntegerSWAR<valueof<T>>(srcStart, srcEnd, slot);
|
|
682
|
+
if (!srcStart) break;
|
|
683
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
684
|
+
if (srcStart >= srcEnd) break;
|
|
680
685
|
|
|
681
686
|
const code = load<u16>(srcStart);
|
|
682
687
|
if (code == COMMA) {
|
|
683
688
|
srcStart += 2;
|
|
689
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
684
690
|
index++;
|
|
685
691
|
continue;
|
|
686
692
|
}
|
|
687
693
|
if (code == BRACKET_RIGHT) {
|
|
688
|
-
|
|
694
|
+
const nextLen = index + 1;
|
|
695
|
+
if (out.length != nextLen) out.length = nextLen;
|
|
689
696
|
return srcStart + 2;
|
|
690
697
|
}
|
|
691
698
|
break;
|
|
@@ -701,7 +708,7 @@ function deserializeNarrowIntegerArray_SWAR<T extends number[]>(
|
|
|
701
708
|
srcEnd: usize,
|
|
702
709
|
fieldPtr: usize,
|
|
703
710
|
): usize {
|
|
704
|
-
return
|
|
711
|
+
return deserializeIntegerArrayBody<T>(
|
|
705
712
|
srcStart,
|
|
706
713
|
srcEnd,
|
|
707
714
|
ensureArrayField<T>(fieldPtr),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { deserializeGenericArrayBody } from "./generic";
|
|
1
2
|
import { ensureArrayField } from "./shared";
|
|
2
3
|
|
|
3
4
|
|
|
@@ -6,6 +7,9 @@ import { ensureArrayField } from "./shared";
|
|
|
6
7
|
srcEnd: usize,
|
|
7
8
|
fieldPtr: usize,
|
|
8
9
|
): usize {
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
return deserializeGenericArrayBody<T>(
|
|
11
|
+
srcStart,
|
|
12
|
+
srcEnd,
|
|
13
|
+
ensureArrayField<T>(fieldPtr),
|
|
14
|
+
);
|
|
11
15
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { JSON } from "../../..";
|
|
1
2
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
2
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ensureArrayElementSlot,
|
|
5
|
+
ensureArrayField,
|
|
6
|
+
scanValueEnd,
|
|
7
|
+
skipWhitespace,
|
|
8
|
+
} from "./shared";
|
|
3
9
|
|
|
4
10
|
|
|
5
|
-
@inline
|
|
11
|
+
@inline function deserializeObjectArrayBody<T extends unknown[]>(
|
|
6
12
|
srcStart: usize,
|
|
7
13
|
srcEnd: usize,
|
|
8
14
|
out: T,
|
|
@@ -12,6 +18,7 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
12
18
|
do {
|
|
13
19
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
14
20
|
srcStart += 2;
|
|
21
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
15
22
|
if (srcStart >= srcEnd) break;
|
|
16
23
|
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
17
24
|
out.length = 0;
|
|
@@ -20,44 +27,29 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
20
27
|
|
|
21
28
|
while (srcStart < srcEnd) {
|
|
22
29
|
const slot = ensureArrayElementSlot<T>(out, index);
|
|
23
|
-
let value = load<valueof<T>>(slot);
|
|
24
|
-
if (changetype<usize>(value) == 0) {
|
|
25
|
-
value = changetype<valueof<T>>(
|
|
26
|
-
__new(offsetof<nonnull<valueof<T>>>(), idof<nonnull<valueof<T>>>()),
|
|
27
|
-
);
|
|
28
|
-
// @ts-ignore: supplied by transform
|
|
29
|
-
if (isDefined(changetype<nonnull<valueof<T>>>(value).__INITIALIZE)) {
|
|
30
|
-
// @ts-ignore: supplied by transform
|
|
31
|
-
changetype<nonnull<valueof<T>>>(value).__INITIALIZE();
|
|
32
|
-
}
|
|
33
|
-
store<valueof<T>>(slot, value);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
30
|
const valueStart = srcStart;
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
srcStart = changetype<nonnull<valueof<T>>>(value).__DESERIALIZE_SLOW<
|
|
48
|
-
valueof<T>
|
|
49
|
-
>(valueStart, srcEnd, value);
|
|
50
|
-
}
|
|
51
|
-
if (!srcStart || srcStart >= srcEnd) break;
|
|
31
|
+
const valueEnd = scanValueEnd(valueStart, srcEnd);
|
|
32
|
+
if (!valueEnd) break;
|
|
33
|
+
|
|
34
|
+
const value = JSON.__deserialize<valueof<T>>(
|
|
35
|
+
valueStart,
|
|
36
|
+
valueEnd,
|
|
37
|
+
changetype<usize>(load<valueof<T>>(slot)),
|
|
38
|
+
);
|
|
39
|
+
store<valueof<T>>(slot, value);
|
|
40
|
+
srcStart = valueEnd;
|
|
52
41
|
|
|
42
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
53
43
|
const code = load<u16>(srcStart);
|
|
54
44
|
if (code == COMMA) {
|
|
55
45
|
srcStart += 2;
|
|
46
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
56
47
|
index++;
|
|
57
48
|
continue;
|
|
58
49
|
}
|
|
59
50
|
if (code == BRACKET_RIGHT) {
|
|
60
|
-
|
|
51
|
+
const nextLen = index + 1;
|
|
52
|
+
if (out.length != nextLen) out.length = nextLen;
|
|
61
53
|
return srcStart + 2;
|
|
62
54
|
}
|
|
63
55
|
break;
|
|
@@ -73,7 +65,7 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
73
65
|
srcEnd: usize,
|
|
74
66
|
fieldPtr: usize,
|
|
75
67
|
): usize {
|
|
76
|
-
return
|
|
68
|
+
return deserializeObjectArrayBody<T>(
|
|
77
69
|
srcStart,
|
|
78
70
|
srcEnd,
|
|
79
71
|
ensureArrayField<T>(fieldPtr),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { JSON } from "../../..";
|
|
2
|
+
import { deserializeGenericArrayBody } from "./generic";
|
|
2
3
|
import { ensureArrayField } from "./shared";
|
|
3
4
|
|
|
4
5
|
|
|
@@ -7,6 +8,9 @@ import { ensureArrayField } from "./shared";
|
|
|
7
8
|
srcEnd: usize,
|
|
8
9
|
fieldPtr: usize,
|
|
9
10
|
): usize {
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
return deserializeGenericArrayBody<JSON.Raw[]>(
|
|
12
|
+
srcStart,
|
|
13
|
+
srcEnd,
|
|
14
|
+
ensureArrayField<JSON.Raw[]>(fieldPtr),
|
|
15
|
+
);
|
|
12
16
|
}
|
|
@@ -7,6 +7,14 @@ import {
|
|
|
7
7
|
COMMA,
|
|
8
8
|
QUOTE,
|
|
9
9
|
} from "../../../custom/chars";
|
|
10
|
+
import { isSpace } from "../../../util";
|
|
11
|
+
|
|
12
|
+
/** Advance past JSON whitespace (space, tab, LF, CR). */
|
|
13
|
+
// @ts-expect-error: @inline is a valid decorator
|
|
14
|
+
@inline export function skipWhitespace(srcStart: usize, srcEnd: usize): usize {
|
|
15
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
16
|
+
return srcStart;
|
|
17
|
+
}
|
|
10
18
|
|
|
11
19
|
|
|
12
20
|
@inline export function ensureArrayField<T extends Array<any>>(
|
|
@@ -50,13 +58,21 @@ import {
|
|
|
50
58
|
): usize {
|
|
51
59
|
const nextLength = index + 1;
|
|
52
60
|
if (out.length < nextLength) {
|
|
53
|
-
out.length = nextLength
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
// Grow via `push`, not `out.length = nextLength`. AS's `length=`
|
|
62
|
+
// setter calls `ensureCapacity(canGrow=false)` which reallocates to
|
|
63
|
+
// *exactly* the requested size — fine for a one-shot resize, but
|
|
64
|
+
// catastrophic in the per-element loop (every push triggers a full
|
|
65
|
+
// copy of the array, giving O(N²) growth cost). `push` goes through
|
|
66
|
+
// `canGrow=true`, doubling capacity geometrically as needed.
|
|
67
|
+
//
|
|
68
|
+
// We push a zero-bit default: `0` for primitives, the null reference
|
|
69
|
+
// for managed/reference element types. The caller overwrites this
|
|
70
|
+
// slot immediately, so the placeholder is never observed.
|
|
71
|
+
if (isManaged<valueof<T>>() || isReference<valueof<T>>()) {
|
|
72
|
+
out.push(changetype<valueof<T>>(0));
|
|
73
|
+
} else {
|
|
74
|
+
out.push(<valueof<T>>0);
|
|
75
|
+
}
|
|
60
76
|
}
|
|
61
77
|
return out.dataStart + <usize>index * sizeof<valueof<T>>();
|
|
62
78
|
}
|
|
@@ -127,7 +143,15 @@ import {
|
|
|
127
143
|
|
|
128
144
|
while (srcStart < srcEnd) {
|
|
129
145
|
const code = load<u16>(srcStart);
|
|
130
|
-
|
|
146
|
+
// Stop at the structural terminator OR trailing whitespace, so the returned
|
|
147
|
+
// range is the exact value (scalar parsers assume no trailing whitespace).
|
|
148
|
+
// Callers skip whitespace to reach the following `,`/`]`/`}`.
|
|
149
|
+
if (
|
|
150
|
+
code == COMMA ||
|
|
151
|
+
code == BRACKET_RIGHT ||
|
|
152
|
+
code == BRACE_RIGHT ||
|
|
153
|
+
isSpace(code)
|
|
154
|
+
)
|
|
131
155
|
return srcStart;
|
|
132
156
|
srcStart += 2;
|
|
133
157
|
}
|