File: reader.go

package info (click to toggle)
panicparse 2.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 744 kB
  • sloc: sh: 13; makefile: 5
file content (103 lines) | stat: -rw-r--r-- 2,138 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Copyright 2020 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package stack

import (
	"bytes"
	"errors"
	"io"
)

var (
	errBufferFull = errors.New("buffer full")
)

type reader struct {
	buf  [16 * 1024]byte
	rd   io.Reader
	r, w int
	err  error
}

// fill reads a new chunk into the buffer.
func (r *reader) fill() {
	// Slide existing data to beginning.
	if r.r > 0 {
		copy(r.buf[:], r.buf[r.r:r.w])
		r.w -= r.r
		r.r = 0
	}
	if r.w >= len(r.buf) {
		panic("tried to fill full buffer")
	}
	// Read new data: try a limited number of times.
	for i := 100; i > 0; i-- {
		n, err := r.rd.Read(r.buf[r.w:])
		if n < 0 {
			panic("reader returned negative count from Read")
		}
		r.w += n
		if err != nil {
			r.err = err
			return
		}
		if n > 0 {
			return
		}
	}
	r.err = io.ErrNoProgress
}

func (r *reader) buffered() []byte {
	return r.buf[r.r:r.w]
}

func (r *reader) readSlice() ([]byte, error) {
	for s := 0; ; r.fill() {
		if i := bytes.IndexByte(r.buf[r.r+s:r.w], '\n'); i >= 0 {
			i += s
			line := r.buf[r.r : r.r+i+1]
			r.r += i + 1
			return line, nil
		}
		if r.err != nil {
			line := r.buf[r.r:r.w]
			r.r = r.w
			err := r.err
			r.err = nil
			return line, err
		}
		if r.w-r.r == len(r.buf) {
			r.r = r.w
			return r.buf[:], errBufferFull
		}
		s = r.w - r.r
	}
}

// readLine is our own implementation of ReadBytes().
//
// We try to use readSlice() as much as we can but we need to tolerate if an
// input line is longer than the buffer specified at Reader creation. Not using
// the more complicated slice of slices that Reader.ReadBytes() uses since it
// should not happen often here. Instead bootstrap the memory allocation by
// starting with 4x buffer size, which should get most cases with a single
// allocation.
func (r *reader) readLine() ([]byte, error) {
	var d []byte
	for {
		f, err := r.readSlice()
		if err != errBufferFull {
			if d == nil {
				return f, err
			}
			return append(d, f...), err
		}
		if d == nil {
			d = make([]byte, 0, len(f)*4)
		}
		d = append(d, f...)
	}
}