json-as 1.4.0 → 1.6.0
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 +54 -29
- package/README.md +126 -33
- package/assembly/custom/chars.ts +39 -78
- package/assembly/deserialize/error.ts +21 -0
- package/assembly/deserialize/index/arbitrary.ts +50 -11
- package/assembly/deserialize/index/array.ts +2 -1
- package/assembly/deserialize/index/bool.ts +1 -1
- package/assembly/deserialize/index/float.ts +2 -4
- package/assembly/deserialize/index/integer.ts +2 -4
- package/assembly/deserialize/index/object.ts +9 -1
- package/assembly/deserialize/index/string.ts +39 -7
- package/assembly/deserialize/index/unsigned.ts +2 -4
- package/assembly/deserialize/index.ts +0 -1
- package/assembly/deserialize/naive/array/arbitrary.ts +3 -2
- package/assembly/deserialize/naive/array/array.ts +1 -0
- package/assembly/deserialize/naive/array/bool.ts +21 -11
- package/assembly/deserialize/naive/array/box.ts +13 -33
- package/assembly/deserialize/naive/array/float.ts +23 -13
- package/assembly/deserialize/naive/array/integer.ts +34 -22
- package/assembly/deserialize/naive/array/map.ts +1 -1
- package/assembly/deserialize/naive/array/object.ts +2 -1
- package/assembly/deserialize/naive/array/string.ts +29 -16
- package/assembly/deserialize/naive/array/struct.ts +19 -1
- package/assembly/deserialize/naive/bool.ts +18 -10
- package/assembly/deserialize/naive/date.ts +1 -2
- package/assembly/deserialize/naive/float.ts +3 -9
- package/assembly/deserialize/naive/integer.ts +1 -2
- package/assembly/deserialize/naive/map.ts +342 -43
- package/assembly/deserialize/naive/object.ts +250 -55
- package/assembly/deserialize/naive/raw.ts +10 -2
- package/assembly/deserialize/naive/set.ts +2 -5
- package/assembly/deserialize/naive/staticarray.ts +4 -4
- package/assembly/deserialize/naive/string.ts +46 -60
- package/assembly/deserialize/naive/unsigned.ts +1 -2
- package/assembly/deserialize/parseMode.ts +216 -0
- package/assembly/deserialize/simd/array/integer.ts +8 -10
- package/assembly/deserialize/simd/float.ts +38 -34
- package/assembly/deserialize/simd/integer.ts +2 -7
- package/assembly/deserialize/simd/string.ts +84 -39
- package/assembly/deserialize/string-validation.ts +34 -0
- package/assembly/deserialize/swar/array/arbitrary.ts +1 -2
- package/assembly/deserialize/swar/array/array.ts +64 -15
- package/assembly/deserialize/swar/array/bool.ts +15 -5
- package/assembly/deserialize/swar/array/box.ts +1 -2
- package/assembly/deserialize/swar/array/float.ts +399 -30
- package/assembly/deserialize/swar/array/generic.ts +13 -4
- package/assembly/deserialize/swar/array/integer.ts +29 -78
- package/assembly/deserialize/swar/array/map.ts +1 -2
- package/assembly/deserialize/swar/array/object.ts +12 -4
- package/assembly/deserialize/swar/array/raw.ts +1 -2
- package/assembly/deserialize/swar/array/shared.ts +7 -14
- package/assembly/deserialize/swar/array/string.ts +37 -13
- package/assembly/deserialize/swar/array/struct.ts +109 -21
- package/assembly/deserialize/swar/array.ts +1 -3
- package/assembly/deserialize/swar/float.ts +23 -21
- package/assembly/deserialize/swar/integer.ts +2 -7
- package/assembly/deserialize/swar/string.ts +81 -124
- package/assembly/deserialize/swar/typedarray.ts +4 -4
- package/assembly/index.d.ts +35 -24
- package/assembly/index.ts +1775 -281
- package/assembly/serialize/index/arbitrary.ts +70 -4
- package/assembly/serialize/index/bool.ts +1 -1
- package/assembly/serialize/index/float.ts +1 -5
- package/assembly/serialize/index/integer.ts +1 -1
- package/assembly/serialize/index/jsonarray.ts +51 -0
- package/assembly/serialize/index/object.ts +42 -3
- package/assembly/serialize/index/string.ts +1 -2
- package/assembly/serialize/index/typedarray.ts +1 -2
- package/assembly/serialize/index.ts +1 -0
- package/assembly/serialize/naive/array.ts +87 -34
- package/assembly/serialize/naive/bool.ts +0 -1
- package/assembly/serialize/naive/float.ts +15 -29
- package/assembly/serialize/naive/integer.ts +1 -5
- package/assembly/serialize/naive/map.ts +37 -0
- package/assembly/serialize/naive/raw.ts +1 -2
- package/assembly/serialize/naive/set.ts +0 -5
- package/assembly/serialize/naive/staticarray.ts +0 -6
- package/assembly/serialize/naive/string.ts +1 -10
- package/assembly/serialize/naive/typedarray.ts +0 -7
- package/assembly/serialize/simd/string.ts +1 -3
- package/assembly/serialize/swar/string.ts +1 -2
- package/assembly/util/atoi-fast.ts +4 -14
- package/assembly/util/bytes.ts +1 -2
- package/assembly/util/eisel-lemire.ts +179 -0
- package/assembly/util/idofd.ts +1 -2
- package/assembly/util/isSpace.ts +1 -2
- package/assembly/util/itoa-fast.ts +6 -9
- package/assembly/util/nextPowerOf2.ts +1 -2
- package/assembly/util/parsefloat-fast.ts +3 -5
- package/assembly/util/prettyWhitespaceSimd.ts +69 -0
- package/assembly/util/ptrToStr.ts +1 -2
- package/assembly/util/scanValueEndSimd.ts +83 -22
- package/assembly/util/scanValueEndSwar.ts +67 -25
- package/assembly/util/scientific.ts +5 -8
- package/assembly/util/snp.ts +1 -2
- package/assembly/util/swar-int.ts +5 -10
- package/assembly/util/swar.ts +2 -4
- package/assembly/util/validateJson.ts +338 -0
- package/lib/as-bs.ts +51 -51
- package/package.json +25 -8
- package/transform/lib/index.d.ts +6 -0
- package/transform/lib/index.js +874 -171
- package/transform/lib/types.d.ts +3 -1
- package/transform/lib/types.js +6 -0
- package/assembly/deserialize/index/struct.ts +0 -1
- package/assembly/deserialize/naive/struct.ts +0 -21
- package/assembly/util/dragonbox-cache.ts +0 -445
- package/assembly/util/dragonbox.ts +0 -652
|
@@ -4,25 +4,25 @@ import { deserializeFloatField_NAIVE } from "../../naive/float";
|
|
|
4
4
|
import { deserializeFloatArray_NAIVE } from "../../naive/array/float";
|
|
5
5
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
6
6
|
import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
parse4Digits_PairMul,
|
|
9
|
+
parse8Digits_PairMul,
|
|
10
|
+
} from "../../../util/swar-int";
|
|
8
11
|
import { loadPow10, MAX_EXACT_MANTISSA, MAX_EXACT_POW10 } from "../float";
|
|
9
12
|
import { isSpace } from "../../../util";
|
|
13
|
+
import {
|
|
14
|
+
eiselLemire22,
|
|
15
|
+
eiselLemireMinus14,
|
|
16
|
+
eiselLemireMinus14_54Bit,
|
|
17
|
+
} from "../../../util/eisel-lemire";
|
|
18
|
+
import { markProductionParseError } from "../../error";
|
|
10
19
|
|
|
11
|
-
|
|
12
|
-
@inline function skipFloatArrayWhitespace(
|
|
13
|
-
srcStart: usize,
|
|
14
|
-
srcEnd: usize,
|
|
15
|
-
): usize {
|
|
20
|
+
function skipFloatArrayWhitespace(srcStart: usize, srcEnd: usize): usize {
|
|
16
21
|
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
17
22
|
return srcStart;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
@inline function fallbackStore<E>(
|
|
22
|
-
origStart: usize,
|
|
23
|
-
end: usize,
|
|
24
|
-
slot: usize,
|
|
25
|
-
): void {
|
|
25
|
+
function fallbackStore<E>(origStart: usize, end: usize, slot: usize): void {
|
|
26
26
|
const s = ptrToStr(origStart, end);
|
|
27
27
|
if (sizeof<E>() == sizeof<f32>()) {
|
|
28
28
|
store<f32>(slot, f32.parse(s));
|
|
@@ -31,6 +31,228 @@ import { isSpace } from "../../../util";
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Cold companion to the 14-digit GeoJSON hot path. Keeping the less common
|
|
35
|
+
// fixed widths out of `parseFloatElementSWAR` preserves its compact branch
|
|
36
|
+
// layout while avoiding the generic digit loops for the remaining coordinate
|
|
37
|
+
// shapes seen in real GeoJSON payloads.
|
|
38
|
+
function parseGeoAlternateFixed<E>(
|
|
39
|
+
p: usize,
|
|
40
|
+
srcEnd: usize,
|
|
41
|
+
slot: usize,
|
|
42
|
+
negative: bool,
|
|
43
|
+
firstDigit: u32,
|
|
44
|
+
): usize {
|
|
45
|
+
if (p + 20 >= srcEnd) return 0;
|
|
46
|
+
let intDigits = 0;
|
|
47
|
+
if (load<u16>(p, 4) == 46) {
|
|
48
|
+
intDigits = 2;
|
|
49
|
+
} else if (load<u16>(p, 6) == 46) {
|
|
50
|
+
intDigits = 3;
|
|
51
|
+
} else {
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const frac = p + <usize>((intDigits + 1) << 1);
|
|
56
|
+
let fracDigits = 0;
|
|
57
|
+
let term = frac + 12;
|
|
58
|
+
let termCode = load<u16>(term);
|
|
59
|
+
if (termCode == COMMA || termCode == BRACKET_RIGHT || isSpace(termCode)) {
|
|
60
|
+
fracDigits = 6;
|
|
61
|
+
} else {
|
|
62
|
+
term = frac + 30;
|
|
63
|
+
if (term >= srcEnd) return 0;
|
|
64
|
+
termCode = load<u16>(term);
|
|
65
|
+
if (termCode == COMMA || termCode == BRACKET_RIGHT || isSpace(termCode)) {
|
|
66
|
+
fracDigits = 15;
|
|
67
|
+
} else {
|
|
68
|
+
term = frac + 26;
|
|
69
|
+
termCode = load<u16>(term);
|
|
70
|
+
if (termCode == COMMA || termCode == BRACKET_RIGHT || isSpace(termCode)) {
|
|
71
|
+
fracDigits = 13;
|
|
72
|
+
} else {
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const d1 = <u32>load<u16>(p, 2) - 48;
|
|
79
|
+
const d2 = intDigits == 3 ? <u32>load<u16>(p, 4) - 48 : <u32>0;
|
|
80
|
+
if (d1 > 9 || d2 > 9) return 0;
|
|
81
|
+
const whole =
|
|
82
|
+
intDigits == 2
|
|
83
|
+
? <u64>(firstDigit * 10 + d1)
|
|
84
|
+
: <u64>(firstDigit * 100 + d1 * 10 + d2);
|
|
85
|
+
|
|
86
|
+
let mantissa: u64;
|
|
87
|
+
if (fracDigits == 6) {
|
|
88
|
+
const a = parse4Digits_PairMul(load<u64>(frac));
|
|
89
|
+
const d4 = <u32>load<u16>(frac, 8) - 48;
|
|
90
|
+
const d5 = <u32>load<u16>(frac, 10) - 48;
|
|
91
|
+
if (a == U32.MAX_VALUE || d4 > 9 || d5 > 9) return 0;
|
|
92
|
+
mantissa = whole * 1_000_000 + <u64>a * 100 + <u64>(d4 * 10 + d5);
|
|
93
|
+
} else {
|
|
94
|
+
const a = parse8Digits_PairMul(load<u64>(frac), load<u64>(frac, 8));
|
|
95
|
+
const c = parse4Digits_PairMul(load<u64>(frac, 16));
|
|
96
|
+
const d12 = <u32>load<u16>(frac, 24) - 48;
|
|
97
|
+
if (a == U32.MAX_VALUE || c == U32.MAX_VALUE || d12 > 9) return 0;
|
|
98
|
+
if (fracDigits == 13) {
|
|
99
|
+
mantissa =
|
|
100
|
+
whole * 10_000_000_000_000 + <u64>a * 100_000 + <u64>c * 10 + <u64>d12;
|
|
101
|
+
} else {
|
|
102
|
+
const d13 = <u32>load<u16>(frac, 26) - 48;
|
|
103
|
+
const d14 = <u32>load<u16>(frac, 28) - 48;
|
|
104
|
+
if (d13 > 9 || d14 > 9) return 0;
|
|
105
|
+
mantissa =
|
|
106
|
+
whole * 1_000_000_000_000_000 +
|
|
107
|
+
<u64>a * 10_000_000 +
|
|
108
|
+
<u64>c * 1_000 +
|
|
109
|
+
<u64>(d12 * 100 + d13 * 10 + d14);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let result: f64;
|
|
114
|
+
if (fracDigits == 6) {
|
|
115
|
+
result = <f64>mantissa / loadPow10(6);
|
|
116
|
+
} else if (fracDigits == 15) {
|
|
117
|
+
result = eiselLemire22(mantissa, -15);
|
|
118
|
+
} else {
|
|
119
|
+
result =
|
|
120
|
+
mantissa <= MAX_EXACT_MANTISSA
|
|
121
|
+
? <f64>mantissa / loadPow10(13)
|
|
122
|
+
: eiselLemire22(mantissa, -13);
|
|
123
|
+
}
|
|
124
|
+
if (negative) result = -result;
|
|
125
|
+
if (sizeof<E>() == sizeof<f32>()) {
|
|
126
|
+
store<f32>(slot, <f32>result);
|
|
127
|
+
} else {
|
|
128
|
+
store<f64>(slot, result);
|
|
129
|
+
}
|
|
130
|
+
return term;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function parseFixed14Pair<E>(
|
|
134
|
+
srcStart: usize,
|
|
135
|
+
srcEnd: usize,
|
|
136
|
+
dataStart: usize,
|
|
137
|
+
): usize {
|
|
138
|
+
let p0 = srcStart;
|
|
139
|
+
let negative0 = false;
|
|
140
|
+
if (load<u16>(p0) == 45) {
|
|
141
|
+
negative0 = true;
|
|
142
|
+
p0 += 2;
|
|
143
|
+
}
|
|
144
|
+
if (p0 + 36 >= srcEnd) return 0;
|
|
145
|
+
const first0 = <u32>load<u16>(p0) - 48;
|
|
146
|
+
if (first0 > 9) return 0;
|
|
147
|
+
let intDigits0 = 0;
|
|
148
|
+
if (load<u16>(p0, 4) == 46) {
|
|
149
|
+
intDigits0 = 2;
|
|
150
|
+
} else if (load<u16>(p0, 6) == 46) {
|
|
151
|
+
intDigits0 = 3;
|
|
152
|
+
} else {
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
const frac0 = p0 + <usize>((intDigits0 + 1) << 1);
|
|
156
|
+
const term0 = frac0 + 28;
|
|
157
|
+
if (load<u16>(term0) != COMMA) return 0;
|
|
158
|
+
|
|
159
|
+
let p1 = term0 + 2;
|
|
160
|
+
if (load<u16>(p1) == 32) p1 += 2;
|
|
161
|
+
let negative1 = false;
|
|
162
|
+
if (load<u16>(p1) == 45) {
|
|
163
|
+
negative1 = true;
|
|
164
|
+
p1 += 2;
|
|
165
|
+
}
|
|
166
|
+
if (p1 + 36 >= srcEnd) return 0;
|
|
167
|
+
const first1 = <u32>load<u16>(p1) - 48;
|
|
168
|
+
if (first1 > 9) return 0;
|
|
169
|
+
let intDigits1 = 0;
|
|
170
|
+
if (load<u16>(p1, 4) == 46) {
|
|
171
|
+
intDigits1 = 2;
|
|
172
|
+
} else if (load<u16>(p1, 6) == 46) {
|
|
173
|
+
intDigits1 = 3;
|
|
174
|
+
} else {
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
const frac1 = p1 + <usize>((intDigits1 + 1) << 1);
|
|
178
|
+
const term1 = frac1 + 28;
|
|
179
|
+
if (load<u16>(term1) != BRACKET_RIGHT) return 0;
|
|
180
|
+
|
|
181
|
+
const a0 = parse8Digits_PairMul(load<u64>(frac0), load<u64>(frac0, 8));
|
|
182
|
+
const c0 = parse4Digits_PairMul(load<u64>(frac0, 16));
|
|
183
|
+
const d012 = <u32>load<u16>(frac0, 24) - 48;
|
|
184
|
+
const d013 = <u32>load<u16>(frac0, 26) - 48;
|
|
185
|
+
const d01 = <u32>load<u16>(p0, 2) - 48;
|
|
186
|
+
const d02 = intDigits0 == 3 ? <u32>load<u16>(p0, 4) - 48 : <u32>0;
|
|
187
|
+
if (
|
|
188
|
+
a0 == U32.MAX_VALUE ||
|
|
189
|
+
c0 == U32.MAX_VALUE ||
|
|
190
|
+
d012 > 9 ||
|
|
191
|
+
d013 > 9 ||
|
|
192
|
+
d01 > 9 ||
|
|
193
|
+
d02 > 9
|
|
194
|
+
)
|
|
195
|
+
return 0;
|
|
196
|
+
|
|
197
|
+
const a1 = parse8Digits_PairMul(load<u64>(frac1), load<u64>(frac1, 8));
|
|
198
|
+
const c1 = parse4Digits_PairMul(load<u64>(frac1, 16));
|
|
199
|
+
const d112 = <u32>load<u16>(frac1, 24) - 48;
|
|
200
|
+
const d113 = <u32>load<u16>(frac1, 26) - 48;
|
|
201
|
+
const d11 = <u32>load<u16>(p1, 2) - 48;
|
|
202
|
+
const d12 = intDigits1 == 3 ? <u32>load<u16>(p1, 4) - 48 : <u32>0;
|
|
203
|
+
if (
|
|
204
|
+
a1 == U32.MAX_VALUE ||
|
|
205
|
+
c1 == U32.MAX_VALUE ||
|
|
206
|
+
d112 > 9 ||
|
|
207
|
+
d113 > 9 ||
|
|
208
|
+
d11 > 9 ||
|
|
209
|
+
d12 > 9
|
|
210
|
+
)
|
|
211
|
+
return 0;
|
|
212
|
+
|
|
213
|
+
const whole0 =
|
|
214
|
+
intDigits0 == 2
|
|
215
|
+
? <u64>(first0 * 10 + d01)
|
|
216
|
+
: <u64>(first0 * 100 + d01 * 10 + d02);
|
|
217
|
+
const whole1 =
|
|
218
|
+
intDigits1 == 2
|
|
219
|
+
? <u64>(first1 * 10 + d11)
|
|
220
|
+
: <u64>(first1 * 100 + d11 * 10 + d12);
|
|
221
|
+
const mantissa0 =
|
|
222
|
+
whole0 * 100_000_000_000_000 +
|
|
223
|
+
<u64>a0 * 1_000_000 +
|
|
224
|
+
<u64>c0 * 100 +
|
|
225
|
+
<u64>(d012 * 10 + d013);
|
|
226
|
+
const mantissa1 =
|
|
227
|
+
whole1 * 100_000_000_000_000 +
|
|
228
|
+
<u64>a1 * 1_000_000 +
|
|
229
|
+
<u64>c1 * 100 +
|
|
230
|
+
<u64>(d112 * 10 + d113);
|
|
231
|
+
|
|
232
|
+
let value0 =
|
|
233
|
+
mantissa0 <= MAX_EXACT_MANTISSA
|
|
234
|
+
? <f64>mantissa0 / loadPow10(14)
|
|
235
|
+
: mantissa0 < (<u64>1) << 54
|
|
236
|
+
? eiselLemireMinus14_54Bit(mantissa0)
|
|
237
|
+
: eiselLemireMinus14(mantissa0);
|
|
238
|
+
let value1 =
|
|
239
|
+
mantissa1 <= MAX_EXACT_MANTISSA
|
|
240
|
+
? <f64>mantissa1 / loadPow10(14)
|
|
241
|
+
: mantissa1 < (<u64>1) << 54
|
|
242
|
+
? eiselLemireMinus14_54Bit(mantissa1)
|
|
243
|
+
: eiselLemireMinus14(mantissa1);
|
|
244
|
+
if (negative0) value0 = -value0;
|
|
245
|
+
if (negative1) value1 = -value1;
|
|
246
|
+
if (sizeof<E>() == sizeof<f32>()) {
|
|
247
|
+
store<f32>(dataStart, <f32>value0);
|
|
248
|
+
store<f32>(dataStart + sizeof<E>(), <f32>value1);
|
|
249
|
+
} else {
|
|
250
|
+
store<f64>(dataStart, value0);
|
|
251
|
+
store<f64>(dataStart + sizeof<E>(), value1);
|
|
252
|
+
}
|
|
253
|
+
return term1 + 2;
|
|
254
|
+
}
|
|
255
|
+
|
|
34
256
|
/**
|
|
35
257
|
* Inline single-pass Lemire-style float element parser for arrays.
|
|
36
258
|
*
|
|
@@ -65,37 +287,128 @@ export function parseFloatElementSWAR<E>(
|
|
|
65
287
|
let firstDigit = <u32>code - 48;
|
|
66
288
|
if (firstDigit > 9) return 0;
|
|
67
289
|
|
|
290
|
+
// GeoJSON coordinates overwhelmingly use one of these two fixed layouts:
|
|
291
|
+
// `DD.ffffffffffffff` or `DDD.ffffffffffffff`. Recognize them before the
|
|
292
|
+
// generic scan so the common case avoids four loop exits (including the
|
|
293
|
+
// guaranteed failing parse4 probe at the fraction terminator). Each parse4
|
|
294
|
+
// still validates its lanes; malformed or exponent-bearing values fall
|
|
295
|
+
// through unchanged to the fully general parser below.
|
|
296
|
+
if (ASC_FEATURE_SIMD && p + 36 < srcEnd) {
|
|
297
|
+
let intDigitsFast = 0;
|
|
298
|
+
if (load<u16>(p, 4) == 46) {
|
|
299
|
+
intDigitsFast = 2;
|
|
300
|
+
} else if (load<u16>(p, 6) == 46) {
|
|
301
|
+
intDigitsFast = 3;
|
|
302
|
+
}
|
|
303
|
+
if (intDigitsFast != 0) {
|
|
304
|
+
const frac = p + <usize>((intDigitsFast + 1) << 1);
|
|
305
|
+
const term = frac + 28;
|
|
306
|
+
const termCode = load<u16>(term);
|
|
307
|
+
if (termCode == COMMA || termCode == BRACKET_RIGHT || isSpace(termCode)) {
|
|
308
|
+
const a = parse8Digits_PairMul(load<u64>(frac), load<u64>(frac, 8));
|
|
309
|
+
const c = parse4Digits_PairMul(load<u64>(frac, 16));
|
|
310
|
+
const d12 = <u32>load<u16>(frac, 24) - 48;
|
|
311
|
+
const d13 = <u32>load<u16>(frac, 26) - 48;
|
|
312
|
+
const d1 = <u32>load<u16>(p, 2) - 48;
|
|
313
|
+
const d2 = intDigitsFast == 3 ? <u32>load<u16>(p, 4) - 48 : <u32>0;
|
|
314
|
+
if (
|
|
315
|
+
a != U32.MAX_VALUE &&
|
|
316
|
+
c != U32.MAX_VALUE &&
|
|
317
|
+
d1 <= 9 &&
|
|
318
|
+
d2 <= 9 &&
|
|
319
|
+
d12 <= 9 &&
|
|
320
|
+
d13 <= 9
|
|
321
|
+
) {
|
|
322
|
+
const whole =
|
|
323
|
+
intDigitsFast == 2
|
|
324
|
+
? <u64>(firstDigit * 10 + d1)
|
|
325
|
+
: <u64>(firstDigit * 100 + d1 * 10 + d2);
|
|
326
|
+
const mantissa =
|
|
327
|
+
whole * 100_000_000_000_000 +
|
|
328
|
+
<u64>a * 1_000_000 +
|
|
329
|
+
<u64>c * 100 +
|
|
330
|
+
<u64>(d12 * 10 + d13);
|
|
331
|
+
let result =
|
|
332
|
+
mantissa <= MAX_EXACT_MANTISSA
|
|
333
|
+
? <f64>mantissa / loadPow10(14)
|
|
334
|
+
: mantissa < (<u64>1) << 54
|
|
335
|
+
? eiselLemireMinus14_54Bit(mantissa)
|
|
336
|
+
: eiselLemireMinus14(mantissa);
|
|
337
|
+
if (negative) result = -result;
|
|
338
|
+
if (sizeof<E>() == sizeof<f32>()) {
|
|
339
|
+
store<f32>(slot, <f32>result);
|
|
340
|
+
} else {
|
|
341
|
+
store<f64>(slot, result);
|
|
342
|
+
}
|
|
343
|
+
return term;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (ASC_FEATURE_SIMD) {
|
|
350
|
+
const alternateEnd = parseGeoAlternateFixed<E>(
|
|
351
|
+
p,
|
|
352
|
+
srcEnd,
|
|
353
|
+
slot,
|
|
354
|
+
negative,
|
|
355
|
+
firstDigit,
|
|
356
|
+
);
|
|
357
|
+
if (alternateEnd) return alternateEnd;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return parseFloatElementGeneric<E>(origStart, srcEnd, slot);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function parseFloatElementGeneric<E>(
|
|
364
|
+
srcStart: usize,
|
|
365
|
+
srcEnd: usize,
|
|
366
|
+
slot: usize,
|
|
367
|
+
): usize {
|
|
368
|
+
const origStart = srcStart;
|
|
369
|
+
let p = srcStart;
|
|
370
|
+
let negative = false;
|
|
371
|
+
let code = load<u16>(p);
|
|
372
|
+
if (code == 45) {
|
|
373
|
+
negative = true;
|
|
374
|
+
p += 2;
|
|
375
|
+
if (p >= srcEnd) return 0;
|
|
376
|
+
code = load<u16>(p);
|
|
377
|
+
}
|
|
378
|
+
const firstDigit = <u32>code - 48;
|
|
379
|
+
if (firstDigit > 9) return 0;
|
|
380
|
+
|
|
68
381
|
// Integer mantissa: scalar (most JSON integers are 1-3 digits).
|
|
69
382
|
let mantissa: u64 = 0;
|
|
70
|
-
|
|
383
|
+
const intStart = p;
|
|
71
384
|
while (p < srcEnd) {
|
|
72
385
|
const d = <u32>load<u16>(p) - 48;
|
|
73
386
|
if (d > 9) break;
|
|
74
387
|
mantissa = mantissa * 10 + <u64>d;
|
|
75
|
-
intDigits++;
|
|
76
388
|
p += 2;
|
|
77
389
|
}
|
|
390
|
+
const intDigits = <i32>((p - intStart) >> 1);
|
|
78
391
|
|
|
79
392
|
// Fractional mantissa: parse4 SWAR stride + scalar tail. Same u64
|
|
80
|
-
// accumulator as the integer part
|
|
81
|
-
let
|
|
393
|
+
// accumulator as the integer part - exponent compensates for fracDigits.
|
|
394
|
+
let fracStart = p;
|
|
82
395
|
if (p < srcEnd && load<u16>(p) == 46) {
|
|
83
396
|
p += 2;
|
|
397
|
+
fracStart = p;
|
|
84
398
|
while (p + 6 < srcEnd) {
|
|
85
399
|
const parsed = parse4Digits_PairMul(load<u64>(p));
|
|
86
400
|
if (parsed == U32.MAX_VALUE) break;
|
|
87
401
|
mantissa = mantissa * 10_000 + <u64>parsed;
|
|
88
|
-
fracDigits += 4;
|
|
89
402
|
p += 8;
|
|
90
403
|
}
|
|
91
404
|
while (p < srcEnd) {
|
|
92
405
|
const d = <u32>load<u16>(p) - 48;
|
|
93
406
|
if (d > 9) break;
|
|
94
407
|
mantissa = mantissa * 10 + <u64>d;
|
|
95
|
-
fracDigits++;
|
|
96
408
|
p += 2;
|
|
97
409
|
}
|
|
98
410
|
}
|
|
411
|
+
const fracDigits = <i32>((p - fracStart) >> 1);
|
|
99
412
|
|
|
100
413
|
const mantDigits = intDigits + fracDigits;
|
|
101
414
|
let exponent: i32 = -fracDigits;
|
|
@@ -159,12 +472,14 @@ export function parseFloatElementSWAR<E>(
|
|
|
159
472
|
result /= loadPow10(<u32>-exponent);
|
|
160
473
|
}
|
|
161
474
|
} else if (mantDigits <= 19) {
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
475
|
+
// Eisel-Lemire handles the overwhelmingly common medium exponent range
|
|
476
|
+
// without the u64 division/modulo in `scientific`'s scaledown path.
|
|
477
|
+
result =
|
|
478
|
+
exponent >= -22 && exponent <= 22
|
|
479
|
+
? eiselLemire22(mantissa, exponent)
|
|
480
|
+
: scientific(mantissa, exponent);
|
|
166
481
|
} else {
|
|
167
|
-
// >19 mantissa digits
|
|
482
|
+
// >19 mantissa digits - beyond u64 capacity, may need strtod's sticky-bit
|
|
168
483
|
// pattern. Hand off to f*.parse on the float's substring.
|
|
169
484
|
fallbackStore<E>(origStart, p, slot);
|
|
170
485
|
return p;
|
|
@@ -255,7 +570,7 @@ export function deserializeFloatArray_SWAR<T extends number[]>(
|
|
|
255
570
|
}
|
|
256
571
|
|
|
257
572
|
/**
|
|
258
|
-
* Field/into variant
|
|
573
|
+
* Field/into variant - parses `[..]` into the existing `out` array and
|
|
259
574
|
* returns the cursor past the closing `]`.
|
|
260
575
|
*
|
|
261
576
|
* Worst-case pre-sizing (`(srcEnd - srcStart) >> 2`) used by the top-level
|
|
@@ -264,12 +579,19 @@ export function deserializeFloatArray_SWAR<T extends number[]>(
|
|
|
264
579
|
* `[lon,lat]` would over-allocate megabytes of f64 capacity. Instead we
|
|
265
580
|
* use `ensureArrayElementSlot`'s grow-or-reuse strategy.
|
|
266
581
|
*/
|
|
582
|
+
@inline
|
|
267
583
|
export function deserializeFloatArrayBody<T extends number[]>(
|
|
268
584
|
srcStart: usize,
|
|
269
585
|
srcEnd: usize,
|
|
270
586
|
out: T,
|
|
271
587
|
): usize {
|
|
272
588
|
let index = 0;
|
|
589
|
+
const reusableLength = load<i32>(
|
|
590
|
+
changetype<usize>(out),
|
|
591
|
+
offsetof<T>("length_"),
|
|
592
|
+
);
|
|
593
|
+
const reusableDataStart = out.dataStart;
|
|
594
|
+
const elementSize = sizeof<valueof<T>>();
|
|
273
595
|
|
|
274
596
|
do {
|
|
275
597
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
@@ -281,8 +603,56 @@ export function deserializeFloatArrayBody<T extends number[]>(
|
|
|
281
603
|
return srcStart + 2;
|
|
282
604
|
}
|
|
283
605
|
|
|
606
|
+
// GeoJSON's innermost coordinate arrays are overwhelmingly reused
|
|
607
|
+
// `[longitude,latitude]` pairs. Unroll that stable-shape case so neither
|
|
608
|
+
// element pays the generic index/capacity selection or loop backedge. A
|
|
609
|
+
// mismatch restores the first-value cursor and falls through unchanged.
|
|
610
|
+
if (ASC_FEATURE_SIMD && reusableLength == 2) {
|
|
611
|
+
const firstStart = srcStart;
|
|
612
|
+
const pairEnd = parseFixed14Pair<valueof<T>>(
|
|
613
|
+
srcStart,
|
|
614
|
+
srcEnd,
|
|
615
|
+
reusableDataStart,
|
|
616
|
+
);
|
|
617
|
+
if (pairEnd) return pairEnd;
|
|
618
|
+
let next = parseFloatElementSWAR<valueof<T>>(
|
|
619
|
+
srcStart,
|
|
620
|
+
srcEnd,
|
|
621
|
+
reusableDataStart,
|
|
622
|
+
);
|
|
623
|
+
if (next) {
|
|
624
|
+
srcStart = next;
|
|
625
|
+
if (srcStart < srcEnd && load<u16>(srcStart) != COMMA)
|
|
626
|
+
srcStart = skipFloatArrayWhitespace(srcStart, srcEnd);
|
|
627
|
+
if (srcStart < srcEnd && load<u16>(srcStart) == COMMA) {
|
|
628
|
+
srcStart += 2;
|
|
629
|
+
if (srcStart < srcEnd && load<u16>(srcStart) == 32) {
|
|
630
|
+
srcStart += 2;
|
|
631
|
+
} else {
|
|
632
|
+
srcStart = skipFloatArrayWhitespace(srcStart, srcEnd);
|
|
633
|
+
}
|
|
634
|
+
next = parseFloatElementSWAR<valueof<T>>(
|
|
635
|
+
srcStart,
|
|
636
|
+
srcEnd,
|
|
637
|
+
reusableDataStart + elementSize,
|
|
638
|
+
);
|
|
639
|
+
if (next) {
|
|
640
|
+
srcStart = next;
|
|
641
|
+
if (srcStart < srcEnd && load<u16>(srcStart) != BRACKET_RIGHT)
|
|
642
|
+
srcStart = skipFloatArrayWhitespace(srcStart, srcEnd);
|
|
643
|
+
if (srcStart < srcEnd && load<u16>(srcStart) == BRACKET_RIGHT)
|
|
644
|
+
return srcStart + 2;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
srcStart = firstStart;
|
|
649
|
+
}
|
|
650
|
+
|
|
284
651
|
while (srcStart < srcEnd) {
|
|
285
|
-
const slot =
|
|
652
|
+
const slot =
|
|
653
|
+
index < reusableLength
|
|
654
|
+
? reusableDataStart + <usize>index * elementSize
|
|
655
|
+
: ensureArrayElementSlot<T>(out, index);
|
|
286
656
|
let next = parseFloatElementSWAR<valueof<T>>(srcStart, srcEnd, slot);
|
|
287
657
|
if (!next) {
|
|
288
658
|
next = deserializeFloatField_NAIVE<valueof<T>>(srcStart, srcEnd, slot);
|
|
@@ -306,18 +676,17 @@ export function deserializeFloatArrayBody<T extends number[]>(
|
|
|
306
676
|
// pairs across thousands of geometries) the length is unchanged
|
|
307
677
|
// and the AS runtime's `ensureCapacity` call is pure overhead.
|
|
308
678
|
const nextLen = index + 1;
|
|
309
|
-
if (
|
|
679
|
+
if (reusableLength != nextLen) out.length = nextLen;
|
|
310
680
|
return srcStart + 2;
|
|
311
681
|
}
|
|
312
682
|
break;
|
|
313
683
|
}
|
|
314
684
|
} while (false);
|
|
315
685
|
|
|
316
|
-
|
|
686
|
+
markProductionParseError();
|
|
687
|
+
return 0;
|
|
317
688
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
@inline export function deserializeFloatArrayField<T extends number[]>(
|
|
689
|
+
export function deserializeFloatArrayField<T extends number[]>(
|
|
321
690
|
srcStart: usize,
|
|
322
691
|
srcEnd: usize,
|
|
323
692
|
fieldPtr: usize,
|
|
@@ -20,12 +20,22 @@ export function deserializeGenericArrayBody<T extends unknown[]>(
|
|
|
20
20
|
if (load<u16>(srcStart) == BRACKET_RIGHT) return srcStart + 2;
|
|
21
21
|
|
|
22
22
|
let index = 0;
|
|
23
|
+
const reusableLength = load<i32>(
|
|
24
|
+
changetype<usize>(out),
|
|
25
|
+
offsetof<T>("length_"),
|
|
26
|
+
);
|
|
27
|
+
const reusableDataStart = out.dataStart;
|
|
28
|
+
const elementSize = sizeof<valueof<T>>();
|
|
23
29
|
|
|
24
30
|
while (srcStart < srcEnd) {
|
|
25
31
|
const valueEnd = scanValueEnd(srcStart, srcEnd);
|
|
26
32
|
if (!valueEnd || valueEnd <= srcStart) break;
|
|
27
33
|
|
|
28
|
-
const slot =
|
|
34
|
+
const slot =
|
|
35
|
+
index < reusableLength
|
|
36
|
+
? reusableDataStart + <usize>index * elementSize
|
|
37
|
+
: ensureArrayElementSlot<T>(out, index);
|
|
38
|
+
index++;
|
|
29
39
|
store<valueof<T>>(slot, JSON.__deserialize<valueof<T>>(srcStart, valueEnd));
|
|
30
40
|
srcStart = valueEnd;
|
|
31
41
|
|
|
@@ -38,7 +48,7 @@ export function deserializeGenericArrayBody<T extends unknown[]>(
|
|
|
38
48
|
continue;
|
|
39
49
|
}
|
|
40
50
|
if (code == BRACKET_RIGHT) {
|
|
41
|
-
out.length = index;
|
|
51
|
+
if (reusableLength != index) out.length = index;
|
|
42
52
|
return srcStart + 2;
|
|
43
53
|
}
|
|
44
54
|
break;
|
|
@@ -47,8 +57,7 @@ export function deserializeGenericArrayBody<T extends unknown[]>(
|
|
|
47
57
|
throw new Error("Failed to parse JSON!");
|
|
48
58
|
}
|
|
49
59
|
|
|
50
|
-
|
|
51
|
-
@inline export function deserializeGenericArrayField<T extends unknown[]>(
|
|
60
|
+
export function deserializeGenericArrayField<T extends unknown[]>(
|
|
52
61
|
srcStart: usize,
|
|
53
62
|
srcEnd: usize,
|
|
54
63
|
fieldPtr: usize,
|