Comparing version
@@ -92,3 +92,3 @@ import { JSON } from ".."; | ||
it("should ser/de string arrays", () => { | ||
canSerde<string[]>(['string \"with random spa\nces and \nnewlines\n\n\n']); | ||
canSerde<string[]>(['string \"with random spa\nces and \nnewlines\n\n\n'], '["string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"]'); | ||
}); | ||
@@ -95,0 +95,0 @@ |
@@ -24,2 +24,3 @@ import { StringSink } from "as-string-sink/assembly"; | ||
falseWord, | ||
newLineCode, | ||
} from "./chars"; | ||
@@ -223,3 +224,3 @@ import { snip_fast, unsafeCharCodeAt } from "./util"; | ||
// @ts-ignore: Decorator | ||
@inline export function serializeString(data: string): string { | ||
@inline function serializeString(data: string): string { | ||
let result = new StringSink('"'); | ||
@@ -235,3 +236,2 @@ | ||
last = i; | ||
//i++; | ||
} else if (char <= 13 && char >= 8) { | ||
@@ -276,3 +276,3 @@ result.write(<string>data, last, i); | ||
@inline function parseString(data: string): string { | ||
let result = ""; | ||
let result = new StringSink(); | ||
let last = 1; | ||
@@ -283,5 +283,5 @@ for (let i = 1; i < data.length - 1; i++) { | ||
const char = unsafeCharCodeAt(data, ++i); | ||
result += data.slice(last, i - 1); | ||
result.write(data, last, i - 1); | ||
if (char === 34) { | ||
result += '"'; | ||
result.writeCodePoint(quoteCode); | ||
last = i + 1; | ||
@@ -291,3 +291,3 @@ } else if (char >= 92 && char <= 117) { | ||
case 92: { | ||
result += "\\"; | ||
result.writeCodePoint(backSlashCode); | ||
last = i + 1; | ||
@@ -297,3 +297,3 @@ break; | ||
case 98: { | ||
result += "\b"; | ||
result.write("\b"); | ||
last = i + 1; | ||
@@ -303,3 +303,3 @@ break; | ||
case 102: { | ||
result += "\f"; | ||
result.write("\f"); | ||
last = i + 1; | ||
@@ -309,3 +309,3 @@ break; | ||
case 110: { | ||
result += "\n"; | ||
result.writeCodePoint(newLineCode); | ||
last = i + 1; | ||
@@ -315,3 +315,3 @@ break; | ||
case 114: { | ||
result += "\r"; | ||
result.write("\r"); | ||
last = i + 1; | ||
@@ -321,3 +321,3 @@ break; | ||
case 116: { | ||
result += "\t"; | ||
result.write("\t"); | ||
last = i + 1; | ||
@@ -332,3 +332,3 @@ break; | ||
) { | ||
result += "\u000b"; | ||
result.write("\u000b"); | ||
i += 4; | ||
@@ -343,4 +343,4 @@ last = i + 1; | ||
} | ||
result += data.slice(last, data.length - 1); | ||
return result; | ||
if ((data.length - 1) > last) result.write(data, last, data.length - 1); | ||
return result.toString(); | ||
} | ||
@@ -356,3 +356,3 @@ | ||
// @ts-ignore: Decorator | ||
@inline export function parseNumber<T>(data: string): T { | ||
@inline function parseNumber<T>(data: string): T { | ||
if (isInteger<T>()) { | ||
@@ -613,3 +613,3 @@ // @ts-ignore | ||
// @ts-ignore: Decorator | ||
@inline export function parseObjectArray<T extends unknown[]>(data: string): T { | ||
@inline function parseObjectArray<T extends unknown[]>(data: string): T { | ||
const result = instantiate<T>(); | ||
@@ -616,0 +616,0 @@ let lastPos: u32 = 1; |
import { bench, blackbox } from "../../../WebAssembly/benchmark-wasm/assembly/bench"; | ||
import { JSON, serializeString } from "./src/json"; | ||
import { JSON, parseString, parseStringArray, parseStringArrayVirtual, serializeString } from "./src/json"; | ||
// @ts-ignore | ||
@@ -50,6 +50,19 @@ @json | ||
console.log("Serialized String: " + serializeString('st"ring" w""ith quotes"')); | ||
console.log("Parsed Array: " + JSON.stringify(parseStringArray('["st\\"ring\\" w\\"\\"ith quotes\\""]'))); | ||
console.log("Parsed Array: " + JSON.stringify(parseStringArrayVirtual('["st\\"ring\\" w\\"\\"ith quotes\\""]'))); | ||
bench("New Stringify String", () => { | ||
blackbox<string>(serializeString(blackbox<string>('st"ring" w""ith quotes"'))); | ||
}); | ||
bench("New Parse String", () => { | ||
blackbox<string>(parseString(blackbox<string>('"st\\"ring\\" w\\"\\"ith quotes\\""'))) | ||
}); | ||
bench("Old Parse String Array", () => { | ||
blackbox<string[]>(parseStringArray('["st\\"ring\\" w\\"\\"ith quotes\\""]')); | ||
}) | ||
bench("New Parse String Array", () => { | ||
blackbox<string[]>(parseStringArrayVirtual('["st\\"ring\\" w\\"\\"ith quotes\\""]')); | ||
}); | ||
/* | ||
@@ -56,0 +69,0 @@ // 9,325,755 |
import { bench, blackbox } from "../../../WebAssembly/benchmark-wasm/assembly/bench"; | ||
import { __atoi_fast, snip_fast, unsafeCharCodeAt } from "../assembly/src/util"; | ||
import { __atoi_fast } from "../assembly/src/util"; | ||
import { JSON } from "../assembly"; | ||
import { backSlashCode, commaCode, eCode, fCode, leftBraceCode, leftBracketCode, nCode, nullWord, quoteCode, rCode, rightBraceCode, rightBracketCode, tCode, trueWord, uCode } from "../assembly/src/chars"; | ||
import { isSpace } from "util/string"; | ||
@json | ||
class Vec3 { | ||
@@ -10,148 +10,2 @@ x: i32; | ||
z: i32; | ||
@inline | ||
__JSON_Serialize(): string { | ||
return `{"x":${this.x.toString()},"y":${this.y.toString()},"z":${this.z.toString()}}`; | ||
} | ||
@inline | ||
__JSON_Set_Key(key: string, value: string): void { | ||
if (key == "x") { | ||
this.x = ____parseObjectValue<i32>(value); | ||
return; | ||
} | ||
if (key == "y") { | ||
this.y = ____parseObjectValue<i32>(value); | ||
return; | ||
} | ||
if (key == "z") { | ||
this.z = ____parseObjectValue<i32>(value); | ||
return; | ||
} | ||
} | ||
@inline | ||
__JSON_Deserialize(data: string): Vec3 { | ||
let schema: nonnull<Vec3> = changetype<nonnull<Vec3>>( | ||
__new(offsetof<nonnull<Vec3>>(), idof<nonnull<Vec3>>()) | ||
); | ||
let key = ""; | ||
let isKey = false; | ||
let depth = 0; | ||
let outerLoopIndex = 1; | ||
for (; outerLoopIndex < data.length - 1; outerLoopIndex++) { | ||
const char = unsafeCharCodeAt(data, outerLoopIndex); | ||
if (char === leftBracketCode) { | ||
for ( | ||
let arrayValueIndex = outerLoopIndex; | ||
arrayValueIndex < data.length - 1; | ||
arrayValueIndex++ | ||
) { | ||
const char = unsafeCharCodeAt(data, arrayValueIndex); | ||
if (char === leftBracketCode) { | ||
depth++; | ||
} else if (char === rightBracketCode) { | ||
depth--; | ||
if (depth === 0) { | ||
++arrayValueIndex; | ||
// @ts-ignore | ||
schema.__JSON_Set_Key( | ||
key, | ||
data.slice(outerLoopIndex, arrayValueIndex) | ||
); | ||
outerLoopIndex = arrayValueIndex; | ||
isKey = false; | ||
break; | ||
} | ||
} | ||
} | ||
} else if (char === leftBraceCode) { | ||
for ( | ||
let objectValueIndex = outerLoopIndex; | ||
objectValueIndex < data.length - 1; | ||
objectValueIndex++ | ||
) { | ||
const char = unsafeCharCodeAt(data, objectValueIndex); | ||
if (char === leftBraceCode) { | ||
depth++; | ||
} else if (char === rightBraceCode) { | ||
depth--; | ||
if (depth === 0) { | ||
++objectValueIndex; | ||
// @ts-ignore | ||
schema.__JSON_Set_Key( | ||
key, | ||
data.slice(outerLoopIndex, objectValueIndex) | ||
); | ||
outerLoopIndex = objectValueIndex; | ||
isKey = false; | ||
break; | ||
} | ||
} | ||
} | ||
} else if (char === quoteCode) { | ||
for ( | ||
let stringValueIndex = ++outerLoopIndex; | ||
stringValueIndex < data.length - 1; | ||
stringValueIndex++ | ||
) { | ||
const char = unsafeCharCodeAt(data, stringValueIndex); | ||
if ( | ||
char === quoteCode && | ||
unsafeCharCodeAt(data, stringValueIndex - 1) !== backSlashCode | ||
) { | ||
if (isKey === false) { | ||
key = data.slice(outerLoopIndex, stringValueIndex); | ||
isKey = true; | ||
} else { | ||
// @ts-ignore | ||
schema.__JSON_Set_Key( | ||
key, | ||
data.slice(outerLoopIndex, stringValueIndex) | ||
); | ||
isKey = false; | ||
} | ||
outerLoopIndex = ++stringValueIndex; | ||
break; | ||
} | ||
} | ||
} else if (char == nCode) { | ||
// @ts-ignore | ||
schema.__JSON_Set_Key(key, nullWord); | ||
isKey = false; | ||
} else if ( | ||
char === tCode && | ||
unsafeCharCodeAt(data, ++outerLoopIndex) === rCode && | ||
unsafeCharCodeAt(data, ++outerLoopIndex) === uCode && | ||
unsafeCharCodeAt(data, ++outerLoopIndex) === eCode | ||
) { | ||
// @ts-ignore | ||
schema.__JSON_Set_Key(key, trueWord); | ||
isKey = false; | ||
} else if ( | ||
char === fCode && | ||
unsafeCharCodeAt(data, ++outerLoopIndex) === "a".charCodeAt(0) && | ||
unsafeCharCodeAt(data, ++outerLoopIndex) === "l".charCodeAt(0) && | ||
unsafeCharCodeAt(data, ++outerLoopIndex) === "s".charCodeAt(0) && | ||
unsafeCharCodeAt(data, ++outerLoopIndex) === eCode | ||
) { | ||
// @ts-ignore | ||
schema.__JSON_Set_Key(key, "false"); | ||
isKey = false; | ||
} else if ((char >= 48 && char <= 57) || char === 45) { | ||
let numberValueIndex = ++outerLoopIndex; | ||
for (; numberValueIndex < data.length; numberValueIndex++) { | ||
const char = unsafeCharCodeAt(data, numberValueIndex); | ||
if (char === commaCode || char === rightBraceCode || isSpace(char)) { | ||
// @ts-ignore | ||
schema.__JSON_Set_Key( | ||
key, | ||
data.slice(outerLoopIndex - 1, numberValueIndex) | ||
); | ||
outerLoopIndex = numberValueIndex; | ||
isKey = false; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
return schema; | ||
} | ||
} | ||
@@ -176,9 +30,9 @@ | ||
}); | ||
*/ | ||
bench("Stringify Object (Vec3)", () => { | ||
blackbox<string>(vec.__JSON_Serialize()); | ||
});*/ | ||
blackbox<string>(JSON.stringify(vec)); | ||
}); | ||
bench("Parse Object (Vec3)", () => { | ||
blackbox<Vec3>(vec.__JSON_Deserialize('{"x":0,"y":0,"z":0}')); | ||
blackbox<Vec3>(JSON.parse<Vec3>('{"x":0,"y":0,"z":0}')); | ||
}); | ||
@@ -201,3 +55,3 @@ | ||
}); | ||
/* | ||
bench("Stringify Boolean Array", () => { | ||
@@ -209,2 +63,2 @@ blackbox(JSON.stringify<boolean[]>([true, false, true])); | ||
blackbox(JSON.stringify<string[]>(["a", "b", "c"])); | ||
}); | ||
});*/ |
{ | ||
"name": "json-as", | ||
"version": "0.5.56", | ||
"version": "0.5.57", | ||
"description": "JSON encoder/decoder for AssemblyScript", | ||
@@ -34,2 +34,3 @@ "types": "assembly/index.ts", | ||
"@assemblyscript/wasi-shim": "^0.1.0", | ||
"as-bench": "^0.0.0-alpha", | ||
"assemblyscript": "^0.27.9", | ||
@@ -48,3 +49,3 @@ "assemblyscript-prettier": "^2.0.2", | ||
"as-variant": "^0.4.1", | ||
"as-virtual": "^0.1.8" | ||
"as-virtual": "^0.1.9" | ||
}, | ||
@@ -51,0 +52,0 @@ "repository": { |
@@ -74,36 +74,54 @@ # AS-JSON | ||
Here are some benchmarks I took with `tinybench` (JavaScript) and `astral` (AssemblyScript). | ||
I took the benchmarks using the minimal runtime which doesn't call the Garbage Collector, so you may expect a 10% to 40% decrease from low to high throughput. | ||
I took the benchmarks using the stub runtime which doesn't call the Garbage Collector, so you may expect a 10% to 40% decrease from low to high throughput. | ||
Tests are run on Ubuntu/WSL2 with a AMD Ryzen 9 CPU | ||
JavaScript Results (TinyBench/NodeJS 19) | ||
JavaScript Results | ||
``` | ||
┌───────────────────────────┬─────────────┬────────────────────┬──────────┐ | ||
│ Task Name │ ops / sec │ Average Time(ns) │ Margin │ | ||
├───────────────────────────┼─────────────┼────────────────────┼──────────┤ | ||
│ 'Stringify Object (Vec3)' │ '817,816' │ 1222.76 │ '±3.55%' │ | ||
│ 'Parse Object (Vec3)' │ '726,115' │ 1377.19 │ '±3.21%' │ | ||
│ 'Stringify Number Array' │ '1,104,036' │ 905.77 │ '±6.48%' │ | ||
│ 'Parse Number Array' │ '1,114,053' │ 897.62 │ '±2.58%' │ | ||
│ 'Stringify String' │ '1,565,716' │ 638.69 │ '±2.04%' │ | ||
│ 'Parse String' │ '69,568' │ 14374.22 │ '±2.55%' │ | ||
└───────────────────────────┴─────────────┴────────────────────┴──────────┘ | ||
NodeJS v20.5.1 - TinyBench v2.5.0 (V8) | ||
┌───────────────────────────┬───────────────┐ | ||
│ Task Name │ ops / sec │ | ||
├───────────────────────────┼───────────────┤ | ||
│ 'Stringify Object (Vec3)' │ '1,191,221' │ | ||
│ 'Parse Object (Vec3)' │ '897,759' │ | ||
│ 'Stringify Number Array' │ '1,552,255' │ | ||
│ 'Parse Number Array' │ '1,225,325' │ | ||
│ 'Stringify String' │ '1,761,011' │ | ||
│ 'Parse String' │ '80,845' │ | ||
└───────────────────────────┴───────────────┘ | ||
``` | ||
AssemblyScript Results (Runtime Minimal) | ||
AssemblyScript Results | ||
``` | ||
┌───────────────────────────┬─────────────┬────────────────────┬──────────┐ | ||
│ Task Name │ ops / sec │ Average Time(ns) │ Diff │ | ||
├───────────────────────────┼─────────────┼────────────────────┼──────────┤ | ||
│ 'Stringify Object (Vec3)' │ '2,091,000' │ 417.22 │ -805ns │ | ||
│ 'Parse Object (Vec3)' │ '1,780,000' │ 539.02 │ -838ns | | ||
│ 'Stringify Number Array' │ '1,920,000' │ 445.43 │ -460ns │ | ||
│ 'Parse Number Array' │ '1,660,000' │ 597.17 │ -300ns │ | ||
│ 'Stringify String' │ '1,280,000' │ 736.27 │ +97ns │ | ||
│ 'Parse String' │ '4,230,000' │ 239.21 │ -14135ns │ | ||
└───────────────────────────┴─────────────┴────────────────────┴──────────┘ | ||
WAVM v0.0.0-prerelease - as-bench v0.0.0-alpha (LLVM) | ||
┌───────────────────────────┬───────────────┐ | ||
│ Task Name │ ops / sec │ | ||
├───────────────────────────┼───────────────┤ | ||
│ 'Stringify Object (Vec3)' │ '6,270,322' │ | ||
│ 'Parse Object (Vec3)' │ '8,000,195' | | ||
│ 'Stringify Number Array' │ '6,664,937' │ | ||
│ 'Parse Number Array' │ '6,557,357' │ | ||
│ 'Stringify String' │ '6,946,947' │ | ||
│ 'Parse String' │ '10,952,502' │ | ||
└───────────────────────────┴───────────────┘ | ||
``` | ||
``` | ||
Wasmtime v11.0.1 - as-bench v0.0.0-alpha (Cranelift) | ||
┌───────────────────────────┬───────────────┐ | ||
│ Task Name │ ops / sec │ | ||
├───────────────────────────┼───────────────┤ | ||
│ 'Stringify Object (Vec3)' │ '2,038,684' │ | ||
│ 'Parse Object (Vec3)' │ '4,623,337' | | ||
│ 'Stringify Number Array' │ '2,500,947' │ | ||
│ 'Parse Number Array' │ '2,959,180' │ | ||
│ 'Stringify String' │ '3,236,896' │ | ||
│ 'Parse String' │ '5,634,594' │ | ||
└───────────────────────────┴───────────────┘ | ||
``` | ||
## Issues | ||
Please submit an issue to https://github.com/JairusSW/as-json/issues if you find anything wrong with this library |
{ | ||
"name": "@json-as/transform", | ||
"version": "0.5.54", | ||
"version": "0.5.57", | ||
"description": "JSON encoder/decoder for AssemblyScript", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
127
16.51%111207
-6.16%13
8.33%2219
-5.21%2
Infinity%Updated