json-as 0.9.29 → 1.0.0-alpha.2
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/.github/workflows/nodejs.yml +0 -3
- package/.gitmodules +0 -0
- package/.prettierrc.json +3 -2
- package/CHANGELOG +24 -0
- package/LICENSE +1 -1
- package/README.md +23 -7
- package/as-test.config.json +1 -1
- package/asconfig.json +2 -2
- package/assembly/__benches__/misc.bench.ts +0 -34
- package/assembly/__tests__/bool.spec.ts +1 -1
- package/assembly/__tests__/simd/string.spec.ts +32 -0
- package/assembly/custom/memory.ts +25 -0
- package/assembly/custom/util.ts +14 -92
- package/assembly/deserialize/simd/string.ts +103 -0
- package/assembly/deserialize/simple/arbitrary.ts +17 -0
- package/assembly/deserialize/simple/array/arbitrary.ts +113 -0
- package/assembly/deserialize/simple/array/array.ts +18 -0
- package/assembly/deserialize/simple/array/bool.ts +17 -0
- package/assembly/deserialize/simple/array/float.ts +28 -0
- package/assembly/deserialize/simple/array/integer.ts +27 -0
- package/assembly/deserialize/simple/array/map.ts +18 -0
- package/assembly/deserialize/simple/array/object.ts +18 -0
- package/assembly/deserialize/simple/array/string.ts +22 -0
- package/assembly/deserialize/simple/array.ts +48 -0
- package/assembly/deserialize/simple/bool.ts +9 -0
- package/assembly/deserialize/simple/date.ts +11 -0
- package/assembly/deserialize/simple/float.ts +10 -0
- package/assembly/deserialize/simple/integer.ts +5 -0
- package/assembly/deserialize/simple/map.ts +154 -0
- package/assembly/deserialize/simple/object.ts +158 -0
- package/assembly/deserialize/simple/string.ts +48 -0
- package/assembly/globals/tables.ts +417 -0
- package/assembly/index.d.ts +9 -13
- package/assembly/index.ts +261 -146
- package/assembly/serialize/simd/string.ts +176 -0
- package/assembly/serialize/simple/arbitrary.ts +36 -0
- package/assembly/serialize/simple/array.ts +32 -0
- package/assembly/serialize/simple/bool.ts +19 -0
- package/assembly/serialize/simple/date.ts +13 -0
- package/assembly/serialize/simple/float.ts +7 -0
- package/assembly/serialize/simple/integer.ts +7 -0
- package/assembly/serialize/simple/map.ts +43 -0
- package/assembly/serialize/simple/object.ts +7 -0
- package/assembly/serialize/simple/string.ts +48 -0
- package/assembly/test.ts +36 -27
- package/assembly/tsconfig.json +2 -91
- package/assembly/types.ts +0 -0
- package/assembly/util/atoi.ts +35 -0
- package/assembly/util/bytes.ts +12 -0
- package/assembly/util/concat.ts +9 -0
- package/assembly/util/getArrayDepth.ts +17 -0
- package/assembly/util/index.ts +5 -0
- package/assembly/util/isSpace.ts +4 -0
- package/assembly/util/nextPowerOf2.ts +4 -0
- package/assembly/util/ptrToStr.ts +7 -0
- package/assembly/util/snp.ts +69 -0
- package/bench.js +5 -5
- package/modules/as-bs/LICENSE +21 -0
- package/modules/as-bs/README.md +95 -0
- package/modules/as-bs/assembly/index.ts +166 -0
- package/modules/as-bs/assembly/tsconfig.json +97 -0
- package/modules/as-bs/index.ts +1 -0
- package/modules/as-bs/package.json +32 -0
- package/package.json +41 -48
- package/transform/lib/builder.js +1275 -0
- package/transform/lib/builder.js.map +1 -0
- package/transform/lib/index.js +548 -443
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/linker.js +16 -0
- package/transform/lib/linker.js.map +1 -0
- package/transform/lib/types.js +26 -0
- package/transform/lib/types.js.map +1 -0
- package/transform/lib/util.js +47 -0
- package/transform/lib/util.js.map +1 -0
- package/transform/lib/visitor.js +510 -430
- package/transform/lib/visitor.js.map +1 -0
- package/transform/package.json +1 -33
- package/transform/src/builder.ts +1371 -0
- package/transform/src/index.ts +574 -340
- package/transform/src/linker.ts +21 -0
- package/transform/src/types.ts +28 -0
- package/transform/src/util.ts +56 -0
- package/transform/src/visitor.ts +531 -0
- package/transform/tsconfig.json +3 -1
- package/assembly/__benches__/as-tral.d.ts +0 -1
- package/assembly/__tests__/date.spec.ts +0 -12
- package/assembly/custom/bs.ts +0 -202
- package/assembly/deserialize/array/array.ts +0 -31
- package/assembly/deserialize/array/bool.ts +0 -19
- package/assembly/deserialize/array/float.ts +0 -24
- package/assembly/deserialize/array/integer.ts +0 -24
- package/assembly/deserialize/array/map.ts +0 -27
- package/assembly/deserialize/array/object.ts +0 -27
- package/assembly/deserialize/array/string.ts +0 -29
- package/assembly/deserialize/array.ts +0 -46
- package/assembly/deserialize/bool.ts +0 -34
- package/assembly/deserialize/date.ts +0 -19
- package/assembly/deserialize/float.ts +0 -21
- package/assembly/deserialize/integer.ts +0 -16
- package/assembly/deserialize/map.ts +0 -139
- package/assembly/deserialize/object.ts +0 -211
- package/assembly/deserialize/string.ts +0 -149
- package/assembly/serialize/array.ts +0 -44
- package/assembly/serialize/bool.ts +0 -10
- package/assembly/serialize/date.ts +0 -4
- package/assembly/serialize/float.ts +0 -4
- package/assembly/serialize/integer.ts +0 -5
- package/assembly/serialize/map.ts +0 -24
- package/assembly/serialize/object.ts +0 -13
- package/assembly/serialize/string.ts +0 -284
package/.gitmodules
ADDED
|
File without changes
|
package/.prettierrc.json
CHANGED
package/CHANGELOG
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
## UNRELEASED
|
|
4
|
+
|
|
5
|
+
## 2025-01-20 - 1.0.0-alpha.2
|
|
6
|
+
|
|
7
|
+
- fix: disable SIMD in generated transform code by default
|
|
8
|
+
- fix: re-add as-bs dependency so that it will not break in non-local environments
|
|
9
|
+
- fix: remove AS201 'conversion from type usize to i32' warning
|
|
10
|
+
- fix: add as-bs to peer dependencies so only one version is installed
|
|
11
|
+
- fix: point as-bs imports to submodule
|
|
12
|
+
- fix: remove submodule in favor of static module
|
|
13
|
+
- fix: bs.ensureSize would not grow and thus cause memory faults
|
|
14
|
+
- fix: bs.ensureSize triggering unintentionally
|
|
15
|
+
|
|
16
|
+
## 2025-01-20 - 1.0.0-alpha.1
|
|
17
|
+
|
|
18
|
+
- feat: finish implementation of arbitrary data serialization and deserialization using JSON.Value
|
|
19
|
+
- feat: reinstate usage of `JSON.Box<T>()` to support nullable primitive types
|
|
20
|
+
- feat: eliminate the need to import the `JSON` namespace when defining a schema
|
|
21
|
+
- feat: reduce memory usage so that it is viable for low-memory environments
|
|
22
|
+
- feat: write to a central buffer and reduce memory overhead
|
|
23
|
+
- feat: rewrite the transform to properly resolve schemas and link them together
|
|
24
|
+
- feat: pre-allocate and compute the minimum size of a schema to avoid memory out of range errors
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2025 Jairus Tanaka <me@jairus.dev>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -6,29 +6,29 @@
|
|
|
6
6
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
7
7
|
█████ ███████ ██████ ██ ████ ██ ██ ███████
|
|
8
8
|
</span>
|
|
9
|
-
AssemblyScript -
|
|
9
|
+
AssemblyScript - v1.0.0-alpha.2
|
|
10
10
|
</pre>
|
|
11
11
|
</h5>
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm install json-as
|
|
16
|
+
npm install json-as@1.0.0-alpha.2
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Add the `--transform` to your `asc` command (e.g. in package.json)
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
--transform json-as
|
|
22
|
+
--transform json-as
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
Alternatively, add it to your `asconfig.json`
|
|
26
26
|
|
|
27
|
-
```
|
|
27
|
+
```
|
|
28
28
|
{
|
|
29
29
|
// ...
|
|
30
30
|
"options": {
|
|
31
|
-
"transform": ["json-as
|
|
31
|
+
"transform": ["json-as"]
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
```
|
|
@@ -38,7 +38,7 @@ If you'd like to see the code that the transform generates, run with `JSON_DEBUG
|
|
|
38
38
|
## Usage
|
|
39
39
|
|
|
40
40
|
```js
|
|
41
|
-
import { JSON } from "json-as
|
|
41
|
+
import { JSON } from "json-as";
|
|
42
42
|
|
|
43
43
|
// @json or @serializable work here
|
|
44
44
|
@json
|
|
@@ -55,7 +55,8 @@ class Player {
|
|
|
55
55
|
lastName!: string;
|
|
56
56
|
lastActive!: i32[];
|
|
57
57
|
// Drop in a code block, function, or expression that evaluates to a boolean
|
|
58
|
-
@omitif(
|
|
58
|
+
@omitif((age) => age < 18)
|
|
59
|
+
@omitif('this.age <= 0')
|
|
59
60
|
age!: i32;
|
|
60
61
|
@omitnull()
|
|
61
62
|
pos!: Vec3 | null;
|
|
@@ -110,8 +111,23 @@ const serialized = JSON.stringify(arr);
|
|
|
110
111
|
const parsed = JSON.parse<Base[]>(serialized);
|
|
111
112
|
```
|
|
112
113
|
|
|
114
|
+
You can also add it to your `asconfig.json`
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
// ...
|
|
119
|
+
"options": {
|
|
120
|
+
"transform": ["json-as/transform"]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
113
125
|
If you use this project in your codebase, consider dropping a [star](https://github.com/JairusSW/as-json). I would really appreciate it!
|
|
114
126
|
|
|
127
|
+
## Notes
|
|
128
|
+
|
|
129
|
+
If you want a feature, drop an issue (and again, maybe a star). I'll likely add it in less than 7 days.
|
|
130
|
+
|
|
115
131
|
## Contact
|
|
116
132
|
|
|
117
133
|
- [Email](mailto:me@jairus.dev)
|
package/as-test.config.json
CHANGED
package/asconfig.json
CHANGED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { JSON } from "..";
|
|
2
|
-
import { BRACE_LEFT, BRACKET_LEFT, CHAR_F, CHAR_T, QUOTE } from "../custom/chars";
|
|
3
|
-
|
|
4
|
-
bench("Match Type (string)", () => {
|
|
5
|
-
blackbox<boolean>(matchType(blackbox<string>('"'), JSON.Types.String));
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
bench("Match Type (bool)", () => {
|
|
9
|
-
blackbox<boolean>(matchType(blackbox<string>("t"), JSON.Types.Bool));
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
bench("Match Type (array)", () => {
|
|
13
|
-
blackbox<boolean>(matchType(blackbox<string>("["), JSON.Types.Array));
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
bench("Match Type (struct)", () => {
|
|
17
|
-
blackbox<boolean>(matchType(blackbox<string>("{"), JSON.Types.Obj));
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
bench("Match Type (raw)", () => {
|
|
21
|
-
blackbox<boolean>(matchType(blackbox<string>('"'), JSON.Types.Raw));
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@inline function matchType(data: string, type: JSON.Types): boolean {
|
|
26
|
-
const firstChar = load<u8>(changetype<usize>(data));
|
|
27
|
-
if (JSON.Types.String == type && firstChar == QUOTE) return true;
|
|
28
|
-
else if (JSON.Types.Bool == type && (firstChar == CHAR_T || firstChar == CHAR_F)) return true;
|
|
29
|
-
else if (JSON.Types.Array == type && firstChar == BRACKET_LEFT) return true;
|
|
30
|
-
else if (JSON.Types.Obj == type && firstChar == BRACE_LEFT) return true;
|
|
31
|
-
else if (type < 7 && type > 0 && firstChar < 58 && firstChar > 46) return true;
|
|
32
|
-
else if (JSON.Types.Raw == type) return true;
|
|
33
|
-
else return false;
|
|
34
|
-
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, run } from "as-test/assembly";
|
|
2
|
+
import { serializeString_SIMD } from "../../serialize/simd/string";
|
|
3
|
+
import { deserializeString_SIMD } from "../../deserialize/simd/string";
|
|
4
|
+
|
|
5
|
+
const out = changetype<usize>(new ArrayBuffer(512));
|
|
6
|
+
|
|
7
|
+
const serialize_simd = (data: string): string => String.UTF16.decodeUnsafe(out, serializeString_SIMD(data, out));
|
|
8
|
+
const deserialize_simd = (data: string): string => String.UTF16.decodeUnsafe(out, deserializeString_SIMD(data, out));
|
|
9
|
+
describe("Should serialize strings", () => {
|
|
10
|
+
expect(serialize_simd("abcdefg")).toBe('"abcdefg"');
|
|
11
|
+
|
|
12
|
+
expect(serialize_simd('st"ring" w""ith quotes"')).toBe('"st\\"ring\\" w\\"\\"ith quotes\\""');
|
|
13
|
+
|
|
14
|
+
expect(serialize_simd('string "with random spa\nces and \nnewlines\n\n\n')).toBe('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"');
|
|
15
|
+
|
|
16
|
+
expect(serialize_simd('string with colon : comma , brace [ ] bracket { } and quote " and other quote "')).toBe('"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\""');
|
|
17
|
+
|
|
18
|
+
expect(serialize_simd("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f")).toBe('"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u000f\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f"');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("Should deserialize strings", () => {
|
|
22
|
+
expect(deserialize_simd('"abcdefg"')).toBe("abcdefg");
|
|
23
|
+
expect(deserialize_simd('"st\\"ring\\" w\\"\\"ith quotes\\""')).toBe('st"ring" w""ith quotes"');
|
|
24
|
+
|
|
25
|
+
expect(deserialize_simd('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"')).toBe('string "with random spa\nces and \nnewlines\n\n\n');
|
|
26
|
+
|
|
27
|
+
expect(deserialize_simd('"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\""')).toBe('string with colon : comma , brace [ ] bracket { } and quote " and other quote "');
|
|
28
|
+
|
|
29
|
+
expect(deserialize_simd('"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u000f\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f"')).toBe("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
run();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BLOCK_MAXSIZE, OBJECT, TOTAL_OVERHEAD } from "rt/common";
|
|
2
|
+
import { E_INVALIDLENGTH } from "util/error";
|
|
3
|
+
|
|
4
|
+
// @ts-ignore: Decorator valid here
|
|
5
|
+
@inline export function ensureCapacity<T>(obj: T, newSize: usize): usize {
|
|
6
|
+
const ptr = changetype<usize>(obj);
|
|
7
|
+
const oldCapacity = changetype<OBJECT>(ptr - TOTAL_OVERHEAD).rtSize;
|
|
8
|
+
if (newSize > oldCapacity) {
|
|
9
|
+
if (newSize > BLOCK_MAXSIZE) throw new RangeError(E_INVALIDLENGTH);
|
|
10
|
+
const newCapacity = max(min(oldCapacity << 1, BLOCK_MAXSIZE), newSize);
|
|
11
|
+
const newObj = __renew(ptr, newCapacity);
|
|
12
|
+
return newObj;
|
|
13
|
+
}
|
|
14
|
+
return ptr;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// @ts-ignore: Decorator valid here
|
|
18
|
+
@inline export function setCapacity<T>(obj: T, oldCapacity: usize, newCapacity: usize): usize {
|
|
19
|
+
const ptr = changetype<usize>(obj);
|
|
20
|
+
if (newCapacity > oldCapacity) {
|
|
21
|
+
if (newCapacity > BLOCK_MAXSIZE) throw new RangeError(E_INVALIDLENGTH);
|
|
22
|
+
return __renew(ptr, newCapacity);
|
|
23
|
+
}
|
|
24
|
+
return ptr;
|
|
25
|
+
}
|
package/assembly/custom/util.ts
CHANGED
|
@@ -1,78 +1,6 @@
|
|
|
1
1
|
import { isSpace } from "util/string";
|
|
2
|
-
import { BACK_SLASH,
|
|
2
|
+
import { BACK_SLASH, QUOTE } from "./chars";
|
|
3
3
|
import { Sink } from "./sink";
|
|
4
|
-
import { JSON } from "..";
|
|
5
|
-
|
|
6
|
-
// @ts-ignore: Decorator
|
|
7
|
-
export function isMap<T>(): bool {
|
|
8
|
-
let type = changetype<T>(0);
|
|
9
|
-
return type instanceof Map;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// @ts-ignore: Decorator
|
|
13
|
-
@inline export function unsafeCharCodeAt(data: string, pos: i32): i32 {
|
|
14
|
-
return load<u16>(changetype<usize>(data) + ((<usize>pos) << 1));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// @ts-ignore: Decorator
|
|
18
|
-
@inline export function removeWhitespace(data: string): string {
|
|
19
|
-
const result = new Sink();
|
|
20
|
-
let instr = false;
|
|
21
|
-
for (let i = 0; i < data.length; i++) {
|
|
22
|
-
const char = unsafeCharCodeAt(data, i);
|
|
23
|
-
if (instr === false && char === QUOTE) instr = true;
|
|
24
|
-
else if (instr === true && char === QUOTE && unsafeCharCodeAt(data, i - 1) !== BACK_SLASH) instr = false;
|
|
25
|
-
|
|
26
|
-
if (instr === false) {
|
|
27
|
-
if (!isSpace(char)) result.write(data.charAt(i));
|
|
28
|
-
} else {
|
|
29
|
-
result.write(data.charAt(i));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return result.toString();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// @ts-ignore: Decorator
|
|
36
|
-
@inline export function escapeChar(char: string): string {
|
|
37
|
-
switch (unsafeCharCodeAt(char, 0)) {
|
|
38
|
-
case 0x22:
|
|
39
|
-
return '\\"';
|
|
40
|
-
case 0x5c:
|
|
41
|
-
return "\\\\";
|
|
42
|
-
case 0x08:
|
|
43
|
-
return "\\b";
|
|
44
|
-
case 0x0a:
|
|
45
|
-
return "\\n";
|
|
46
|
-
case 0x0d:
|
|
47
|
-
return "\\r";
|
|
48
|
-
case 0x09:
|
|
49
|
-
return "\\t";
|
|
50
|
-
case 0x0c:
|
|
51
|
-
return "\\f";
|
|
52
|
-
case 0x0b:
|
|
53
|
-
return "\\u000b";
|
|
54
|
-
default:
|
|
55
|
-
return char;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* A terrible function which finds the depth of a certain array.
|
|
61
|
-
* Suffers no overhead besides function calling and a if/else.
|
|
62
|
-
* @returns depth of array
|
|
63
|
-
*/
|
|
64
|
-
|
|
65
|
-
// @ts-ignore: Decorator
|
|
66
|
-
export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
67
|
-
if (!isArray<T>()) {
|
|
68
|
-
return 0;
|
|
69
|
-
} else if (isArray<valueof<T>>()) {
|
|
70
|
-
depth++;
|
|
71
|
-
return getArrayDepth<valueof<T>>(depth);
|
|
72
|
-
} else {
|
|
73
|
-
return depth;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
4
|
|
|
77
5
|
/** Scientific Notation Integer Parsing - SNIP
|
|
78
6
|
* This is absolutely the fastest algorithm I could think of while adding full support for Scientific Notation
|
|
@@ -94,8 +22,8 @@ export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
|
94
22
|
@inline export function snip_fast<T extends number>(str: string, len: u32 = 0, offset: u32 = 0): T {
|
|
95
23
|
if (isSigned<T>()) {
|
|
96
24
|
const firstChar: u32 = load<u16>(changetype<usize>(str));
|
|
97
|
-
if (firstChar
|
|
98
|
-
const isNegative = firstChar
|
|
25
|
+
if (firstChar == 48) return 0 as T;
|
|
26
|
+
const isNegative = firstChar == 45; // Check if the number is negative
|
|
99
27
|
let val: T = 0 as T;
|
|
100
28
|
if (len == 0) len = u32(str.length << 1);
|
|
101
29
|
if (isNegative) {
|
|
@@ -199,7 +127,7 @@ export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
|
199
127
|
}
|
|
200
128
|
} else {
|
|
201
129
|
const firstChar: u32 = load<u16>(changetype<usize>(str));
|
|
202
|
-
if (firstChar
|
|
130
|
+
if (firstChar == 48) return 0 as T;
|
|
203
131
|
let val: T = 0 as T;
|
|
204
132
|
if (len == 0) len = u32(str.length << 1);
|
|
205
133
|
if (len >= 4) {
|
|
@@ -262,7 +190,7 @@ export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
|
262
190
|
if (!end) end = start + u32(str.length << 1);
|
|
263
191
|
if (isSigned<T>()) {
|
|
264
192
|
// Negative path
|
|
265
|
-
if (load<u16>(changetype<usize>(str) + <usize>start)
|
|
193
|
+
if (load<u16>(changetype<usize>(str) + <usize>start) == 45) {
|
|
266
194
|
start += 2;
|
|
267
195
|
for (; start < end; start += 2) {
|
|
268
196
|
val = (val * 10 + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
@@ -296,14 +224,14 @@ export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
|
296
224
|
let val: T = 0;
|
|
297
225
|
let offset = 0;
|
|
298
226
|
let firstChar = load<u16>(changetype<usize>(str) + <usize>offset);
|
|
299
|
-
if (firstChar
|
|
227
|
+
if (firstChar == 45) {
|
|
300
228
|
offset = 2;
|
|
301
229
|
}
|
|
302
230
|
for (; offset < str.length << 1; offset += 2) {
|
|
303
231
|
const char = load<u16>(changetype<usize>(str) + <usize>offset);
|
|
304
|
-
if (char
|
|
232
|
+
if (char == 101 || char == 69) {
|
|
305
233
|
const char = load<u16>(changetype<usize>(str) + <usize>(offset += 2));
|
|
306
|
-
if (char
|
|
234
|
+
if (char == 45) {
|
|
307
235
|
// @ts-ignore
|
|
308
236
|
val /= sciNote<T>(__atoi_fast<T>(str, (offset += 2)));
|
|
309
237
|
// @ts-ignore
|
|
@@ -319,7 +247,7 @@ export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
|
319
247
|
val = (val << 1) + (val << 3) + (char - 48);
|
|
320
248
|
// We use load because in this case, there is no need to have bounds-checking
|
|
321
249
|
}
|
|
322
|
-
if (firstChar
|
|
250
|
+
if (firstChar == 45) {
|
|
323
251
|
val = -val as T;
|
|
324
252
|
}
|
|
325
253
|
return val;
|
|
@@ -342,17 +270,6 @@ export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
|
342
270
|
return res;
|
|
343
271
|
}
|
|
344
272
|
|
|
345
|
-
// @ts-ignore
|
|
346
|
-
@inline function equalsSlice(p1_data: string, p1_start: i32, p1_end: i32, p2_data: string, p2_start: i32, p2_end: i32): boolean {
|
|
347
|
-
const p1_len = p1_end - p1_start;
|
|
348
|
-
const p2_len = p2_end - p2_start;
|
|
349
|
-
if (p1_len != p2_len) return false;
|
|
350
|
-
if (p1_len == 2) {
|
|
351
|
-
return load<u16>(changetype<usize>(p1_data) + p1_start) == load<u16>(changetype<usize>(p2_data) + p2_start);
|
|
352
|
-
}
|
|
353
|
-
return memory.compare(changetype<usize>(p1_data) + p1_start, changetype<usize>(p2_data) + p2_start, p1_len) === 0;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
273
|
// @ts-ignore
|
|
357
274
|
@inline export function containsCodePoint(str: string, code: u32, start: i32, end: i32): bool {
|
|
358
275
|
for (let i = start; i <= end; i++) {
|
|
@@ -390,3 +307,8 @@ export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
|
390
307
|
}
|
|
391
308
|
}
|
|
392
309
|
}
|
|
310
|
+
|
|
311
|
+
// @ts-ignore: Decorator valid here
|
|
312
|
+
@inline export function nextPowerOf2(n: u32): u32 {
|
|
313
|
+
return 1 << (32 - clz(n - 1));
|
|
314
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { BACK_SLASH } from "../../custom/chars";
|
|
2
|
+
import { DESERIALIZE_ESCAPE_TABLE, ESCAPE_HEX_TABLE } from "../../globals/tables";
|
|
3
|
+
|
|
4
|
+
const SPLAT_92 = i16x8.splat(92); /* \ */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Deserializes strings back into into their original form using SIMD operations
|
|
8
|
+
* @param src string to deserialize
|
|
9
|
+
* @param dst buffer to write to
|
|
10
|
+
* @returns number of bytes written
|
|
11
|
+
*/
|
|
12
|
+
// todo: optimize and stuff. it works, its not pretty. ideally, i'd like this to be (nearly) branchless
|
|
13
|
+
export function deserializeString_SIMD(src: string, srcStart: usize, srcEnd: usize, dst: usize): usize {
|
|
14
|
+
let src_ptr = srcStart + 2;
|
|
15
|
+
let dst_ptr = changetype<usize>(dst);
|
|
16
|
+
|
|
17
|
+
const src_end = srcEnd - 2;
|
|
18
|
+
const src_end_15 = src_end - 15;
|
|
19
|
+
|
|
20
|
+
while (src_ptr < src_end_15) {
|
|
21
|
+
const block = v128.load(src_ptr);
|
|
22
|
+
v128.store(dst_ptr, block);
|
|
23
|
+
|
|
24
|
+
const backslash_indices = i16x8.eq(block, SPLAT_92);
|
|
25
|
+
let mask = i16x8.bitmask(backslash_indices);
|
|
26
|
+
|
|
27
|
+
while (mask != 0) {
|
|
28
|
+
const lane_index = ctz(mask) << 1;
|
|
29
|
+
const dst_offset = dst_ptr + lane_index;
|
|
30
|
+
const src_offset = src_ptr + lane_index;
|
|
31
|
+
const code = load<u16>(src_offset, 2);
|
|
32
|
+
|
|
33
|
+
mask &= mask - 1;
|
|
34
|
+
if (code == 117 && load<u32>(src_offset, 4) == 3145776) {
|
|
35
|
+
const block = load<u32>(src_offset, 8);
|
|
36
|
+
const codeA = block & 0xffff;
|
|
37
|
+
const codeB = (block >> 16) & 0xffff;
|
|
38
|
+
const escapedA = load<u8>(ESCAPE_HEX_TABLE + codeA);
|
|
39
|
+
const escapedB = load<u8>(ESCAPE_HEX_TABLE + codeB);
|
|
40
|
+
const escaped = (escapedA << 4) + escapedB;
|
|
41
|
+
// console.log("Escaped:");
|
|
42
|
+
// console.log(" a: " + escapedA.toString())
|
|
43
|
+
// console.log(" b: " + escapedB.toString());
|
|
44
|
+
// console.log(" c: " + escaped.toString());
|
|
45
|
+
// console.log(" o: " + (dst_ptr - dst).toString());
|
|
46
|
+
// console.log(" d: " + (dst_offset - dst).toString())
|
|
47
|
+
// console.log(" l: " + (lane_index).toString())
|
|
48
|
+
store<u16>(dst_offset, escaped);
|
|
49
|
+
v128.store(dst_offset, v128.load(src_offset, 4), 2);
|
|
50
|
+
if (lane_index >= 6) {
|
|
51
|
+
const bytes_left = lane_index - 4;
|
|
52
|
+
src_ptr += bytes_left;
|
|
53
|
+
dst_ptr += bytes_left;
|
|
54
|
+
// console.log(" e: " + (bytes_left).toString())
|
|
55
|
+
}
|
|
56
|
+
dst_ptr -= 10;
|
|
57
|
+
} else {
|
|
58
|
+
const escaped = load<u8>(DESERIALIZE_ESCAPE_TABLE + code);
|
|
59
|
+
store<u16>(dst_offset, escaped);
|
|
60
|
+
v128.store(dst_offset, v128.load(src_offset, 4), 2);
|
|
61
|
+
// console.log("Escaped:");
|
|
62
|
+
if (lane_index == 14) {
|
|
63
|
+
src_ptr += 2;
|
|
64
|
+
} else {
|
|
65
|
+
dst_ptr -= 2;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
src_ptr += 16;
|
|
71
|
+
dst_ptr += 16;
|
|
72
|
+
|
|
73
|
+
// console.log("src: " + (src_ptr - changetype<usize>(src)).toString());
|
|
74
|
+
// console.log("dst: " + (dst_ptr - dst).toString());
|
|
75
|
+
}
|
|
76
|
+
while (src_ptr < src_end) {
|
|
77
|
+
let code = load<u16>(src_ptr);
|
|
78
|
+
if (code == BACK_SLASH) {
|
|
79
|
+
code = load<u16>(DESERIALIZE_ESCAPE_TABLE + load<u8>(src_ptr, 2));
|
|
80
|
+
if (code == 117 && load<u32>(src_ptr, 4) == 3145776) {
|
|
81
|
+
const block = load<u32>(src_ptr, 8);
|
|
82
|
+
const codeA = block & 0xffff;
|
|
83
|
+
const codeB = (block >> 16) & 0xffff;
|
|
84
|
+
const escapedA = load<u8>(ESCAPE_HEX_TABLE + codeA);
|
|
85
|
+
const escapedB = load<u8>(ESCAPE_HEX_TABLE + codeB);
|
|
86
|
+
const escaped = (escapedA << 4) + escapedB;
|
|
87
|
+
store<u16>(dst_ptr, escaped);
|
|
88
|
+
dst_ptr += 2;
|
|
89
|
+
src_ptr += 12;
|
|
90
|
+
} else {
|
|
91
|
+
store<u16>(dst_ptr, code);
|
|
92
|
+
dst_ptr += 2;
|
|
93
|
+
src_ptr += 4;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
store<u16>(dst_ptr, code);
|
|
97
|
+
dst_ptr += 2;
|
|
98
|
+
src_ptr += 2;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return dst_ptr - dst;
|
|
103
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { JSON } from "../..";
|
|
2
|
+
import { deserializeArray } from "./array";
|
|
3
|
+
import { deserializeBoolean } from "./bool";
|
|
4
|
+
import { deserializeFloat } from "./float";
|
|
5
|
+
import { deserializeObject } from "./object";
|
|
6
|
+
import { deserializeString } from "./string";
|
|
7
|
+
|
|
8
|
+
export function deserializeArbitrary(srcStart: usize, srcEnd: usize, dst: usize): JSON.Value {
|
|
9
|
+
const firstChar = load<u16>(srcStart);
|
|
10
|
+
if (firstChar == 34) return JSON.Value.from(deserializeString(srcStart, srcEnd, dst));
|
|
11
|
+
else if (firstChar == 123) return JSON.Value.from(deserializeObject(srcStart, srcEnd, dst));
|
|
12
|
+
else if (firstChar - 48 <= 9 || firstChar == 45) return JSON.Value.from(deserializeFloat<f64>(srcStart, srcEnd));
|
|
13
|
+
else if (firstChar == 91) {
|
|
14
|
+
return JSON.Value.from(deserializeArray<JSON.Value[]>(srcStart, srcEnd, dst));
|
|
15
|
+
} else if (firstChar == 116 || firstChar == 102) return JSON.Value.from(deserializeBoolean(srcStart, srcEnd));
|
|
16
|
+
return unreachable();
|
|
17
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { BACK_SLASH, BRACE_LEFT, BRACE_RIGHT, BRACKET_LEFT, BRACKET_RIGHT, CHAR_F, CHAR_N, CHAR_T, COMMA, QUOTE } from "../../../custom/chars";
|
|
2
|
+
import { JSON } from "../../../";
|
|
3
|
+
import { isSpace } from "util/string";
|
|
4
|
+
|
|
5
|
+
export function deserializeArbitraryArray<T extends JSON.Value>(srcStart: usize, srcEnd: usize, dst: usize): JSON.Value[] {
|
|
6
|
+
const out = dst ? changetype<T>(dst) : instantiate<T>();
|
|
7
|
+
let lastIndex: usize = 0;
|
|
8
|
+
let depth: u32 = 0;
|
|
9
|
+
while (srcStart < srcEnd) {
|
|
10
|
+
const code = load<u16>(srcStart);
|
|
11
|
+
if (code == QUOTE) {
|
|
12
|
+
lastIndex = srcStart;
|
|
13
|
+
srcStart += 2;
|
|
14
|
+
while (srcStart < srcEnd) {
|
|
15
|
+
const code = load<u16>(srcStart);
|
|
16
|
+
if (code == QUOTE && load<u16>(srcStart - 2) !== BACK_SLASH) {
|
|
17
|
+
while (isSpace(load<u16>((srcStart += 2)))) {
|
|
18
|
+
/* empty */
|
|
19
|
+
}
|
|
20
|
+
// console.log("Value (string): " + ptrToStr(lastIndex, srcStart));
|
|
21
|
+
// @ts-ignore: exists
|
|
22
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
srcStart += 2;
|
|
26
|
+
}
|
|
27
|
+
} else if (code - 48 <= 9 || code == 45) {
|
|
28
|
+
lastIndex = srcStart;
|
|
29
|
+
srcStart += 2;
|
|
30
|
+
while (srcStart < srcEnd) {
|
|
31
|
+
const code = load<u16>(srcStart);
|
|
32
|
+
if (code == COMMA || code == BRACE_RIGHT || isSpace(code)) {
|
|
33
|
+
// @ts-ignore: type
|
|
34
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
|
|
35
|
+
// console.log("Value (number): " + ptrToStr(lastIndex, srcStart));
|
|
36
|
+
while (isSpace(load<u16>((srcStart += 2)))) {
|
|
37
|
+
/* empty */
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
srcStart += 2;
|
|
42
|
+
}
|
|
43
|
+
} else if (code == BRACE_LEFT) {
|
|
44
|
+
lastIndex = srcStart;
|
|
45
|
+
depth++;
|
|
46
|
+
srcStart += 2;
|
|
47
|
+
while (srcStart < srcEnd) {
|
|
48
|
+
const code = load<u16>(srcStart);
|
|
49
|
+
if (code == BRACE_RIGHT) {
|
|
50
|
+
if (--depth == 0) {
|
|
51
|
+
// @ts-ignore: type
|
|
52
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
|
|
53
|
+
// console.log("Value (object): " + ptrToStr(lastIndex, srcStart));
|
|
54
|
+
while (isSpace(load<u16>((srcStart += 2)))) {
|
|
55
|
+
/* empty */
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
} else if (code == BRACE_LEFT) depth++;
|
|
60
|
+
srcStart += 2;
|
|
61
|
+
}
|
|
62
|
+
} else if (code == BRACKET_LEFT) {
|
|
63
|
+
lastIndex = srcStart;
|
|
64
|
+
depth++;
|
|
65
|
+
srcStart += 2;
|
|
66
|
+
while (srcStart < srcEnd) {
|
|
67
|
+
const code = load<u16>(srcStart);
|
|
68
|
+
if (code == BRACKET_RIGHT) {
|
|
69
|
+
if (--depth == 0) {
|
|
70
|
+
// @ts-ignore: type
|
|
71
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
|
|
72
|
+
// console.log("Value (array): " + ptrToStr(lastIndex, srcStart));
|
|
73
|
+
while (isSpace(load<u16>((srcStart += 2)))) {
|
|
74
|
+
/* empty */
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
} else if (code == BRACKET_LEFT) depth++;
|
|
79
|
+
srcStart += 2;
|
|
80
|
+
}
|
|
81
|
+
} else if (code == CHAR_T) {
|
|
82
|
+
if (load<u64>(srcStart) == 28429475166421108) {
|
|
83
|
+
// @ts-ignore: type
|
|
84
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, (srcStart += 8)));
|
|
85
|
+
// console.log("Value (bool): " + ptrToStr(srcStart - 8, srcStart));
|
|
86
|
+
while (isSpace(load<u16>((srcStart += 2)))) {
|
|
87
|
+
/* empty */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} else if (code == CHAR_F) {
|
|
91
|
+
if (load<u64>(srcStart, 2) == 28429466576093281) {
|
|
92
|
+
// @ts-ignore: type
|
|
93
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, (srcStart += 10)));
|
|
94
|
+
// console.log("Value (bool): " + ptrToStr(srcStart - 10, srcStart));
|
|
95
|
+
while (isSpace(load<u16>((srcStart += 2)))) {
|
|
96
|
+
/* empty */
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} else if (code == CHAR_N) {
|
|
100
|
+
if (load<u64>(srcStart) == 30399761348886638) {
|
|
101
|
+
// @ts-ignore: type
|
|
102
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, (srcStart += 8)));
|
|
103
|
+
// console.log("Value (null): " + ptrToStr(srcStart - 8, srcStart));
|
|
104
|
+
while (isSpace(load<u16>((srcStart += 2)))) {
|
|
105
|
+
/* empty */
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
srcStart += 2;
|
|
110
|
+
}
|
|
111
|
+
// @ts-ignore: type
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BRACKET_LEFT, BRACKET_RIGHT } from "../../../custom/chars";
|
|
2
|
+
import { JSON } from "../../../";
|
|
3
|
+
|
|
4
|
+
export function deserializeArrayArray<T extends unknown[][]>(srcStart: usize, srcEnd: usize, dst: usize): T {
|
|
5
|
+
const out = dst ? changetype<T>(dst) : instantiate<T>();
|
|
6
|
+
let lastIndex: usize = 0;
|
|
7
|
+
let depth: u32 = 0;
|
|
8
|
+
while (srcStart < srcEnd) {
|
|
9
|
+
const code = load<u16>(srcStart);
|
|
10
|
+
if (code == BRACKET_LEFT && depth++ == 0) {
|
|
11
|
+
lastIndex = srcStart;
|
|
12
|
+
} else if (code == BRACKET_RIGHT && --depth == 0) {
|
|
13
|
+
out.push(JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
|
|
14
|
+
}
|
|
15
|
+
srcStart += 2;
|
|
16
|
+
}
|
|
17
|
+
return out;
|
|
18
|
+
}
|