@@ -13,7 +13,6 @@ internal class LineTrackingStringBuffer
13
13
private readonly IList < TextLine > _lines ;
14
14
private readonly string _filePath ;
15
15
private TextLine _currentLine ;
16
- private TextLine _endLine ;
17
16
18
17
public LineTrackingStringBuffer ( string content , string filePath )
19
18
: this ( content . ToCharArray ( ) , filePath )
@@ -22,67 +21,66 @@ public LineTrackingStringBuffer(string content, string filePath)
22
21
23
22
public LineTrackingStringBuffer ( char [ ] content , string filePath )
24
23
{
25
- _endLine = new TextLine ( 0 , 0 ) ;
26
- _lines = new List < TextLine > ( ) { _endLine } ;
24
+ _lines = new List < TextLine > ( ) ;
27
25
28
- Append ( content ) ;
26
+ BuildTextLines ( content ) ;
29
27
30
28
_filePath = filePath ;
31
29
}
32
30
33
31
public int Length
34
32
{
35
- get { return _endLine . End ; }
33
+ get { return _lines [ _lines . Count - 1 ] . End ; }
36
34
}
37
35
38
36
public SourceLocation EndLocation
39
37
{
40
- get { return new SourceLocation ( _filePath , Length , _lines . Count - 1 , _lines [ _lines . Count - 1 ] . Length ) ; }
38
+ get { return new SourceLocation ( _filePath , Length , _lines . Count - 1 , Length ) ; }
41
39
}
42
40
43
41
public CharacterReference CharAt ( int absoluteIndex )
44
42
{
45
43
var line = FindLine ( absoluteIndex ) ;
46
- if ( line == null )
44
+ if ( line . IsDefault )
47
45
{
48
46
throw new ArgumentOutOfRangeException ( nameof ( absoluteIndex ) ) ;
49
47
}
50
48
var idx = absoluteIndex - line . Start ;
51
49
return new CharacterReference ( line . Content [ idx ] , new SourceLocation ( _filePath , absoluteIndex , line . Index , idx ) ) ;
52
50
}
53
51
54
- private void Append ( char [ ] content )
52
+ private void BuildTextLines ( char [ ] content )
55
53
{
54
+ string lineText ;
55
+ var lineStart = 0 ;
56
+
56
57
for ( int i = 0 ; i < content . Length ; i ++ )
57
58
{
58
- AppendCore ( content [ i ] ) ;
59
-
60
- // \r on it's own: Start a new line, otherwise wait for \n
61
- // Other Newline: Start a new line
62
- if ( ( content [ i ] == '\r ' && ( i + 1 == content . Length || content [ i + 1 ] != '\n ' ) ) || ( content [ i ] != '\r ' && ParserHelpers . IsNewLine ( content [ i ] ) ) )
59
+ if ( ParserHelpers . IsNewLine ( content [ i ] ) )
63
60
{
64
- PushNewLine ( ) ;
61
+ // \r on it's own: Start a new line, otherwise wait for \n
62
+ // Other Newline: Start a new line
63
+ if ( content [ i ] == '\r ' && i + 1 < content . Length && content [ i + 1 ] == '\n ' )
64
+ {
65
+ i ++ ;
66
+ }
67
+
68
+ lineText = new string ( content , lineStart , ( i - lineStart ) + 1 ) ; // +1 to include the current char
69
+ _lines . Add ( new TextLine ( lineStart , _lines . Count , lineText ) ) ;
70
+
71
+ lineStart = i + 1 ;
65
72
}
66
73
}
67
- }
68
74
69
- private void PushNewLine ( )
70
- {
71
- _endLine = new TextLine ( _endLine . End , _endLine . Index + 1 ) ;
72
- _lines . Add ( _endLine ) ;
73
- }
74
-
75
- private void AppendCore ( char chr )
76
- {
77
- Debug . Assert ( _lines . Count > 0 ) ;
78
- _lines [ _lines . Count - 1 ] . Content . Append ( chr ) ;
75
+ lineText = new string ( content , lineStart , content . Length - lineStart ) ; // no +1 as content.Length points past the last char already
76
+ _lines . Add ( new TextLine ( lineStart , _lines . Count , lineText ) ) ;
79
77
}
80
78
81
79
private TextLine FindLine ( int absoluteIndex )
82
80
{
83
- TextLine selected = null ;
81
+ TextLine selected ;
84
82
85
- if ( _currentLine == null )
83
+ if ( _currentLine . IsDefault )
86
84
{
87
85
// Scan from line 0
88
86
selected = ScanLines ( absoluteIndex , 0 , _lines . Count ) ;
@@ -104,6 +102,10 @@ private TextLine FindLine(int absoluteIndex)
104
102
selected = ScanLines ( absoluteIndex , _currentLine . Index , _lines . Count ) ;
105
103
}
106
104
}
105
+ else
106
+ {
107
+ selected = default ;
108
+ }
107
109
}
108
110
else if ( absoluteIndex < _currentLine . Start )
109
111
{
@@ -122,14 +124,18 @@ private TextLine FindLine(int absoluteIndex)
122
124
selected = ScanLines ( absoluteIndex , 0 , _currentLine . Index ) ;
123
125
}
124
126
}
127
+ else
128
+ {
129
+ selected = default ;
130
+ }
125
131
}
126
132
else
127
133
{
128
134
// This index is on the last read line
129
135
selected = _currentLine ;
130
136
}
131
137
132
- Debug . Assert ( selected == null || selected . Contains ( absoluteIndex ) ) ;
138
+ Debug . Assert ( selected . IsDefault || selected . Contains ( absoluteIndex ) ) ;
133
139
_currentLine = selected ;
134
140
return selected ;
135
141
}
@@ -159,7 +165,7 @@ private TextLine ScanLines(int absoluteIndex, int startLineIndex, int endLineInd
159
165
}
160
166
}
161
167
162
- return null ;
168
+ return default ;
163
169
}
164
170
165
171
internal struct CharacterReference
@@ -175,28 +181,26 @@ public CharacterReference(char character, SourceLocation location)
175
181
public SourceLocation Location { get ; }
176
182
}
177
183
178
- private class TextLine
184
+ private struct TextLine
179
185
{
180
- private StringBuilder _content = new StringBuilder ( ) ;
181
-
182
- public TextLine ( int start , int index )
186
+ public TextLine ( int start , int index , string content )
183
187
{
184
188
Start = start ;
185
189
Index = index ;
190
+ Content = content ;
186
191
}
187
192
188
- public StringBuilder Content
189
- {
190
- get { return _content ; }
191
- }
193
+ public string Content { get ; }
194
+
195
+ public bool IsDefault => Content == null ;
192
196
193
197
public int Length
194
198
{
195
199
get { return Content . Length ; }
196
200
}
197
201
198
- public int Start { get ; set ; }
199
- public int Index { get ; set ; }
202
+ public int Start { get ; }
203
+ public int Index { get ; }
200
204
201
205
public int End
202
206
{
0 commit comments