@@ -186,6 +186,8 @@ private int GetNumNewLineCharacters()
186186 private class TextLines : IList < String >
187187 {
188188 private LinkedList < String > lines ;
189+ private int lastAccessedIndex ;
190+ private LinkedListNode < String > lastAccessedNode ;
189191
190192 private void ValidateIndex ( int index )
191193 {
@@ -195,23 +197,94 @@ private void ValidateIndex(int index)
195197 }
196198 }
197199
200+ private void SetLastAccessed ( int index , LinkedListNode < String > node )
201+ {
202+ lastAccessedIndex = index ;
203+ lastAccessedNode = node ;
204+ }
205+
206+ private void InvalidateLastAccessed ( )
207+ {
208+ lastAccessedIndex = - 1 ;
209+ lastAccessedNode = null ;
210+ }
211+
212+ private bool IsLastAccessedValid ( )
213+ {
214+ return lastAccessedIndex != - 1 ;
215+ }
216+
198217 private LinkedListNode < String > GetNodeAt ( int index )
199218 {
200- var node = lines . First ;
201- int count = 0 ;
219+ if ( index == 0 )
220+ {
221+ return lines . First ;
222+ }
223+
224+ if ( index == Count - 1 )
225+ {
226+ return lines . Last ;
227+ }
228+
229+ LinkedListNode < string > node ;
230+ int searchDirection ;
231+ int count ;
232+ GetClosestReference ( index , out node , out count , out searchDirection ) ;
202233 while ( node != null )
203234 {
204- if ( count ++ == index )
235+ if ( count == index )
205236 {
206237 return node ;
207238 }
208239
209- node = node . Next ;
240+ count += searchDirection ;
241+ if ( searchDirection > 0 )
242+ {
243+ node = node . Next ;
244+ }
245+ else
246+ {
247+ node = node . Previous ;
248+ }
210249 }
211250
212251 throw new InvalidOperationException ( ) ;
213252 }
214253
254+ private void GetClosestReference (
255+ int index ,
256+ out LinkedListNode < string > refNode ,
257+ out int refIndex ,
258+ out int searchDirection )
259+ {
260+ var delta = index - lastAccessedIndex ;
261+ var deltaAbs = Math . Abs ( delta ) ;
262+
263+ // lastAccessedIndex is closer to index than 0
264+ if ( IsLastAccessedValid ( ) && deltaAbs < index )
265+ {
266+ // lastAccessedIndex is closer to index than Count - 1
267+ if ( deltaAbs < ( Count - 1 - index ) )
268+ {
269+ refNode = lastAccessedNode ;
270+ refIndex = lastAccessedIndex ;
271+ searchDirection = Math . Sign ( delta ) ;
272+ }
273+ else
274+ {
275+ refNode = lines . Last ;
276+ refIndex = Count - 1 ;
277+ searchDirection = - 1 ;
278+ }
279+ }
280+ else
281+ {
282+ refNode = lines . First ;
283+ refIndex = 0 ;
284+ searchDirection = 1 ;
285+ }
286+ }
287+
215288 public string this [ int index ]
216289 {
217290 get
@@ -235,9 +308,10 @@ public TextLines()
235308 {
236309 lines = new LinkedList < String > ( ) ;
237310 Count = 0 ;
311+ InvalidateLastAccessed ( ) ;
238312 }
239313
240- public TextLines ( IEnumerable < String > inputLines )
314+ public TextLines ( IEnumerable < String > inputLines ) : this ( )
241315 {
242316 if ( inputLines == null )
243317 {
@@ -305,19 +379,7 @@ public int IndexOf(string item)
305379 public void Insert ( int index , string item )
306380 {
307381 ValidateIndex ( index ) ;
308- if ( index == 0 )
309- {
310- lines . AddFirst ( item ) ;
311- }
312- else if ( index == Count - 1 )
313- {
314- lines . AddBefore ( lines . Last , item ) ;
315- }
316- else
317- {
318- lines . AddBefore ( GetNodeAt ( index ) , item ) ;
319- }
320-
382+ SetLastAccessed ( index , lines . AddBefore ( GetNodeAt ( index ) , item ) ) ;
321383 Count ++ ;
322384 }
323385
@@ -334,7 +396,21 @@ public bool Remove(string item)
334396
335397 public void RemoveAt ( int index )
336398 {
337- lines . Remove ( GetNodeAt ( index ) ) ;
399+ var node = GetNodeAt ( index ) ;
400+ if ( node . Next != null )
401+ {
402+ SetLastAccessed ( index , node . Next ) ;
403+ }
404+ else if ( node . Previous != null )
405+ {
406+ SetLastAccessed ( index - 1 , node . Previous ) ;
407+ }
408+ else
409+ {
410+ InvalidateLastAccessed ( ) ;
411+ }
412+
413+ lines . Remove ( node ) ;
338414 Count -- ;
339415 }
340416
0 commit comments