Skip to content

Commit b323844

Browse files
authored
Merge pull request #16 from aminya/perf
2 parents ed3925c + cc6171a commit b323844

File tree

3 files changed

+42
-32
lines changed

3 files changed

+42
-32
lines changed

Readme.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Minify JSON files **blazing fast**! Supports Comments. Written in D.
44

5-
55 times faster than jsonminify!
5+
60 times faster than jsonminify!
66

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

@@ -90,10 +90,10 @@ minifyFiles(["file1.json", "file2.json"], true);
9090

9191
```
9292
❯ node .\benchmark\native-benchmark.mjs
93-
1.066 seconds
93+
0.977 seconds
9494
9595
❯ node .\benchmark\js-benchmark.mjs
96-
58.686 seconds
96+
58.818 seconds
9797
```
9898

9999
### Contributing

src/native/lib.d

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
module minijson.lib;
22

33
import std : ctRegex, replaceAll, join, array, matchAll, matchFirst, RegexMatch;
4-
import automem : Vector;
54

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

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

11-
const repeatingBackSlashRegex = ctRegex!(`(\\)*$`);
12-
1310
/**
1411
Minify the given JSON string
1512
@@ -20,12 +17,12 @@ const repeatingBackSlashRegex = ctRegex!(`(\\)*$`);
2017
Return:
2118
the minified json string
2219
*/
23-
string minifyString(string jsonString, bool hasComment = false) @trusted
20+
string minifyString(in string jsonString, in bool hasComment = false) @trusted
2421
{
2522
auto in_string = false;
2623
auto in_multiline_comment = false;
2724
auto in_singleline_comment = false;
28-
Vector!string new_str;
25+
string result;
2926
size_t from = 0;
3027
auto rightContext = "";
3128

@@ -49,22 +46,24 @@ string minifyString(string jsonString, bool hasComment = false) @trusted
4946
if (noCommentOrNotInComment)
5047
{
5148
auto leftContextSubstr = match.pre()[prevFrom .. $];
52-
53-
if (!in_string)
49+
if (leftContextSubstr.length != 0)
5450
{
55-
leftContextSubstr = leftContextSubstr.replaceAll(spaceOrBreakRegex, "");
56-
}
57-
new_str ~= leftContextSubstr;
51+
if (!in_string)
52+
{
53+
leftContextSubstr = leftContextSubstr.replaceAll(spaceOrBreakRegex, "");
54+
}
55+
result ~= leftContextSubstr;
5856

59-
if (matchFrontHit == "\"")
60-
{
61-
if (!in_string || hasNoSlashOrEvenNumberOfSlashes(leftContextSubstr))
57+
if (matchFrontHit == "\"")
6258
{
63-
// start of string with ", or unescaped " character found to end string
64-
in_string = !in_string;
59+
if (!in_string || hasNoSlashOrEvenNumberOfSlashes(leftContextSubstr))
60+
{
61+
// start of string with ", or unescaped " character found to end string
62+
in_string = !in_string;
63+
}
64+
--from; // include " character in next catch
65+
rightContext = jsonString[from .. $];
6566
}
66-
--from; // include " character in next catch
67-
rightContext = jsonString[from .. $];
6867
}
6968
}
7069
// comments
@@ -82,7 +81,7 @@ string minifyString(string jsonString, bool hasComment = false) @trusted
8281
}
8382
else if (notSlashAndNoSpaceOrBreak(matchFrontHit))
8483
{
85-
new_str ~= matchFrontHit;
84+
result ~= matchFrontHit;
8685
}
8786
}
8887
else if (in_multiline_comment && !in_singleline_comment && matchFrontHit == "*/")
@@ -94,24 +93,35 @@ string minifyString(string jsonString, bool hasComment = false) @trusted
9493
in_singleline_comment = false;
9594
}
9695
}
97-
if (!hasComment && notSlashAndNoSpaceOrBreak(matchFrontHit))
96+
else if (!hasComment && notSlashAndNoSpaceOrBreak(matchFrontHit))
9897
{
99-
new_str ~= matchFrontHit;
98+
result ~= matchFrontHit;
10099
}
101100
match.popFront();
102101
}
103-
new_str ~= rightContext;
104-
return new_str.array().join("");
102+
result ~= rightContext;
103+
return result;
105104
}
106105

107-
private bool hasNoSlashOrEvenNumberOfSlashes(string leftContext) @safe
106+
private bool hasNoSlashOrEvenNumberOfSlashes(in string leftContextSubstr) @safe @nogc
108107
{
109-
auto leftContextMatch = leftContext.matchFirst(repeatingBackSlashRegex);
110-
// if not matched the hit length will be 0 (== leftContextMatch.empty())
111-
return leftContextMatch.hit().length % 2 == 0;
108+
size_t slashCount = 0;
109+
110+
// NOTE leftContextSubstr.length is not 0 (checked outside of the function)
111+
size_t index = leftContextSubstr.length - 1;
112+
113+
// loop over the string backwards and find `\`
114+
while (leftContextSubstr[index] == '\\')
115+
{
116+
slashCount += 1;
117+
118+
index -= 1;
119+
}
120+
// no slash or even number of slashes
121+
return slashCount % 2 == 0;
112122
}
113123

114-
private bool notSlashAndNoSpaceOrBreak(string matchFrontHit)
124+
private bool notSlashAndNoSpaceOrBreak(in string matchFrontHit) @safe
115125
{
116126
return matchFrontHit != "\"" && matchFrontHit.matchFirst(spaceOrBreakRegex).empty();
117127
}
@@ -123,7 +133,7 @@ private bool notSlashAndNoSpaceOrBreak(string matchFrontHit)
123133
files = the paths to the files.
124134
hasComment = a boolean to support comments in json. Default: `false`.
125135
*/
126-
void minifyFiles(string[] files, bool hasComment = false)
136+
void minifyFiles(in string[] files, in bool hasComment = false)
127137
{
128138
import std.parallelism : parallel;
129139
import std.file : readText, write;

src/native/libc.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ extern (C):
1414
Return:
1515
the minified json string
1616
*/
17-
auto minifyString(char* jsonCString, bool hasComment = false)
17+
auto minifyString(in char* jsonCString, in bool hasComment = false)
1818
{
1919
import std : fromStringz, toStringz;
2020

0 commit comments

Comments
 (0)