json-as 0.5.51 → 0.5.54
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/.github/workflows/nodejs.yml +25 -0
- package/LICENSE +17 -17
- package/README.md +0 -23
- package/assembly/__benches__/as-json.ts +23 -61
- package/assembly/__tests__/as-json.spec.ts +14 -26
- package/assembly/src/json.ts +47 -82
- package/assembly/src/util.ts +217 -56
- package/assembly/test.ts +4 -277
- package/bench-results/INTEGER-PARSING.md +52 -0
- package/bench.js +1 -3
- package/package.json +11 -8
- package/transform/lib/index.js +77 -48
- package/transform/package.json +1 -1
- package/asconfig.json +0 -15
package/assembly/src/util.ts
CHANGED
|
@@ -2,26 +2,22 @@ import { StringSink } from "as-string-sink/assembly";
|
|
|
2
2
|
import { isSpace } from "util/string";
|
|
3
3
|
import { backSlashCode, quoteCode } from "./chars";
|
|
4
4
|
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
@inline
|
|
7
|
-
export function unsafeCharCodeAt(data: string, pos: i32): i32 {
|
|
5
|
+
// @ts-ignore: Decorator
|
|
6
|
+
@inline export function unsafeCharCodeAt(data: string, pos: i32): i32 {
|
|
8
7
|
return load<u16>(changetype<usize>(data) + ((<usize>pos) << 1));
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
@inline
|
|
13
|
-
export function removeWhitespace(data: string): string {
|
|
10
|
+
// @ts-ignore: Decorator
|
|
11
|
+
@inline export function removeWhitespace(data: string): string {
|
|
14
12
|
const result = new StringSink();
|
|
15
13
|
let instr = false;
|
|
16
14
|
for (let i = 0; i < data.length; i++) {
|
|
17
15
|
const char = data.charCodeAt(i);
|
|
18
16
|
if (instr === false && char === quoteCode) instr = true;
|
|
19
17
|
else if (
|
|
20
|
-
instr === true &&
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
)
|
|
24
|
-
instr = false;
|
|
18
|
+
instr === true && char === quoteCode
|
|
19
|
+
&& data.charCodeAt(i - 1) !== backSlashCode
|
|
20
|
+
) instr = false;
|
|
25
21
|
|
|
26
22
|
if (instr === false) {
|
|
27
23
|
if (!isSpace(char)) result.write(data.charAt(i));
|
|
@@ -32,9 +28,8 @@ export function removeWhitespace(data: string): string {
|
|
|
32
28
|
return result.toString();
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
// @ts-ignore
|
|
36
|
-
@inline
|
|
37
|
-
export function escapeChar(char: string): string {
|
|
31
|
+
// @ts-ignore: Decorator
|
|
32
|
+
@inline export function escapeChar(char: string): string {
|
|
38
33
|
switch (unsafeCharCodeAt(char, 0)) {
|
|
39
34
|
case 0x22:
|
|
40
35
|
return '\\"';
|
|
@@ -63,56 +58,224 @@ export function escapeChar(char: string): string {
|
|
|
63
58
|
* @returns depth of array
|
|
64
59
|
*/
|
|
65
60
|
|
|
66
|
-
// @ts-ignore
|
|
67
|
-
@inline
|
|
68
|
-
export function getArrayDepth<T>(depth: i32 = 1): i32 {
|
|
69
|
-
// @ts-ignore
|
|
61
|
+
// @ts-ignore: Decorator
|
|
62
|
+
@inline export function getArrayDepth<T extends ArrayLike>(depth: i32 = 1): i32 {
|
|
70
63
|
if (!isArray<T>()) {
|
|
71
64
|
return 0;
|
|
72
|
-
// @ts-ignore
|
|
73
65
|
} else if (isArray<valueof<T>>()) {
|
|
74
66
|
depth++;
|
|
75
|
-
// @ts-ignore
|
|
76
67
|
return getArrayDepth<valueof<T>>(depth);
|
|
77
68
|
} else {
|
|
78
69
|
return depth;
|
|
79
70
|
}
|
|
80
71
|
}
|
|
81
72
|
|
|
73
|
+
/** Scientific Notation Integer Parsing - SNIP
|
|
74
|
+
* This is absolutely the fastest algorithm I could think of while adding full support for Scientific Notation
|
|
75
|
+
* Loads 32 bits and retrieves the high/low bits.
|
|
76
|
+
* The reason why we only load 4 bytes at a time is that numbers in the 32-bit range are 7 chars long at most.
|
|
77
|
+
* Using SIMD or 64 bit loads would only work well when parsing large 128+ numbers.
|
|
78
|
+
*
|
|
79
|
+
* Here are some benchmarks
|
|
80
|
+
* Parsing: "12345"
|
|
81
|
+
* Results are spread over 5000ms
|
|
82
|
+
*
|
|
83
|
+
* SNIP: 270M iterations
|
|
84
|
+
* ATOI: 285M iterations
|
|
85
|
+
* ParseInt: 176M iterations
|
|
86
|
+
*
|
|
87
|
+
* @param str - Any number. Can include scientific notation.
|
|
88
|
+
*/
|
|
89
|
+
// @ts-ignore: Decorator
|
|
90
|
+
@inline export function snip_fast<T extends number>(str: string, len: u32 = 0, offset: u32 = 0): T {
|
|
91
|
+
if (isSigned<T>()) {
|
|
92
|
+
const firstChar: u32 = load<u16>(changetype<usize>(str));
|
|
93
|
+
if (firstChar === 48) return 0 as T;
|
|
94
|
+
const isNegative = firstChar === 45; // Check if the number is negative
|
|
95
|
+
let val: T = 0 as T;
|
|
96
|
+
if (len == 0) len = u32(str.length << 1);
|
|
97
|
+
if (isNegative) {
|
|
98
|
+
offset += 2;
|
|
99
|
+
if (len >= 4) {
|
|
100
|
+
// 32-bit route
|
|
101
|
+
for (; offset < (len - 3); offset += 4) {
|
|
102
|
+
const ch = load<u32>(changetype<usize>(str) + <usize>offset);
|
|
103
|
+
const low = ch & 0xFFFF;
|
|
104
|
+
const high = ch >> 16;
|
|
105
|
+
// 9 is 57. The highest group of two numbers is 114, so if a e or an E is included, this will fire.
|
|
106
|
+
if (low > 57) {
|
|
107
|
+
// The first char (f) is E or e
|
|
108
|
+
// We push the offset up by two and apply the notation.
|
|
109
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
110
|
+
return -(val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
111
|
+
} else {
|
|
112
|
+
// Inlined this operation instead of using a loop
|
|
113
|
+
return -(val * (10 ** (atoi_fast<u32>(str, offset + 2) + 1))) as T;
|
|
114
|
+
}
|
|
115
|
+
} else if (high > 57) {
|
|
116
|
+
// The first char (f) is E or e
|
|
117
|
+
// We push the offset up by two and apply the notation.
|
|
118
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
119
|
+
return -(val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
120
|
+
} else {
|
|
121
|
+
// Inlined this operation instead of using a loop
|
|
122
|
+
return -(val * (10 ** (atoi_fast<u32>(str, offset + 4) + 1))) as T;
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
val = (val * 100 + ((low - 48) * 10) + (high - 48)) as T;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Finish up the remainder with 16 bits.
|
|
130
|
+
for (; offset < len; offset += 2) {
|
|
131
|
+
const ch = load<u16>(changetype<usize>(str) + <usize>offset);
|
|
132
|
+
// 9 is 57. E and e are larger. Assumes valid JSON.
|
|
133
|
+
if (ch > 57) {
|
|
134
|
+
// The first char (f) is E or e
|
|
135
|
+
// We push the offset up by two and apply the notation.
|
|
136
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
137
|
+
return -(val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
138
|
+
} else {
|
|
139
|
+
// Inlined this operation instead of using a loop
|
|
140
|
+
return -(val * (10 ** (atoi_fast<u32>(str, offset + 2) + 1))) as T;
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
val = (val * 10) + (ch - 48) as T;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return -val as T;
|
|
147
|
+
} else {
|
|
148
|
+
if (len >= 4) {
|
|
149
|
+
// Duplet 16 bit lane load
|
|
150
|
+
for (; offset < (len - 3); offset += 4) {
|
|
151
|
+
const ch = load<u32>(changetype<usize>(str) + <usize>offset);
|
|
152
|
+
const low = ch & 0xFFFF;
|
|
153
|
+
const high = ch >> 16;
|
|
154
|
+
// 9 is 57. The highest group of two numbers is 114, so if a e or an E is included, this will fire.
|
|
155
|
+
if (low > 57) {
|
|
156
|
+
// The first char (f) is E or e
|
|
157
|
+
// We push the offset up by two and apply the notation.
|
|
158
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
159
|
+
return (val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
160
|
+
} else {
|
|
161
|
+
// Inlined this operation instead of using a loop
|
|
162
|
+
return (val * (10 ** (atoi_fast<u32>(str, offset + 2) + 1))) as T;
|
|
163
|
+
}
|
|
164
|
+
} else if (high > 57) {
|
|
165
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
166
|
+
return (val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
167
|
+
} else {
|
|
168
|
+
// Inlined this operation instead of using a loop
|
|
169
|
+
return (val * (10 ** (atoi_fast<u32>(str, offset + 4) + 1))) as T;
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
// Optimized with multiplications and shifts.
|
|
173
|
+
val = (val * 100 + ((low - 48) * 10) + (high - 48)) as T;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Cover the remaining numbers with 16 bit loads.
|
|
178
|
+
for (; offset < len; offset += 2) {
|
|
179
|
+
const ch = load<u16>(changetype<usize>(str) + <usize>offset);
|
|
180
|
+
// 0's char is 48 and 9 is 57. Anything above this range would signify an exponent (e or E).
|
|
181
|
+
// e is 101 and E is 69.
|
|
182
|
+
if (ch > 57) {
|
|
183
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
184
|
+
val = (val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
185
|
+
} else {
|
|
186
|
+
// Inlined this operation instead of using a loop
|
|
187
|
+
val = (val * (10 ** (atoi_fast<u32>(str, offset + 2) + 1))) as T;
|
|
188
|
+
}
|
|
189
|
+
return val as T;
|
|
190
|
+
} else {
|
|
191
|
+
val = (val * 10) + (ch - 48) as T;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return val as T;
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
const firstChar: u32 = load<u16>(changetype<usize>(str));
|
|
198
|
+
if (firstChar === 48) return 0 as T;
|
|
199
|
+
let val: T = 0 as T;
|
|
200
|
+
if (len == 0) len = u32(str.length << 1);
|
|
201
|
+
if (len >= 4) {
|
|
202
|
+
// Duplet 16 bit lane load
|
|
203
|
+
for (; offset < (len - 3); offset += 4) {
|
|
204
|
+
const ch = load<u32>(changetype<usize>(str) + <usize>offset);
|
|
205
|
+
const low = ch & 0xFFFF;
|
|
206
|
+
const high = ch >> 16;
|
|
207
|
+
// 9 is 57. The highest group of two numbers is 114, so if a e or an E is included, this will fire.
|
|
208
|
+
if (low > 57) {
|
|
209
|
+
// The first char (f) is E or e
|
|
210
|
+
// We push the offset up by two and apply the notation.
|
|
211
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
212
|
+
return (val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
213
|
+
} else {
|
|
214
|
+
// Inlined this operation instead of using a loop
|
|
215
|
+
return (val * (10 ** (atoi_fast<u32>(str, offset + 2) + 1))) as T;
|
|
216
|
+
}
|
|
217
|
+
} else if (high > 57) {
|
|
218
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
219
|
+
return (val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
220
|
+
} else {
|
|
221
|
+
// Inlined this operation instead of using a loop
|
|
222
|
+
return (val * (10 ** (atoi_fast<u32>(str, offset + 4) + 1))) as T;
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
// Optimized with multiplications and shifts.
|
|
226
|
+
val = (val * 100 + ((low - 48) * 10) + (high - 48)) as T;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Cover the remaining numbers with 16 bit loads.
|
|
231
|
+
for (; offset < len; offset += 2) {
|
|
232
|
+
const ch = load<u16>(changetype<usize>(str) + <usize>offset);
|
|
233
|
+
// 0's char is 48 and 9 is 57. Anything above this range would signify an exponent (e or E).
|
|
234
|
+
// e is 101 and E is 69.
|
|
235
|
+
if (ch > 57) {
|
|
236
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
237
|
+
return (val / (10 ** (atoi_fast<u32>(str, offset + 6) - 1))) as T;
|
|
238
|
+
} else {
|
|
239
|
+
// Inlined this operation instead of using a loop
|
|
240
|
+
return (val * (10 ** (atoi_fast<u32>(str, offset + 2) + 1))) as T;
|
|
241
|
+
}
|
|
242
|
+
} else {
|
|
243
|
+
val = (val * 10) + (ch - 48) as T;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return val as T;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
82
250
|
/**
|
|
83
251
|
* Implementation of ATOI. Can be much much faster with SIMD.
|
|
84
|
-
* Benchmark: 40-46m ops/s
|
|
85
252
|
*/
|
|
86
253
|
|
|
87
254
|
// @ts-ignore
|
|
88
|
-
@inline
|
|
89
|
-
export function atoi_fast<T extends number>(str: string, offset: i32 = 0): T {
|
|
255
|
+
@inline export function atoi_fast<T extends number>(str: string, offset: u32 = 0): T {
|
|
90
256
|
// @ts-ignore
|
|
91
257
|
let val: T = 0;
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
(val
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
258
|
+
const len = u32(str.length << 1);
|
|
259
|
+
if (isSigned<T>()) {
|
|
260
|
+
// Negative path
|
|
261
|
+
if (load<u16>(changetype<usize>(str) + <usize>offset) === 45) {
|
|
262
|
+
offset += 2;
|
|
263
|
+
for (; offset < len; offset += 2) {
|
|
264
|
+
val = (val * 10) + (load<u16>(changetype<usize>(str) + <usize>offset) - 48) as T;
|
|
265
|
+
}
|
|
266
|
+
return -val as T;
|
|
267
|
+
} else {
|
|
268
|
+
for (; offset < len; offset += 2) {
|
|
269
|
+
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>offset) - 48)) as T;
|
|
270
|
+
}
|
|
271
|
+
return val as T;
|
|
102
272
|
}
|
|
103
|
-
// @ts-ignore
|
|
104
|
-
val = -val;
|
|
105
273
|
} else {
|
|
106
|
-
for (; offset <
|
|
107
|
-
|
|
108
|
-
val =
|
|
109
|
-
(val << 1) +
|
|
110
|
-
(val << 3) +
|
|
111
|
-
(load<u16>(changetype<usize>(str) + <usize>offset) - 48);
|
|
112
|
-
// We use load because in this case, there is no need to have bounds-checking
|
|
274
|
+
for (; offset < len; offset += 2) {
|
|
275
|
+
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>offset) - 48)) as T;
|
|
113
276
|
}
|
|
277
|
+
return val as T;
|
|
114
278
|
}
|
|
115
|
-
return val;
|
|
116
279
|
}
|
|
117
280
|
|
|
118
281
|
/**
|
|
@@ -124,8 +287,7 @@ export function atoi_fast<T extends number>(str: string, offset: i32 = 0): T {
|
|
|
124
287
|
*/
|
|
125
288
|
|
|
126
289
|
// @ts-ignore
|
|
127
|
-
@inline
|
|
128
|
-
export function parseSciInteger<T extends number>(str: string): T {
|
|
290
|
+
@inline export function parseSciInteger<T extends number>(str: string): T {
|
|
129
291
|
// @ts-ignore
|
|
130
292
|
let val: T = 0;
|
|
131
293
|
let offset = 0;
|
|
@@ -154,25 +316,24 @@ export function parseSciInteger<T extends number>(str: string): T {
|
|
|
154
316
|
// We use load because in this case, there is no need to have bounds-checking
|
|
155
317
|
}
|
|
156
318
|
if (firstChar === 45) {
|
|
157
|
-
val = -val;
|
|
319
|
+
val = -val as T;
|
|
158
320
|
}
|
|
159
321
|
return val;
|
|
160
322
|
}
|
|
161
323
|
|
|
162
324
|
// @ts-ignore
|
|
163
|
-
@inline
|
|
164
|
-
function sciNote<T extends number>(num: T): T {
|
|
325
|
+
@inline function sciNote<T extends number>(num: T): T {
|
|
165
326
|
let res = 1;
|
|
166
327
|
// @ts-ignore
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
328
|
+
if (num > 0) {
|
|
329
|
+
for (let i: T = <T>0; i < num; i++) {
|
|
330
|
+
res *= 10;
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
for (let i: T = <T>0; i < num; i++) {
|
|
334
|
+
res /= 10;
|
|
175
335
|
}
|
|
336
|
+
}
|
|
176
337
|
// @ts-ignore
|
|
177
338
|
return res;
|
|
178
339
|
}
|
package/assembly/test.ts
CHANGED
|
@@ -1,279 +1,6 @@
|
|
|
1
1
|
import { JSON } from "./src/json";
|
|
2
|
-
import { atoi_fast, parseSciInteger } from "./src/util";
|
|
3
|
-
import * as a from "util/number";
|
|
4
|
-
// "st\"ring\" w\"\"ith quotes\""
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
z!: f32;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
@json
|
|
14
|
-
class Player {
|
|
15
|
-
firstName!: string;
|
|
16
|
-
lastName!: string;
|
|
17
|
-
lastActive!: i32[];
|
|
18
|
-
age!: i32;
|
|
19
|
-
pos!: Vec3 | null;
|
|
20
|
-
isVerified!: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const player: Player = {
|
|
24
|
-
firstName: "Emmet",
|
|
25
|
-
lastName: "West",
|
|
26
|
-
lastActive: [8, 27, 2022],
|
|
27
|
-
age: 23,
|
|
28
|
-
pos: {
|
|
29
|
-
x: 3.4,
|
|
30
|
-
y: 1.2,
|
|
31
|
-
z: 8.3,
|
|
32
|
-
},
|
|
33
|
-
isVerified: true,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const vec: Vec3 = {
|
|
37
|
-
x: 3,
|
|
38
|
-
y: 1,
|
|
39
|
-
z: 8,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const serializedPlayer = JSON.stringify<Player>(player);
|
|
43
|
-
console.log(serializedPlayer);
|
|
44
|
-
const parsedPlayer = JSON.parse<Player>(serializedPlayer);
|
|
45
|
-
console.log(JSON.stringify(parsedPlayer));
|
|
46
|
-
|
|
47
|
-
const serializedVec3 = JSON.stringify(vec);
|
|
48
|
-
console.log(serializedVec3);
|
|
49
|
-
|
|
50
|
-
const parsedVec3 = JSON.parse<Vec3>(serializedVec3);
|
|
51
|
-
console.log(JSON.stringify(parsedVec3));
|
|
52
|
-
|
|
53
|
-
console.log("atoi:");
|
|
54
|
-
console.log("123 - " + parseSciInteger<i32>("123").toString());
|
|
55
|
-
console.log("1230 - " + parseSciInteger<i32>("123e1").toString());
|
|
56
|
-
console.log("12300 - " + parseSciInteger<i32>("123e2").toString());
|
|
57
|
-
console.log("123000 - " + parseSciInteger<i32>("123e3").toString());
|
|
58
|
-
console.log("12 - " + parseSciInteger<i32>("123e-1").toString());
|
|
59
|
-
console.log(parseSciInteger<i32>("100").toString());
|
|
60
|
-
console.log(parseSciInteger<i32>("-100").toString());
|
|
61
|
-
|
|
62
|
-
console.log(JSON.stringify("abcdefg"));
|
|
63
|
-
console.log('"abcdefg"')
|
|
64
|
-
console.log(JSON.stringify('st"ring" w""ith quotes"'));
|
|
65
|
-
console.log('"st\\"ring\\" w\\"\\"ith quotes\\""')
|
|
66
|
-
console.log(JSON.stringify(['string "with random spa\nces and \nnewlines\n\n\n']));
|
|
67
|
-
console.log(JSON.stringify(JSON.parse<string[]>(JSON.stringify(['string "with random spa\nces and \nnewlines\n\n\n']))));
|
|
68
|
-
console.log('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"')
|
|
69
|
-
console.log(JSON.stringify('string with colon : comma , brace [ ] bracket { } and quote " and other quote "'));
|
|
70
|
-
/*console.log(JSON.stringify(JSON.parse<string[]>(JSON.stringify([
|
|
71
|
-
"abcdefg",
|
|
72
|
-
'st"ring" w""ith quotes"',
|
|
73
|
-
'string \t\r"with ran\tdom spa\nces and \nnewlines\n\n\n',
|
|
74
|
-
'string with colon : comma , brace [ ] bracket { } and quote " and other quote "',
|
|
75
|
-
]))));
|
|
76
|
-
console.log('["abcdefg","st\"ring\" w\"\"ith quotes\"","string \t\r\"with ran\tdom spa\nces and \nnewlines\n\n\n","string with colon : comma , brace [ ] bracket { } and quote \" and other quote \""]');/*
|
|
77
|
-
console.log(
|
|
78
|
-
JSON.stringify(
|
|
79
|
-
JSON.parse<string[]>(
|
|
80
|
-
JSON.stringify([
|
|
81
|
-
"abcdefg",
|
|
82
|
-
'st"ring" w""ith quotes"',
|
|
83
|
-
'string \t\r"with ran\tdom spa\nces and \nnewlines\n\n\n',
|
|
84
|
-
'string with colon : comma , brace [ ] bracket { } and quote " and other quote "',
|
|
85
|
-
])
|
|
86
|
-
)
|
|
87
|
-
)
|
|
88
|
-
);
|
|
89
|
-
/*
|
|
90
|
-
const str = changetype<string>(new ArrayBuffer(6));
|
|
91
|
-
console.log("istr:");
|
|
92
|
-
console.log("123 - " + istr8(123));
|
|
93
|
-
console.log("32 - " + istr8(32));
|
|
94
|
-
console.log("3 - " + istr8(3));
|
|
95
|
-
|
|
96
|
-
console.log(Uint8Array.wrap(changetype<ArrayBuffer>(istr8(12))).join(" "));
|
|
97
|
-
console.log(load<u32>(changetype<usize>(istr8(12))).toString());
|
|
98
|
-
@inline function istr8<
|
|
99
|
-
T extends number
|
|
100
|
-
>(int: T): string {
|
|
101
|
-
if (int >= 100) {
|
|
102
|
-
const str = changetype<string>(__new(6, idof<String>()));
|
|
103
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48);
|
|
104
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 2);
|
|
105
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 4);
|
|
106
|
-
return str;
|
|
107
|
-
} else if (int >= 10) {
|
|
108
|
-
const str = changetype<string>(__new(4, idof<String>()));
|
|
109
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48);
|
|
110
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 2);
|
|
111
|
-
return str;
|
|
112
|
-
} else {
|
|
113
|
-
const str = changetype<string>(__new(2, idof<String>()));
|
|
114
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48);
|
|
115
|
-
return str;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function istr16<T extends number>(int: T): string {
|
|
120
|
-
if (int >= 10_000) {
|
|
121
|
-
const str = changetype<string>(__new(10, idof<String>()));
|
|
122
|
-
store<u16>(changetype<usize>(str), ((int / 10000) % 10) + 48);
|
|
123
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48, 2);
|
|
124
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 4);
|
|
125
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 6);
|
|
126
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 8);
|
|
127
|
-
return str;
|
|
128
|
-
} else if (int >= 1_000) {
|
|
129
|
-
const str = changetype<string>(__new(8, idof<String>()));
|
|
130
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48);
|
|
131
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 2);
|
|
132
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 4);
|
|
133
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 6);
|
|
134
|
-
return str;
|
|
135
|
-
} else if (int >= 100) {
|
|
136
|
-
const str = changetype<string>(__new(6, idof<String>()));
|
|
137
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48);
|
|
138
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 2);
|
|
139
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 4);
|
|
140
|
-
return str;
|
|
141
|
-
} else if (int >= 10) {
|
|
142
|
-
const str = changetype<string>(__new(4, idof<String>()));
|
|
143
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48);
|
|
144
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 2);
|
|
145
|
-
return str;
|
|
146
|
-
} else {
|
|
147
|
-
const str = changetype<string>(__new(2, idof<String>()));
|
|
148
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48);
|
|
149
|
-
return str;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export function istr32<T extends number>(int: T): string {
|
|
154
|
-
if (int >= 1_000_000_000) {
|
|
155
|
-
const str = changetype<string>(__new(22, idof<String>()));
|
|
156
|
-
store<u16>(changetype<usize>(str), ((int / 10000000000) % 10) + 48);
|
|
157
|
-
store<u16>(changetype<usize>(str), ((int / 1000000000) % 10) + 48, 2);
|
|
158
|
-
store<u16>(changetype<usize>(str), ((int / 100000000) % 10) + 48, 4);
|
|
159
|
-
store<u16>(changetype<usize>(str), ((int / 10000000) % 10) + 48, 6);
|
|
160
|
-
store<u16>(changetype<usize>(str), ((int / 1000000) % 10) + 48, 8);
|
|
161
|
-
store<u16>(changetype<usize>(str), ((int / 100000) % 10) + 48, 10);
|
|
162
|
-
store<u16>(changetype<usize>(str), ((int / 10000) % 10) + 48, 12);
|
|
163
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48, 14);
|
|
164
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 16);
|
|
165
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 18);
|
|
166
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 20);
|
|
167
|
-
return str;
|
|
168
|
-
} else if (int >= 100_000_000) {
|
|
169
|
-
const str = changetype<string>(__new(20, idof<String>()));
|
|
170
|
-
store<u16>(changetype<usize>(str), ((int / 1000000000) % 10) + 48);
|
|
171
|
-
store<u16>(changetype<usize>(str), ((int / 100000000) % 10) + 48, 2);
|
|
172
|
-
store<u16>(changetype<usize>(str), ((int / 10000000) % 10) + 48, 4);
|
|
173
|
-
store<u16>(changetype<usize>(str), ((int / 1000000) % 10) + 48, 6);
|
|
174
|
-
store<u16>(changetype<usize>(str), ((int / 100000) % 10) + 48, 8);
|
|
175
|
-
store<u16>(changetype<usize>(str), ((int / 10000) % 10) + 48, 10);
|
|
176
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48, 12);
|
|
177
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 14);
|
|
178
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 16);
|
|
179
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 18);
|
|
180
|
-
return str;
|
|
181
|
-
} else if (int >= 10_000_000) {
|
|
182
|
-
const str = changetype<string>(__new(18, idof<String>()));
|
|
183
|
-
store<u16>(changetype<usize>(str), ((int / 100000000) % 10) + 48);
|
|
184
|
-
store<u16>(changetype<usize>(str), ((int / 10000000) % 10) + 48, 2);
|
|
185
|
-
store<u16>(changetype<usize>(str), ((int / 1000000) % 10) + 48, 4);
|
|
186
|
-
store<u16>(changetype<usize>(str), ((int / 100000) % 10) + 48, 6);
|
|
187
|
-
store<u16>(changetype<usize>(str), ((int / 10000) % 10) + 48, 8);
|
|
188
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48, 10);
|
|
189
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 12);
|
|
190
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 14);
|
|
191
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 16);
|
|
192
|
-
return str;
|
|
193
|
-
} else if (int >= 10_000_000) {
|
|
194
|
-
const str = changetype<string>(__new(16, idof<String>()));
|
|
195
|
-
store<u16>(changetype<usize>(str), ((int / 10000000) % 10) + 48);
|
|
196
|
-
store<u16>(changetype<usize>(str), ((int / 1000000) % 10) + 48, 2);
|
|
197
|
-
store<u16>(changetype<usize>(str), ((int / 100000) % 10) + 48, 4);
|
|
198
|
-
store<u16>(changetype<usize>(str), ((int / 10000) % 10) + 48, 6);
|
|
199
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48, 8);
|
|
200
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 10);
|
|
201
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 12);
|
|
202
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 14);
|
|
203
|
-
return str;
|
|
204
|
-
} else if (int >= 1_000_000) {
|
|
205
|
-
const str = changetype<string>(__new(14, idof<String>()));
|
|
206
|
-
store<u16>(changetype<usize>(str), ((int / 1000000) % 10) + 48);
|
|
207
|
-
store<u16>(changetype<usize>(str), ((int / 100000) % 10) + 48, 2);
|
|
208
|
-
store<u16>(changetype<usize>(str), ((int / 10000) % 10) + 48, 4);
|
|
209
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48, 6);
|
|
210
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 8);
|
|
211
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 10);
|
|
212
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 12);
|
|
213
|
-
return str;
|
|
214
|
-
} else if (int >= 100_000) {
|
|
215
|
-
const str = changetype<string>(__new(12, idof<String>()));
|
|
216
|
-
store<u16>(changetype<usize>(str), ((int / 100000) % 10) + 48);
|
|
217
|
-
store<u16>(changetype<usize>(str), ((int / 10000) % 10) + 48, 2);
|
|
218
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48, 4);
|
|
219
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 6);
|
|
220
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 8);
|
|
221
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 10);
|
|
222
|
-
return str;
|
|
223
|
-
} else if (int >= 10_000) {
|
|
224
|
-
const str = changetype<string>(__new(10, idof<String>()));
|
|
225
|
-
store<u16>(changetype<usize>(str), ((int / 10000) % 10) + 48);
|
|
226
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48, 2);
|
|
227
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 4);
|
|
228
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 6);
|
|
229
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 8);
|
|
230
|
-
return str;
|
|
231
|
-
} else if (int >= 1_000) {
|
|
232
|
-
const str = changetype<string>(__new(8, idof<String>()));
|
|
233
|
-
store<u16>(changetype<usize>(str), ((int / 1000) % 10) + 48);
|
|
234
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48, 2);
|
|
235
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 4);
|
|
236
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 6);
|
|
237
|
-
return str;
|
|
238
|
-
} else if (int >= 100) {
|
|
239
|
-
const str = changetype<string>(__new(6, idof<String>()));
|
|
240
|
-
store<u16>(changetype<usize>(str), ((int / 100) % 10) + 48);
|
|
241
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48, 2);
|
|
242
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 4);
|
|
243
|
-
return str;
|
|
244
|
-
} else if (int >= 10) {
|
|
245
|
-
const str = changetype<string>(__new(4, idof<String>()));
|
|
246
|
-
store<u16>(changetype<usize>(str), ((int / 10) % 10) + 48);
|
|
247
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48, 2);
|
|
248
|
-
return str;
|
|
249
|
-
} else {
|
|
250
|
-
const str = changetype<string>(__new(2, idof<String>()));
|
|
251
|
-
store<u16>(changetype<usize>(str), (int % 10) + 48);
|
|
252
|
-
return str;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
export function istr64<T extends number>(int: T): string {
|
|
257
|
-
const val = new ArrayBuffer(6);
|
|
258
|
-
store<u16>(changetype<usize>(val), (int % 10) + 48, 4);
|
|
259
|
-
if ((int = (int / 10) as T) > 0)
|
|
260
|
-
store<u16>(changetype<usize>(val), (int % 10) + 48, 2);
|
|
261
|
-
else return changetype<string>(val);
|
|
262
|
-
if ((int = (int / 10) as T) > 0)
|
|
263
|
-
store<u16>(changetype<usize>(val), (int % 10) + 48);
|
|
264
|
-
return changetype<string>(val);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// 0 = 48
|
|
268
|
-
// 1 = 49
|
|
269
|
-
// 2 = 50
|
|
270
|
-
// 3 = 51
|
|
271
|
-
// 4 = 52
|
|
272
|
-
// 5 = 53
|
|
273
|
-
// 6 = 54
|
|
274
|
-
// 7 = 55
|
|
275
|
-
// 8 = 56
|
|
276
|
-
// 9 = 57
|
|
277
|
-
|
|
278
|
-
console.log(JSON.stringify("h\\i from gray\bson"));
|
|
279
|
-
*/
|
|
3
|
+
console.log(JSON.parse<u32>("100").toString());
|
|
4
|
+
console.log(JSON.stringify<u32>(100));
|
|
5
|
+
console.log(JSON.stringify(JSON.parse<u32>(JSON.stringify(100))))
|
|
6
|
+
console.log((100).toString())
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Comparison between integer parsing algorithms
|
|
2
|
+
|
|
3
|
+
SNIP: 261M iterations over 5000ms
|
|
4
|
+
ATOI: 285M iterations over 5000ms
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### Log
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
yarn run v1.22.19
|
|
11
|
+
$ astral -Ospeed --noAssert --uncheckedBehavior always --runtime stub
|
|
12
|
+
Compiling assembly/__benches__/as-json.ts
|
|
13
|
+
|
|
14
|
+
Benchmarking Parse Number SNIP: Warming up for 3000ms
|
|
15
|
+
Benchmarking Parse Number SNIP: Collecting 100 samples in estimated 5000ms (261M iterations)
|
|
16
|
+
Benchmarking Parse Number SNIP: Analyzing
|
|
17
|
+
Parse Number SNIP time: [18.146ns 18.381ns 18.624ns]
|
|
18
|
+
change: [-13.073% -10.614% -8.1347%] (p = 0.00 < 0.05)
|
|
19
|
+
Performance has improved.
|
|
20
|
+
Found 9 outliers among 100 measurements (9%)
|
|
21
|
+
8 (8%) high mild
|
|
22
|
+
1 (1%) high severe
|
|
23
|
+
|
|
24
|
+
Benchmarking Parse Number ATOI: Warming up for 3000ms
|
|
25
|
+
Benchmarking Parse Number ATOI: Collecting 100 samples in estimated 5000ms (285M iterations)
|
|
26
|
+
Benchmarking Parse Number ATOI: Analyzing
|
|
27
|
+
Parse Number ATOI time: [16.962ns 17.219ns 17.501ns]
|
|
28
|
+
change: [-3.5659% -0.8496% +2.0516%] (p = 0.00 < 0.05)
|
|
29
|
+
Change within noise threshold.
|
|
30
|
+
Found 7 outliers among 100 measurements (7%)
|
|
31
|
+
2 (2%) high mild
|
|
32
|
+
5 (5%) high severe
|
|
33
|
+
|
|
34
|
+
Benchmarking Parse Number STDLIB: Warming up for 3000ms
|
|
35
|
+
Benchmarking Parse Number STDLIB: Collecting 100 samples in estimated 5000ms (176M iterations)
|
|
36
|
+
Benchmarking Parse Number STDLIB: Analyzing
|
|
37
|
+
Parse Number STDLIB time: [28.298ns 28.763ns 29.383ns]
|
|
38
|
+
change: [-3.3724% -1.5367% +0.1796%] (p = 0.00 < 0.05)
|
|
39
|
+
Change within noise threshold.
|
|
40
|
+
Found 5 outliers among 100 measurements (5%)
|
|
41
|
+
3 (3%) high mild
|
|
42
|
+
2 (2%) high severe
|
|
43
|
+
|
|
44
|
+
Benchmarking Parse Number OLD: Warming up for 3000ms
|
|
45
|
+
Benchmarking Parse Number OLD: Collecting 100 samples in estimated 5000ms (171M iterations)
|
|
46
|
+
Benchmarking Parse Number OLD: Analyzing
|
|
47
|
+
Parse Number OLD time: [28.888ns 29.341ns 29.804ns]
|
|
48
|
+
change: [-2.123% -0.5458% +1.1939%] (p = 0.00 < 0.05)
|
|
49
|
+
Change within noise threshold.
|
|
50
|
+
Found 3 outliers among 100 measurements (3%)
|
|
51
|
+
3 (3%) high mild
|
|
52
|
+
```
|