Skip to content

Commit d46de1d

Browse files
committed
Reuse buffer for default encoder
1 parent e5792f9 commit d46de1d

File tree

5 files changed

+48
-34
lines changed

5 files changed

+48
-34
lines changed

encode.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package tblfmt
22

33
import (
44
"bufio"
5+
"bytes"
56
"encoding/csv"
67
"encoding/json"
78
"fmt"
@@ -39,6 +40,9 @@ type TableEncoder struct {
3940
// lineStyle is the table line style.
4041
lineStyle LineStyle
4142

43+
// rowStyles is the table of row style.
44+
rowStyles map[[4]rune]rowStyle
45+
4246
// formatter handles formatting values prior to output.
4347
formatter Formatter
4448

@@ -94,6 +98,7 @@ func NewTableEncoder(resultSet ResultSet, opts ...Option) (Encoder, error) {
9498
border: 1,
9599
tab: 8,
96100
lineStyle: ASCIILineStyle(),
101+
rowStyles: make(map[[4]rune]rowStyle),
97102
formatter: NewEscapeFormatter(WithHeaderAlign(AlignCenter)),
98103
summary: DefaultTableSummary(),
99104
empty: &Value{
@@ -117,6 +122,7 @@ func NewTableEncoder(resultSet ResultSet, opts ...Option) (Encoder, error) {
117122
enc.lineStyle.Wrap,
118123
enc.lineStyle.End,
119124
} {
125+
enc.rowStyles[l] = enc.rowStyle(l)
120126
for _, r := range l {
121127
if r != 0 && runewidth.RuneWidth(r) != 1 {
122128
return nil, ErrInvalidLineStyle
@@ -214,7 +220,7 @@ func (enc *TableEncoder) Encode(w io.Writer) error {
214220

215221
// draw end border
216222
if enc.border >= 2 {
217-
enc.divider(enc.rowStyle(enc.lineStyle.End))
223+
enc.divider(enc.rowStyles[enc.lineStyle.End])
218224
}
219225
}
220226

@@ -239,7 +245,7 @@ func (enc *TableEncoder) initBuffers() {
239245
}
240246

241247
func (enc *TableEncoder) encodeVals(vals [][]*Value) error {
242-
rs := enc.rowStyle(enc.lineStyle.Row)
248+
rs := enc.rowStyles[enc.lineStyle.Row]
243249
// print buffered vals
244250
for i := 0; i < len(vals); i++ {
245251
enc.row(vals[i], rs)
@@ -308,7 +314,7 @@ func (enc *TableEncoder) nextResults() ([][]*Value, error) {
308314
func (enc *TableEncoder) calcWidth(vals [][]*Value) {
309315
// calc offsets and widths for this batch of rows
310316
var offset int
311-
rs := enc.rowStyle(enc.lineStyle.Row)
317+
rs := enc.rowStyles[enc.lineStyle.Row]
312318
offset += runewidth.StringWidth(string(rs.left))
313319
for i, h := range enc.headers {
314320
if i != 0 {
@@ -339,7 +345,7 @@ func (enc *TableEncoder) calcWidth(vals [][]*Value) {
339345
}
340346

341347
func (enc *TableEncoder) header() {
342-
rs := enc.rowStyle(enc.lineStyle.Row)
348+
rs := enc.rowStyles[enc.lineStyle.Row]
343349

344350
if enc.title != nil && enc.title.Width != 0 {
345351
maxWidth := ((enc.tableWidth() - enc.title.Width) / 2) + enc.title.Width
@@ -348,20 +354,20 @@ func (enc *TableEncoder) header() {
348354
}
349355
// draw top border
350356
if enc.border >= 2 && !enc.inline {
351-
enc.divider(enc.rowStyle(enc.lineStyle.Top))
357+
enc.divider(enc.rowStyles[enc.lineStyle.Top])
352358
}
353359

354360
// draw the header row with top border style
355361
if enc.inline {
356-
rs = enc.rowStyle(enc.lineStyle.Top)
362+
rs = enc.rowStyles[enc.lineStyle.Top]
357363
}
358364

359365
// write header
360366
enc.row(enc.headers, rs)
361367

362368
if !enc.inline {
363369
// draw mid divider
364-
enc.divider(enc.rowStyle(enc.lineStyle.Mid))
370+
enc.divider(enc.rowStyles[enc.lineStyle.Mid])
365371
}
366372
}
367373

@@ -400,14 +406,15 @@ func (enc TableEncoder) rowStyle(r [4]rune) rowStyle {
400406
middle = string(r[2]) + spacer
401407
}
402408

403-
return rowStyle{
409+
rs := rowStyle{
404410
left: []byte(left),
405411
wrapper: []byte(string(enc.lineStyle.Wrap[1])),
406412
middle: []byte(middle),
407413
right: []byte(right + string(enc.newline)),
408-
filler: []byte(filler),
414+
filler: bytes.Repeat([]byte(filler), 8)[:len(filler)],
409415
hasWrapping: runewidth.RuneWidth(enc.lineStyle.Row[1]) > 0,
410416
}
417+
return rs
411418
}
412419

413420
// scanAndFormat scans and formats values from the result set.
@@ -449,7 +456,7 @@ func (enc *TableEncoder) divider(rs rowStyle) {
449456

450457
// tableWidth calculates total table width.
451458
func (enc *TableEncoder) tableWidth() int {
452-
rs := enc.rowStyle(enc.lineStyle.Mid)
459+
rs := enc.rowStyles[enc.lineStyle.Mid]
453460
width := runewidth.StringWidth(string(rs.left)) + runewidth.StringWidth(string(rs.right))
454461

455462
for i, w := range enc.maxWidths {
@@ -682,7 +689,7 @@ func (enc *ExpandedEncoder) Encode(w io.Writer) error {
682689
}
683690

684691
func (enc *ExpandedEncoder) encodeVals(vals [][]*Value) error {
685-
rs := enc.rowStyle(enc.lineStyle.Row)
692+
rs := enc.rowStyles[enc.lineStyle.Row]
686693
// print buffered vals
687694
for i := 0; i < len(vals); i++ {
688695
enc.record(i, vals[i], rs)
@@ -701,7 +708,7 @@ func (enc *ExpandedEncoder) encodeVals(vals [][]*Value) error {
701708

702709
// draw end border
703710
if enc.border >= 2 && enc.scanCount != 0 {
704-
enc.divider(enc.rowStyle(enc.lineStyle.End))
711+
enc.divider(enc.rowStyles[enc.lineStyle.End])
705712
}
706713
return nil
707714
}
@@ -732,7 +739,7 @@ func (enc *ExpandedEncoder) EncodeAll(w io.Writer) error {
732739
}
733740

734741
func (enc *ExpandedEncoder) calcWidth(vals [][]*Value) {
735-
rs := enc.rowStyle(enc.lineStyle.Row)
742+
rs := enc.rowStyles[enc.lineStyle.Row]
736743

737744
offset := runewidth.StringWidth(string(rs.left))
738745

@@ -770,9 +777,9 @@ func (enc *ExpandedEncoder) record(i int, vals []*Value, rs rowStyle) {
770777
headerRS := rs
771778
header := enc.recordHeader(i)
772779
if enc.border != 0 {
773-
headerRS = enc.rowStyle(enc.lineStyle.Top)
780+
headerRS = enc.rowStyles[enc.lineStyle.Top]
774781
if i != 0 {
775-
headerRS = enc.rowStyle(enc.lineStyle.Mid)
782+
headerRS = enc.rowStyles[enc.lineStyle.Mid]
776783
}
777784
}
778785

fmt.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ type EscapeFormatter struct {
4747
// If nil, the standard encoding/json.Encoder will be used instead.
4848
marshaler func(interface{}) ([]byte, error)
4949

50+
defaultMarshaler *json.Encoder
51+
defaultMarshalerBuffer *bytes.Buffer
52+
5053
// prefix is indent prefix used by the JSON encoder when Marshaler is nil.
5154
prefix string
5255

@@ -79,11 +82,15 @@ type EscapeFormatter struct {
7982
// values.
8083
func NewEscapeFormatter(opts ...EscapeFormatterOption) *EscapeFormatter {
8184
f := &EscapeFormatter{
82-
mask: "%d",
83-
timeFormat: time.RFC3339Nano,
84-
indent: " ",
85-
valuesPool: newValuesPool(),
85+
mask: "%d",
86+
timeFormat: time.RFC3339Nano,
87+
indent: " ",
88+
valuesPool: newValuesPool(),
89+
defaultMarshalerBuffer: new(bytes.Buffer),
8690
}
91+
f.defaultMarshaler = json.NewEncoder(f.defaultMarshalerBuffer)
92+
f.defaultMarshaler.SetIndent(f.prefix, f.indent)
93+
f.defaultMarshaler.SetEscapeHTML(f.escapeHTML)
8794
f.Configure(opts...)
8895
return f
8996
}
@@ -288,17 +295,15 @@ func (f *EscapeFormatter) Format(vals []interface{}) ([]*Value, error) {
288295
res[i] = f.valuesPool.newRaw(buf)
289296
} else {
290297
// json encode
291-
buf := new(bytes.Buffer)
292-
enc := json.NewEncoder(buf)
293-
enc.SetIndent(f.prefix, f.indent)
294-
enc.SetEscapeHTML(f.escapeHTML)
295-
if err := enc.Encode(v); err != nil {
298+
// TODO reuse buffer and reset it before every use
299+
f.defaultMarshalerBuffer.Reset()
300+
if err := f.defaultMarshaler.Encode(v); err != nil {
296301
return nil, err
297302
}
298303
if f.escapeJSON {
299-
res[i] = f.valuesPool.newRaw(bytes.TrimSpace(buf.Bytes()))
304+
res[i] = f.valuesPool.newRaw(bytes.TrimSpace(f.defaultMarshalerBuffer.Bytes()))
300305
} else {
301-
res[i] = f.valuesPool.formatBytes(bytes.TrimSpace(buf.Bytes()), f.invalid, f.invalidWidth, false)
306+
res[i] = f.valuesPool.formatBytes(bytes.TrimSpace(f.defaultMarshalerBuffer.Bytes()), f.invalid, f.invalidWidth, false)
302307
res[i].Raw = true
303308
}
304309
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module github.com/xo/tblfmt
22

33
require (
4-
github.com/mattn/go-runewidth v0.0.9
4+
github.com/mattn/go-runewidth v0.0.10
55
github.com/nathan-fiscaletti/consolesize-go v0.0.0-20210105204122-a87d9f614b9d
66
)
77

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
2-
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
1+
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
2+
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
33
github.com/nathan-fiscaletti/consolesize-go v0.0.0-20210105204122-a87d9f614b9d h1:PQW4Aqovdqc9efHl9EVA+bhKmuZ4ME1HvSYYDvaDiK0=
44
github.com/nathan-fiscaletti/consolesize-go v0.0.0-20210105204122-a87d9f614b9d/go.mod h1:cxIIfNMTwff8f/ZvRouvWYF6wOoO7nj99neWSx2q/Es=
5+
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
6+
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=

util.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ func repeat(w io.Writer, b []byte, c int) []byte {
114114
w.Write(b[:c])
115115
return b
116116
}
117-
nb := b[:cap(b)]
118-
for len(nb) < c {
119-
nb = append(nb, nb...)
117+
b = b[:cap(b)]
118+
for len(b) < c {
119+
b = append(b, b...)
120120
}
121-
w.Write(nb[:c])
122-
return nb[:len(b)]
121+
w.Write(b[:c])
122+
return b[:1]
123123
}

0 commit comments

Comments
 (0)