json-as 1.4.0 → 1.5.0

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 (86) hide show
  1. package/CHANGELOG.md +50 -29
  2. package/README.md +84 -33
  3. package/assembly/custom/chars.ts +39 -78
  4. package/assembly/deserialize/index/arbitrary.ts +26 -8
  5. package/assembly/deserialize/index/float.ts +2 -4
  6. package/assembly/deserialize/index/integer.ts +2 -4
  7. package/assembly/deserialize/index/object.ts +6 -1
  8. package/assembly/deserialize/index/string.ts +2 -7
  9. package/assembly/deserialize/index/unsigned.ts +2 -4
  10. package/assembly/deserialize/naive/array/integer.ts +1 -1
  11. package/assembly/deserialize/naive/array/map.ts +1 -1
  12. package/assembly/deserialize/naive/array/object.ts +1 -1
  13. package/assembly/deserialize/naive/array/struct.ts +19 -1
  14. package/assembly/deserialize/naive/bool.ts +1 -5
  15. package/assembly/deserialize/naive/date.ts +1 -2
  16. package/assembly/deserialize/naive/float.ts +2 -7
  17. package/assembly/deserialize/naive/integer.ts +1 -2
  18. package/assembly/deserialize/naive/map.ts +5 -6
  19. package/assembly/deserialize/naive/object.ts +151 -13
  20. package/assembly/deserialize/naive/raw.ts +1 -5
  21. package/assembly/deserialize/naive/set.ts +2 -4
  22. package/assembly/deserialize/naive/staticarray.ts +1 -2
  23. package/assembly/deserialize/naive/string.ts +6 -9
  24. package/assembly/deserialize/naive/unsigned.ts +1 -2
  25. package/assembly/deserialize/simd/array/integer.ts +2 -7
  26. package/assembly/deserialize/simd/float.ts +3 -5
  27. package/assembly/deserialize/simd/integer.ts +2 -7
  28. package/assembly/deserialize/simd/string.ts +5 -22
  29. package/assembly/deserialize/swar/array/arbitrary.ts +1 -2
  30. package/assembly/deserialize/swar/array/array.ts +1 -2
  31. package/assembly/deserialize/swar/array/bool.ts +1 -2
  32. package/assembly/deserialize/swar/array/box.ts +1 -2
  33. package/assembly/deserialize/swar/array/float.ts +6 -18
  34. package/assembly/deserialize/swar/array/generic.ts +1 -2
  35. package/assembly/deserialize/swar/array/integer.ts +7 -16
  36. package/assembly/deserialize/swar/array/map.ts +1 -2
  37. package/assembly/deserialize/swar/array/object.ts +1 -2
  38. package/assembly/deserialize/swar/array/raw.ts +1 -2
  39. package/assembly/deserialize/swar/array/shared.ts +6 -13
  40. package/assembly/deserialize/swar/array/string.ts +3 -8
  41. package/assembly/deserialize/swar/array/struct.ts +2 -8
  42. package/assembly/deserialize/swar/array.ts +1 -3
  43. package/assembly/deserialize/swar/float.ts +4 -9
  44. package/assembly/deserialize/swar/integer.ts +2 -7
  45. package/assembly/deserialize/swar/string.ts +13 -15
  46. package/assembly/deserialize/swar/typedarray.ts +4 -4
  47. package/assembly/index.d.ts +29 -24
  48. package/assembly/index.ts +1362 -246
  49. package/assembly/serialize/index/arbitrary.ts +70 -4
  50. package/assembly/serialize/index/jsonarray.ts +51 -0
  51. package/assembly/serialize/index/object.ts +25 -3
  52. package/assembly/serialize/index/string.ts +1 -2
  53. package/assembly/serialize/index/typedarray.ts +1 -2
  54. package/assembly/serialize/index.ts +1 -0
  55. package/assembly/serialize/naive/array.ts +23 -34
  56. package/assembly/serialize/naive/bool.ts +0 -1
  57. package/assembly/serialize/naive/float.ts +16 -25
  58. package/assembly/serialize/naive/integer.ts +1 -5
  59. package/assembly/serialize/naive/raw.ts +1 -2
  60. package/assembly/serialize/naive/set.ts +0 -4
  61. package/assembly/serialize/naive/staticarray.ts +0 -5
  62. package/assembly/serialize/naive/string.ts +2 -5
  63. package/assembly/serialize/naive/typedarray.ts +0 -6
  64. package/assembly/serialize/simd/string.ts +1 -3
  65. package/assembly/serialize/swar/string.ts +1 -2
  66. package/assembly/util/atoi-fast.ts +4 -14
  67. package/assembly/util/bytes.ts +1 -2
  68. package/assembly/util/idofd.ts +1 -2
  69. package/assembly/util/isSpace.ts +1 -2
  70. package/assembly/util/itoa-fast.ts +6 -9
  71. package/assembly/util/nextPowerOf2.ts +1 -2
  72. package/assembly/util/parsefloat-fast.ts +3 -5
  73. package/assembly/util/ptrToStr.ts +1 -2
  74. package/assembly/util/scanValueEndSimd.ts +54 -16
  75. package/assembly/util/scanValueEndSwar.ts +67 -25
  76. package/assembly/util/scientific.ts +5 -8
  77. package/assembly/util/snp.ts +1 -2
  78. package/assembly/util/swar-int.ts +5 -10
  79. package/assembly/util/swar.ts +2 -4
  80. package/lib/as-bs.ts +23 -45
  81. package/package.json +14 -7
  82. package/transform/lib/index.js +108 -64
  83. package/transform/lib/types.d.ts +2 -1
  84. package/transform/lib/types.js +3 -0
  85. package/assembly/util/dragonbox-cache.ts +0 -445
  86. package/assembly/util/dragonbox.ts +0 -652
