json-as 1.2.3 → 1.2.5
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/.claude/settings.local.json +9 -0
- package/ARCHITECTURE.md +320 -0
- package/CONTRIBUTING.md +238 -0
- package/LICENSE +2 -2
- package/README.md +34 -2
- package/TODO +1 -0
- package/assembly/custom/chars.ts +9 -0
- package/assembly/deserialize/simd/string.ts +6 -41
- package/assembly/deserialize/simple/set.ts +169 -0
- package/assembly/deserialize/simple/staticarray/array.ts +37 -0
- package/assembly/deserialize/simple/staticarray/bool.ts +39 -0
- package/assembly/deserialize/simple/staticarray/float.ts +44 -0
- package/assembly/deserialize/simple/staticarray/integer.ts +44 -0
- package/assembly/deserialize/simple/staticarray/string.ts +45 -0
- package/assembly/deserialize/simple/staticarray/struct.ts +47 -0
- package/assembly/deserialize/simple/staticarray.ts +28 -0
- package/assembly/deserialize/swar/string.ts +6 -5
- package/assembly/index.ts +337 -143
- package/assembly/serialize/simd/string.ts +14 -17
- package/assembly/serialize/simple/set.ts +34 -0
- package/assembly/serialize/simple/staticarray.ts +30 -0
- package/assembly/serialize/swar/string.ts +50 -36
- package/assembly/test.ts +20 -38
- package/assembly/util/swar.ts +2 -2
- package/eslint.config.js +77 -0
- package/lib/as-bs.ts +143 -50
- package/package.json +18 -5
- package/transform/lib/builder.d.ts +87 -0
- package/transform/lib/builder.d.ts.map +1 -0
- package/transform/lib/builder.js +169 -169
- package/transform/lib/builder.js.map +1 -1
- package/transform/lib/index.d.ts +32 -0
- package/transform/lib/index.d.ts.map +1 -0
- package/transform/lib/index.js +40 -18
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/linkers/alias.d.ts +12 -0
- package/transform/lib/linkers/alias.d.ts.map +1 -0
- package/transform/lib/linkers/alias.js +1 -1
- package/transform/lib/linkers/alias.js.map +1 -1
- package/transform/lib/linkers/custom.d.ts +10 -0
- package/transform/lib/linkers/custom.d.ts.map +1 -0
- package/transform/lib/linkers/imports.d.ts +3 -0
- package/transform/lib/linkers/imports.d.ts.map +1 -0
- package/transform/lib/linkers/imports.js +1 -1
- package/transform/lib/linkers/imports.js.map +1 -1
- package/transform/lib/types.d.ts +66 -0
- package/transform/lib/types.d.ts.map +1 -0
- package/transform/lib/types.js +6 -5
- package/transform/lib/types.js.map +1 -1
- package/transform/lib/util.d.ts +18 -0
- package/transform/lib/util.d.ts.map +1 -0
- package/transform/lib/util.js +4 -4
- package/transform/lib/util.js.map +1 -1
- package/transform/lib/visitor.d.ts +84 -0
- package/transform/lib/visitor.d.ts.map +1 -0
- package/transform/lib/visitor.js +76 -76
- package/transform/lib/visitor.js.map +1 -1
- package/transform/tsconfig.json +29 -2
- package/assembly/serialize/swar/number.ts +0 -0
- package/assembly/test.mask.ts +0 -87
- package/transform/lib/linkers/classes.js +0 -36
- package/transform/lib/linkers/classes.js.map +0 -1
|
@@ -3,7 +3,7 @@ import { BACK_SLASH } from "../../custom/chars";
|
|
|
3
3
|
import { DESERIALIZE_ESCAPE_TABLE, ESCAPE_HEX_TABLE } from "../../globals/tables";
|
|
4
4
|
import { hex4_to_u16_swar } from "../../util/swar";
|
|
5
5
|
|
|
6
|
-
// @ts-
|
|
6
|
+
// @ts-expect-error: @lazy is a valid decorator
|
|
7
7
|
@lazy const SPLAT_5C = i16x8.splat(0x5C); // \
|
|
8
8
|
|
|
9
9
|
// Overflow Pattern for Unicode Escapes (READ)
|
|
@@ -71,15 +71,17 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize): string {
|
|
|
71
71
|
const block = load<v128>(srcStart);
|
|
72
72
|
store<v128>(bs.offset, block);
|
|
73
73
|
|
|
74
|
-
const eq5C = i16x8.eq(
|
|
75
|
-
|
|
74
|
+
const eq5C = i16x8.eq(block, SPLAT_5C);
|
|
75
|
+
|
|
76
76
|
// Early exit
|
|
77
|
-
if (
|
|
77
|
+
if (!v128.any_true(eq5C)) {
|
|
78
78
|
srcStart += 16;
|
|
79
79
|
bs.offset += 16;
|
|
80
80
|
continue;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
let mask = i16x8.bitmask(eq5C);
|
|
84
|
+
|
|
83
85
|
let srcChg: usize = 0;
|
|
84
86
|
let lastLane: usize = 0;
|
|
85
87
|
do {
|
|
@@ -157,40 +159,3 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize): string {
|
|
|
157
159
|
|
|
158
160
|
return bs.out<string>();
|
|
159
161
|
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Computes a per-lane mask identifying UTF-16 code units whose **low byte**
|
|
163
|
-
* is the ASCII backslash (`'\\'`, 0x5C).
|
|
164
|
-
*
|
|
165
|
-
* The mask is produced in two stages:
|
|
166
|
-
* 1. Detects bytes equal to 0x5C using a SWAR equality test.
|
|
167
|
-
* 2. Clears matches where 0x5C appears in the **high byte** of a UTF-16 code unit,
|
|
168
|
-
* ensuring only valid low-byte backslashes are reported.
|
|
169
|
-
*
|
|
170
|
-
* Each matching lane sets itself to 0x80.
|
|
171
|
-
*/
|
|
172
|
-
// @ts-ignore: decorator
|
|
173
|
-
@inline function backslash_mask(block: u64): u64 {
|
|
174
|
-
const b = block ^ 0x005C_005C_005C_005C;
|
|
175
|
-
const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
|
|
176
|
-
const high_byte_mask =
|
|
177
|
-
~(((block - 0x0100_0100_0100_0100) & ~block & 0x8000_8000_8000_8000)
|
|
178
|
-
^ 0x8000_8000_8000_8000) >> 8;
|
|
179
|
-
return backslash_mask & high_byte_mask;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Computes a per-lane mask identifying UTF-16 code units whose **low byte**
|
|
184
|
-
* is the ASCII backslash (`'\\'`, 0x5C).
|
|
185
|
-
*
|
|
186
|
-
* Each matching lane sets itself to 0x80.
|
|
187
|
-
*
|
|
188
|
-
* WARNING: The low byte of a code unit *may* be a backslash, thus triggering false positives!
|
|
189
|
-
* This is useful for a hot path where it is possible to detect the false positive scalarly.
|
|
190
|
-
*/
|
|
191
|
-
// @ts-ignore: decorator
|
|
192
|
-
@inline function backslash_mask_unsafe(block: u64): u64 {
|
|
193
|
-
const b = block ^ 0x005C_005C_005C_005C;
|
|
194
|
-
const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
|
|
195
|
-
return backslash_mask;
|
|
196
|
-
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { JSON } from "../..";
|
|
2
|
+
import { BACK_SLASH, BRACKET_LEFT, BRACKET_RIGHT, BRACE_LEFT, BRACE_RIGHT, CHAR_F, CHAR_N, CHAR_T, COMMA, QUOTE } from "../../custom/chars";
|
|
3
|
+
import { isSpace, atoi } from "../../util";
|
|
4
|
+
|
|
5
|
+
export function deserializeSet<T extends Set<any>>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
6
|
+
const out = changetype<nonnull<T>>(dst || changetype<usize>(instantiate<T>()));
|
|
7
|
+
|
|
8
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
9
|
+
while (srcEnd > srcStart && isSpace(load<u16>(srcEnd - 2))) srcEnd -= 2;
|
|
10
|
+
|
|
11
|
+
if (srcStart >= srcEnd) throw new Error("Input string had zero length or was all whitespace");
|
|
12
|
+
if (load<u16>(srcStart) != BRACKET_LEFT) throw new Error("Expected '[' at start of set");
|
|
13
|
+
if (load<u16>(srcEnd - 2) != BRACKET_RIGHT) throw new Error("Expected ']' at end of set");
|
|
14
|
+
|
|
15
|
+
srcStart += 2;
|
|
16
|
+
|
|
17
|
+
while (srcStart < srcEnd - 2) {
|
|
18
|
+
let code = load<u16>(srcStart);
|
|
19
|
+
while (isSpace(code)) code = load<u16>((srcStart += 2));
|
|
20
|
+
|
|
21
|
+
// @ts-ignore: type
|
|
22
|
+
if (isString<indexof<T>>()) {
|
|
23
|
+
if (code == QUOTE) {
|
|
24
|
+
const lastIndex = srcStart;
|
|
25
|
+
srcStart += 2;
|
|
26
|
+
while (srcStart < srcEnd) {
|
|
27
|
+
const c = load<u16>(srcStart);
|
|
28
|
+
if (c == QUOTE && load<u16>(srcStart - 2) != BACK_SLASH) {
|
|
29
|
+
// @ts-ignore: type
|
|
30
|
+
out.add(JSON.__deserialize<indexof<T>>(lastIndex, srcStart + 2));
|
|
31
|
+
srcStart += 2;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
srcStart += 2;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// @ts-ignore: type
|
|
38
|
+
} else if (isBoolean<indexof<T>>()) {
|
|
39
|
+
if (code == CHAR_T) {
|
|
40
|
+
// @ts-ignore: type
|
|
41
|
+
out.add(<indexof<T>>true);
|
|
42
|
+
srcStart += 8;
|
|
43
|
+
} else if (code == CHAR_F) {
|
|
44
|
+
// @ts-ignore: type
|
|
45
|
+
out.add(<indexof<T>>false);
|
|
46
|
+
srcStart += 10;
|
|
47
|
+
}
|
|
48
|
+
// @ts-ignore: type
|
|
49
|
+
} else if (isInteger<indexof<T>>()) {
|
|
50
|
+
if (code - 48 <= 9 || code == 45) {
|
|
51
|
+
const lastIndex = srcStart;
|
|
52
|
+
srcStart += 2;
|
|
53
|
+
while (srcStart < srcEnd) {
|
|
54
|
+
const c = load<u16>(srcStart);
|
|
55
|
+
if (c == COMMA || c == BRACKET_RIGHT || isSpace(c)) {
|
|
56
|
+
// @ts-ignore: type
|
|
57
|
+
out.add(atoi<indexof<T>>(lastIndex, srcStart));
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
srcStart += 2;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// @ts-ignore: type
|
|
64
|
+
} else if (isFloat<indexof<T>>()) {
|
|
65
|
+
if (code - 48 <= 9 || code == 45) {
|
|
66
|
+
const lastIndex = srcStart;
|
|
67
|
+
srcStart += 2;
|
|
68
|
+
while (srcStart < srcEnd) {
|
|
69
|
+
const c = load<u16>(srcStart);
|
|
70
|
+
if (c == COMMA || c == BRACKET_RIGHT || isSpace(c)) {
|
|
71
|
+
// @ts-ignore: type
|
|
72
|
+
out.add(JSON.__deserialize<indexof<T>>(lastIndex, srcStart));
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
srcStart += 2;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// @ts-ignore: type
|
|
79
|
+
} else if (isManaged<indexof<T>>() || isReference<indexof<T>>()) {
|
|
80
|
+
// @ts-ignore: type
|
|
81
|
+
const type = changetype<nonnull<indexof<T>>>(0);
|
|
82
|
+
if (code == BRACE_LEFT) {
|
|
83
|
+
// Object
|
|
84
|
+
const lastIndex = srcStart;
|
|
85
|
+
let depth: u32 = 1;
|
|
86
|
+
srcStart += 2;
|
|
87
|
+
while (srcStart < srcEnd) {
|
|
88
|
+
const c = load<u16>(srcStart);
|
|
89
|
+
if (c == QUOTE) {
|
|
90
|
+
srcStart += 2;
|
|
91
|
+
while (!(load<u16>(srcStart) == QUOTE && load<u16>(srcStart - 2) != BACK_SLASH)) srcStart += 2;
|
|
92
|
+
} else if (c == BRACE_RIGHT) {
|
|
93
|
+
if (--depth == 0) {
|
|
94
|
+
srcStart += 2;
|
|
95
|
+
// @ts-ignore: type
|
|
96
|
+
out.add(JSON.__deserialize<indexof<T>>(lastIndex, srcStart));
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
} else if (c == BRACE_LEFT) {
|
|
100
|
+
depth++;
|
|
101
|
+
}
|
|
102
|
+
srcStart += 2;
|
|
103
|
+
}
|
|
104
|
+
} else if (code == BRACKET_LEFT) {
|
|
105
|
+
// Nested array/set
|
|
106
|
+
const lastIndex = srcStart;
|
|
107
|
+
let depth: u32 = 1;
|
|
108
|
+
srcStart += 2;
|
|
109
|
+
while (srcStart < srcEnd) {
|
|
110
|
+
const c = load<u16>(srcStart);
|
|
111
|
+
if (c == BRACKET_RIGHT) {
|
|
112
|
+
if (--depth == 0) {
|
|
113
|
+
srcStart += 2;
|
|
114
|
+
// @ts-ignore: type
|
|
115
|
+
out.add(JSON.__deserialize<indexof<T>>(lastIndex, srcStart));
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
} else if (c == BRACKET_LEFT) {
|
|
119
|
+
depth++;
|
|
120
|
+
}
|
|
121
|
+
srcStart += 2;
|
|
122
|
+
}
|
|
123
|
+
} else if (type instanceof JSON.Raw) {
|
|
124
|
+
// Handle JSON.Raw
|
|
125
|
+
if (code == QUOTE) {
|
|
126
|
+
const lastIndex = srcStart;
|
|
127
|
+
srcStart += 2;
|
|
128
|
+
while (srcStart < srcEnd) {
|
|
129
|
+
const c = load<u16>(srcStart);
|
|
130
|
+
if (c == QUOTE && load<u16>(srcStart - 2) != BACK_SLASH) {
|
|
131
|
+
// @ts-ignore: type
|
|
132
|
+
out.add(JSON.__deserialize<indexof<T>>(lastIndex, srcStart + 2));
|
|
133
|
+
srcStart += 2;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
srcStart += 2;
|
|
137
|
+
}
|
|
138
|
+
} else if (code - 48 <= 9 || code == 45) {
|
|
139
|
+
const lastIndex = srcStart;
|
|
140
|
+
srcStart += 2;
|
|
141
|
+
while (srcStart < srcEnd) {
|
|
142
|
+
const c = load<u16>(srcStart);
|
|
143
|
+
if (c == COMMA || c == BRACKET_RIGHT || isSpace(c)) {
|
|
144
|
+
// @ts-ignore: type
|
|
145
|
+
out.add(JSON.__deserialize<indexof<T>>(lastIndex, srcStart));
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
srcStart += 2;
|
|
149
|
+
}
|
|
150
|
+
} else if (code == CHAR_T) {
|
|
151
|
+
// @ts-ignore: type
|
|
152
|
+
out.add(JSON.__deserialize<indexof<T>>(srcStart, srcStart + 8));
|
|
153
|
+
srcStart += 8;
|
|
154
|
+
} else if (code == CHAR_F) {
|
|
155
|
+
// @ts-ignore: type
|
|
156
|
+
out.add(JSON.__deserialize<indexof<T>>(srcStart, srcStart + 10));
|
|
157
|
+
srcStart += 10;
|
|
158
|
+
} else if (code == CHAR_N) {
|
|
159
|
+
// @ts-ignore: type
|
|
160
|
+
out.add(JSON.__deserialize<indexof<T>>(srcStart, srcStart + 8));
|
|
161
|
+
srcStart += 8;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
srcStart += 2;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BRACKET_LEFT, BRACKET_RIGHT } from "../../../custom/chars";
|
|
2
|
+
import { JSON } from "../../../";
|
|
3
|
+
|
|
4
|
+
export function deserializeStaticArrayArray<T extends StaticArray<any>>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
5
|
+
let count: i32 = 0;
|
|
6
|
+
let depth: u32 = 0;
|
|
7
|
+
let ptr = srcStart + 2;
|
|
8
|
+
while (ptr < srcEnd - 2) {
|
|
9
|
+
const code = load<u16>(ptr);
|
|
10
|
+
if (code == BRACKET_LEFT && depth++ == 0) {
|
|
11
|
+
// start of nested array
|
|
12
|
+
} else if (code == BRACKET_RIGHT && --depth == 0) {
|
|
13
|
+
count++;
|
|
14
|
+
}
|
|
15
|
+
ptr += 2;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const outSize = <usize>count << alignof<valueof<T>>();
|
|
19
|
+
const out = changetype<nonnull<T>>(dst || __new(outSize, idof<T>()));
|
|
20
|
+
|
|
21
|
+
// Second pass: populate values
|
|
22
|
+
let index = 0;
|
|
23
|
+
let lastIndex: usize = 0;
|
|
24
|
+
depth = 0;
|
|
25
|
+
srcStart += 2;
|
|
26
|
+
while (srcStart < srcEnd - 2) {
|
|
27
|
+
const code = load<u16>(srcStart);
|
|
28
|
+
if (code == BRACKET_LEFT && depth++ == 0) {
|
|
29
|
+
lastIndex = srcStart;
|
|
30
|
+
} else if (code == BRACKET_RIGHT && --depth == 0) {
|
|
31
|
+
unchecked((out[index++] = JSON.__deserialize<valueof<T>>(lastIndex, srcStart + 2)));
|
|
32
|
+
}
|
|
33
|
+
srcStart += 2;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function deserializeStaticArrayBoolean<T extends StaticArray<any>>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
2
|
+
// First pass: count elements using same logic as Array deserializer
|
|
3
|
+
let count: i32 = 0;
|
|
4
|
+
let ptr = srcStart + 2; // skip [
|
|
5
|
+
while (ptr < srcEnd) {
|
|
6
|
+
const block = load<u64>(ptr);
|
|
7
|
+
if (block == 28429475166421108) {
|
|
8
|
+
count++;
|
|
9
|
+
ptr += 10;
|
|
10
|
+
} else if (block == 32370086184550502 && load<u16>(ptr, 8) == 101) {
|
|
11
|
+
count++;
|
|
12
|
+
ptr += 12;
|
|
13
|
+
} else {
|
|
14
|
+
ptr += 2;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Allocate StaticArray with correct size
|
|
19
|
+
const outSize = <usize>count << alignof<valueof<T>>();
|
|
20
|
+
const out = changetype<nonnull<T>>(dst || __new(outSize, idof<T>()));
|
|
21
|
+
|
|
22
|
+
// Second pass: populate values
|
|
23
|
+
let index = 0;
|
|
24
|
+
srcStart += 2; // skip [
|
|
25
|
+
while (srcStart < srcEnd) {
|
|
26
|
+
const block = load<u64>(srcStart);
|
|
27
|
+
if (block == 28429475166421108) {
|
|
28
|
+
unchecked((out[index++] = <valueof<T>>true));
|
|
29
|
+
srcStart += 10;
|
|
30
|
+
} else if (block == 32370086184550502 && load<u16>(srcStart, 8) == 101) {
|
|
31
|
+
unchecked((out[index++] = <valueof<T>>false));
|
|
32
|
+
srcStart += 12;
|
|
33
|
+
} else {
|
|
34
|
+
srcStart += 2;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isSpace } from "../../../util";
|
|
2
|
+
import { COMMA, BRACKET_RIGHT } from "../../../custom/chars";
|
|
3
|
+
import { JSON } from "../../..";
|
|
4
|
+
|
|
5
|
+
export function deserializeStaticArrayFloat<T extends StaticArray<any>>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
6
|
+
let count: i32 = 0;
|
|
7
|
+
let ptr = srcStart;
|
|
8
|
+
while (ptr < srcEnd) {
|
|
9
|
+
const code = load<u16>(ptr);
|
|
10
|
+
if (code - 48 <= 9 || code == 45) {
|
|
11
|
+
count++;
|
|
12
|
+
ptr += 2;
|
|
13
|
+
while (ptr < srcEnd) {
|
|
14
|
+
const code = load<u16>(ptr);
|
|
15
|
+
if (code == COMMA || code == BRACKET_RIGHT || isSpace(code)) break;
|
|
16
|
+
ptr += 2;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
ptr += 2;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const outSize = <usize>count << alignof<valueof<T>>();
|
|
23
|
+
const out = changetype<nonnull<T>>(dst || __new(outSize, idof<T>()));
|
|
24
|
+
|
|
25
|
+
let index = 0;
|
|
26
|
+
while (srcStart < srcEnd) {
|
|
27
|
+
const code = load<u16>(srcStart);
|
|
28
|
+
if (code - 48 <= 9 || code == 45) {
|
|
29
|
+
const lastIndex = srcStart;
|
|
30
|
+
srcStart += 2;
|
|
31
|
+
while (srcStart < srcEnd) {
|
|
32
|
+
const code = load<u16>(srcStart);
|
|
33
|
+
if (code == COMMA || code == BRACKET_RIGHT || isSpace(code)) {
|
|
34
|
+
unchecked((out[index++] = JSON.__deserialize<valueof<T>>(lastIndex, srcStart)));
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
srcStart += 2;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
srcStart += 2;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { atoi, isSpace } from "../../../util";
|
|
2
|
+
import { COMMA, BRACKET_RIGHT } from "../../../custom/chars";
|
|
3
|
+
|
|
4
|
+
export function deserializeStaticArrayInteger<T extends StaticArray<any>>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
5
|
+
let count: i32 = 0;
|
|
6
|
+
let ptr = srcStart;
|
|
7
|
+
while (ptr < srcEnd) {
|
|
8
|
+
const code = load<u16>(ptr);
|
|
9
|
+
if (code - 48 <= 9 || code == 45) {
|
|
10
|
+
count++;
|
|
11
|
+
ptr += 2;
|
|
12
|
+
while (ptr < srcEnd) {
|
|
13
|
+
const code = load<u16>(ptr);
|
|
14
|
+
if (code == COMMA || code == BRACKET_RIGHT || isSpace(code)) break;
|
|
15
|
+
ptr += 2;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
ptr += 2;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const outSize = <usize>count << alignof<valueof<T>>();
|
|
22
|
+
const out = changetype<nonnull<T>>(dst || __new(outSize, idof<T>()));
|
|
23
|
+
|
|
24
|
+
// Second pass: populate values
|
|
25
|
+
let index = 0;
|
|
26
|
+
while (srcStart < srcEnd) {
|
|
27
|
+
const code = load<u16>(srcStart);
|
|
28
|
+
if (code - 48 <= 9 || code == 45) {
|
|
29
|
+
const lastIndex = srcStart;
|
|
30
|
+
srcStart += 2;
|
|
31
|
+
while (srcStart < srcEnd) {
|
|
32
|
+
const code = load<u16>(srcStart);
|
|
33
|
+
if (code == COMMA || code == BRACKET_RIGHT || isSpace(code)) {
|
|
34
|
+
unchecked((out[index++] = atoi<valueof<T>>(lastIndex, srcStart)));
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
srcStart += 2;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
srcStart += 2;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { JSON } from "../../..";
|
|
2
|
+
import { BACK_SLASH, QUOTE } from "../../../custom/chars";
|
|
3
|
+
|
|
4
|
+
export function deserializeStaticArrayString(srcStart: usize, srcEnd: usize, dst: usize): StaticArray<string> {
|
|
5
|
+
// First pass: count elements using same logic as Array deserializer
|
|
6
|
+
let count: i32 = 0;
|
|
7
|
+
let ptr = srcStart;
|
|
8
|
+
let inString = false;
|
|
9
|
+
while (ptr < srcEnd) {
|
|
10
|
+
const code = load<u16>(ptr);
|
|
11
|
+
if (code == QUOTE) {
|
|
12
|
+
if (!inString) {
|
|
13
|
+
inString = true;
|
|
14
|
+
} else if (load<u16>(ptr - 2) != BACK_SLASH) {
|
|
15
|
+
count++;
|
|
16
|
+
inString = false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
ptr += 2;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Allocate StaticArray with correct size
|
|
23
|
+
const outSize = <usize>count << alignof<string>();
|
|
24
|
+
const out = changetype<StaticArray<string>>(dst || __new(outSize, idof<StaticArray<string>>()));
|
|
25
|
+
|
|
26
|
+
// Second pass: populate values
|
|
27
|
+
let index = 0;
|
|
28
|
+
let lastPos: usize = 0;
|
|
29
|
+
inString = false;
|
|
30
|
+
while (srcStart < srcEnd) {
|
|
31
|
+
const code = load<u16>(srcStart);
|
|
32
|
+
if (code == QUOTE) {
|
|
33
|
+
if (!inString) {
|
|
34
|
+
inString = true;
|
|
35
|
+
lastPos = srcStart;
|
|
36
|
+
} else if (load<u16>(srcStart - 2) != BACK_SLASH) {
|
|
37
|
+
unchecked((out[index++] = JSON.__deserialize<string>(lastPos, srcStart + 2)));
|
|
38
|
+
inString = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
srcStart += 2;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BRACE_LEFT, BRACE_RIGHT, BRACKET_LEFT, BRACKET_RIGHT } from "../../../custom/chars";
|
|
2
|
+
import { JSON } from "../../..";
|
|
3
|
+
import { isSpace } from "util/string";
|
|
4
|
+
|
|
5
|
+
export function deserializeStaticArrayStruct<T extends StaticArray<any>>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
6
|
+
while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
|
|
7
|
+
while (srcEnd > srcStart && isSpace(load<u16>(srcEnd - 2))) srcEnd -= 2;
|
|
8
|
+
|
|
9
|
+
if (srcStart - srcEnd == 0) throw new Error("Input string had zero length or was all whitespace");
|
|
10
|
+
|
|
11
|
+
if (load<u16>(srcStart) != BRACKET_LEFT) throw new Error("Expected '[' at start of object at position " + (srcEnd - srcStart).toString());
|
|
12
|
+
if (load<u16>(srcEnd - 2) != BRACKET_RIGHT) throw new Error("Expected ']' at end of object at position " + (srcEnd - srcStart).toString());
|
|
13
|
+
|
|
14
|
+
// First pass: count elements using same logic as Array deserializer
|
|
15
|
+
let count: i32 = 0;
|
|
16
|
+
let depth: u32 = 0;
|
|
17
|
+
let ptr = srcStart;
|
|
18
|
+
while (ptr < srcEnd) {
|
|
19
|
+
const code = load<u16>(ptr);
|
|
20
|
+
if (code == BRACE_LEFT && depth++ == 0) {
|
|
21
|
+
// start of object
|
|
22
|
+
} else if (code == BRACE_RIGHT && --depth == 0) {
|
|
23
|
+
count++;
|
|
24
|
+
}
|
|
25
|
+
ptr += 2;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Allocate StaticArray with correct size
|
|
29
|
+
const outSize = <usize>count << alignof<valueof<T>>();
|
|
30
|
+
const out = changetype<nonnull<T>>(dst || __new(outSize, idof<T>()));
|
|
31
|
+
|
|
32
|
+
// Second pass: populate values
|
|
33
|
+
let index = 0;
|
|
34
|
+
let lastIndex: usize = 0;
|
|
35
|
+
depth = 0;
|
|
36
|
+
while (srcStart < srcEnd) {
|
|
37
|
+
const code = load<u16>(srcStart);
|
|
38
|
+
if (code == BRACE_LEFT && depth++ == 0) {
|
|
39
|
+
lastIndex = srcStart;
|
|
40
|
+
} else if (code == BRACE_RIGHT && --depth == 0) {
|
|
41
|
+
unchecked((out[index++] = JSON.__deserialize<valueof<T>>(lastIndex, (srcStart += 2))));
|
|
42
|
+
}
|
|
43
|
+
srcStart += 2;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { deserializeStaticArrayInteger } from "./staticarray/integer";
|
|
2
|
+
import { deserializeStaticArrayFloat } from "./staticarray/float";
|
|
3
|
+
import { deserializeStaticArrayBoolean } from "./staticarray/bool";
|
|
4
|
+
import { deserializeStaticArrayString } from "./staticarray/string";
|
|
5
|
+
import { deserializeStaticArrayArray } from "./staticarray/array";
|
|
6
|
+
import { deserializeStaticArrayStruct } from "./staticarray/struct";
|
|
7
|
+
|
|
8
|
+
export function deserializeStaticArray<T extends StaticArray<any>>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
9
|
+
if (isString<valueof<T>>()) {
|
|
10
|
+
return <T>deserializeStaticArrayString(srcStart, srcEnd, dst);
|
|
11
|
+
} else if (isBoolean<valueof<T>>()) {
|
|
12
|
+
return deserializeStaticArrayBoolean<T>(srcStart, srcEnd, dst);
|
|
13
|
+
} else if (isInteger<valueof<T>>()) {
|
|
14
|
+
return deserializeStaticArrayInteger<T>(srcStart, srcEnd, dst);
|
|
15
|
+
} else if (isFloat<valueof<T>>()) {
|
|
16
|
+
return deserializeStaticArrayFloat<T>(srcStart, srcEnd, dst);
|
|
17
|
+
} else if (isArrayLike<valueof<T>>()) {
|
|
18
|
+
return deserializeStaticArrayArray<T>(srcStart, srcEnd, dst);
|
|
19
|
+
} else if (isManaged<valueof<T>>() || isReference<valueof<T>>()) {
|
|
20
|
+
const type = changetype<nonnull<valueof<T>>>(0);
|
|
21
|
+
if (isDefined(type.__DESERIALIZE)) {
|
|
22
|
+
return deserializeStaticArrayStruct<T>(srcStart, srcEnd, dst);
|
|
23
|
+
}
|
|
24
|
+
throw new Error("Could not parse static array of type " + nameof<T>() + "!");
|
|
25
|
+
} else {
|
|
26
|
+
throw new Error("Could not parse static array of type " + nameof<T>() + "!");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -30,7 +30,7 @@ import { hex4_to_u16_swar } from "../../util/swar";
|
|
|
30
30
|
// -\n- 2 -*-_ - 2
|
|
31
31
|
// --\n 4 --*_ - 2
|
|
32
32
|
// ---\n 6 ---* - 0
|
|
33
|
-
// Formula: overflow =
|
|
33
|
+
// Formula: overflow =
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Deserializes strings back into into their original form using SIMD operations
|
|
@@ -48,7 +48,8 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
48
48
|
while (srcStart < srcEnd8) {
|
|
49
49
|
const block = load<u64>(srcStart);
|
|
50
50
|
store<u64>(bs.offset, block);
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
let mask = inline.always(backslash_mask_unsafe(block));
|
|
52
53
|
|
|
53
54
|
// Early exit
|
|
54
55
|
if (mask === 0) {
|
|
@@ -138,7 +139,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
138
139
|
*
|
|
139
140
|
* Each matching lane sets itself to 0x80.
|
|
140
141
|
*/
|
|
141
|
-
// @ts-
|
|
142
|
+
// @ts-expect-error: @inline is a valid decorator
|
|
142
143
|
@inline function backslash_mask(block: u64): u64 {
|
|
143
144
|
const b = block ^ 0x005C_005C_005C_005C;
|
|
144
145
|
const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
|
|
@@ -153,11 +154,11 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
|
|
|
153
154
|
* is the ASCII backslash (`'\\'`, 0x5C).
|
|
154
155
|
*
|
|
155
156
|
* Each matching lane sets itself to 0x80.
|
|
156
|
-
*
|
|
157
|
+
*
|
|
157
158
|
* WARNING: The low byte of a code unit *may* be a backslash, thus triggering false positives!
|
|
158
159
|
* This is useful for a hot path where it is possible to detect the false positive scalarly.
|
|
159
160
|
*/
|
|
160
|
-
// @ts-
|
|
161
|
+
// @ts-expect-error: @inline is a valid decorator
|
|
161
162
|
@inline function backslash_mask_unsafe(block: u64): u64 {
|
|
162
163
|
const b = block ^ 0x005C_005C_005C_005C;
|
|
163
164
|
const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
|