json-as 1.2.6 → 1.3.1

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 (135) hide show
  1. package/CHANGELOG.md +417 -0
  2. package/README.md +135 -36
  3. package/assembly/custom/util.ts +24 -70
  4. package/assembly/deserialize/float.ts +181 -0
  5. package/assembly/deserialize/helpers/uint.ts +12 -0
  6. package/assembly/deserialize/index/arbitrary.ts +25 -0
  7. package/assembly/deserialize/index/array.ts +61 -0
  8. package/assembly/deserialize/index/bool.ts +1 -0
  9. package/assembly/deserialize/index/date.ts +1 -0
  10. package/assembly/deserialize/index/float.ts +1 -0
  11. package/assembly/deserialize/index/integer.ts +1 -0
  12. package/assembly/deserialize/index/map.ts +1 -0
  13. package/assembly/deserialize/index/object.ts +1 -0
  14. package/assembly/deserialize/index/raw.ts +1 -0
  15. package/assembly/deserialize/index/set.ts +1 -0
  16. package/assembly/deserialize/index/staticarray.ts +1 -0
  17. package/assembly/deserialize/index/string.ts +15 -0
  18. package/assembly/deserialize/index/struct.ts +1 -0
  19. package/assembly/deserialize/index/typedarray.ts +15 -0
  20. package/assembly/deserialize/index/unsigned.ts +1 -0
  21. package/assembly/deserialize/index.ts +14 -0
  22. package/assembly/deserialize/integer.ts +42 -0
  23. package/assembly/deserialize/simd/array/integer.ts +307 -0
  24. package/assembly/deserialize/simd/string.ts +130 -11
  25. package/assembly/deserialize/simple/arbitrary.ts +5 -12
  26. package/assembly/deserialize/simple/array/arbitrary.ts +12 -36
  27. package/assembly/deserialize/simple/array/array.ts +2 -8
  28. package/assembly/deserialize/simple/array/bool.ts +2 -8
  29. package/assembly/deserialize/simple/array/box.ts +2 -8
  30. package/assembly/deserialize/simple/array/float.ts +2 -8
  31. package/assembly/deserialize/simple/array/integer.ts +2 -8
  32. package/assembly/deserialize/simple/array/map.ts +6 -26
  33. package/assembly/deserialize/simple/array/object.ts +6 -26
  34. package/assembly/deserialize/simple/array/raw.ts +18 -61
  35. package/assembly/deserialize/simple/array/string.ts +5 -10
  36. package/assembly/deserialize/simple/array/struct.ts +6 -26
  37. package/assembly/deserialize/simple/array.ts +2 -5
  38. package/assembly/deserialize/simple/bool.ts +2 -6
  39. package/assembly/deserialize/simple/map.ts +29 -102
  40. package/assembly/deserialize/simple/object.ts +24 -81
  41. package/assembly/deserialize/simple/raw.ts +1 -4
  42. package/assembly/deserialize/simple/set.ts +11 -37
  43. package/assembly/deserialize/simple/staticarray/array.ts +1 -1
  44. package/assembly/deserialize/simple/staticarray/bool.ts +1 -1
  45. package/assembly/deserialize/simple/staticarray/float.ts +1 -1
  46. package/assembly/deserialize/simple/staticarray/integer.ts +1 -1
  47. package/assembly/deserialize/simple/staticarray/string.ts +7 -14
  48. package/assembly/deserialize/simple/staticarray/struct.ts +1 -1
  49. package/assembly/deserialize/simple/staticarray.ts +57 -21
  50. package/assembly/deserialize/simple/string.ts +90 -10
  51. package/assembly/deserialize/simple/struct.ts +25 -121
  52. package/assembly/deserialize/simple/typedarray.ts +94 -0
  53. package/assembly/deserialize/swar/array/arbitrary.ts +8 -0
  54. package/assembly/deserialize/swar/array/array.ts +39 -0
  55. package/assembly/deserialize/swar/array/bool.ts +47 -0
  56. package/assembly/deserialize/swar/array/box.ts +8 -0
  57. package/assembly/deserialize/swar/array/float.ts +39 -0
  58. package/assembly/deserialize/swar/array/integer.ts +461 -0
  59. package/assembly/deserialize/swar/array/map.ts +7 -0
  60. package/assembly/deserialize/swar/array/object.ts +44 -0
  61. package/assembly/deserialize/swar/array/raw.ts +8 -0
  62. package/assembly/deserialize/swar/array/shared.ts +96 -0
  63. package/assembly/deserialize/swar/array/string.ts +39 -0
  64. package/assembly/deserialize/swar/array/struct.ts +44 -0
  65. package/assembly/deserialize/swar/array.ts +49 -0
  66. package/assembly/deserialize/swar/string.ts +648 -15
  67. package/assembly/deserialize/unsigned.ts +75 -0
  68. package/assembly/index.d.ts +1 -3
  69. package/assembly/index.ts +316 -374
  70. package/assembly/serialize/index/arbitrary.ts +75 -0
  71. package/assembly/serialize/index/array.ts +1 -0
  72. package/assembly/serialize/index/bool.ts +1 -0
  73. package/assembly/serialize/index/date.ts +1 -0
  74. package/assembly/serialize/index/float.ts +1 -0
  75. package/assembly/serialize/index/integer.ts +1 -0
  76. package/assembly/serialize/index/map.ts +1 -0
  77. package/assembly/serialize/index/object.ts +46 -0
  78. package/assembly/serialize/index/raw.ts +1 -0
  79. package/assembly/serialize/index/set.ts +1 -0
  80. package/assembly/serialize/index/staticarray.ts +1 -0
  81. package/assembly/serialize/index/string.ts +15 -0
  82. package/assembly/serialize/index/struct.ts +1 -0
  83. package/assembly/serialize/index/typedarray.ts +66 -0
  84. package/assembly/serialize/index.ts +13 -0
  85. package/assembly/serialize/simd/string.ts +4 -13
  86. package/assembly/serialize/simple/arbitrary.ts +6 -0
  87. package/assembly/serialize/simple/raw.ts +1 -5
  88. package/assembly/serialize/simple/string.ts +3 -11
  89. package/assembly/serialize/simple/typedarray.ts +63 -0
  90. package/assembly/serialize/swar/string.ts +6 -21
  91. package/assembly/util/concat.ts +1 -5
  92. package/assembly/util/index.ts +1 -0
  93. package/assembly/util/masks.ts +12 -18
  94. package/assembly/util/memory.ts +0 -0
  95. package/assembly/util/snp.ts +1 -4
  96. package/assembly/util/stringScan.ts +24 -0
  97. package/assembly/util/swar.ts +50 -6
  98. package/lib/as-bs.ts +137 -127
  99. package/package.json +26 -5
  100. package/transform/lib/builder.d.ts.map +1 -1
  101. package/transform/lib/builder.js +5 -13
  102. package/transform/lib/builder.js.map +1 -1
  103. package/transform/lib/index.d.ts +1 -0
  104. package/transform/lib/index.d.ts.map +1 -1
  105. package/transform/lib/index.js +672 -757
  106. package/transform/lib/index.js.map +1 -1
  107. package/transform/lib/linkers/alias.d.ts.map +1 -1
  108. package/transform/lib/linkers/alias.js.map +1 -1
  109. package/transform/lib/linkers/custom.d.ts.map +1 -1
  110. package/transform/lib/linkers/custom.js +8 -9
  111. package/transform/lib/linkers/custom.js.map +1 -1
  112. package/transform/lib/linkers/imports.d.ts.map +1 -1
  113. package/transform/lib/linkers/imports.js.map +1 -1
  114. package/transform/lib/types.d.ts +6 -0
  115. package/transform/lib/types.d.ts.map +1 -1
  116. package/transform/lib/types.js +83 -21
  117. package/transform/lib/types.js.map +1 -1
  118. package/transform/lib/util.d.ts.map +1 -1
  119. package/transform/lib/util.js +1 -1
  120. package/transform/lib/util.js.map +1 -1
  121. package/transform/lib/visitor.d.ts.map +1 -1
  122. package/transform/lib/visitor.js +1 -2
  123. package/transform/lib/visitor.js.map +1 -1
  124. package/.prettierrc +0 -3
  125. package/ARCHITECTURE.md +0 -320
  126. package/CONTRIBUTING.md +0 -238
  127. package/TODO +0 -1
  128. package/assembly/deserialize/simple/float.ts +0 -11
  129. package/assembly/deserialize/simple/integer.ts +0 -9
  130. package/assembly/test.ts +0 -30
  131. package/eslint.config.js +0 -60
  132. package/lib/tsconfig.json +0 -8
  133. package/tools/assemblyscript-eslint-local.js +0 -29
  134. package/tools/assemblyscript-eslint.js +0 -29
  135. package/transform/tsconfig.json +0 -35
