return len(*line)
}
-func handlePanic(err *error, op string) {
+func (b *Writer) handlePanic(err *error, op string) {
if e := recover(); e != nil {
+ if op == "Flush" {
+ // If Flush ran into a panic, we still need to reset.
+ b.reset()
+ }
if nerr, ok := e.(osError); ok {
*err = nerr.err
return
return b.flush()
}
+// flush is the internal version of Flush, with a named return value which we
+// don't want to expose.
func (b *Writer) flush() (err error) {
- defer b.reset() // even in the presence of errors
- defer handlePanic(&err, "Flush")
+ defer b.handlePanic(&err, "Flush")
+ return b.flushNoDefers()
+}
+// flushNoDefers is like flush, but without a deferred handlePanic call. This
+// can be called from other methods which already have their own deferred
+// handlePanic calls, such as Write, and avoid the extra defer work.
+func (b *Writer) flushNoDefers() (err error) {
// add current cell if not empty
if b.cell.size > 0 {
if b.endChar != 0 {
// format contents of buffer
b.format(0, 0, len(b.lines))
+ b.reset()
return nil
}
// while writing to the underlying output stream.
//
func (b *Writer) Write(buf []byte) (n int, err error) {
- defer handlePanic(&err, "Write")
+ defer b.handlePanic(&err, "Write")
// split text into cells
n = 0
// the formatting of the following lines (the last cell per
// line is ignored by format()), thus we can flush the
// Writer contents.
- if err = b.Flush(); err != nil {
+ if err = b.flushNoDefers(); err != nil {
return
}
if ch == '\f' && b.flags&Debug != 0 {
})
}
}
+
+const codeSnippet = `
+some command
+
+foo # aligned
+barbaz # comments
+
+but
+mostly
+single
+cell
+lines
+`
+
+func BenchmarkCode(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings
+ // The code is small, so it's reasonable for the tabwriter user
+ // to write it all at once, or buffer the writes.
+ w.Write([]byte(codeSnippet))
+ w.Flush()
+ }
+}