json-as 1.3.1 → 1.3.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +9 -26
  2. package/README.md +41 -18
  3. package/assembly/deserialize/index/arbitrary.ts +1 -1
  4. package/assembly/deserialize/index/array.ts +6 -1
  5. package/assembly/deserialize/index/float.ts +1 -1
  6. package/assembly/deserialize/index/integer.ts +1 -1
  7. package/assembly/deserialize/index/unsigned.ts +1 -1
  8. package/assembly/deserialize/simd/string.ts +17 -13
  9. package/assembly/deserialize/simple/arbitrary.ts +1 -1
  10. package/assembly/deserialize/simple/array/generic.ts +42 -0
  11. package/assembly/deserialize/simple/array.ts +8 -1
  12. package/assembly/deserialize/{float.ts → simple/float.ts} +22 -2
  13. package/assembly/deserialize/{integer.ts → simple/integer.ts} +3 -2
  14. package/assembly/deserialize/simple/map.ts +60 -12
  15. package/assembly/deserialize/simple/object.ts +1 -1
  16. package/assembly/deserialize/simple/set.ts +119 -134
  17. package/assembly/deserialize/simple/staticarray.ts +12 -1
  18. package/assembly/deserialize/simple/string.ts +15 -10
  19. package/assembly/deserialize/simple/struct.ts +7 -157
  20. package/assembly/deserialize/simple/typedarray.ts +1 -1
  21. package/assembly/deserialize/{unsigned.ts → simple/unsigned.ts} +3 -2
  22. package/assembly/deserialize/swar/array/array.ts +42 -7
  23. package/assembly/deserialize/swar/array/bool.ts +5 -2
  24. package/assembly/deserialize/swar/array/float.ts +7 -3
  25. package/assembly/deserialize/swar/array/generic.ts +40 -0
  26. package/assembly/deserialize/swar/array/integer.ts +7 -4
  27. package/assembly/deserialize/swar/array/object.ts +20 -4
  28. package/assembly/deserialize/swar/array/shared.ts +18 -4
  29. package/assembly/deserialize/swar/array/string.ts +5 -2
  30. package/assembly/deserialize/swar/array/struct.ts +20 -4
  31. package/assembly/deserialize/swar/array.ts +56 -2
  32. package/assembly/deserialize/swar/string.ts +249 -371
  33. package/assembly/index.ts +74 -17
  34. package/assembly/serialize/index/arbitrary.ts +3 -3
  35. package/assembly/serialize/index/float.ts +1 -1
  36. package/assembly/serialize/index/object.ts +1 -5
  37. package/assembly/serialize/simd/string.ts +4 -5
  38. package/assembly/serialize/simple/arbitrary.ts +3 -3
  39. package/assembly/serialize/simple/array.ts +17 -6
  40. package/assembly/serialize/simple/float.ts +18 -4
  41. package/assembly/serialize/simple/map.ts +10 -27
  42. package/assembly/serialize/simple/object.ts +1 -5
  43. package/assembly/serialize/simple/set.ts +3 -4
  44. package/assembly/serialize/simple/staticarray.ts +4 -3
  45. package/assembly/serialize/simple/typedarray.ts +9 -7
  46. package/assembly/serialize/swar/string.ts +0 -1
  47. package/assembly/tsconfig.json +3 -2
  48. package/assembly/util/dragonbox-cache.ts +1322 -0
  49. package/assembly/util/dragonbox.ts +596 -0
  50. package/lib/as-bs.ts +10 -7
  51. package/package.json +17 -10
  52. package/transform/lib/index.d.ts.map +1 -1
  53. package/transform/lib/index.js +408 -191
  54. package/transform/lib/index.js.map +1 -1
@@ -1,5 +1,6 @@
1
1
  import { bs } from "../../../lib/as-bs";
2
2
  import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
3
+ import { __heap_base } from "memory";
3
4
  import { BACK_SLASH, QUOTE } from "../../custom/chars";
4
5
  import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
5
6
  import { hex4_to_u16_swar } from "../../util/swar";
