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.
- package/CHANGELOG.md +9 -26
- package/README.md +41 -18
- package/assembly/deserialize/index/arbitrary.ts +1 -1
- package/assembly/deserialize/index/array.ts +6 -1
- package/assembly/deserialize/index/float.ts +1 -1
- package/assembly/deserialize/index/integer.ts +1 -1
- package/assembly/deserialize/index/unsigned.ts +1 -1
- package/assembly/deserialize/simd/string.ts +17 -13
- package/assembly/deserialize/simple/arbitrary.ts +1 -1
- package/assembly/deserialize/simple/array/generic.ts +42 -0
- package/assembly/deserialize/simple/array.ts +8 -1
- package/assembly/deserialize/{float.ts → simple/float.ts} +22 -2
- package/assembly/deserialize/{integer.ts → simple/integer.ts} +3 -2
- package/assembly/deserialize/simple/map.ts +60 -12
- package/assembly/deserialize/simple/object.ts +1 -1
- package/assembly/deserialize/simple/set.ts +119 -134
- package/assembly/deserialize/simple/staticarray.ts +12 -1
- package/assembly/deserialize/simple/string.ts +15 -10
- package/assembly/deserialize/simple/struct.ts +7 -157
- package/assembly/deserialize/simple/typedarray.ts +1 -1
- package/assembly/deserialize/{unsigned.ts → simple/unsigned.ts} +3 -2
- package/assembly/deserialize/swar/array/array.ts +42 -7
- package/assembly/deserialize/swar/array/bool.ts +5 -2
- package/assembly/deserialize/swar/array/float.ts +7 -3
- package/assembly/deserialize/swar/array/generic.ts +40 -0
- package/assembly/deserialize/swar/array/integer.ts +7 -4
- package/assembly/deserialize/swar/array/object.ts +20 -4
- package/assembly/deserialize/swar/array/shared.ts +18 -4
- package/assembly/deserialize/swar/array/string.ts +5 -2
- package/assembly/deserialize/swar/array/struct.ts +20 -4
- package/assembly/deserialize/swar/array.ts +56 -2
- package/assembly/deserialize/swar/string.ts +249 -371
- package/assembly/index.ts +74 -17
- package/assembly/serialize/index/arbitrary.ts +3 -3
- package/assembly/serialize/index/float.ts +1 -1
- package/assembly/serialize/index/object.ts +1 -5
- package/assembly/serialize/simd/string.ts +4 -5
- package/assembly/serialize/simple/arbitrary.ts +3 -3
- package/assembly/serialize/simple/array.ts +17 -6
- package/assembly/serialize/simple/float.ts +18 -4
- package/assembly/serialize/simple/map.ts +10 -27
- package/assembly/serialize/simple/object.ts +1 -5
- package/assembly/serialize/simple/set.ts +3 -4
- package/assembly/serialize/simple/staticarray.ts +4 -3
- package/assembly/serialize/simple/typedarray.ts +9 -7
- package/assembly/serialize/swar/string.ts +0 -1
- package/assembly/tsconfig.json +3 -2
- package/assembly/util/dragonbox-cache.ts +1322 -0
- package/assembly/util/dragonbox.ts +596 -0
- package/lib/as-bs.ts +10 -7
- package/package.json +17 -10
- package/transform/lib/index.d.ts.map +1 -1
- package/transform/lib/index.js +408 -191
- 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
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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.
|
|
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.
|
|
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://
|
|
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 --
|
|
84
|
-
"test:
|
|
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 &&
|
|
87
|
-
"bench:as": "bash ./run-bench.as.sh",
|
|
88
|
-
"bench:js": "bash ./run-bench.js.sh",
|
|
89
|
-
"
|
|
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
|
|
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",
|