github.com/jmigpin/editor@v1.6.0/util/iout/autobufwriter.go (about)

     1  package iout
     2  
     3  import (
     4  	"bufio"
     5  	"io"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  //godebug:annotatefile
    11  
    12  // small amounts of output need to be flushed (not filling the buffer)
    13  const abwUpdatesPerSecond = 10
    14  
    15  // Flushes after x time if the buffer doesn't get filled. Safe to use concurrently.
    16  type AutoBufWriter struct {
    17  	w  io.Writer
    18  	mu struct {
    19  		sync.Mutex
    20  		buf   *bufio.Writer
    21  		timer *time.Timer
    22  	}
    23  }
    24  
    25  func NewAutoBufWriter(w io.Writer, size int) *AutoBufWriter {
    26  	abw := &AutoBufWriter{w: w}
    27  	abw.mu.buf = bufio.NewWriterSize(abw.w, size)
    28  	return abw
    29  }
    30  
    31  // Implements io.Closer
    32  func (w *AutoBufWriter) Close() error {
    33  	w.mu.Lock()
    34  	defer w.mu.Unlock()
    35  	w.clearTimer()
    36  	w.mu.buf.Flush()
    37  	return nil
    38  }
    39  
    40  // Implements io.Writer
    41  func (w *AutoBufWriter) Write(p []byte) (int, error) {
    42  	w.mu.Lock()
    43  	defer w.mu.Unlock()
    44  	n, err := w.mu.buf.Write(p)
    45  	w.autoFlush()
    46  	return n, err
    47  }
    48  
    49  //----------
    50  
    51  func (w *AutoBufWriter) autoFlush() {
    52  	if w.mu.buf.Buffered() == 0 {
    53  		return
    54  	}
    55  	if w.mu.timer == nil {
    56  		t := time.Second / abwUpdatesPerSecond
    57  		w.mu.timer = time.AfterFunc(t, w.flushTime)
    58  	}
    59  }
    60  func (w *AutoBufWriter) flushTime() {
    61  	w.mu.Lock()
    62  	defer w.mu.Unlock()
    63  	w.mu.buf.Flush()
    64  	w.clearTimer()
    65  }
    66  
    67  func (w *AutoBufWriter) clearTimer() {
    68  	if w.mu.timer != nil {
    69  		w.mu.timer.Stop()
    70  		w.mu.timer = nil
    71  	}
    72  }