@@ -184,106 +185,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
184
185
  return copyStringFromSource(payloadStart, srcEnd - payloadStart);
185
186
  }
186
187
 
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.
188
+ // Writes into the destination field, reusing or resizing the backing string.
287
189
  // @ts-expect-error: @inline is a valid decorator
288
190
  @inline function writeStringToField(dstFieldPtr: usize, srcStart: usize, byteLength: u32): void {
289
191
  if (byteLength == 0) {
@@ -293,11 +195,13 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
293
195
 
294
196
  const current = load<usize>(dstFieldPtr);
295
197
  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);
198
+ if (current >= __heap_base) {
199
+ if (changetype<OBJECT>(current - TOTAL_OVERHEAD).rtSize == byteLength) {
200
+ stringPtr = current;
201
+ } else {
202
+ stringPtr = __renew(current, byteLength);
203
+ store<usize>(dstFieldPtr, stringPtr);
204
+ }
301
205
  } else {
302
206
  stringPtr = __new(byteLength, idof<string>());
303
207
  store<usize>(dstFieldPtr, stringPtr);
@@ -305,17 +209,14 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
305
209
  memory.copy(stringPtr, srcStart, byteLength);
306
210
  }
307
211
 
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
212
 
312
- const payloadStart = srcStart + 2;
313
- const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
314
- srcStart = payloadStart;
213
+ // @ts-expect-error: @inline is a valid decorator
214
+ @inline function deserializeEscapedStringContinuation_SWAR(lastPtr: usize, srcStart: usize, srcEnd: usize, dstFieldPtr: usize, outStart: usize): usize {
215
+ const srcEnd8 = srcEnd - 8;
315
216
 
316
217
  while (srcStart <= srcEnd8) {
218
+ const blockStart = srcStart;
317
219
  let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
318
-
319
220
  if (mask === 0) {
320
221
  srcStart += 8;
321
222
  continue;
@@ -323,294 +224,93 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
323
224
 
324
225
  do {
325
226
  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.
227
+ mask &= mask - 1;
328
228
  const srcIdx = srcStart + laneIdx;
329
229
  const char = load<u16>(srcIdx);
330
-
331
230
  if (char == QUOTE) {
332
- writeStringToField(dstFieldPtr, payloadStart, <u32>(srcIdx - payloadStart));
231
+ const runLen = <u32>(srcIdx - lastPtr);
232
+ if (runLen != 0) {
233
+ memory.copy(bs.offset, lastPtr, runLen);
234
+ bs.offset += runLen;
235
+ }
236
+ bs.toField(outStart, dstFieldPtr);
333
237
  return srcIdx + 2;
334
238
  }
335
239
  if (char != BACK_SLASH) continue;
336
240
 
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;
241
+ const runLen = <u32>(srcIdx - lastPtr);
242
+ if (runLen != 0) {
243
+ memory.copy(bs.offset, lastPtr, runLen);
244
+ bs.offset += runLen;
343
245
  }
344
246
 
345
247
  const chunk = load<u32>(srcIdx);
346
248
  const code = <u16>(chunk >> 16);
347
-
348
249
  if (code !== 0x75) {
349
250
  store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
350
251
  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;
252
+ lastPtr = srcIdx + 4;
439
253
  } else {
440
254
  store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
441
255
  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;
256
+ lastPtr = srcIdx + 12;
530
257
  }
258
+ srcStart = lastPtr;
259
+ break;
531
260
  } while (mask !== 0);
261
+
262
+ if (srcStart == blockStart) srcStart += 8;
532
263
  }
533
264
 
534
265
  while (srcStart < srcEnd) {
535
266
  const char = load<u16>(srcStart);
536
267
  if (char == QUOTE) {
537
- writeStringToField(dstFieldPtr, payloadStart, <u32>(srcStart - payloadStart));
268
+ const runLen = <u32>(srcStart - lastPtr);
269
+ if (runLen != 0) {
270
+ memory.copy(bs.offset, lastPtr, runLen);
271
+ bs.offset += runLen;
272
+ }
273
+ bs.toField(outStart, dstFieldPtr);
538
274
  return srcStart + 2;
539
275
  }
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
- }
276
+ if (char != BACK_SLASH) {
277
+ srcStart += 2;
278
+ continue;
279
+ }
548
280
 
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
- }
281
+ const runLen = <u32>(srcStart - lastPtr);
282
+ if (runLen != 0) {
283
+ memory.copy(bs.offset, lastPtr, runLen);
284
+ bs.offset += runLen;
285
+ }
578
286
 
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;
287
+ const code = load<u16>(srcStart, 2);
288
+ if (code !== 0x75) {
289
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
290
+ bs.offset += 2;
291
+ srcStart += 4;
292
+ } else {
293
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
294
+ bs.offset += 2;
295
+ srcStart += 12;
598
296
  }
599
- srcStart += 2;
297
+ lastPtr = srcStart;
600
298
  }
601
299
 
300
+ bs.offset = bs.buffer + outStart;
301
+ abort("Unterminated string literal");
602
302
  return srcStart;
603
303
  }
