Skip to content

Commit 2e2114b

Browse files
committedSep 7, 2016
Adds no-sort flag; minor optimisations
1 parent dd4eb1f commit 2e2114b

File tree

7 files changed

+28442
-20
lines changed

7 files changed

+28442
-20
lines changed
 

‎README.mkd

+1
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ Usage:
183183
Options:
184184
-u, --ungron Reverse the operation (turn assignments back into JSON)
185185
-m, --monochrome Monochrome (don't colorize output)
186+
--no-sort Don't sort output (faster)
186187
--version Print version information
187188
188189
Exit Codes:

‎formatter.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ func (f monoFormatter) assignment(key string, value interface{}) string {
6969
case nil:
7070
valStr = "null"
7171
}
72-
return fmt.Sprintf("%s = %s;", key, valStr)
72+
// concatenation has proven to be faster than fmt.Sprintf here
73+
return key + " = " + valStr + ";"
7374
}
7475

7576
// colorFormatter formats statements in color

‎formatter_test.go

+25-3
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,45 @@ func TestPrefixHappy(t *testing.T) {
2727
}
2828
}
2929

30-
func BenchmarkMakePrefixUnquoted(b *testing.B) {
30+
func BenchmarkFormatterMakePrefixUnquoted(b *testing.B) {
3131
var f monoFormatter
3232
for i := 0; i < b.N; i++ {
3333
_, _ = f.prefix("json", "isunquoted")
3434
}
3535
}
3636

37-
func BenchmarkMakePrefixQuoted(b *testing.B) {
37+
func BenchmarkFormatterMakePrefixQuoted(b *testing.B) {
3838
var f monoFormatter
3939
for i := 0; i < b.N; i++ {
4040
_, _ = f.prefix("json", "this-is-quoted")
4141
}
4242
}
4343

44-
func BenchmarkMakePrefixInt(b *testing.B) {
44+
func BenchmarkFormatterMakePrefixInt(b *testing.B) {
4545
var f monoFormatter
4646
for i := 0; i < b.N; i++ {
4747
_, _ = f.prefix("json", 212)
4848
}
4949
}
50+
51+
func BenchmarkFormatterAssignmentString(b *testing.B) {
52+
var f monoFormatter
53+
for i := 0; i < b.N; i++ {
54+
_ = f.assignment("json.foo", "bar")
55+
}
56+
}
57+
58+
func BenchmarkFormatterAssignmentMap(b *testing.B) {
59+
var f monoFormatter
60+
val := make(map[string]interface{})
61+
for i := 0; i < b.N; i++ {
62+
_ = f.assignment("json.foo", val)
63+
}
64+
}
65+
66+
func BenchmarkFormatterValueString(b *testing.B) {
67+
var f monoFormatter
68+
for i := 0; i < b.N; i++ {
69+
_ = f.value("a string")
70+
}
71+
}

‎main.go

+31-12
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ const (
2626
exitJSONEncode
2727
)
2828

29+
// Option bitfields
30+
const (
31+
optMonochrome = iota + 1
32+
optNoSort
33+
)
34+
2935
// Output colors
3036
var (
3137
strColor = color.New(color.FgYellow)
@@ -49,6 +55,7 @@ func init() {
4955
h += "Options:\n"
5056
h += " -u, --ungron Reverse the operation (turn assignments back into JSON)\n"
5157
h += " -m, --monochrome Monochrome (don't colorize output)\n"
58+
h += " --no-sort Don't sort output (faster)\n"
5259
h += " --version Print version information\n\n"
5360

5461
h += "Exit Codes:\n"
@@ -75,14 +82,16 @@ func main() {
7582
var (
7683
ungronFlag bool
7784
monochromeFlag bool
85+
noSortFlag bool
7886
versionFlag bool
7987
)
8088

81-
flag.BoolVar(&ungronFlag, "ungron", false, "Turn statements into JSON instead")
82-
flag.BoolVar(&ungronFlag, "u", false, "Turn statements into JSON instead")
83-
flag.BoolVar(&monochromeFlag, "monochrome", false, "Monochrome (don't colorize output)")
84-
flag.BoolVar(&monochromeFlag, "m", false, "Monochrome (don't colorize output)")
85-
flag.BoolVar(&versionFlag, "version", false, "Print version information")
89+
flag.BoolVar(&ungronFlag, "ungron", false, "")
90+
flag.BoolVar(&ungronFlag, "u", false, "")
91+
flag.BoolVar(&monochromeFlag, "monochrome", false, "")
92+
flag.BoolVar(&monochromeFlag, "m", false, "")
93+
flag.BoolVar(&noSortFlag, "no-sort", false, "")
94+
flag.BoolVar(&versionFlag, "version", false, "")
8695

8796
flag.Parse()
8897

@@ -113,11 +122,19 @@ func main() {
113122
}
114123
}
115124

125+
var opts int
126+
if monochromeFlag {
127+
opts = opts | optMonochrome
128+
}
129+
if noSortFlag {
130+
opts = opts | optNoSort
131+
}
132+
116133
var a actionFn = gron
117134
if ungronFlag {
118135
a = ungron
119136
}
120-
exitCode, err := a(raw, os.Stdout, monochromeFlag)
137+
exitCode, err := a(raw, os.Stdout, opts)
121138

122139
if exitCode != exitOK {
123140
fatal(exitCode, err)
@@ -126,12 +143,12 @@ func main() {
126143
os.Exit(exitOK)
127144
}
128145

129-
type actionFn func(io.Reader, io.Writer, bool) (int, error)
146+
type actionFn func(io.Reader, io.Writer, int) (int, error)
130147

131-
func gron(r io.Reader, w io.Writer, monochrome bool) (int, error) {
148+
func gron(r io.Reader, w io.Writer, opts int) (int, error) {
132149

133150
formatter = colorFormatter{}
134-
if monochrome {
151+
if opts&optMonochrome > 0 {
135152
formatter = monoFormatter{}
136153
}
137154

@@ -142,7 +159,9 @@ func gron(r io.Reader, w io.Writer, monochrome bool) (int, error) {
142159

143160
// Go's maps do not have well-defined ordering, but we want a consistent
144161
// output for a given input, so we must sort the statements
145-
sort.Sort(ss)
162+
if opts&optNoSort == 0 {
163+
sort.Sort(ss)
164+
}
146165

147166
for _, s := range ss {
148167
fmt.Fprintln(w, s)
@@ -151,7 +170,7 @@ func gron(r io.Reader, w io.Writer, monochrome bool) (int, error) {
151170
return exitOK, nil
152171
}
153172

154-
func ungron(r io.Reader, w io.Writer, monochrome bool) (int, error) {
173+
func ungron(r io.Reader, w io.Writer, opts int) (int, error) {
155174
scanner := bufio.NewScanner(r)
156175

157176
// Make a list of statements from the input
@@ -186,7 +205,7 @@ func ungron(r io.Reader, w io.Writer, monochrome bool) (int, error) {
186205
}
187206

188207
// If the output isn't monochrome, add color to the JSON
189-
if !monochrome {
208+
if opts&optMonochrome == 0 {
190209
c, err := colorizeJSON(j)
191210

192211
// If we failed to colorize the JSON for whatever reason,

‎main_test.go

+22-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestGron(t *testing.T) {
3131
}
3232

3333
out := &bytes.Buffer{}
34-
code, err := gron(in, out, true)
34+
code, err := gron(in, out, optMonochrome)
3535

3636
if code != exitOK {
3737
t.Errorf("want exitOK; have %d", code)
@@ -78,7 +78,7 @@ func TestUngron(t *testing.T) {
7878
}
7979

8080
out := &bytes.Buffer{}
81-
code, err := ungron(in, out, true)
81+
code, err := ungron(in, out, optMonochrome)
8282

8383
if code != exitOK {
8484
t.Errorf("want exitOK; have %d", code)
@@ -101,3 +101,23 @@ func TestUngron(t *testing.T) {
101101

102102
}
103103
}
104+
105+
func BenchmarkBigJSON(b *testing.B) {
106+
in, err := os.Open("testdata/big.json")
107+
if err != nil {
108+
b.Fatalf("failed to open test data file: %s", err)
109+
}
110+
111+
for i := 0; i < b.N; i++ {
112+
out := &bytes.Buffer{}
113+
_, err = in.Seek(0, 0)
114+
if err != nil {
115+
b.Fatalf("failed to rewind input: %s", err)
116+
}
117+
118+
_, err := gron(in, out, optMonochrome|optNoSort)
119+
if err != nil {
120+
b.Fatalf("failed to gron: %s", err)
121+
}
122+
}
123+
}

‎statements.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,15 @@ func (ss statements) Less(a, b int) bool {
9696
// The statements may contain ANSI color codes. We don't
9797
// want to sort based on the colors so we need to strip
9898
// them out first
99-
aStr := stripColors(ss[a])
100-
bStr := stripColors(ss[b])
99+
var aStr, bStr string
100+
switch formatter.(type) {
101+
case colorFormatter:
102+
aStr = stripColors(ss[a])
103+
bStr = stripColors(ss[b])
104+
default:
105+
aStr = ss[a]
106+
bStr = ss[b]
107+
}
101108

102109
// Find where the two strings start to differ, keeping track
103110
// of where any numbers start so that we can compare them properly

‎testdata/big.json

+28,352
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.