json-as 1.3.2 → 1.3.4

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 (34) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +3 -2
  3. package/assembly/deserialize/simd/string.ts +20 -0
  4. package/assembly/deserialize/simple/map.ts +2 -0
  5. package/assembly/deserialize/simple/staticarray.ts +1 -0
  6. package/assembly/deserialize/simple/struct.ts +3 -1
  7. package/assembly/deserialize/swar/array/bool.ts +1 -0
  8. package/assembly/deserialize/swar/array/generic.ts +2 -1
  9. package/assembly/deserialize/swar/array/integer.ts +1 -0
  10. package/assembly/deserialize/swar/array/object.ts +1 -0
  11. package/assembly/deserialize/swar/array/shared.ts +18 -3
  12. package/assembly/deserialize/swar/array/string.ts +1 -0
  13. package/assembly/deserialize/swar/array/struct.ts +1 -0
  14. package/assembly/deserialize/swar/array.ts +1 -0
  15. package/assembly/deserialize/swar/string.ts +21 -2
  16. package/assembly/index.d.ts +1 -0
  17. package/assembly/index.ts +27 -22
  18. package/assembly/serialize/simd/string.ts +43 -16
  19. package/assembly/serialize/simple/array.ts +48 -6
  20. package/assembly/serialize/simple/bool.ts +12 -0
  21. package/assembly/serialize/simple/float.ts +16 -0
  22. package/assembly/serialize/simple/integer.ts +6 -0
  23. package/assembly/serialize/simple/set.ts +59 -5
  24. package/assembly/serialize/simple/staticarray.ts +57 -3
  25. package/assembly/serialize/simple/typedarray.ts +29 -9
  26. package/assembly/serialize/swar/string.ts +165 -18
  27. package/assembly/tsconfig.json +2 -2
  28. package/assembly/util/dragonbox-cache.ts +2 -1320
  29. package/assembly/util/dragonbox.ts +63 -35
  30. package/lib/as-bs.ts +26 -18
  31. package/package.json +11 -10
  32. package/transform/lib/index.d.ts.map +1 -1
  33. package/transform/lib/index.js +288 -73
  34. package/transform/lib/index.js.map +1 -1
@@ -14,43 +14,51 @@ let _dbMulIsInteger: bool = false;
14
14
  let _dbParity: bool = false;
15
15
  let _dbRemovedExponent: i32 = 0;
16
16
 
17
+
17
18
  @inline
18
19
  function rotr32(n: u32, r: i32): u32 {
19
20
  const s = r & 31;
20
21
  return (n >>> s) | (n << ((32 - s) & 31));
21
22
  }
22
23
 
24
+
23
25
  @inline
24
26
  function rotr64(n: u64, r: i32): u64 {
25
27
  const s = r & 63;
26
28
  return (n >>> s) | (n << ((64 - s) & 63));
27
29
  }
28
30
 
31
+
29
32
  @inline
30
33
  function floor_log10_pow2(e: i32): i32 {
31
34
  return (e * 315653) >> 20;
32
35
  }
33
36
 
37
+
34
38
  @inline
35
39
  function floor_log2_pow10(e: i32): i32 {
36
40
  return (e * 1741647) >> 19;
37
41
  }
38
42
 
43
+
39
44
  @inline
40
45
  function floor_log10_pow2_minus_log10_4_over_3(e: i32): i32 {
41
46
  return (e * 631305 - 261663) >> 21;
42
47
  }
43
48
 
49
+
44
50
  @inline
45
51
  function floor_log5_pow2(e: i32): i32 {
46
52
  return (e * 225799) >> 19;
47
53
  }
48
54
 
55
+
49
56
  @inline
50
57
  function floor_log5_pow2_minus_log5_3(e: i32): i32 {
51
58
  return (e * 451597 - 715764) >> 20;
52
59
  }
53
60
 
61
+
54
62
  @inline
