Skip to content

Commit

Permalink
implement new utoa
Browse files Browse the repository at this point in the history
  • Loading branch information
JairusSW committed Jul 2, 2024
1 parent 17542bb commit 22294d9
Show file tree
Hide file tree
Showing 24 changed files with 36,104 additions and 26,029 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ v0.9.6 - Fix bugs
v0.9.7 - Update testing framework and readme logo
v0.9.8 - Update dependencies
v0.9.8a - Fix #80 - Empty Maps were not serialized to {}, instead, threw memory out of bounds
v0.9.8b - Fix #81 - Revert transform
v1.0.0 - Fix #81 - Revert transform
[UNRELEASED] v0.9.9
- Allow nullable primitives
- Port over JSON.Value
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
__| || __|| || | | ___ | _ || __|
| | ||__ || | || | | ||___|| ||__ |
|_____||_____||_____||_|___| |__|__||_____|
v0.9.8b
v1.0.0
</pre>
</h5>

Expand Down
23 changes: 23 additions & 0 deletions as-test.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"input": ["./assembly/__tests__/*.spec.ts"],
"outDir": "./build",
"suites": [],
"coverage": {
"enabled": true,
"show": false
},
"reporter": "log",
"buildOptions": {
"args": ["--transform json-as/transform"],
"wasi": true,
"parallel": true,
"verbose": true
},
"runOptions": {
"runtime": {
"name": "wasmtime",
"run": "wasmtime <file>",
"args": []
}
}
}
3 changes: 1 addition & 2 deletions assembly/__tests__/test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,5 @@ describe("Should deserialize Objects", () => {
});

run({
log: true,
coverage: true
log: true
});
20 changes: 20 additions & 0 deletions assembly/bl.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { dtoa_buffered, itoa_buffered } from "util/number";
import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
@inline const MAX_LEN: usize = 65536;
const STORE: usize[] = [];
Expand All @@ -8,6 +9,22 @@ let POINTER = changetype<usize>(CACHE);
@inline const MAX_CACHE = CACHE + MAX_LEN;

