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
@@ -0,0 +1,596 @@
1
+ import { DRAGONBOX_F32_CACHE, DRAGONBOX_F64_CACHE } from "./dragonbox-cache";
2
+ import { decimalCount32, itoa_buffered, utoa32_dec_core } from "util/number";
3
+
4
+ const CHAR_MINUS: u16 = 45;
5
+ const CHAR_DOT: u16 = 46;
6
+ const CHAR_0: u16 = 48;
7
+ const CHAR_E: u16 = 101;
8
+ const CHAR_PLUS: u16 = 43;
9
+
10
+ let _dbK: i32 = 0;
11
+ let _dbMulInteger32: u32 = 0;
12
+ let _dbMulInteger64: u64 = 0;
13
+ let _dbMulIsInteger: bool = false;
14
+ let _dbParity: bool = false;
15
+ let _dbRemovedExponent: i32 = 0;
16
+
17
+ @inline
18
+ function rotr32(n: u32, r: i32): u32 {
19
+ const s = r & 31;
20
+ return (n >>> s) | (n << ((32 - s) & 31));
21
+ }
22
+
23
+ @inline
24
+ function rotr64(n: u64, r: i32): u64 {
25
+ const s = r & 63;
26
+ return (n >>> s) | (n << ((64 - s) & 63));
27
+ }
28
+
29
+ @inline
30
+ function floor_log10_pow2(e: i32): i32 {
31
+ return (e * 315653) >> 20;
32
+ }
33
+
34
+ @inline
35
+ function floor_log2_pow10(e: i32): i32 {
36
+ return (e * 1741647) >> 19;
37
+ }
38
+
39
+ @inline
40
+ function floor_log10_pow2_minus_log10_4_over_3(e: i32): i32 {
41
+ return (e * 631305 - 261663) >> 21;
42
+ }
43
+
44
+ @inline
45
+ function floor_log5_pow2(e: i32): i32 {
46
+ return (e * 225799) >> 19;
47
+ }
48
+
49
+ @inline
50
+ function floor_log5_pow2_minus_log5_3(e: i32): i32 {
51
+ return (e * 451597 - 715764) >> 20;
52
+ }
53
+
54
+ @inline
55
+ function umul128_upper64(x: u64, y: u64): u64 {
56
+ const a = <u32>(x >>> 32);
57
+ const b = <u32>x;
58
+ const c = <u32>(y >>> 32);
59
+ const d = <u32>y;
60
+ const ac = <u64>a * c;
61
+ const bc = <u64>b * c;
62
+ const ad = <u64>a * d;
63
+ const bd = <u64>b * d;
64
+ const intermediate = (bd >>> 32) + <u32>ad + <u32>bc;
65
+ return ac + (intermediate >>> 32) + (ad >>> 32) + (bc >>> 32);
66
+ }
67
+
68
+ @inline
69
+ function umul96_upper64(x: u32, y: u64): u64 {
70
+ const yh = <u32>(y >>> 32);
71
+ const yl = <u32>y;
72
+ const xyh = <u64>x * yh;
73
+ const xyl = <u64>x * yl;
74
+ return xyh + (xyl >>> 32);
75
+ }
76
+
77
+ @inline
78
+ function computeMul32(u: u32, cache: u64): void {
79
+ const r = umul96_upper64(u, cache);
80
+ _dbMulInteger32 = <u32>(r >>> 32);
81
+ _dbMulIsInteger = <u32>r == 0;
82
+ }
83
+
84
+ @inline
85
+ function computeMulParity32(twoF: u32, cache: u64, beta: i32): void {
86
+ const r = <u64>twoF * cache;
87
+ _dbParity = ((r >>> (64 - beta)) & 1) != 0;
88
+ _dbMulIsInteger = (<u32>(r >>> (32 - beta))) == 0;
89
+ }
90
+
91
+ @inline
92
+ function computeLeftEndpointShorter32(cache: u64, beta: i32): u32 {
93
+ return <u32>((cache - (cache >>> 25)) >>> (40 - beta));
94
+ }
95
+
96
+ @inline
97
+ function computeRightEndpointShorter32(cache: u64, beta: i32): u32 {
98
+ return <u32>((cache + (cache >>> 24)) >>> (40 - beta));
99
+ }
100
+
101
+ @inline
102
+ function computeRoundUpShorter32(cache: u64, beta: i32): u32 {
103
+ return (<u32>(cache >>> (39 - beta)) + 1) >>> 1;
104
+ }
105
+
106
+ @inline
107
+ function removeTrailingZeros32(significand: u32): u32 {
108
+ let exponent = 0;
109
+ let r = rotr32(significand * 184254097, 4);
110
+ let b = r < 429497;
111
+ let s: u32 = b ? 1 : 0;
112
+ if (b) significand = r;
113
+
114
+ r = rotr32(significand * 42949673, 2);
115
+ b = r < 42949673;
116
+ s = s * 2 + (b ? 1 : 0);
117
+ if (b) significand = r;
118
+
119
+ r = rotr32(significand * 1288490189, 1);
120
+ b = r < 429496730;
121
+ s = s * 2 + (b ? 1 : 0);
122
+ if (b) significand = r;
123
+
124
+ exponent += s;
125
+ _dbRemovedExponent = exponent;
126
+ return significand;
127
+ }
128
+
129
+ @inline
130
+ function divideByPow10_32_1(n: u32): u32 {
131
+ return <u32>((<u64>n * 429496730) >>> 32);
132
+ }
133
+
134
+ @inline
135
+ function divideByPow10_32_2(n: u32): u32 {
136
+ return <u32>((<u64>n * 1374389535) >>> 37);
137
+ }
138
+
139
+ @inline
140
+ function checkDivisibilityAndDivideByPow10_32_1(n: u32): u64 {
141
+ const prod = <u32>(n * 6554);
142
+ return (<u64>(prod >>> 16) << 32) | (((prod & 0xFFFF) < 6554) ? 1 : 0);
143
+ }
144
+
145
+ @inline
146
+ function computeMul64(u: u64, cacheHigh: u64, cacheLow: u64): void {
147
+ const high = umul128_upper64(u, cacheHigh);
148
+
149
+ const a = <u32>(u >>> 32);
150
+ const b = <u32>u;
151
+ const c = <u32>(cacheHigh >>> 32);
152
+ const d = <u32>cacheHigh;
153
+ const ac = <u64>a * c;
154
+ const bc = <u64>b * c;
155
+ const ad = <u64>a * d;
156
+ const bd = <u64>b * d;
157
+ let intermediate = (bd >>> 32) + <u32>ad + <u32>bc;
158
+ let rHigh = ac + (intermediate >>> 32) + (ad >>> 32) + (bc >>> 32);
159
+ let rLow = (intermediate << 32) + <u32>bd;
160
+
161
+ const add = umul128_upper64(u, cacheLow);
162
+ const sumLow = rLow + add;
163
+ rHigh += sumLow < rLow ? 1 : 0;
164
+ rLow = sumLow;
165
+
166
+ _dbMulInteger64 = rHigh;
167
+ _dbMulIsInteger = rLow == 0;
168
+ }
169
+
170
+ @inline
171
+ function computeMulParity64(twoF: u64, cacheHigh: u64, cacheLow: u64, beta: i32): void {
172
+ const high = twoF * cacheHigh;
173
+
174
+ const a = <u32>(twoF >>> 32);
175
+ const b = <u32>twoF;
176
+ const c = <u32>(cacheLow >>> 32);
177
+ const d = <u32>cacheLow;
178
+ const ac = <u64>a * c;
179
+ const bc = <u64>b * c;
180
+ const ad = <u64>a * d;
181
+ const bd = <u64>b * d;
182
+ const intermediate = (bd >>> 32) + <u32>ad + <u32>bc;
183
+ const lowHigh = ac + (intermediate >>> 32) + (ad >>> 32) + (bc >>> 32);
184
+ const lowLow = (intermediate << 32) + <u32>bd;
185
+
186
+ const rHigh = high + lowHigh;
187
+ _dbParity = ((rHigh >>> (64 - beta)) & 1) != 0;
188
+ _dbMulIsInteger = ((((rHigh << beta) & 0xFFFFFFFFFFFFFFFF) | (lowLow >>> (64 - beta))) == 0);
189
+ }
190
+
191
+ @inline
192
+ function computeLeftEndpointShorter64(cacheHigh: u64, beta: i32): u64 {
193
+ return (cacheHigh - (cacheHigh >>> 54)) >>> (11 - beta);
194
+ }
195
+
196
+ @inline
197
+ function computeRightEndpointShorter64(cacheHigh: u64, beta: i32): u64 {
198
+ return (cacheHigh + (cacheHigh >>> 53)) >>> (11 - beta);
199
+ }
200
+
201
+ @inline
202
+ function computeRoundUpShorter64(cacheHigh: u64, beta: i32): u64 {
203
+ return ((cacheHigh >>> (10 - beta)) + 1) >>> 1;
204
+ }
205
+
206
+ @inline
207
+ function removeTrailingZeros64(significand: u64): u64 {
208
+ let exponent = 0;
209
+ let r = rotr64(significand * 28999941890838049, 8);
210
+ let b = r < 184467440738;
211
+ let s: u32 = b ? 1 : 0;
212
+ if (b) significand = r;
213
+
214
+ r = rotr64(significand * 182622766329724561, 4);
215
+ b = r < 1844674407370956;
216
+ s = s * 2 + (b ? 1 : 0);
217
+ if (b) significand = r;
218
+
219
+ r = rotr64(significand * 10330176681277348905, 2);
220
+ b = r < 184467440737095517;
221
+ s = s * 2 + (b ? 1 : 0);
222
+ if (b) significand = r;
223
+
224
+ r = rotr64(significand * 14757395258967641293, 1);
225
+ b = r < 1844674407370955162;
226
+ s = s * 2 + (b ? 1 : 0);
227
+ if (b) significand = r;
228
+
229
+ exponent += s;
230
+ _dbRemovedExponent = exponent;
231
+ return significand;
232
+ }
233
+
234
+ @inline
235
+ function divideByPow10_64_1(n: u64): u64 {
236
+ return umul128_upper64(n, 1844674407370955162);
237
+ }
238
+
239
+ @inline
240
+ function divideByPow10_64_3(n: u64): u64 {
241
+ return umul128_upper64(n, 4722366482869645214) >>> 8;
242
+ }
243
+
244
+ @inline
245
+ function checkDivisibilityAndDivideByPow10_64_2(n: u64): u64 {
246
+ const prod = <u32>(n * 656);
247
+ return (<u64>(prod >>> 16) << 32) | (((prod & 0xFFFF) < 656) ? 1 : 0);
248
+ }
249
+
250
+ @inline
251
+ function genExponent(buffer: usize, k: i32): i32 {
252
+ let negative = k < 0;
253
+ if (negative) k = -k;
254
+ let decimals = decimalCount32(<u32>k) + 1;
255
+ utoa32_dec_core(buffer, <u32>k, <usize>decimals);
256
+ store<u16>(buffer, negative ? CHAR_MINUS : CHAR_PLUS);
257
+ return decimals;
258
+ }
259
+
260
+ function prettify(buffer: usize, length: i32, k: i32): i32 {
261
+ const fast = prettifyFast(buffer, length, k);
262
+ if (fast >= 0) return fast;
263
+
264
+ if (!k) {
265
+ const tail = buffer + (<usize>length << 1);
266
+ store<u16>(tail, CHAR_DOT);
267
+ store<u16>(tail, CHAR_0, 2);
268
+ return length + 2;
269
+ }
270
+
271
+ const kk = length + k;
272
+ 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);
275
+ store<u16>(tail, CHAR_DOT);
276
+ store<u16>(tail, CHAR_0, 2);
277
+ return kk + 2;
278
+ } 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);
282
+ return length + 1;
283
+ } else if (-6 < kk && kk <= 0) {
284
+ const offset = 2 - kk;
285
+ memory.copy(buffer + (<usize>offset << 1), buffer, <usize>length << 1);
286
+ store<u16>(buffer, CHAR_0);
287
+ store<u16>(buffer, CHAR_DOT, 2);
288
+ for (let i = 2; i < offset; ++i) store<u16>(buffer + (<usize>i << 1), CHAR_0);
289
+ return length + offset;
290
+ } else if (length == 1) {
291
+ store<u16>(buffer, CHAR_E, 2);
292
+ length = genExponent(buffer + 4, kk - 1);
293
+ return length + 2;
294
+ } else {
295
+ const len = <usize>length << 1;
296
+ memory.copy(buffer + 4, buffer + 2, len - 2);
297
+ store<u16>(buffer, CHAR_DOT, 2);
298
+ store<u16>(buffer + len, CHAR_E, 2);
299
+ length += genExponent(buffer + len + 4, kk - 1);
300
+ return length + 2;
301
+ }
302
+ }
303
+
304
+ function prettifyFast(buffer: usize, length: i32, k: i32): i32 {
305
+ if (k == 0) {
306
+ const tail = buffer + (<usize>length << 1);
307
+ store<u16>(tail, CHAR_DOT);
308
+ store<u16>(tail, CHAR_0, 2);
309
+ return length + 2;
310
+ }
311
+
312
+ const kk = length + k;
313
+ if (length <= kk && kk <= 21) {
314
+ for (let i = length; i < kk; ++i) {
315
+ store<u16>(buffer + (<usize>i << 1), CHAR_0);
316
+ }
317
+ const tail = buffer + (<usize>kk << 1);
318
+ store<u16>(tail, CHAR_DOT);
319
+ store<u16>(tail, CHAR_0, 2);
320
+ return kk + 2;
321
+ } 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);
325
+ return length + 1;
326
+ } else if (-6 < kk && kk <= 0) {
327
+ const offset = 2 - kk;
328
+ memory.copy(buffer + (<usize>offset << 1), buffer, <usize>length << 1);
329
+ store<u16>(buffer, CHAR_0);
330
+ store<u16>(buffer, CHAR_DOT, 2);
331
+ for (let i = 2; i < offset; ++i) {
332
+ store<u16>(buffer + (<usize>i << 1), CHAR_0);
333
+ }
334
+ return length + offset;
335
+ }
336
+
337
+ return -1;
338
+ }
339
+
340
+ function dragonboxToDecimalF32(binarySignificand: u32, binaryExponent: i32): u32 {
341
+ const isEven = (binarySignificand & 1) == 0;
342
+ let twoFc = binarySignificand << 1;
343
+
344
+ if (binaryExponent != 0) {
345
+ binaryExponent += -150;
346
+ if (twoFc == 0) {
347
+ const minusK = floor_log10_pow2_minus_log10_4_over_3(binaryExponent);
348
+ const beta = binaryExponent + floor_log2_pow10(-minusK);
349
+ const cache = load<u64>(DRAGONBOX_F32_CACHE + (<usize>(31 - minusK) << 3));
350
+ let xi = computeLeftEndpointShorter32(cache, beta);
351
+ const zi = computeRightEndpointShorter32(cache, beta);
352
+ if (!(binaryExponent >= 2 && binaryExponent <= 3)) ++xi;
353
+ let decimalSignificand = divideByPow10_32_1(zi);
354
+ if (decimalSignificand * 10 >= xi) {
355
+ let decimalExponent = minusK + 1;
356
+ decimalSignificand = removeTrailingZeros32(decimalSignificand);
357
+ decimalExponent += _dbRemovedExponent;
358
+ _dbK = decimalExponent;
359
+ return decimalSignificand;
360
+ }
361
+ decimalSignificand = computeRoundUpShorter32(cache, beta);
362
+ if ((decimalSignificand & 1) != 0 && binaryExponent == -35) --decimalSignificand;
363
+ else if (decimalSignificand < xi) ++decimalSignificand;
364
+ _dbK = minusK;
365
+ return decimalSignificand;
366
+ }
367
+ twoFc |= 1 << 24;
368
+ } else {
369
+ binaryExponent = -149;
370
+ }
371
+
372
+ const minusK = floor_log10_pow2(binaryExponent) - 1;
373
+ const cache = load<u64>(DRAGONBOX_F32_CACHE + (<usize>(31 - minusK) << 3));
374
+ const beta = binaryExponent + floor_log2_pow10(-minusK);
375
+ const deltai = <u32>(cache >>> (63 - beta));
376
+
377
+ computeMul32(<u32>((twoFc | 1) << beta), cache);
378
+ let decimalSignificand = divideByPow10_32_2(_dbMulInteger32);
379
+ let r = _dbMulInteger32 - decimalSignificand * 100;
380
+
381
+ if (r < deltai) {
382
+ if ((r | (_dbMulIsInteger ? 0 : 1) | (isEven ? 1 : 0)) == 0) {
383
+ --decimalSignificand;
384
+ r = 100;
385
+ } else {
386
+ let decimalExponent = minusK + 2;
387
+ decimalSignificand = removeTrailingZeros32(decimalSignificand);
388
+ decimalExponent += _dbRemovedExponent;
389
+ _dbK = decimalExponent;
390
+ return decimalSignificand;
391
+ }
392
+ } else if (r == deltai) {
393
+ computeMulParity32(twoFc - 1, cache, beta);
394
+ if (_dbParity || (_dbMulIsInteger && isEven)) {
395
+ let decimalExponent = minusK + 2;
396
+ decimalSignificand = removeTrailingZeros32(decimalSignificand);
397
+ decimalExponent += _dbRemovedExponent;
398
+ _dbK = decimalExponent;
399
+ return decimalSignificand;
400
+ }
401
+ } else if (r < deltai) {
402
+ let decimalExponent = minusK + 2;
403
+ decimalSignificand = removeTrailingZeros32(decimalSignificand);
404
+ decimalExponent += _dbRemovedExponent;
405
+ _dbK = decimalExponent;
406
+ return decimalSignificand;
407
+ }
408
+
409
+ decimalSignificand *= 10;
410
+ let dist = r - (deltai >>> 1) + 5;
411
+ const approxYParity = ((dist ^ 5) & 1) != 0;
412
+ let packedDiv = checkDivisibilityAndDivideByPow10_32_1(dist);
413
+ dist = <u32>(packedDiv >>> 32);
414
+ decimalSignificand += dist;
415
+
416
+ if ((packedDiv & 1) != 0) {
417
+ computeMulParity32(twoFc, cache, beta);
418
+ if (_dbParity != approxYParity) --decimalSignificand;
419
+ else if ((decimalSignificand & 1) != 0 && _dbMulIsInteger) --decimalSignificand;
420
+ }
421
+
422
+ _dbK = minusK + 1;
423
+ return decimalSignificand;
424
+ }
425
+
426
+ function dragonboxToDecimalF64(binarySignificand: u64, binaryExponent: i32): u64 {
427
+ const isEven = (binarySignificand & 1) == 0;
428
+ let twoFc = binarySignificand << 1;
429
+
430
+ if (binaryExponent != 0) {
431
+ binaryExponent += -1075;
432
+ if (twoFc == 0) {
433
+ const minusK = floor_log10_pow2_minus_log10_4_over_3(binaryExponent);
434
+ const beta = binaryExponent + floor_log2_pow10(-minusK);
435
+ const idx = <usize>(292 - minusK) << 4;
436
+ const cacheHigh = load<u64>(DRAGONBOX_F64_CACHE + idx);
437
+ const cacheLow = load<u64>(DRAGONBOX_F64_CACHE + idx + 8);
438
+ let xi = computeLeftEndpointShorter64(cacheHigh, beta);
439
+ const zi = computeRightEndpointShorter64(cacheHigh, beta);
440
+ if (!(binaryExponent >= 2 && binaryExponent <= 3)) ++xi;
441
+ let decimalSignificand = divideByPow10_64_1(zi);
442
+ if (decimalSignificand * 10 >= xi) {
443
+ let decimalExponent = minusK + 1;
444
+ decimalSignificand = removeTrailingZeros64(decimalSignificand);
445
+ decimalExponent += _dbRemovedExponent;
446
+ _dbK = decimalExponent;
447
+ return decimalSignificand;
448
+ }
449
+ decimalSignificand = computeRoundUpShorter64(cacheHigh, beta);
450
+ if ((decimalSignificand & 1) != 0 && binaryExponent == -77) --decimalSignificand;
451
+ else if (decimalSignificand < xi) ++decimalSignificand;
452
+ _dbK = minusK;
453
+ return decimalSignificand;
454
+ }
455
+ twoFc |= (<u64>1) << 53;
456
+ } else {
457
+ binaryExponent = -1074;
458
+ }
459
+
460
+ const minusK = floor_log10_pow2(binaryExponent) - 2;
461
+ const idx = <usize>(292 - minusK) << 4;
462
+ const cacheHigh = load<u64>(DRAGONBOX_F64_CACHE + idx);
463
+ const cacheLow = load<u64>(DRAGONBOX_F64_CACHE + idx + 8);
464
+ const beta = binaryExponent + floor_log2_pow10(-minusK);
465
+ const deltai = cacheHigh >>> (63 - beta);
466
+
467
+ computeMul64((twoFc | 1) << beta, cacheHigh, cacheLow);
468
+ let decimalSignificand = divideByPow10_64_3(_dbMulInteger64);
469
+ let r = _dbMulInteger64 - decimalSignificand * 1000;
470
+
471
+ if (r < deltai) {
472
+ if ((r | (_dbMulIsInteger ? 0 : 1) | (isEven ? 1 : 0)) == 0) {
473
+ --decimalSignificand;
474
+ r = 1000;
475
+ } else {
476
+ let decimalExponent = minusK + 3;
477
+ decimalSignificand = removeTrailingZeros64(decimalSignificand);
478
+ decimalExponent += _dbRemovedExponent;
479
+ _dbK = decimalExponent;
480
+ return decimalSignificand;
481
+ }
482
+ } else if (r == deltai) {
483
+ computeMulParity64(twoFc - 1, cacheHigh, cacheLow, beta);
484
+ if (_dbParity || (_dbMulIsInteger && isEven)) {
485
+ let decimalExponent = minusK + 3;
486
+ decimalSignificand = removeTrailingZeros64(decimalSignificand);
487
+ decimalExponent += _dbRemovedExponent;
488
+ _dbK = decimalExponent;
489
+ return decimalSignificand;
490
+ }
491
+ } else if (r < deltai) {
492
+ let decimalExponent = minusK + 3;
493
+ decimalSignificand = removeTrailingZeros64(decimalSignificand);
494
+ decimalExponent += _dbRemovedExponent;
495
+ _dbK = decimalExponent;
496
+ return decimalSignificand;
497
+ }
498
+
499
+ decimalSignificand *= 10;
500
+ let dist = r - (deltai >>> 1) + 50;
501
+ const approxYParity = ((dist ^ 50) & 1) != 0;
502
+ let packedDiv = checkDivisibilityAndDivideByPow10_64_2(dist);
503
+ dist = packedDiv >>> 32;
504
+ decimalSignificand += dist;
505
+
506
+ if ((packedDiv & 1) != 0) {
507
+ computeMulParity64(twoFc, cacheHigh, cacheLow, beta);
508
+ if (_dbParity != approxYParity) --decimalSignificand;
509
+ else if ((decimalSignificand & 1) != 0 && _dbMulIsInteger) --decimalSignificand;
510
+ }
511
+
512
+ _dbK = minusK + 2;
513
+ return decimalSignificand;
514
+ }
515
+
516
+ function dragonboxCoreF32(buffer: usize, value: f32): u32 {
517
+ let sign = 0;
518
+ if (value < 0) {
519
+ sign = 1;
520
+ value = -value;
521
+ store<u16>(buffer, CHAR_MINUS);
522
+ }
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);
526
+ }
527
+
528
+ function dragonboxCoreF64(buffer: usize, value: f64): u32 {
529
+ let sign = 0;
530
+ if (value < 0) {
531
+ sign = 1;
532
+ value = -value;
533
+ store<u16>(buffer, CHAR_MINUS);
534
+ }
535
+ 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);
539
+ }
540
+
541
+ export function dragonbox_f32_buffered(buffer: usize, value: f32): u32 {
542
+ if (value == 0) {
543
+ store<u16>(buffer, CHAR_0);
544
+ store<u16>(buffer, CHAR_DOT, 2);
545
+ store<u16>(buffer, CHAR_0, 4);
546
+ return 3;
547
+ }
548
+ if (!isFinite(value)) {
549
+ if (isNaN(value)) {
550
+ store<u16>(buffer, 78);
551
+ store<u16>(buffer, 97, 2);
552
+ store<u16>(buffer, 78, 4);
553
+ return 3;
554
+ }
555
+ let sign = value < 0;
556
+ if (sign) {
557
+ store<u16>(buffer, CHAR_MINUS);
558
+ buffer += 2;
559
+ }
560
+ store<u64>(buffer, 0x690066006E0049);
561
+ store<u64>(buffer + 8, 0x7900740069006E);
562
+ return 8 + (sign ? 1 : 0);
563
+ }
564
+ return dragonboxCoreF32(buffer, value);
565
+ }
566
+
567
+ export function dragonbox_f64_buffered(buffer: usize, value: f64): u32 {
568
+ if (value == 0) {
569
+ store<u16>(buffer, CHAR_0);
570
+ store<u16>(buffer, CHAR_DOT, 2);
571
+ store<u16>(buffer, CHAR_0, 4);
572
+ return 3;
573
+ }
574
+ if (!isFinite(value)) {
575
+ if (isNaN(value)) {
576
+ store<u16>(buffer, 78);
577
+ store<u16>(buffer, 97, 2);
578
+ store<u16>(buffer, 78, 4);
579
+ return 3;
580
+ }
581
+ let sign = value < 0;
582
+ if (sign) {
583
+ store<u16>(buffer, CHAR_MINUS);
584
+ buffer += 2;
585
+ }
586
+ store<u64>(buffer, 0x690066006E0049);
587
+ store<u64>(buffer + 8, 0x7900740069006E);
588
+ return 8 + (sign ? 1 : 0);
589
+ }
590
+ return dragonboxCoreF64(buffer, value);
591
+ }
592
+
593
+ export function dragonbox_buffered<T extends number>(buffer: usize, value: T): u32 {
594
+ if (sizeof<T>() == 4) return dragonbox_f32_buffered(buffer, <f32>value);
595
+ return dragonbox_f64_buffered(buffer, <f64>value);
596
+ }
package/lib/as-bs.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
2
- import { heap } from "memory";
2
+ import { __heap_base, heap } from "memory";
3
3
 
