Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2389-EpsLexicase/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Document/GapTextBuffer.cs

Last change on this file was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 6.6 KB
Line 
1// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Diagnostics;
21using System.Text;
22
23using ICSharpCode.AvalonEdit.Utils;
24
25namespace ICSharpCode.AvalonEdit.Document
26{
27  /*
28  /// <summary>
29  /// Implementation of a gap text buffer.
30  /// </summary>
31  sealed class GapTextBuffer
32  {
33    char[] buffer = Empty<char>.Array;
34   
35    /// <summary>
36    /// The current text content.
37    /// Is set to null whenever the buffer changes, and gets a value only when the
38    /// full text content is requested.
39    /// </summary>
40    string textContent;
41   
42    /// <summary>
43    /// last GetText result
44    /// </summary>
45    string lastGetTextResult;
46    int lastGetTextRequestOffset;
47   
48    int gapBeginOffset;
49    int gapEndOffset;
50    int gapLength; // gapLength == gapEndOffset - gapBeginOffset
51   
52    /// <summary>
53    /// when gap is too small for inserted text or gap is too large (exceeds maxGapLength),
54    /// a new buffer is reallocated with a new gap of at least this size.
55    /// </summary>
56    const int minGapLength = 128;
57   
58    /// <summary>
59    /// when the gap exceeds this size, reallocate a smaller buffer
60    /// </summary>
61    const int maxGapLength = 4096;
62   
63    public int Length {
64      get {
65        return buffer.Length - gapLength;
66      }
67    }
68   
69    /// <summary>
70    /// Gets the buffer content.
71    /// </summary>
72    public string Text {
73      get {
74        if (textContent == null)
75          textContent = GetText(0, Length);
76        return textContent;
77      }
78      set {
79        Debug.Assert(value != null);
80        textContent = value;  lastGetTextResult = null;
81        buffer = new char[value.Length + minGapLength];
82        value.CopyTo(0, buffer, 0, value.Length);
83        gapBeginOffset = value.Length;
84        gapEndOffset = buffer.Length;
85        gapLength = gapEndOffset - gapBeginOffset;
86      }
87    }
88   
89    public char GetCharAt(int offset)
90    {
91      return offset < gapBeginOffset ? buffer[offset] : buffer[offset + gapLength];
92    }
93   
94    public string GetText(int offset, int length)
95    {
96      if (length == 0)
97        return string.Empty;
98      if (lastGetTextRequestOffset == offset && lastGetTextResult != null && length == lastGetTextResult.Length)
99        return lastGetTextResult;
100     
101      int end = offset + length;
102      string result;
103      if (end < gapBeginOffset) {
104        result = new string(buffer, offset, length);
105      } else if (offset > gapBeginOffset) {
106        result = new string(buffer, offset + gapLength, length);
107      } else {
108        int block1Size = gapBeginOffset - offset;
109        int block2Size = end - gapBeginOffset;
110       
111        StringBuilder buf = new StringBuilder(block1Size + block2Size);
112        buf.Append(buffer, offset,       block1Size);
113        buf.Append(buffer, gapEndOffset, block2Size);
114        result = buf.ToString();
115      }
116      lastGetTextRequestOffset = offset;
117      lastGetTextResult = result;
118      return result;
119    }
120   
121    /// <summary>
122    /// Inserts text at the specified offset.
123    /// </summary>
124    public void Insert(int offset, string text)
125    {
126      Debug.Assert(offset >= 0 && offset <= Length);
127     
128      if (text.Length == 0)
129        return;
130     
131      textContent = null; lastGetTextResult = null;
132      PlaceGap(offset, text.Length);
133      text.CopyTo(0, buffer, gapBeginOffset, text.Length);
134      gapBeginOffset += text.Length;
135      gapLength = gapEndOffset - gapBeginOffset;
136    }
137   
138    /// <summary>
139    /// Remove <paramref name="length"/> characters at <paramref name="offset"/>.
140    /// Leave a gap of at least <paramref name="reserveGapSize"/>.
141    /// </summary>
142    public void Remove(int offset, int length, int reserveGapSize)
143    {
144      Debug.Assert(offset >= 0 && offset <= Length);
145      Debug.Assert(length >= 0 && offset + length <= Length);
146      Debug.Assert(reserveGapSize >= 0);
147     
148      if (length == 0)
149        return;
150     
151      textContent = null; lastGetTextResult = null;
152      PlaceGap(offset, reserveGapSize - length);
153      gapEndOffset += length; // delete removed text
154      gapLength = gapEndOffset - gapBeginOffset;
155      if (gapLength - reserveGapSize > maxGapLength && gapLength - reserveGapSize > buffer.Length / 4) {
156        // shrink gap
157        MakeNewBuffer(gapBeginOffset, reserveGapSize + minGapLength);
158      }
159    }
160   
161    void PlaceGap(int newGapOffset, int minRequiredGapLength)
162    {
163      if (gapLength < minRequiredGapLength) {
164        // enlarge gap
165        MakeNewBuffer(newGapOffset, minRequiredGapLength + Math.Max(minGapLength, buffer.Length / 8));
166      } else {
167        while (newGapOffset < gapBeginOffset) {
168          buffer[--gapEndOffset] = buffer[--gapBeginOffset];
169        }
170        while (newGapOffset > gapBeginOffset) {
171          buffer[gapBeginOffset++] = buffer[gapEndOffset++];
172        }
173      }
174    }
175   
176    void MakeNewBuffer(int newGapOffset, int newGapLength)
177    {
178      char[] newBuffer = new char[Length + newGapLength];
179      Debug.WriteLine("GapTextBuffer was reallocated, new size=" + newBuffer.Length);
180      if (newGapOffset < gapBeginOffset) {
181        // gap is moving backwards
182       
183        // first part:
184        Array.Copy(buffer, 0, newBuffer, 0, newGapOffset);
185        // moving middle part:
186        Array.Copy(buffer, newGapOffset, newBuffer, newGapOffset + newGapLength, gapBeginOffset - newGapOffset);
187        // last part:
188        Array.Copy(buffer, gapEndOffset, newBuffer, newBuffer.Length - (buffer.Length - gapEndOffset), buffer.Length - gapEndOffset);
189      } else {
190        // gap is moving forwards
191        // first part:
192        Array.Copy(buffer, 0, newBuffer, 0, gapBeginOffset);
193        // moving middle part:
194        Array.Copy(buffer, gapEndOffset, newBuffer, gapBeginOffset, newGapOffset - gapBeginOffset);
195        // last part:
196        int lastPartLength = newBuffer.Length - (newGapOffset + newGapLength);
197        Array.Copy(buffer, buffer.Length - lastPartLength, newBuffer, newGapOffset + newGapLength, lastPartLength);
198      }
199     
200      gapBeginOffset = newGapOffset;
201      gapEndOffset = newGapOffset + newGapLength;
202      gapLength = newGapLength;
203      buffer = newBuffer;
204    }
205  }
206  */
207}
Note: See TracBrowser for help on using the repository browser.