json-as 1.3.6 → 1.3.8
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 +45 -0
- package/README.md +1 -1
- package/assembly/deserialize/helpers/uint.ts +4 -1
- package/assembly/deserialize/index/arbitrary.ts +7 -3
- package/assembly/deserialize/index/array.ts +42 -17
- 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 +68 -1
- 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 +32 -4
- package/assembly/deserialize/index/struct.ts +1 -1
- package/assembly/deserialize/index/typedarray.ts +30 -10
- package/assembly/deserialize/index/unsigned.ts +78 -1
- package/assembly/deserialize/index.ts +1 -0
- package/assembly/deserialize/{simple → naive}/array/arbitrary.ts +24 -5
- package/assembly/deserialize/{simple → naive}/array/array.ts +8 -2
- package/assembly/deserialize/naive/array/bool.ts +68 -0
- package/assembly/deserialize/{simple → naive}/array/box.ts +8 -2
- package/assembly/deserialize/naive/array/float.ts +63 -0
- package/assembly/deserialize/{simple → naive}/array/generic.ts +14 -7
- package/assembly/deserialize/naive/array/integer.ts +86 -0
- package/assembly/deserialize/naive/array/map.ts +47 -0
- package/assembly/deserialize/naive/array/object.ts +47 -0
- package/assembly/deserialize/{simple → naive}/array/raw.ts +34 -7
- package/assembly/deserialize/naive/array/string.ts +69 -0
- package/assembly/deserialize/naive/array/struct.ts +47 -0
- package/assembly/deserialize/{simple → naive}/array.ts +15 -10
- package/assembly/deserialize/{simple → naive}/bool.ts +6 -2
- package/assembly/deserialize/naive/float.ts +135 -0
- package/assembly/deserialize/{simple → naive}/integer.ts +10 -2
- package/assembly/deserialize/{simple → naive}/map.ts +106 -27
- package/assembly/deserialize/{simple → naive}/object.ts +65 -19
- package/assembly/deserialize/{simple → naive}/raw.ts +4 -1
- package/assembly/deserialize/{simple → naive}/set.ts +49 -19
- 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/string.ts +11 -3
- package/assembly/deserialize/{simple → naive}/staticarray/struct.ts +1 -2
- package/assembly/deserialize/{simple → naive}/staticarray.ts +68 -18
- package/assembly/deserialize/naive/string.ts +199 -0
- package/assembly/deserialize/{simple → naive}/struct.ts +5 -1
- package/assembly/deserialize/{simple → naive}/typedarray.ts +17 -4
- package/assembly/deserialize/{simple → naive}/unsigned.ts +10 -15
- package/assembly/deserialize/simd/array/integer.ts +339 -62
- package/assembly/deserialize/simd/float.ts +303 -0
- package/assembly/deserialize/simd/integer.ts +233 -0
- package/assembly/deserialize/simd/string.ts +266 -107
- package/assembly/deserialize/swar/array/arbitrary.ts +11 -3
- package/assembly/deserialize/swar/array/array.ts +40 -9
- package/assembly/deserialize/swar/array/bool.ts +28 -5
- package/assembly/deserialize/swar/array/box.ts +11 -3
- package/assembly/deserialize/swar/array/float.ts +295 -7
- package/assembly/deserialize/swar/array/generic.ts +28 -7
- package/assembly/deserialize/swar/array/integer.ts +363 -112
- package/assembly/deserialize/swar/array/map.ts +11 -3
- package/assembly/deserialize/swar/array/object.ts +37 -25
- package/assembly/deserialize/swar/array/raw.ts +11 -3
- package/assembly/deserialize/swar/array/shared.ts +63 -14
- package/assembly/deserialize/swar/array/string.ts +140 -7
- package/assembly/deserialize/swar/array/struct.ts +66 -12
- package/assembly/deserialize/swar/array.ts +12 -51
- package/assembly/deserialize/swar/float.ts +304 -0
- package/assembly/deserialize/swar/integer.ts +246 -0
- package/assembly/deserialize/swar/string.ts +213 -294
- package/assembly/deserialize/swar/typedarray.ts +224 -0
- package/assembly/index.d.ts +3 -1
- package/assembly/index.ts +402 -261
- 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 +5 -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 +21 -12
- package/assembly/serialize/index.ts +1 -0
- package/assembly/serialize/naive/array.ts +351 -0
- package/assembly/serialize/{simple → naive}/float.ts +4 -1
- package/assembly/serialize/naive/integer.ts +19 -0
- package/assembly/serialize/{simple → naive}/map.ts +6 -2
- package/assembly/serialize/{simple → naive}/raw.ts +5 -1
- package/assembly/serialize/{simple → naive}/set.ts +6 -1
- package/assembly/serialize/{simple → naive}/staticarray.ts +6 -1
- package/assembly/serialize/{simple → naive}/string.ts +1 -2
- package/assembly/serialize/{simple → naive}/typedarray.ts +10 -3
- package/assembly/serialize/simd/string.ts +6 -2
- package/assembly/serialize/swar/string.ts +15 -141
- 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 +53 -17
- package/assembly/util/itoa-fast.ts +241 -0
- package/assembly/util/masks.ts +18 -1
- package/assembly/util/parsefloat-fast.ts +167 -0
- package/assembly/util/scanValueEnd.ts +78 -0
- package/assembly/util/scientific.ts +132 -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 +27 -6
- package/package.json +15 -11
- 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 +5 -0
- package/transform/lib/index.d.ts.map +1 -1
- package/transform/lib/index.js +1046 -340
- 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
- package/assembly/deserialize/simple/arbitrary.ts +0 -23
- package/assembly/deserialize/simple/array/bool.ts +0 -17
- package/assembly/deserialize/simple/array/float.ts +0 -28
- package/assembly/deserialize/simple/array/integer.ts +0 -27
- package/assembly/deserialize/simple/array/map.ts +0 -28
- package/assembly/deserialize/simple/array/object.ts +0 -28
- package/assembly/deserialize/simple/array/string.ts +0 -23
- package/assembly/deserialize/simple/array/struct.ts +0 -28
- package/assembly/deserialize/simple/float.ts +0 -201
- package/assembly/deserialize/simple/string.ts +0 -132
- package/assembly/serialize/simple/arbitrary.ts +0 -79
- package/assembly/serialize/simple/array.ts +0 -86
- package/assembly/serialize/simple/integer.ts +0 -20
- package/assembly/serialize/simple/object.ts +0 -42
- /package/assembly/deserialize/{simple → naive}/date.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}/struct.ts +0 -0
|
@@ -1,53 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { deserializeUnsignedField } from "../../simple/unsigned";
|
|
1
|
+
import { deserializeIntegerArray_NAIVE } from "../../naive/array/integer";
|
|
3
2
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
4
3
|
import { isSpace } from "../../../util";
|
|
5
4
|
import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@inline function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} else if (sizeof<valueof<T>>() == sizeof<i32>()) {
|
|
19
|
-
out.push(<valueof<T>>(<i32>value));
|
|
20
|
-
} else if (sizeof<valueof<T>>() == sizeof<isize>()) {
|
|
21
|
-
out.push(<valueof<T>>(<isize>value));
|
|
22
|
-
} else {
|
|
23
|
-
out.push(<valueof<T>>value);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@inline function pushUnsignedInteger<T extends number[]>(out: T, value: u64): void {
|
|
29
|
-
if (sizeof<valueof<T>>() == sizeof<u8>()) {
|
|
30
|
-
out.push(<valueof<T>>(<u8>value));
|
|
31
|
-
} else if (sizeof<valueof<T>>() == sizeof<u16>()) {
|
|
32
|
-
out.push(<valueof<T>>(<u16>value));
|
|
33
|
-
} else if (sizeof<valueof<T>>() == sizeof<u32>()) {
|
|
34
|
-
out.push(<valueof<T>>(<u32>value));
|
|
35
|
-
} else if (sizeof<valueof<T>>() == sizeof<usize>()) {
|
|
36
|
-
out.push(<valueof<T>>(<usize>value));
|
|
37
|
-
} else {
|
|
38
|
-
out.push(<valueof<T>>value);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@inline function storeSignedInteger<T extends number[]>(slot: usize, value: i64): void {
|
|
44
|
-
if (sizeof<valueof<T>>() == sizeof<i8>()) {
|
|
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>(
|
|
13
|
+
slot: usize,
|
|
14
|
+
value: i64,
|
|
15
|
+
): void {
|
|
16
|
+
if (sizeof<E>() == sizeof<i8>()) {
|
|
45
17
|
store<i8>(slot, <i8>value);
|
|
46
|
-
} else if (sizeof<
|
|
18
|
+
} else if (sizeof<E>() == sizeof<i16>()) {
|
|
47
19
|
store<i16>(slot, <i16>value);
|
|
48
|
-
} else if (sizeof<
|
|
20
|
+
} else if (sizeof<E>() == sizeof<i32>()) {
|
|
49
21
|
store<i32>(slot, <i32>value);
|
|
50
|
-
} else if (sizeof<
|
|
22
|
+
} else if (sizeof<E>() == sizeof<isize>()) {
|
|
51
23
|
store<isize>(slot, <isize>value);
|
|
52
24
|
} else {
|
|
53
25
|
store<i64>(slot, value);
|
|
@@ -55,30 +27,37 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
55
27
|
}
|
|
56
28
|
|
|
57
29
|
|
|
58
|
-
@inline function
|
|
59
|
-
|
|
30
|
+
@inline function storeUnsignedIntegerE<E extends number>(
|
|
31
|
+
slot: usize,
|
|
32
|
+
value: u64,
|
|
33
|
+
): void {
|
|
34
|
+
if (sizeof<E>() == sizeof<u8>()) {
|
|
60
35
|
store<u8>(slot, <u8>value);
|
|
61
|
-
} else if (sizeof<
|
|
36
|
+
} else if (sizeof<E>() == sizeof<u16>()) {
|
|
62
37
|
store<u16>(slot, <u16>value);
|
|
63
|
-
} else if (sizeof<
|
|
38
|
+
} else if (sizeof<E>() == sizeof<u32>()) {
|
|
64
39
|
store<u32>(slot, <u32>value);
|
|
65
|
-
} else if (sizeof<
|
|
40
|
+
} else if (sizeof<E>() == sizeof<usize>()) {
|
|
66
41
|
store<usize>(slot, <usize>value);
|
|
67
42
|
} else {
|
|
68
43
|
store<u64>(slot, value);
|
|
69
44
|
}
|
|
70
45
|
}
|
|
71
46
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@inline function parseSignedIntegerScalar<
|
|
47
|
+
// The four parse helpers below take a `slot` pointer (`writePtr`) and store
|
|
48
|
+
// the value directly via `store<valueof<T>>(slot, ...)`. The outer dispatcher
|
|
49
|
+
// owns the array's `out.length = maxElements` pre-allocation and the
|
|
50
|
+
// `writePtr` advance, so the per-element `Array.push` capacity check and
|
|
51
|
+
// length write are eliminated for every integer width, not just the u8/i8
|
|
52
|
+
// narrow-lane path.
|
|
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>(
|
|
57
|
+
srcStart: usize,
|
|
58
|
+
srcEnd: usize,
|
|
59
|
+
slot: usize,
|
|
60
|
+
): usize {
|
|
82
61
|
let negative = false;
|
|
83
62
|
let code = load<u16>(srcStart);
|
|
84
63
|
if (code == 45) {
|
|
@@ -100,12 +79,16 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
100
79
|
srcStart += 2;
|
|
101
80
|
}
|
|
102
81
|
|
|
103
|
-
|
|
82
|
+
storeSignedIntegerE<E>(slot, negative ? -(<i64>value) : <i64>value);
|
|
104
83
|
return srcStart;
|
|
105
84
|
}
|
|
106
85
|
|
|
107
86
|
|
|
108
|
-
@inline function parseUnsignedIntegerScalar<
|
|
87
|
+
@inline export function parseUnsignedIntegerScalar<E extends number>(
|
|
88
|
+
srcStart: usize,
|
|
89
|
+
srcEnd: usize,
|
|
90
|
+
slot: usize,
|
|
91
|
+
): usize {
|
|
109
92
|
let digit = <u32>load<u16>(srcStart) - 48;
|
|
110
93
|
if (digit > 9) return 0;
|
|
111
94
|
|
|
@@ -118,12 +101,16 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
118
101
|
srcStart += 2;
|
|
119
102
|
}
|
|
120
103
|
|
|
121
|
-
|
|
104
|
+
storeUnsignedIntegerE<E>(slot, value);
|
|
122
105
|
return srcStart;
|
|
123
106
|
}
|
|
124
107
|
|
|
125
108
|
|
|
126
|
-
@inline function parseSignedIntegerSWAR<
|
|
109
|
+
@inline export function parseSignedIntegerSWAR<E extends number>(
|
|
110
|
+
srcStart: usize,
|
|
111
|
+
srcEnd: usize,
|
|
112
|
+
slot: usize,
|
|
113
|
+
): usize {
|
|
127
114
|
let negative = false;
|
|
128
115
|
let code = load<u16>(srcStart);
|
|
129
116
|
if (code == 45) {
|
|
@@ -139,11 +126,21 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
139
126
|
let value: u64 = digit;
|
|
140
127
|
srcStart += 2;
|
|
141
128
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
+
//
|
|
134
|
+
// i8 tops out at 3 digits (-128..127), so the 4-digit kernel can never fire
|
|
135
|
+
// and the failing load + range check just burns cycles. Gate on the lane
|
|
136
|
+
// width so AS folds the loop away at compile time.
|
|
137
|
+
if (sizeof<E>() > 1) {
|
|
138
|
+
while (srcStart + 6 < srcEnd) {
|
|
139
|
+
const parsed = parse4Digits_PairMul(load<u64>(srcStart));
|
|
140
|
+
if (parsed == U32.MAX_VALUE) break;
|
|
141
|
+
value = value * 10000 + parsed;
|
|
142
|
+
srcStart += 8;
|
|
143
|
+
}
|
|
147
144
|
}
|
|
148
145
|
|
|
149
146
|
while (srcStart < srcEnd) {
|
|
@@ -153,20 +150,54 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
153
150
|
srcStart += 2;
|
|
154
151
|
}
|
|
155
152
|
|
|
156
|
-
|
|
153
|
+
storeSignedIntegerE<E>(slot, negative ? -(<i64>value) : <i64>value);
|
|
157
154
|
return srcStart;
|
|
158
155
|
}
|
|
159
156
|
|
|
160
157
|
|
|
161
|
-
@inline function parseUnsignedIntegerSWAR<
|
|
158
|
+
@inline export function parseUnsignedIntegerSWAR<E extends number>(
|
|
159
|
+
srcStart: usize,
|
|
160
|
+
srcEnd: usize,
|
|
161
|
+
slot: usize,
|
|
162
|
+
): usize {
|
|
163
|
+
// Narrow-type path mirrors the NAIVE structure: a tight scan loop to find
|
|
164
|
+
// the element terminator, then a fixed-count fold with no per-digit break.
|
|
165
|
+
// TurboFan tends to schedule this better than a single combined
|
|
166
|
+
// scan-and-fold loop because the fold has no data-dependent exit.
|
|
167
|
+
if (sizeof<E>() <= 2) {
|
|
168
|
+
const first = <u32>load<u16>(srcStart) - 48;
|
|
169
|
+
if (first > 9) return 0;
|
|
170
|
+
const lastIndex = srcStart;
|
|
171
|
+
srcStart += 2;
|
|
172
|
+
while (srcStart < srcEnd) {
|
|
173
|
+
const c = <u32>load<u16>(srcStart) - 48;
|
|
174
|
+
if (c > 9) break;
|
|
175
|
+
srcStart += 2;
|
|
176
|
+
}
|
|
177
|
+
let value: u64 = 0;
|
|
178
|
+
let p = lastIndex;
|
|
179
|
+
while (p < srcStart) {
|
|
180
|
+
value = value * 10 + (<u32>load<u16>(p) - 48);
|
|
181
|
+
p += 2;
|
|
182
|
+
}
|
|
183
|
+
storeUnsignedIntegerE<E>(slot, value);
|
|
184
|
+
return srcStart;
|
|
185
|
+
}
|
|
186
|
+
|
|
162
187
|
let digit = <u32>load<u16>(srcStart) - 48;
|
|
163
188
|
if (digit > 9) return 0;
|
|
164
189
|
|
|
165
190
|
let value: u64 = digit;
|
|
166
191
|
srcStart += 2;
|
|
167
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.
|
|
168
199
|
while (srcStart + 6 < srcEnd) {
|
|
169
|
-
const parsed =
|
|
200
|
+
const parsed = parse4Digits_PairMul(load<u64>(srcStart));
|
|
170
201
|
if (parsed == U32.MAX_VALUE) break;
|
|
171
202
|
value = value * 10000 + parsed;
|
|
172
203
|
srcStart += 8;
|
|
@@ -179,12 +210,15 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
179
210
|
srcStart += 2;
|
|
180
211
|
}
|
|
181
212
|
|
|
182
|
-
|
|
213
|
+
storeUnsignedIntegerE<E>(slot, value);
|
|
183
214
|
return srcStart;
|
|
184
215
|
}
|
|
185
216
|
|
|
186
217
|
|
|
187
|
-
@inline function skipIntegerArrayWhitespace(
|
|
218
|
+
@inline function skipIntegerArrayWhitespace(
|
|
219
|
+
srcStart: usize,
|
|
220
|
+
srcEnd: usize,
|
|
221
|
+
): usize {
|
|
188
222
|
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) {
|
|
189
223
|
srcStart += 2;
|
|
190
224
|
}
|
|
@@ -192,12 +226,17 @@ const ASCII_RANGE_ADD_4: u64 = 0x0006000600060006;
|
|
|
192
226
|
}
|
|
193
227
|
|
|
194
228
|
// @ts-ignore: Decorator valid here
|
|
195
|
-
export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
196
|
-
|
|
229
|
+
export function deserializeIntegerArray_SLOW<T extends number[]>(
|
|
230
|
+
srcStart: usize,
|
|
231
|
+
srcEnd: usize,
|
|
232
|
+
dst: usize,
|
|
233
|
+
): T {
|
|
234
|
+
const out = changetype<nonnull<T>>(
|
|
235
|
+
dst || changetype<usize>(instantiate<T>()),
|
|
236
|
+
);
|
|
197
237
|
let index = 0;
|
|
198
238
|
|
|
199
239
|
out.length = 0;
|
|
200
|
-
srcStart = skipIntegerArrayWhitespace(srcStart, srcEnd);
|
|
201
240
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) {
|
|
202
241
|
throw new Error("Failed to parse JSON!");
|
|
203
242
|
}
|
|
@@ -231,7 +270,10 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(srcStart: usize
|
|
|
231
270
|
srcStart += 2;
|
|
232
271
|
}
|
|
233
272
|
|
|
234
|
-
|
|
273
|
+
storeSignedIntegerE<valueof<T>>(
|
|
274
|
+
ensureArrayElementSlot<T>(out, index),
|
|
275
|
+
negative ? -(<i64>value) : <i64>value,
|
|
276
|
+
);
|
|
235
277
|
} else {
|
|
236
278
|
let digit = <u32>code - 48;
|
|
237
279
|
if (digit > 9) break;
|
|
@@ -245,7 +287,10 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(srcStart: usize
|
|
|
245
287
|
srcStart += 2;
|
|
246
288
|
}
|
|
247
289
|
|
|
248
|
-
|
|
290
|
+
storeUnsignedIntegerE<valueof<T>>(
|
|
291
|
+
ensureArrayElementSlot<T>(out, index),
|
|
292
|
+
value,
|
|
293
|
+
);
|
|
249
294
|
}
|
|
250
295
|
|
|
251
296
|
index++;
|
|
@@ -265,8 +310,15 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(srcStart: usize
|
|
|
265
310
|
}
|
|
266
311
|
|
|
267
312
|
|
|
268
|
-
@inline function deserializeIntegerArrayImpl<T extends number[]>(
|
|
269
|
-
|
|
313
|
+
@inline function deserializeIntegerArrayImpl<T extends number[]>(
|
|
314
|
+
srcStart: usize,
|
|
315
|
+
srcEnd: usize,
|
|
316
|
+
dst: usize,
|
|
317
|
+
useSWAR: bool,
|
|
318
|
+
): T {
|
|
319
|
+
const out = changetype<nonnull<T>>(
|
|
320
|
+
dst || changetype<usize>(instantiate<T>()),
|
|
321
|
+
);
|
|
270
322
|
const originalSrcStart = srcStart;
|
|
271
323
|
const reusableLength = out.length;
|
|
272
324
|
|
|
@@ -300,11 +352,13 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(srcStart: usize
|
|
|
300
352
|
let value: u64 = digit;
|
|
301
353
|
srcStart += 2;
|
|
302
354
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
355
|
+
if (sizeof<valueof<T>>() > 1) {
|
|
356
|
+
while (srcStart + 6 < srcEnd) {
|
|
357
|
+
const parsed = parse4Digits_PairMul(load<u64>(srcStart));
|
|
358
|
+
if (parsed == U32.MAX_VALUE) break;
|
|
359
|
+
value = value * 10000 + parsed;
|
|
360
|
+
srcStart += 8;
|
|
361
|
+
}
|
|
308
362
|
}
|
|
309
363
|
|
|
310
364
|
while (srcStart < srcEnd) {
|
|
@@ -315,7 +369,10 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(srcStart: usize
|
|
|
315
369
|
}
|
|
316
370
|
|
|
317
371
|
if (index >= reusableLength) break;
|
|
318
|
-
|
|
372
|
+
storeSignedIntegerE<valueof<T>>(
|
|
373
|
+
dataStart + <usize>index * sizeof<valueof<T>>(),
|
|
374
|
+
negative ? -(<i64>value) : <i64>value,
|
|
375
|
+
);
|
|
319
376
|
index++;
|
|
320
377
|
if (srcStart >= srcEnd) break;
|
|
321
378
|
|
|
@@ -338,11 +395,13 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(srcStart: usize
|
|
|
338
395
|
let value: u64 = digit;
|
|
339
396
|
srcStart += 2;
|
|
340
397
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
398
|
+
if (sizeof<valueof<T>>() > 1) {
|
|
399
|
+
while (srcStart + 6 < srcEnd) {
|
|
400
|
+
const parsed = parse4Digits_PairMul(load<u64>(srcStart));
|
|
401
|
+
if (parsed == U32.MAX_VALUE) break;
|
|
402
|
+
value = value * 10000 + parsed;
|
|
403
|
+
srcStart += 8;
|
|
404
|
+
}
|
|
346
405
|
}
|
|
347
406
|
|
|
348
407
|
while (srcStart < srcEnd) {
|
|
@@ -353,7 +412,10 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(srcStart: usize
|
|
|
353
412
|
}
|
|
354
413
|
|
|
355
414
|
if (index >= reusableLength) break;
|
|
356
|
-
|
|
415
|
+
storeUnsignedIntegerE<valueof<T>>(
|
|
416
|
+
dataStart + <usize>index * sizeof<valueof<T>>(),
|
|
417
|
+
value,
|
|
418
|
+
);
|
|
357
419
|
index++;
|
|
358
420
|
if (srcStart >= srcEnd) break;
|
|
359
421
|
|
|
@@ -374,63 +436,226 @@ export function deserializeIntegerArray_SLOW<T extends number[]>(srcStart: usize
|
|
|
374
436
|
srcStart = originalSrcStart;
|
|
375
437
|
}
|
|
376
438
|
|
|
377
|
-
|
|
439
|
+
// Worst-case sizing: every element is at least 1 digit + 1 delimiter = 2
|
|
440
|
+
// UTF-16 chars = 4 bytes. AS skips zero-fill on `length=` for unmanaged
|
|
441
|
+
// primitive types (every concrete `valueof<T>` here is an integer), so the
|
|
442
|
+
// over-allocation costs only a small amount of trimmed storage at the end.
|
|
443
|
+
// The parse helpers below store through `writePtr` directly, eliminating
|
|
444
|
+
// `Array.push`'s per-element capacity check + length write for every
|
|
445
|
+
// integer width.
|
|
446
|
+
const elementSize = sizeof<valueof<T>>();
|
|
447
|
+
const maxElements = i32((<usize>(srcEnd - srcStart)) >> 2);
|
|
448
|
+
if (maxElements > 0) out.length = maxElements;
|
|
449
|
+
const dataStart = out.dataStart;
|
|
450
|
+
let writePtr = dataStart;
|
|
378
451
|
|
|
379
452
|
do {
|
|
380
453
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
381
454
|
srcStart += 2;
|
|
382
455
|
if (srcStart >= srcEnd) break;
|
|
383
|
-
if (load<u16>(srcStart) == BRACKET_RIGHT)
|
|
456
|
+
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
457
|
+
out.length = 0;
|
|
458
|
+
return out;
|
|
459
|
+
}
|
|
384
460
|
|
|
385
461
|
if (isSigned<valueof<T>>()) {
|
|
386
462
|
while (srcStart < srcEnd) {
|
|
387
|
-
|
|
388
|
-
|
|
463
|
+
const next = useSWAR
|
|
464
|
+
? parseSignedIntegerSWAR<valueof<T>>(srcStart, srcEnd, writePtr)
|
|
465
|
+
: parseSignedIntegerScalar<valueof<T>>(srcStart, srcEnd, writePtr);
|
|
466
|
+
if (!next) break;
|
|
467
|
+
writePtr += elementSize;
|
|
468
|
+
srcStart = next;
|
|
469
|
+
if (srcStart >= srcEnd) break;
|
|
389
470
|
|
|
390
471
|
const code = load<u16>(srcStart);
|
|
391
472
|
if (code == COMMA) {
|
|
392
473
|
srcStart += 2;
|
|
393
474
|
continue;
|
|
394
475
|
}
|
|
395
|
-
if (code == BRACKET_RIGHT)
|
|
476
|
+
if (code == BRACKET_RIGHT) {
|
|
477
|
+
out.length = i32(<usize>(writePtr - dataStart) / elementSize);
|
|
478
|
+
return out;
|
|
479
|
+
}
|
|
396
480
|
break;
|
|
397
481
|
}
|
|
398
482
|
} else {
|
|
399
483
|
while (srcStart < srcEnd) {
|
|
400
|
-
|
|
401
|
-
|
|
484
|
+
const next = useSWAR
|
|
485
|
+
? parseUnsignedIntegerSWAR<valueof<T>>(srcStart, srcEnd, writePtr)
|
|
486
|
+
: parseUnsignedIntegerScalar<valueof<T>>(srcStart, srcEnd, writePtr);
|
|
487
|
+
if (!next) break;
|
|
488
|
+
writePtr += elementSize;
|
|
489
|
+
srcStart = next;
|
|
490
|
+
if (srcStart >= srcEnd) break;
|
|
402
491
|
|
|
403
492
|
const code = load<u16>(srcStart);
|
|
404
493
|
if (code == COMMA) {
|
|
405
494
|
srcStart += 2;
|
|
406
495
|
continue;
|
|
407
496
|
}
|
|
408
|
-
if (code == BRACKET_RIGHT)
|
|
497
|
+
if (code == BRACKET_RIGHT) {
|
|
498
|
+
out.length = i32(<usize>(writePtr - dataStart) / elementSize);
|
|
499
|
+
return out;
|
|
500
|
+
}
|
|
409
501
|
break;
|
|
410
502
|
}
|
|
411
503
|
}
|
|
412
504
|
} while (false);
|
|
413
505
|
|
|
414
|
-
|
|
506
|
+
// Fast path bailed (whitespace, malformed numbers, etc). Hand off to the
|
|
507
|
+
// SLOW path which resets `out.length` to 0 and re-parses from the original
|
|
508
|
+
// input. The pre-allocated buffer is retained, so SLOW's per-element
|
|
509
|
+
// `ensureArrayElementSlot` grows-or-reuses through the existing capacity.
|
|
510
|
+
return deserializeIntegerArray_SLOW<T>(
|
|
511
|
+
originalSrcStart,
|
|
512
|
+
srcEnd,
|
|
513
|
+
changetype<usize>(out),
|
|
514
|
+
);
|
|
415
515
|
}
|
|
416
516
|
|
|
417
517
|
// @ts-ignore: Decorator valid here
|
|
418
|
-
export function
|
|
419
|
-
|
|
518
|
+
export function deserializeIntegerArray_SWAR<T extends number[]>(
|
|
519
|
+
srcStart: usize,
|
|
520
|
+
srcEnd: usize,
|
|
521
|
+
dst: usize,
|
|
522
|
+
): T {
|
|
523
|
+
// u8/i8 elements use a dedicated two-pass SWAR path: a 4-char-stride
|
|
524
|
+
// comma counter pre-sizes the array so the parse pass can drop the
|
|
525
|
+
// per-push capacity check and write through a direct pointer. The
|
|
526
|
+
// wider-lane SWAR kernel never amortizes itself for narrow elements
|
|
527
|
+
// (u8 max 3 digits) so we skip it entirely here.
|
|
528
|
+
if (sizeof<valueof<T>>() <= 1) {
|
|
529
|
+
return deserializeNarrowIntegerArray_SWAR<T>(srcStart, srcEnd, dst);
|
|
530
|
+
}
|
|
531
|
+
return deserializeIntegerArrayImpl<T>(srcStart, srcEnd, dst, true);
|
|
420
532
|
}
|
|
421
533
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
534
|
+
/**
|
|
535
|
+
* Narrow-lane (u8/i8) integer-array deserializer.
|
|
536
|
+
*
|
|
537
|
+
* Two passes:
|
|
538
|
+
* 1) SWAR comma counter (4 chars per stride, popcnt over the lane mask)
|
|
539
|
+
* sizes the array exactly so the parse pass can use unchecked stores.
|
|
540
|
+
* 2) Walks the input NAIVE-style (skip non-digits, scan to separator,
|
|
541
|
+
* fold digits) but writes through a direct pointer, eliminating
|
|
542
|
+
* `Array.push`'s per-element capacity check and length write.
|
|
543
|
+
*
|
|
544
|
+
* V8 already auto-SIMDs NAIVE's scalar scan loop tighter than a hand-rolled
|
|
545
|
+
* SWAR scan in pass 2, so we keep that pattern there and only pay SWAR cost
|
|
546
|
+
* on the pre-count - which is a tight load-mask-popcnt loop where V8's
|
|
547
|
+
* scalar code can't compete with the explicit 4-lane stride.
|
|
548
|
+
*/
|
|
549
|
+
function deserializeNarrowIntegerArray_SWAR<T extends number[]>(
|
|
550
|
+
srcStart: usize,
|
|
551
|
+
srcEnd: usize,
|
|
552
|
+
dst: usize,
|
|
553
|
+
): T {
|
|
554
|
+
const out = changetype<nonnull<T>>(
|
|
555
|
+
dst || changetype<usize>(instantiate<T>()),
|
|
556
|
+
);
|
|
557
|
+
|
|
558
|
+
// Worst-case sizing: every element is at least 1 digit + 1 delimiter = 2
|
|
559
|
+
// UTF-16 chars = 4 bytes, so the body inside `[...]` can't hold more than
|
|
560
|
+
// `(srcEnd - srcStart) / 4` elements. AS skips zero-fill on `length=` for
|
|
561
|
+
// unmanaged element types, so over-allocation is essentially free here
|
|
562
|
+
// and saves a full SWAR pass over the input.
|
|
563
|
+
const maxElements = i32((<usize>(srcEnd - srcStart)) >> 2);
|
|
564
|
+
if (maxElements > 0) out.length = maxElements;
|
|
565
|
+
const dataStart = out.dataStart;
|
|
566
|
+
const elementSize = sizeof<valueof<T>>();
|
|
567
|
+
let writePtr = dataStart;
|
|
568
|
+
|
|
569
|
+
while (srcStart < srcEnd) {
|
|
570
|
+
// Fast paths: 1-, 2-, or 3-digit unsigned element followed by `,` packs
|
|
571
|
+
// into one u64 load (covers ~100% of the typical 0..255 cycle). Ordered
|
|
572
|
+
// 3 -> 2 -> 1 because 3-digit values dominate any wide-range payload;
|
|
573
|
+
// the 2- and 1-digit branches cover the rest of `out`.
|
|
574
|
+
if (!isSigned<valueof<T>>() && srcStart + 6 < srcEnd) {
|
|
575
|
+
const block = load<u64>(srcStart);
|
|
576
|
+
if (((block >> 48) & 0xffff) == COMMA) {
|
|
577
|
+
const digits = (block & 0x0000_00ff_00ff_00ff) - 0x0000_0030_0030_0030;
|
|
578
|
+
const oor =
|
|
579
|
+
(digits | (digits + 0x0000_0006_0006_0006)) & 0x0000_fff0_fff0_fff0;
|
|
580
|
+
if (oor == 0) {
|
|
581
|
+
const d0 = <u32>(digits & 0xffff);
|
|
582
|
+
const d1 = <u32>((digits >> 16) & 0xffff);
|
|
583
|
+
const d2 = <u32>((digits >> 32) & 0xffff);
|
|
584
|
+
store<valueof<T>>(writePtr, <valueof<T>>(d0 * 100 + d1 * 10 + d2));
|
|
585
|
+
writePtr += elementSize;
|
|
586
|
+
srcStart += 8;
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
} else if (((block >> 32) & 0xffff) == COMMA) {
|
|
590
|
+
const digits = (block & 0x0000_0000_00ff_00ff) - 0x0000_0000_0030_0030;
|
|
591
|
+
const oor =
|
|
592
|
+
(digits | (digits + 0x0000_0000_0006_0006)) & 0x0000_0000_fff0_fff0;
|
|
593
|
+
if (oor == 0) {
|
|
594
|
+
const d0 = <u32>(digits & 0xffff);
|
|
595
|
+
const d1 = <u32>((digits >> 16) & 0xffff);
|
|
596
|
+
store<valueof<T>>(writePtr, <valueof<T>>(d0 * 10 + d1));
|
|
597
|
+
writePtr += elementSize;
|
|
598
|
+
srcStart += 6;
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
} else if (((block >> 16) & 0xffff) == COMMA) {
|
|
602
|
+
const d0 = <u32>(block & 0xffff) - 48;
|
|
603
|
+
if (d0 <= 9) {
|
|
604
|
+
store<valueof<T>>(writePtr, <valueof<T>>d0);
|
|
605
|
+
writePtr += elementSize;
|
|
606
|
+
srcStart += 4;
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
const code = load<u16>(srcStart);
|
|
612
|
+
if (<u32>code - 48 <= 9 || (isSigned<valueof<T>>() && code == 45)) {
|
|
613
|
+
const lastIndex = srcStart;
|
|
614
|
+
srcStart += 2;
|
|
615
|
+
while (srcStart < srcEnd) {
|
|
616
|
+
const c = load<u16>(srcStart);
|
|
617
|
+
if (c == COMMA || c == BRACKET_RIGHT || isSpace(c)) {
|
|
618
|
+
let value: u64 = 0;
|
|
619
|
+
let p = lastIndex;
|
|
620
|
+
if (isSigned<valueof<T>>() && load<u16>(p) == 45) {
|
|
621
|
+
p += 2;
|
|
622
|
+
while (p < srcStart) {
|
|
623
|
+
value = value * 10 + (<u32>load<u16>(p) - 48);
|
|
624
|
+
p += 2;
|
|
625
|
+
}
|
|
626
|
+
store<valueof<T>>(writePtr, <valueof<T>>-(<i64>value));
|
|
627
|
+
} else {
|
|
628
|
+
while (p < srcStart) {
|
|
629
|
+
value = value * 10 + (<u32>load<u16>(p) - 48);
|
|
630
|
+
p += 2;
|
|
631
|
+
}
|
|
632
|
+
store<valueof<T>>(writePtr, <valueof<T>>value);
|
|
633
|
+
}
|
|
634
|
+
writePtr += elementSize;
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
srcStart += 2;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
srcStart += 2;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
out.length = i32(<usize>(writePtr - dataStart) / elementSize);
|
|
644
|
+
return out;
|
|
425
645
|
}
|
|
426
646
|
|
|
427
647
|
|
|
428
|
-
@inline
|
|
648
|
+
@inline function deserializeIntegerArrayBody<T extends number[]>(
|
|
649
|
+
srcStart: usize,
|
|
650
|
+
srcEnd: usize,
|
|
651
|
+
out: T,
|
|
652
|
+
): usize {
|
|
429
653
|
let index = 0;
|
|
430
654
|
|
|
431
655
|
do {
|
|
432
656
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
433
657
|
srcStart += 2;
|
|
658
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
434
659
|
if (srcStart >= srcEnd) break;
|
|
435
660
|
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
436
661
|
out.length = 0;
|
|
@@ -439,17 +664,35 @@ export function deserializeIntegerArray_SWAR<T extends number[]>(srcStart: usize
|
|
|
439
664
|
|
|
440
665
|
while (srcStart < srcEnd) {
|
|
441
666
|
const slot = ensureArrayElementSlot<T>(out, index);
|
|
442
|
-
|
|
443
|
-
|
|
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.
|
|
679
|
+
srcStart = isSigned<valueof<T>>()
|
|
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;
|
|
444
685
|
|
|
445
686
|
const code = load<u16>(srcStart);
|
|
446
687
|
if (code == COMMA) {
|
|
447
688
|
srcStart += 2;
|
|
689
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
448
690
|
index++;
|
|
449
691
|
continue;
|
|
450
692
|
}
|
|
451
693
|
if (code == BRACKET_RIGHT) {
|
|
452
|
-
|
|
694
|
+
const nextLen = index + 1;
|
|
695
|
+
if (out.length != nextLen) out.length = nextLen;
|
|
453
696
|
return srcStart + 2;
|
|
454
697
|
}
|
|
455
698
|
break;
|
|
@@ -460,6 +703,14 @@ export function deserializeIntegerArray_SWAR<T extends number[]>(srcStart: usize
|
|
|
460
703
|
}
|
|
461
704
|
|
|
462
705
|
|
|
463
|
-
@inline export function deserializeIntegerArrayField<T extends number[]>(
|
|
464
|
-
|
|
706
|
+
@inline export function deserializeIntegerArrayField<T extends number[]>(
|
|
707
|
+
srcStart: usize,
|
|
708
|
+
srcEnd: usize,
|
|
709
|
+
fieldPtr: usize,
|
|
710
|
+
): usize {
|
|
711
|
+
return deserializeIntegerArrayBody<T>(
|
|
712
|
+
srcStart,
|
|
713
|
+
srcEnd,
|
|
714
|
+
ensureArrayField<T>(fieldPtr),
|
|
715
|
+
);
|
|
465
716
|
}
|