604
- */
605
304
 
305
+ // Scans a quoted string value, writes into the destination field, and returns next unread src pointer.
606
306
  // @ts-expect-error: @inline is a valid decorator
607
- @inline function deserializeEscapedStringScan_SWAR(payloadStart: usize, escapeStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
307
+ @inline function deserializeEscapedStringScan_SWAR_SplitTuned(payloadStart: usize, escapeStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
608
308
  const prefixLen = <u32>(escapeStart - payloadStart);
609
- const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
610
- const outStart = bs.offset - bs.buffer;
309
+ const srcEnd8 = srcEnd - 8;
310
+ bs.offset = bs.buffer;
611
311
  bs.ensureSize(<u32>(srcEnd - payloadStart));
612
312
  if (prefixLen != 0) {
613
- memory.copy(bs.offset, payloadStart, prefixLen);
313
+ memory.copy(bs.buffer, payloadStart, prefixLen);
614
314
  bs.offset += prefixLen;
615
315
  }
616
316
 
@@ -636,7 +336,8 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
636
336
  memory.copy(bs.offset, lastPtr, runLen);
637
337
  bs.offset += runLen;
638
338
  }
639
- bs.toField(outStart, dstFieldPtr);
339
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
340
+ bs.offset = bs.buffer;
640
341
  return srcIdx + 2;
641
342
  }
642
343
  if (char != BACK_SLASH) continue;
@@ -672,7 +373,8 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
672
373
  memory.copy(bs.offset, lastPtr, runLen);
673
374
  bs.offset += runLen;
674
375
  }
675
- bs.toField(outStart, dstFieldPtr);
376
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
377
+ bs.offset = bs.buffer;
676
378
  return srcStart + 2;
677
379
  }
678
380
  if (char != BACK_SLASH) {
@@ -696,21 +398,197 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
696
398
  bs.offset += 2;
697
399
  srcStart += 12;
698
400
  }
699
-
700
401
  lastPtr = srcStart;
701
402
  }
702
403
 
703
- bs.offset = bs.buffer + outStart;
404
+ bs.offset = bs.buffer;
704
405
  abort("Unterminated string literal");
705
406
  return srcStart;
706
407
  }
707
408
 
