WriteTo string concat allocation reduction (#177)
* reduce string concat allocs in Tree.writeTo * fix failingWriter and usages
This commit is contained in:
committed by
Thomas Pelletier
parent
4a000a21a4
commit
ef23ce9e92
+15
-6
@@ -118,8 +118,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
|||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
}
|
}
|
||||||
|
|
||||||
kvRepr := indent + k + " = " + repr + "\n"
|
writtenBytesCount, err := writeStrings(w, indent, k, " = ", repr, "\n")
|
||||||
writtenBytesCount, err := w.Write([]byte(kvRepr))
|
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
@@ -137,8 +136,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 := "\n" + indent + "[" + combinedKey + "]\n"
|
writtenBytesCount, err := writeStrings(w, "\n", indent, "[", combinedKey, "]\n")
|
||||||
writtenBytesCount, err := w.Write([]byte(tableName))
|
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
@@ -149,8 +147,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 := "\n" + indent + "[[" + combinedKey + "]]\n"
|
writtenBytesCount, err := writeStrings(w, "\n", indent, "[[", combinedKey, "]]\n")
|
||||||
writtenBytesCount, err := w.Write([]byte(tableArrayName))
|
|
||||||
bytesCount += int64(writtenBytesCount)
|
bytesCount += int64(writtenBytesCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bytesCount, err
|
return bytesCount, err
|
||||||
@@ -167,6 +164,18 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
|
|||||||
return bytesCount, nil
|
return bytesCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeStrings(w io.Writer, s ...string) (int, error) {
|
||||||
|
var n int
|
||||||
|
for i := range s {
|
||||||
|
b, err := io.WriteString(w, s[i])
|
||||||
|
n += b
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
// WriteTo encode the Tree as Toml and writes it to the writer w.
|
// WriteTo encode the Tree as Toml and writes it to the writer w.
|
||||||
// Returns the number of bytes written in case of success, or an error if anything happened.
|
// Returns the number of bytes written in case of success, or an error if anything happened.
|
||||||
func (t *Tree) WriteTo(w io.Writer) (int64, error) {
|
func (t *Tree) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
|||||||
+11
-11
@@ -16,26 +16,26 @@ type failingWriter struct {
|
|||||||
buffer bytes.Buffer
|
buffer bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f failingWriter) Write(p []byte) (n int, err error) {
|
func (f *failingWriter) Write(p []byte) (n int, err error) {
|
||||||
count := len(p)
|
count := len(p)
|
||||||
toWrite := f.failAt - count + f.written
|
toWrite := f.failAt - (count + f.written)
|
||||||
if toWrite < 0 {
|
if toWrite < 0 {
|
||||||
toWrite = 0
|
toWrite = 0
|
||||||
}
|
}
|
||||||
if toWrite > count {
|
if toWrite > count {
|
||||||
f.written += count
|
f.written += count
|
||||||
f.buffer.WriteString(string(p))
|
f.buffer.Write(p)
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f.buffer.WriteString(string(p[:toWrite]))
|
f.buffer.Write(p[:toWrite])
|
||||||
f.written = f.failAt
|
f.written = f.failAt
|
||||||
return f.written, fmt.Errorf("failingWriter failed after writting %d bytes", f.written)
|
return toWrite, fmt.Errorf("failingWriter failed after writting %d bytes", f.written)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertErrorString(t *testing.T, expected string, err error) {
|
func assertErrorString(t *testing.T, expected string, err error) {
|
||||||
expectedErr := errors.New(expected)
|
expectedErr := errors.New(expected)
|
||||||
if err.Error() != expectedErr.Error() {
|
if err == nil || err.Error() != expectedErr.Error() {
|
||||||
t.Errorf("expecting error %s, but got %s instead", expected, err)
|
t.Errorf("expecting error %s, but got %s instead", expected, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ func TestTreeWriteToInvalidTreeTomlValueArray(t *testing.T) {
|
|||||||
func TestTreeWriteToFailingWriterInSimpleValue(t *testing.T) {
|
func TestTreeWriteToFailingWriterInSimpleValue(t *testing.T) {
|
||||||
toml, _ := Load(`a = 2`)
|
toml, _ := Load(`a = 2`)
|
||||||
writer := failingWriter{failAt: 0, written: 0}
|
writer := failingWriter{failAt: 0, written: 0}
|
||||||
_, err := toml.WriteTo(writer)
|
_, err := toml.WriteTo(&writer)
|
||||||
assertErrorString(t, "failingWriter failed after writting 0 bytes", err)
|
assertErrorString(t, "failingWriter failed after writting 0 bytes", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,11 +184,11 @@ func TestTreeWriteToFailingWriterInTable(t *testing.T) {
|
|||||||
[b]
|
[b]
|
||||||
a = 2`)
|
a = 2`)
|
||||||
writer := failingWriter{failAt: 2, written: 0}
|
writer := failingWriter{failAt: 2, written: 0}
|
||||||
_, err := toml.WriteTo(writer)
|
_, err := toml.WriteTo(&writer)
|
||||||
assertErrorString(t, "failingWriter failed after writting 2 bytes", err)
|
assertErrorString(t, "failingWriter failed after writting 2 bytes", err)
|
||||||
|
|
||||||
writer = failingWriter{failAt: 13, written: 0}
|
writer = failingWriter{failAt: 13, written: 0}
|
||||||
_, err = toml.WriteTo(writer)
|
_, err = toml.WriteTo(&writer)
|
||||||
assertErrorString(t, "failingWriter failed after writting 13 bytes", err)
|
assertErrorString(t, "failingWriter failed after writting 13 bytes", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,11 +197,11 @@ func TestTreeWriteToFailingWriterInArray(t *testing.T) {
|
|||||||
[[b]]
|
[[b]]
|
||||||
a = 2`)
|
a = 2`)
|
||||||
writer := failingWriter{failAt: 2, written: 0}
|
writer := failingWriter{failAt: 2, written: 0}
|
||||||
_, err := toml.WriteTo(writer)
|
_, err := toml.WriteTo(&writer)
|
||||||
assertErrorString(t, "failingWriter failed after writting 2 bytes", err)
|
assertErrorString(t, "failingWriter failed after writting 2 bytes", err)
|
||||||
|
|
||||||
writer = failingWriter{failAt: 15, written: 0}
|
writer = failingWriter{failAt: 15, written: 0}
|
||||||
_, err = toml.WriteTo(writer)
|
_, err = toml.WriteTo(&writer)
|
||||||
assertErrorString(t, "failingWriter failed after writting 15 bytes", err)
|
assertErrorString(t, "failingWriter failed after writting 15 bytes", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user