json-as 1.2.6 → 1.3.1
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 +417 -0
- package/README.md +135 -36
- package/assembly/custom/util.ts +24 -70
- package/assembly/deserialize/float.ts +181 -0
- package/assembly/deserialize/helpers/uint.ts +12 -0
- package/assembly/deserialize/index/arbitrary.ts +25 -0
- package/assembly/deserialize/index/array.ts +61 -0
- package/assembly/deserialize/index/bool.ts +1 -0
- package/assembly/deserialize/index/date.ts +1 -0
- package/assembly/deserialize/index/float.ts +1 -0
- package/assembly/deserialize/index/integer.ts +1 -0
- package/assembly/deserialize/index/map.ts +1 -0
- package/assembly/deserialize/index/object.ts +1 -0
- package/assembly/deserialize/index/raw.ts +1 -0
- package/assembly/deserialize/index/set.ts +1 -0
- package/assembly/deserialize/index/staticarray.ts +1 -0
- package/assembly/deserialize/index/string.ts +15 -0
- package/assembly/deserialize/index/struct.ts +1 -0
- package/assembly/deserialize/index/typedarray.ts +15 -0
- package/assembly/deserialize/index/unsigned.ts +1 -0
- package/assembly/deserialize/index.ts +14 -0
- package/assembly/deserialize/integer.ts +42 -0
- package/assembly/deserialize/simd/array/integer.ts +307 -0
- package/assembly/deserialize/simd/string.ts +130 -11
- package/assembly/deserialize/simple/arbitrary.ts +5 -12
- package/assembly/deserialize/simple/array/arbitrary.ts +12 -36
- package/assembly/deserialize/simple/array/array.ts +2 -8
- package/assembly/deserialize/simple/array/bool.ts +2 -8
- package/assembly/deserialize/simple/array/box.ts +2 -8
- package/assembly/deserialize/simple/array/float.ts +2 -8
- package/assembly/deserialize/simple/array/integer.ts +2 -8
- package/assembly/deserialize/simple/array/map.ts +6 -26
- package/assembly/deserialize/simple/array/object.ts +6 -26
- package/assembly/deserialize/simple/array/raw.ts +18 -61
- package/assembly/deserialize/simple/array/string.ts +5 -10
- package/assembly/deserialize/simple/array/struct.ts +6 -26
- package/assembly/deserialize/simple/array.ts +2 -5
- package/assembly/deserialize/simple/bool.ts +2 -6
- package/assembly/deserialize/simple/map.ts +29 -102
- package/assembly/deserialize/simple/object.ts +24 -81
- package/assembly/deserialize/simple/raw.ts +1 -4
- package/assembly/deserialize/simple/set.ts +11 -37
- package/assembly/deserialize/simple/staticarray/array.ts +1 -1
- package/assembly/deserialize/simple/staticarray/bool.ts +1 -1
- package/assembly/deserialize/simple/staticarray/float.ts +1 -1
- package/assembly/deserialize/simple/staticarray/integer.ts +1 -1
- package/assembly/deserialize/simple/staticarray/string.ts +7 -14
- package/assembly/deserialize/simple/staticarray/struct.ts +1 -1
- package/assembly/deserialize/simple/staticarray.ts +57 -21
- package/assembly/deserialize/simple/string.ts +90 -10
- package/assembly/deserialize/simple/struct.ts +25 -121
- package/assembly/deserialize/simple/typedarray.ts +94 -0
- package/assembly/deserialize/swar/array/arbitrary.ts +8 -0
- package/assembly/deserialize/swar/array/array.ts +39 -0
- package/assembly/deserialize/swar/array/bool.ts +47 -0
- package/assembly/deserialize/swar/array/box.ts +8 -0
- package/assembly/deserialize/swar/array/float.ts +39 -0
- package/assembly/deserialize/swar/array/integer.ts +461 -0
- package/assembly/deserialize/swar/array/map.ts +7 -0
- package/assembly/deserialize/swar/array/object.ts +44 -0
- package/assembly/deserialize/swar/array/raw.ts +8 -0
- package/assembly/deserialize/swar/array/shared.ts +96 -0
- package/assembly/deserialize/swar/array/string.ts +39 -0
- package/assembly/deserialize/swar/array/struct.ts +44 -0
- package/assembly/deserialize/swar/array.ts +49 -0
- package/assembly/deserialize/swar/string.ts +648 -15
- package/assembly/deserialize/unsigned.ts +75 -0
- package/assembly/index.d.ts +1 -3
- package/assembly/index.ts +316 -374
- package/assembly/serialize/index/arbitrary.ts +75 -0
- package/assembly/serialize/index/array.ts +1 -0
- package/assembly/serialize/index/bool.ts +1 -0
- package/assembly/serialize/index/date.ts +1 -0
- package/assembly/serialize/index/float.ts +1 -0
- package/assembly/serialize/index/integer.ts +1 -0
- package/assembly/serialize/index/map.ts +1 -0
- package/assembly/serialize/index/object.ts +46 -0
- package/assembly/serialize/index/raw.ts +1 -0
- package/assembly/serialize/index/set.ts +1 -0
- package/assembly/serialize/index/staticarray.ts +1 -0
- package/assembly/serialize/index/string.ts +15 -0
- package/assembly/serialize/index/struct.ts +1 -0
- package/assembly/serialize/index/typedarray.ts +66 -0
- package/assembly/serialize/index.ts +13 -0
- package/assembly/serialize/simd/string.ts +4 -13
- package/assembly/serialize/simple/arbitrary.ts +6 -0
- package/assembly/serialize/simple/raw.ts +1 -5
- package/assembly/serialize/simple/string.ts +3 -11
- package/assembly/serialize/simple/typedarray.ts +63 -0
- package/assembly/serialize/swar/string.ts +6 -21
- package/assembly/util/concat.ts +1 -5
- package/assembly/util/index.ts +1 -0
- package/assembly/util/masks.ts +12 -18
- package/assembly/util/memory.ts +0 -0
- package/assembly/util/snp.ts +1 -4
- package/assembly/util/stringScan.ts +24 -0
- package/assembly/util/swar.ts +50 -6
- package/lib/as-bs.ts +137 -127
- package/package.json +26 -5
- package/transform/lib/builder.d.ts.map +1 -1
- package/transform/lib/builder.js +5 -13
- package/transform/lib/builder.js.map +1 -1
- package/transform/lib/index.d.ts +1 -0
- package/transform/lib/index.d.ts.map +1 -1
- package/transform/lib/index.js +672 -757
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/linkers/alias.d.ts.map +1 -1
- package/transform/lib/linkers/alias.js.map +1 -1
- package/transform/lib/linkers/custom.d.ts.map +1 -1
- package/transform/lib/linkers/custom.js +8 -9
- package/transform/lib/linkers/custom.js.map +1 -1
- package/transform/lib/linkers/imports.d.ts.map +1 -1
- package/transform/lib/linkers/imports.js.map +1 -1
- package/transform/lib/types.d.ts +6 -0
- package/transform/lib/types.d.ts.map +1 -1
- package/transform/lib/types.js +83 -21
- package/transform/lib/types.js.map +1 -1
- package/transform/lib/util.d.ts.map +1 -1
- package/transform/lib/util.js +1 -1
- package/transform/lib/util.js.map +1 -1
- package/transform/lib/visitor.d.ts.map +1 -1
- package/transform/lib/visitor.js +1 -2
- package/transform/lib/visitor.js.map +1 -1
- package/.prettierrc +0 -3
- package/ARCHITECTURE.md +0 -320
- package/CONTRIBUTING.md +0 -238
- package/TODO +0 -1
- package/assembly/deserialize/simple/float.ts +0 -11
- package/assembly/deserialize/simple/integer.ts +0 -9
- package/assembly/test.ts +0 -30
- package/eslint.config.js +0 -60
- package/lib/tsconfig.json +0 -8
- package/tools/assemblyscript-eslint-local.js +0 -29
- package/tools/assemblyscript-eslint.js +0 -29
- package/transform/tsconfig.json +0 -35
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
- [Using Raw JSON Strings](#using-raw-json-strings)
|
|
15
15
|
- [Working with Enums](#working-with-enums)
|
|
16
16
|
- [Using Custom Serializers or Deserializers](#using-custom-serializers-or-deserializers)
|
|
17
|
+
- [Overriding built-in Container Types](#overriding-built-in-container-types)
|
|
17
18
|
- [Performance](#performance)
|
|
18
19
|
- [Comparison to JavaScript](#comparison-to-javascript)
|
|
19
20
|
- [Performance Tuning](#performance-tuning)
|
|
@@ -36,7 +37,7 @@ npm install json-as
|
|
|
36
37
|
Add the `--transform` to your `asc` command (e.g. in package.json)
|
|
37
38
|
|
|
38
39
|
```bash
|
|
39
|
-
--transform json-as
|
|
40
|
+
--transform json-as
|
|
40
41
|
```
|
|
41
42
|
|
|
42
43
|
Optionally, for additional performance, also add:
|
|
@@ -50,7 +51,7 @@ Alternatively, add it to your `asconfig.json`
|
|
|
50
51
|
```typescript
|
|
51
52
|
{
|
|
52
53
|
"options": {
|
|
53
|
-
"transform": ["json-as
|
|
54
|
+
"transform": ["json-as"]
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
```
|
|
@@ -334,11 +335,11 @@ const serialized = JSON.stringify<Foo>(Foo.bar);
|
|
|
334
335
|
|
|
335
336
|
This library supports custom serialization and deserialization methods, which can be defined using the `@serializer` and `@deserializer` decorators.
|
|
336
337
|
|
|
337
|
-
|
|
338
|
+
Custom serializers and deserializers must always speak valid JSON. You can optionally provide the JSON value shape they operate on using one of: `"any"`, `"string"`, `"number"`, `"object"`, `"array"`, `"boolean"`, or `"null"`. If omitted, the shape defaults to `"any"`.
|
|
338
339
|
|
|
339
|
-
|
|
340
|
-
import { bytes } from "json-as/assembly/util";
|
|
340
|
+
Here's an example of creating a custom data type called `Point` which serializes to a JSON string:
|
|
341
341
|
|
|
342
|
+
```typescript
|
|
342
343
|
@json
|
|
343
344
|
class Point {
|
|
344
345
|
x: f64 = 0.0;
|
|
@@ -348,21 +349,21 @@ class Point {
|
|
|
348
349
|
this.y = y;
|
|
349
350
|
}
|
|
350
351
|
|
|
351
|
-
@serializer
|
|
352
|
+
@serializer("string")
|
|
352
353
|
serializer(self: Point): string {
|
|
353
|
-
return
|
|
354
|
+
return JSON.stringify(`${self.x},${self.y}`);
|
|
354
355
|
}
|
|
355
356
|
|
|
356
|
-
@deserializer
|
|
357
|
+
@deserializer("string")
|
|
357
358
|
deserializer(data: string): Point {
|
|
358
|
-
const
|
|
359
|
-
if (
|
|
359
|
+
const raw = JSON.parse<string>(data);
|
|
360
|
+
if (!raw.length) throw new Error("Could not deserialize provided data as type Point");
|
|
360
361
|
|
|
361
|
-
const c =
|
|
362
|
-
const x =
|
|
363
|
-
const y =
|
|
362
|
+
const c = raw.indexOf(",");
|
|
363
|
+
const x = raw.slice(0, c);
|
|
364
|
+
const y = raw.slice(c + 1);
|
|
364
365
|
|
|
365
|
-
return new Point(f64.parse(x), f64.parse(y));
|
|
366
|
+
return new Point(f64.parse(x), f64.parse(y)); // NEVER use this in deserializers. Always return a new instance
|
|
366
367
|
}
|
|
367
368
|
}
|
|
368
369
|
|
|
@@ -375,9 +376,11 @@ console.log("Serialized " + serialized);
|
|
|
375
376
|
console.log("Deserialized " + JSON.stringify(deserialized));
|
|
376
377
|
```
|
|
377
378
|
|
|
378
|
-
The serializer function converts a `Point` instance into a string
|
|
379
|
+
The serializer function converts a `Point` instance into a valid JSON string value.
|
|
380
|
+
|
|
381
|
+
The deserializer function parses that JSON string back into a `Point` instance.
|
|
379
382
|
|
|
380
|
-
|
|
383
|
+
Custom deserializers should always instantiate and return a new object. They should not assume an existing destination instance will be passed in or reused.
|
|
381
384
|
|
|
382
385
|
These functions are then wrapped before being consumed by the json-as library:
|
|
383
386
|
|
|
@@ -396,19 +399,98 @@ These functions are then wrapped before being consumed by the json-as library:
|
|
|
396
399
|
|
|
397
400
|
This allows custom serialization while maintaining a generic interface for the library to access.
|
|
398
401
|
|
|
399
|
-
|
|
402
|
+
### Overriding built-in container types
|
|
400
403
|
|
|
401
|
-
|
|
404
|
+
Undecorated subclasses of built-in container types keep the built-in JSON behavior.
|
|
405
|
+
|
|
406
|
+
This rule applies consistently across:
|
|
407
|
+
|
|
408
|
+
- `JSON.stringify(...)`
|
|
409
|
+
- `JSON.parse<T>(...)`
|
|
410
|
+
- `JSON.Value.from(...)`
|
|
411
|
+
- `JSON.internal.stringify(...)`
|
|
412
|
+
- `JSON.internal.parse(...)`
|
|
413
|
+
|
|
414
|
+
For example:
|
|
415
|
+
|
|
416
|
+
- `class MyBytes extends Uint8Array {}` still serializes like a normal `Uint8Array`
|
|
417
|
+
- `class MyMap extends Map<string, i32> {}` still serializes like a normal `Map<string, i32>`
|
|
418
|
+
- the same applies to subclassable built-ins such as `Array`, `Set`, and typed arrays
|
|
419
|
+
|
|
420
|
+
If you decorate that subclass with `@json`, it is treated as a normal generated class instead of inheriting the built-in container behavior. That means generated `__SERIALIZE` / `__DESERIALIZE` logic and custom serializer/deserializer hooks can take over.
|
|
421
|
+
|
|
422
|
+
If you want a different wire format, decorate the subclass with `@json` and provide custom `@serializer(...)` / `@deserializer(...)` methods:
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
function hexDigit(value: u8): string {
|
|
426
|
+
return String.fromCharCode(value < 10 ? 48 + value : 87 + value);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function parseHexNibble(code: u16): u8 {
|
|
430
|
+
if (code >= 48 && code <= 57) return <u8>(code - 48);
|
|
431
|
+
if (code >= 97 && code <= 102) return <u8>(code - 87);
|
|
432
|
+
return <u8>(code - 55);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
@json
|
|
436
|
+
class HexBytes extends Uint8Array {
|
|
437
|
+
constructor(length: i32 = 0) {
|
|
438
|
+
super(length);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
@serializer("string")
|
|
442
|
+
serializer(self: HexBytes): string {
|
|
443
|
+
let out = "";
|
|
444
|
+
for (let i = 0; i < self.length; i++) {
|
|
445
|
+
const value = unchecked(self[i]);
|
|
446
|
+
out += hexDigit(value >> 4);
|
|
447
|
+
out += hexDigit(value & 0x0f);
|
|
448
|
+
}
|
|
449
|
+
return JSON.stringify(out);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
@deserializer("string")
|
|
453
|
+
deserializer(data: string): HexBytes {
|
|
454
|
+
const raw = JSON.parse<string>(data);
|
|
455
|
+
const out = new HexBytes(raw.length >> 1);
|
|
456
|
+
|
|
457
|
+
for (let i = 0, j = 0; i < raw.length; i += 2, j++) {
|
|
458
|
+
const hi = parseHexNibble(<u16>raw.charCodeAt(i));
|
|
459
|
+
const lo = parseHexNibble(<u16>raw.charCodeAt(i + 1));
|
|
460
|
+
unchecked((out[j] = <u8>((hi << 4) | lo)));
|
|
461
|
+
}
|
|
402
462
|
|
|
403
|
-
|
|
463
|
+
return out;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const bytes = new HexBytes(4);
|
|
468
|
+
bytes[0] = 10;
|
|
469
|
+
bytes[1] = 20;
|
|
470
|
+
bytes[2] = 30;
|
|
471
|
+
bytes[3] = 40;
|
|
472
|
+
|
|
473
|
+
JSON.stringify(bytes); // "\"0a141e28\""
|
|
474
|
+
JSON.parse<HexBytes>("\"0a141e28\"");
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
This same pattern works for subclassable built-ins like `Array`, `Map`, `Set`, and typed arrays.
|
|
404
478
|
|
|
405
|
-
|
|
479
|
+
`ArrayBuffer` and `String` are `@final` in AssemblyScript, so they cannot be subclassed there.
|
|
480
|
+
|
|
481
|
+
## Performance
|
|
482
|
+
|
|
483
|
+
The `json-as` library is engineered for **multi-GB/s processing speeds**, leveraging SIMD and SWAR optimizations along with highly efficient transformations. The charts below highlight key performance metrics such as build time, operations-per-second, and throughput.
|
|
406
484
|
|
|
407
485
|
### Comparison to JavaScript
|
|
408
486
|
|
|
409
|
-
The following charts compare JSON-AS (both SWAR and SIMD variants) against JavaScript's native `JSON` implementation.
|
|
487
|
+
The following charts compare JSON-AS (both SWAR and SIMD variants) against JavaScript's native `JSON` implementation. The published charts are generated locally and pushed to the `docs` branch.
|
|
410
488
|
|
|
411
489
|
> Note: Benchmarks reflect the **latest version**. Older versions may show different performance.
|
|
490
|
+
>
|
|
491
|
+
> Current local benchmark machine: AMD Ryzen 7 7800X3D (8 cores, 8 threads), 96 MB L3 cache, 32 GB RAM.
|
|
492
|
+
>
|
|
493
|
+
> Benchmark results include normal end-to-end work such as allocating the destination object or array before deserializing into it. Raw parser throughput is higher than the published figures because these numbers intentionally include that allocation/setup cost.
|
|
412
494
|
|
|
413
495
|
<img src="https://raw.githubusercontent.com/JairusSW/json-as/refs/heads/docs/charts/chart01.svg" alt="Performance Chart 1">
|
|
414
496
|
|
|
@@ -418,9 +500,9 @@ The following charts compare JSON-AS (both SWAR and SIMD variants) against JavaS
|
|
|
418
500
|
|
|
419
501
|
<img src="https://raw.githubusercontent.com/JairusSW/json-as/refs/heads/docs/charts/chart04.png" alt="Performance Chart 4">
|
|
420
502
|
|
|
421
|
-
|
|
503
|
+
<img src="https://raw.githubusercontent.com/JairusSW/json-as/refs/heads/docs/charts/chart05.png" alt="Performance Chart 5">
|
|
422
504
|
|
|
423
|
-
|
|
505
|
+
<img src="https://raw.githubusercontent.com/JairusSW/json-as/refs/heads/docs/charts/chart06.png" alt="Performance Chart 6">
|
|
424
506
|
|
|
425
507
|
### Performance Tuning
|
|
426
508
|
|
|
@@ -433,46 +515,63 @@ Here's a short list:
|
|
|
433
515
|
|
|
434
516
|
**JSON_MODE** (default: SWAR) - Selects which mode should be used. Can be `NAIVE,SWAR,SIMD`. Note that `--enable simd` may be required.
|
|
435
517
|
|
|
518
|
+
**JSON_USE_FAST_PATH** (default: 0) - When set to `1`, the transform emits the fast `__DESERIALIZE` implementation for generated structs. When unset or `0`, it emits only the slow path.
|
|
519
|
+
|
|
436
520
|
**JSON_WRITE** (default: "") - Select a series of files to output after transform and optimization passes have completed for easy inspection. Usage: `JSON_WRITE=.path-to-file-a.ts,./path-to-file-b.ts`
|
|
437
521
|
|
|
438
|
-
### Running
|
|
522
|
+
### Running Benchmarks Locally
|
|
439
523
|
|
|
440
|
-
Benchmarks are run directly on top of v8 for
|
|
524
|
+
Benchmarks are run directly on top of `v8` for tighter control over the engine configuration.
|
|
441
525
|
|
|
442
|
-
1.
|
|
526
|
+
1. Install the local benchmark prerequisites:
|
|
443
527
|
|
|
444
528
|
```bash
|
|
445
|
-
npm install
|
|
529
|
+
npm install -g jsvu
|
|
530
|
+
jsvu --engines=v8
|
|
446
531
|
```
|
|
447
532
|
|
|
448
|
-
2.
|
|
533
|
+
2. Add `~/.jsvu/bin` to your `PATH` and make sure `wasm-opt` is installed:
|
|
449
534
|
|
|
450
535
|
```bash
|
|
451
536
|
export PATH="${HOME}/.jsvu/bin:${PATH}"
|
|
537
|
+
sudo apt-get install -y binaryen
|
|
452
538
|
```
|
|
453
539
|
|
|
454
|
-
3.
|
|
540
|
+
3. Install project dependencies:
|
|
455
541
|
|
|
456
542
|
```bash
|
|
457
|
-
|
|
543
|
+
npm install
|
|
458
544
|
```
|
|
459
545
|
|
|
460
|
-
4.
|
|
546
|
+
4. Run either benchmark suite directly:
|
|
461
547
|
|
|
462
548
|
```bash
|
|
463
|
-
|
|
549
|
+
./run-bench.as.sh
|
|
550
|
+
./run-bench.js.sh
|
|
464
551
|
```
|
|
465
552
|
|
|
466
|
-
5.
|
|
553
|
+
5. Build charts from the latest local logs:
|
|
467
554
|
|
|
468
555
|
```bash
|
|
469
|
-
./
|
|
556
|
+
./build-charts.sh
|
|
470
557
|
```
|
|
471
558
|
|
|
472
|
-
|
|
559
|
+
6. Publish benchmark charts to the `docs` branch:
|
|
473
560
|
|
|
474
561
|
```bash
|
|
475
|
-
./
|
|
562
|
+
./publish-benchmarks.sh
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
If you already have fresh logs and only want to rebuild charts and push them:
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
./publish-benchmarks.sh --no-run
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
Or run the full local publish flow in one step:
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
npm run bench:publish
|
|
476
575
|
```
|
|
477
576
|
|
|
478
577
|
## Debugging
|
package/assembly/custom/util.ts
CHANGED
|
@@ -15,11 +15,7 @@
|
|
|
15
15
|
* @param str - Any number. Can include scientific notation.
|
|
16
16
|
*/
|
|
17
17
|
// @ts-ignore: Decorator
|
|
18
|
-
@inline export function snip_fast<T extends number>(
|
|
19
|
-
str: string,
|
|
20
|
-
len: u32 = 0,
|
|
21
|
-
offset: u32 = 0,
|
|
22
|
-
): T {
|
|
18
|
+
@inline export function snip_fast<T extends number>(str: string, len: u32 = 0, offset: u32 = 0): T {
|
|
23
19
|
if (isSigned<T>()) {
|
|
24
20
|
const firstChar: u32 = load<u16>(changetype<usize>(str));
|
|
25
21
|
if (firstChar == 48) return 0 as T;
|
|
@@ -39,31 +35,19 @@
|
|
|
39
35
|
// The first char (f) is E or e
|
|
40
36
|
// We push the offset up by two and apply the notation.
|
|
41
37
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
42
|
-
return -(
|
|
43
|
-
val /
|
|
44
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)
|
|
45
|
-
) as T;
|
|
38
|
+
return -(val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
46
39
|
} else {
|
|
47
40
|
// Inlined this operation instead of using a loop
|
|
48
|
-
return -(
|
|
49
|
-
val *
|
|
50
|
-
10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)
|
|
51
|
-
) as T;
|
|
41
|
+
return -(val * 10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
52
42
|
}
|
|
53
43
|
} else if (high > 57) {
|
|
54
44
|
// The first char (f) is E or e
|
|
55
45
|
// We push the offset up by two and apply the notation.
|
|
56
46
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
57
|
-
return -(
|
|
58
|
-
val /
|
|
59
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)
|
|
60
|
-
) as T;
|
|
47
|
+
return -(val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
61
48
|
} else {
|
|
62
49
|
// Inlined this operation instead of using a loop
|
|
63
|
-
return -(
|
|
64
|
-
val *
|
|
65
|
-
10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1)
|
|
66
|
-
) as T;
|
|
50
|
+
return -(val * 10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1)) as T;
|
|
67
51
|
}
|
|
68
52
|
} else {
|
|
69
53
|
val = (val * 100 + (low - 48) * 10 + (high - 48)) as T;
|
|
@@ -78,16 +62,10 @@
|
|
|
78
62
|
// The first char (f) is E or e
|
|
79
63
|
// We push the offset up by two and apply the notation.
|
|
80
64
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
81
|
-
return -(
|
|
82
|
-
val /
|
|
83
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)
|
|
84
|
-
) as T;
|
|
65
|
+
return -(val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
85
66
|
} else {
|
|
86
67
|
// Inlined this operation instead of using a loop
|
|
87
|
-
return -(
|
|
88
|
-
val *
|
|
89
|
-
10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)
|
|
90
|
-
) as T;
|
|
68
|
+
return -(val * 10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
91
69
|
}
|
|
92
70
|
} else {
|
|
93
71
|
val = (val * 10 + (ch - 48)) as T;
|
|
@@ -106,21 +84,17 @@
|
|
|
106
84
|
// The first char (f) is E or e
|
|
107
85
|
// We push the offset up by two and apply the notation.
|
|
108
86
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
109
|
-
return (val /
|
|
110
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
87
|
+
return (val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
111
88
|
} else {
|
|
112
89
|
// Inlined this operation instead of using a loop
|
|
113
|
-
return (val *
|
|
114
|
-
10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
90
|
+
return (val * 10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
115
91
|
}
|
|
116
92
|
} else if (high > 57) {
|
|
117
93
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
118
|
-
return (val /
|
|
119
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
94
|
+
return (val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
120
95
|
} else {
|
|
121
96
|
// Inlined this operation instead of using a loop
|
|
122
|
-
return (val *
|
|
123
|
-
10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1)) as T;
|
|
97
|
+
return (val * 10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1)) as T;
|
|
124
98
|
}
|
|
125
99
|
} else {
|
|
126
100
|
// Optimized with multiplications and shifts.
|
|
@@ -135,12 +109,10 @@
|
|
|
135
109
|
// e is 101 and E is 69.
|
|
136
110
|
if (ch > 57) {
|
|
137
111
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
138
|
-
val = (val /
|
|
139
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
112
|
+
val = (val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
140
113
|
} else {
|
|
141
114
|
// Inlined this operation instead of using a loop
|
|
142
|
-
val = (val *
|
|
143
|
-
10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
115
|
+
val = (val * 10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
144
116
|
}
|
|
145
117
|
return val as T;
|
|
146
118
|
} else {
|
|
@@ -165,21 +137,17 @@
|
|
|
165
137
|
// The first char (f) is E or e
|
|
166
138
|
// We push the offset up by two and apply the notation.
|
|
167
139
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
168
|
-
return (val /
|
|
169
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
140
|
+
return (val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
170
141
|
} else {
|
|
171
142
|
// Inlined this operation instead of using a loop
|
|
172
|
-
return (val *
|
|
173
|
-
10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
143
|
+
return (val * 10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
174
144
|
}
|
|
175
145
|
} else if (high > 57) {
|
|
176
146
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 4) == 45) {
|
|
177
|
-
return (val /
|
|
178
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
147
|
+
return (val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
179
148
|
} else {
|
|
180
149
|
// Inlined this operation instead of using a loop
|
|
181
|
-
return (val *
|
|
182
|
-
10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1)) as T;
|
|
150
|
+
return (val * 10 ** (__atoi_fast<u32>(str, offset + 4, offset + 6) + 1)) as T;
|
|
183
151
|
}
|
|
184
152
|
} else {
|
|
185
153
|
// Optimized with multiplications and shifts.
|
|
@@ -194,12 +162,10 @@
|
|
|
194
162
|
// e is 101 and E is 69.
|
|
195
163
|
if (ch > 57) {
|
|
196
164
|
if (load<u16>(changetype<usize>(str) + <usize>offset + 2) == 45) {
|
|
197
|
-
return (val /
|
|
198
|
-
10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
165
|
+
return (val / 10 ** (__atoi_fast<u32>(str, offset + 6, offset + 8) - 1)) as T;
|
|
199
166
|
} else {
|
|
200
167
|
// Inlined this operation instead of using a loop
|
|
201
|
-
return (val *
|
|
202
|
-
10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
168
|
+
return (val * 10 ** (__atoi_fast<u32>(str, offset + 2, offset + 4) + 1)) as T;
|
|
203
169
|
}
|
|
204
170
|
} else {
|
|
205
171
|
val = (val * 10 + (ch - 48)) as T;
|
|
@@ -214,11 +180,7 @@
|
|
|
214
180
|
*/
|
|
215
181
|
|
|
216
182
|
// @ts-ignore
|
|
217
|
-
@inline export function __atoi_fast<T extends number>(
|
|
218
|
-
str: string,
|
|
219
|
-
start: u32 = 0,
|
|
220
|
-
end: u32 = 0,
|
|
221
|
-
): T {
|
|
183
|
+
@inline export function __atoi_fast<T extends number>(str: string, start: u32 = 0, end: u32 = 0): T {
|
|
222
184
|
// @ts-ignore
|
|
223
185
|
let val: T = 0;
|
|
224
186
|
if (!end) end = start + u32(str.length << 1);
|
|
@@ -227,21 +189,18 @@
|
|
|
227
189
|
if (load<u16>(changetype<usize>(str) + <usize>start) == 45) {
|
|
228
190
|
start += 2;
|
|
229
191
|
for (; start < end; start += 2) {
|
|
230
|
-
val = (val * 10 +
|
|
231
|
-
(load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
192
|
+
val = (val * 10 + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
232
193
|
}
|
|
233
194
|
return -val as T;
|
|
234
195
|
} else {
|
|
235
196
|
for (; start < end; start += 2) {
|
|
236
|
-
val = (val * 10 +
|
|
237
|
-
(load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
197
|
+
val = (val * 10 + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
238
198
|
}
|
|
239
199
|
return val as T;
|
|
240
200
|
}
|
|
241
201
|
} else {
|
|
242
202
|
for (; start < end; start += 2) {
|
|
243
|
-
val = (val * 10 +
|
|
244
|
-
(load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
203
|
+
val = (val * 10 + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
|
|
245
204
|
}
|
|
246
205
|
return val as T;
|
|
247
206
|
}
|
|
@@ -308,12 +267,7 @@
|
|
|
308
267
|
}
|
|
309
268
|
|
|
310
269
|
// @ts-ignore
|
|
311
|
-
@inline export function containsCodePoint(
|
|
312
|
-
str: string,
|
|
313
|
-
code: u32,
|
|
314
|
-
start: i32,
|
|
315
|
-
end: i32,
|
|
316
|
-
): bool {
|
|
270
|
+
@inline export function containsCodePoint(str: string, code: u32, start: i32, end: i32): bool {
|
|
317
271
|
for (let i = start; i <= end; i++) {
|
|
318
272
|
if (unsafeCharCodeAt(str, i) == code) return true;
|
|
319
273
|
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { ptrToStr } from "../util/ptrToStr";
|
|
2
|
+
|
|
3
|
+
// @ts-ignore: inline
|
|
4
|
+
@inline function pow10Fast(exponent: u32): f64 {
|
|
5
|
+
let result = 1.0;
|
|
6
|
+
if (exponent & 1) result *= 1e1;
|
|
7
|
+
if (exponent & 2) result *= 1e2;
|
|
8
|
+
if (exponent & 4) result *= 1e4;
|
|
9
|
+
if (exponent & 8) result *= 1e8;
|
|
10
|
+
if (exponent & 16) result *= 1e16;
|
|
11
|
+
if (exponent & 32) result *= 1e32;
|
|
12
|
+
if (exponent & 64) result *= 1e64;
|
|
13
|
+
if (exponent & 128) result *= 1e128;
|
|
14
|
+
if (exponent & 256) result *= 1e256;
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// @ts-ignore: inline
|
|
19
|
+
@inline export function deserializeFloat<T>(srcStart: usize, srcEnd: usize): T {
|
|
20
|
+
let negative = false;
|
|
21
|
+
if (load<u16>(srcStart) == 45) {
|
|
22
|
+
negative = true;
|
|
23
|
+
srcStart += 2;
|
|
24
|
+
if (srcStart >= srcEnd) unreachable();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let value: f64 = 0.0;
|
|
28
|
+
let seenDigit = false;
|
|
29
|
+
|
|
30
|
+
while (srcStart < srcEnd) {
|
|
31
|
+
const digit = <u32>load<u16>(srcStart) - 48;
|
|
32
|
+
if (digit > 9) break;
|
|
33
|
+
value = value * 10.0 + <f64>digit;
|
|
34
|
+
seenDigit = true;
|
|
35
|
+
srcStart += 2;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (srcStart < srcEnd && load<u16>(srcStart) == 46) {
|
|
39
|
+
srcStart += 2;
|
|
40
|
+
let fraction: u64 = 0;
|
|
41
|
+
let digits: u32 = 0;
|
|
42
|
+
while (srcStart < srcEnd) {
|
|
43
|
+
const digit = <u32>load<u16>(srcStart) - 48;
|
|
44
|
+
if (digit > 9) break;
|
|
45
|
+
fraction = fraction * 10 + digit;
|
|
46
|
+
digits += 1;
|
|
47
|
+
seenDigit = true;
|
|
48
|
+
srcStart += 2;
|
|
49
|
+
}
|
|
50
|
+
if (digits != 0) value += <f64>fraction / pow10Fast(digits);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!seenDigit) {
|
|
54
|
+
// @ts-ignore
|
|
55
|
+
const type: T = 0;
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
if (type instanceof f64) return f64.parse(ptrToStr(srcStart, srcEnd));
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
return f32.parse(ptrToStr(srcStart, srcEnd));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (srcStart < srcEnd) {
|
|
63
|
+
const code = load<u16>(srcStart);
|
|
64
|
+
if (code == 101 || code == 69) {
|
|
65
|
+
srcStart += 2;
|
|
66
|
+
if (srcStart >= srcEnd) unreachable();
|
|
67
|
+
|
|
68
|
+
let exponentNegative = false;
|
|
69
|
+
let exponentCode = load<u16>(srcStart);
|
|
70
|
+
if (exponentCode == 45 || exponentCode == 43) {
|
|
71
|
+
exponentNegative = exponentCode == 45;
|
|
72
|
+
srcStart += 2;
|
|
73
|
+
if (srcStart >= srcEnd) unreachable();
|
|
74
|
+
exponentCode = load<u16>(srcStart);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let exponent = <u32>exponentCode - 48;
|
|
78
|
+
if (exponent > 9) unreachable();
|
|
79
|
+
srcStart += 2;
|
|
80
|
+
while (srcStart < srcEnd) {
|
|
81
|
+
const digit = <u32>load<u16>(srcStart) - 48;
|
|
82
|
+
if (digit > 9) break;
|
|
83
|
+
exponent = exponent * 10 + digit;
|
|
84
|
+
srcStart += 2;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const power = pow10Fast(exponent);
|
|
88
|
+
value = exponentNegative ? value / power : value * power;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (negative) value = -value;
|
|
93
|
+
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
const type: T = 0;
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
if (type instanceof f64) return <T>value;
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
return <T>(<f32>value);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// @ts-ignore: inline
|
|
103
|
+
@inline export function deserializeFloatField<T extends number>(srcStart: usize, srcEnd: usize, fieldPtr: usize): usize {
|
|
104
|
+
let negative = false;
|
|
105
|
+
if (load<u16>(srcStart) == 45) {
|
|
106
|
+
negative = true;
|
|
107
|
+
srcStart += 2;
|
|
108
|
+
if (srcStart >= srcEnd) unreachable();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let value: f64 = 0.0;
|
|
112
|
+
let seenDigit = false;
|
|
113
|
+
|
|
114
|
+
while (srcStart < srcEnd) {
|
|
115
|
+
const code = load<u16>(srcStart);
|
|
116
|
+
const digit = <u32>code - 48;
|
|
117
|
+
if (digit > 9) break;
|
|
118
|
+
value = value * 10.0 + <f64>digit;
|
|
119
|
+
seenDigit = true;
|
|
120
|
+
srcStart += 2;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (srcStart < srcEnd && load<u16>(srcStart) == 46) {
|
|
124
|
+
srcStart += 2;
|
|
125
|
+
let fraction: u64 = 0;
|
|
126
|
+
let digits: u32 = 0;
|
|
127
|
+
while (srcStart < srcEnd) {
|
|
128
|
+
const code = load<u16>(srcStart);
|
|
129
|
+
const digit = <u32>code - 48;
|
|
130
|
+
if (digit > 9) break;
|
|
131
|
+
fraction = fraction * 10 + digit;
|
|
132
|
+
digits += 1;
|
|
133
|
+
seenDigit = true;
|
|
134
|
+
srcStart += 2;
|
|
135
|
+
}
|
|
136
|
+
if (digits != 0) value += <f64>fraction / pow10Fast(digits);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!seenDigit) unreachable();
|
|
140
|
+
|
|
141
|
+
if (srcStart < srcEnd) {
|
|
142
|
+
const code = load<u16>(srcStart);
|
|
143
|
+
if (code == 101 || code == 69) {
|
|
144
|
+
srcStart += 2;
|
|
145
|
+
if (srcStart >= srcEnd) unreachable();
|
|
146
|
+
|
|
147
|
+
let exponentNegative = false;
|
|
148
|
+
let exponentCode = load<u16>(srcStart);
|
|
149
|
+
if (exponentCode == 45 || exponentCode == 43) {
|
|
150
|
+
exponentNegative = exponentCode == 45;
|
|
151
|
+
srcStart += 2;
|
|
152
|
+
if (srcStart >= srcEnd) unreachable();
|
|
153
|
+
exponentCode = load<u16>(srcStart);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let exponent = <u32>exponentCode - 48;
|
|
157
|
+
if (exponent > 9) unreachable();
|
|
158
|
+
srcStart += 2;
|
|
159
|
+
while (srcStart < srcEnd) {
|
|
160
|
+
const code = load<u16>(srcStart);
|
|
161
|
+
const digit = <u32>code - 48;
|
|
162
|
+
if (digit > 9) break;
|
|
163
|
+
exponent = exponent * 10 + digit;
|
|
164
|
+
srcStart += 2;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const power = pow10Fast(exponent);
|
|
168
|
+
value = exponentNegative ? value / power : value * power;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (negative) value = -value;
|
|
173
|
+
|
|
174
|
+
if (sizeof<T>() == sizeof<f32>()) {
|
|
175
|
+
store<f32>(fieldPtr, <f32>value);
|
|
176
|
+
} else {
|
|
177
|
+
store<f64>(fieldPtr, value);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return srcStart;
|
|
181
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function deserializeUintScan<T extends number>(src: usize, dst: usize): usize {
|
|
2
|
+
let digit = <T>load<u16>(src) - 48;
|
|
3
|
+
if (digit > 9) abort("Found invalid digit");
|
|
4
|
+
let val = digit;
|
|
5
|
+
src += 2;
|
|
6
|
+
while ((digit = <u32>load<u16>(src) - 48) < 10) {
|
|
7
|
+
val = val * 10 + digit;
|
|
8
|
+
src += 2;
|
|
9
|
+
}
|
|
10
|
+
store<T>(dst, val);
|
|
11
|
+
return src;
|
|
12
|
+
}
|