json-as 1.1.25 → 1.1.27

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.
Files changed (52) hide show
  1. package/.github/workflows/benchmark.yml +64 -0
  2. package/.prettierrc.json +1 -0
  3. package/CHANGELOG.md +4 -0
  4. package/README.md +40 -63
  5. package/assembly/__benches__/abc.bench.ts +5 -9
  6. package/assembly/__benches__/large.bench.ts +114 -120
  7. package/assembly/__benches__/lib/bench.ts +44 -1
  8. package/assembly/__benches__/medium.bench.ts +108 -29
  9. package/assembly/__benches__/small.bench.ts +28 -18
  10. package/assembly/__benches__/throughput.ts +172 -0
  11. package/assembly/__benches__/vec3.bench.ts +8 -3
  12. package/assembly/__tests__/string.spec.ts +4 -0
  13. package/assembly/deserialize/simple/arbitrary.ts +5 -2
  14. package/assembly/deserialize/simple/object.ts +3 -1
  15. package/assembly/deserialize/swar/string.ts +128 -0
  16. package/assembly/index.ts +6 -2
  17. package/assembly/serialize/swar/number.ts +0 -0
  18. package/assembly/serialize/swar/string.ts +72 -70
  19. package/assembly/test.tmp.ts +5 -9
  20. package/assembly/test.ts +3 -6
  21. package/bench/abc.bench.ts +6 -8
  22. package/bench/large.bench.ts +119 -118
  23. package/bench/lib/bench.d.ts +27 -0
  24. package/bench/lib/bench.js +53 -0
  25. package/bench/lib/chart.ts +217 -0
  26. package/bench/medium.bench.ts +55 -30
  27. package/bench/runners/assemblyscript.js +6 -1
  28. package/bench/small.bench.ts +7 -3
  29. package/bench/throughput.ts +87 -0
  30. package/bench/tsconfig.json +3 -2
  31. package/bench/vec3.bench.ts +7 -3
  32. package/ci/bench/runners/assemblyscript.js +29 -0
  33. package/ci/run-bench.as.sh +63 -0
  34. package/data/chart01.svg +258 -0
  35. package/data/chart02.svg +246 -0
  36. package/data/chart03.svg +193 -0
  37. package/data/chart05.svg +142 -0
  38. package/dump.txt +41590 -0
  39. package/package.json +4 -2
  40. package/run-bench.as.sh +21 -13
  41. package/run-bench.js.sh +9 -7
  42. package/run-tests.sh +34 -14
  43. package/scripts/build-chart01.ts +38 -0
  44. package/scripts/build-chart02.ts +38 -0
  45. package/scripts/build-chart03.ts +139 -0
  46. package/scripts/build-chart05.ts +47 -0
  47. package/scripts/generate-as-class.ts +50 -0
  48. package/scripts/lib/bench-utils.ts +308 -0
  49. package/transform/lib/index.js +2 -2
  50. package/transform/lib/index.js.map +1 -1
  51. package/transform/src/index.ts +2 -2
  52. /package/{bench → ci/bench}/lib/bench.ts +0 -0