4
4
  // Buffer management constants
5
5
  const SHRINK_EVERY_N_MASK: usize = 255; // check every 256 outputs
@@ -190,6 +190,7 @@ export namespace bs {
190
190
  }
191
191
  }
192
192
 
193
+
193
194
  /**
194
195
  * Copies the slice starting at a caller-provided relative buffer offset and restores
195
196
  * `offset` back to that slice start.
@@ -227,12 +228,14 @@ export namespace bs {
227
228
 
228
229
  const current = load<usize>(dstFieldPtr);
229
230
  let stringPtr: usize;
230
- if (current != 0 && changetype<OBJECT>(current - TOTAL_OVERHEAD).rtSize == byteLength) {
231
- stringPtr = current;
232
- } else if (current != 0 && current != changetype<usize>("")) {
233
- // @ts-expect-error: __renew is a runtime builtin
234
- stringPtr = __renew(current, byteLength);
235
- store<usize>(dstFieldPtr, stringPtr);
231
+ if (current >= __heap_base) {
232
+ if (changetype<OBJECT>(current - TOTAL_OVERHEAD).rtSize == byteLength) {
233
+ stringPtr = current;
234
+ } else {
235
+ // @ts-expect-error: __renew is a runtime builtin
236
+ stringPtr = __renew(current, byteLength);
237
+ store<usize>(dstFieldPtr, stringPtr);
238
+ }
236
239
  } else {
237
240
  // @ts-expect-error: __new is a runtime builtin
238
241
  stringPtr = __new(byteLength, idof<string>());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "author": "Jairus Tanaka",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,13 +12,14 @@
12
12
  "@assemblyscript/wasi-shim": "^0.1.0",
13
13
  "@eslint/js": "^9.0.0",
14
14
  "@types/node": "^25.0.10",
15
- "as-test": "^1.0.1",
15
+ "as-test": "^1.0.6",
16
16
  "assemblyscript": "^0.28.9",
17
17
  "assemblyscript-prettier": "^3.0.1",
18
18
  "chartjs-node-canvas": "^5.0.0",
19
19
  "chartjs-plugin-datalabels": "^2.2.0",
20
20
  "eslint": "^10.0.0",
21
21
  "prettier": "3.8.1",
22
+ "serve": "^14.2.6",
22
23
  "tinybench": "^6.0.0",
23
24
  "typescript": "^5.9.3",
24
25
  "typescript-eslint": "^8.0.0"
@@ -40,7 +41,7 @@
40
41
  "Deon Groenewald"
41
42
  ],
42
43
  "description": "The only JSON library you'll need for AssemblyScript with SIMD and SWAR",
43
- "homepage": "https://github.com/JairusSW/json-as#readme",
44
+ "homepage": "https://docs.jairus.dev/json-as",
44
45
  "files": [
45
46
  "assembly/custom/",
46
47
  "assembly/deserialize/",
@@ -80,16 +81,22 @@
80
81
  },
81
82
  "scripts": {
82
83
  "ci": "act",
83
- "test": "ast test --disable coverage --disable try-as",
84
- "test:ci": "ast test --disable coverage --clean",
84
+ "test": "ast test --parallel",
85
+ "test:fast": "npm run build:transform && JSON_USE_FAST_PATH=1 ast test --parallel --mode swar,simd",
86
+ "fuzz": "ast fuzz",
87
+ "test:fuzz": "ast test --fuzz --parallel",
88
+ "test:ci": "ast test --parallel --clean",
89
+ "test:ci:fast": "JSON_USE_FAST_PATH=1 ast test --parallel --clean",
85
90
  "test:coverage": "ast test --enable coverage",
86
- "bench": "npm run bench:as && npm run bench:js && ./build-charts.sh",
87
- "bench:as": "bash ./run-bench.as.sh",
88
- "bench:js": "bash ./run-bench.js.sh",
89
- "bench:publish": "bash ./publish-benchmarks.sh",
91
+ "bench": "npm run bench:as && npm run bench:js && npm run charts:build",
92
+ "bench:as": "bash ./scripts/run-bench.as.sh",
93
+ "bench:js": "bash ./scripts/run-bench.js.sh",
94
+ "charts:build": "bash ./scripts/build-charts.sh",
95
+ "charts:publish": "bash ./scripts/publish-benchmarks.sh",
96
+ "charts:serve": "serve ./build/charts/",
90
97
  "build:test": "JSON_DEBUG=0 JSON_WRITE=assembly/test.ts asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --enable simd --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
91
98
  "build:tmp:test": "JSON_DEBUG=1 asc assembly/test.tmp.ts -o ./build/test.wasm --textFile ./build/test.wat --enable simd --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
92
- "build:test:wine": "JSON_DEBUG=1 JSON_WRITE=assembly/test.ts NODE_SKIP_PLATFORM_CHECK=1 wine ~/.win-bin/node/node.exe ./node_modules/assemblyscript/bin/asc.js assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
99
+ "build:test:wine": "JSON_DEBUG=1 JSON_WRITE=assembly/test.ts NODE_SKIP_PLATFORM_CHECK=1 wineconsole --backend=curses ~/.win-bin/node/node.exe ./node_modules/assemblyscript/bin/asc.js assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
93
100
  "test:wasmtime": "wasmtime ./build/test.wasm",
94
101
  "test:wasmer": "wasmer ./build/test.wasm",
95
102
  "build:transform": "tsc -p ./transform",