@@ -31,47 +31,41 @@ type lineReaderAt struct {
3131}
3232
3333func (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
131136func isLen (r io.ReaderAt , n int64 ) (bool , error ) {
0 commit comments