@@ -0,0 +1,128 @@
1
+ import { bs } from "../../../lib/as-bs";
2
+ import { BACK_SLASH } from "../../custom/chars";
3
+ import { DESERIALIZE_ESCAPE_TABLE, ESCAPE_HEX_TABLE } from "../../globals/tables";
4
+
5
+ // @ts-ignore: decorator allowed
6
+ @lazy const LANE_MASK_HIGH = 0xFF00_FF00_FF00_FF00;
7
+ // @ts-ignore: decorator allowed
8
+ @lazy const LANE_MASK_LOW = 0x00FF_00FF_00FF_00FF;
9
+ // @ts-ignore: decorator allowed
10
+ @lazy const UINT64_H8 = 0x8080808080808080;
11
+ // @ts-ignore: decorator allowed
12
+ @lazy const QUOTE_MASK = 0x0022_0022_0022_0022;
13
+ // @ts-ignore: decorator allowed
14
+ @lazy const BACKSLASH_MASK = 0x005C_005C_005C_005C;
15
+ // @ts-ignore: decorator allowed
16
+ @lazy const CONTROL_MASK = 0x0020_0020_0020_0020;
17
+ // @ts-ignore: decorator allowed
18
+ @lazy const U00_MARKER = 13511005048209500;
19
+
20
+ /**
21
+ * Deserializes strings back into into their original form using SIMD operations
22
+ * @param src string to deserialize
23
+ * @param dst buffer to write to
24
+ * @returns number of bytes written
25
+ */
26
+ // todo: optimize and stuff. it works, its not pretty. ideally, i'd like this to be (nearly) branchless
27
+ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): void {
28
+ srcStart += 2;
29
+ srcEnd -= 2;
30
+ bs.proposeSize(u32(srcEnd - srcStart));
31
+
32
+ // const src_end_15 = srcEnd - 15;
33
+ // while (srcStart < src_end_15) {
34
+ // const block = load<u64>(srcStart);
35
+ // store<u64>(dst_ptr, block);
36
+
37
+ // let mask = v64x4_eq(block, BACKSLASH_MASK);
38
+
39
+ // while (mask != 0) {
40
+ // const lane_index = usize(ctz(mask) >> 3);
41
+ // const dst_offset = dst_ptr + lane_index;
42
+ // const src_offset = srcStart + lane_index;
43
+ // const code = load<u16>(src_offset, 2);
44
+
45
+ // mask &= mask - 1;
46
+ // if (code == 117 && load<u32>(src_offset, 4) == 3145776) {
47
+ // const block = load<u32>(src_offset, 8);
48
+ // const codeA = block & 0xffff;
49
+ // const codeB = (block >> 16) & 0xffff;
50
+ // const escapedA = load<u8>(ESCAPE_HEX_TABLE + codeA);
51
+ // const escapedB = load<u8>(ESCAPE_HEX_TABLE + codeB);
52
+ // const escaped = (escapedA << 4) + escapedB;
53
+ // // console.log("Escaped:");
54
+ // // console.log(" a: " + escapedA.toString())
55
+ // // console.log(" b: " + escapedB.toString());
56
+ // // console.log(" c: " + escaped.toString());
57
+ // // console.log(" o: " + (dst_ptr - dst).toString());
58
+ // // console.log(" d: " + (dst_offset - dst).toString())
59
+ // // console.log(" l: " + (lane_index).toString())
60
+ // store<u16>(dst_offset, escaped);
61
+ // memory.copy(dst_offset + 2, src_offset + 4, (4 - lane_index) << 1);
62
+ // // v128.store(dst_offset, v128.load(src_offset, 4), 2);
63
+ // if (lane_index >= 6) {
64
+ // const bytes_left = lane_index - 4;
65
+ // srcStart += bytes_left;
66
+ // dst_ptr += bytes_left;
67
+ // // console.log(" e: " + (bytes_left).toString())
68
+ // }
69
+ // dst_ptr -= 10;
70
+ // } else {
71
+ // const escaped = load<u8>(DESERIALIZE_ESCAPE_TABLE + code);
72
+ // store<u16>(dst_offset, escaped);
73
+ // memory.copy(dst_offset + 2, src_offset + 4, (4 - lane_index) << 1);
74
+ // // v128.store(dst_offset, v128.load(src_offset, 4), 2);
75
+ // // console.log("Escaped:");
76
+ // if (lane_index == 14) {
77
+ // srcStart += 2;
78
+ // } else {
79
+ // dst_ptr -= 2;
80
+ // }
81
+ // }
82
+ // }
83
+
84
+ // srcStart += 16;
85
+ // dst_ptr += 16;
86
+
87
+ // // console.log("src: " + (srcStart - changetype<usize>(src)).toString());
88
+ // // console.log("dst: " + (dst_ptr - dst).toString());
89
+ // }
90
+ while (srcStart < srcEnd) {
91
+ let code = load<u16>(srcStart);
92
+ if (code == BACK_SLASH) {
93
+ code = load<u16>(DESERIALIZE_ESCAPE_TABLE + load<u8>(srcStart, 2));
94
+ if (code == 117 && load<u32>(srcStart, 4) == 3145776) {
95
+ const block = load<u32>(srcStart, 8);
96
+ const codeA = block & 0xffff;
97
+ const codeB = (block >> 16) & 0xffff;
98
+ const escapedA = load<u8>(ESCAPE_HEX_TABLE + codeA);
99
+ const escapedB = load<u8>(ESCAPE_HEX_TABLE + codeB);
100
+ const escaped = (escapedA << 4) + escapedB;
101
+ store<u16>(bs.offset, escaped);
102
+ bs.offset += 2;
103
+ srcStart += 12;
104
+ } else {
105
+ store<u16>(bs.offset, code);
106
+ bs.offset += 2;
107
+ srcStart += 4;
108
+ }
109
+ } else {
110
+ store<u16>(bs.offset, code);
111
+ bs.offset += 2;
112
+ srcStart += 2;
113
+ }
114
+ }
115
+ }
116
+
117
+ // @ts-ignore: decorators allowed
118
+ @inline function v64x4_eq(x: u64, y: u64): u64 {
119
+ const xored = (x ^ LANE_MASK_HIGH) ^ y;
120
+ const mask = (((xored >> 1) | UINT64_H8) - xored) & UINT64_H8;
121
+ return (mask << 1) - (mask >> 7);
122
+ }
123
+
124
+ // @ts-ignore: decorators allowed
125
+ @inline function v64x4_ltu(a: u64, b: u64): u64 {
126
+ // Vigna's algorithm - fastest SWAR unsigned less-than
127
+ return (((a | UINT64_H8) - (b & ~UINT64_H8)) | (a ^ b)) ^ (a | ~b);
128
+ }
package/assembly/index.ts CHANGED
@@ -11,7 +11,7 @@ import { deserializeFloat } from "./deserialize/simple/float";
11
11
  import { deserializeMap } from "./deserialize/simple/map";
