@@ -62,6 +62,13 @@ type Reader interface {
6262 // that the returned first line may be different from the requested one.
6363 GetLines (firstLine linemetadata.Index , wantedLineCount int ) InputLines
6464
65+ // GetLines gets the indicated lines from the input. The lines will be stored
66+ // in the provided preallocated slice to avoid allocations. The line count is
67+ // determined by the capacity of the provided slice.
68+ //
69+ // The return value is the status text for the returned lines.
70+ GetLinesPreallocated (firstLine linemetadata.Index , resultLines * []NumberedLine ) string
71+
6572 // False when paused. Showing the paused line count is confusing, because
6673 // the user might think that the number is the total line count, even though
6774 // we are not done yet.
@@ -944,7 +951,6 @@ func clipRangeToLength(start linemetadata.Index, wantedCount int, maxIndex int)
944951// GetLines gets the indicated lines from the input
945952func (reader * ReaderImpl ) GetLines (firstLine linemetadata.Index , wantedLineCount int ) InputLines {
946953 reader .RLock ()
947-
948954 if len (reader .lines ) == 0 || wantedLineCount == 0 {
949955 statusText := reader .createStatusUnlocked (firstLine )
950956 reader .RUnlock ()
@@ -953,29 +959,54 @@ func (reader *ReaderImpl) GetLines(firstLine linemetadata.Index, wantedLineCount
953959 StatusText : statusText ,
954960 }
955961 }
962+ reader .RUnlock ()
956963
957- // Prevent reading past the end of the available lines
958964 firstLineIndex , lastLineIndex := clipRangeToLength (firstLine , wantedLineCount , len (reader .lines )- 1 )
965+ wantedLineCount = lastLineIndex - firstLineIndex + 1
966+
967+ resultLines := make ([]NumberedLine , 0 , wantedLineCount )
968+ statusText := reader .GetLinesPreallocated (linemetadata .IndexFromZeroBased (firstLineIndex ), & resultLines )
969+
970+ return InputLines {
971+ Lines : resultLines ,
972+ StatusText : statusText ,
973+ }
974+ }
975+
976+ // GetLines gets the indicated lines from the input. The lines will be stored
977+ // in the provided preallocated slice to avoid allocations. The line count is
978+ // determined by the capacity of the provided slice.
979+ //
980+ // The return value is the status text for the returned lines.
981+ func (reader * ReaderImpl ) GetLinesPreallocated (firstLine linemetadata.Index , resultLines * []NumberedLine ) string {
982+ // Clear the result slice
983+ * resultLines = (* resultLines )[:0 ]
984+
985+ reader .RLock ()
986+
987+ if len (reader .lines ) == 0 || cap (* resultLines ) == 0 {
988+ statusText := reader .createStatusUnlocked (firstLine )
989+ reader .RUnlock ()
990+
991+ return statusText
992+ }
993+
994+ // Prevent reading past the end of the available lines
995+ firstLineIndex , lastLineIndex := clipRangeToLength (firstLine , cap (* resultLines ), len (reader .lines )- 1 )
959996
960997 statusText := reader .createStatusUnlocked (linemetadata .IndexFromZeroBased (lastLineIndex ))
961998
962- returnLines := make ([]NumberedLine , 0 , lastLineIndex - firstLineIndex + 1 )
963999 for loopIndex , returnLine := range reader .lines [firstLineIndex : lastLineIndex + 1 ] {
964- lineIndex := linemetadata .IndexFromZeroBased (firstLineIndex + loopIndex )
965- returnLines = append (returnLines , NumberedLine {
966- Index : lineIndex ,
1000+ * resultLines = append (* resultLines , NumberedLine {
1001+ Index : linemetadata .IndexFromZeroBased (firstLineIndex + loopIndex ),
9671002 Number : linemetadata .NumberFromZeroBased (firstLineIndex + loopIndex ),
9681003 Line : returnLine ,
9691004 })
9701005 }
9711006
972- // Scary parts done, no lock needed anymore
9731007 reader .RUnlock ()
9741008
975- return InputLines {
976- Lines : returnLines ,
977- StatusText : statusText ,
978- }
1009+ return statusText
9791010}
9801011
9811012func (reader * ReaderImpl ) PumpToStdout () {
0 commit comments