@@ -1,4 +1,6 @@
1
1
  import { bs } from "../../../lib/as-bs";
2
+ import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
3
+ import { BACK_SLASH, QUOTE } from "../../custom/chars";
2
4
  import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
3
5
  import { hex4_to_u16_swar } from "../../util/swar";
4
6
 
@@ -38,12 +40,26 @@ import { hex4_to_u16_swar } from "../../util/swar";
38
40
  * @param dst buffer to write to
39
41
  * @returns number of bytes written
40
42
  */
41
- export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
42
- // Strip quotes
43
- srcStart += 2;
44
- srcEnd -= 2;
43
+ // @ts-expect-error: @inline is a valid decorator
44
+ @inline function copyStringFromSource(srcStart: usize, byteLength: usize): string {
45
+ if (byteLength == 0) return changetype<string>("");
46
+ const out = __new(byteLength, idof<string>());
47
+ memory.copy(out, srcStart, byteLength);
48
+ return changetype<string>(out);
49
+ }
50
+
51
+ // @ts-expect-error: @inline is a valid decorator
52
+ @inline function deserializeEscapedString_SWAR(payloadStart: usize, escapeStart: usize, srcEnd: usize): string {
45
53
  const srcEnd8 = srcEnd - 8;
46
- bs.ensureSize(u32(srcEnd - srcStart));
54
+ const prefixLen = <u32>(escapeStart - payloadStart);
55
+ const outStart = bs.offset - bs.buffer;
56
+ bs.ensureSize(<u32>(srcEnd - payloadStart));
57
+ if (prefixLen != 0) {
58
+ memory.copy(bs.offset, payloadStart, prefixLen);
59
+ bs.offset += prefixLen;
60
+ }
61
+
62
+ let srcStart = escapeStart;
47
63
 
48
64
  while (srcStart < srcEnd8) {
49
65
  const block = load<u64>(srcStart);
@@ -124,9 +140,632 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
124
140
 
125
141
  bs.offset += 2;
126
142
  }
127
- return bs.out<string>();
143
+ return bs.sliceOut<string>(outStart);
144
+ }
145
+
146
+ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
147
+ // Strip quotes
148
+ srcStart += 2;
149
+ srcEnd -= 2;
150
+ const payloadStart = srcStart;
151
+ const srcEnd8 = srcEnd - 8;
152
+
153
+ while (srcStart < srcEnd8) {
154
+ const block = load<u64>(srcStart);
155
+ let mask = inline.always(backslash_mask_unsafe(block));
156
+
157
+ if (mask === 0) {
158
+ srcStart += 8;
159
+ continue;
160
+ }
161
+
162
+ do {
163
+ const laneIdx = usize(ctz(mask) >> 3);
164
+ mask &= mask - 1;
165
+ const srcIdx = srcStart + laneIdx;
166
+ const header = load<u32>(srcIdx);
167
+
168
+ // Detect false positive (code unit where low byte is 0x5C)
169
+ if ((header & 0xffff) !== 0x5c) continue;
170
+
171
+ return inline.always(deserializeEscapedString_SWAR(payloadStart, srcIdx, srcEnd));
172
+ } while (mask !== 0);
173
+
174
+ srcStart += 8;
175
+ }
176
+
177
+ while (srcStart < srcEnd) {
178
+ if (load<u16>(srcStart) == BACK_SLASH) {
179
+ return inline.always(deserializeEscapedString_SWAR(payloadStart, srcStart, srcEnd));
180
+ }
181
+ srcStart += 2;
182
+ }
183
+
184
+ return copyStringFromSource(payloadStart, srcEnd - payloadStart);
185
+ }
186
+
187
+ // /**
188
+ // * Deserializes a quoted JSON string into a reused/renewed destination string buffer.
189
+ // * @param srcStart pointer to opening quote
190
+ // * @param srcEnd pointer to closing quote
191
+ // * @param outPtr existing destination string pointer (or 0)
192
+ // * @returns next unread source pointer
193
+ // */
194
+ // export function deserializeString_SWAR_TO(srcStart: usize, srcEnd: usize, outPtr: usize): usize {
195
+ // srcStart += 2;
196
+ // let dst = outPtr;
197
+ // const srcEnd8 = srcEnd - 8;
198
+ // const byteSize = srcEnd - srcStart;
199
+ // if (!dst) {
200
+ // dst = __new(byteSize, idof<string>());
201
+ // } else if (changetype<OBJECT>(dst - TOTAL_OVERHEAD).rtSize < <u32>byteSize) {
202
+ // dst = __renew(dst, byteSize);
203
+ // }
204
+ // let offset = dst;
205
+
206
+ // while (srcStart < srcEnd8) {
207
+ // const block = load<u64>(srcStart);
208
+ // store<u64>(offset, block);
209
+
210
+ // let mask = inline.always(backslash_mask_unsafe(block));
211
+
212
+ // if (mask === 0) {
213
+ // srcStart += 8;
214
+ // offset += 8;
215
+ // continue;
216
+ // }
217
+
218
+ // do {
219
+ // const laneIdx = usize(ctz(mask) >> 3); // 0 2 4 6
220
+ // mask &= mask - 1;
221
+ // const srcIdx = srcStart + laneIdx;
222
+ // const dstIdx = offset + laneIdx;
223
+ // const header = load<u32>(srcIdx);
224
+ // const code = <u16>(header >> 16);
225
+
226
+ // if ((header & 0xffff) !== 0x5c) continue;
227
+
228
+ // if (code !== 0x75) {
229
+ // const escaped = load<u16>(DESERIALIZE_ESCAPE_TABLE + code);
230
+ // mask &= mask - usize(escaped === 0x5c);
231
+ // store<u16>(dstIdx, escaped);
232
+ // const copyStart = srcIdx + 4;
233
+ // if (copyStart < srcEnd) {
234
+ // const copyBytes = min<usize>(4, srcEnd - copyStart);
235
+ // memory.copy(dstIdx + 2, copyStart, copyBytes);
236
+ // }
237
+
238
+ // const l6 = usize(laneIdx === 6);
239
+ // offset -= (1 - l6) << 1;
240
+ // srcStart += l6 << 1;
241
+ // continue;
242
+ // }
243
+
244
+ // const block = load<u64>(srcIdx, 4); // XXXX
245
+ // const escaped = hex4_to_u16_swar(block);
246
+ // store<u16>(dstIdx, escaped);
247
+ // srcStart += 4 + laneIdx;
248
+ // offset -= 6 - laneIdx;
249
+ // } while (mask !== 0);
250
+
251
+ // offset += 8;
252
+ // srcStart += 8;
253
+ // }
254
+
255
+ // while (srcStart < srcEnd) {
256
+ // const block = load<u16>(srcStart);
257
+ // store<u16>(offset, block);
258
+ // srcStart += 2;
259
+
260
+ // if (block !== 0x5c) {
261
+ // offset += 2;
262
+ // continue;
263
+ // }
264
+
265
+ // const code = load<u16>(srcStart);
266
+ // if (code !== 0x75) {
267
+ // const block = load<u16>(srcStart);
268
+ // const escape = load<u16>(DESERIALIZE_ESCAPE_TABLE + block);
269
+ // store<u16>(offset, escape);
270
+ // srcStart += 2;
271
+ // } else {
272
+ // const block = load<u64>(srcStart, 2); // XXXX
273
+ // const escaped = hex4_to_u16_swar(block);
274
+ // store<u16>(offset, escaped);
275
+ // srcStart += 10;
276
+ // }
277
+
278
+ // offset += 2;
279
+ // }
280
+ // if (offset - dst != byteSize) {
281
+ // dst = __renew(dst, offset - dst);
282
+ // }
283
+ // return srcEnd + 2;
284
+ // }
285
+
286
+ // Scans a quoted string value, writes into the destination field, and returns next unread src pointer.
287
+ // @ts-expect-error: @inline is a valid decorator
288
+ @inline function writeStringToField(dstFieldPtr: usize, srcStart: usize, byteLength: u32): void {
289
+ if (byteLength == 0) {
290
+ store<usize>(dstFieldPtr, changetype<usize>(""));
291
+ return;
292
+ }
293
+
294
+ const current = load<usize>(dstFieldPtr);
295
+ let stringPtr: usize;
296
+ if (current != 0 && changetype<OBJECT>(current - TOTAL_OVERHEAD).rtSize == byteLength) {
297
+ stringPtr = current;
298
+ } else if (current != 0 && current != changetype<usize>("")) {
299
+ stringPtr = __renew(current, byteLength);
300
+ store<usize>(dstFieldPtr, stringPtr);
301
+ } else {
302
+ stringPtr = __new(byteLength, idof<string>());
303
+ store<usize>(dstFieldPtr, stringPtr);
304
+ }
305
+ memory.copy(stringPtr, srcStart, byteLength);
128
306
  }
