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,7 +1,15 @@
|
|
|
1
|
+
import { deserializeGenericArrayBody } from "./generic";
|
|
1
2
|
import { ensureArrayField } from "./shared";
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
@inline export function deserializeMapArrayField<T extends Map<any, any>[]>(
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
@inline export function deserializeMapArrayField<T extends Map<any, any>[]>(
|
|
6
|
+
srcStart: usize,
|
|
7
|
+
srcEnd: usize,
|
|
8
|
+
fieldPtr: usize,
|
|
9
|
+
): usize {
|
|
10
|
+
return deserializeGenericArrayBody<T>(
|
|
11
|
+
srcStart,
|
|
12
|
+
srcEnd,
|
|
13
|
+
ensureArrayField<T>(fieldPtr),
|
|
14
|
+
);
|
|
7
15
|
}
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
+
import { JSON } from "../../..";
|
|
1
2
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
2
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ensureArrayElementSlot,
|
|
5
|
+
ensureArrayField,
|
|
6
|
+
scanValueEnd,
|
|
7
|
+
skipWhitespace,
|
|
8
|
+
} from "./shared";
|
|
3
9
|
|
|
4
10
|
|
|
5
|
-
@inline
|
|
11
|
+
@inline function deserializeObjectArrayBody<T extends unknown[]>(
|
|
12
|
+
srcStart: usize,
|
|
13
|
+
srcEnd: usize,
|
|
14
|
+
out: T,
|
|
15
|
+
): usize {
|
|
6
16
|
let index = 0;
|
|
7
17
|
|
|
8
18
|
do {
|
|
9
19
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
10
20
|
srcStart += 2;
|
|
21
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
11
22
|
if (srcStart >= srcEnd) break;
|
|
12
23
|
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
13
24
|
out.length = 0;
|
|
@@ -16,36 +27,29 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
16
27
|
|
|
17
28
|
while (srcStart < srcEnd) {
|
|
18
29
|
const slot = ensureArrayElementSlot<T>(out, index);
|
|
19
|
-
let value = load<valueof<T>>(slot);
|
|
20
|
-
if (changetype<usize>(value) == 0) {
|
|
21
|
-
value = changetype<valueof<T>>(__new(offsetof<nonnull<valueof<T>>>(), idof<nonnull<valueof<T>>>()));
|
|
22
|
-
// @ts-ignore: supplied by transform
|
|
23
|
-
if (isDefined(changetype<nonnull<valueof<T>>>(value).__INITIALIZE)) {
|
|
24
|
-
// @ts-ignore: supplied by transform
|
|
25
|
-
changetype<nonnull<valueof<T>>>(value).__INITIALIZE();
|
|
26
|
-
}
|
|
27
|
-
store<valueof<T>>(slot, value);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
30
|
const valueStart = srcStart;
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
const valueEnd = scanValueEnd(valueStart, srcEnd);
|
|
32
|
+
if (!valueEnd) break;
|
|
33
|
+
|
|
34
|
+
const value = JSON.__deserialize<valueof<T>>(
|
|
35
|
+
valueStart,
|
|
36
|
+
valueEnd,
|
|
37
|
+
changetype<usize>(load<valueof<T>>(slot)),
|
|
38
|
+
);
|
|
39
|
+
store<valueof<T>>(slot, value);
|
|
40
|
+
srcStart = valueEnd;
|
|
40
41
|
|
|
42
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
41
43
|
const code = load<u16>(srcStart);
|
|
42
44
|
if (code == COMMA) {
|
|
43
45
|
srcStart += 2;
|
|
46
|
+
srcStart = skipWhitespace(srcStart, srcEnd);
|
|
44
47
|
index++;
|
|
45
48
|
continue;
|
|
46
49
|
}
|
|
47
50
|
if (code == BRACKET_RIGHT) {
|
|
48
|
-
|
|
51
|
+
const nextLen = index + 1;
|
|
52
|
+
if (out.length != nextLen) out.length = nextLen;
|
|
49
53
|
return srcStart + 2;
|
|
50
54
|
}
|
|
51
55
|
break;
|
|
@@ -56,6 +60,14 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
|
|
59
|
-
@inline export function deserializeObjectArrayField<T extends unknown[]>(
|
|
60
|
-
|
|
63
|
+
@inline export function deserializeObjectArrayField<T extends unknown[]>(
|
|
64
|
+
srcStart: usize,
|
|
65
|
+
srcEnd: usize,
|
|
66
|
+
fieldPtr: usize,
|
|
67
|
+
): usize {
|
|
68
|
+
return deserializeObjectArrayBody<T>(
|
|
69
|
+
srcStart,
|
|
70
|
+
srcEnd,
|
|
71
|
+
ensureArrayField<T>(fieldPtr),
|
|
72
|
+
);
|
|
61
73
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { JSON } from "../../..";
|
|
2
|
+
import { deserializeGenericArrayBody } from "./generic";
|
|
2
3
|
import { ensureArrayField } from "./shared";
|
|
3
4
|
|
|
4
5
|
|
|
5
|
-
@inline export function deserializeRawArrayField(
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
@inline export function deserializeRawArrayField(
|
|
7
|
+
srcStart: usize,
|
|
8
|
+
srcEnd: usize,
|
|
9
|
+
fieldPtr: usize,
|
|
10
|
+
): usize {
|
|
11
|
+
return deserializeGenericArrayBody<JSON.Raw[]>(
|
|
12
|
+
srcStart,
|
|
13
|
+
srcEnd,
|
|
14
|
+
ensureArrayField<JSON.Raw[]>(fieldPtr),
|
|
15
|
+
);
|
|
8
16
|
}
|
|
@@ -1,7 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BACK_SLASH,
|
|
3
|
+
BRACE_LEFT,
|
|
4
|
+
BRACE_RIGHT,
|
|
5
|
+
BRACKET_LEFT,
|
|
6
|
+
BRACKET_RIGHT,
|
|
7
|
+
COMMA,
|
|
8
|
+
QUOTE,
|
|
9
|
+
} from "../../../custom/chars";
|
|
10
|
+
import { isSpace } from "../../../util";
|
|
11
|
+
|
|
12
|
+
/** Advance past JSON whitespace (space, tab, LF, CR). */
|
|
13
|
+
// @ts-expect-error: @inline is a valid decorator
|
|
14
|
+
@inline export function skipWhitespace(srcStart: usize, srcEnd: usize): usize {
|
|
15
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
16
|
+
return srcStart;
|
|
17
|
+
}
|
|
2
18
|
|
|
3
19
|
|
|
4
|
-
@inline export function ensureArrayField<T extends Array<any>>(
|
|
20
|
+
@inline export function ensureArrayField<T extends Array<any>>(
|
|
21
|
+
fieldPtr: usize,
|
|
22
|
+
): T {
|
|
5
23
|
let out = load<T>(fieldPtr);
|
|
6
24
|
if (!changetype<usize>(out)) {
|
|
7
25
|
out = changetype<T>(instantiate<T>());
|
|
@@ -11,7 +29,10 @@ import { BACK_SLASH, BRACE_LEFT, BRACE_RIGHT, BRACKET_LEFT, BRACKET_RIGHT, COMMA
|
|
|
11
29
|
}
|
|
12
30
|
|
|
13
31
|
|
|
14
|
-
@inline export function ensureArrayFieldAt<T extends Array<any>>(
|
|
32
|
+
@inline export function ensureArrayFieldAt<T extends Array<any>>(
|
|
33
|
+
dstObj: usize,
|
|
34
|
+
dstOffset: usize,
|
|
35
|
+
): T {
|
|
15
36
|
let out = load<T>(dstObj, dstOffset);
|
|
16
37
|
if (!changetype<usize>(out)) {
|
|
17
38
|
out = changetype<T>(instantiate<T>());
|
|
@@ -24,25 +45,43 @@ import { BACK_SLASH, BRACE_LEFT, BRACE_RIGHT, BRACKET_LEFT, BRACKET_RIGHT, COMMA
|
|
|
24
45
|
@inline function backslashOrQuoteMask(block: u64): u64 {
|
|
25
46
|
const b = block ^ 0x005c_005c_005c_005c;
|
|
26
47
|
const q = block ^ 0x0022_0022_0022_0022;
|
|
27
|
-
return (
|
|
48
|
+
return (
|
|
49
|
+
(((q - 0x0001_0001_0001_0001) & ~q) | ((b - 0x0001_0001_0001_0001) & ~b)) &
|
|
50
|
+
0x0080_0080_0080_0080
|
|
51
|
+
);
|
|
28
52
|
}
|
|
29
53
|
|
|
30
54
|
|
|
31
|
-
@inline export function ensureArrayElementSlot<T extends Array<any>>(
|
|
55
|
+
@inline export function ensureArrayElementSlot<T extends Array<any>>(
|
|
56
|
+
out: T,
|
|
57
|
+
index: i32,
|
|
58
|
+
): usize {
|
|
32
59
|
const nextLength = index + 1;
|
|
33
60
|
if (out.length < nextLength) {
|
|
34
|
-
out.length = nextLength
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
61
|
+
// Grow via `push`, not `out.length = nextLength`. AS's `length=`
|
|
62
|
+
// setter calls `ensureCapacity(canGrow=false)` which reallocates to
|
|
63
|
+
// *exactly* the requested size — fine for a one-shot resize, but
|
|
64
|
+
// catastrophic in the per-element loop (every push triggers a full
|
|
65
|
+
// copy of the array, giving O(N²) growth cost). `push` goes through
|
|
66
|
+
// `canGrow=true`, doubling capacity geometrically as needed.
|
|
67
|
+
//
|
|
68
|
+
// We push a zero-bit default: `0` for primitives, the null reference
|
|
69
|
+
// for managed/reference element types. The caller overwrites this
|
|
70
|
+
// slot immediately, so the placeholder is never observed.
|
|
71
|
+
if (isManaged<valueof<T>>() || isReference<valueof<T>>()) {
|
|
72
|
+
out.push(changetype<valueof<T>>(0));
|
|
73
|
+
} else {
|
|
74
|
+
out.push(<valueof<T>>0);
|
|
75
|
+
}
|
|
40
76
|
}
|
|
41
77
|
return out.dataStart + <usize>index * sizeof<valueof<T>>();
|
|
42
78
|
}
|
|
43
79
|
|
|
44
80
|
|
|
45
|
-
@inline export function scanQuotedValueEnd_SWAR(
|
|
81
|
+
@inline export function scanQuotedValueEnd_SWAR(
|
|
82
|
+
srcStart: usize,
|
|
83
|
+
srcEnd: usize,
|
|
84
|
+
): usize {
|
|
46
85
|
srcStart += 2;
|
|
47
86
|
const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
|
|
48
87
|
|
|
@@ -67,7 +106,8 @@ import { BACK_SLASH, BRACE_LEFT, BRACE_RIGHT, BRACKET_LEFT, BRACKET_RIGHT, COMMA
|
|
|
67
106
|
|
|
68
107
|
while (srcStart < srcEnd) {
|
|
69
108
|
const char = load<u16>(srcStart);
|
|
70
|
-
if (char == QUOTE && load<u16>(srcStart - 2) != BACK_SLASH)
|
|
109
|
+
if (char == QUOTE && load<u16>(srcStart - 2) != BACK_SLASH)
|
|
110
|
+
return srcStart + 2;
|
|
71
111
|
srcStart += 2;
|
|
72
112
|
}
|
|
73
113
|
|
|
@@ -103,7 +143,16 @@ import { BACK_SLASH, BRACE_LEFT, BRACE_RIGHT, BRACKET_LEFT, BRACKET_RIGHT, COMMA
|
|
|
103
143
|
|
|
104
144
|
while (srcStart < srcEnd) {
|
|
105
145
|
const code = load<u16>(srcStart);
|
|
106
|
-
|
|
146
|
+
// Stop at the structural terminator OR trailing whitespace, so the returned
|
|
147
|
+
// range is the exact value (scalar parsers assume no trailing whitespace).
|
|
148
|
+
// Callers skip whitespace to reach the following `,`/`]`/`}`.
|
|
149
|
+
if (
|
|
150
|
+
code == COMMA ||
|
|
151
|
+
code == BRACKET_RIGHT ||
|
|
152
|
+
code == BRACE_RIGHT ||
|
|
153
|
+
isSpace(code)
|
|
154
|
+
)
|
|
155
|
+
return srcStart;
|
|
107
156
|
srcStart += 2;
|
|
108
157
|
}
|
|
109
158
|
|
|
@@ -1,14 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BRACKET_LEFT,
|
|
3
|
+
BRACKET_RIGHT,
|
|
4
|
+
COMMA,
|
|
5
|
+
NULL_WORD_U64,
|
|
6
|
+
} from "../../../custom/chars";
|
|
7
|
+
import { isSpace } from "../../../util";
|
|
2
8
|
import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
3
9
|
import { deserializeStringField_SWAR } from "../string";
|
|
4
10
|
|
|
5
11
|
|
|
6
|
-
@inline
|
|
12
|
+
@inline function skipStringArrayWhitespace(
|
|
13
|
+
srcStart: usize,
|
|
14
|
+
srcEnd: usize,
|
|
15
|
+
): usize {
|
|
16
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
17
|
+
return srcStart;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@inline function deserializeStringArrayBody<T extends string[]>(
|
|
22
|
+
srcStart: usize,
|
|
23
|
+
srcEnd: usize,
|
|
24
|
+
out: T,
|
|
25
|
+
): usize {
|
|
7
26
|
let index = 0;
|
|
8
27
|
|
|
9
28
|
do {
|
|
10
29
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
11
30
|
srcStart += 2;
|
|
31
|
+
srcStart = skipStringArrayWhitespace(srcStart, srcEnd);
|
|
12
32
|
if (srcStart >= srcEnd) break;
|
|
13
33
|
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
14
34
|
out.length = 0;
|
|
@@ -17,17 +37,41 @@ import { deserializeStringField_SWAR } from "../string";
|
|
|
17
37
|
|
|
18
38
|
while (srcStart < srcEnd) {
|
|
19
39
|
const slot = ensureArrayElementSlot<T>(out, index);
|
|
20
|
-
|
|
21
|
-
|
|
40
|
+
// Null fast path for `(string | null)[]`. "null" is 4 UTF-16 chars
|
|
41
|
+
// = 8 bytes, exactly one u64 compare. Store 0 (the AS null reference)
|
|
42
|
+
// and skip 8 bytes.
|
|
43
|
+
//
|
|
44
|
+
// We accept null tokens unconditionally rather than gating on
|
|
45
|
+
// `isNullable<valueof<T>>()` — AS's `valueof` of a nullable-array
|
|
46
|
+
// element type doesn't always preserve the nullable marker through
|
|
47
|
+
// the dispatcher's `<T>` cast, so the gate would mis-fire for the
|
|
48
|
+
// very case it's meant to handle. The runtime cost on plain
|
|
49
|
+
// `string[]` arrays is one extra u64 compare per element; a
|
|
50
|
+
// well-formed `string[]` input never matches it.
|
|
51
|
+
if (srcStart + 8 <= srcEnd && load<u64>(srcStart) == NULL_WORD_U64) {
|
|
52
|
+
store<usize>(slot, 0);
|
|
53
|
+
srcStart += 8;
|
|
54
|
+
} else {
|
|
55
|
+
srcStart = deserializeStringField_SWAR<valueof<T>>(
|
|
56
|
+
srcStart,
|
|
57
|
+
srcEnd,
|
|
58
|
+
slot,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (!srcStart) break;
|
|
62
|
+
srcStart = skipStringArrayWhitespace(srcStart, srcEnd);
|
|
63
|
+
if (srcStart >= srcEnd) break;
|
|
22
64
|
|
|
23
65
|
const code = load<u16>(srcStart);
|
|
24
66
|
if (code == COMMA) {
|
|
25
67
|
srcStart += 2;
|
|
68
|
+
srcStart = skipStringArrayWhitespace(srcStart, srcEnd);
|
|
26
69
|
index++;
|
|
27
70
|
continue;
|
|
28
71
|
}
|
|
29
72
|
if (code == BRACKET_RIGHT) {
|
|
30
|
-
|
|
73
|
+
const nextLen = index + 1;
|
|
74
|
+
if (out.length != nextLen) out.length = nextLen;
|
|
31
75
|
return srcStart + 2;
|
|
32
76
|
}
|
|
33
77
|
break;
|
|
@@ -38,6 +82,95 @@ import { deserializeStringField_SWAR } from "../string";
|
|
|
38
82
|
}
|
|
39
83
|
|
|
40
84
|
|
|
41
|
-
@inline export function deserializeStringArrayField<T extends string[]>(
|
|
42
|
-
|
|
85
|
+
@inline export function deserializeStringArrayField<T extends string[]>(
|
|
86
|
+
srcStart: usize,
|
|
87
|
+
srcEnd: usize,
|
|
88
|
+
fieldPtr: usize,
|
|
89
|
+
): usize {
|
|
90
|
+
return deserializeStringArrayBody<T>(
|
|
91
|
+
srcStart,
|
|
92
|
+
srcEnd,
|
|
93
|
+
ensureArrayField<T>(fieldPtr),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Top-level entry for `JSON.parse<string[]>` / `JSON.parse<(string | null)[]>`.
|
|
98
|
+
//
|
|
99
|
+
// Pre-grows the destination array to a worst-case bound in one allocation,
|
|
100
|
+
// then writes elements via `writePtr` direct stores. This sidesteps the
|
|
101
|
+
// per-element growth cost of `deserializeStringArrayBody`'s
|
|
102
|
+
// `ensureArrayElementSlot` path. The incremental runtime zero-initializes
|
|
103
|
+
// new allocations, so `null` slots need no per-element store on cold
|
|
104
|
+
// arrays (we still write 0 to handle reused arrays whose old refs would
|
|
105
|
+
// otherwise leak through).
|
|
106
|
+
export function deserializeStringArray_SWAR<T extends string[]>(
|
|
107
|
+
srcStart: usize,
|
|
108
|
+
srcEnd: usize,
|
|
109
|
+
dst: usize,
|
|
110
|
+
): T {
|
|
111
|
+
const out = changetype<nonnull<T>>(
|
|
112
|
+
dst || changetype<usize>(instantiate<T>()),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
// Worst-case sizing: shortest possible element is `""` followed by `,` =
|
|
116
|
+
// 6 UTF-16 bytes, so `(srcLen + 5) / 6` upper-bounds the count. Clamp to
|
|
117
|
+
// AS's BLOCK_MAXSIZE / sizeof<string ref> = (1<<28) - 4 elements; payloads
|
|
118
|
+
// that exceed this would fail the `out.length =` setter anyway. For a
|
|
119
|
+
// 1 GiB UTF-16 source that maxes at ~256M slot allocation = ~1 GiB.
|
|
120
|
+
const elementSize: usize = sizeof<usize>();
|
|
121
|
+
const maxBlockElements: i32 = i32((<usize>0x40000000 - 16) / elementSize);
|
|
122
|
+
let maxElements: i32 = i32((<usize>(srcEnd - srcStart) + 5) / 6);
|
|
123
|
+
if (maxElements < 0 || maxElements > maxBlockElements) {
|
|
124
|
+
maxElements = maxBlockElements;
|
|
125
|
+
}
|
|
126
|
+
if (out.length < maxElements) out.length = maxElements;
|
|
127
|
+
|
|
128
|
+
const dataStart: usize = out.dataStart;
|
|
129
|
+
let writePtr: usize = dataStart;
|
|
130
|
+
const writePtrLimit: usize = dataStart + <usize>maxElements * elementSize;
|
|
131
|
+
|
|
132
|
+
// Caller guarantees srcStart is at the opening `[`.
|
|
133
|
+
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) {
|
|
134
|
+
out.length = 0;
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
srcStart += 2;
|
|
138
|
+
srcStart = skipStringArrayWhitespace(srcStart, srcEnd);
|
|
139
|
+
if (srcStart < srcEnd && load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
140
|
+
out.length = 0;
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
while (srcStart < srcEnd && writePtr < writePtrLimit) {
|
|
145
|
+
// Null fast path: one u64 compare.
|
|
146
|
+
if (srcStart + 8 <= srcEnd && load<u64>(srcStart) == NULL_WORD_U64) {
|
|
147
|
+
store<usize>(writePtr, 0);
|
|
148
|
+
srcStart += 8;
|
|
149
|
+
} else {
|
|
150
|
+
srcStart = deserializeStringField_SWAR<valueof<T>>(
|
|
151
|
+
srcStart,
|
|
152
|
+
srcEnd,
|
|
153
|
+
writePtr,
|
|
154
|
+
);
|
|
155
|
+
if (!srcStart) break;
|
|
156
|
+
}
|
|
157
|
+
writePtr += elementSize;
|
|
158
|
+
srcStart = skipStringArrayWhitespace(srcStart, srcEnd);
|
|
159
|
+
if (srcStart >= srcEnd) break;
|
|
160
|
+
|
|
161
|
+
const code = load<u16>(srcStart);
|
|
162
|
+
if (code == COMMA) {
|
|
163
|
+
srcStart += 2;
|
|
164
|
+
srcStart = skipStringArrayWhitespace(srcStart, srcEnd);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (code == BRACKET_RIGHT) {
|
|
168
|
+
const finalLen = i32(<usize>(writePtr - dataStart) / elementSize);
|
|
169
|
+
if (out.length != finalLen) out.length = finalLen;
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
throw new Error("Failed to parse JSON!");
|
|
43
176
|
}
|
|
@@ -1,13 +1,42 @@
|
|
|
1
1
|
import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
|
|
2
|
+
import { isSpace } from "../../../util";
|
|
2
3
|
import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
3
4
|
|
|
4
5
|
|
|
5
|
-
@inline
|
|
6
|
+
@inline function skipStructArrayWhitespace(
|
|
7
|
+
srcStart: usize,
|
|
8
|
+
srcEnd: usize,
|
|
9
|
+
): usize {
|
|
10
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
11
|
+
return srcStart;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Per-element worker for `@json class Foo[]` fields. Each element is a
|
|
15
|
+
// managed reference whose value is produced by the transform-generated
|
|
16
|
+
// `__DESERIALIZE_FAST` / `__DESERIALIZE_SLOW` methods, so the loop pattern
|
|
17
|
+
// is structurally different from primitive-array bodies:
|
|
18
|
+
//
|
|
19
|
+
// - The slot stores a *reference*; reused arrays may already hold an
|
|
20
|
+
// allocated instance whose fields we just overwrite. Only allocate +
|
|
21
|
+
// `__INITIALIZE` when the slot is null.
|
|
22
|
+
// - `__DESERIALIZE_FAST` returns the cursor past the closing `}` on
|
|
23
|
+
// success, or `0` to signal "bail to slow path". We mirror the
|
|
24
|
+
// dispatcher in `JSON.__deserialize` here: try FAST first, fall back
|
|
25
|
+
// to SLOW on `0`.
|
|
26
|
+
// - Whitespace is skipped at each separator boundary so struct-array
|
|
27
|
+
// fields tolerate the same `[ {...} , {...} ]` shape that top-level
|
|
28
|
+
// `JSON.parse` does.
|
|
29
|
+
@inline function deserializeStructArrayBody<T extends unknown[]>(
|
|
30
|
+
srcStart: usize,
|
|
31
|
+
srcEnd: usize,
|
|
32
|
+
out: T,
|
|
33
|
+
): usize {
|
|
6
34
|
let index = 0;
|
|
7
35
|
|
|
8
36
|
do {
|
|
9
37
|
if (srcStart >= srcEnd || load<u16>(srcStart) != BRACKET_LEFT) break;
|
|
10
38
|
srcStart += 2;
|
|
39
|
+
srcStart = skipStructArrayWhitespace(srcStart, srcEnd);
|
|
11
40
|
if (srcStart >= srcEnd) break;
|
|
12
41
|
if (load<u16>(srcStart) == BRACKET_RIGHT) {
|
|
13
42
|
out.length = 0;
|
|
@@ -18,7 +47,9 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
18
47
|
const slot = ensureArrayElementSlot<T>(out, index);
|
|
19
48
|
let value = load<valueof<T>>(slot);
|
|
20
49
|
if (changetype<usize>(value) == 0) {
|
|
21
|
-
value = changetype<valueof<T>>(
|
|
50
|
+
value = changetype<valueof<T>>(
|
|
51
|
+
__new(offsetof<nonnull<valueof<T>>>(), idof<nonnull<valueof<T>>>()),
|
|
52
|
+
);
|
|
22
53
|
// @ts-ignore: supplied by transform
|
|
23
54
|
if (isDefined(changetype<nonnull<valueof<T>>>(value).__INITIALIZE)) {
|
|
24
55
|
// @ts-ignore: supplied by transform
|
|
@@ -27,25 +58,40 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
27
58
|
store<valueof<T>>(slot, value);
|
|
28
59
|
}
|
|
29
60
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (isDefined(changetype<nonnull<valueof<T>>>(value).__DESERIALIZE_FAST)) {
|
|
61
|
+
let next: usize = 0;
|
|
62
|
+
if (
|
|
33
63
|
// @ts-ignore: supplied by transform
|
|
34
|
-
|
|
35
|
-
|
|
64
|
+
isDefined(changetype<nonnull<valueof<T>>>(value).__DESERIALIZE_FAST)
|
|
65
|
+
) {
|
|
66
|
+
// @ts-ignore: supplied by transform
|
|
67
|
+
next = changetype<nonnull<valueof<T>>>(value).__DESERIALIZE_FAST<
|
|
68
|
+
valueof<T>
|
|
69
|
+
>(srcStart, srcEnd, value);
|
|
70
|
+
}
|
|
71
|
+
if (!next) {
|
|
36
72
|
// @ts-ignore: supplied by transform
|
|
37
|
-
|
|
73
|
+
next = changetype<nonnull<valueof<T>>>(value).__DESERIALIZE_SLOW<
|
|
74
|
+
valueof<T>
|
|
75
|
+
>(srcStart, srcEnd, value);
|
|
38
76
|
}
|
|
39
|
-
if (!
|
|
77
|
+
if (!next) break;
|
|
78
|
+
srcStart = next;
|
|
79
|
+
srcStart = skipStructArrayWhitespace(srcStart, srcEnd);
|
|
80
|
+
if (srcStart >= srcEnd) break;
|
|
40
81
|
|
|
41
82
|
const code = load<u16>(srcStart);
|
|
42
83
|
if (code == COMMA) {
|
|
43
84
|
srcStart += 2;
|
|
85
|
+
srcStart = skipStructArrayWhitespace(srcStart, srcEnd);
|
|
44
86
|
index++;
|
|
45
87
|
continue;
|
|
46
88
|
}
|
|
47
89
|
if (code == BRACKET_RIGHT) {
|
|
48
|
-
|
|
90
|
+
// Skip `ensureCapacity` when the reused array already has the
|
|
91
|
+
// right length (e.g. canada-style geometry rings whose count
|
|
92
|
+
// matches a previous parse).
|
|
93
|
+
const nextLen = index + 1;
|
|
94
|
+
if (out.length != nextLen) out.length = nextLen;
|
|
49
95
|
return srcStart + 2;
|
|
50
96
|
}
|
|
51
97
|
break;
|
|
@@ -56,6 +102,14 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
|
|
|
56
102
|
}
|
|
57
103
|
|
|
58
104
|
|
|
59
|
-
@inline export function deserializeStructArrayField<T extends unknown[]>(
|
|
60
|
-
|
|
105
|
+
@inline export function deserializeStructArrayField<T extends unknown[]>(
|
|
106
|
+
srcStart: usize,
|
|
107
|
+
srcEnd: usize,
|
|
108
|
+
fieldPtr: usize,
|
|
109
|
+
): usize {
|
|
110
|
+
return deserializeStructArrayBody<T>(
|
|
111
|
+
srcStart,
|
|
112
|
+
srcEnd,
|
|
113
|
+
ensureArrayField<T>(fieldPtr),
|
|
114
|
+
);
|
|
61
115
|
}
|
|
@@ -11,17 +11,16 @@ import { deserializeObjectArrayField } from "./array/object";
|
|
|
11
11
|
import { deserializeRawArrayField } from "./array/raw";
|
|
12
12
|
import { deserializeStringArrayField } from "./array/string";
|
|
13
13
|
import { deserializeStructArrayField } from "./array/struct";
|
|
14
|
-
import { deserializeArrayArrayInto } from "./array/array";
|
|
15
|
-
import { deserializeBooleanArrayInto } from "./array/bool";
|
|
16
|
-
import { deserializeFloatArrayInto } from "./array/float";
|
|
17
|
-
import { deserializeGenericArrayInto } from "./array/generic";
|
|
18
|
-
import { deserializeIntegerArrayInto } from "./array/integer";
|
|
19
|
-
import { deserializeObjectArrayInto } from "./array/object";
|
|
20
|
-
import { deserializeStringArrayInto } from "./array/string";
|
|
21
|
-
import { deserializeStructArrayInto } from "./array/struct";
|
|
22
14
|
|
|
15
|
+
export { deserializeArrayField as deserializeArrayField_SWAR };
|
|
23
16
|
|
|
24
|
-
|
|
17
|
+
|
|
18
|
+
@inline export function deserializeArrayField<T extends unknown[]>(
|
|
19
|
+
srcStart: usize,
|
|
20
|
+
srcEnd: usize,
|
|
21
|
+
dstObj: usize,
|
|
22
|
+
dstOffset: usize = 0,
|
|
23
|
+
): usize {
|
|
25
24
|
const fieldPtr = dstObj + dstOffset;
|
|
26
25
|
if (isString<valueof<T>>()) {
|
|
27
26
|
return deserializeStringArrayField<T>(srcStart, srcEnd, fieldPtr);
|
|
@@ -53,7 +52,10 @@ import { deserializeStructArrayInto } from "./array/struct";
|
|
|
53
52
|
} else if (isDefined(type.__DESERIALIZE_CUSTOM)) {
|
|
54
53
|
return deserializeStructArrayField<T>(srcStart, srcEnd, fieldPtr);
|
|
55
54
|
// @ts-ignore: defined by transform
|
|
56
|
-
} else if (
|
|
55
|
+
} else if (
|
|
56
|
+
isDefined(type.__DESERIALIZE_SLOW) ||
|
|
57
|
+
isDefined(type.__DESERIALIZE_FAST)
|
|
58
|
+
) {
|
|
57
59
|
return deserializeStructArrayField<T>(srcStart, srcEnd, fieldPtr);
|
|
58
60
|
}
|
|
59
61
|
throw new Error("Could not parse array field of type " + nameof<T>() + "!");
|
|
@@ -61,44 +63,3 @@ import { deserializeStructArrayInto } from "./array/struct";
|
|
|
61
63
|
throw new Error("Could not parse array field of type " + nameof<T>() + "!");
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
@inline export function deserializeArrayInto_SWAR<T extends unknown[]>(srcStart: usize, srcEnd: usize, out: T): usize {
|
|
67
|
-
if (isString<valueof<T>>()) {
|
|
68
|
-
return deserializeStringArrayInto<T>(srcStart, srcEnd, out);
|
|
69
|
-
} else if (isBoolean<valueof<T>>()) {
|
|
70
|
-
return deserializeBooleanArrayInto<T>(srcStart, srcEnd, out);
|
|
71
|
-
} else if (isInteger<valueof<T>>()) {
|
|
72
|
-
return deserializeIntegerArrayInto<T>(srcStart, srcEnd, out);
|
|
73
|
-
} else if (isFloat<valueof<T>>()) {
|
|
74
|
-
return deserializeFloatArrayInto<T>(srcStart, srcEnd, out);
|
|
75
|
-
} else if (isArray<valueof<T>>()) {
|
|
76
|
-
return deserializeArrayArrayInto<T>(srcStart, srcEnd, out);
|
|
77
|
-
} else if (isManaged<valueof<T>>() || isReference<valueof<T>>()) {
|
|
78
|
-
const type = changetype<nonnull<valueof<T>>>(0);
|
|
79
|
-
if (type instanceof JSON.Value) {
|
|
80
|
-
return deserializeGenericArrayInto<T>(srcStart, srcEnd, out);
|
|
81
|
-
} else if (type instanceof JSON.Box) {
|
|
82
|
-
throw new Error("Failed to parse JSON!");
|
|
83
|
-
} else if (type instanceof JSON.Obj) {
|
|
84
|
-
return deserializeObjectArrayInto<T>(srcStart, srcEnd, out);
|
|
85
|
-
} else if (type instanceof JSON.Raw) {
|
|
86
|
-
throw new Error("Failed to parse JSON!");
|
|
87
|
-
} else if (type instanceof Date) {
|
|
88
|
-
return deserializeGenericArrayInto<T>(srcStart, srcEnd, out);
|
|
89
|
-
} else if (type instanceof Set) {
|
|
90
|
-
return deserializeGenericArrayInto<T>(srcStart, srcEnd, out);
|
|
91
|
-
} else if (type instanceof Map) {
|
|
92
|
-
throw new Error("Failed to parse JSON!");
|
|
93
|
-
// @ts-ignore: defined by transform
|
|
94
|
-
} else if (isDefined(type.__DESERIALIZE_CUSTOM)) {
|
|
95
|
-
return deserializeStructArrayInto<T>(srcStart, srcEnd, out);
|
|
96
|
-
// @ts-ignore: defined by transform
|
|
97
|
-
} else if (isDefined(type.__DESERIALIZE_SLOW) || isDefined(type.__DESERIALIZE_FAST)) {
|
|
98
|
-
return deserializeStructArrayInto<T>(srcStart, srcEnd, out);
|
|
99
|
-
}
|
|
100
|
-
throw new Error("Could not parse array field of type " + nameof<T>() + "!");
|
|
101
|
-
} else {
|
|
102
|
-
throw new Error("Could not parse array field of type " + nameof<T>() + "!");
|
|
103
|
-
}
|
|
104
|
-
}
|