Skip to content

Commit

Permalink
Merge pull request #13 from aminya/perf
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya authored Jul 7, 2021
2 parents eb1adeb + 9be67f4 commit 6f33d71
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 23 deletions.
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ pnpm-lock.yaml
package-lock.json
CHANGELOG.md
dist
test/fixtures/*-minified.json
dub.selections.json
12 changes: 6 additions & 6 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# minijson

Minify JSON files **fast**! Written in D.
Minify JSON files **blazing fast**! Written in D.

1.5 times faster than jsonminify.
55 times faster than jsonminify!

[![CI](https://github.com/aminya/minijson/actions/workflows/CI.yml/badge.svg)](https://github.com/aminya/minijson/actions/workflows/CI.yml)

Expand All @@ -23,9 +23,9 @@ https://github.com/aminya/minijson/releases/tag/v0.3.1
- Dub

```
dub build --config=library --build=release --compiler=ldc2
dub build --config=library --build=release-nobounds --compiler=ldc2
# or
dub build --config=executable --build=release --compiler=ldc2
dub build --config=executable --build=release-nobounds --compiler=ldc2
```

### CLI Usage
Expand Down Expand Up @@ -70,10 +70,10 @@ minifyFiles(["file1.json", "file2.json"]);

```
❯ node .\benchmark\native-benchmark.mjs
38,823 ms
1.086 seconds
❯ node .\benchmark\js-benchmark.mjs
58,686 ms
58.686 seconds
```

### Contributing
Expand Down
2 changes: 1 addition & 1 deletion benchmark/js-benchmark.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ await Promise.all(
)

const t2 = performance.now()
console.log(t2 - t1)
console.log(((t2 - t1)/1000).toFixed(3), "seconds")
2 changes: 1 addition & 1 deletion benchmark/native-benchmark.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ const t1 = performance.now()
await minifyFiles(jsonFiles)

const t2 = performance.now()
console.log(t2 - t1)
console.log(((t2 - t1)/1000).toFixed(3), "seconds")
2 changes: 2 additions & 0 deletions dub.sdl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ targetPath "./dist"
sourcePaths "./src/native"
importPaths "./src/native"

dependency "automem" version="~>0.6.6"

configuration "executable" {
targetType "executable"
mainSourceFile "./src/native/cli.d"
Expand Down
8 changes: 8 additions & 0 deletions dub.selections.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"fileVersion": 1,
"versions": {
"automem": "0.6.6",
"test_allocator": "0.3.3",
"unit-threaded": "2.0.0"
}
}
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@aminya/minijson",
"author": "Amin Yahyaabdi",
"version": "0.3.1",
"description": "Minify JSON files fast! Written in D",
"description": "Minify JSON files blazing fast! Written in D",
"homepage": "https://github.com/aminya/minijson",
"license": "MIT",
"files": [
Expand All @@ -20,9 +20,9 @@
"test": "jasmine ./test/index-test.mjs",
"clean": "shx rm -rf dist",
"build.native": "dub build --config=executable",
"build.native.release": "pnpm build.native -- --build release",
"build.native.profile": "pnpm build.native -- --build profile",
"start.profile": "cd dist && minijson.exe --file ../benchmark/fixtures/1.0.0.json && profdump.exe --dot trace.log trace.dot && dot -Tsvg trace.dot -o trace.svg && ./trace.svg",
"build.native.release": "pnpm build.native -- --build release-nobounds --compiler=ldc2",
"build.native.profile": "pnpm build.native -- --build profile --compiler=ldc2",
"start.profile": "cd dist && minijson.exe --file ../test/fixtures/0.4.2.json && profdump.exe --dot trace.log trace.dot && dot -Tsvg trace.dot -o trace.svg && ./trace.svg",
"build.node": "npm run build.native.release && node ./src/node/build.js && (tsc -p ./src/node/tsconfig.json || echo done)",
"build.wasm": "ldc2 ./src/wasm/wasm.d ./src/native/lib.d --od ./dist --O3 --mtriple=wasm32-unknown-unknown-wasm",
"build.browser": "npm run build.wasm && parcel build --target browser ./src/browser/index.html",
Expand Down
26 changes: 16 additions & 10 deletions src/native/lib.d
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
module minijson.lib;

import std : ctRegex, replaceAll, join, appender, array, matchAll, matchFirst, RegexMatch;
import std : ctRegex, replaceAll, join, array, matchAll, matchFirst, RegexMatch;
import automem : Vector;

const tokenizer = ctRegex!(`"|(/\*)|(\*/)|(//)|\n|\r|[|]`, "g");
const tokenizerWithComment = ctRegex!(`"|(/\*)|(\*/)|(//)|\n|\r|\[|]`, "g");
const tokenizerNoComment = ctRegex!(`[\n\r"[]]`, "g");

const spaceOrBreakRegex = ctRegex!(`\s`);

Expand All @@ -18,15 +20,17 @@ const repeatingBackSlashRegex = ctRegex!(`(\\)*$`);
Return:
the minified json string
*/
string minifyString(string jsonString, bool hasComments = false) @safe
string minifyString(string jsonString, bool hasComments = false) @trusted
{
auto in_string = false;
auto in_multiline_comment = false;
auto in_singleline_comment = false;
auto new_str = appender!(string[]);
Vector!string new_str;
size_t from = 0;
auto rightContext = "";

const tokenizer = !hasComments ? tokenizerNoComment : tokenizerWithComment;

auto match = jsonString.matchAll(tokenizer);

while (!match.empty())
Expand All @@ -39,22 +43,23 @@ string minifyString(string jsonString, bool hasComments = false) @safe
const lastIndex = jsonString.length - rightContext.length;

const noCommentOrNotInComment = !hasComments || (!in_multiline_comment && !in_singleline_comment);

auto leftContextSubstr = leftContext[from .. $];
if (noCommentOrNotInComment)
{
auto leftContextSubstr = leftContext[from .. $];
if (!in_string)
{
leftContextSubstr = leftContextSubstr.replaceAll(spaceOrBreakRegex, "");
}
new_str.put(leftContextSubstr);
new_str ~= leftContextSubstr;
}
from = lastIndex;

if (noCommentOrNotInComment)
{
if (matchFrontHit == "\"")
{
if (!in_string || hasNoSlashOrEvenNumberOfSlashes(leftContext))
if (!in_string || hasNoSlashOrEvenNumberOfSlashes(leftContextSubstr))
{
// start of string with ", or unescaped " character found to end string
in_string = !in_string;
Expand All @@ -64,7 +69,7 @@ string minifyString(string jsonString, bool hasComments = false) @safe
}
else if (matchFrontHit.matchFirst(spaceOrBreakRegex).empty())
{
new_str.put(matchFrontHit);
new_str ~= matchFrontHit;
}
}
// comments
Expand Down Expand Up @@ -93,14 +98,15 @@ string minifyString(string jsonString, bool hasComments = false) @safe

match.popFront();
}
new_str.put(rightContext);
new_str ~= rightContext;
return new_str.array().join("");
}

bool hasNoSlashOrEvenNumberOfSlashes(string leftContext) @safe
{
auto leftContextMatch = leftContext.matchFirst(repeatingBackSlashRegex);
return leftContextMatch.empty() || (leftContextMatch.hit().length % 2 == 0);
// if not matched the hit length will be 0 (== leftContextMatch.empty())
return leftContextMatch.hit().length % 2 == 0;
}

/**
Expand Down
8 changes: 7 additions & 1 deletion test/helper.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ export async function minifyFixtures(jsonFiles) {
const resultInfo = await Promise.all(
minifiedFiles.map(async (minifiedFile) => {
const minifiedString = await readFile(minifiedFile, "utf8")
const minifiedObject = JSON.parse(minifiedString)
let minifiedObject
try {
minifiedObject = JSON.parse(minifiedString)
} catch (e) {
console.error(`The minified file is not valid for: ${minifiedFile}`)
throw e
}
return { minifiedString, minifiedObject }
})
)
Expand Down

0 comments on commit 6f33d71

Please sign in to comment.