Skip to content

Commit 1454fb5

Browse files
committed
Closure dispatch table replaced with a switch state statement
1 parent 39f0051 commit 1454fb5

3 files changed

Lines changed: 30 additions & 68 deletions

File tree

jsonc.go

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import (
44
"encoding/json"
55
)
66

7-
// Unmarshal parses the JSON-encoded data with comment support and stores the result in the value pointed to by v.
87
func Unmarshal(data []byte, v interface{}) error {
9-
processedData := decomment(data)
8+
processedData := stripComments(data)
109
return json.Unmarshal(processedData, v)
1110
}
1211

13-
func decomment(data []byte) []byte {
12+
func stripComments(data []byte) []byte {
1413
const (
1514
OUTSIDE = iota
1615
SINGLE_LINE
@@ -23,65 +22,48 @@ func decomment(data []byte) []byte {
2322
result := make([]byte, len(data))
2423
copy(result, data)
2524

26-
stateHandlers := []func(int, []byte, []byte) int{
27-
// OUTSIDE
28-
func(i int, data, result []byte) int {
25+
for i := 0; i < len(result); i++ {
26+
switch state {
27+
case OUTSIDE:
2928
if data[i] == '/' && i+1 < len(data) {
3029
if data[i+1] == '/' {
3130
state = SINGLE_LINE
3231
result[i] = ' '
3332
result[i+1] = ' '
34-
return i + 1 // skip the next character
33+
i++
3534
} else if data[i+1] == '*' {
3635
state = MULTI_LINE
3736
result[i] = ' '
3837
result[i+1] = ' '
39-
return i + 1 // skip the next character
38+
i++
4039
}
4140
} else if data[i] == '"' {
4241
state = IN_STRING
4342
}
44-
return i
45-
},
46-
// SINGLE_LINE
47-
func(i int, data, result []byte) int {
43+
case SINGLE_LINE:
4844
if data[i] == '\n' {
4945
state = OUTSIDE
5046
} else {
5147
result[i] = ' '
5248
}
53-
return i
54-
},
55-
// MULTI_LINE
56-
func(i int, data, result []byte) int {
49+
case MULTI_LINE:
5750
if data[i] == '*' && i+1 < len(result) && data[i+1] == '/' {
5851
state = MULTI_LINE_ENDING
5952
result[i] = ' '
6053
result[i+1] = ' '
61-
return i + 1 // skip the next character
54+
i++
6255
} else if result[i] != '\n' {
6356
result[i] = ' '
6457
}
65-
return i
66-
},
67-
// MULTI_LINE_ENDING
68-
func(i int, data, result []byte) int {
58+
case MULTI_LINE_ENDING:
6959
state = OUTSIDE
70-
return i
71-
},
72-
// IN_STRING
73-
func(i int, data, result []byte) int {
60+
case IN_STRING:
7461
if data[i] == '\\' && i+1 < len(data) {
75-
return i + 1 // skip the escaped character
62+
i++
7663
} else if data[i] == '"' {
7764
state = OUTSIDE
7865
}
79-
return i
80-
},
81-
}
82-
83-
for i := 0; i < len(result); i++ {
84-
i = stateHandlers[state](i, data, result)
66+
}
8567
}
8668

8769
return result

jsonc_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestUnmarshalWithComments(t *testing.T) {
7373
}
7474
}
7575

76-
func TestDecommenter(t *testing.T) {
76+
func TestStripComments(t *testing.T) {
7777
tests := []struct {
7878
name string
7979
input string
@@ -222,7 +222,7 @@ World"}
222222

223223
for _, tt := range tests {
224224
t.Run(tt.name, func(t *testing.T) {
225-
got := decomment([]byte(tt.input))
225+
got := stripComments([]byte(tt.input))
226226
if string(got) != tt.expected {
227227
t.Errorf("\ntest: \"%s\"\ngot \"%s\"\nwant \"%s\"", tt.input, string(got), tt.expected)
228228
} else {

v2/jsonc.go

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@ package jsonc
22

33
import "encoding/json/v2"
44

5-
// Unmarshal parses the JSON-encoded data with comment support and stores the result
6-
// in the value pointed to by v. Options may be passed to configure the behavior of
7-
// encoding/json/v2's Unmarshal.
85
func Unmarshal(data []byte, v any, opts ...json.Options) error {
9-
processedData := decomment(data)
6+
processedData := stripComments(data)
107
return json.Unmarshal(processedData, v, opts...)
118
}
129

13-
func decomment(data []byte) []byte {
10+
func stripComments(data []byte) []byte {
1411
const (
1512
OUTSIDE = iota
1613
SINGLE_LINE
@@ -23,65 +20,48 @@ func decomment(data []byte) []byte {
2320
result := make([]byte, len(data))
2421
copy(result, data)
2522

26-
stateHandlers := []func(int, []byte, []byte) int{
27-
// OUTSIDE
28-
func(i int, data, result []byte) int {
23+
for i := 0; i < len(result); i++ {
24+
switch state {
25+
case OUTSIDE:
2926
if data[i] == '/' && i+1 < len(data) {
3027
if data[i+1] == '/' {
3128
state = SINGLE_LINE
3229
result[i] = ' '
3330
result[i+1] = ' '
34-
return i + 1 // skip the next character
31+
i++
3532
} else if data[i+1] == '*' {
3633
state = MULTI_LINE
3734
result[i] = ' '
3835
result[i+1] = ' '
39-
return i + 1 // skip the next character
36+
i++
4037
}
4138
} else if data[i] == '"' {
4239
state = IN_STRING
4340
}
44-
return i
45-
},
46-
// SINGLE_LINE
47-
func(i int, data, result []byte) int {
41+
case SINGLE_LINE:
4842
if data[i] == '\n' {
4943
state = OUTSIDE
5044
} else {
5145
result[i] = ' '
5246
}
53-
return i
54-
},
55-
// MULTI_LINE
56-
func(i int, data, result []byte) int {
47+
case MULTI_LINE:
5748
if data[i] == '*' && i+1 < len(result) && data[i+1] == '/' {
5849
state = MULTI_LINE_ENDING
5950
result[i] = ' '
6051
result[i+1] = ' '
61-
return i + 1 // skip the next character
52+
i++
6253
} else if result[i] != '\n' {
6354
result[i] = ' '
6455
}
65-
return i
66-
},
67-
// MULTI_LINE_ENDING
68-
func(i int, data, result []byte) int {
56+
case MULTI_LINE_ENDING:
6957
state = OUTSIDE
70-
return i
71-
},
72-
// IN_STRING
73-
func(i int, data, result []byte) int {
58+
case IN_STRING:
7459
if data[i] == '\\' && i+1 < len(data) {
75-
return i + 1 // skip the escaped character
60+
i++
7661
} else if data[i] == '"' {
7762
state = OUTSIDE
7863
}
79-
return i
80-
},
81-
}
82-
83-
for i := 0; i < len(result); i++ {
84-
i = stateHandlers[state](i, data, result)
64+
}
8565
}
8666

8767
return result

0 commit comments

Comments
 (0)