diff --git a/README.md b/README.md index 9ac49fb..4113dee 100644 --- a/README.md +++ b/README.md @@ -92,20 +92,20 @@ My library beats JSON (written in C++) on all counts *and*, I see many places wh Serialization Benchmarks: -| Value | JavaScript (ops/s) | AssemblyScript (ops/s) | % Diff | -|----------------------------|--------------------|------------------------|--------| -| "hello world" | 28,629,598 | 64,210,666 | + 124% | -| 12345 | 31,562,431 | 48,035,001 | + 52% | -| 1.2345 | 15,977,278 | 20,322,939 | + 27% | -| [[],[[]],[[],[[]]]] | 8,998,624 | 34,453,102 | + 283% | +| Value | JavaScript (ops/s) | JSON-as (ops/s) | JSON-AS with Pages | +|----------------------------|--------------------|-----------------|--------------------| +| "hello world" | 28,629,598 | 64,210,666 | + 124% | +| 12345 | 31,562,431 | 48,035,001 | 316,518,756 ops/s | +| 1.2345 | 15,977,278 | 20,322,939 | 30,307,616 ops/s | +| [[],[[]],[[],[[]]]] | 8,998,624 | 34,453,102 | + 283% | Deserialization Benchmarks: (WIP) -| Value | JavaScript (ops/s) | AssemblyScript (ops/s) | % Diff | -|----------------------------|--------------------|------------------------|--------| -| "12345" | 34,647,886 | 254,640,930 | + 635% | +| Value | JavaScript (ops/s) | JSON-AS (ops/s) | % Diff | +|----------------------------|--------------------|-----------------|--------| +| "12345" | 34,647,886 | 254,640,930 | + 635% | And my PC specs: diff --git a/assembly/bench/bench.ts b/assembly/bench/bench.ts index bb7e499..66fab9b 100644 --- a/assembly/bench/bench.ts +++ b/assembly/bench/bench.ts @@ -1,38 +1,45 @@ import { bench, blackbox } from "as-bench/assembly/bench"; import { Sink } from "../src/sink"; import { JSON } from ".."; +import { serializeString } from "../serialize/string"; const set = JSON.Value.from([ JSON.Value.from([]), JSON.Value.from([ - JSON.Value.from([]) + JSON.Value.from([]) ]), JSON.Value.from([ - JSON.Value.from([]), - JSON.Value.from([ - JSON.Value.from([]) - ]), + JSON.Value.from([]), + JSON.Value.from([ + JSON.Value.from([]) + ]), ]), ]); +const page = Sink.withCapacity(65536); +/* +bench("Serialize Integer", () => { + blackbox(JSON.serialize(12345, page)); +}); + + bench("Serialize Set Theoretical Representation", () => { - blackbox(JSON.serialize(set)); + blackbox(JSON.serialize(set,page)); + page.reset(); }); -/*bench("Serialize Float", () => { - blackbox(JSON.serialize(1.2345)); +bench("Serialize Float", () => { + blackbox(JSON.serialize(1.2345, page)); + page.reset(); }); bench("Serialize Float32", () => { - blackbox(JSON.serialize(1.2345)); -}); + blackbox(JSON.serialize(1.2345, page)); + page.reset(); +});*/ bench("Serialize String", () => { - blackbox(JSON.serialize("hello world")); + blackbox(serializeString("hello world", page)); }); - -bench("Serialize Integer", () => { - blackbox(JSON.serialize(12345)); -}); - -bench("Parse Number: " + __atoi_fast("12345").toString(), () => { - blackbox(__atoi_fast("12345")); +/* +bench("Parse Number: " + snip_fast("12345").toString(), () => { + blackbox(snip_fast("12345")); });*/ \ No newline at end of file diff --git a/assembly/serialize/integer.ts b/assembly/serialize/integer.ts index 27aaa39..613f1e3 100644 --- a/assembly/serialize/integer.ts +++ b/assembly/serialize/integer.ts @@ -3,4 +3,47 @@ import { Sink } from "../src/sink"; @inline export function serializeInteger(data: T, out: Sink | null = null): Sink { if (!out) out = Sink.withCapacity(0); return out.writeNumber(data); +} + +@inline export function utoa16(data: u32): string { + const str = changetype(__new(10, idof())); + const buf = changetype(str); + const fix4_28 = (1 << 28) / 10000; + let tmp = data * (fix4_28 + 1) - (data / 4); + + store(buf, 48 + (tmp >> 28)); + tmp = (tmp & 0x0fffffff) * 10; + + store(buf, 48 + (tmp >> 28), 2); + tmp = (tmp & 0x0fffffff) * 10; + + store(buf, 48 + (tmp >> 28), 4); + tmp = (tmp & 0x0fffffff) * 10; + + store(buf, 48 + (tmp >> 28), 6); + tmp = (tmp & 0x0fffffff) * 10; + + store(buf, 48 + (tmp >> 28), 8); + return str +} + +@inline function utoa32(buf: usize, data: u32): void { + const low = data % 10000; + const high = data / 10000; + const fix4_28 = (1 << 28) / 10000; + let tmp = data * (fix4_28 + 1) - (data / 4); + + store(buf, 48 + (tmp >> 28)); + tmp = (tmp & 0x0fffffff) * 10; + + store(buf, 48 + (tmp >> 28), 2); + tmp = (tmp & 0x0fffffff) * 10; + + store(buf, 48 + (tmp >> 28), 4); + tmp = (tmp & 0x0fffffff) * 10; + + store(buf, 48 + (tmp >> 28), 6); + tmp = (tmp & 0x0fffffff) * 10; + + store(buf, 48 + (tmp >> 28), 8); } \ No newline at end of file diff --git a/assembly/src/sink.ts b/assembly/src/sink.ts index 77c1a92..c912929 100644 --- a/assembly/src/sink.ts +++ b/assembly/src/sink.ts @@ -86,7 +86,9 @@ export class Sink { @inline get capacity(): i32 { return this.buffer.byteLength >>> 1; } - + @inline reset(): void { + this.offset = 0; + } @inline write(src: string, start: i32 = 0, end: i32 = i32.MAX_VALUE): Sink | null { let len = src.length as u32; @@ -199,6 +201,38 @@ export class Sink { this.offset = offset; return this; } + @inline writeNumberUnsafe(value: T): Sink { + let offset = this.offset; + if (isInteger()) { + offset += itoa_buffered( + changetype(this.buffer) + offset, + value + ) << 1; + } else { + offset += dtoa_buffered( + changetype(this.buffer) + offset, + value + ) << 1; + } + this.offset = offset; + return this; + } + @inline writeIntegerUnsafe(value: T): Sink { + let offset = this.offset; + if (isInteger()) { + offset += itoa_buffered( + changetype(this.buffer) + offset, + value + ) << 1; + } else { + offset += dtoa_buffered( + changetype(this.buffer) + offset, + value + ) << 1; + } + this.offset = offset; + return this; + } @inline reserve(capacity: i32, clear: bool = false): void { if (clear) this.offset = 0; diff --git a/assembly/test.ts b/assembly/test.ts index 70e9d35..a16bb62 100644 --- a/assembly/test.ts +++ b/assembly/test.ts @@ -1,4 +1,5 @@ import { JSON } from "."; +import { utoa16 } from "./serialize/integer"; import { Sink } from "./src/sink"; import { describe, expect } from "as-test/assembly"; @@ -8,6 +9,8 @@ describe("Serialize String", () => { describe("Serialize Integer", () => { expect(JSON.serialize(65536).toString()).toBe("65536"); + expect(utoa16(65536)).toBe("65536"); + console.log(utoa16(6553)) }); describe("Serialize Float", () => { expect(JSON.serialize(3.1415).toString()).toBe("3.1415");