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
|
||||
func encodeTomlString(value string) string {
|
||||
result := ""
|
||||
var b bytes.Buffer
|
||||
|
||||
for _, rr := range value {
|
||||
switch rr {
|
||||
case '\b':
|
||||
result += "\\b"
|
||||
b.WriteString(`\b`)
|
||||
case '\t':
|
||||
result += "\\t"
|
||||
b.WriteString(`\t`)
|
||||
case '\n':
|
||||
result += "\\n"
|
||||
b.WriteString(`\n`)
|
||||
case '\f':
|
||||
result += "\\f"
|
||||
b.WriteString(`\f`)
|
||||
case '\r':
|
||||
result += "\\r"
|
||||
b.WriteString(`\r`)
|
||||
case '"':
|
||||
result += "\\\""
|
||||
b.WriteString(`\"`)
|
||||
case '\\':
|
||||
result += "\\\\"
|
||||
b.WriteString(`\\`)
|
||||
default:
|
||||
intRr := uint16(rr)
|
||||
if intRr < 0x001F {
|
||||
result += fmt.Sprintf("\\u%0.4X", intRr)
|
||||
b.WriteString(fmt.Sprintf("\\u%0.4X", intRr))
|
||||
} else {
|
||||
result += string(rr)
|
||||
b.WriteRune(rr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
return b.String()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
kvRepr := fmt.Sprintf("%s%s = %s\n", indent, k, repr)
|
||||
kvRepr := indent + k + " = " + repr + "\n"
|
||||
writtenBytesCount, err := w.Write([]byte(kvRepr))
|
||||
bytesCount += int64(writtenBytesCount)
|
||||
if err != nil {
|
||||
@@ -130,7 +131,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
||||
switch node := v.(type) {
|
||||
// node has to be of those two types given how keys are sorted above
|
||||
case *Tree:
|
||||
tableName := fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
|
||||
tableName := "\n" + indent + "[" + combinedKey + "]\n"
|
||||
writtenBytesCount, err := w.Write([]byte(tableName))
|
||||
bytesCount += int64(writtenBytesCount)
|
||||
if err != nil {
|
||||
@@ -142,7 +143,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
||||
}
|
||||
case []*Tree:
|
||||
for _, subTree := range node {
|
||||
tableArrayName := fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey)
|
||||
tableArrayName := "\n" + indent + "[[" + combinedKey + "]]\n"
|
||||
writtenBytesCount, err := w.Write([]byte(tableArrayName))
|
||||
bytesCount += int64(writtenBytesCount)
|
||||
if err != nil {
|
||||
|
||||
@@ -293,3 +293,51 @@ func TestTreeWriteToMapWithArrayOfInlineTables(t *testing.T) {
|
||||
treeMap := tree.ToMap()
|
||||
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