export namespace bl {
@inline export function write_int<T extends number>(num: T): void {
POINTER += itoa_buffered(POINTER, num) << 1;
if (MAX_CACHE <= POINTER) bl.shrink();
}
@inline export function write_int_u<T extends number>(num: T): void {
POINTER += itoa_buffered(POINTER, num) << 1;
}

@inline export function write_fl<T extends number>(num: T): void {
POINTER += dtoa_buffered(POINTER, num) << 1;
if (MAX_CACHE <= POINTER) bl.shrink();
}
@inline export function write_fl_u<T extends number>(num: T): void {
POINTER += dtoa_buffered(POINTER, num) << 1;
}

@inline export function write_b(buf: usize, bytes: usize = changetype<OBJECT>(buf - TOTAL_OVERHEAD).rtSize): void {
memory.copy(POINTER, buf, bytes);
POINTER += bytes;
Expand All @@ -17,6 +34,7 @@ export namespace bl {
memory.copy(POINTER, buf, bytes);
POINTER += bytes;
}

@inline export function write_s(str: string, bytes: usize = changetype<OBJECT>(changetype<usize>(str) - TOTAL_OVERHEAD).rtSize): void {
memory.copy(POINTER, changetype<usize>(str), bytes);
POINTER += bytes;
Expand All @@ -26,6 +44,7 @@ export namespace bl {
memory.copy(POINTER, changetype<usize>(str), bytes);
POINTER += bytes;
}

@inline export function write_s_se(str: string, start: usize, end: usize): void {
const bytes = end - start;
memory.copy(POINTER, changetype<usize>(str) + start, bytes);
Expand All @@ -37,6 +56,7 @@ export namespace bl {
memory.copy(POINTER, changetype<usize>(str) + start, bytes);
POINTER += bytes;
}

@inline export function write_16(char: i32): void {
store<u16>(POINTER, char);
POINTER += 2;
Expand Down
30 changes: 30 additions & 0 deletions assembly/custom/atoi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Implementation of ATOI. Can be much much faster with SIMD.
*/

// @ts-ignore
export function __atoi_fast<T extends number>(str: string, start: u32 = 0, end: u32 = 0): T {
// @ts-ignore
let val: T = 0;
if (!end) end = start + u32(str.length << 1);
if (isSigned<T>()) {
// Negative path
if (load<u16>(changetype<usize>(str) + <usize>start) === 45) {
start += 2;
for (; start < end; start += 2) {
val = (val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48) as T;
}
return -val as T;
} else {
for (; start < end; start += 2) {
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
}
return val as T;
}
} else {
for (; start < end; start += 2) {
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
}
return val as T;
}
}
48 changes: 48 additions & 0 deletions assembly/custom/itoa.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
@inline export function __itoa_fast<T extends number>(buf: usize, val: T): i32 {
if (val > 10000) {
store<u32>(buf,
(((val / 10000) % 10) + 48) |
((((val / 1000) % 10) + 48) << 16),
0
);
store<u32>(buf,
(((val / 100) % 10) + 48) |
((((val / 10) % 10) + 48) << 16),
4
);
store<u16>(buf, (val % 10) + 48, 8);
} else if (val > 1000) {
store<u32>(buf,
(((val / 1000) % 10) + 48) |
((((val / 100) % 10) + 48) << 16),
0
);
store<u32>(buf,
(((val / 10) % 10) + 48) |
(((val % 10) + 48) << 16),
4
);
} else if (val > 100) {
store<u32>(buf,
(((val / 100) % 10) + 48) |
((((val / 10) % 10) + 48) << 16),
0
);
store<u16>(buf,
((val % 10) + 48),
4
);
} else if (val > 10) {
store<u32>(buf,
(((val / 10) % 10) + 48) |
(((val % 10) + 48) << 16),
0
);
} else {
store<u16>(buf,
val + 48,
0
);
}
return 0;
}
2 changes: 1 addition & 1 deletion assembly/serialize/float.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import { bl } from "../bl";

// @ts-ignore: Decorator valid here
@inline export function serializeFloatBL<T extends number>(data: T): void {
bl.write_s(data.toString());
bl.write_fl(data);
}
2 changes: 1 addition & 1 deletion assembly/serialize/integer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import { bl } from "../bl";

// @ts-ignore: Decorator valid here
@inline export function serializeIntegerBL<T extends number>(data: T): void {
bl.write_32_u(3276849);
bl.write_int<T>(data);
}
3 changes: 1 addition & 2 deletions assembly/serialize/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ import { _intTo16, intTo16, unsafeCharCodeAt } from "../util";
last = i;
}
} else {

if (16 > char) {
if (16 > char) {
result.write(<string>data, last, i);
last = i + 1;
switch (char) {
Expand Down
30 changes: 10 additions & 20 deletions assembly/test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
import { JSON } from ".";
import { bl } from "./bl";
/*
@json
class Vec3 {
x: f64 = 1.0;
y: f64 = 2.0;
z: f64 = 3.0;
__SERIALIZE_BL(): void {
bl.write_128(i16x8(123, 34, 120, 34, 58, 49, 44, 34)); /* {"x":1," */
// bl.write_128(i16x8(121, 34, 58, 50, 44, 34, 122, 34)); /* y":2,"z" */
// bl.write_32(3342394); /* :3 */
// bl.write_16(125); /* } */
// }
//}
//const vec = new Vec3();*/
JSON.stringifyBL("hello w\"orld!");
console.log(bl.out<string>())/*
JSON.stringifyBL(vec);
console.log(bl.out<string>())*/
import { itoa_buffered } from "util/number";
import { __itoa_fast } from "./custom/itoa";

// Usage example
let buf = new ArrayBuffer(10); // 11 characters * 2 bytes per character
const l = __itoa_fast(changetype<usize>(buf), 12345);
console.log(Uint16Array.wrap(buf).join(" "));

const len = itoa_buffered(changetype<usize>(buf), 12345);
console.log(Uint16Array.wrap(buf.slice(0, len * 2)).join(" "));
33 changes: 2 additions & 31 deletions assembly/util.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { isSpace } from "util/string";
import { BACK_SLASH, QUOTE } from "./chars";
import { Sink } from "./sink";
import { __atoi_fast } from "./custom/atoi";


// @ts-ignore: Decorator
export function isMap<T>(): bool {
Expand Down Expand Up @@ -253,37 +255,6 @@ export function snip_fast<T extends number>(str: string, len: u32 = 0, offset: u
}
}

/**
* Implementation of ATOI. Can be much much faster with SIMD.
*/

// @ts-ignore
export function __atoi_fast<T extends number>(str: string, start: u32 = 0, end: u32 = 0): T {
// @ts-ignore
let val: T = 0;
if (!end) end = start + u32(str.length << 1);
if (isSigned<T>()) {
// Negative path
if (load<u16>(changetype<usize>(str) + <usize>start) === 45) {
start += 2;
for (; start < end; start += 2) {
val = (val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48) as T;
}
return -val as T;
} else {
for (; start < end; start += 2) {
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
}
return val as T;
}
} else {
for (; start < end; start += 2) {
val = ((val * 10) + (load<u16>(changetype<usize>(str) + <usize>start) - 48)) as T;
}
return val as T;
}
}

/**
* Parses an integer using __atoi_fast and applies the appended exponential number to it as scientific notation.
* Benchmark: Hovers around 30m ops/s
Expand Down
48 changes: 5 additions & 43 deletions bench/benchmark.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,9 @@
import { bench, blackbox } from "as-bench/assembly/bench";
import { __atoi_fast } from "../assembly/util";
import { JSON } from "../assembly";
import { bench} from "as-bench/assembly/bench";
import { __itoa_fast } from "../assembly/custom/itoa"
import { itoa_buffered } from "util/number";

import { bl } from "../assembly/bl";
import { serializeString, serializeStringBL } from "../assembly/serialize/string";
import { serializeInteger, serializeIntegerBL } from "../assembly/serialize/integer";
import { serializeFloatBL } from "../assembly/serialize/float";
const out = new ArrayBuffer(10);

const out = new ArrayBuffer(65536);
@json
class Vec3 {
x: i32;
y: i32;
z: i32;
__SERIALIZE_BL(): void {
bl.write_128_u(i16x8(123, 34, 120, 34, 58, 49, 44, 34)); /* {"x":1," */
bl.write_128_u(i16x8(121, 34, 58, 50, 44, 34, 122, 34)); /* y":2,"z" */
bl.write_32_u(3342394); /* :3 */
bl.write_16_u(125); /* } */
}
}

@json
class Foo {
a: i32;
b: i32;
c: i32;
d: i32;
e: i32;
f: i32;
g: i32;
h: i32;
i: i32;
j: i32;
k: i32;
}

console.log(load<i32>(changetype<usize>("12")).toString())
const vec: Vec3 = {
x: 3,
y: 1,
z: 8,
}

bench("Serialize String (New)", () => {
serializeStringBL("hello world");
Expand Down Expand Up @@ -73,4 +35,4 @@ bench("Serialize Float", () => {
serializeFloatBL<f64>(1.2345);
bl._out(changetype<usize>(out))
bl.reset();
})
})*/
Binary file modified bench/benchmark.wasm
Binary file not shown.
Binary file modified build/test.spec.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion build/test.spec.wasm.map

Large diffs are not rendered by default.

Loading

0 comments on commit 22294d9

Please sign in to comment.