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.
@@ -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
- char === quoteCode &&
22
- data.charCodeAt(i - 1) !== backSlashCode
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
- let firstChar = load<u16>(changetype<usize>(str) + <usize>offset);
93
- if (firstChar === 45) {
94
- offset += 2;
95
- for (; offset < str.length << 1; offset += 2) {
96
- // @ts-ignore
97
- val =
98
- (val << 1) +
99
- (val << 3) +
100
- (load<u16>(changetype<usize>(str) + <usize>offset) - 48);
101
- // We use load because in this case, there is no need to have bounds-checking
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 < str.length << 1; offset += 2) {
107
- // @ts-ignore
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
- if (num > 0) {
168
- for (let i: T = 0; i < num; i++) {
169
- res *= 10;
170
- }
171
- } else {
172
- for (let i: T = 0; i < num; i++) {
173
- res /= 10;
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
- @json
7
- class Vec3 {
8
- x!: f32;
9
- y!: f32;
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
+ ```