55
63
  function umul128_upper64(x: u64, y: u64): u64 {
56
64
  const a = <u32>(x >>> 32);
@@ -65,6 +73,7 @@ function umul128_upper64(x: u64, y: u64): u64 {
65
73
  return ac + (intermediate >>> 32) + (ad >>> 32) + (bc >>> 32);
66
74
  }
67
75
 
76
+
68
77
  @inline
69
78
  function umul96_upper64(x: u32, y: u64): u64 {
70
79
  const yh = <u32>(y >>> 32);
@@ -74,6 +83,7 @@ function umul96_upper64(x: u32, y: u64): u64 {
74
83
  return xyh + (xyl >>> 32);
75
84
  }
76
85
 
86
+
77
87
  @inline
78
88
  function computeMul32(u: u32, cache: u64): void {
79
89
  const r = umul96_upper64(u, cache);
@@ -81,28 +91,33 @@ function computeMul32(u: u32, cache: u64): void {
81
91
  _dbMulIsInteger = <u32>r == 0;
82
92
  }
83
93
 
94
+
84
95
  @inline
85
96
  function computeMulParity32(twoF: u32, cache: u64, beta: i32): void {
86
97
  const r = <u64>twoF * cache;
87
98
  _dbParity = ((r >>> (64 - beta)) & 1) != 0;
88
- _dbMulIsInteger = (<u32>(r >>> (32 - beta))) == 0;
99
+ _dbMulIsInteger = <u32>(r >>> (32 - beta)) == 0;
89
100
  }
90
101
 
102
+
91
103
  @inline
92
104
  function computeLeftEndpointShorter32(cache: u64, beta: i32): u32 {
93
105
  return <u32>((cache - (cache >>> 25)) >>> (40 - beta));
94
106
  }
95
107
 
108
+
96
109
  @inline
97
110
  function computeRightEndpointShorter32(cache: u64, beta: i32): u32 {
98
111
  return <u32>((cache + (cache >>> 24)) >>> (40 - beta));
99
112
  }
100
113
 
114
+
101
115
  @inline
102
116
  function computeRoundUpShorter32(cache: u64, beta: i32): u32 {
103
117
  return (<u32>(cache >>> (39 - beta)) + 1) >>> 1;
104
118
  }
105
119
 
120
+
106
121
  @inline
107
122
  function removeTrailingZeros32(significand: u32): u32 {
108
123
  let exponent = 0;
@@ -126,22 +141,26 @@ function removeTrailingZeros32(significand: u32): u32 {
126
141
  return significand;
127
142
  }
128
143
 
144
+
129
145
  @inline
130
146
  function divideByPow10_32_1(n: u32): u32 {
131
147
  return <u32>((<u64>n * 429496730) >>> 32);
132
148
  }
133
149
 
150
+
134
151
  @inline
135
152
  function divideByPow10_32_2(n: u32): u32 {
136
153
  return <u32>((<u64>n * 1374389535) >>> 37);
137
154
  }
138
155
 
156
+
139
157
  @inline
140
158
  function checkDivisibilityAndDivideByPow10_32_1(n: u32): u64 {
141
159
  const prod = <u32>(n * 6554);
142
- return (<u64>(prod >>> 16) << 32) | (((prod & 0xFFFF) < 6554) ? 1 : 0);
160
+ return ((<u64>(prod >>> 16)) << 32) | ((prod & 0xffff) < 6554 ? 1 : 0);
143
161
  }
144
162
 
163
+
145
164
  @inline
146
165
  function computeMul64(u: u64, cacheHigh: u64, cacheLow: u64): void {
147
166
  const high = umul128_upper64(u, cacheHigh);
@@ -167,6 +186,7 @@ function computeMul64(u: u64, cacheHigh: u64, cacheLow: u64): void {
167
186
  _dbMulIsInteger = rLow == 0;
168
187
  }
169
188
 
189
+
170
190
  @inline
171
191
  function computeMulParity64(twoF: u64, cacheHigh: u64, cacheLow: u64, beta: i32): void {
172
192
  const high = twoF * cacheHigh;
@@ -185,24 +205,28 @@ function computeMulParity64(twoF: u64, cacheHigh: u64, cacheLow: u64, beta: i32)
185
205
 
186
206
  const rHigh = high + lowHigh;
187
207
  _dbParity = ((rHigh >>> (64 - beta)) & 1) != 0;
188
- _dbMulIsInteger = ((((rHigh << beta) & 0xFFFFFFFFFFFFFFFF) | (lowLow >>> (64 - beta))) == 0);
208
+ _dbMulIsInteger = (((rHigh << beta) & 0xffffffffffffffff) | (lowLow >>> (64 - beta))) == 0;
189
209
  }
190
210
 
211
+
191
212
  @inline
192
213
  function computeLeftEndpointShorter64(cacheHigh: u64, beta: i32): u64 {
193
214
  return (cacheHigh - (cacheHigh >>> 54)) >>> (11 - beta);
194
215
  }
195
216
 
217
+
196
218
  @inline
197
219
  function computeRightEndpointShorter64(cacheHigh: u64, beta: i32): u64 {
198
220
  return (cacheHigh + (cacheHigh >>> 53)) >>> (11 - beta);
199
221
  }
200
222
 
223
+
201
224
  @inline
202
225
  function computeRoundUpShorter64(cacheHigh: u64, beta: i32): u64 {
203
226
  return ((cacheHigh >>> (10 - beta)) + 1) >>> 1;
204
227
  }
205
228
 
229
+
206
230
  @inline
207
231
  function removeTrailingZeros64(significand: u64): u64 {
208
232
  let exponent = 0;
@@ -231,22 +255,26 @@ function removeTrailingZeros64(significand: u64): u64 {
231
255
  return significand;
232
256
  }
233
257
 
258
+
234
259
  @inline
235
260
  function divideByPow10_64_1(n: u64): u64 {
236
261
  return umul128_upper64(n, 1844674407370955162);
237
262
  }
238
263
 
264
+
239
265
  @inline
240
266
  function divideByPow10_64_3(n: u64): u64 {
241
267
  return umul128_upper64(n, 4722366482869645214) >>> 8;
242
268
  }
243
269
 
270
+
244
271
  @inline
245
272
  function checkDivisibilityAndDivideByPow10_64_2(n: u64): u64 {
246
273
  const prod = <u32>(n * 656);
247
- return (<u64>(prod >>> 16) << 32) | (((prod & 0xFFFF) < 656) ? 1 : 0);
274
+ return ((<u64>(prod >>> 16)) << 32) | ((prod & 0xffff) < 656 ? 1 : 0);
248
275
  }
249
276
 
277
+
250
278
  @inline
251
279
  function genExponent(buffer: usize, k: i32): i32 {
252
280
  let negative = k < 0;
@@ -262,7 +290,7 @@ function prettify(buffer: usize, length: i32, k: i32): i32 {
262
290
  if (fast >= 0) return fast;
263
291
 
264
292
  if (!k) {
265
- const tail = buffer + (<usize>length << 1);
293
+ const tail = buffer + ((<usize>length) << 1);
266
294
  store<u16>(tail, CHAR_DOT);
267
295
  store<u16>(tail, CHAR_0, 2);
268
296
  return length + 2;
@@ -270,29 +298,29 @@ function prettify(buffer: usize, length: i32, k: i32): i32 {
270
298
 
271
299
  const kk = length + k;
272
300
  if (length <= kk && kk <= 21) {
273
- for (let i = length; i < kk; ++i) store<u16>(buffer + (<usize>i << 1), CHAR_0);
274
- const tail = buffer + (<usize>kk << 1);
301
+ for (let i = length; i < kk; ++i) store<u16>(buffer + ((<usize>i) << 1), CHAR_0);
302
+ const tail = buffer + ((<usize>kk) << 1);
275
303
  store<u16>(tail, CHAR_DOT);
276
304
  store<u16>(tail, CHAR_0, 2);
277
305
  return kk + 2;
278
306
  } else if (kk > 0 && kk <= 21) {
279
- const ptr = buffer + (<usize>kk << 1);
280
- memory.copy(ptr + 2, ptr, <usize>(-k) << 1);
281
- store<u16>(buffer + (<usize>kk << 1), CHAR_DOT);
307
+ const ptr = buffer + ((<usize>kk) << 1);
308
+ memory.copy(ptr + 2, ptr, (<usize>-k) << 1);
309
+ store<u16>(buffer + ((<usize>kk) << 1), CHAR_DOT);
282
310
  return length + 1;
283
311
  } else if (-6 < kk && kk <= 0) {
284
312
  const offset = 2 - kk;
285
- memory.copy(buffer + (<usize>offset << 1), buffer, <usize>length << 1);
313
+ memory.copy(buffer + ((<usize>offset) << 1), buffer, (<usize>length) << 1);
286
314
  store<u16>(buffer, CHAR_0);
287
315
  store<u16>(buffer, CHAR_DOT, 2);
288
- for (let i = 2; i < offset; ++i) store<u16>(buffer + (<usize>i << 1), CHAR_0);
316
+ for (let i = 2; i < offset; ++i) store<u16>(buffer + ((<usize>i) << 1), CHAR_0);
289
317
  return length + offset;
290
318
  } else if (length == 1) {
291
319
  store<u16>(buffer, CHAR_E, 2);
292
320
  length = genExponent(buffer + 4, kk - 1);
293
321
  return length + 2;
294
322
  } else {
295
- const len = <usize>length << 1;
323
+ const len = (<usize>length) << 1;
296
324
  memory.copy(buffer + 4, buffer + 2, len - 2);
297
325
  store<u16>(buffer, CHAR_DOT, 2);
298
326
  store<u16>(buffer + len, CHAR_E, 2);
@@ -303,7 +331,7 @@ function prettify(buffer: usize, length: i32, k: i32): i32 {
303
331
 
304
332
  function prettifyFast(buffer: usize, length: i32, k: i32): i32 {
305
333
  if (k == 0) {
306
- const tail = buffer + (<usize>length << 1);
334
+ const tail = buffer + ((<usize>length) << 1);
307
335
  store<u16>(tail, CHAR_DOT);
308
336
  store<u16>(tail, CHAR_0, 2);
309
337
  return length + 2;
@@ -312,24 +340,24 @@ function prettifyFast(buffer: usize, length: i32, k: i32): i32 {
312
340
  const kk = length + k;
313
341
  if (length <= kk && kk <= 21) {
314
342
  for (let i = length; i < kk; ++i) {
315
- store<u16>(buffer + (<usize>i << 1), CHAR_0);
343
+ store<u16>(buffer + ((<usize>i) << 1), CHAR_0);
316
344
  }
317
- const tail = buffer + (<usize>kk << 1);
345
+ const tail = buffer + ((<usize>kk) << 1);
318
346
  store<u16>(tail, CHAR_DOT);
319
347
  store<u16>(tail, CHAR_0, 2);
320
348
  return kk + 2;
321
349
  } else if (kk > 0 && kk <= 21) {
322
- const ptr = buffer + (<usize>kk << 1);
323
- memory.copy(ptr + 2, ptr, <usize>(length - kk) << 1);
324
- store<u16>(buffer + (<usize>kk << 1), CHAR_DOT);
350
+ const ptr = buffer + ((<usize>kk) << 1);
351
+ memory.copy(ptr + 2, ptr, (<usize>(length - kk)) << 1);
352
+ store<u16>(buffer + ((<usize>kk) << 1), CHAR_DOT);
325
353
  return length + 1;
326
354
  } else if (-6 < kk && kk <= 0) {
327
355
  const offset = 2 - kk;
328
- memory.copy(buffer + (<usize>offset << 1), buffer, <usize>length << 1);
356
+ memory.copy(buffer + ((<usize>offset) << 1), buffer, (<usize>length) << 1);
329
357
  store<u16>(buffer, CHAR_0);
330
358
  store<u16>(buffer, CHAR_DOT, 2);
331
359
  for (let i = 2; i < offset; ++i) {
332
- store<u16>(buffer + (<usize>i << 1), CHAR_0);
360
+ store<u16>(buffer + ((<usize>i) << 1), CHAR_0);
333
361
  }
334
362
  return length + offset;
335
363
  }
@@ -346,7 +374,7 @@ function dragonboxToDecimalF32(binarySignificand: u32, binaryExponent: i32): u32
346
374
  if (twoFc == 0) {
347
375
  const minusK = floor_log10_pow2_minus_log10_4_over_3(binaryExponent);
348
376
  const beta = binaryExponent + floor_log2_pow10(-minusK);
349
- const cache = load<u64>(DRAGONBOX_F32_CACHE + (<usize>(31 - minusK) << 3));
377
+ const cache = load<u64>(DRAGONBOX_F32_CACHE + ((<usize>(31 - minusK)) << 3));
350
378
  let xi = computeLeftEndpointShorter32(cache, beta);
351
379
  const zi = computeRightEndpointShorter32(cache, beta);
352
380
  if (!(binaryExponent >= 2 && binaryExponent <= 3)) ++xi;
@@ -370,7 +398,7 @@ function dragonboxToDecimalF32(binarySignificand: u32, binaryExponent: i32): u32
370
398
  }
371
399
 
372
400
  const minusK = floor_log10_pow2(binaryExponent) - 1;
373
- const cache = load<u64>(DRAGONBOX_F32_CACHE + (<usize>(31 - minusK) << 3));
401
+ const cache = load<u64>(DRAGONBOX_F32_CACHE + ((<usize>(31 - minusK)) << 3));
374
402
  const beta = binaryExponent + floor_log2_pow10(-minusK);
375
403
  const deltai = <u32>(cache >>> (63 - beta));
376
404
 
@@ -432,7 +460,7 @@ function dragonboxToDecimalF64(binarySignificand: u64, binaryExponent: i32): u64
432
460
  if (twoFc == 0) {
433
461
  const minusK = floor_log10_pow2_minus_log10_4_over_3(binaryExponent);
434
462
  const beta = binaryExponent + floor_log2_pow10(-minusK);
435
- const idx = <usize>(292 - minusK) << 4;
463
+ const idx = (<usize>(292 - minusK)) << 4;
436
464
  const cacheHigh = load<u64>(DRAGONBOX_F64_CACHE + idx);
437
465
  const cacheLow = load<u64>(DRAGONBOX_F64_CACHE + idx + 8);
438
466
  let xi = computeLeftEndpointShorter64(cacheHigh, beta);
@@ -458,7 +486,7 @@ function dragonboxToDecimalF64(binarySignificand: u64, binaryExponent: i32): u64
458
486
  }
459
487
 
460
488
  const minusK = floor_log10_pow2(binaryExponent) - 2;
461
- const idx = <usize>(292 - minusK) << 4;
489
+ const idx = (<usize>(292 - minusK)) << 4;
462
490
  const cacheHigh = load<u64>(DRAGONBOX_F64_CACHE + idx);
463
491
  const cacheLow = load<u64>(DRAGONBOX_F64_CACHE + idx + 8);
464
492
  const beta = binaryExponent + floor_log2_pow10(-minusK);
@@ -520,9 +548,9 @@ function dragonboxCoreF32(buffer: usize, value: f32): u32 {
520
548
  value = -value;
521
549
  store<u16>(buffer, CHAR_MINUS);
522
550
  }
523
- const digits = dragonboxToDecimalF32(reinterpret<u32>(value) & 0x7FFFFF, (reinterpret<u32>(value) >>> 23) & 0xFF);
524
- let len = itoa_buffered<u32>(buffer + (<usize>sign << 1), digits);
525
- return <u32>(prettify(buffer + (<usize>sign << 1), len, _dbK) + sign);
551
+ const digits = dragonboxToDecimalF32(reinterpret<u32>(value) & 0x7fffff, (reinterpret<u32>(value) >>> 23) & 0xff);
552
+ let len = itoa_buffered<u32>(buffer + ((<usize>sign) << 1), digits);
553
+ return <u32>(prettify(buffer + ((<usize>sign) << 1), len, _dbK) + sign);
526
554
  }
527
555
 
528
556
  function dragonboxCoreF64(buffer: usize, value: f64): u32 {
@@ -533,9 +561,9 @@ function dragonboxCoreF64(buffer: usize, value: f64): u32 {
533
561
  store<u16>(buffer, CHAR_MINUS);
534
562
  }
535
563
  const bits = reinterpret<u64>(value);
536
- const digits = dragonboxToDecimalF64(bits & 0x000FFFFFFFFFFFFF, <i32>((bits >>> 52) & 0x7FF));
537
- let len = itoa_buffered<u64>(buffer + (<usize>sign << 1), digits);
538
- return <u32>(prettify(buffer + (<usize>sign << 1), len, _dbK) + sign);
564
+ const digits = dragonboxToDecimalF64(bits & 0x000fffffffffffff, <i32>((bits >>> 52) & 0x7ff));
565
+ let len = itoa_buffered<u64>(buffer + ((<usize>sign) << 1), digits);
566
+ return <u32>(prettify(buffer + ((<usize>sign) << 1), len, _dbK) + sign);
539
567
  }
540
568
 
541
569
  export function dragonbox_f32_buffered(buffer: usize, value: f32): u32 {
@@ -557,8 +585,8 @@ export function dragonbox_f32_buffered(buffer: usize, value: f32): u32 {
557
585
  store<u16>(buffer, CHAR_MINUS);
558
586
  buffer += 2;
559
587
  }
560
- store<u64>(buffer, 0x690066006E0049);
561
- store<u64>(buffer + 8, 0x7900740069006E);
588
+ store<u64>(buffer, 0x690066006e0049);
589
+ store<u64>(buffer + 8, 0x7900740069006e);
562
590
  return 8 + (sign ? 1 : 0);
563
591
  }
564
592
  return dragonboxCoreF32(buffer, value);
@@ -583,8 +611,8 @@ export function dragonbox_f64_buffered(buffer: usize, value: f64): u32 {
583
611
  store<u16>(buffer, CHAR_MINUS);
584
612
  buffer += 2;
585
613
  }
586
- store<u64>(buffer, 0x690066006E0049);
587
- store<u64>(buffer + 8, 0x7900740069006E);
614
+ store<u64>(buffer, 0x690066006e0049);
615
+ store<u64>(buffer + 8, 0x7900740069006e);
588
616
  return 8 + (sign ? 1 : 0);
589
617
  }
590
618
  return dragonboxCoreF64(buffer, value);
package/lib/as-bs.ts CHANGED
@@ -190,7 +190,6 @@ export namespace bs {
190
190
  }
191
191
  }
192
192
 
193
-
194
193
  /**
195
194
  * Copies the slice starting at a caller-provided relative buffer offset and restores
196
195
  * `offset` back to that slice start.
@@ -287,18 +286,21 @@ export namespace bs {
287
286
  *
288
287
  * Enable caching by setting the `JSON_CACHE` environment variable:
289
288
  * ```bash
290
- * JSON_CACHE=1 npx asc your-file.ts --transform json-as/transform
289
+ * JSON_CACHE=true npx asc your-file.ts --transform json-as/transform
291
290
  * ```
292
291
  *
293
- * ## Memory Configuration
292
+ * You can also configure cache size directly:
293
+ * - `JSON_CACHE=<int>` => bytes
294
+ * - `JSON_CACHE=<int>kb|mb|gb` => kilobits/megabits/gigabits
295
+ * - `JSON_CACHE=<int>KB|MB|GB` => kilobytes/megabytes/gigabytes
294
296
  *
295
- * The cache uses the following fixed memory allocations:
297
+ * ## Memory Configuration
296
298
  *
297
- * - **CACHE_SIZE** (4096 entries): Number of cache slots. Uses direct-mapped
298
- * caching with pointer-based indexing. Collisions will evict previous entries.
299
- * Memory usage: ~49KB (4096 * 12 bytes per entry)
299
+ * The cache uses a size budget from `JSON_CACHE` (or defaults to 1MB when
300
+ * enabled with `true/on/yes`):
300
301
  *
301
- * - **ARENA_SIZE** (1MB): Circular buffer for storing cached serialized strings.
302
+ * - **CACHE_SIZE**: Number of direct-mapped cache slots. Derived from budget.
303
+ * - **ARENA_SIZE**: Circular buffer for storing cached serialized strings.
302
304
  * When full, wraps around and overwrites oldest entries. Larger values retain
303
305
  * more cached data but consume more memory.
304
306
  *
@@ -325,16 +327,20 @@ export namespace sc {
325
327
  // @ts-expect-error: @inline is a valid decorator
326
328
  @inline export const ENTRY_LEN = offsetof<sc.Entry>("len");
327
329
 
328
- /** Number of cache slots (power of 2 for efficient masking). Set to 0 when caching disabled. */
329
- // @ts-expect-error: JSON_CACHE may not be defined. If so, it will default to 0.
330
- export const CACHE_SIZE = isDefined(JSON_CACHE) ? 1024 : 0;
331
- /** Bitmask for fast modulo operation on cache index */
332
- export const CACHE_MASK = CACHE_SIZE - 1;
333
-
334
- /** Size of the circular arena buffer for cached strings (1MB) */
335
- export const ARENA_SIZE = 1 << 20;
330
+ // @ts-expect-error: JSON_CACHE may not be defined. If so, it will default to false.
331
+ export const CACHE_ENABLED: bool = isDefined(JSON_CACHE) ? JSON_CACHE : false;
332
+ // @ts-expect-error: JSON_CACHE_SIZE may not be defined. If so, it will default to 1MB.
333
+ export const CACHE_BYTES: usize = isDefined(JSON_CACHE_SIZE) ? <usize>JSON_CACHE_SIZE : (1 << 20);
336
334
  /** Minimum serialized length to cache - smaller outputs aren't worth caching */
337
335
  export const MIN_CACHE_LEN: usize = 128;
336
+ /** Size of the circular arena buffer for cached strings */
337
+ export const ARENA_SIZE: usize = CACHE_BYTES >= MIN_CACHE_LEN ? CACHE_BYTES : MIN_CACHE_LEN;
338
+
339
+ /** Number of cache slots (power of 2 for efficient masking). Set to 0 when caching disabled. */
340
+ const CACHE_SIZE_BASE: i32 = CACHE_ENABLED ? i32((ARENA_SIZE >> 10) >= 1 ? (ARENA_SIZE >> 10) : 1) : 0;
341
+ export const CACHE_SIZE: usize = CACHE_ENABLED ? <usize>(1 << (32 - clz<i32>(CACHE_SIZE_BASE - 1))) : 0;
342
+ /** Bitmask for fast modulo operation on cache index */
343
+ export const CACHE_MASK: usize = CACHE_SIZE > 0 ? CACHE_SIZE - 1 : 0;
338
344
 
339
345
  /** Cache entry structure - stores pointer to string, cached output location, and length */
340
346
  @unmanaged
@@ -348,9 +354,9 @@ export namespace sc {
348
354
  }
349
355
 
350
356
  /** Static array of cache entries */
351
- export const entries = new StaticArray<sc.Entry>(CACHE_SIZE);
357
+ export const entries = new StaticArray<sc.Entry>(i32(CACHE_SIZE));
352
358
  /** Circular buffer arena for storing cached serialized strings */
353
- export const arena = new ArrayBuffer(ARENA_SIZE);
359
+ export const arena = new ArrayBuffer(i32(ARENA_SIZE));
354
360
  /** Current write position in the arena */
355
361
  export let arenaPtr: usize = changetype<usize>(arena);
356
362
  /** End boundary of the arena */
@@ -394,7 +400,9 @@ export namespace sc {
394
400
  * @param len - Length of serialized output
395
401
  */
396
402
  export function insertCached(str: usize, start: usize, len: usize): void {
403
+ if (!CACHE_ENABLED || ARENA_SIZE == 0) return;
397
404
  if (len < MIN_CACHE_LEN) return;
405
+ if (len > ARENA_SIZE) return;
398
406
  if (arenaPtr + len > arenaEnd) {
399
407
  // Wrap around to beginning of arena (circular buffer)
400
408
  arenaPtr = changetype<usize>(arena);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "author": "Jairus Tanaka",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,19 +10,19 @@
10
10
  "main": "transform/lib/index.js",
11
11
  "devDependencies": {
12
12
  "@assemblyscript/wasi-shim": "^0.1.0",
13
- "@eslint/js": "^9.0.0",
14
- "@types/node": "^25.0.10",
15
- "as-test": "^1.0.6",
16
- "assemblyscript": "^0.28.9",
17
- "assemblyscript-prettier": "^3.0.1",
13
+ "@eslint/js": "^10.0.1",
14
+ "@types/node": "^25.6.0",
15
+ "as-test": "^1.0.7",
16
+ "assemblyscript": "^0.28.14",
17
+ "assemblyscript-prettier": "^3.0.4",
18
18
  "chartjs-node-canvas": "^5.0.0",
19
19
  "chartjs-plugin-datalabels": "^2.2.0",
20
- "eslint": "^10.0.0",
21
- "prettier": "3.8.1",
20
+ "eslint": "^10.2.0",
21
+ "prettier": "3.8.3",
22
22
  "serve": "^14.2.6",
23
23
  "tinybench": "^6.0.0",
24
- "typescript": "^5.9.3",
25
- "typescript-eslint": "^8.0.0"
24
+ "typescript": "^6.0.2",
25
+ "typescript-eslint": "^8.58.2"
26
26
  },
27
27
  "bugs": {
28
28
  "url": "https://github.com/JairusSW/json-as/issues"
@@ -91,6 +91,7 @@
91
91
  "bench": "npm run bench:as && npm run bench:js && npm run charts:build",
92
92
  "bench:as": "bash ./scripts/run-bench.as.sh",
93
93
  "bench:js": "bash ./scripts/run-bench.js.sh",
94
+ "charts": "bun run charts:build && bun run charts:serve",
94
95
  "charts:build": "bash ./scripts/build-charts.sh",
95
96
  "charts:publish": "bash ./scripts/publish-benchmarks.sh",
96
97
  "charts:serve": "serve ./build/charts/",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA4G,eAAe,EAA8G,MAAM,EAAE,OAAO,EAAS,MAAM,EAA6C,MAAM,uCAAuC,CAAC;AAC3X,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAK7D,OAAO,EAA2B,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAkFvC,qBAAa,aAAc,SAAQ,OAAO;IACxC,MAAM,CAAC,EAAE,EAAE,aAAa,CAAuB;IAExC,OAAO,EAAG,OAAO,CAAC;IAClB,OAAO,EAAG,MAAM,CAAC;IACjB,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAA+B;IAC7D,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,CAAmB;IACrC,OAAO,EAAE,eAAe,EAAE,CAAM;IAChC,cAAc,EAAE,MAAM,EAAE,CAAM;IAE9B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAqB;IAEvD,OAAO,CAAC,4BAA4B;IA6CpC,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAYtD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,cAAoB,GAAG,MAAM;IAsC3E,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAy7CnD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItC,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IA4ClD,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIjD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA+J9B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,OAAe,GAAG,MAAM,EAAE;IA0BxD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO;CAc3D;AA4BD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,SAAS;IAChD,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBvD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAwDjC;AAoKD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA4G,eAAe,EAA8G,MAAM,EAAE,OAAO,EAAS,MAAM,EAA6C,MAAM,uCAAuC,CAAC;AAC3X,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAK7D,OAAO,EAA2B,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAuJvC,qBAAa,aAAc,SAAQ,OAAO;IACxC,MAAM,CAAC,EAAE,EAAE,aAAa,CAAuB;IAExC,OAAO,EAAG,OAAO,CAAC;IAClB,OAAO,EAAG,MAAM,CAAC;IACjB,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAA+B;IAC7D,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,CAAmB;IACrC,OAAO,EAAE,eAAe,EAAE,CAAM;IAChC,cAAc,EAAE,MAAM,EAAE,CAAM;IAE9B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAqB;IAEvD,OAAO,CAAC,4BAA4B;IA6CpC,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAYtD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,cAAoB,GAAG,MAAM;IAsC3E,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAuiDnD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItC,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IA4ClD,oBAAoB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIjD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA+J9B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,OAAe,GAAG,MAAM,EAAE;IA0BxD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO;CAc3D;AA4BD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,SAAS;IAChD,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBvD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAwDjC;AA+MD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C"}