708
- // Scans a quoted string value, writes into the destination field, and returns next unread src pointer.
409
+ // @ts-expect-error: @inline is a valid decorator
410
+ @inline function deserializeEscapedStringContinuation_SWAR_MergedTuned(lastPtr: usize, srcStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
411
+ const srcEnd8 = srcEnd - 8;
412
+
413
+ while (srcStart <= srcEnd8) {
414
+ const blockStart = srcStart;
415
+ let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
416
+ if (mask === 0) {
417
+ srcStart += 8;
418
+ continue;
419
+ }
420
+
421
+ do {
422
+ const laneIdx = usize(ctz(mask) >> 3);
423
+ mask &= mask - 1;
424
+ const srcIdx = srcStart + laneIdx;
425
+ const char = load<u16>(srcIdx);
426
+ if (char == QUOTE) {
427
+ const runLen = <u32>(srcIdx - lastPtr);
428
+ if (runLen != 0) {
429
+ memory.copy(bs.offset, lastPtr, runLen);
430
+ bs.offset += runLen;
431
+ }
432
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
433
+ bs.offset = bs.buffer;
434
+ return srcIdx + 2;
435
+ }
436
+ if (char != BACK_SLASH) continue;
437
+
438
+ const runLen = <u32>(srcIdx - lastPtr);
439
+ if (runLen != 0) {
440
+ memory.copy(bs.offset, lastPtr, runLen);
441
+ bs.offset += runLen;
442
+ }
443
+
444
+ const chunk = load<u32>(srcIdx);
445
+ const code = <u16>(chunk >> 16);
446
+ if (code !== 0x75) {
447
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
448
+ bs.offset += 2;
449
+ lastPtr = srcIdx + 4;
450
+ } else {
451
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
452
+ bs.offset += 2;
453
+ lastPtr = srcIdx + 12;
454
+ }
455
+ srcStart = lastPtr;
456
+ break;
457
+ } while (mask !== 0);
458
+
459
+ if (srcStart == blockStart) srcStart += 8;
460
+ }
461
+
462
+ while (srcStart < srcEnd) {
463
+ const tailChar = load<u16>(srcStart);
464
+ if (tailChar == QUOTE) {
465
+ const runLen = <u32>(srcStart - lastPtr);
466
+ if (runLen != 0) {
467
+ memory.copy(bs.offset, lastPtr, runLen);
468
+ bs.offset += runLen;
469
+ }
470
+ writeStringToField(dstFieldPtr, bs.buffer, <u32>(bs.offset - bs.buffer));
471
+ bs.offset = bs.buffer;
472
+ return srcStart + 2;
473
+ }
474
+ if (tailChar != BACK_SLASH) {
475
+ srcStart += 2;
476
+ continue;
477
+ }
478
+
479
+ const runLen = <u32>(srcStart - lastPtr);
480
+ if (runLen != 0) {
481
+ memory.copy(bs.offset, lastPtr, runLen);
482
+ bs.offset += runLen;
483
+ }
484
+ const tailCode = load<u16>(srcStart, 2);
485
+ if (tailCode !== 0x75) {
486
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + tailCode));
487
+ bs.offset += 2;
488
+ srcStart += 4;
489
+ } else {
490
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
491
+ bs.offset += 2;
492
+ srcStart += 12;
493
+ }
494
+ lastPtr = srcStart;
495
+ }
496
+
497
+ bs.offset = bs.buffer;
498
+ return srcStart;
499
+ }
500
+
501
+ function deserializeStringField_SWAR_MergedTuned(srcStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
502
+ if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE) abort("Expected leading quote");
503
+
504
+ const payloadStart = srcStart + 2;
505
+ const srcEnd8 = srcEnd - 8;
506
+ srcStart = payloadStart;
507
+
508
+ while (srcStart <= srcEnd8) {
509
+ let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
510
+ if (mask === 0) {
511
+ srcStart += 8;
512
+ continue;
513
+ }
514
+
515
+ do {
516
+ const laneIdx = usize(ctz(mask) >> 3);
517
+ mask &= ~(0xffff << (laneIdx << 3));
518
+ const srcIdx = srcStart + laneIdx;
519
+ const char = load<u16>(srcIdx);
520
+
521
+ if (char == QUOTE) {
522
+ writeStringToField(dstFieldPtr, payloadStart, <u32>(srcIdx - payloadStart));
523
+ return srcIdx + 2;
524
+ }
525
+ if (char != BACK_SLASH) continue;
526
+
527
+ bs.offset = bs.buffer;
528
+ bs.ensureSize(<u32>(srcEnd - payloadStart));
529
+ const prefixLen = <u32>(srcIdx - payloadStart);
530
+ if (prefixLen != 0) {
531
+ memory.copy(bs.buffer, payloadStart, prefixLen);
532
+ bs.offset += prefixLen;
533
+ }
534
+
535
+ const chunk = load<u32>(srcIdx);
536
+ const code = <u16>(chunk >> 16);
537
+ let lastPtr: usize;
538
+ if (code !== 0x75) {
539
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
540
+ bs.offset += 2;
541
+ lastPtr = srcIdx + 4;
542
+ } else {
543
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcIdx, 4)));
544
+ bs.offset += 2;
545
+ lastPtr = srcIdx + 12;
546
+ }
547
+ return inline.always(deserializeEscapedStringContinuation_SWAR_MergedTuned(lastPtr, lastPtr, srcEnd, dstFieldPtr));
548
+ } while (mask !== 0);
549
+
550
+ srcStart += 8;
551
+ }
552
+
553
+ while (srcStart < srcEnd) {
554
+ const char = load<u16>(srcStart);
555
+ if (char == QUOTE) {
556
+ writeStringToField(dstFieldPtr, payloadStart, <u32>(srcStart - payloadStart));
557
+ return srcStart + 2;
558
+ }
559
+ if (char == BACK_SLASH) {
560
+ bs.offset = bs.buffer;
561
+ bs.ensureSize(<u32>(srcEnd - payloadStart));
562
+ const prefixLen = <u32>(srcStart - payloadStart);
563
+ if (prefixLen != 0) {
564
+ memory.copy(bs.buffer, payloadStart, prefixLen);
565
+ bs.offset += prefixLen;
566
+ }
567
+
568
+ const code = load<u16>(srcStart, 2);
569
+ let lastPtr: usize;
570
+ if (code !== 0x75) {
571
+ store<u16>(bs.offset, load<u16>(DESERIALIZE_ESCAPE_TABLE + code));
572
+ bs.offset += 2;
573
+ lastPtr = srcStart + 4;
574
+ } else {
575
+ store<u16>(bs.offset, hex4_to_u16_swar(load<u64>(srcStart, 4)));
576
+ bs.offset += 2;
577
+ lastPtr = srcStart + 12;
578
+ }
579
+ return inline.always(deserializeEscapedStringContinuation_SWAR_MergedTuned(lastPtr, lastPtr, srcEnd, dstFieldPtr));
580
+ }
581
+ srcStart += 2;
582
+ }
583
+
584
+ return srcStart;
585
+ }
586
+
709
587
  export function deserializeStringField_SWAR<T extends string | null>(srcStart: usize, srcEnd: usize, dstFieldPtr: usize): usize {
710
588
  if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE) abort("Expected leading quote");
