github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/repeat/repeat.go (about)

     1  // Package repeat implements the repeat-reader. A repeat-reader outputs a given
     2  // constant byte sequence repeatedly.
     3  //
     4  // This package was originally written for testing and profiling parsers.
     5  // A typical use may look something like this:
     6  //
     7  //	input := "some line to be parsed\n"
     8  //	r := NewReader([]byte(input), 1000)
     9  //	parser := myparse.NewParser(r)
    10  //
    11  //	(start profiling)
    12  //	// Parse 1000 lines until non-nil error.
    13  //	for parser.ParseNext() == nil {}
    14  //	(stop profiling)
    15  package repeat
    16  
    17  import "io"
    18  
    19  // Reader outputs a given constant byte sequence repeatedly.
    20  type Reader struct {
    21  	data []byte
    22  	i    int
    23  	n    int
    24  }
    25  
    26  // NewReader returns a reader that outputs data n times. If n is negative, repeats
    27  // infinitely. Copies the contents of data.
    28  func NewReader(data []byte, n int) *Reader {
    29  	cp := make([]byte, len(data))
    30  	copy(cp, data)
    31  	return &Reader{data: cp, n: n}
    32  }
    33  
    34  // Read fills p with repetitions of the reader's data. Writes until p is full or
    35  // until the last repetition was written. Subsequent calls to Read resume from where
    36  // the last repetition stopped. When no more bytes are available, returns 0, EOF.
    37  // Otherwise the error is nil.
    38  func (r *Reader) Read(p []byte) (int, error) {
    39  	if len(p) == 0 {
    40  		return 0, nil
    41  	}
    42  	if r.i == 0 && r.n == 0 {
    43  		return 0, io.EOF
    44  	}
    45  	m := 0
    46  	for {
    47  		n := copy(p, r.data[r.i:])
    48  		r.i += n
    49  		if r.i == len(r.data) {
    50  			r.i = 0
    51  			if r.n > 0 {
    52  				r.n--
    53  			}
    54  		}
    55  		p = p[n:]
    56  		m += n
    57  		if len(p) == 0 || (r.i == 0 && r.n == 0) {
    58  			break
    59  		}
    60  	}
    61  	return m, nil
    62  }
    63  
    64  // Close is a no-op. Implements [io.ReadCloser].
    65  func (r *Reader) Close() error {
    66  	return nil
    67  }