Optimize some string handling (#170)
* Don't use fmt.Sprintf on simple strings * Use bytes.Buffer in encodeTomlString name old time/op new time/op delta Lexer-8 162µs ± 0% 161µs ± 0% -0.12% TreeToTomlString-8 19.7µs ± 0% 7.5µs ± 0% -61.80% name old alloc/op new alloc/op delta TreeToTomlString-8 9.75kB ± 0% 4.96kB ± 0% -49.12% name old allocs/op new allocs/op delta TreeToTomlString-8 485 ± 0% 78 ± 0% -83.92%
This commit is contained in:
committed by
Thomas Pelletier
parent
5ccdfb18c7
commit
a60c71373e
+15
-14
@@ -13,33 +13,34 @@ import (
|
|||||||
|
|
||||||
// encodes a string to a TOML-compliant string value
|
// encodes a string to a TOML-compliant string value
|
||||||
func encodeTomlString(value string) string {
|
func encodeTomlString(value string) string {
|
||||||
result := ""
|
var b bytes.Buffer
|
||||||
|
|
||||||
for _, rr := range value {
|
for _, rr := range value {
|
||||||
switch rr {
|
switch rr {
|
||||||
case '\b':
|
case '\b':
|
||||||
result += "\\b"
|
b.WriteString(`\b`)
|
||||||
case '\t':
|
case '\t':
|
||||||
result += "\\t"
|
b.WriteString(`\t`)
|
||||||
case '\n':
|
case '\n':
|
||||||
result += "\\n"
|
b.WriteString(`\n`)
|
||||||
case '\f':
|
case '\f':
|
||||||
result += "\\f"
|
b.WriteString(`\f`)
|
||||||
case '\r':
|
case '\r':
|
||||||
result += "\\r"
|
b.WriteString(`\r`)
|
||||||
case '"':
|
case '"':
|
||||||
result += "\\\""
|
b.WriteString(`\"`)
|
||||||
case '\\':
|
case '\\':
|
||||||
result += "\\\\"
|
b.WriteString(`\\`)
|
||||||
default:
|
default:
|
||||||
intRr := uint16(rr)
|
intRr := uint16(rr)
|
||||||
if intRr < 0x001F {
|
if intRr < 0x001F {
|
||||||
result += fmt.Sprintf("\\u%0.4X", intRr)
|
b.WriteString(fmt.Sprintf("\\u%0.4X", intRr))
|
||||||
} else {
|
} else {
|
||||||
result += string(rr)
|
b.WriteRune(rr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func tomlValueStringRepresentation(v interface{}) (string, error) {
|
func tomlValueStringRepresentation(v interface{}) (string, error) {
|
||||||
@@ -111,7 +112,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
|||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
|
|
||||||
kvRepr := fmt.Sprintf("%s%s = %s\n", indent, k, repr)
|
kvRepr := indent + k + " = " + repr + "\n"
|
||||||
writtenBytesCount, err := w.Write([]byte(kvRepr))
|
writtenBytesCount, err := w.Write([]byte(kvRepr))
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -130,7 +131,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
|||||||
switch node := v.(type) {
|
switch node := v.(type) {
|
||||||
// node has to be of those two types given how keys are sorted above
|
// node has to be of those two types given how keys are sorted above
|
||||||
case *Tree:
|
case *Tree:
|
||||||
tableName := fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
|
tableName := "\n" + indent + "[" + combinedKey + "]\n"
|
||||||
writtenBytesCount, err := w.Write([]byte(tableName))
|
writtenBytesCount, err := w.Write([]byte(tableName))
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -142,7 +143,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
|||||||
}
|
}
|
||||||
case []*Tree:
|
case []*Tree:
|
||||||
for _, subTree := range node {
|
for _, subTree := range node {
|
||||||
tableArrayName := fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey)
|
tableArrayName := "\n" + indent + "[[" + combinedKey + "]]\n"
|
||||||
writtenBytesCount, err := w.Write([]byte(tableArrayName))
|
writtenBytesCount, err := w.Write([]byte(tableArrayName))
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -293,3 +293,51 @@ func TestTreeWriteToMapWithArrayOfInlineTables(t *testing.T) {
|
|||||||
treeMap := tree.ToMap()
|
treeMap := tree.ToMap()
|
||||||
testMaps(t, treeMap, expected)
|
testMaps(t, treeMap, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkTreeToTomlString(b *testing.B) {
|
||||||
|
toml, err := Load(sampleHard)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal("Unexpected error:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := toml.ToTomlString()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sampleHard = `# Test file for TOML
|
||||||
|
# Only this one tries to emulate a TOML file written by a user of the kind of parser writers probably hate
|
||||||
|
# This part you'll really hate
|
||||||
|
|
||||||
|
[the]
|
||||||
|
test_string = "You'll hate me after this - #" # " Annoying, isn't it?
|
||||||
|
|
||||||
|
[the.hard]
|
||||||
|
test_array = [ "] ", " # "] # ] There you go, parse this!
|
||||||
|
test_array2 = [ "Test #11 ]proved that", "Experiment #9 was a success" ]
|
||||||
|
# You didn't think it'd as easy as chucking out the last #, did you?
|
||||||
|
another_test_string = " Same thing, but with a string #"
|
||||||
|
harder_test_string = " And when \"'s are in the string, along with # \"" # "and comments are there too"
|
||||||
|
# Things will get harder
|
||||||
|
|
||||||
|
[the.hard."bit#"]
|
||||||
|
"what?" = "You don't think some user won't do that?"
|
||||||
|
multi_line_array = [
|
||||||
|
"]",
|
||||||
|
# ] Oh yes I did
|
||||||
|
]
|
||||||
|
|
||||||
|
# Each of the following keygroups/key value pairs should produce an error. Uncomment to them to test
|
||||||
|
|
||||||
|
#[error] if you didn't catch this, your parser is broken
|
||||||
|
#string = "Anything other than tabs, spaces and newline after a keygroup or key value pair has ended should produce an error unless it is a comment" like this
|
||||||
|
#array = [
|
||||||
|
# "This might most likely happen in multiline arrays",
|
||||||
|
# Like here,
|
||||||
|
# "or here,
|
||||||
|
# and here"
|
||||||
|
# ] End of array comment, forgot the #
|
||||||
|
#number = 3.14 pi <--again forgot the # `
|
||||||
|
|||||||
Reference in New Issue
Block a user