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
|
@@ -42,104 +42,113 @@ import { hex4_to_u16_swar } from "../../util/swar";
|
|
|
42
42
|
* @returns number of bytes written
|
|
43
43
|
*/
|
|
44
44
|
// @ts-expect-error: @inline is a valid decorator
|
|
45
|
-
@inline function copyStringFromSource(
|
|
45
|
+
@inline function copyStringFromSource(
|
|
46
|
+
srcStart: usize,
|
|
47
|
+
byteLength: usize,
|
|
48
|
+
): string {
|
|
46
49
|
if (byteLength == 0) return changetype<string>("");
|
|
47
50
|
const out = __new(byteLength, idof<string>());
|
|
48
51
|
memory.copy(out, srcStart, byteLength);
|
|
49
52
|
return changetype<string>(out);
|
|
50
53
|
}
|
|
51
54
|
|
|
55
|
+
// Standalone (whole-value) escaped scanner. Quotes are already stripped, so
|
|
56
|
+
// `srcEnd` is the payload end and only `\` escapes are handled. Same HYBRID
|
|
57
|
+
// strategy as the field scanner: escape blocks use a free optimistic u64 store
|
|
58
|
+
// for the plain prefix; clean runs stream the first block then bulk-memcpy the
|
|
59
|
+
// remainder. The `backslash_mask_unsafe` hits are confirmed scalarly.
|
|
60
|
+
//
|
|
61
|
+
// NOTE: vs the prior overflow scanner this is faster on dense and sparse
|
|
62
|
+
// escaping but ~20% slower on sustained moderate-density escaping (escape
|
|
63
|
+
// every ~20 chars), where multi-escape-per-block had an edge.
|
|
52
64
|
// @ts-expect-error: @inline is a valid decorator
|
|
53
|
-
@inline function deserializeEscapedString_SWAR(
|
|
54
|
-
|
|
65
|
+
@inline function deserializeEscapedString_SWAR(
|
|
66
|
+
payloadStart: usize,
|
|
67
|
+
escapeStart: usize,
|
|
68
|
+
srcEnd: usize,
|
|
69
|
+
): string {
|
|
55
70
|
const prefixLen = <u32>(escapeStart - payloadStart);
|
|
56
71
|
const outStart = bs.offset - bs.buffer;
|
|
57
|
-
bs.ensureSize(<u32>(srcEnd - payloadStart));
|
|
72
|
+
bs.ensureSize(<u32>(srcEnd - payloadStart) + 8); // +8 slack for u64 overcopy
|
|
58
73
|
if (prefixLen != 0) {
|
|
59
74
|
memory.copy(bs.offset, payloadStart, prefixLen);
|
|
60
75
|
bs.offset += prefixLen;
|
|
61
76
|
}
|
|
62
77
|
|
|
63
78
|
let srcStart = escapeStart;
|
|
79
|
+
const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
|
|
64
80
|
|
|
65
|
-
while (srcStart
|
|
81
|
+
while (srcStart <= srcEnd8) {
|
|
66
82
|
const block = load<u64>(srcStart);
|
|
67
|
-
store<u64>(bs.offset, block);
|
|
68
|
-
|
|
69
83
|
let mask = inline.always(backslash_mask_unsafe(block));
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (mask === 0) {
|
|
73
|
-
srcStart += 8;
|
|
84
|
+
if (mask == 0) {
|
|
85
|
+
store<u64>(bs.offset, block);
|
|
74
86
|
bs.offset += 8;
|
|
87
|
+
srcStart += 8;
|
|
88
|
+
if (
|
|
89
|
+
srcStart <= srcEnd8 &&
|
|
90
|
+
inline.always(backslash_mask_unsafe(load<u64>(srcStart))) == 0
|
|
91
|
+
) {
|
|
92
|
+
const runStart = srcStart;
|
|
93
|
+
srcStart += 8;
|
|
94
|
+
while (
|
|
95
|
+
srcStart <= srcEnd8 &&
|
|
96
|
+
inline.always(backslash_mask_unsafe(load<u64>(srcStart))) == 0
|
|
97
|
+
) {
|
|
98
|
+
srcStart += 8;
|
|
99
|
+
}
|
|
100
|
+
const runLen = <u32>(srcStart - runStart);
|
|
101
|
+
memory.copy(bs.offset, runStart, runLen);
|
|
102
|
+
bs.offset += runLen;
|
|
103
|
+
}
|
|
75
104
|
continue;
|
|
76
105
|
}
|
|
77
106
|
|
|
107
|
+
store<u64>(bs.offset, block);
|
|
108
|
+
let handled = false;
|
|
78
109
|
do {
|
|
79
|
-
const laneIdx = usize(ctz(mask) >> 3);
|
|
110
|
+
const laneIdx = usize(ctz(mask) >> 3);
|
|
80
111
|
mask &= mask - 1;
|
|
81
112
|
const srcIdx = srcStart + laneIdx;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const code = <u16>(
|
|
85
|
-
|
|
86
|
-
// Detect false positive (code unit where low byte is 0x5C)
|
|
87
|
-
if ((header & 0xffff) !== 0x5c) continue;
|
|
88
|
-
|
|
89
|
-
// Hot path (negative bias)
|
|
113
|
+
if ((load<u32>(srcIdx) & 0xffff) !== 0x5c) continue; // false positive
|
|
114
|
+
bs.offset += laneIdx;
|
|
115
|
+
const code = load<u16>(srcIdx, 2);
|
|
90
116
|
if (code !== 0x75) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
store<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
bs.offset -= (1 - l6) << 1;
|
|
99
|
-
srcStart += l6 << 1;
|
|
100
|
-
continue;
|
|
117
|
+
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
118
|
+
bs.offset += 2;
|
|
119
|
+
srcStart = srcIdx + 4;
|
|
120
|
+
} else {
|
|
121
|
+
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
|
|
122
|
+
bs.offset += 2;
|
|
123
|
+
srcStart = srcIdx + 12;
|
|
101
124
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
bs.offset -= 6 - laneIdx;
|
|
110
|
-
} while (mask !== 0);
|
|
111
|
-
|
|
112
|
-
bs.offset += 8;
|
|
113
|
-
srcStart += 8;
|
|
125
|
+
handled = true;
|
|
126
|
+
break;
|
|
127
|
+
} while (mask != 0);
|
|
128
|
+
if (!handled) {
|
|
129
|
+
bs.offset += 8;
|
|
130
|
+
srcStart += 8;
|
|
131
|
+
}
|
|
114
132
|
}
|
|
115
133
|
|
|
116
134
|
while (srcStart < srcEnd) {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// Early exit
|
|
122
|
-
if (block !== 0x5c) {
|
|
135
|
+
const char = load<u16>(srcStart);
|
|
136
|
+
if (char != BACK_SLASH) {
|
|
137
|
+
store<u16>(bs.offset, char);
|
|
123
138
|
bs.offset += 2;
|
|
139
|
+
srcStart += 2;
|
|
124
140
|
continue;
|
|
125
141
|
}
|
|
126
|
-
|
|
127
|
-
const code = load<u16>(srcStart);
|
|
142
|
+
const code = load<u16>(srcStart, 2);
|
|
128
143
|
if (code !== 0x75) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
store<u16>(bs.offset, escape);
|
|
133
|
-
srcStart += 2;
|
|
144
|
+
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
145
|
+
bs.offset += 2;
|
|
146
|
+
srcStart += 4;
|
|
134
147
|
} else {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
store<u16>(bs.offset, escaped);
|
|
139
|
-
srcStart += 10;
|
|
148
|
+
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
|
|
149
|
+
bs.offset += 2;
|
|
150
|
+
srcStart += 12;
|
|
140
151
|
}
|
|
141
|
-
|
|
142
|
-
bs.offset += 2;
|
|
143
152
|
}
|
|
144
153
|
return bs.sliceOut<string>(outStart);
|
|
145
154
|
}
|
|
@@ -190,7 +199,9 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
190
199
|
// Detect false positive (code unit where low byte is 0x5C)
|
|
191
200
|
if ((header & 0xffff) !== 0x5c) continue;
|
|
192
201
|
|
|
193
|
-
return inline.always(
|
|
202
|
+
return inline.always(
|
|
203
|
+
deserializeEscapedString_SWAR(payloadStart, srcIdx, srcEnd),
|
|
204
|
+
);
|
|
194
205
|
} while (mask !== 0);
|
|
195
206
|
|
|
196
207
|
srcStart += 8;
|
|
@@ -198,7 +209,9 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
198
209
|
|
|
199
210
|
while (srcStart < srcEnd) {
|
|
200
211
|
if (load<u16>(srcStart) == BACK_SLASH) {
|
|
201
|
-
return inline.always(
|
|
212
|
+
return inline.always(
|
|
213
|
+
deserializeEscapedString_SWAR(payloadStart, srcStart, srcEnd),
|
|
214
|
+
);
|
|
202
215
|
}
|
|
203
216
|
srcStart += 2;
|
|
204
217
|
}
|
|
@@ -208,7 +221,11 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
208
221
|
|
|
209
222
|
// Writes into the destination field, reusing or resizing the backing string.
|
|
210
223
|
// @ts-expect-error: @inline is a valid decorator
|
|
211
|
-
@inline function writeStringToField(
|
|
224
|
+
@inline function writeStringToField(
|
|
225
|
+
dstFieldPtr: usize,
|
|
226
|
+
srcStart: usize,
|
|
227
|
+
byteLength: u32,
|
|
228
|
+
): void {
|
|
212
229
|
if (byteLength == 0) {
|
|
213
230
|
store<usize>(dstFieldPtr, changetype<usize>(""));
|
|
214
231
|
return;
|
|
@@ -230,184 +247,113 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
230
247
|
memory.copy(stringPtr, srcStart, byteLength);
|
|
231
248
|
}
|
|
232
249
|
|
|
250
|
+
// Scans a quoted string value, writes into the destination field, and returns
|
|
251
|
+
// the next unread src pointer.
|
|
252
|
+
//
|
|
253
|
+
// HYBRID strategy (validated against the prior run-copy scanner across escape
|
|
254
|
+
// densities — see __benches__/custom/swar-string-deser-hybrid-h2h: +17–70%):
|
|
255
|
+
// * Escape-bearing block: one optimistic whole-block u64 store copies the
|
|
256
|
+
// plain prefix for free, then the (scalar-confirmed) escape is decoded.
|
|
257
|
+
// * Clean block: stream the first one, then if the clean run continues switch
|
|
258
|
+
// to one bulk memory.copy for the remainder.
|
|
259
|
+
// SWAR masks carry high-byte false positives, so each hit is confirmed
|
|
260
|
+
// scalarly before acting.
|
|
233
261
|
// @ts-expect-error: @inline is a valid decorator
|
|
234
|
-
@inline function
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (mask === 0) {
|
|
241
|
-
srcStart += 8;
|
|
242
|
-
continue;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
do {
|
|
246
|
-
const laneIdx = usize(ctz(mask) >> 3);
|
|
247
|
-
mask &= mask - 1;
|
|
248
|
-
const srcIdx = srcStart + laneIdx;
|
|
249
|
-
const char = load<u16>(srcIdx);
|
|
250
|
-
if (char == QUOTE) {
|
|
251
|
-
const runLen = <u32>(srcIdx - lastPtr);
|
|
252
|
-
if (runLen != 0) {
|
|
253
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
254
|
-
bs.offset += runLen;
|
|
255
|
-
}
|
|
256
|
-
bs.toField(outStart, dstFieldPtr);
|
|
257
|
-
return srcIdx + 2;
|
|
258
|
-
}
|
|
259
|
-
if (char != BACK_SLASH) continue;
|
|
260
|
-
|
|
261
|
-
const runLen = <u32>(srcIdx - lastPtr);
|
|
262
|
-
if (runLen != 0) {
|
|
263
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
264
|
-
bs.offset += runLen;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const chunk = load<u32>(srcIdx);
|
|
268
|
-
const code = <u16>(chunk >> 16);
|
|
269
|
-
if (code !== 0x75) {
|
|
270
|
-
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
271
|
-
bs.offset += 2;
|
|
272
|
-
lastPtr = srcIdx + 4;
|
|
273
|
-
} else {
|
|
274
|
-
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
|
|
275
|
-
bs.offset += 2;
|
|
276
|
-
lastPtr = srcIdx + 12;
|
|
277
|
-
}
|
|
278
|
-
srcStart = lastPtr;
|
|
279
|
-
break;
|
|
280
|
-
} while (mask !== 0);
|
|
281
|
-
|
|
282
|
-
if (srcStart == blockStart) srcStart += 8;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
while (srcStart < srcEnd) {
|
|
286
|
-
const char = load<u16>(srcStart);
|
|
287
|
-
if (char == QUOTE) {
|
|
288
|
-
const runLen = <u32>(srcStart - lastPtr);
|
|
289
|
-
if (runLen != 0) {
|
|
290
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
291
|
-
bs.offset += runLen;
|
|
292
|
-
}
|
|
293
|
-
bs.toField(outStart, dstFieldPtr);
|
|
294
|
-
return srcStart + 2;
|
|
295
|
-
}
|
|
296
|
-
if (char != BACK_SLASH) {
|
|
297
|
-
srcStart += 2;
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const runLen = <u32>(srcStart - lastPtr);
|
|
302
|
-
if (runLen != 0) {
|
|
303
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
304
|
-
bs.offset += runLen;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const code = load<u16>(srcStart, 2);
|
|
308
|
-
if (code !== 0x75) {
|
|
309
|
-
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
310
|
-
bs.offset += 2;
|
|
311
|
-
srcStart += 4;
|
|
312
|
-
} else {
|
|
313
|
-
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
|
|
314
|
-
bs.offset += 2;
|
|
315
|
-
srcStart += 12;
|
|
316
|
-
}
|
|
317
|
-
lastPtr = srcStart;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
bs.offset = bs.buffer + outStart;
|
|
321
|
-
abort("Unterminated string literal");
|
|
322
|
-
return srcStart;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Scans a quoted string value, writes into the destination field, and returns next unread src pointer.
|
|
326
|
-
// @ts-expect-error: @inline is a valid decorator
|
|
327
|
-
@inline function deserializeEscapedStringScan_SWAR_SplitTuned(payloadStart: usize, escapeStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
|
|
262
|
+
@inline function deserializeEscapedStringField_SWAR(
|
|
263
|
+
payloadStart: usize,
|
|
264
|
+
escapeStart: usize,
|
|
265
|
+
srcEnd: usize,
|
|
266
|
+
dstFieldPtr: usize,
|
|
267
|
+
): usize {
|
|
328
268
|
const prefixLen = <u32>(escapeStart - payloadStart);
|
|
329
|
-
const srcEnd8 = srcEnd - 8;
|
|
330
269
|
bs.offset = bs.buffer;
|
|
331
|
-
bs.ensureSize(<u32>(srcEnd - payloadStart));
|
|
270
|
+
bs.ensureSize(<u32>(srcEnd - payloadStart) + 8); // +8 slack for u64 overcopy
|
|
332
271
|
if (prefixLen != 0) {
|
|
333
272
|
memory.copy(bs.buffer, payloadStart, prefixLen);
|
|
334
273
|
bs.offset += prefixLen;
|
|
335
274
|
}
|
|
336
275
|
|
|
337
|
-
let lastPtr = escapeStart;
|
|
338
276
|
let srcStart = escapeStart;
|
|
277
|
+
const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
|
|
339
278
|
|
|
340
279
|
while (srcStart <= srcEnd8) {
|
|
341
|
-
const
|
|
342
|
-
let mask = inline.always(backslash_or_quote_mask(
|
|
343
|
-
if (mask
|
|
280
|
+
const block = load<u64>(srcStart);
|
|
281
|
+
let mask = inline.always(backslash_or_quote_mask(block));
|
|
282
|
+
if (mask == 0) {
|
|
283
|
+
store<u64>(bs.offset, block);
|
|
284
|
+
bs.offset += 8;
|
|
344
285
|
srcStart += 8;
|
|
286
|
+
if (
|
|
287
|
+
srcStart <= srcEnd8 &&
|
|
288
|
+
inline.always(backslash_or_quote_mask(load<u64>(srcStart))) == 0
|
|
289
|
+
) {
|
|
290
|
+
const runStart = srcStart;
|
|
291
|
+
srcStart += 8;
|
|
292
|
+
while (
|
|
293
|
+
srcStart <= srcEnd8 &&
|
|
294
|
+
inline.always(backslash_or_quote_mask(load<u64>(srcStart))) == 0
|
|
295
|
+
) {
|
|
296
|
+
srcStart += 8;
|
|
297
|
+
}
|
|
298
|
+
const runLen = <u32>(srcStart - runStart);
|
|
299
|
+
memory.copy(bs.offset, runStart, runLen);
|
|
300
|
+
bs.offset += runLen;
|
|
301
|
+
}
|
|
345
302
|
continue;
|
|
346
303
|
}
|
|
347
304
|
|
|
305
|
+
// Escape/quote block (mask may carry high-byte false positives).
|
|
306
|
+
store<u64>(bs.offset, block);
|
|
307
|
+
let handled = false;
|
|
348
308
|
do {
|
|
349
309
|
const laneIdx = usize(ctz(mask) >> 3);
|
|
350
310
|
mask &= mask - 1;
|
|
351
311
|
const srcIdx = srcStart + laneIdx;
|
|
352
312
|
const char = load<u16>(srcIdx);
|
|
313
|
+
if (char != QUOTE && char != BACK_SLASH) continue; // false positive
|
|
314
|
+
bs.offset += laneIdx;
|
|
353
315
|
if (char == QUOTE) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
bs.offset
|
|
358
|
-
|
|
359
|
-
writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
|
|
316
|
+
writeStringToField(
|
|
317
|
+
dstFieldPtr,
|
|
318
|
+
bs.buffer,
|
|
319
|
+
<u32>(bs.offset - bs.buffer),
|
|
320
|
+
);
|
|
360
321
|
bs.offset = bs.buffer;
|
|
361
322
|
return srcIdx + 2;
|
|
362
323
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const runLen = <u32>(srcIdx - lastPtr);
|
|
366
|
-
if (runLen != 0) {
|
|
367
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
368
|
-
bs.offset += runLen;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const chunk = load<u32>(srcIdx);
|
|
372
|
-
const code = <u16>(chunk >> 16);
|
|
324
|
+
const code = load<u16>(srcIdx, 2);
|
|
373
325
|
if (code !== 0x75) {
|
|
374
326
|
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
375
327
|
bs.offset += 2;
|
|
376
|
-
|
|
328
|
+
srcStart = srcIdx + 4;
|
|
377
329
|
} else {
|
|
378
330
|
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
|
|
379
331
|
bs.offset += 2;
|
|
380
|
-
|
|
332
|
+
srcStart = srcIdx + 12;
|
|
381
333
|
}
|
|
382
|
-
|
|
334
|
+
handled = true;
|
|
383
335
|
break;
|
|
384
|
-
} while (mask
|
|
385
|
-
if (
|
|
336
|
+
} while (mask != 0);
|
|
337
|
+
if (!handled) {
|
|
338
|
+
bs.offset += 8;
|
|
339
|
+
srcStart += 8;
|
|
340
|
+
}
|
|
386
341
|
}
|
|
387
342
|
|
|
343
|
+
// scalar tail (< 8 bytes remaining)
|
|
388
344
|
while (srcStart < srcEnd) {
|
|
389
345
|
const char = load<u16>(srcStart);
|
|
390
346
|
if (char == QUOTE) {
|
|
391
|
-
const runLen = <u32>(srcStart - lastPtr);
|
|
392
|
-
if (runLen != 0) {
|
|
393
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
394
|
-
bs.offset += runLen;
|
|
395
|
-
}
|
|
396
347
|
writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
|
|
397
348
|
bs.offset = bs.buffer;
|
|
398
349
|
return srcStart + 2;
|
|
399
350
|
}
|
|
400
351
|
if (char != BACK_SLASH) {
|
|
352
|
+
store<u16>(bs.offset, char);
|
|
353
|
+
bs.offset += 2;
|
|
401
354
|
srcStart += 2;
|
|
402
355
|
continue;
|
|
403
356
|
}
|
|
404
|
-
|
|
405
|
-
const runLen = <u32>(srcStart - lastPtr);
|
|
406
|
-
if (runLen != 0) {
|
|
407
|
-
memory.copy(bs.offset, lastPtr, runLen);
|
|
408
|
-
bs.offset += runLen;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
357
|
const code = load<u16>(srcStart, 2);
|
|
412
358
|
if (code !== 0x75) {
|
|
413
359
|
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
@@ -418,7 +364,6 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
418
364
|
bs.offset += 2;
|
|
419
365
|
srcStart += 12;
|
|
420
366
|
}
|
|
421
|
-
lastPtr = srcStart;
|
|
422
367
|
}
|
|
423
368
|
|
|
424
369
|
bs.offset = bs.buffer;
|
|
@@ -427,7 +372,12 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
427
372
|
}
|
|
428
373
|
|
|
429
374
|
// @ts-expect-error: @inline is a valid decorator
|
|
430
|
-
@inline function deserializeEscapedStringContinuation_SWAR_MergedTuned(
|
|
375
|
+
@inline function deserializeEscapedStringContinuation_SWAR_MergedTuned(
|
|
376
|
+
lastPtr: usize,
|
|
377
|
+
srcStart: usize,
|
|
378
|
+
srcEnd: usize,
|
|
379
|
+
dstFieldPtr: usize,
|
|
380
|
+
): usize {
|
|
431
381
|
const srcEnd8 = srcEnd - 8;
|
|
432
382
|
|
|
433
383
|
while (srcStart <= srcEnd8) {
|
|
@@ -449,7 +399,11 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
449
399
|
memory.copy(bs.offset, lastPtr, runLen);
|
|
450
400
|
bs.offset += runLen;
|
|
451
401
|
}
|
|
452
|
-
writeStringToField(
|
|
402
|
+
writeStringToField(
|
|
403
|
+
dstFieldPtr,
|
|
404
|
+
bs.buffer,
|
|
405
|
+
<u32>(bs.offset - bs.buffer),
|
|
406
|
+
);
|
|
453
407
|
bs.offset = bs.buffer;
|
|
454
408
|
return srcIdx + 2;
|
|
455
409
|
}
|
|
@@ -518,99 +472,33 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
518
472
|
return srcStart;
|
|
519
473
|
}
|
|
520
474
|
|
|
521
|
-
function
|
|
522
|
-
|
|
475
|
+
export function deserializeStringField_SWAR<T extends string | null>(
|
|
476
|
+
srcStart: usize,
|
|
477
|
+
srcEnd: usize,
|
|
478
|
+
dstObj: usize,
|
|
479
|
+
dstOffset: usize = 0,
|
|
480
|
+
): usize {
|
|
481
|
+
const dstFieldPtr = dstObj + dstOffset;
|
|
482
|
+
if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE)
|
|
483
|
+
abort("Expected leading quote");
|
|
523
484
|
|
|
524
485
|
const payloadStart = srcStart + 2;
|
|
525
|
-
const srcEnd8 = srcEnd - 8;
|
|
526
486
|
srcStart = payloadStart;
|
|
527
487
|
|
|
528
|
-
while
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const srcIdx = srcStart + laneIdx;
|
|
539
|
-
const char = load<u16>(srcIdx);
|
|
540
|
-
|
|
541
|
-
if (char == QUOTE) {
|
|
542
|
-
writeStringToField(dstFieldPtr, payloadStart, <u32>(srcIdx - payloadStart));
|
|
543
|
-
return srcIdx + 2;
|
|
544
|
-
}
|
|
545
|
-
if (char != BACK_SLASH) continue;
|
|
546
|
-
|
|
547
|
-
bs.offset = bs.buffer;
|
|
548
|
-
bs.ensureSize(<u32>(srcEnd - payloadStart));
|
|
549
|
-
const prefixLen = <u32>(srcIdx - payloadStart);
|
|
550
|
-
if (prefixLen != 0) {
|
|
551
|
-
memory.copy(bs.buffer, payloadStart, prefixLen);
|
|
552
|
-
bs.offset += prefixLen;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
const chunk = load<u32>(srcIdx);
|
|
556
|
-
const code = <u16>(chunk >> 16);
|
|
557
|
-
let lastPtr: usize;
|
|
558
|
-
if (code !== 0x75) {
|
|
559
|
-
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
560
|
-
bs.offset += 2;
|
|
561
|
-
lastPtr = srcIdx + 4;
|
|
562
|
-
} else {
|
|
563
|
-
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
|
|
564
|
-
bs.offset += 2;
|
|
565
|
-
lastPtr = srcIdx + 12;
|
|
566
|
-
}
|
|
567
|
-
return inline.always(deserializeEscapedStringContinuation_SWAR_MergedTuned(lastPtr, lastPtr, srcEnd, dstFieldPtr));
|
|
568
|
-
} while (mask !== 0);
|
|
569
|
-
|
|
570
|
-
srcStart += 8;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
while (srcStart < srcEnd) {
|
|
574
|
-
const char = load<u16>(srcStart);
|
|
575
|
-
if (char == QUOTE) {
|
|
576
|
-
writeStringToField(dstFieldPtr, payloadStart, <u32>(srcStart - payloadStart));
|
|
577
|
-
return srcStart + 2;
|
|
578
|
-
}
|
|
579
|
-
if (char == BACK_SLASH) {
|
|
580
|
-
bs.offset = bs.buffer;
|
|
581
|
-
bs.ensureSize(<u32>(srcEnd - payloadStart));
|
|
582
|
-
const prefixLen = <u32>(srcStart - payloadStart);
|
|
583
|
-
if (prefixLen != 0) {
|
|
584
|
-
memory.copy(bs.buffer, payloadStart, prefixLen);
|
|
585
|
-
bs.offset += prefixLen;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
const code = load<u16>(srcStart, 2);
|
|
589
|
-
let lastPtr: usize;
|
|
590
|
-
if (code !== 0x75) {
|
|
591
|
-
store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
|
|
592
|
-
bs.offset += 2;
|
|
593
|
-
lastPtr = srcStart + 4;
|
|
594
|
-
} else {
|
|
595
|
-
store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
|
|
596
|
-
bs.offset += 2;
|
|
597
|
-
lastPtr = srcStart + 12;
|
|
598
|
-
}
|
|
599
|
-
return inline.always(deserializeEscapedStringContinuation_SWAR_MergedTuned(lastPtr, lastPtr, srcEnd, dstFieldPtr));
|
|
488
|
+
// Wide pre-scan: skip 16 bytes per iter while both halves are clean. The
|
|
489
|
+
// common case (plain ASCII payloads, no escape) hits this loop exclusively
|
|
490
|
+
// and is bound by load+SWAR throughput, not branch frequency.
|
|
491
|
+
if (srcEnd >= 16) {
|
|
492
|
+
const srcEnd16 = srcEnd - 16;
|
|
493
|
+
while (srcStart <= srcEnd16) {
|
|
494
|
+
const m0 = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
|
|
495
|
+
const m1 = inline.always(backslash_or_quote_mask(load<u64>(srcStart, 8)));
|
|
496
|
+
if ((m0 | m1) != 0) break;
|
|
497
|
+
srcStart += 16;
|
|
600
498
|
}
|
|
601
|
-
srcStart += 2;
|
|
602
499
|
}
|
|
603
500
|
|
|
604
|
-
return srcStart;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
export function deserializeStringField_SWAR<T extends string | null>(srcStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
|
|
608
|
-
if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE) abort("Expected leading quote");
|
|
609
|
-
|
|
610
|
-
const payloadStart = srcStart + 2;
|
|
611
501
|
const srcEnd8 = srcEnd - 8;
|
|
612
|
-
srcStart = payloadStart;
|
|
613
|
-
|
|
614
502
|
while (srcStart <= srcEnd8) {
|
|
615
503
|
let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
|
|
616
504
|
if (mask === 0) {
|
|
@@ -624,11 +512,22 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
|
|
|
624
512
|
const srcIdx = srcStart + laneIdx;
|
|
625
513
|
const char = load<u16>(srcIdx);
|
|
626
514
|
if (char == QUOTE) {
|
|
627
|
-
writeStringToField(
|
|
515
|
+
writeStringToField(
|
|
516
|
+
dstFieldPtr,
|
|
517
|
+
payloadStart,
|
|
518
|
+
<u32>(srcIdx - payloadStart),
|
|
519
|
+
);
|
|
628
520
|
return srcIdx + 2;
|
|
629
521
|
}
|
|
630
522
|
if (char != BACK_SLASH) continue;
|
|
631
|
-
return inline.always(
|
|
523
|
+
return inline.always(
|
|
524
|
+
deserializeEscapedStringField_SWAR(
|
|
525
|
+
payloadStart,
|
|
526
|
+
srcIdx,
|
|
527
|
+
srcEnd,
|
|
528
|
+
dstFieldPtr,
|
|
529
|
+
),
|
|
530
|
+
);
|
|
632
531
|
} while (mask !== 0);
|
|
633
532
|
|
|
634
533
|
srcStart += 8;
|
|
@@ -637,11 +536,22 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
|
|
|
637
536
|
while (srcStart < srcEnd) {
|
|
638
537
|
const char = load<u16>(srcStart);
|
|
639
538
|
if (char == QUOTE) {
|
|
640
|
-
writeStringToField(
|
|
539
|
+
writeStringToField(
|
|
540
|
+
dstFieldPtr,
|
|
541
|
+
payloadStart,
|
|
542
|
+
<u32>(srcStart - payloadStart),
|
|
543
|
+
);
|
|
641
544
|
return srcStart + 2;
|
|
642
545
|
}
|
|
643
546
|
if (char == BACK_SLASH) {
|
|
644
|
-
return inline.always(
|
|
547
|
+
return inline.always(
|
|
548
|
+
deserializeEscapedStringField_SWAR(
|
|
549
|
+
payloadStart,
|
|
550
|
+
srcStart,
|
|
551
|
+
srcEnd,
|
|
552
|
+
dstFieldPtr,
|
|
553
|
+
),
|
|
554
|
+
);
|
|
645
555
|
}
|
|
646
556
|
srcStart += 2;
|
|
647
557
|
}
|
|
@@ -661,7 +571,10 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
|
|
|
661
571
|
@inline function backslash_or_quote_mask(block: u64): u64 {
|
|
662
572
|
const b = block ^ 0x005c_005c_005c_005c;
|
|
663
573
|
const q = block ^ 0x0022_0022_0022_0022;
|
|
664
|
-
return (
|
|
574
|
+
return (
|
|
575
|
+
(((q - 0x0001_0001_0001_0001) & ~q) | ((b - 0x0001_0001_0001_0001) & ~b)) &
|
|
576
|
+
0x0080_0080_0080_0080
|
|
577
|
+
);
|
|
665
578
|
}
|
|
666
579
|
/**
|
|
667
580
|
* Computes a per-lane mask identifying UTF-16 code units whose **low byte**
|
|
@@ -677,8 +590,13 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
|
|
|
677
590
|
// @ts-expect-error: @inline is a valid decorator
|
|
678
591
|
@inline function backslash_mask(block: u64): u64 {
|
|
679
592
|
const b = block ^ 0x005c_005c_005c_005c;
|
|
680
|
-
const backslash_mask =
|
|
681
|
-
|
|
593
|
+
const backslash_mask =
|
|
594
|
+
(b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
|
|
595
|
+
const high_byte_mask =
|
|
596
|
+
~(
|
|
597
|
+
((block - 0x0100_0100_0100_0100) & ~block & 0x8000_8000_8000_8000) ^
|
|
598
|
+
0x8000_8000_8000_8000
|
|
599
|
+
) >> 8;
|
|
682
600
|
return backslash_mask & high_byte_mask;
|
|
683
601
|
}
|
|
684
602
|
|
|
@@ -694,6 +612,7 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
|
|
|
694
612
|
// @ts-expect-error: @inline is a valid decorator
|
|
695
613
|
@inline function backslash_mask_unsafe(block: u64): u64 {
|
|
696
614
|
const b = block ^ 0x005c_005c_005c_005c;
|
|
697
|
-
const backslash_mask =
|
|
615
|
+
const backslash_mask =
|
|
616
|
+
(b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
|
|
698
617
|
return backslash_mask;
|
|
699
618
|
}
|