Skip to content

Commit fa88623

Browse files
committed
Improve clarity of LineReaderAt implementation
Try to avoid confusion about whether variables refer to byte or line counts/positions. It still isn't perfect, but I'm not sure how to further clarify without being overly verbose.
1 parent 206a57e commit fa88623

File tree

1 file changed

+36
-31
lines changed

1 file changed

+36
-31
lines changed

gitdiff/io.go

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,47 +31,41 @@ type lineReaderAt struct {
3131
}
3232

3333
func (r *lineReaderAt) ReadLinesAt(lines [][]byte, offset int64) (n int, err error) {
34-
// TODO(bkeyes): revisit variable names
35-
// - it's generally not clear when something is bytes vs lines
36-
// - offset is a good example of this
37-
3834
if offset < 0 {
3935
return 0, errors.New("ReadLinesAt: negative offset")
4036
}
4137
if len(lines) == 0 {
4238
return 0, nil
4339
}
4440

45-
endLine := offset + int64(len(lines))
41+
count := len(lines)
42+
startLine := offset
43+
endLine := startLine + int64(count)
44+
4645
if endLine > int64(len(r.index)) && !r.eof {
4746
if err := r.indexTo(endLine); err != nil {
4847
return 0, err
4948
}
5049
}
51-
if offset > int64(len(r.index)) {
50+
if startLine > int64(len(r.index)) {
5251
return 0, io.EOF
5352
}
5453

55-
size, readOffset := lookupLines(r.index, offset, int64(len(lines)))
56-
57-
b := make([]byte, size)
58-
if _, err := r.r.ReadAt(b, readOffset); err != nil {
59-
if err == io.EOF {
60-
err = errors.New("ReadLinesAt: corrupt line index or changed source data")
61-
}
54+
buf, byteOffset, err := r.readBytes(startLine, int64(count))
55+
if err != nil {
6256
return 0, err
6357
}
6458

65-
for n = 0; n < len(lines) && offset+int64(n) < int64(len(r.index)); n++ {
66-
i := offset + int64(n)
67-
start, end := readOffset, r.index[i]
68-
if i > 0 {
69-
start = r.index[i-1]
59+
for n = 0; n < count && startLine+int64(n) < int64(len(r.index)); n++ {
60+
lineno := startLine + int64(n)
61+
start, end := int64(0), r.index[lineno]-byteOffset
62+
if lineno > 0 {
63+
start = r.index[lineno-1] - byteOffset
7064
}
71-
lines[n] = b[start-readOffset : end-readOffset]
65+
lines[n] = buf[start:end]
7266
}
7367

74-
if n < len(lines) || b[size-1] != '\n' {
68+
if n < count || buf[len(buf)-1] != '\n' {
7569
return n, io.EOF
7670
}
7771
return n, nil
@@ -110,22 +104,33 @@ func (r *lineReaderAt) indexTo(line int64) error {
110104
return nil
111105
}
112106

113-
// lookupLines gets the byte offset and size of a range of lines from an index
114-
// where the value at n is the offset of the first byte after line number n.
115-
func lookupLines(index []int64, start, n int64) (size int64, offset int64) {
116-
if start > int64(len(index)) {
117-
offset = index[len(index)-1]
118-
} else if start > 0 {
119-
offset = index[start-1]
107+
// readBytes reads the bytes of the n lines starting at line and returns the
108+
// bytes and the offset of the first byte in the underlying source.
109+
func (r *lineReaderAt) readBytes(line, n int64) (b []byte, offset int64, err error) {
110+
indexLen := int64(len(r.index))
111+
112+
var size int64
113+
if line > indexLen {
114+
offset = r.index[indexLen-1]
115+
} else if line > 0 {
116+
offset = r.index[line-1]
120117
}
121118
if n > 0 {
122-
if start+n > int64(len(index)) {
123-
size = index[len(index)-1] - offset
119+
if line+n > indexLen {
120+
size = r.index[indexLen-1] - offset
124121
} else {
125-
size = index[start+n-1] - offset
122+
size = r.index[line+n-1] - offset
123+
}
124+
}
125+
126+
b = make([]byte, size)
127+
if _, err := r.r.ReadAt(b, offset); err != nil {
128+
if err == io.EOF {
129+
err = errors.New("ReadLinesAt: corrupt line index or changed source data")
126130
}
131+
return nil, 0, err
127132
}
128-
return
133+
return b, offset, nil
129134
}
130135

131136
func isLen(r io.ReaderAt, n int64) (bool, error) {

0 commit comments

Comments
 (0)