json-as 0.5.54 → 0.5.57
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/LICENSE +1 -1
- package/README.md +41 -23
- package/asconfig.json +15 -0
- package/assembly/__benches__/as-json.ts +10 -10
- package/assembly/__tests__/as-json.spec.ts +1 -1
- package/assembly/src/chars.ts +52 -26
- package/assembly/src/json.ts +108 -151
- package/assembly/src/util.ts +42 -31
- package/assembly/test.ts +80 -5
- package/bench/bench-node.js +17 -0
- package/bench/benchmark.ts +60 -0
- package/bench/tsconfig.json +99 -0
- package/package.json +13 -6
- package/transform/lib/index.js +26 -11
- package/transform/package.json +1 -1
- package/transform/src/index.ts +44 -22
- package/bench-results/INTEGER-PARSING.md +0 -52
package/assembly/src/json.ts
CHANGED
|
@@ -20,8 +20,11 @@ import {
|
|
|
20
20
|
trueWord,
|
|
21
21
|
uCode,
|
|
22
22
|
emptyArrayWord,
|
|
23
|
+
falseWord,
|
|
24
|
+
newLineCode,
|
|
23
25
|
} from "./chars";
|
|
24
26
|
import { snip_fast, unsafeCharCodeAt } from "./util";
|
|
27
|
+
import { Virtual } from "as-virtual/assembly";
|
|
25
28
|
|
|
26
29
|
/**
|
|
27
30
|
* JSON Encoder/Decoder for AssemblyScript
|
|
@@ -138,208 +141,174 @@ export namespace JSON {
|
|
|
138
141
|
);
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// @ts-ignore: Decorator
|
|
147
|
+
@global @inline function __parseObjectValue<T>(data: string): T {
|
|
148
|
+
let type: T;
|
|
149
|
+
if (isString<T>()) {
|
|
150
|
+
// @ts-ignore
|
|
151
|
+
let result = "";
|
|
152
|
+
let last = 0;
|
|
153
|
+
for (let i = 0; i < data.length; i++) {
|
|
154
|
+
// \\"
|
|
155
|
+
if (unsafeCharCodeAt(data, i) === backSlashCode) {
|
|
156
|
+
const char = unsafeCharCodeAt(data, ++i);
|
|
157
|
+
result += data.slice(last, i - 1);
|
|
158
|
+
if (char === 34) {
|
|
159
|
+
result += '"';
|
|
160
|
+
last = ++i;
|
|
161
|
+
} else if (char === 110) {
|
|
162
|
+
result += "\n";
|
|
163
|
+
last = ++i;
|
|
164
|
+
// 92 98 114 116 102 117
|
|
165
|
+
} else if (char >= 92 && char <= 117) {
|
|
166
|
+
if (char === 92) {
|
|
167
|
+
result += "\\";
|
|
155
168
|
last = ++i;
|
|
156
|
-
} else if (char ===
|
|
157
|
-
result += "\
|
|
169
|
+
} else if (char === 98) {
|
|
170
|
+
result += "\b";
|
|
171
|
+
last = ++i;
|
|
172
|
+
} else if (char === 102) {
|
|
173
|
+
result += "\f";
|
|
174
|
+
last = ++i;
|
|
175
|
+
} else if (char === 114) {
|
|
176
|
+
result += "\r";
|
|
177
|
+
last = ++i;
|
|
178
|
+
} else if (char === 116) {
|
|
179
|
+
result += "\t";
|
|
180
|
+
last = ++i;
|
|
181
|
+
} else if (
|
|
182
|
+
char === 117 &&
|
|
183
|
+
load<u64>(changetype<usize>(data) + <usize>((i + 1) << 1)) ===
|
|
184
|
+
27584753879220272
|
|
185
|
+
) {
|
|
186
|
+
result += "\u000b";
|
|
187
|
+
i += 4;
|
|
158
188
|
last = ++i;
|
|
159
|
-
// 92 98 114 116 102 117
|
|
160
|
-
} else if (char >= 92 && char <= 117) {
|
|
161
|
-
if (char === 92) {
|
|
162
|
-
result += "\\";
|
|
163
|
-
last = ++i;
|
|
164
|
-
} else if (char === 98) {
|
|
165
|
-
result += "\b";
|
|
166
|
-
last = ++i;
|
|
167
|
-
} else if (char === 102) {
|
|
168
|
-
result += "\f";
|
|
169
|
-
last = ++i;
|
|
170
|
-
} else if (char === 114) {
|
|
171
|
-
result += "\r";
|
|
172
|
-
last = ++i;
|
|
173
|
-
} else if (char === 116) {
|
|
174
|
-
result += "\t";
|
|
175
|
-
last = ++i;
|
|
176
|
-
} else if (
|
|
177
|
-
char === 117 &&
|
|
178
|
-
load<u64>(changetype<usize>(data) + <usize>((i + 1) << 1)) ===
|
|
179
|
-
27584753879220272
|
|
180
|
-
) {
|
|
181
|
-
result += "\u000b";
|
|
182
|
-
i += 4;
|
|
183
|
-
last = ++i;
|
|
184
|
-
}
|
|
185
189
|
}
|
|
186
190
|
}
|
|
187
191
|
}
|
|
188
|
-
result += data.slice(last);
|
|
189
|
-
// @ts-ignore
|
|
190
|
-
return result;
|
|
191
|
-
} else if (isBoolean<T>()) {
|
|
192
|
-
// @ts-ignore
|
|
193
|
-
return parseBoolean<T>(data);
|
|
194
|
-
} else if (isFloat<T>() || isInteger<T>()) {
|
|
195
|
-
return parseNumber<T>(data);
|
|
196
|
-
} else if (isArrayLike<T>()) {
|
|
197
|
-
// @ts-ignore
|
|
198
|
-
return parseArray<T>(data);
|
|
199
|
-
// @ts-ignore
|
|
200
|
-
} else if (isNullable<T>() && data == "null") {
|
|
201
|
-
// @ts-ignore
|
|
202
|
-
return null;
|
|
203
|
-
// @ts-ignore
|
|
204
|
-
} else if (isDefined(type.__JSON_Set_Key)) {
|
|
205
|
-
return parseObject<T>(data.trimStart());
|
|
206
|
-
} else if (idof<nonnull<T>>() == idof<Date>()) {
|
|
207
|
-
// @ts-ignore
|
|
208
|
-
return Date.fromString(data);
|
|
209
|
-
} else {
|
|
210
|
-
// @ts-ignore
|
|
211
|
-
throw new Error(
|
|
212
|
-
`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
|
|
213
|
-
);
|
|
214
192
|
}
|
|
193
|
+
result += data.slice(last);
|
|
194
|
+
// @ts-ignore
|
|
195
|
+
return result;
|
|
196
|
+
} else if (isBoolean<T>()) {
|
|
197
|
+
// @ts-ignore
|
|
198
|
+
return parseBoolean<T>(data);
|
|
199
|
+
} else if (isFloat<T>() || isInteger<T>()) {
|
|
200
|
+
return parseNumber<T>(data);
|
|
201
|
+
} else if (isArrayLike<T>()) {
|
|
202
|
+
// @ts-ignore
|
|
203
|
+
return parseArray<T>(data);
|
|
204
|
+
// @ts-ignore
|
|
205
|
+
} else if (isNullable<T>() && data == "null") {
|
|
206
|
+
// @ts-ignore
|
|
207
|
+
return null;
|
|
208
|
+
// @ts-ignore
|
|
209
|
+
} else if (isDefined(type.__JSON_Set_Key)) {
|
|
210
|
+
return parseObject<T>(data.trimStart());
|
|
211
|
+
} else if (idof<nonnull<T>>() == idof<Date>()) {
|
|
212
|
+
// @ts-ignore
|
|
213
|
+
return Date.fromString(data);
|
|
214
|
+
} else {
|
|
215
|
+
// @ts-ignore
|
|
216
|
+
throw new Error(
|
|
217
|
+
`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
|
|
218
|
+
);
|
|
215
219
|
}
|
|
216
220
|
}
|
|
217
221
|
|
|
218
222
|
// @ts-ignore: Decorator
|
|
219
223
|
@inline function serializeString(data: string): string {
|
|
220
|
-
|
|
221
|
-
//if (data.length === 0) return "\"\"";
|
|
222
|
-
/*
|
|
223
|
-
let char: i32 = 0;
|
|
224
|
-
if (data.length === 1) {
|
|
225
|
-
char = unsafeCharCodeAt(data, 0);
|
|
226
|
-
if (char === 34) {
|
|
227
|
-
return "\\\"";
|
|
228
|
-
} else if (char === 92) {
|
|
229
|
-
return "\\n";
|
|
230
|
-
} else if (char <= 13 && char >= 8) {
|
|
231
|
-
switch (char) {
|
|
232
|
-
case 0x5C: {
|
|
233
|
-
return "\\\\";
|
|
234
|
-
}
|
|
235
|
-
case 0x08: {
|
|
236
|
-
return "\\b";
|
|
237
|
-
}
|
|
238
|
-
case 0x0D: {
|
|
239
|
-
return "\\r";
|
|
240
|
-
}
|
|
241
|
-
case 0x09: {
|
|
242
|
-
return "\\t";
|
|
243
|
-
}
|
|
244
|
-
case 0x0C: {
|
|
245
|
-
return "\\f";
|
|
246
|
-
}
|
|
247
|
-
case 0x0B: {
|
|
248
|
-
return "\\u000b";
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
} else {
|
|
252
|
-
return data;
|
|
253
|
-
}
|
|
254
|
-
}*/
|
|
255
|
-
|
|
256
|
-
let result = '"';
|
|
224
|
+
let result = new StringSink('"');
|
|
257
225
|
|
|
258
226
|
let last: i32 = 0;
|
|
259
227
|
// @ts-ignore
|
|
260
228
|
for (let i = 0; i < data.length; i++) {
|
|
261
229
|
const char = unsafeCharCodeAt(<string>data, i);
|
|
262
230
|
if (char === 34 || char === 92) {
|
|
263
|
-
result
|
|
231
|
+
result.write(<string>data, last, i);
|
|
232
|
+
result.writeCodePoint(backSlashCode);
|
|
264
233
|
last = i;
|
|
265
|
-
//i++;
|
|
266
234
|
} else if (char <= 13 && char >= 8) {
|
|
267
|
-
result
|
|
235
|
+
result.write(<string>data, last, i);
|
|
268
236
|
last = i + 1;
|
|
269
237
|
switch (char) {
|
|
270
238
|
case 8: {
|
|
271
|
-
result
|
|
239
|
+
result.write("\\b");
|
|
272
240
|
break;
|
|
273
241
|
}
|
|
274
242
|
case 9: {
|
|
275
|
-
result
|
|
243
|
+
result.write("\\t");
|
|
276
244
|
break;
|
|
277
245
|
}
|
|
278
246
|
case 10: {
|
|
279
|
-
result
|
|
247
|
+
result.write("\\n");
|
|
280
248
|
break;
|
|
281
249
|
}
|
|
282
250
|
case 11: {
|
|
283
|
-
result
|
|
251
|
+
result.write("\\x0B"); // \\u000b
|
|
284
252
|
break;
|
|
285
253
|
}
|
|
286
254
|
case 12: {
|
|
287
|
-
result
|
|
255
|
+
result.write("\\f");
|
|
288
256
|
break;
|
|
289
257
|
}
|
|
290
258
|
case 13: {
|
|
291
|
-
result
|
|
259
|
+
result.write("\\r");
|
|
292
260
|
break;
|
|
293
261
|
}
|
|
294
262
|
}
|
|
295
263
|
}
|
|
296
264
|
}
|
|
297
265
|
if (result.length === 1) return '"' + data + '"';
|
|
298
|
-
else result
|
|
299
|
-
|
|
266
|
+
else result.write(<string>data, last);
|
|
267
|
+
result.write("\"");
|
|
268
|
+
return result.toString();
|
|
300
269
|
}
|
|
301
270
|
|
|
302
271
|
// @ts-ignore: Decorator
|
|
303
272
|
@inline function parseString(data: string): string {
|
|
304
|
-
let result =
|
|
273
|
+
let result = new StringSink();
|
|
305
274
|
let last = 1;
|
|
306
275
|
for (let i = 1; i < data.length - 1; i++) {
|
|
307
276
|
// \\"
|
|
308
277
|
if (unsafeCharCodeAt(data, i) === backSlashCode) {
|
|
309
278
|
const char = unsafeCharCodeAt(data, ++i);
|
|
310
|
-
result
|
|
279
|
+
result.write(data, last, i - 1);
|
|
311
280
|
if (char === 34) {
|
|
312
|
-
result
|
|
281
|
+
result.writeCodePoint(quoteCode);
|
|
313
282
|
last = i + 1;
|
|
314
283
|
} else if (char >= 92 && char <= 117) {
|
|
315
284
|
switch (char) {
|
|
316
285
|
case 92: {
|
|
317
|
-
result
|
|
286
|
+
result.writeCodePoint(backSlashCode);
|
|
318
287
|
last = i + 1;
|
|
319
288
|
break;
|
|
320
289
|
}
|
|
321
290
|
case 98: {
|
|
322
|
-
result
|
|
291
|
+
result.write("\b");
|
|
323
292
|
last = i + 1;
|
|
324
293
|
break;
|
|
325
294
|
}
|
|
326
295
|
case 102: {
|
|
327
|
-
result
|
|
296
|
+
result.write("\f");
|
|
328
297
|
last = i + 1;
|
|
329
298
|
break;
|
|
330
299
|
}
|
|
331
300
|
case 110: {
|
|
332
|
-
result
|
|
301
|
+
result.writeCodePoint(newLineCode);
|
|
333
302
|
last = i + 1;
|
|
334
303
|
break;
|
|
335
304
|
}
|
|
336
305
|
case 114: {
|
|
337
|
-
result
|
|
306
|
+
result.write("\r");
|
|
338
307
|
last = i + 1;
|
|
339
308
|
break;
|
|
340
309
|
}
|
|
341
310
|
case 116: {
|
|
342
|
-
result
|
|
311
|
+
result.write("\t");
|
|
343
312
|
last = i + 1;
|
|
344
313
|
break;
|
|
345
314
|
}
|
|
@@ -349,7 +318,7 @@ export namespace JSON {
|
|
|
349
318
|
load<u64>(changetype<usize>(data) + <usize>((i + 1) << 1)) ===
|
|
350
319
|
27584753879220272
|
|
351
320
|
) {
|
|
352
|
-
result
|
|
321
|
+
result.write("\u000b");
|
|
353
322
|
i += 4;
|
|
354
323
|
last = i + 1;
|
|
355
324
|
}
|
|
@@ -359,8 +328,8 @@ export namespace JSON {
|
|
|
359
328
|
}
|
|
360
329
|
}
|
|
361
330
|
}
|
|
362
|
-
|
|
363
|
-
return result;
|
|
331
|
+
if ((data.length - 1) > last) result.write(data, last, data.length - 1);
|
|
332
|
+
return result.toString();
|
|
364
333
|
}
|
|
365
334
|
|
|
366
335
|
// @ts-ignore: Decorator
|
|
@@ -371,7 +340,7 @@ export namespace JSON {
|
|
|
371
340
|
}
|
|
372
341
|
|
|
373
342
|
// @ts-ignore: Decorator
|
|
374
|
-
@inline
|
|
343
|
+
@inline function parseNumber<T>(data: string): T {
|
|
375
344
|
if (isInteger<T>()) {
|
|
376
345
|
// @ts-ignore
|
|
377
346
|
return snip_fast<T>(data);
|
|
@@ -389,7 +358,7 @@ export namespace JSON {
|
|
|
389
358
|
let schema: nonnull<T> = changetype<nonnull<T>>(
|
|
390
359
|
__new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
|
|
391
360
|
);
|
|
392
|
-
let key =
|
|
361
|
+
let key = Virtual.createEmpty<string>();
|
|
393
362
|
let isKey = false;
|
|
394
363
|
let depth = 0;
|
|
395
364
|
let outerLoopIndex = 1;
|
|
@@ -409,10 +378,7 @@ export namespace JSON {
|
|
|
409
378
|
if (depth === 0) {
|
|
410
379
|
++arrayValueIndex;
|
|
411
380
|
// @ts-ignore
|
|
412
|
-
schema.__JSON_Set_Key(
|
|
413
|
-
key,
|
|
414
|
-
data.slice(outerLoopIndex, arrayValueIndex)
|
|
415
|
-
);
|
|
381
|
+
schema.__JSON_Set_Key<Virtual<string>>(key, data, outerLoopIndex, arrayValueIndex);
|
|
416
382
|
outerLoopIndex = arrayValueIndex;
|
|
417
383
|
isKey = false;
|
|
418
384
|
break;
|
|
@@ -433,10 +399,7 @@ export namespace JSON {
|
|
|
433
399
|
if (depth === 0) {
|
|
434
400
|
++objectValueIndex;
|
|
435
401
|
// @ts-ignore
|
|
436
|
-
schema.__JSON_Set_Key(
|
|
437
|
-
key,
|
|
438
|
-
data.slice(outerLoopIndex, objectValueIndex)
|
|
439
|
-
);
|
|
402
|
+
schema.__JSON_Set_Key<Virtual<string>>(key, data, outerLoopIndex, objectValueIndex);
|
|
440
403
|
outerLoopIndex = objectValueIndex;
|
|
441
404
|
isKey = false;
|
|
442
405
|
break;
|
|
@@ -455,14 +418,11 @@ export namespace JSON {
|
|
|
455
418
|
unsafeCharCodeAt(data, stringValueIndex - 1) !== backSlashCode
|
|
456
419
|
) {
|
|
457
420
|
if (isKey === false) {
|
|
458
|
-
key
|
|
421
|
+
key.reinst(data, outerLoopIndex, stringValueIndex);
|
|
459
422
|
isKey = true;
|
|
460
423
|
} else {
|
|
461
424
|
// @ts-ignore
|
|
462
|
-
schema.__JSON_Set_Key(
|
|
463
|
-
key,
|
|
464
|
-
data.slice(outerLoopIndex, stringValueIndex)
|
|
465
|
-
);
|
|
425
|
+
schema.__JSON_Set_Key<Virtual<string>>(key, data, outerLoopIndex, stringValueIndex);
|
|
466
426
|
isKey = false;
|
|
467
427
|
}
|
|
468
428
|
outerLoopIndex = ++stringValueIndex;
|
|
@@ -471,7 +431,7 @@ export namespace JSON {
|
|
|
471
431
|
}
|
|
472
432
|
} else if (char == nCode) {
|
|
473
433
|
// @ts-ignore
|
|
474
|
-
schema.__JSON_Set_Key(key, nullWord);
|
|
434
|
+
schema.__JSON_Set_Key<Virtual<string>>(key, nullWord, 0, 4);
|
|
475
435
|
isKey = false;
|
|
476
436
|
} else if (
|
|
477
437
|
char === tCode &&
|
|
@@ -480,7 +440,7 @@ export namespace JSON {
|
|
|
480
440
|
unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
|
|
481
441
|
) {
|
|
482
442
|
// @ts-ignore
|
|
483
|
-
schema.__JSON_Set_Key(key, trueWord);
|
|
443
|
+
schema.__JSON_Set_Key<Virtual<string>>(key, trueWord, 0, 4);
|
|
484
444
|
isKey = false;
|
|
485
445
|
} else if (
|
|
486
446
|
char === fCode &&
|
|
@@ -490,7 +450,7 @@ export namespace JSON {
|
|
|
490
450
|
unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
|
|
491
451
|
) {
|
|
492
452
|
// @ts-ignore
|
|
493
|
-
schema.__JSON_Set_Key(key,
|
|
453
|
+
schema.__JSON_Set_Key<Virtual<string>>(key, falseWord, 0, 5);
|
|
494
454
|
isKey = false;
|
|
495
455
|
} else if ((char >= 48 && char <= 57) || char === 45) {
|
|
496
456
|
let numberValueIndex = ++outerLoopIndex;
|
|
@@ -498,10 +458,7 @@ export namespace JSON {
|
|
|
498
458
|
const char = unsafeCharCodeAt(data, numberValueIndex);
|
|
499
459
|
if (char === commaCode || char === rightBraceCode || isSpace(char)) {
|
|
500
460
|
// @ts-ignore
|
|
501
|
-
schema.__JSON_Set_Key(
|
|
502
|
-
key,
|
|
503
|
-
data.slice(outerLoopIndex - 1, numberValueIndex)
|
|
504
|
-
);
|
|
461
|
+
schema.__JSON_Set_Key<Virtual<string>>(key, data, outerLoopIndex - 1, numberValueIndex);
|
|
505
462
|
outerLoopIndex = numberValueIndex;
|
|
506
463
|
isKey = false;
|
|
507
464
|
break;
|
|
@@ -639,7 +596,7 @@ export namespace JSON {
|
|
|
639
596
|
}
|
|
640
597
|
|
|
641
598
|
// @ts-ignore: Decorator
|
|
642
|
-
@inline
|
|
599
|
+
@inline function parseObjectArray<T extends unknown[]>(data: string): T {
|
|
643
600
|
const result = instantiate<T>();
|
|
644
601
|
let lastPos: u32 = 1;
|
|
645
602
|
let depth: u32 = 0;
|
package/assembly/src/util.ts
CHANGED
|
@@ -107,19 +107,19 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
107
107
|
// The first char (f) is E or e
|
|
108
108
|
// We push the offset up by two and apply the notation.
|
|
109
109
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
110
|
-
return -(val / (10 ** (
|
|
110
|
+
return -(val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
111
111
|
} else {
|
|
112
112
|
// Inlined this operation instead of using a loop
|
|
113
|
-
return -(val * (10 ** (
|
|
113
|
+
return -(val * (10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1))) as T;
|
|
114
114
|
}
|
|
115
115
|
} else if (high > 57) {
|
|
116
116
|
// The first char (f) is E or e
|
|
117
117
|
// We push the offset up by two and apply the notation.
|
|
118
118
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
119
|
-
return -(val / (10 ** (
|
|
119
|
+
return -(val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
120
120
|
} else {
|
|
121
121
|
// Inlined this operation instead of using a loop
|
|
122
|
-
return -(val * (10 ** (
|
|
122
|
+
return -(val * (10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1))) as T;
|
|
123
123
|
}
|
|
124
124
|
} else {
|
|
125
125
|
val = (val * 100 + ((low - 48) * 10) + (high - 48)) as T;
|
|
@@ -134,10 +134,10 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
134
134
|
// The first char (f) is E or e
|
|
135
135
|
// We push the offset up by two and apply the notation.
|
|
136
136
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
137
|
-
return -(val / (10 ** (
|
|
137
|
+
return -(val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
138
138
|
} else {
|
|
139
139
|
// Inlined this operation instead of using a loop
|
|
140
|
-
return -(val * (10 ** (
|
|
140
|
+
return -(val * (10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1))) as T;
|
|
141
141
|
}
|
|
142
142
|
} else {
|
|
143
143
|
val = (val * 10) + (ch - 48) as T;
|
|
@@ -156,17 +156,17 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
156
156
|
// The first char (f) is E or e
|
|
157
157
|
// We push the offset up by two and apply the notation.
|
|
158
158
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
159
|
-
return (val / (10 ** (
|
|
159
|
+
return (val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
160
160
|
} else {
|
|
161
161
|
// Inlined this operation instead of using a loop
|
|
162
|
-
return (val * (10 ** (
|
|
162
|
+
return (val * (10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1))) as T;
|
|
163
163
|
}
|
|
164
164
|
} else if (high > 57) {
|
|
165
165
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
166
|
-
return (val / (10 ** (
|
|
166
|
+
return (val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
167
167
|
} else {
|
|
168
168
|
// Inlined this operation instead of using a loop
|
|
169
|
-
return (val * (10 ** (
|
|
169
|
+
return (val * (10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1))) as T;
|
|
170
170
|
}
|
|
171
171
|
} else {
|
|
172
172
|
// Optimized with multiplications and shifts.
|
|
@@ -181,10 +181,10 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
181
181
|
// e is 101 and E is 69.
|
|
182
182
|
if (ch > 57) {
|
|
183
183
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
184
|
-
val = (val / (10 ** (
|
|
184
|
+
val = (val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
185
185
|
} else {
|
|
186
186
|
// Inlined this operation instead of using a loop
|
|
187
|
-
val = (val * (10 ** (
|
|
187
|
+
val = (val * (10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1))) as T;
|
|
188
188
|
}
|
|
189
189
|
return val as T;
|
|
190
190
|
} else {
|
|
@@ -209,17 +209,17 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
209
209
|
// The first char (f) is E or e
|
|
210
210
|
// We push the offset up by two and apply the notation.
|
|
211
211
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
212
|
-
return (val / (10 ** (
|
|
212
|
+
return (val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
213
213
|
} else {
|
|
214
214
|
// Inlined this operation instead of using a loop
|
|
215
|
-
return (val * (10 ** (
|
|
215
|
+
return (val * (10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1))) as T;
|
|
216
216
|
}
|
|
217
217
|
} else if (high > 57) {
|
|
218
218
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
219
|
-
return (val / (10 ** (
|
|
219
|
+
return (val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
220
220
|
} else {
|
|
221
221
|
// Inlined this operation instead of using a loop
|
|
222
|
-
return (val * (10 ** (
|
|
222
|
+
return (val * (10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1))) as T;
|
|
223
223
|
}
|
|
224
224
|
} else {
|
|
225
225
|
// Optimized with multiplications and shifts.
|
|
@@ -234,10 +234,10 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
234
234
|
// e is 101 and E is 69.
|
|
235
235
|
if (ch > 57) {
|
|
236
236
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
237
|
-
return (val / (10 ** (
|
|
237
|
+
return (val / (10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1))) as T;
|
|
238
238
|
} else {
|
|
239
239
|
// Inlined this operation instead of using a loop
|
|
240
|
-
return (val * (10 ** (
|
|
240
|
+
return (val * (10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1))) as T;
|
|
241
241
|
}
|
|
242
242
|
} else {
|
|
243
243
|
val = (val * 10) + (ch - 48) as T;
|
|
@@ -252,34 +252,34 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
252
252
|
*/
|
|
253
253
|
|
|
254
254
|
// @ts-ignore
|
|
255
|
-
@inline export function
|
|
255
|
+
@global @inline export function __atoi_fast<T extends number>(str: string, start: u32 = 0, end: u32 = 0): T {
|
|
256
256
|
// @ts-ignore
|
|
257
257
|
let val: T = 0;
|
|
258
|
-
|
|
258
|
+
if (!end) end = start + u32(str.length << 1);
|
|
259
259
|
if (isSigned<T>()) {
|
|
260
260
|
// Negative path
|
|
261
|
-
if (load<u16>(changetype<usize>(str) + <usize>
|
|
262
|
-
|
|
263
|
-
for (;
|
|
264
|
-
val = (val * 10) + (load<u16>(changetype<usize>(str) + <usize>
|
|
261
|
+
if (load<u16>(changetype<usize>(str) + <usize>start) === 45) {
|
|
262
|
+
start += 2;
|
|
263
|
+
for (; start < end; start += 2) {
|
|
264
|
+
val = (val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48) as T;
|
|
265
265
|
}
|
|
266
266
|
return -val as T;
|
|
267
267
|
} else {
|
|
268
|
-
for (;
|
|
269
|
-
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>
|
|
268
|
+
for (; start < end; start += 2) {
|
|
269
|
+
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
270
270
|
}
|
|
271
271
|
return val as T;
|
|
272
272
|
}
|
|
273
273
|
} else {
|
|
274
|
-
for (;
|
|
275
|
-
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>
|
|
274
|
+
for (; start < end; start += 2) {
|
|
275
|
+
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
276
276
|
}
|
|
277
277
|
return val as T;
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
/**
|
|
282
|
-
* Parses an integer using
|
|
282
|
+
* Parses an integer using __atoi_fast and applies the appended exponential number to it as scientific notation.
|
|
283
283
|
* Benchmark: Hovers around 30m ops/s
|
|
284
284
|
* Only safe if the string is valid.
|
|
285
285
|
* @param str integer to parse. example: 123e1, 123e-1, 123E100
|
|
@@ -301,12 +301,12 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
301
301
|
const char = load<u16>(changetype<usize>(str) + <usize>(offset += 2));
|
|
302
302
|
if (char === 45) {
|
|
303
303
|
// @ts-ignore
|
|
304
|
-
val /= sciNote<T>(
|
|
304
|
+
val /= sciNote<T>(__atoi_fast<T>(str, (offset += 2)));
|
|
305
305
|
// @ts-ignore
|
|
306
306
|
return val;
|
|
307
307
|
} else {
|
|
308
308
|
// @ts-ignore
|
|
309
|
-
val *= sciNote<T>(
|
|
309
|
+
val *= sciNote<T>(__atoi_fast<T>(str, offset));
|
|
310
310
|
// @ts-ignore
|
|
311
311
|
return val;
|
|
312
312
|
}
|
|
@@ -336,4 +336,15 @@ import { backSlashCode, quoteCode } from "./chars";
|
|
|
336
336
|
}
|
|
337
337
|
// @ts-ignore
|
|
338
338
|
return res;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// @ts-ignore
|
|
342
|
+
@inline function equalsSlice(p1_data: string, p1_start: i32, p1_end: i32, p2_data: string, p2_start: i32, p2_end: i32): boolean {
|
|
343
|
+
const p1_len = p1_end - p1_start;
|
|
344
|
+
const p2_len = p2_end - p2_start;
|
|
345
|
+
if (p1_len != p2_len) return false;
|
|
346
|
+
if (p1_len == 2) {
|
|
347
|
+
return load<u16>(changetype<usize>(p1_data) + p1_start) == load<u16>(changetype<usize>(p2_data) + p2_start)
|
|
348
|
+
}
|
|
349
|
+
return memory.compare(changetype<usize>(p1_data) + p1_start, changetype<usize>(p2_data) + p2_start, p1_len) === 0;
|
|
339
350
|
}
|