12
12
  import { deserializeDate } from "./deserialize/simple/date";
13
13
  import { deserializeInteger } from "./deserialize/simple/integer";
14
- import { deserializeString } from "./deserialize/simple/string";
14
+ // import { deserializeString } from "./deserialize/simple/string";
15
15
  import { serializeArbitrary } from "./serialize/simple/arbitrary";
16
16
 
17
17
  import { NULL_WORD, QUOTE } from "./custom/chars";
@@ -29,6 +29,8 @@ import { serializeRaw } from "./serialize/simple/raw";
29
29
  import { deserializeRaw } from "./deserialize/simple/raw";
30
30
  import { serializeString_SIMD } from "./serialize/simd/string";
31
31
  import { serializeString_SWAR } from "./serialize/swar/string";
32
+ import { deserializeString_SWAR } from "./deserialize/swar/string";
33
+ import { deserializeString } from "./deserialize/simple/string";
32
34
  // import { deserializeString_SIMD } from "./deserialize/simd/string";
33
35
 
34
36
  /**
@@ -185,8 +187,9 @@ export namespace JSON {
185
187
  // // @ts-ignore
186
188
  // return changetype<string>(deserializeString_SIMD(dataPtr, dataPtr + dataSize, __new(dataSize - 4, idof<string>())));
187
189
  // } else {
190
+
188
191
  // @ts-ignore
189
- return deserializeString(dataPtr, dataPtr + dataSize, __new(dataSize - 4, idof<string>()));
192
+ return deserializeString(dataPtr, dataPtr + dataSize, 0);
190
193
  // }
191
194
  } else if (isArray<T>()) {
192
195
  // @ts-ignore
@@ -605,6 +608,7 @@ export namespace JSON {
605
608
  return deserializeFloat<T>(srcStart, srcEnd);
606
609
  } else if (isString<T>()) {
607
610
  if (srcEnd - srcStart < 4) throw new Error("Cannot parse data as string because it was formatted incorrectly!");
611
+
608
612
  // @ts-ignore: type
609
613
  return deserializeString(srcStart, srcEnd, dst);
610
614
  } else if (isNullable<T>() && srcEnd - srcStart == 8 && load<u64>(srcStart) == 30399761348886638) {
File without changes
@@ -2,14 +2,17 @@ import { bs } from "../../../lib/as-bs";
2
2
  import { BACK_SLASH } from "../../custom/chars";
3
3
  import { SERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
4
4
  import { bytes } from "../../util/bytes";
5
+ import { serializeString } from "../simple/string";
5
6
 
6
7
 
7
8
  // @ts-ignore: decorator allowed
8
9
  @lazy const LANE_MASK_HIGH = 0xFF00_FF00_FF00_FF00;
9
10
  // @ts-ignore: decorator allowed
11
+ @lazy const ONES: u64 = 0x0101010101010101;
12
+ // @ts-ignore: decorator allowed
10
13
  @lazy const LANE_MASK_LOW = 0x00FF_00FF_00FF_00FF;
11
14
  // @ts-ignore: decorator allowed
12
- @lazy const UINT64_H8 = 0x8080808080808080;
15
+ @lazy const HIGHS = 0x8080808080808080;
13
16
  // @ts-ignore: decorator allowed
14
17
  @lazy const QUOTE_MASK = 0x0022_0022_0022_0022;
15
18
  // @ts-ignore: decorator allowed
@@ -19,91 +22,90 @@ import { bytes } from "../../util/bytes";
19
22
  // @ts-ignore: decorator allowed
20
23
  @lazy const U00_MARKER = 13511005048209500;
21
24
 
22
- export function serializeString_SWAR(src: string): void {
23
- const srcSize = bytes(src);
24
- let srcStart = changetype<usize>(src);
25
- const srcEnd = srcStart + srcSize;
26
- const srcEnd8 = srcEnd - 8;
25
+ // @ts-ignore: decorator valid here
26
+ @inline export function serializeString_SWAR(src: string): void {
27
+ serializeString(src);
28
+
29
+ // const srcSize = bytes(src);
30
+ // let srcStart = changetype<usize>(src);
31
+ // const srcEnd = srcStart + srcSize;
32
+ // const srcEnd8 = srcEnd - 8;
27
33
 
28
- bs.proposeSize(srcSize + 4);
29
- store<u16>(bs.offset, 34); // "
30
- bs.offset += 2;
34
+ // bs.proposeSize(srcSize + 4);
35
+ // store<u16>(bs.offset, 34); // "
36
+ // bs.offset += 2;
31
37
 
32
- while (srcStart <= srcEnd8) {
33
- const block = load<u64>(srcStart);
34
- store<u64>(bs.offset, block);
38
+ // while (srcStart <= srcEnd8) {
39
+ // const block = load<u64>(srcStart);
40
+ // store<u64>(bs.offset, block);
35
41
 
36
- let mask = (
37
- v64x4_eq(block, QUOTE_MASK) |
38
- v64x4_eq(block, BACKSLASH_MASK) |
39
- v64x4_ltu(block & LANE_MASK_LOW, CONTROL_MASK)
40
- ) & UINT64_H8
42
+ // let mask = (
43
+ // v64x4_eq(block, QUOTE_MASK) |
44
+ // v64x4_eq(block, BACKSLASH_MASK) |
45
+ // v64x4_ltu(block & LANE_MASK_LOW, CONTROL_MASK)
46
+ // ) & HIGHS
41
47
 
42
- while (mask != 0) {
43
- const lane_index = usize(ctz(mask) >> 3);
44
- console.log("lane index " + lane_index.toString());
45
- const src_offset = srcStart + lane_index;
46
- const code = load<u16>(src_offset) << 2;
47
- const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + code);
48
+ // while (mask != 0) {
49
+ // const lane_index = usize(ctz(mask) >> 3);
50
+ // const src_offset = srcStart + lane_index;
51
+ // const dst_offset = bs.offset + lane_index;
52
+ // const code = load<u16>(src_offset) << 2;
53
+ // const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + code);
48
54
 
49
- if ((escaped & 0xffff) != BACK_SLASH) {
50
- bs.growSize(10);
51
- const dst_offset = bs.offset + lane_index;
52
- store<u64>(dst_offset, U00_MARKER);
53
- store<u32>(dst_offset, escaped, 8);
54
- // store<u64>(dst_offset, load<u64>(src_offset, 2), 12); // unsafe. can overflow here
55
- memory.copy(dst_offset + 12, src_offset + 2, (4 - lane_index) << 1);
56
- bs.offset += 10;
57
- } else {
58
- bs.growSize(2);
59
- const dst_offset = bs.offset + lane_index;
60
- store<u32>(dst_offset, escaped);
61
- // store<u64>(dst_offset, load<u64>(src_offset, 2), 4);
62
- memory.copy(dst_offset + 4, src_offset + 2, (4 - lane_index) << 1);
63
- bs.offset += 2;
64
- }
55
+ // if ((escaped & 0xffff) != BACK_SLASH) {
56
+ // bs.growSize(10);
57
+ // store<u64>(dst_offset, U00_MARKER);
58
+ // store<u32>(dst_offset, escaped, 8);
59
+ // // store<u64>(dst_offset, load<u64>(src_offset, 2), 12); // unsafe. can overflow here
60
+ // memory.copy(dst_offset + 12, src_offset + 2, (4 - lane_index) << 1);
61
+ // bs.offset += 10;
62
+ // } else {
63
+ // bs.growSize(2);
64
+ // store<u32>(dst_offset, escaped);
65
+ // // store<u64>(dst_offset, load<u64>(src_offset, 2), 4);
66
+ // memory.copy(dst_offset + 4, src_offset + 2, (4 - lane_index) << 1);
67
+ // bs.offset += 2;
68
+ // }
65
69
 
66
- mask &= mask - 1;
67
- }
70
+ // mask &= mask - 1;
71
+ // }
68
72
 
69
- srcStart += 8;
70
- bs.offset += 8;
71
- }
73
+ // srcStart += 8;
74
+ // bs.offset += 8;
75
+ // }
72
76
 
73
- while (srcStart <= srcEnd - 2) {
74
- const code = load<u16>(srcStart);
75
- if (code == 92 || code == 34 || code < 32) {
76
- const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (code << 2));
77
- if ((escaped & 0xffff) != BACK_SLASH) {
78
- bs.growSize(10);
79
- store<u64>(bs.offset, U00_MARKER);
80
- store<u32>(bs.offset, escaped, 8);
81
- bs.offset += 12;
82
- } else {
83
- bs.growSize(2);
84
- store<u32>(bs.offset, escaped);
85
- bs.offset += 4;
86
- }
87
- } else {
88
- store<u16>(bs.offset, code);
89
- bs.offset += 2;
90
- }
91
- srcStart += 2;
92
- }
77
+ // while (srcStart <= srcEnd - 2) {
78
+ // const code = load<u16>(srcStart);
79
+ // if (code == 92 || code == 34 || code < 32) {
80
+ // const escaped = load<u32>(SERIALIZE_ESCAPE_TABLE + (code << 2));
81
+ // if ((escaped & 0xffff) != BACK_SLASH) {
82
+ // bs.growSize(10);
83
+ // store<u64>(bs.offset, U00_MARKER);
84
+ // store<u32>(bs.offset, escaped, 8);
85
+ // bs.offset += 12;
86
+ // } else {
87
+ // bs.growSize(2);
88
+ // store<u32>(bs.offset, escaped);
89
+ // bs.offset += 4;
90
+ // }
91
+ // } else {
92
+ // store<u16>(bs.offset, code);
93
+ // bs.offset += 2;
94
+ // }
95
+ // srcStart += 2;
96
+ // }
93
97
 
94
- store<u16>(bs.offset, 34); // "
95
- bs.offset += 2;
98
+ // store<u16>(bs.offset, 34); // "
99
+ // bs.offset += 2;
96
100
  }
97
101
 
98
102
  // @ts-ignore: decorators allowed
99
103
  @inline function v64x4_eq(x: u64, y: u64): u64 {
100
104
  const xored = (x ^ LANE_MASK_HIGH) ^ y;
101
- const mask = (((xored >> 1) | UINT64_H8) - xored) & UINT64_H8;
105
+ const mask = (((xored >> 1) | HIGHS) - xored) & HIGHS;
102
106
  return (mask << 1) - (mask >> 7);
103
107
  }
104
-
105
108
  // @ts-ignore: decorators allowed
106
109
  @inline function v64x4_ltu(a: u64, b: u64): u64 {
107
- // Vigna's algorithm - fastest SWAR unsigned less-than
108
- return (((a | UINT64_H8) - (b & ~UINT64_H8)) | (a ^ b)) ^ (a | ~b);
110
+ return (((a | HIGHS) - (b & ~HIGHS)) | (a ^ b)) ^ (a | ~b);
109
111
  }
@@ -1,11 +1,7 @@
1
1
  import {
2
- bs
3
- } from "../lib/as-bs";
2
+ JSON
3
+ } from ".";
4
4
  import {
5
- serializeString_SIMD
6
- } from "./serialize/simd/string";
7
- import {
8
- serializeString_SWAR
9
- } from "./serialize/swar/string";
10
- serializeString_SWAR("a\"cd");
11
- console.log(bs.out<string>());
5
+ expect
6
+ } from "./__tests__/lib";
7
+ expect(JSON.stringify(JSON.parse<string>(JSON.stringify("abcdYZ12345890sdfw\"vie91kfESDFOK12i9i12dsf./?")))).toBe("\"abcdYZ12345890sdfw\b\"vie91kfESDFOK12i9i12dsf./?\"");
package/assembly/test.ts CHANGED
@@ -1,7 +1,4 @@
1
- import { bs } from "../lib/as-bs";
2
- import { serializeString_SIMD } from "./serialize/simd/string";
3
- import { serializeString_SWAR } from "./serialize/swar/string";
1
+ import { JSON } from ".";
2
+ import { expect } from "./__tests__/lib";
4
3
 
5
- serializeString_SWAR("a\"cd");
6
- // serializeString_SIMD("a\0b\"\nd");
7
- console.log(bs.out<string>());
4
+ expect(JSON.stringify(JSON.parse<string>(JSON.stringify("abcdYZ12345890sdfw\"vie91kfESDFOK12i9i12dsf./?")))).toBe('"abcdYZ12345890sdfw\\"vie91kfESDFOK12i9i12dsf./?"')
@@ -1,4 +1,5 @@
1
- import { bench } from "./lib/bench.js";
1
+ import { dumpToFile } from "./lib/bench.js";
2
+ import { bench, blackbox } from "./lib/bench.js";
2
3
 
3
4
  const v1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
4
5
  const v2 = '"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"';
@@ -6,22 +7,19 @@ const v2 = '"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"';
6
7
  bench(
7
8
  "Serialize Alphabet",
8
9
  () => {
9
- blackbox(JSON.stringify(blackbox(v1)));
10
+ blackbox(JSON.stringify(v1));
10
11
  },
11
12
  64_000_00,
12
13
  v1.length << 1,
13
14
  );
15
+ dumpToFile("abc", "serialize")
14
16
 
15
17
  bench(
16
18
  "Deserialize Alphabet",
17
19
  () => {
18
- blackbox(JSON.parse(blackbox(v2)));
20
+ blackbox(JSON.parse(v2));
19
21
  },
20
22
  64_000_00,
21
23
  v2.length << 1,
22
24
  );
23
-
24
- function blackbox<T>(value: T): T {
25
- (globalThis as any).__blackhole = value;
26
- return globalThis.__blackhole;
27
- }
25
+ dumpToFile("abc", "deserialize")