129
307
 
308
+ /*
309
+ export function deserializeStringField_SWAR<T extends string | null>(srcStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
310
+ if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE) abort("Expected leading quote");
311
+
312
+ const payloadStart = srcStart + 2;
313
+ const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
314
+ srcStart = payloadStart;
315
+
316
+ while (srcStart <= srcEnd8) {
317
+ let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
318
+
319
+ if (mask === 0) {
320
+ srcStart += 8;
321
+ continue;
322
+ }
323
+
324
+ do {
325
+ const laneIdx = usize(ctz(mask) >> 3);
326
+ mask &= ~(0xffff << (laneIdx << 3));
327
+ // since we clear the entire byte, we can guarentee that any discovered lane where char == QUOTE is unescaped and a terminator.
328
+ const srcIdx = srcStart + laneIdx;
329
+ const char = load<u16>(srcIdx);
330
+
331
+ if (char == QUOTE) {
332
+ writeStringToField(dstFieldPtr, payloadStart, <u32>(srcIdx - payloadStart));
333
+ return srcIdx + 2;
334
+ }
335
+ if (char != BACK_SLASH) continue;
336
+
337
+ bs.offset = bs.buffer;
338
+ bs.ensureSize(<u32>(srcEnd - payloadStart));
339
+ const prefixLen = <u32>(srcIdx - payloadStart);
340
+ if (prefixLen != 0) {
341
+ memory.copy(bs.buffer, payloadStart, prefixLen);
342
+ bs.offset += prefixLen;
343
+ }
344
+
345
+ const chunk = load<u32>(srcIdx);
346
+ const code = <u16>(chunk >> 16);
347
+
348
+ if (code !== 0x75) {
349
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
350
+ bs.offset += 2;
351
+ let lastPtr = srcIdx + 4;
352
+ srcStart = lastPtr;
353
+ while (srcStart <= srcEnd8) {
354
+ const blockStart = srcStart;
355
+ let escapedMask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
356
+ if (escapedMask === 0) {
357
+ srcStart += 8;
358
+ continue;
359
+ }
360
+
361
+ do {
362
+ const escapedLaneIdx = usize(ctz(escapedMask) >> 3);
363
+ escapedMask &= escapedMask - 1;
364
+ const escapedIdx = srcStart + escapedLaneIdx;
365
+ const escapedChar = load<u16>(escapedIdx);
366
+
367
+ if (escapedChar == QUOTE) {
368
+ const runLen = <u32>(escapedIdx - lastPtr);
369
+ if (runLen != 0) {
370
+ memory.copy(bs.offset, lastPtr, runLen);
371
+ bs.offset += runLen;
372
+ }
373
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
374
+ bs.offset = bs.buffer;
375
+ return escapedIdx + 2;
376
+ }
377
+ if (escapedChar != BACK_SLASH) continue;
378
+
379
+ const runLen = <u32>(escapedIdx - lastPtr);
380
+ if (runLen != 0) {
381
+ memory.copy(bs.offset, lastPtr, runLen);
382
+ bs.offset += runLen;
383
+ }
384
+
385
+ const escapedChunk = load<u32>(escapedIdx);
386
+ const escapedCode = <u16>(escapedChunk >> 16);
387
+ if (escapedCode !== 0x75) {
388
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + escapedCode));
389
+ bs.offset += 2;
390
+ lastPtr = escapedIdx + 4;
391
+ } else {
392
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(escapedIdx, 4)));
393
+ bs.offset += 2;
394
+ lastPtr = escapedIdx + 12;
395
+ }
396
+ srcStart = lastPtr;
397
+ break;
398
+ } while (escapedMask !== 0);
399
+
400
+ if (srcStart == blockStart) srcStart += 8;
401
+ }
402
+
403
+ while (srcStart < srcEnd) {
404
+ const tailChar = load<u16>(srcStart);
405
+ if (tailChar == QUOTE) {
406
+ const runLen = <u32>(srcStart - lastPtr);
407
+ if (runLen != 0) {
408
+ memory.copy(bs.offset, lastPtr, runLen);
409
+ bs.offset += runLen;
410
+ }
411
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
412
+ bs.offset = bs.buffer;
413
+ return srcStart + 2;
414
+ }
415
+ if (tailChar != BACK_SLASH) {
416
+ srcStart += 2;
417
+ continue;
418
+ }
419
+
420
+ const runLen = <u32>(srcStart - lastPtr);
421
+ if (runLen != 0) {
422
+ memory.copy(bs.offset, lastPtr, runLen);
423
+ bs.offset += runLen;
424
+ }
425
+ const tailCode = load<u16>(srcStart, 2);
426
+ if (tailCode !== 0x75) {
427
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + tailCode));
428
+ bs.offset += 2;
429
+ srcStart += 4;
430
+ } else {
431
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
432
+ bs.offset += 2;
433
+ srcStart += 12;
434
+ }
435
+ lastPtr = srcStart;
436
+ }
437
+ bs.offset = bs.buffer;
438
+ return srcStart;
439
+ } else {
440
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
441
+ bs.offset += 2;
442
+ let lastPtr = srcIdx + 12;
443
+ srcStart = lastPtr;
444
+ while (srcStart <= srcEnd8) {
445
+ const blockStart = srcStart;
446
+ let escapedMask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
447
+ if (escapedMask === 0) {
448
+ srcStart += 8;
449
+ continue;
450
+ }
451
+
452
+ do {
453
+ const escapedLaneIdx = usize(ctz(escapedMask) >> 3);
454
+ escapedMask &= escapedMask - 1;
455
+ const escapedIdx = srcStart + escapedLaneIdx;
456
+ const escapedChar = load<u16>(escapedIdx);
457
+
458
+ if (escapedChar == QUOTE) {
459
+ const runLen = <u32>(escapedIdx - lastPtr);
460
+ if (runLen != 0) {
461
+ memory.copy(bs.offset, lastPtr, runLen);
462
+ bs.offset += runLen;
463
+ }
464
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
465
+ bs.offset = bs.buffer;
466
+ return escapedIdx + 2;
467
+ }
468
+ if (escapedChar != BACK_SLASH) continue;
469
+
470
+ const runLen = <u32>(escapedIdx - lastPtr);
471
+ if (runLen != 0) {
472
+ memory.copy(bs.offset, lastPtr, runLen);
473
+ bs.offset += runLen;
474
+ }
475
+
476
+ const escapedChunk = load<u32>(escapedIdx);
477
+ const escapedCode = <u16>(escapedChunk >> 16);
478
+ if (escapedCode !== 0x75) {
479
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + escapedCode));
480
+ bs.offset += 2;
481
+ lastPtr = escapedIdx + 4;
482
+ } else {
483
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(escapedIdx, 4)));
484
+ bs.offset += 2;
485
+ lastPtr = escapedIdx + 12;
486
+ }
487
+ srcStart = lastPtr;
488
+ break;
489
+ } while (escapedMask !== 0);
490
+
491
+ if (srcStart == blockStart) srcStart += 8;
492
+ }
493
+
494
+ while (srcStart < srcEnd) {
495
+ const tailChar = load<u16>(srcStart);
496
+ if (tailChar == QUOTE) {
497
+ const runLen = <u32>(srcStart - lastPtr);
498
+ if (runLen != 0) {
499
+ memory.copy(bs.offset, lastPtr, runLen);
500
+ bs.offset += runLen;
501
+ }
502
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
503
+ bs.offset = bs.buffer;
504
+ return srcStart + 2;
505
+ }
506
+ if (tailChar != BACK_SLASH) {
507
+ srcStart += 2;
508
+ continue;
509
+ }
510
+
511
+ const runLen = <u32>(srcStart - lastPtr);
512
+ if (runLen != 0) {
513
+ memory.copy(bs.offset, lastPtr, runLen);
514
+ bs.offset += runLen;
515
+ }
516
+ const tailCode = load<u16>(srcStart, 2);
517
+ if (tailCode !== 0x75) {
518
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + tailCode));
519
+ bs.offset += 2;
520
+ srcStart += 4;
521
+ } else {
522
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
523
+ bs.offset += 2;
524
+ srcStart += 12;
525
+ }
526
+ lastPtr = srcStart;
527
+ }
528
+ bs.offset = bs.buffer;
529
+ return srcStart;
530
+ }
531
+ } while (mask !== 0);
532
+ }
533
+
534
+ while (srcStart < srcEnd) {
535
+ const char = load<u16>(srcStart);
536
+ if (char == QUOTE) {
537
+ writeStringToField(dstFieldPtr, payloadStart, <u32>(srcStart - payloadStart));
538
+ return srcStart + 2;
539
+ }
540
+ if (char == BACK_SLASH) {
541
+ bs.offset = bs.buffer;
542
+ bs.ensureSize(<u32>(srcEnd - payloadStart));
543
+ const prefixLen = <u32>(srcStart - payloadStart);
544
+ if (prefixLen != 0) {
545
+ memory.copy(bs.buffer, payloadStart, prefixLen);
546
+ bs.offset += prefixLen;
547
+ }
548
+
549
+ let lastPtr = srcStart;
550
+ const code = load<u16>(srcStart, 2);
551
+ if (code !== 0x75) {
552
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
553
+ bs.offset += 2;
554
+ srcStart += 4;
555
+ } else {
556
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
557
+ bs.offset += 2;
558
+ srcStart += 12;
559
+ }
560
+ lastPtr = srcStart;
561
+
562
+ while (srcStart < srcEnd) {
563
+ const tailChar = load<u16>(srcStart);
564
+ if (tailChar == QUOTE) {
565
+ const runLen = <u32>(srcStart - lastPtr);
566
+ if (runLen != 0) {
567
+ memory.copy(bs.offset, lastPtr, runLen);
568
+ bs.offset += runLen;
569
+ }
570
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
571
+ bs.offset = bs.buffer;
572
+ return srcStart + 2;
573
+ }
574
+ if (tailChar != BACK_SLASH) {
575
+ srcStart += 2;
576
+ continue;
577
+ }
578
+
579
+ const runLen = <u32>(srcStart - lastPtr);
580
+ if (runLen != 0) {
581
+ memory.copy(bs.offset, lastPtr, runLen);
582
+ bs.offset += runLen;
583
+ }
584
+ const tailCode = load<u16>(srcStart, 2);
585
+ if (tailCode !== 0x75) {
586
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + tailCode));
587
+ bs.offset += 2;
588
+ srcStart += 4;
589
+ } else {
590
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
591
+ bs.offset += 2;
592
+ srcStart += 12;
593
+ }
594
+ lastPtr = srcStart;
595
+ }
596
+ bs.offset = bs.buffer;
597
+ return srcStart;
598
+ }
599
+ srcStart += 2;
600
+ }
601
+
602
+ return srcStart;
603
+ }
604
+ */
605
+
606
+ // @ts-expect-error: @inline is a valid decorator
607
+ @inline function deserializeEscapedStringScan_SWAR(payloadStart: usize, escapeStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
608
+ const prefixLen = <u32>(escapeStart - payloadStart);
609
+ const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
610
+ const outStart = bs.offset - bs.buffer;
611
+ bs.ensureSize(<u32>(srcEnd - payloadStart));
612
+ if (prefixLen != 0) {
613
+ memory.copy(bs.offset, payloadStart, prefixLen);
614
+ bs.offset += prefixLen;
615
+ }
616
+
617
+ let lastPtr = escapeStart;
618
+ let srcStart = escapeStart;
619
+
620
+ while (srcStart <= srcEnd8) {
621
+ const blockStart = srcStart;
622
+ let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
623
+ if (mask === 0) {
624
+ srcStart += 8;
625
+ continue;
626
+ }
627
+
628
+ do {
629
+ const laneIdx = usize(ctz(mask) >> 3);
630
+ mask &= mask - 1;
631
+ const srcIdx = srcStart + laneIdx;
632
+ const char = load<u16>(srcIdx);
633
+ if (char == QUOTE) {
634
+ const runLen = <u32>(srcIdx - lastPtr);
635
+ if (runLen != 0) {
636
+ memory.copy(bs.offset, lastPtr, runLen);
637
+ bs.offset += runLen;
638
+ }
639
+ bs.toField(outStart, dstFieldPtr);
640
+ return srcIdx + 2;
641
+ }
642
+ if (char != BACK_SLASH) continue;
643
+
644
+ const runLen = <u32>(srcIdx - lastPtr);
645
+ if (runLen != 0) {
646
+ memory.copy(bs.offset, lastPtr, runLen);
647
+ bs.offset += runLen;
648
+ }
649
+
650
+ const chunk = load<u32>(srcIdx);
651
+ const code = <u16>(chunk >> 16);
652
+ if (code !== 0x75) {
653
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
654
+ bs.offset += 2;
655
+ lastPtr = srcIdx + 4;
656
+ } else {
657
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
658
+ bs.offset += 2;
659
+ lastPtr = srcIdx + 12;
660
+ }
661
+ srcStart = lastPtr;
662
+ break;
663
+ } while (mask !== 0);
664
+ if (srcStart == blockStart) srcStart += 8;
665
+ }
666
+
667
+ while (srcStart < srcEnd) {
668
+ const char = load<u16>(srcStart);
669
+ if (char == QUOTE) {
670
+ const runLen = <u32>(srcStart - lastPtr);
671
+ if (runLen != 0) {
672
+ memory.copy(bs.offset, lastPtr, runLen);
673
+ bs.offset += runLen;
674
+ }
675
+ bs.toField(outStart, dstFieldPtr);
676
+ return srcStart + 2;
677
+ }
678
+ if (char != BACK_SLASH) {
679
+ srcStart += 2;
680
+ continue;
681
+ }
682
+
683
+ const runLen = <u32>(srcStart - lastPtr);
684
+ if (runLen != 0) {
685
+ memory.copy(bs.offset, lastPtr, runLen);
686
+ bs.offset += runLen;
687
+ }
688
+
689
+ const code = load<u16>(srcStart, 2);
690
+ if (code !== 0x75) {
691
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
692
+ bs.offset += 2;
693
+ srcStart += 4;
694
+ } else {
695
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
696
+ bs.offset += 2;
697
+ srcStart += 12;
698
+ }
699
+
700
+ lastPtr = srcStart;
701
+ }
702
+
703
+ bs.offset = bs.buffer + outStart;
704
+ abort("Unterminated string literal");
705
+ return srcStart;
706
+ }
707
+
708
+ // Scans a quoted string value, writes into the destination field, and returns next unread src pointer.
709
+ export function deserializeStringField_SWAR<T extends string | null>(srcStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
710
+ if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE) abort("Expected leading quote");
711
+
712
+ const payloadStart = srcStart + 2;
713
+ const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
714
+ srcStart = payloadStart;
715
+
716
+ while (srcStart <= srcEnd8) {
717
+ let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
718
+ if (mask === 0) {
719
+ srcStart += 8;
720
+ continue;
721
+ }
722
+
723
+ do {
724
+ const laneIdx = usize(ctz(mask) >> 3);
725
+ mask &= mask - 1;
726
+ const srcIdx = srcStart + laneIdx;
727
+ const char = load<u16>(srcIdx);
728
+ if (char == QUOTE) {
729
+ writeStringToField(dstFieldPtr, payloadStart, <u32>(srcIdx - payloadStart));
730
+ return srcIdx + 2;
731
+ }
732
+ if (char != BACK_SLASH) continue;
733
+
734
+ return deserializeEscapedStringScan_SWAR(payloadStart, srcIdx, srcEnd, dstFieldPtr);
735
+ } while (mask !== 0);
736
+
737
+ srcStart += 8;
738
+ }
739
+
740
+ while (srcStart < srcEnd) {
741
+ const char = load<u16>(srcStart);
742
+ if (char == QUOTE) {
743
+ writeStringToField(dstFieldPtr, payloadStart, <u32>(srcStart - payloadStart));
744
+ return srcStart + 2;
745
+ }
746
+ if (char == BACK_SLASH) {
747
+ return deserializeEscapedStringScan_SWAR(payloadStart, srcStart, srcEnd, dstFieldPtr);
748
+ }
749
+ srcStart += 2;
750
+ }
751
+
752
+ abort("Unterminated string literal");
753
+ return srcStart;
754
+ }
755
+
756
+ /**
757
+ * Computes a per-byte mask identifying ASCII backslash or quote bytes.
758
+ *
759
+ * WARNING: Matches in the high byte of a UTF-16 code unit are not filtered,
760
+ * so callers must confirm the hit scalarly.
761
+ * Each matching lane sets itself to 0x80.
762
+ */
763
+ // @ts-expect-error: @inline is a valid decorator
764
+ @inline function backslash_or_quote_mask(block: u64): u64 {
765
+ const b = block ^ 0x005c_005c_005c_005c;
766
+ const q = block ^ 0x0022_0022_0022_0022;
767
+ return (((q - 0x0001_0001_0001_0001) & ~q) | ((b - 0x0001_0001_0001_0001) & ~b)) & 0x0080_0080_0080_0080;
768
+ }
130
769
  /**
131
770
  * Computes a per-lane mask identifying UTF-16 code units whose **low byte**
132
771
  * is the ASCII backslash (`'\\'`, 0x5C).
@@ -141,13 +780,8 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
141
780
  // @ts-expect-error: @inline is a valid decorator
142
781
  @inline function backslash_mask(block: u64): u64 {
143
782
  const b = block ^ 0x005c_005c_005c_005c;
144
- const backslash_mask =
145
- (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
146
- const high_byte_mask =
147
- ~(
148
- ((block - 0x0100_0100_0100_0100) & ~block & 0x8000_8000_8000_8000) ^
149
- 0x8000_8000_8000_8000
150
- ) >> 8;
783
+ const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
784
+ const high_byte_mask = ~(((block - 0x0100_0100_0100_0100) & ~block & 0x8000_8000_8000_8000) ^ 0x8000_8000_8000_8000) >> 8;
151
785
  return backslash_mask & high_byte_mask;
152
786
  }
153
787
 
@@ -163,7 +797,6 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
163
797
  // @ts-expect-error: @inline is a valid decorator
164
798
  @inline function backslash_mask_unsafe(block: u64): u64 {
165
799
  const b = block ^ 0x005c_005c_005c_005c;
166
- const backslash_mask =
167
- (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
800
+ const backslash_mask = (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
168
801
  return backslash_mask;
169
802
  }