711
589
 
712
590
  const payloadStart = srcStart + 2;
713
- const srcEnd8 = srcEnd >= 8 ? srcEnd - 8 : 0;
591
+ const srcEnd8 = srcEnd - 8;
714
592
  srcStart = payloadStart;
715
593
 
716
594
  while (srcStart <= srcEnd8) {
@@ -730,8 +608,7 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
730
608
  return srcIdx + 2;
731
609
  }
732
610
  if (char != BACK_SLASH) continue;
733
-
734
- return deserializeEscapedStringScan_SWAR(payloadStart, srcIdx, srcEnd, dstFieldPtr);
611
+ return inline.always(deserializeEscapedStringScan_SWAR_SplitTuned(payloadStart, srcIdx, srcEnd, dstFieldPtr));
735
612
  } while (mask !== 0);
736
613
 
737
614
  srcStart += 8;
@@ -744,7 +621,7 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
744
621
  return srcStart + 2;
745
622
  }
746
623
  if (char == BACK_SLASH) {
747
- return deserializeEscapedStringScan_SWAR(payloadStart, srcStart, srcEnd, dstFieldPtr);
624
+ return inline.always(deserializeEscapedStringScan_SWAR_SplitTuned(payloadStart, srcStart, srcEnd, dstFieldPtr));
748
625
  }
749
626
  srcStart += 2;
750
627
  }
@@ -753,6 +630,7 @@ export function deserializeStringField_SWAR<T extends string | null>(srcStart: u
753
630
  return srcStart;
754
631
  }
755
632
 
633
+
756
634
  /**
757
635
  * Computes a per-byte mask identifying ASCII backslash or quote bytes.
758
636
  *