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,14 +1,281 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ptrToStr } from "../../../util/ptrToStr";
|
|
2
|
+
import { scientific } from "../../../util/scientific";
|
|
3
|
+
import { deserializeFloatField_NAIVE } from "../../naive/float";
|
|
4
|
+
import { deserializeFloatArray_NAIVE } from "../../naive/array/float";
|
|
2
5
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
3
6
|
import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
7
|
+
import { parse4Digits_PairMul } from "../../../util/swar-int";
|
|
8
|
+
import { loadPow10, MAX_EXACT_MANTISSA, MAX_EXACT_POW10 } from "../float";
|
|
9
|
+
import { isSpace } from "../../../util";
|
|
4
10
|
|
|
5
11
|
|
|
6
|
-
@inline
|
|
12
|
+
@inline function skipFloatArrayWhitespace(
|
|
13
|
+
srcStart: usize,
|
|
14
|
+
srcEnd: usize,
|
|
15
|
+
): usize {
|
|
16
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
17
|
+
return srcStart;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// @ts-ignore: inline
|
|
21
|
+
@inline function fallbackStore<E>(
|
|
22
|
+
origStart: usize,
|
|
23
|
+
end: usize,
|
|
24
|
+
slot: usize,
|
|
25
|
+
): void {
|
|
26
|
+
const s = ptrToStr(origStart, end);
|
|
27
|
+
if (sizeof<E>() == sizeof<f32>()) {
|
|
28
|
+
store<f32>(slot, f32.parse(s));
|
|
29
|
+
} else {
|
|
30
|
+
store<f64>(slot, f64.parse(s));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Inline single-pass Lemire-style float element parser for arrays.
|
|
36
|
+
*
|
|
37
|
+
* Bit-identical output to `f64.parse` / `f32.parse`: u64 mantissa
|
|
38
|
+
* accumulation is exact, and `<f64>mantissa * pow10[exp]` is correctly
|
|
39
|
+
* rounded for the fast-path range (mantissa <= 2^53, |exp| <= 22).
|
|
40
|
+
* Pathological inputs (oversized mantissa or exponent) fall back to
|
|
41
|
+
* `f*.parse` over the float's own substring, again matching the NAIVE
|
|
42
|
+
* baseline.
|
|
43
|
+
*
|
|
44
|
+
* Returns the advanced source position on success, or `0` to signal "bail
|
|
45
|
+
* to the per-element NAIVE path" only for truly malformed input (no leading
|
|
46
|
+
* digit, lone minus, malformed exponent suffix). Valid-but-out-of-range
|
|
47
|
+
* numbers are handled inline.
|
|
48
|
+
*/
|
|
49
|
+
// @ts-expect-error: decorators valid here
|
|
50
|
+
@inline export function parseFloatElementSWAR<E>(
|
|
51
|
+
srcStart: usize,
|
|
52
|
+
srcEnd: usize,
|
|
53
|
+
slot: usize,
|
|
54
|
+
): usize {
|
|
55
|
+
const origStart = srcStart;
|
|
56
|
+
let p = srcStart;
|
|
57
|
+
let negative = false;
|
|
58
|
+
let code = load<u16>(p);
|
|
59
|
+
if (code == 45) {
|
|
60
|
+
negative = true;
|
|
61
|
+
p += 2;
|
|
62
|
+
if (p >= srcEnd) return 0;
|
|
63
|
+
code = load<u16>(p);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let firstDigit = <u32>code - 48;
|
|
67
|
+
if (firstDigit > 9) return 0;
|
|
68
|
+
|
|
69
|
+
// Integer mantissa: scalar (most JSON integers are 1-3 digits).
|
|
70
|
+
let mantissa: u64 = 0;
|
|
71
|
+
let intDigits: i32 = 0;
|
|
72
|
+
while (p < srcEnd) {
|
|
73
|
+
const d = <u32>load<u16>(p) - 48;
|
|
74
|
+
if (d > 9) break;
|
|
75
|
+
mantissa = mantissa * 10 + <u64>d;
|
|
76
|
+
intDigits++;
|
|
77
|
+
p += 2;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Fractional mantissa: parse4 SWAR stride + scalar tail. Same u64
|
|
81
|
+
// accumulator as the integer part — exponent compensates for fracDigits.
|
|
82
|
+
let fracDigits: i32 = 0;
|
|
83
|
+
if (p < srcEnd && load<u16>(p) == 46) {
|
|
84
|
+
p += 2;
|
|
85
|
+
while (p + 6 < srcEnd) {
|
|
86
|
+
const parsed = parse4Digits_PairMul(load<u64>(p));
|
|
87
|
+
if (parsed == U32.MAX_VALUE) break;
|
|
88
|
+
mantissa = mantissa * 10_000 + <u64>parsed;
|
|
89
|
+
fracDigits += 4;
|
|
90
|
+
p += 8;
|
|
91
|
+
}
|
|
92
|
+
while (p < srcEnd) {
|
|
93
|
+
const d = <u32>load<u16>(p) - 48;
|
|
94
|
+
if (d > 9) break;
|
|
95
|
+
mantissa = mantissa * 10 + <u64>d;
|
|
96
|
+
fracDigits++;
|
|
97
|
+
p += 2;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const mantDigits = intDigits + fracDigits;
|
|
102
|
+
let exponent: i32 = -fracDigits;
|
|
103
|
+
|
|
104
|
+
// Optional `e[+-]NNN` suffix.
|
|
105
|
+
if (p < srcEnd) {
|
|
106
|
+
code = load<u16>(p);
|
|
107
|
+
if (code == 101 || code == 69) {
|
|
108
|
+
const expStart = p;
|
|
109
|
+
p += 2;
|
|
110
|
+
if (p >= srcEnd) {
|
|
111
|
+
fallbackStore<E>(origStart, expStart, slot);
|
|
112
|
+
return expStart;
|
|
113
|
+
}
|
|
114
|
+
let expNeg = false;
|
|
115
|
+
const sc = load<u16>(p);
|
|
116
|
+
if (sc == 45) {
|
|
117
|
+
expNeg = true;
|
|
118
|
+
p += 2;
|
|
119
|
+
} else if (sc == 43) {
|
|
120
|
+
p += 2;
|
|
121
|
+
}
|
|
122
|
+
if (p >= srcEnd) {
|
|
123
|
+
fallbackStore<E>(origStart, expStart, slot);
|
|
124
|
+
return expStart;
|
|
125
|
+
}
|
|
126
|
+
let exp: i32 = 0;
|
|
127
|
+
let expDigits: i32 = 0;
|
|
128
|
+
while (p < srcEnd) {
|
|
129
|
+
const d = <u32>load<u16>(p) - 48;
|
|
130
|
+
if (d > 9) break;
|
|
131
|
+
exp = exp * 10 + <i32>d;
|
|
132
|
+
expDigits++;
|
|
133
|
+
if (expDigits > 4) {
|
|
134
|
+
fallbackStore<E>(origStart, p, slot);
|
|
135
|
+
return p;
|
|
136
|
+
}
|
|
137
|
+
p += 2;
|
|
138
|
+
}
|
|
139
|
+
if (expDigits == 0) {
|
|
140
|
+
fallbackStore<E>(origStart, expStart, slot);
|
|
141
|
+
return expStart;
|
|
142
|
+
}
|
|
143
|
+
exponent += expNeg ? -exp : exp;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Lemire fast path: mantissa <= 2^53 and |exp| <= 22 means a single fmul
|
|
148
|
+
// on two exactly-representable operands, correctly rounded.
|
|
149
|
+
let result: f64;
|
|
150
|
+
if (
|
|
151
|
+
mantDigits <= 19 &&
|
|
152
|
+
mantissa <= MAX_EXACT_MANTISSA &&
|
|
153
|
+
exponent <= MAX_EXACT_POW10 &&
|
|
154
|
+
exponent >= -MAX_EXACT_POW10
|
|
155
|
+
) {
|
|
156
|
+
result = <f64>mantissa;
|
|
157
|
+
if (exponent > 0) {
|
|
158
|
+
result *= loadPow10(<u32>exponent);
|
|
159
|
+
} else if (exponent < 0) {
|
|
160
|
+
result /= loadPow10(<u32>-exponent);
|
|
161
|
+
}
|
|
162
|
+
} else if (mantDigits <= 19) {
|
|
163
|
+
// Mantissa fits in u64 but the fast-path constraints don't hold. Call
|
|
164
|
+
// `scientific` directly with our already-parsed mantissa+exp, skipping
|
|
165
|
+
// the `ptrToStr` allocation + strtod re-parse.
|
|
166
|
+
result = scientific(mantissa, exponent);
|
|
167
|
+
} else {
|
|
168
|
+
// >19 mantissa digits — beyond u64 capacity, may need strtod's sticky-bit
|
|
169
|
+
// pattern. Hand off to f*.parse on the float's substring.
|
|
170
|
+
fallbackStore<E>(origStart, p, slot);
|
|
171
|
+
return p;
|
|
172
|
+
}
|
|
173
|
+
if (negative) result = -result;
|
|
174
|
+
|
|
175
|
+
if (sizeof<E>() == sizeof<f32>()) {
|
|
176
|
+
store<f32>(slot, <f32>result);
|
|
177
|
+
} else {
|
|
178
|
+
store<f64>(slot, result);
|
|
179
|
+
}
|
|
180
|
+
return p;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Top-level SWAR float-array deserializer (`f64[]` / `f32[]`).
|
|
185
|
+
*
|
|
186
|
+
* Worst-case sizing matches the NAIVE variant: each element occupies >=
|
|
187
|
+
* 2 UTF-16 chars (`D,`), so `(srcEnd - srcStart) >> 2` upper-bounds the
|
|
188
|
+
* element count. `f64`/`f32` are unmanaged so AS skips zero-fill on
|
|
189
|
+
* `length=`, making the over-allocation effectively free; the trailing
|
|
190
|
+
* `out.length` trim recovers the true count.
|
|
191
|
+
*
|
|
192
|
+
* The fast loop writes directly through `writePtr` (eliminating the
|
|
193
|
+
* per-element `Array.push` capacity check + length write) and inlines
|
|
194
|
+
* `parseFloatElementSWAR` (eliminating the double-scan that
|
|
195
|
+
* `deserializeFloatArray_NAIVE` performs: scan-to-terminator +
|
|
196
|
+
* `JSON.__deserialize` re-parse). If the inline parser bails (truly
|
|
197
|
+
* malformed input), we hand off to the NAIVE path with the pre-allocated
|
|
198
|
+
* buffer retained so capacity is reused.
|
|
199
|
+
*/
|
|
200
|
+
export function deserializeFloatArray_SWAR<T extends number[]>(
|
|
201
|
+
srcStart: usize,
|
|
202
|
+
srcEnd: usize,
|
|
203
|
+
dst: usize,
|
|
204
|
+
): T {
|
|
205
|
+
const out = changetype<nonnull<T>>(
|
|
206
|
+
dst || changetype<usize>(instantiate<T>()),
|
|
207
|
+
);
|
|
208
|
+
const originalSrcStart = srcStart;
|
|
209
|
+
|
|
210
|
+
const elementSize = sizeof<valueof<T>>();
|
|
211
|
+
const maxElements = i32((<usize>(srcEnd - srcStart)) >> 2);
|
|
212
|
+
if (maxElements > 0) out.length = maxElements;
|
|
213
|
+
const dataStart = out.dataStart;
|
|
214
|
+
let writePtr = dataStart;
|
|
215
|
+
|
|
216
|
+
do {
|
|
217
|
+
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
218
|
+
srcStart += 2;
|
|
219
|
+
srcStart = skipFloatArrayWhitespace(srcStart, srcEnd);
|
|
220
|
+
if (srcStart >= srcEnd) break;
|
|
221
|
+
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
222
|
+
out.length = 0;
|
|
223
|
+
return out;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
while (srcStart < srcEnd) {
|
|
227
|
+
const next = parseFloatElementSWAR<valueof<T>>(
|
|
228
|
+
srcStart,
|
|
229
|
+
srcEnd,
|
|
230
|
+
writePtr,
|
|
231
|
+
);
|
|
232
|
+
if (!next) break;
|
|
233
|
+
writePtr += elementSize;
|
|
234
|
+
srcStart = skipFloatArrayWhitespace(next, srcEnd);
|
|
235
|
+
if (srcStart >= srcEnd) break;
|
|
236
|
+
|
|
237
|
+
const code = load<u16>(srcStart);
|
|
238
|
+
if (code == COMMA) {
|
|
239
|
+
srcStart += 2;
|
|
240
|
+
srcStart = skipFloatArrayWhitespace(srcStart, srcEnd);
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (code == BRACKET_RIGHT) {
|
|
244
|
+
out.length = i32(<usize>(writePtr - dataStart) / elementSize);
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
} while (false);
|
|
250
|
+
|
|
251
|
+
return deserializeFloatArray_NAIVE<T>(
|
|
252
|
+
originalSrcStart,
|
|
253
|
+
srcEnd,
|
|
254
|
+
changetype<usize>(out),
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Field/into variant — parses `[..]` into the existing `out` array and
|
|
260
|
+
* returns the cursor past the closing `]`.
|
|
261
|
+
*
|
|
262
|
+
* Worst-case pre-sizing (`(srcEnd - srcStart) >> 2`) used by the top-level
|
|
263
|
+
* SWAR entry is unsafe here: nested callers pass the *outer* container's
|
|
264
|
+
* `srcEnd`, so on `f64[][][]` payloads like canada.json each tiny inner
|
|
265
|
+
* `[lon,lat]` would over-allocate megabytes of f64 capacity. Instead we
|
|
266
|
+
* use `ensureArrayElementSlot`'s grow-or-reuse strategy.
|
|
267
|
+
*/
|
|
268
|
+
@inline export function deserializeFloatArrayBody<T extends number[]>(
|
|
269
|
+
srcStart: usize,
|
|
270
|
+
srcEnd: usize,
|
|
271
|
+
out: T,
|
|
272
|
+
): usize {
|
|
7
273
|
let index = 0;
|
|
8
274
|
|
|
9
275
|
do {
|
|
10
276
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
11
277
|
srcStart += 2;
|
|
278
|
+
srcStart = skipFloatArrayWhitespace(srcStart, srcEnd);
|
|
12
279
|
if (srcStart >= srcEnd) break;
|
|
13
280
|
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
14
281
|
out.length = 0;
|
|
@@ -17,17 +284,30 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
17
284
|
|
|
18
285
|
while (srcStart < srcEnd) {
|
|
19
286
|
const slot = ensureArrayElementSlot<T>(out, index);
|
|
20
|
-
|
|
21
|
-
if (!
|
|
287
|
+
let next = parseFloatElementSWAR<valueof<T>>(srcStart, srcEnd, slot);
|
|
288
|
+
if (!next) {
|
|
289
|
+
next = deserializeFloatField_NAIVE<valueof<T>>(srcStart, srcEnd, slot);
|
|
290
|
+
}
|
|
291
|
+
srcStart = next;
|
|
292
|
+
if (!srcStart) break;
|
|
293
|
+
srcStart = skipFloatArrayWhitespace(srcStart, srcEnd);
|
|
294
|
+
if (srcStart >= srcEnd) break;
|
|
22
295
|
|
|
23
296
|
const code = load<u16>(srcStart);
|
|
24
297
|
if (code == COMMA) {
|
|
25
298
|
srcStart += 2;
|
|
299
|
+
srcStart = skipFloatArrayWhitespace(srcStart, srcEnd);
|
|
26
300
|
index++;
|
|
27
301
|
continue;
|
|
28
302
|
}
|
|
29
303
|
if (code == BRACKET_RIGHT) {
|
|
30
|
-
out.length
|
|
304
|
+
// Skip the `out.length =` call when the length is already correct.
|
|
305
|
+
// `ensureArrayElementSlot` only grows (never shrinks), so when this
|
|
306
|
+
// array is being reused with the same shape (canada's `[lon,lat]`
|
|
307
|
+
// pairs across thousands of geometries) the length is unchanged
|
|
308
|
+
// and the AS runtime's `ensureCapacity` call is pure overhead.
|
|
309
|
+
const nextLen = index + 1;
|
|
310
|
+
if (out.length != nextLen) out.length = nextLen;
|
|
31
311
|
return srcStart + 2;
|
|
32
312
|
}
|
|
33
313
|
break;
|
|
@@ -38,6 +318,14 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
38
318
|
}
|
|
39
319
|
|
|
40
320
|
|
|
41
|
-
@inline export function deserializeFloatArrayField<T extends number[]>(
|
|
42
|
-
|
|
321
|
+
@inline export function deserializeFloatArrayField<T extends number[]>(
|
|
322
|
+
srcStart: usize,
|
|
323
|
+
srcEnd: usize,
|
|
324
|
+
fieldPtr: usize,
|
|
325
|
+
): usize {
|
|
326
|
+
return deserializeFloatArrayBody<T>(
|
|
327
|
+
srcStart,
|
|
328
|
+
srcEnd,
|
|
329
|
+
ensureArrayField<T>(fieldPtr),
|
|
330
|
+
);
|
|
43
331
|
}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { JSON } from "../../..";
|
|
2
2
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import {
|
|
4
|
+
ensureArrayElementSlot,
|
|
5
|
+
ensureArrayField,
|
|
6
|
+
scanValueEnd,
|
|
7
|
+
skipWhitespace,
|
|
8
|
+
} from "./shared";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@inline export function deserializeGenericArrayBody<T extends unknown[]>(
|
|
12
|
+
srcStart: usize,
|
|
13
|
+
srcEnd: usize,
|
|
14
|
+
out: T,
|
|
15
|
+
): usize {
|
|
16
|
+
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT)
|
|
17
|
+
throw new Error("Failed to parse JSON!");
|
|
8
18
|
srcStart += 2;
|
|
19
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
9
20
|
if (srcStart >= srcEnd) throw new Error("Failed to parse JSON!");
|
|
10
21
|
if (load<u16>(srcStart) == BRACKET_RIGHT) return srcStart + 2;
|
|
11
22
|
|
|
@@ -19,10 +30,12 @@ import { ensureArrayElementSlot, ensureArrayField, scanValueEnd } from "./shared
|
|
|
19
30
|
store<valueof<T>>(slot, JSON.__deserialize<valueof<T>>(srcStart, valueEnd));
|
|
20
31
|
srcStart = valueEnd;
|
|
21
32
|
|
|
33
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
22
34
|
if (srcStart >= srcEnd) break;
|
|
23
35
|
const code = load<u16>(srcStart);
|
|
24
36
|
if (code == COMMA) {
|
|
25
37
|
srcStart += 2;
|
|
38
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
26
39
|
continue;
|
|
27
40
|
}
|
|
28
41
|
if (code == BRACKET_RIGHT) {
|
|
@@ -36,6 +49,14 @@ import { ensureArrayElementSlot, ensureArrayField, scanValueEnd } from "./shared
|
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
|
|
39
|
-
@inline export function deserializeGenericArrayField<T extends unknown[]>(
|
|
40
|
-
|
|
52
|
+
@inline export function deserializeGenericArrayField<T extends unknown[]>(
|
|
53
|
+
srcStart: usize,
|
|
54
|
+
srcEnd: usize,
|
|
55
|
+
fieldPtr: usize,
|
|
56
|
+
): usize {
|
|
57
|
+
return deserializeGenericArrayBody<T>(
|
|
58
|
+
srcStart,
|
|
59
|
+
srcEnd,
|
|
60
|
+
ensureArrayField<T>(fieldPtr),
|
|
61
|
+
);
|
|
41
62
|
}
|