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 }