PageRenderTime 61ms CodeModel.GetById 57ms app.highlight 1ms RepoModel.GetById 1ms app.codeStats 0ms

/AvalonEdit/ICSharpCode.AvalonEdit/Document/GapTextBuffer.cs

http://github.com/icsharpcode/ILSpy
C# | 207 lines | 7 code | 3 blank | 197 comment | 0 complexity | 86226131f1ec0526c6b8fcfe954643aa MD5 | raw file
  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}