json-as 1.3.6 → 1.3.7
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 +13 -0
- package/assembly/deserialize/helpers/uint.ts +4 -1
- package/assembly/deserialize/index/arbitrary.ts +5 -1
- package/assembly/deserialize/index/array.ts +13 -3
- package/assembly/deserialize/index/integer.ts +68 -1
- package/assembly/deserialize/index/string.ts +4 -1
- package/assembly/deserialize/index/typedarray.ts +13 -3
- package/assembly/deserialize/index/unsigned.ts +78 -1
- package/assembly/deserialize/simd/array/integer.ts +327 -50
- package/assembly/deserialize/simd/integer.ts +233 -0
- package/assembly/deserialize/simd/string.ts +45 -11
- package/assembly/deserialize/simple/arbitrary.ts +11 -4
- package/assembly/deserialize/simple/array/arbitrary.ts +24 -5
- package/assembly/deserialize/simple/array/array.ts +8 -2
- package/assembly/deserialize/simple/array/bool.ts +38 -7
- package/assembly/deserialize/simple/array/box.ts +8 -2
- package/assembly/deserialize/simple/array/float.ts +36 -9
- package/assembly/deserialize/simple/array/generic.ts +12 -4
- package/assembly/deserialize/simple/array/integer.ts +8 -2
- package/assembly/deserialize/simple/array/map.ts +26 -6
- package/assembly/deserialize/simple/array/object.ts +26 -6
- package/assembly/deserialize/simple/array/raw.ts +34 -7
- package/assembly/deserialize/simple/array/string.ts +8 -2
- package/assembly/deserialize/simple/array/struct.ts +26 -6
- package/assembly/deserialize/simple/array.ts +13 -3
- package/assembly/deserialize/simple/bool.ts +6 -2
- package/assembly/deserialize/simple/float.ts +6 -1
- package/assembly/deserialize/simple/integer.ts +10 -2
- package/assembly/deserialize/simple/map.ts +95 -22
- package/assembly/deserialize/simple/object.ts +63 -14
- package/assembly/deserialize/simple/raw.ts +4 -1
- package/assembly/deserialize/simple/set.ts +59 -14
- package/assembly/deserialize/simple/staticarray/string.ts +11 -3
- package/assembly/deserialize/simple/staticarray.ts +64 -14
- package/assembly/deserialize/simple/string.ts +5 -92
- package/assembly/deserialize/simple/struct.ts +5 -1
- package/assembly/deserialize/simple/typedarray.ts +16 -3
- package/assembly/deserialize/simple/unsigned.ts +10 -15
- package/assembly/deserialize/swar/array/arbitrary.ts +5 -1
- package/assembly/deserialize/swar/array/array.ts +30 -6
- package/assembly/deserialize/swar/array/bool.ts +22 -4
- package/assembly/deserialize/swar/array/box.ts +5 -1
- package/assembly/deserialize/swar/array/float.ts +15 -3
- package/assembly/deserialize/swar/array/generic.ts +24 -7
- package/assembly/deserialize/swar/array/integer.ts +328 -84
- package/assembly/deserialize/swar/array/map.ts +5 -1
- package/assembly/deserialize/swar/array/object.ts +27 -7
- package/assembly/deserialize/swar/array/raw.ts +5 -1
- package/assembly/deserialize/swar/array/shared.ts +36 -11
- package/assembly/deserialize/swar/array/string.ts +20 -4
- package/assembly/deserialize/swar/array/struct.ts +27 -7
- package/assembly/deserialize/swar/array.ts +19 -4
- package/assembly/deserialize/swar/integer.ts +246 -0
- package/assembly/deserialize/swar/string.ts +98 -194
- package/assembly/index.d.ts +3 -1
- package/assembly/index.ts +312 -81
- package/assembly/serialize/index/float.ts +5 -1
- package/assembly/serialize/index/typedarray.ts +25 -7
- package/assembly/serialize/simd/string.ts +6 -2
- package/assembly/serialize/simple/array.ts +179 -1
- package/assembly/serialize/simple/float.ts +4 -1
- package/assembly/serialize/simple/integer.ts +8 -9
- package/assembly/serialize/simple/map.ts +6 -2
- package/assembly/serialize/simple/raw.ts +5 -1
- package/assembly/serialize/simple/set.ts +6 -1
- package/assembly/serialize/simple/staticarray.ts +6 -1
- package/assembly/serialize/simple/string.ts +0 -1
- package/assembly/serialize/simple/typedarray.ts +10 -3
- package/assembly/serialize/swar/string.ts +18 -5
- package/assembly/util/atoi-fast.ts +81 -0
- package/assembly/util/concat.ts +5 -1
- package/assembly/util/dragonbox-cache.ts +443 -2
- package/assembly/util/dragonbox.ts +43 -14
- package/assembly/util/itoa-fast.ts +230 -0
- package/assembly/util/masks.ts +18 -1
- package/assembly/util/parsefloat-fast.ts +167 -0
- package/assembly/util/simd-int.ts +191 -0
- package/assembly/util/snp.ts +4 -1
- package/assembly/util/swar-int.ts +248 -0
- package/assembly/util/swar.ts +13 -3
- package/lib/as-bs.ts +13 -5
- package/package.json +5 -2
- package/transform/lib/builder.d.ts.map +1 -1
- package/transform/lib/builder.js +13 -5
- package/transform/lib/builder.js.map +1 -1
- package/transform/lib/index.d.ts +1 -0
- package/transform/lib/index.d.ts.map +1 -1
- package/transform/lib/index.js +1030 -241
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/linkers/alias.d.ts.map +1 -1
- package/transform/lib/linkers/alias.js.map +1 -1
- package/transform/lib/linkers/custom.d.ts.map +1 -1
- package/transform/lib/linkers/custom.js +3 -2
- package/transform/lib/linkers/custom.js.map +1 -1
- package/transform/lib/linkers/imports.d.ts.map +1 -1
- package/transform/lib/linkers/imports.js.map +1 -1
- package/transform/lib/types.d.ts.map +1 -1
- package/transform/lib/types.js +54 -16
- package/transform/lib/types.js.map +1 -1
- package/transform/lib/util.d.ts.map +1 -1
- package/transform/lib/util.js +1 -1
- package/transform/lib/util.js.map +1 -1
- package/transform/lib/visitor.d.ts.map +1 -1
- package/transform/lib/visitor.js +2 -1
- package/transform/lib/visitor.js.map +1 -1
- package/assembly/custom/util.ts +0 -310
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
2
2
|
import { deserializeIntegerArray_SLOW } from "../../swar/array/integer";
|
|
3
|
+
import { isSpace } from "../../../util";
|
|
3
4
|
|
|
4
5
|
const ASCII_LANE_MASK_4: u64 = 0x00ff00ff00ff00ff;
|
|
5
6
|
const ASCII_ZERO_4: u64 = 0x0030003000300030;
|
|
@@ -17,43 +18,33 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
|
|
|
17
18
|
@lazy const ZERO_I32X4 = i32x4.splat(0);
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
@lazy const PACK_WEIGHTS_10_1 = i8x16(
|
|
21
|
+
@lazy const PACK_WEIGHTS_10_1 = i8x16(
|
|
22
|
+
10,
|
|
23
|
+
1,
|
|
24
|
+
10,
|
|
25
|
+
1,
|
|
26
|
+
10,
|
|
27
|
+
1,
|
|
28
|
+
10,
|
|
29
|
+
1,
|
|
30
|
+
0,
|
|
31
|
+
0,
|
|
32
|
+
0,
|
|
33
|
+
0,
|
|
34
|
+
0,
|
|
35
|
+
0,
|
|
36
|
+
0,
|
|
37
|
+
0,
|
|
38
|
+
);
|
|
21
39
|
|
|
22
40
|
|
|
23
41
|
@lazy const PAIR_WEIGHTS_100_1 = i16x8(100, 1, 100, 1, 0, 0, 0, 0);
|
|
24
42
|
|
|
25
43
|
|
|
26
|
-
@inline function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
out.push(<valueof<T>>(<i16>value));
|
|
31
|
-
} else if (sizeof<valueof<T>>() == sizeof<i32>()) {
|
|
32
|
-
out.push(<valueof<T>>(<i32>value));
|
|
33
|
-
} else if (sizeof<valueof<T>>() == sizeof<isize>()) {
|
|
34
|
-
out.push(<valueof<T>>(<isize>value));
|
|
35
|
-
} else {
|
|
36
|
-
out.push(<valueof<T>>value);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
@inline function pushUnsignedInteger<T extends number[]>(out: T, value: u64): void {
|
|
42
|
-
if (sizeof<valueof<T>>() == sizeof<u8>()) {
|
|
43
|
-
out.push(<valueof<T>>(<u8>value));
|
|
44
|
-
} else if (sizeof<valueof<T>>() == sizeof<u16>()) {
|
|
45
|
-
out.push(<valueof<T>>(<u16>value));
|
|
46
|
-
} else if (sizeof<valueof<T>>() == sizeof<u32>()) {
|
|
47
|
-
out.push(<valueof<T>>(<u32>value));
|
|
48
|
-
} else if (sizeof<valueof<T>>() == sizeof<usize>()) {
|
|
49
|
-
out.push(<valueof<T>>(<usize>value));
|
|
50
|
-
} else {
|
|
51
|
-
out.push(<valueof<T>>value);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@inline function storeSignedInteger<T extends number[]>(slot: usize, value: i64): void {
|
|
44
|
+
@inline function storeSignedInteger<T extends number[]>(
|
|
45
|
+
slot: usize,
|
|
46
|
+
value: i64,
|
|
47
|
+
): void {
|
|
57
48
|
if (sizeof<valueof<T>>() == sizeof<i8>()) {
|
|
58
49
|
store<i8>(slot, <i8>value);
|
|
59
50
|
} else if (sizeof<valueof<T>>() == sizeof<i16>()) {
|
|
@@ -68,7 +59,10 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
|
|
|
68
59
|
}
|
|
69
60
|
|
|
70
61
|
|
|
71
|
-
@inline function storeUnsignedInteger<T extends number[]>(
|
|
62
|
+
@inline function storeUnsignedInteger<T extends number[]>(
|
|
63
|
+
slot: usize,
|
|
64
|
+
value: u64,
|
|
65
|
+
): void {
|
|
72
66
|
if (sizeof<valueof<T>>() == sizeof<u8>()) {
|
|
73
67
|
store<u8>(slot, <u8>value);
|
|
74
68
|
} else if (sizeof<valueof<T>>() == sizeof<u16>()) {
|
|
@@ -99,8 +93,16 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
|
|
|
99
93
|
return value * 100000000 + (<u64>lo * 10000 + <u64>hi);
|
|
100
94
|
}
|
|
101
95
|
|
|
96
|
+
// As in the SWAR variant: the parse helpers take a `slot` (`writePtr`) and
|
|
97
|
+
// store directly. The dispatcher owns `out.length = maxElements` and the
|
|
98
|
+
// per-element `writePtr` advance so `Array.push` is removed for every
|
|
99
|
+
// integer width, not just the narrow-lane fast path.
|
|
102
100
|
|
|
103
|
-
@inline function parseSignedIntegerSIMD<T extends number[]>(
|
|
101
|
+
@inline function parseSignedIntegerSIMD<T extends number[]>(
|
|
102
|
+
srcStart: usize,
|
|
103
|
+
srcEnd: usize,
|
|
104
|
+
slot: usize,
|
|
105
|
+
): usize {
|
|
104
106
|
let negative = false;
|
|
105
107
|
let code = load<u16>(srcStart);
|
|
106
108
|
if (code == 45) {
|
|
@@ -130,12 +132,16 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
|
|
|
130
132
|
srcStart += 2;
|
|
131
133
|
}
|
|
132
134
|
|
|
133
|
-
|
|
135
|
+
storeSignedInteger<T>(slot, negative ? -(<i64>value) : <i64>value);
|
|
134
136
|
return srcStart;
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
|
|
138
|
-
@inline function parseUnsignedIntegerSIMD<T extends number[]>(
|
|
140
|
+
@inline function parseUnsignedIntegerSIMD<T extends number[]>(
|
|
141
|
+
srcStart: usize,
|
|
142
|
+
srcEnd: usize,
|
|
143
|
+
slot: usize,
|
|
144
|
+
): usize {
|
|
139
145
|
let digit = <u32>load<u16>(srcStart) - 48;
|
|
140
146
|
if (digit > 9) return 0;
|
|
141
147
|
|
|
@@ -156,13 +162,248 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
|
|
|
156
162
|
srcStart += 2;
|
|
157
163
|
}
|
|
158
164
|
|
|
159
|
-
|
|
165
|
+
storeUnsignedInteger<T>(slot, value);
|
|
160
166
|
return srcStart;
|
|
161
167
|
}
|
|
162
168
|
|
|
169
|
+
|
|
170
|
+
@lazy const COMMA_SPLAT_8 = i16x8.splat(<i16>COMMA);
|
|
171
|
+
|
|
172
|
+
// Pair-multiply weights for the common two-element packings in 8-char blocks.
|
|
173
|
+
// Lanes that fall on a `,` become garbage after the subtract-by-`0` but are
|
|
174
|
+
// killed by zero weights in `i32x4.dot_i16x8_s`. The 9 (a, b) combinations
|
|
175
|
+
// where a+b in {2..6} all reach via these weight vectors; the bottom three
|
|
176
|
+
// (one digit + one digit, etc.) are left to the SWAR cascade fallback since
|
|
177
|
+
// they hit <2% on the uniform 0..255 sweep and add branch cost here.
|
|
178
|
+
// 3+3 (`DDD,DDD,`) bitmask 0x88, advance 16
|
|
179
|
+
// 3+2 (`DDD,DD,?`) bitmask 0x48, advance 14
|
|
180
|
+
// 2+3 (`DD,DDD,?`) bitmask 0x44, advance 14
|
|
181
|
+
// 2+2 (`DD,DD,??`) bitmask 0x24, advance 12
|
|
182
|
+
// 3+1 (`DDD,D,??`) bitmask 0x28, advance 12
|
|
183
|
+
// 1+3 (`D,DDD,??`) bitmask 0x22, advance 12
|
|
184
|
+
@lazy const PAIR_WEIGHTS_3_3_8 = i16x8(100, 10, 1, 0, 100, 10, 1, 0);
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@lazy const PAIR_WEIGHTS_3_2_8 = i16x8(100, 10, 1, 0, 10, 1, 0, 0);
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@lazy const PAIR_WEIGHTS_2_3_8 = i16x8(10, 1, 0, 100, 10, 1, 0, 0);
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@lazy const PAIR_WEIGHTS_2_2_8 = i16x8(10, 1, 0, 10, 1, 0, 0, 0);
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@lazy const PAIR_WEIGHTS_3_1_8 = i16x8(100, 10, 1, 0, 1, 0, 0, 0);
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@lazy const PAIR_WEIGHTS_1_3_8 = i16x8(1, 0, 100, 10, 1, 0, 0, 0);
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@lazy const SPLAT_30_8 = i16x8.splat(0x30);
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Narrow-lane (u8/i8) integer-array deserializer for SIMD mode.
|
|
206
|
+
*
|
|
207
|
+
* The 8-digit SIMD kernel (`tryParseEightDigitsSIMD`) can't fire for u8/i8
|
|
208
|
+
* (max 3 digits), so we skip it entirely and instead pay SIMD cost where
|
|
209
|
+
* it's a strict win: pre-counting commas with a v128 stride. The exact
|
|
210
|
+
* pre-size lets the parse pass use unchecked pointer stores in place of
|
|
211
|
+
* `Array.push`, eliminating its per-element capacity check / length write.
|
|
212
|
+
*/
|
|
213
|
+
function deserializeNarrowIntegerArray_SIMD<T extends number[]>(
|
|
214
|
+
srcStart: usize,
|
|
215
|
+
srcEnd: usize,
|
|
216
|
+
dst: usize,
|
|
217
|
+
): T {
|
|
218
|
+
const out = changetype<nonnull<T>>(
|
|
219
|
+
dst || changetype<usize>(instantiate<T>()),
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
// See SWAR variant: worst-case sizing is `(srcLen / 4)` elements (1 digit
|
|
223
|
+
// + 1 delimiter per element). Zero-fill is skipped for u8/i8 in AS so the
|
|
224
|
+
// over-allocation costs only a small amount of trimmed storage.
|
|
225
|
+
const maxElements = i32((<usize>(srcEnd - srcStart)) >> 2);
|
|
226
|
+
if (maxElements > 0) out.length = maxElements;
|
|
227
|
+
const dataStart = out.dataStart;
|
|
228
|
+
const elementSize = sizeof<valueof<T>>();
|
|
229
|
+
let writePtr = dataStart;
|
|
230
|
+
|
|
231
|
+
while (srcStart < srcEnd) {
|
|
232
|
+
// Fast path: two packed 3-digit elements in one v128 load. Pattern
|
|
233
|
+
// matches `DDD,DDD,` (commas at lanes 3 and 7) which is the majority of
|
|
234
|
+
// pairs for any payload whose values frequently land in 100..255.
|
|
235
|
+
// `i32x4.dot_i16x8_s` with the (100, 10, 1, 0) weights collapses the two
|
|
236
|
+
// 3-digit folds into the dot lanes, then a pair of extracts+adds gives
|
|
237
|
+
// both values without per-element scalar loops.
|
|
238
|
+
if (!isSigned<valueof<T>>() && srcStart + 14 < srcEnd) {
|
|
239
|
+
const block = load<v128>(srcStart);
|
|
240
|
+
const bitmask = i16x8.bitmask(i16x8.eq(block, COMMA_SPLAT_8));
|
|
241
|
+
// Switch on the comma layout. Each branch is a single i32x4.dot with
|
|
242
|
+
// its own (a, b) weight vector, plus 2-3 lane extracts that AS lowers
|
|
243
|
+
// to constant-index reads. Ordered roughly by hit-rate on a uniform
|
|
244
|
+
// 0..255 sweep (0x88 ~37%, 0x48/0x44 ~21% each, 0x24 ~12%, 0x28/0x22
|
|
245
|
+
// ~2.4% each).
|
|
246
|
+
switch (bitmask) {
|
|
247
|
+
case 0x88: {
|
|
248
|
+
const digits = i16x8.sub(block, SPLAT_30_8);
|
|
249
|
+
const dot = i32x4.dot_i16x8_s(digits, PAIR_WEIGHTS_3_3_8);
|
|
250
|
+
const v1 = i32x4.extract_lane(dot, 0) + i32x4.extract_lane(dot, 1);
|
|
251
|
+
const v2 = i32x4.extract_lane(dot, 2) + i32x4.extract_lane(dot, 3);
|
|
252
|
+
store<valueof<T>>(writePtr, <valueof<T>>v1);
|
|
253
|
+
store<valueof<T>>(writePtr + elementSize, <valueof<T>>v2);
|
|
254
|
+
writePtr += elementSize << 1;
|
|
255
|
+
srcStart += 16;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
case 0x48: {
|
|
259
|
+
const digits = i16x8.sub(block, SPLAT_30_8);
|
|
260
|
+
const dot = i32x4.dot_i16x8_s(digits, PAIR_WEIGHTS_3_2_8);
|
|
261
|
+
const v1 = i32x4.extract_lane(dot, 0) + i32x4.extract_lane(dot, 1);
|
|
262
|
+
const v2 = i32x4.extract_lane(dot, 2);
|
|
263
|
+
store<valueof<T>>(writePtr, <valueof<T>>v1);
|
|
264
|
+
store<valueof<T>>(writePtr + elementSize, <valueof<T>>v2);
|
|
265
|
+
writePtr += elementSize << 1;
|
|
266
|
+
srcStart += 14;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
case 0x44: {
|
|
270
|
+
const digits = i16x8.sub(block, SPLAT_30_8);
|
|
271
|
+
const dot = i32x4.dot_i16x8_s(digits, PAIR_WEIGHTS_2_3_8);
|
|
272
|
+
const v1 = i32x4.extract_lane(dot, 0);
|
|
273
|
+
const v2 = i32x4.extract_lane(dot, 1) + i32x4.extract_lane(dot, 2);
|
|
274
|
+
store<valueof<T>>(writePtr, <valueof<T>>v1);
|
|
275
|
+
store<valueof<T>>(writePtr + elementSize, <valueof<T>>v2);
|
|
276
|
+
writePtr += elementSize << 1;
|
|
277
|
+
srcStart += 14;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
case 0x24: {
|
|
281
|
+
const digits = i16x8.sub(block, SPLAT_30_8);
|
|
282
|
+
const dot = i32x4.dot_i16x8_s(digits, PAIR_WEIGHTS_2_2_8);
|
|
283
|
+
const v1 = i32x4.extract_lane(dot, 0);
|
|
284
|
+
const v2 = i32x4.extract_lane(dot, 1) + i32x4.extract_lane(dot, 2);
|
|
285
|
+
store<valueof<T>>(writePtr, <valueof<T>>v1);
|
|
286
|
+
store<valueof<T>>(writePtr + elementSize, <valueof<T>>v2);
|
|
287
|
+
writePtr += elementSize << 1;
|
|
288
|
+
srcStart += 12;
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
case 0x28: {
|
|
292
|
+
const digits = i16x8.sub(block, SPLAT_30_8);
|
|
293
|
+
const dot = i32x4.dot_i16x8_s(digits, PAIR_WEIGHTS_3_1_8);
|
|
294
|
+
const v1 = i32x4.extract_lane(dot, 0) + i32x4.extract_lane(dot, 1);
|
|
295
|
+
const v2 = i32x4.extract_lane(dot, 2);
|
|
296
|
+
store<valueof<T>>(writePtr, <valueof<T>>v1);
|
|
297
|
+
store<valueof<T>>(writePtr + elementSize, <valueof<T>>v2);
|
|
298
|
+
writePtr += elementSize << 1;
|
|
299
|
+
srcStart += 12;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
case 0x22: {
|
|
303
|
+
const digits = i16x8.sub(block, SPLAT_30_8);
|
|
304
|
+
const dot = i32x4.dot_i16x8_s(digits, PAIR_WEIGHTS_1_3_8);
|
|
305
|
+
const v1 = i32x4.extract_lane(dot, 0);
|
|
306
|
+
const v2 = i32x4.extract_lane(dot, 1) + i32x4.extract_lane(dot, 2);
|
|
307
|
+
store<valueof<T>>(writePtr, <valueof<T>>v1);
|
|
308
|
+
store<valueof<T>>(writePtr + elementSize, <valueof<T>>v2);
|
|
309
|
+
writePtr += elementSize << 1;
|
|
310
|
+
srcStart += 12;
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Single-element SWAR fast paths cover the cases where the v128 block
|
|
316
|
+
// didn't match 0x88 (mixed widths, partial element trailing the block).
|
|
317
|
+
if (!isSigned<valueof<T>>() && srcStart + 6 < srcEnd) {
|
|
318
|
+
const block64 = load<u64>(srcStart);
|
|
319
|
+
if (((block64 >> 48) & 0xffff) == COMMA) {
|
|
320
|
+
const digits =
|
|
321
|
+
(block64 & 0x0000_00ff_00ff_00ff) - 0x0000_0030_0030_0030;
|
|
322
|
+
const oor =
|
|
323
|
+
(digits | (digits + 0x0000_0006_0006_0006)) & 0x0000_fff0_fff0_fff0;
|
|
324
|
+
if (oor == 0) {
|
|
325
|
+
const d0 = <u32>(digits & 0xffff);
|
|
326
|
+
const d1 = <u32>((digits >> 16) & 0xffff);
|
|
327
|
+
const d2 = <u32>((digits >> 32) & 0xffff);
|
|
328
|
+
store<valueof<T>>(writePtr, <valueof<T>>(d0 * 100 + d1 * 10 + d2));
|
|
329
|
+
writePtr += elementSize;
|
|
330
|
+
srcStart += 8;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
} else if (((block64 >> 32) & 0xffff) == COMMA) {
|
|
334
|
+
const digits =
|
|
335
|
+
(block64 & 0x0000_0000_00ff_00ff) - 0x0000_0000_0030_0030;
|
|
336
|
+
const oor =
|
|
337
|
+
(digits | (digits + 0x0000_0000_0006_0006)) & 0x0000_0000_fff0_fff0;
|
|
338
|
+
if (oor == 0) {
|
|
339
|
+
const d0 = <u32>(digits & 0xffff);
|
|
340
|
+
const d1 = <u32>((digits >> 16) & 0xffff);
|
|
341
|
+
store<valueof<T>>(writePtr, <valueof<T>>(d0 * 10 + d1));
|
|
342
|
+
writePtr += elementSize;
|
|
343
|
+
srcStart += 6;
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
} else if (((block64 >> 16) & 0xffff) == COMMA) {
|
|
347
|
+
const d0 = <u32>(block64 & 0xffff) - 48;
|
|
348
|
+
if (d0 <= 9) {
|
|
349
|
+
store<valueof<T>>(writePtr, <valueof<T>>d0);
|
|
350
|
+
writePtr += elementSize;
|
|
351
|
+
srcStart += 4;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const code = load<u16>(srcStart);
|
|
357
|
+
if (<u32>code - 48 <= 9 || (isSigned<valueof<T>>() && code == 45)) {
|
|
358
|
+
const lastIndex = srcStart;
|
|
359
|
+
srcStart += 2;
|
|
360
|
+
while (srcStart < srcEnd) {
|
|
361
|
+
const c = load<u16>(srcStart);
|
|
362
|
+
if (c == COMMA || c == BRACKET_RIGHT || isSpace(c)) {
|
|
363
|
+
let value: u64 = 0;
|
|
364
|
+
let p = lastIndex;
|
|
365
|
+
if (isSigned<valueof<T>>() && load<u16>(p) == 45) {
|
|
366
|
+
p += 2;
|
|
367
|
+
while (p < srcStart) {
|
|
368
|
+
value = value * 10 + (<u32>load<u16>(p) - 48);
|
|
369
|
+
p += 2;
|
|
370
|
+
}
|
|
371
|
+
store<valueof<T>>(writePtr, <valueof<T>>-(<i64>value));
|
|
372
|
+
} else {
|
|
373
|
+
while (p < srcStart) {
|
|
374
|
+
value = value * 10 + (<u32>load<u16>(p) - 48);
|
|
375
|
+
p += 2;
|
|
376
|
+
}
|
|
377
|
+
store<valueof<T>>(writePtr, <valueof<T>>value);
|
|
378
|
+
}
|
|
379
|
+
writePtr += elementSize;
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
srcStart += 2;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
srcStart += 2;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
out.length = i32(<usize>(writePtr - dataStart) / elementSize);
|
|
389
|
+
return out;
|
|
390
|
+
}
|
|
391
|
+
|
|
163
392
|
// @ts-ignore: Decorator valid here
|
|
164
|
-
export function deserializeIntegerArray_SIMD<T extends number[]>(
|
|
165
|
-
|
|
393
|
+
export function deserializeIntegerArray_SIMD<T extends number[]>(
|
|
394
|
+
srcStart: usize,
|
|
395
|
+
srcEnd: usize,
|
|
396
|
+
dst: usize,
|
|
397
|
+
): T {
|
|
398
|
+
// u8/i8 elements never amortize the 8-digit SIMD kernel; route them
|
|
399
|
+
// through the SIMD-counted narrow-lane fast path. AS folds the sizeof
|
|
400
|
+
// check at compile time.
|
|
401
|
+
if (sizeof<valueof<T>>() <= 1) {
|
|
402
|
+
return deserializeNarrowIntegerArray_SIMD<T>(srcStart, srcEnd, dst);
|
|
403
|
+
}
|
|
404
|
+
const out = changetype<nonnull<T>>(
|
|
405
|
+
dst || changetype<usize>(instantiate<T>()),
|
|
406
|
+
);
|
|
166
407
|
const originalSrcStart = srcStart;
|
|
167
408
|
const reusableLength = out.length;
|
|
168
409
|
|
|
@@ -209,7 +450,10 @@ export function deserializeIntegerArray_SIMD<T extends number[]>(srcStart: usize
|
|
|
209
450
|
}
|
|
210
451
|
|
|
211
452
|
if (index >= reusableLength) break;
|
|
212
|
-
storeSignedInteger<T>(
|
|
453
|
+
storeSignedInteger<T>(
|
|
454
|
+
dataStart + <usize>index * sizeof<valueof<T>>(),
|
|
455
|
+
negative ? -(<i64>value) : <i64>value,
|
|
456
|
+
);
|
|
213
457
|
index++;
|
|
214
458
|
if (srcStart >= srcEnd) break;
|
|
215
459
|
|
|
@@ -245,7 +489,10 @@ export function deserializeIntegerArray_SIMD<T extends number[]>(srcStart: usize
|
|
|
245
489
|
}
|
|
246
490
|
|
|
247
491
|
if (index >= reusableLength) break;
|
|
248
|
-
storeUnsignedInteger<T>(
|
|
492
|
+
storeUnsignedInteger<T>(
|
|
493
|
+
dataStart + <usize>index * sizeof<valueof<T>>(),
|
|
494
|
+
value,
|
|
495
|
+
);
|
|
249
496
|
index++;
|
|
250
497
|
if (srcStart >= srcEnd) break;
|
|
251
498
|
|
|
@@ -266,42 +513,72 @@ export function deserializeIntegerArray_SIMD<T extends number[]>(srcStart: usize
|
|
|
266
513
|
srcStart = originalSrcStart;
|
|
267
514
|
}
|
|
268
515
|
|
|
269
|
-
|
|
516
|
+
// Worst-case sizing: every element is at least 1 digit + 1 delimiter = 2
|
|
517
|
+
// UTF-16 chars = 4 bytes. The parse helpers below store through `writePtr`
|
|
518
|
+
// directly, eliminating `Array.push`'s per-element capacity check + length
|
|
519
|
+
// write for every integer width.
|
|
520
|
+
const elementSize = sizeof<valueof<T>>();
|
|
521
|
+
const maxElements = i32((<usize>(srcEnd - srcStart)) >> 2);
|
|
522
|
+
if (maxElements > 0) out.length = maxElements;
|
|
523
|
+
const dataStart = out.dataStart;
|
|
524
|
+
let writePtr = dataStart;
|
|
270
525
|
|
|
271
526
|
do {
|
|
272
527
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
273
528
|
srcStart += 2;
|
|
274
529
|
if (srcStart >= srcEnd) break;
|
|
275
|
-
if (load<u16>(srcStart) == BRACKET_RIGHT)
|
|
530
|
+
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
531
|
+
out.length = 0;
|
|
532
|
+
return out;
|
|
533
|
+
}
|
|
276
534
|
|
|
277
535
|
if (isSigned<valueof<T>>()) {
|
|
278
536
|
while (srcStart < srcEnd) {
|
|
279
|
-
|
|
280
|
-
if (!
|
|
537
|
+
const next = parseSignedIntegerSIMD<T>(srcStart, srcEnd, writePtr);
|
|
538
|
+
if (!next) break;
|
|
539
|
+
writePtr += elementSize;
|
|
540
|
+
srcStart = next;
|
|
541
|
+
if (srcStart >= srcEnd) break;
|
|
281
542
|
|
|
282
543
|
const code = load<u16>(srcStart);
|
|
283
544
|
if (code == COMMA) {
|
|
284
545
|
srcStart += 2;
|
|
285
546
|
continue;
|
|
286
547
|
}
|
|
287
|
-
if (code == BRACKET_RIGHT)
|
|
548
|
+
if (code == BRACKET_RIGHT) {
|
|
549
|
+
out.length = i32(<usize>(writePtr - dataStart) / elementSize);
|
|
550
|
+
return out;
|
|
551
|
+
}
|
|
288
552
|
break;
|
|
289
553
|
}
|
|
290
554
|
} else {
|
|
291
555
|
while (srcStart < srcEnd) {
|
|
292
|
-
|
|
293
|
-
if (!
|
|
556
|
+
const next = parseUnsignedIntegerSIMD<T>(srcStart, srcEnd, writePtr);
|
|
557
|
+
if (!next) break;
|
|
558
|
+
writePtr += elementSize;
|
|
559
|
+
srcStart = next;
|
|
560
|
+
if (srcStart >= srcEnd) break;
|
|
294
561
|
|
|
295
562
|
const code = load<u16>(srcStart);
|
|
296
563
|
if (code == COMMA) {
|
|
297
564
|
srcStart += 2;
|
|
298
565
|
continue;
|
|
299
566
|
}
|
|
300
|
-
if (code == BRACKET_RIGHT)
|
|
567
|
+
if (code == BRACKET_RIGHT) {
|
|
568
|
+
out.length = i32(<usize>(writePtr - dataStart) / elementSize);
|
|
569
|
+
return out;
|
|
570
|
+
}
|
|
301
571
|
break;
|
|
302
572
|
}
|
|
303
573
|
}
|
|
304
574
|
} while (false);
|
|
305
575
|
|
|
306
|
-
|
|
576
|
+
// Fall through to SWAR's SLOW path; it resets `out.length = 0` and
|
|
577
|
+
// re-parses from the original input. The pre-allocated buffer is retained
|
|
578
|
+
// so SLOW's per-element `ensureArrayElementSlot` reuses the capacity.
|
|
579
|
+
return deserializeIntegerArray_SLOW<T>(
|
|
580
|
+
originalSrcStart,
|
|
581
|
+
srcEnd,
|
|
582
|
+
changetype<usize>(out),
|
|
583
|
+
);
|
|
307
584
|
}
|