@@ -6,8 +6,8 @@
6
6
  // below. Two reasons:
7
7
  //
8
8
  // 1. V8/wasm lowers `v / 100` (and other `/ <const>`s) to a single
9
- // multiply-shift, so jeaiii's main selling point avoiding division
10
- // hardware gives no win on this target. The op counts come out
9
+ // multiply-shift, so jeaiii's main selling point - avoiding division
10
+ // hardware - gives no win on this target. The op counts come out
11
11
  // roughly equal.
12
12
  //
13
13
  // 2. The div-by-const variant computes each digit pair independently
@@ -24,7 +24,7 @@
24
24
  // - A 100-entry digit-pair LUT keyed on `value % 100`. One `store<u32>`
25
25
  // emits a UTF-16 pair.
26
26
  //
27
- // - Forward write in one pass no `decimalCount32` precomputation, no
27
+ // - Forward write in one pass - no `decimalCount32` precomputation, no
28
28
  // backward write.
29
29
  //
30
30
  // Reference H2H bench: `__benches__/custom/itoa-h2h.bench.ts`.
@@ -43,13 +43,11 @@ function initPairs(): void {
43
43
  _pairsInited = true;
44
44
  }
45
45
 
46
-
47
- @inline export function ensureItoaPairs(): void {
46
+ export function ensureItoaPairs(): void {
48
47
  if (!_pairsInited) initPairs();
49
48
  }
50
49
 
51
- // @ts-expect-error: @inline is a valid decorator
52
- @inline function pair(i: u32): u32 {
50
+ function pair(i: u32): u32 {
53
51
  return load<u32>(DIGIT_PAIRS_UTF16 + ((<usize>i) << 2));
54
52
  }
55
53
 
@@ -213,8 +211,7 @@ export function itoaU64(buf: usize, v: u64): u32 {
213
211
  *
214
212
  * Returns the number of UTF-16 chars written.
215
213
  */
216
- // @ts-expect-error: @inline is a valid decorator
217
- @inline export function itoaFast<T extends number>(buf: usize, value: T): u32 {
214
+ export function itoaFast<T extends number>(buf: usize, value: T): u32 {
218
215
  if (sizeof<T>() <= 4) {
219
216
  if (isSigned<T>()) {
220
217
  let v = <i32>value;
@@ -1,4 +1,3 @@
1
- // @ts-ignore: Decorator valid here
2
- @inline export function nextPowerOf2(n: u32): u32 {
1
+ export function nextPowerOf2(n: u32): u32 {
3
2
  return 1 << (32 - clz(n - 1));
4
3
  }
@@ -3,7 +3,7 @@ import { ptrToStr } from "./ptrToStr";
3
3
  // Lemire-style fast float parser.
4
4
  //
5
5
  // Reference: Daniel Lemire, "Number parsing at a gigabyte per second"
6
- // (2021). https://arxiv.org/abs/2101.11408 implemented in
6
+ // (2021). https://arxiv.org/abs/2101.11408 - implemented in
7
7
  // https://github.com/fastfloat/fast_float.
8
8
  //
9
9
  // The "fast path" applies when:
@@ -35,13 +35,11 @@ const MAX_EXACT_POW10: i32 = 22;
35
35
  // 2^53 = 9_007_199_254_740_992. Any u64 <= this is exact in f64.
36
36
  const MAX_EXACT_MANTISSA: u64 = 1 << 53;
37
37
 
38
-
39
- @inline function loadPow10(exp: u32): f64 {
38
+ function loadPow10(exp: u32): f64 {
40
39
  return load<f64>(POW10_F64_POS + ((<usize>exp) << 3));
41
40
  }
42
41
 
43
-
44
- @inline function fallback<T>(srcStart: usize, srcEnd: usize): T {
42
+ function fallback<T>(srcStart: usize, srcEnd: usize): T {
45
43
  const s = ptrToStr(srcStart, srcEnd);
46
44
  // @ts-ignore: type
47
45
  const type: T = 0;
@@ -1,5 +1,4 @@
1
- // @ts-ignore: decorator
2
- @inline export function ptrToStr(start: usize, end: usize): string {
1
+ export function ptrToStr(start: usize, end: usize): string {
3
2
  const size = end - start;
4
3
  const out = __new(size, idof<string>());
5
4
  memory.copy(out, start, size);
@@ -4,6 +4,7 @@ import {
4
4
  BRACE_RIGHT,
5
5
  BRACKET_LEFT,
6
6
  BRACKET_RIGHT,
7
+ COLON,
7
8
  COMMA,
8
9
  QUOTE,
9
10
  } from "../custom/chars";
@@ -22,23 +23,40 @@ import { isSpace } from "./isSpace";
22
23
  // @ts-expect-error: @lazy is a valid decorator
23
24
  @lazy const SPLAT_SPACE = i16x8.splat(0x20);
24
25
  // JSON whitespace besides space is the contiguous range 0x09..0x0d
25
- // (tab/LF/VT/FF/CR), matched as `(c - 9) u<= 4` one sub + one unsigned
26
+ // (tab/LF/VT/FF/CR), matched as `(c - 9) u<= 4` - one sub + one unsigned
26
27
  // compare instead of five equality tests. Exact: matches `isSpace` with no
27
28
  // false positives.
28
29
  // @ts-expect-error: @lazy is a valid decorator
29
30
  @lazy const SPLAT_WS_LO = i16x8.splat(0x09);
30
31
  // @ts-expect-error: @lazy is a valid decorator
31
32
  @lazy const SPLAT_WS_SPAN = i16x8.splat(0x04);
33
+ // @ts-expect-error: @lazy is a valid decorator
34
+ @lazy const SPLAT_BRACKET_LEFT = i16x8.splat(<i16>BRACKET_LEFT);
35
+ // Clears bit 5 (0x20), folding `{`/`}` onto `[`/`]` so one pair of compares
36
+ // matches either bracket flavor. No ASCII char besides `[{`/`]}` folds onto
37
+ // `[`/`]`, so the structural mask stays exact.
38
+ // @ts-expect-error: @lazy is a valid decorator
39
+ @lazy const SPLAT_BRACKET_FOLD = i16x8.splat(<i16>0xffdf);
32
40
 
33
- // @ts-expect-error: @inline is a valid decorator
34
- @inline function quoteOrBackslashMask(block: v128): i32 {
41
+ function quoteOrBackslashMask(block: v128): i32 {
35
42
  return i16x8.bitmask(
36
43
  v128.or(i16x8.eq(block, SPLAT_QUOTE), i16x8.eq(block, SPLAT_BACK_SLASH)),
37
44
  );
38
45
  }
39
46
 
40
- // @ts-expect-error: @inline is a valid decorator
41
- @inline function scalarTerminatorMask(block: v128): i32 {
47
+ // Lanes equal to `"`, `{`, `}`, `[`, or `]` - the only bytes that, outside a
48
+ // string, change depth or open a string. Everything else (digits, `:`, `,`,
49
+ // whitespace, true/false/null) can be bulk-skipped between them.
50
+ function structuralOrQuoteMask(block: v128): i32 {
51
+ const folded = v128.and(block, SPLAT_BRACKET_FOLD);
52
+ const brackets = v128.or(
53
+ i16x8.eq(folded, SPLAT_BRACKET_LEFT),
54
+ i16x8.eq(folded, SPLAT_BRACKET_RIGHT),
55
+ );
56
+ return i16x8.bitmask(v128.or(brackets, i16x8.eq(block, SPLAT_QUOTE)));
57
+ }
58
+
59
+ function scalarTerminatorMask(block: v128): i32 {
42
60
  const structural = v128.or(
43
61
  v128.or(i16x8.eq(block, SPLAT_COMMA), i16x8.eq(block, SPLAT_BRACE_RIGHT)),
44
62
  i16x8.eq(block, SPLAT_BRACKET_RIGHT),
@@ -86,12 +104,14 @@ function scanQuotedValueEnd_SIMD(srcStart: usize, srcEnd: usize): usize {
86
104
  }
87
105
 
88
106
  function scanCompositeValueEnd_SIMD(srcStart: usize, srcEnd: usize): usize {
89
- // Track object/array depth scalar-side (structural tokens are sparse and a
90
- // bulk token-mask scan loses to a tight loop on token-dense objects), but
91
- // skip nested string VALUES with the vectorized quoted scan that's where
92
- // the long runs (URLs, base64, prose) actually are.
107
+ // Process structural tokens scalar-side (cheap, and token-dense regions stay
108
+ // in a tight loop), but bulk-skip the bytes between them: nested string VALUES
109
+ // via the vectorized quoted scan (URLs, base64, prose), and runs of digits /
110
+ // punctuation / whitespace (numeric arrays like coordinate lists) via a
111
+ // vectorized hunt for the next `"`/`{`/`}`/`[`/`]`.
93
112
  let depth: i32 = 1;
94
113
  let ptr = srcStart + 2;
114
+ const srcEnd16 = srcEnd >= 16 ? srcEnd - 16 : 0;
95
115
  while (ptr < srcEnd) {
96
116
  const code = load<u16>(ptr);
97
117
  if (code == QUOTE) {
@@ -99,12 +119,34 @@ function scanCompositeValueEnd_SIMD(srcStart: usize, srcEnd: usize): usize {
99
119
  if (!ptr) return 0;
100
120
  continue;
101
121
  }
102
- if (code == BRACE_LEFT || code == BRACKET_LEFT) {
122
+ const folded = code & 0xffdf;
123
+ if (folded == BRACKET_LEFT) {
124
+ // `[` or `{`
103
125
  depth++;
104
- } else if (code == BRACE_RIGHT || code == BRACKET_RIGHT) {
126
+ ptr += 2;
127
+ continue;
128
+ }
129
+ if (folded == BRACKET_RIGHT) {
130
+ // `]` or `}`
105
131
  if (--depth == 0) return ptr + 2;
132
+ ptr += 2;
133
+ continue;
106
134
  }
107
135
  ptr += 2;
136
+ // `,` and `:` sit one byte from the next token, so vectorizing them only
137
+ // adds SIMD setup on string-dense objects - stay scalar. Other fillers
138
+ // (number digits, whitespace, true/false/null) can run long; vectorize past
139
+ // them to the next `"`/`{`/`}`/`[`/`]`.
140
+ if (code == COMMA || code == COLON) continue;
141
+ while (ptr <= srcEnd16) {
142
+ const mask = structuralOrQuoteMask(load<v128>(ptr));
143
+ if (mask == 0) {
144
+ ptr += 16;
145
+ continue;
146
+ }
147
+ ptr += usize(ctz(mask) << 1);
148
+ break;
149
+ }
108
150
  }
109
151
  return 0;
110
152
  }
@@ -135,11 +177,7 @@ function scanScalarValueEnd_SIMD(srcStart: usize, srcEnd: usize): usize {
135
177
  return srcStart;
136
178
  }
137
179
 
138
- // @ts-expect-error: @inline is a valid decorator
139
- @inline export function scanValueEnd_SIMD<T>(
140
- srcStart: usize,
141
- srcEnd: usize,
142
- ): usize {
180
+ export function scanValueEnd_SIMD<T>(srcStart: usize, srcEnd: usize): usize {
143
181
  if (srcStart >= srcEnd) return 0;
144
182
  const first = load<u16>(srcStart);
145
183
 
@@ -4,6 +4,7 @@ import {
4
4
  BRACE_RIGHT,
5
5
  BRACKET_LEFT,
6
6
  BRACKET_RIGHT,
7
+ COLON,
7
8
  COMMA,
8
9
  QUOTE,
9
10
  } from "../custom/chars";
@@ -11,33 +12,45 @@ import { isSpace } from "./isSpace";
11
12
 
12
13
  // SWAR analogue of `scanValueEndSimd.ts`, processing four UTF-16 lanes per
13
14
  // 64-bit word for the SWAR build mode (no SIMD feature). Each mask is a fast
14
- // FILTER a matched lane is re-checked with a real `load<u16>` before acting
15
+ // FILTER - a matched lane is re-checked with a real `load<u16>` before acting -
15
16
  // so the masks may over-match non-ASCII lanes whose low byte equals a target
16
17
  // (the verify rejects them). Lane byte offset within a hit word is
17
18
  // `ctz(mask) >> 3` (detection bit sits at lane*16 + 7).
18
19
 
19
- // @ts-expect-error: @inline is a valid decorator
20
- @inline const ONES: u64 = 0x0001_0001_0001_0001;
21
- // @ts-expect-error: @inline is a valid decorator
22
- @inline const HI: u64 = 0x0080_0080_0080_0080;
20
+ const ONES: u64 = 0x0001_0001_0001_0001;
21
+ const HI: u64 = 0x0080_0080_0080_0080;
23
22
 
24
23
  // 16-bit-lane "equals" partials (pre-`& HI`); OR several, then `& HI` once.
25
- // @ts-expect-error: @inline is a valid decorator
26
- @inline function eqPart(block: u64, splat: u64): u64 {
24
+ function eqPart(block: u64, splat: u64): u64 {
27
25
  const t = block ^ splat;
28
26
  return (t - ONES) & ~t;
29
27
  }
30
28
 
31
- // @ts-expect-error: @inline is a valid decorator
32
- @inline const S_QUOTE: u64 = 0x0022_0022_0022_0022;
33
- // @ts-expect-error: @inline is a valid decorator
34
- @inline const S_BACK_SLASH: u64 = 0x005c_005c_005c_005c;
29
+ const S_QUOTE: u64 = 0x0022_0022_0022_0022;
30
+ const S_BACK_SLASH: u64 = 0x005c_005c_005c_005c;
31
+ const S_BRACKET_LEFT: u64 = 0x005b_005b_005b_005b;
32
+ const S_BRACKET_RIGHT: u64 = 0x005d_005d_005d_005d;
33
+ // Clears bit 5 (0x20) of each lane, folding `{`/`}` onto `[`/`]`.
34
+ const FOLD: u64 = 0xffdf_ffdf_ffdf_ffdf;
35
35
 
36
- // @ts-expect-error: @inline is a valid decorator
37
- @inline function quoteOrBackslashMask(block: u64): u64 {
36
+ function quoteOrBackslashMask(block: u64): u64 {
38
37
  return (eqPart(block, S_QUOTE) | eqPart(block, S_BACK_SLASH)) & HI;
39
38
  }
40
39
 
40
+ // Filter for lanes equal to `"`, `{`, `}`, `[`, or `]` - the only bytes that,
41
+ // outside a string, change depth or open a string. As with the other SWAR
42
+ // masks, a hit is a candidate to verify with a real load (it may over-match a
43
+ // non-ASCII lane whose low byte collides).
44
+ function structuralOrQuoteMask(block: u64): u64 {
45
+ const folded = block & FOLD;
46
+ return (
47
+ (eqPart(folded, S_BRACKET_LEFT) |
48
+ eqPart(folded, S_BRACKET_RIGHT) |
49
+ eqPart(block, S_QUOTE)) &
50
+ HI
51
+ );
52
+ }
53
+
41
54
  function scanQuotedValueEnd_SWAR(srcStart: usize, srcEnd: usize): usize {
42
55
  srcStart += 2;
43
56
  const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
@@ -63,21 +76,30 @@ function scanQuotedValueEnd_SWAR(srcStart: usize, srcEnd: usize): usize {
63
76
  break;
64
77
  }
65
78
 
79
+ // Resolve escapes by consuming a backslash *and the char it escapes* together,
80
+ // so escape parity is tracked exactly. A look-back `prev != BACK_SLASH` test is
81
+ // wrong for an escaped backslash: in `"x\\"` the closing quote follows a `\`
82
+ // (the second of the pair) yet still closes the string.
66
83
  while (srcStart < srcEnd) {
67
84
  const code = load<u16>(srcStart);
68
- if (code == QUOTE && load<u16>(srcStart - 2) != BACK_SLASH)
69
- return srcStart + 2;
85
+ if (code == BACK_SLASH) {
86
+ srcStart += 4;
87
+ continue;
88
+ }
89
+ if (code == QUOTE) return srcStart + 2;
70
90
  srcStart += 2;
71
91
  }
72
92
  return 0;
73
93
  }
74
94
 
75
95
  function scanCompositeValueEnd_SWAR(srcStart: usize, srcEnd: usize): usize {
76
- // Scalar depth tracking (structural tokens are sparse; a bulk token-mask scan
77
- // loses to a tight loop on token-dense objects) with SWAR quoted-skip for
78
- // nested string values where the long runs are.
96
+ // Process structural tokens scalar-side, but bulk-skip the bytes between them:
97
+ // nested string VALUES via the SWAR quoted scan, and runs of digits /
98
+ // punctuation / whitespace (numeric arrays) via a SWAR hunt for the next
99
+ // `"`/`{`/`}`/`[`/`]`.
79
100
  let depth: i32 = 1;
80
101
  let ptr = srcStart + 2;
102
+ const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
81
103
  while (ptr < srcEnd) {
82
104
  const code = load<u16>(ptr);
83
105
  if (code == QUOTE) {
@@ -85,12 +107,36 @@ function scanCompositeValueEnd_SWAR(srcStart: usize, srcEnd: usize): usize {
85
107
  if (!ptr) return 0;
86
108
  continue;
87
109
  }
88
- if (code == BRACE_LEFT || code == BRACKET_LEFT) {
110
+ const folded = code & 0xffdf;
111
+ if (folded == BRACKET_LEFT) {
89
112
  depth++;
90
- } else if (code == BRACE_RIGHT || code == BRACKET_RIGHT) {
113
+ ptr += 2;
114
+ continue;
115
+ }
116
+ if (folded == BRACKET_RIGHT) {
91
117
  if (--depth == 0) return ptr + 2;
118
+ ptr += 2;
119
+ continue;
92
120
  }
93
121
  ptr += 2;
122
+ // `,`/`:` sit one byte from the next token - stay scalar (string-dense
123
+ // objects); other fillers can run long, so SWAR-skip past them.
124
+ if (code == COMMA || code == COLON) continue;
125
+ while (ptr <= srcEnd8) {
126
+ const mask = structuralOrQuoteMask(load<u64>(ptr));
127
+ if (mask == 0) {
128
+ ptr += 8;
129
+ continue;
130
+ }
131
+ const idx = ptr + (usize(ctz(mask)) >> 3);
132
+ const c = load<u16>(idx);
133
+ const f = c & 0xffdf;
134
+ if (c == QUOTE || f == BRACKET_LEFT || f == BRACKET_RIGHT) {
135
+ ptr = idx; // real token - the outer loop processes it
136
+ break;
137
+ }
138
+ ptr = idx + 2; // spurious lane match - keep scanning
139
+ }
94
140
  }
95
141
  return 0;
96
142
  }
@@ -117,11 +163,7 @@ function scanScalarValueEnd_SWAR(srcStart: usize, srcEnd: usize): usize {
117
163
  * objects/arrays use the SWAR token scans above; scalars use a short scalar
118
164
  * loop. Returns 0 on empty input or an unterminated string/composite.
119
165
  */
120
- // @ts-expect-error: @inline is a valid decorator
121
- @inline export function scanValueEnd_SWAR<T>(
122
- srcStart: usize,
123
- srcEnd: usize,
124
- ): usize {
166
+ export function scanValueEnd_SWAR<T>(srcStart: usize, srcEnd: usize): usize {
125
167
  if (srcStart >= srcEnd) return 0;
126
168
  const first = load<u16>(srcStart);
127
169
 
@@ -10,7 +10,7 @@
10
10
  // `scientific` directly skips both costs.
11
11
  //
12
12
  // scientific() is correctly rounded for all u64 mantissas and decimal
13
- // exponents that fit in IEEE-754 f64's range including the [2^53, 2^64)
13
+ // exponents that fit in IEEE-754 f64's range - including the [2^53, 2^64)
14
14
  // mantissa range that breaks Lemire's single-fmul fast path.
15
15
 
16
16
  const POWERS10: usize = memory.data<f64>([
@@ -25,13 +25,11 @@ const POWERS5: usize = memory.data<i32>([
25
25
  244140625, 1220703125,
26
26
  ]);
27
27
 
28
- // @ts-ignore: inline
29
- @inline function pow10(n: i32): f64 {
28
+ function pow10(n: i32): f64 {
30
29
  return load<f64>(POWERS10 + ((<usize>n) << alignof<f64>()));
31
30
  }
32
31
 
33
- // @ts-ignore: inline
34
- @inline function pow5_32(n: i32): i32 {
32
+ function pow5_32(n: i32): i32 {
35
33
  return load<i32>(POWERS5 + ((<usize>n) << alignof<i32>()));
36
34
  }
37
35
 
@@ -40,8 +38,7 @@ const POWERS5: usize = memory.data<i32>([
40
38
  // @ts-ignore: lazy decorator
41
39
  @lazy let __fixmulShift: u64 = 0;
42
40
 
43
- // @ts-ignore: inline
44
- @inline function fixmul(a: u64, b: u32): u64 {
41
+ function fixmul(a: u64, b: u32): u64 {
45
42
  const low = (a & 0xffffffff) * b;
46
43
  const high = (a >> 32) * b + (low >> 32);
47
44
  const overflow = <u32>(high >> 32);
@@ -98,7 +95,7 @@ function scaleup(significand: u64, exp: i32): f64 {
98
95
 
99
96
  /**
100
97
  * Construct an f64 from a u64 mantissa and decimal exponent. Result is
101
- * correctly rounded bit-identical to `f64.parse` for any input the SWAR
98
+ * correctly rounded - bit-identical to `f64.parse` for any input the SWAR
102
99
  * float deserializer can pre-parse into this form.
103
100
  *
104
101
  * Caller guarantees the digit run that produced `significand` was already
@@ -58,8 +58,7 @@ export function snp<T extends number>(srcStart: usize, srcEnd: usize): T {
58
58
  }
59
59
  }
60
60
 
61
- // @ts-ignore: Decorator valid here
62
- @inline function pow10<T extends number>(x: u16): T {
61
+ function pow10<T extends number>(x: u16): T {
63
62
  if (sizeof<T>() == 8) {
64
63
  return <T>load<u64>(POW_TEN_TABLE_64 + x);
65
64
  } else {
@@ -26,8 +26,7 @@ const FINAL_4_MAGIC: u64 = 0x0000_0064_0000_0001;
26
26
  * @param block Four UTF-16 code units packed into a `u64`.
27
27
  * @returns The parsed 4-digit value, or `U32.MAX_VALUE` on invalid input.
28
28
  */
29
- // @ts-expect-error: @inline is a valid decorator
30
- @inline export function parse4Digits_Baseline(block: u64): u32 {
29
+ export function parse4Digits_Baseline(block: u64): u32 {
31
30
  const digits = (block & LANE_LO_4) - ZERO_4;
32
31
  if (((digits | (digits + RANGE_ADD_4)) & RANGE_MASK_4) != 0) {
33
32
  return U32.MAX_VALUE;
@@ -58,8 +57,7 @@ const FINAL_4_MAGIC: u64 = 0x0000_0064_0000_0001;
58
57
  * @param block Four UTF-16 code units packed into a `u64`.
59
58
  * @returns The parsed 4-digit value, or `U32.MAX_VALUE` on invalid input.
60
59
  */
61
- // @ts-expect-error: @inline is a valid decorator
62
- @inline export function parse4Digits_PairMul(block: u64): u32 {
60
+ export function parse4Digits_PairMul(block: u64): u32 {
63
61
  const digits = block - ZERO_4;
64
62
  if (((digits | (digits + RANGE_ADD_4)) & RANGE_MASK_4) != 0) {
65
63
  return U32.MAX_VALUE;
@@ -76,8 +74,7 @@ const FINAL_4_MAGIC: u64 = 0x0000_0064_0000_0001;
76
74
  * @param block Four UTF-16 code units packed into a `u64`.
77
75
  * @returns The parsed 4-digit value.
78
76
  */
79
- // @ts-expect-error: @inline is a valid decorator
80
- @inline export function parse4Digits_PairMul_Unsafe(block: u64): u32 {
77
+ export function parse4Digits_PairMul_Unsafe(block: u64): u32 {
81
78
  const digits = block - ZERO_4;
82
79
  const pairs = (digits * 10 + (digits >> 16)) & U32_LO_PAIR;
83
80
  return <u32>((pairs * FINAL_4_MAGIC) >> 32);
@@ -123,8 +120,7 @@ export function parse8Digits_PairMul(lo: u64, hi: u64): u32 {
123
120
  * @param hi The second `u64`, four UTF-16 code units.
124
121
  * @returns The parsed 8-digit value.
125
122
  */
126
- // @ts-expect-error: @inline is a valid decorator
127
- @inline export function parse8Digits_PairMul_Unsafe(lo: u64, hi: u64): u32 {
123
+ export function parse8Digits_PairMul_Unsafe(lo: u64, hi: u64): u32 {
128
124
  const loDigits = lo - ZERO_4;
129
125
  const hiDigits = hi - ZERO_4;
130
126
  const loPairs = (loDigits * 10 + (loDigits >> 16)) & U32_LO_PAIR;
@@ -149,8 +145,7 @@ export function parse8Digits_PairMul(lo: u64, hi: u64): u32 {
149
145
  * @param block Four UTF-16 code units packed into a `u64`.
150
146
  * @returns A mask with non-digit lanes flagged in their high bit, or 0.
151
147
  */
152
- // @ts-expect-error: @inline is a valid decorator
153
- @inline export function nonDigitMask4(block: u64): u64 {
148
+ export function nonDigitMask4(block: u64): u64 {
154
149
  const digits = (block & LANE_LO_4) - ZERO_4;
155
150
  return (digits | (digits + RANGE_ADD_4)) & RANGE_MASK_4;
156
151
  }
@@ -18,8 +18,7 @@
18
18
  * @param block Packed UTF-16 ASCII hex digits.
19
19
  * @returns The decoded 16-bit value.
20
20
  */
21
- // @ts-expect-error: @inline is a valid decorator
22
- @inline export function hex4_to_u16_swar(block: u64): u16 {
21
+ export function hex4_to_u16_swar(block: u64): u16 {
23
22
  // (c & 0xF) + 9 * (c >> 6)
24
23
  block = (block & 0x0f000f000f000f) + ((block >> 6) & 0x03000300030003) * 9;
25
24
 
@@ -51,8 +50,7 @@
51
50
  * @param code The 16-bit value to encode.
52
51
  * @returns Four packed UTF-16 ASCII hex digits.
53
52
  */
54
- // @ts-expect-error: @inline is a valid decorator
55
- @inline export function u16_to_hex4_swar(code: u16): u64 {
53
+ export function u16_to_hex4_swar(code: u16): u64 {
56
54
  let block =
57
55
  (<u64>((code >> 12) & 0xf)) |
58
56
  ((<u64>((code >> 8) & 0xf)) << 16) |