Browse Source

Optimize initializing TextDocument.

pull/14/head
Daniel Grunwald 15 years ago
parent
commit
43a01803db
  1. 29
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ITextSource.cs
  2. 36
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs
  3. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs
  4. 50
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CharRope.cs
  5. 7
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ImmutableStack.cs
  6. 13
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/Rope.cs
  7. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RopeNode.cs
  8. 13
      src/Main/Base/Project/Src/Editor/DocumentUtilitites.cs
  9. 1
      src/Main/StartUp/Project/StartUp.csproj

29
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ITextSource.cs

@ -43,6 +43,15 @@ namespace ICSharpCode.AvalonEdit.Document @@ -43,6 +43,15 @@ namespace ICSharpCode.AvalonEdit.Document
/// it doesn't require creating a String object.</remarks>
char GetCharAt(int offset);
/// <summary>
/// Gets the index of the first occurrence of any character in the specified array.
/// </summary>
/// <param name="anyOf"></param>
/// <param name="startIndex">Start index of the search.</param>
/// <param name="count">Length of the area to search.</param>
/// <returns>The first index where any character was found; or -1 if no occurrence was found.</returns>
int IndexOfAny(char[] anyOf, int startIndex, int count);
/// <summary>
/// Retrieves the text for a portion of the document.
/// </summary>
@ -148,6 +157,14 @@ namespace ICSharpCode.AvalonEdit.Document @@ -148,6 +157,14 @@ namespace ICSharpCode.AvalonEdit.Document
{
return CreateSnapshot().CreateReader();
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
int offset = viewedSegment.Offset;
int result = baseTextSource.IndexOfAny(anyOf, startIndex + offset, count);
return result >= 0 ? result - offset : result;
}
}
/// <summary>
@ -212,6 +229,12 @@ namespace ICSharpCode.AvalonEdit.Document @@ -212,6 +229,12 @@ namespace ICSharpCode.AvalonEdit.Document
{
return new StringTextSource(text.Substring(offset, length));
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
return text.IndexOfAny(anyOf, startIndex, count);
}
}
/// <summary>
@ -287,5 +310,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -287,5 +310,11 @@ namespace ICSharpCode.AvalonEdit.Document
{
return new RopeTextSource(rope.GetRange(offset, length));
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
return rope.IndexOfAny(anyOf, startIndex, count);
}
}
}

36
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs

@ -10,24 +10,21 @@ namespace ICSharpCode.AvalonEdit.Document @@ -10,24 +10,21 @@ namespace ICSharpCode.AvalonEdit.Document
{
static class NewLineFinder
{
static readonly char[] newline = { '\r', '\n' };
/// <summary>
/// Gets the location of the next new line character, or SimpleSegment.Invalid
/// if none is found.
/// </summary>
internal static SimpleSegment NextNewLine(string text, int offset)
{
for (int i = offset; i < text.Length; i++) {
switch (text[i]) {
case '\r':
if (i + 1 < text.Length) {
if (text[i + 1] == '\n') {
return new SimpleSegment(i, 2);
}
}
goto case '\n';
case '\n':
return new SimpleSegment(i, 1);
int pos = text.IndexOfAny(newline, offset);
if (pos >= 0) {
if (text[pos] == '\r') {
if (pos + 1 < text.Length && text[pos + 1] == '\n')
return new SimpleSegment(pos, 2);
}
return new SimpleSegment(pos, 1);
}
return SimpleSegment.Invalid;
}
@ -39,18 +36,13 @@ namespace ICSharpCode.AvalonEdit.Document @@ -39,18 +36,13 @@ namespace ICSharpCode.AvalonEdit.Document
internal static SimpleSegment NextNewLine(ITextSource text, int offset)
{
int textLength = text.TextLength;
for (int i = offset; i < textLength; i++) {
switch (text.GetCharAt(i)) {
case '\r':
if (i + 1 < textLength) {
if (text.GetCharAt(i + 1) == '\n') {
return new SimpleSegment(i, 2);
}
}
goto case '\n';
case '\n':
return new SimpleSegment(i, 1);
int pos = text.IndexOfAny(newline, offset, textLength - offset);
if (pos >= 0) {
if (text.GetCharAt(pos) == '\r') {
if (pos + 1 < textLength && text.GetCharAt(pos + 1) == '\n')
return new SimpleSegment(pos, 2);
}
return new SimpleSegment(pos, 1);
}
return SimpleSegment.Invalid;
}

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs

@ -155,6 +155,12 @@ namespace ICSharpCode.AvalonEdit.Document @@ -155,6 +155,12 @@ namespace ICSharpCode.AvalonEdit.Document
return GetText(segment.Offset, segment.Length);
}
int ITextSource.IndexOfAny(char[] anyOf, int startIndex, int count)
{
DebugVerifyAccess(); // frequently called (NewLineFinder), so must be fast in release builds
return rope.IndexOfAny(anyOf, startIndex, count);
}
/// <inheritdoc/>
public char GetCharAt(int offset)
{

50
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CharRope.cs

@ -93,16 +93,22 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -93,16 +93,22 @@ namespace ICSharpCode.AvalonEdit.Utils
internal static RopeNode<char> InitFromString(string text)
{
char[] arr = text.ToCharArray();
return RopeNode<char>.CreateFromArray(arr, 0, arr.Length);
/*
if (text.Length == 0) {
return RopeNode<char>.emptyRopeNode;
}
RopeNode<char> node = RopeNode<char>.CreateNodes(text.Length);
// TODO: store data
FillNode(node, text, 0);
return node;
*/
}
static void FillNode(RopeNode<char> node, string text, int start)
{
if (node.contents != null) {
text.CopyTo(start, node.contents, 0, node.length);
} else {
FillNode(node.left, text, start);
FillNode(node.right, text, start + node.left.length);
}
}
internal static void WriteTo(this RopeNode<char> node, int index, StringBuilder output, int count)
@ -128,5 +134,39 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -128,5 +134,39 @@ namespace ICSharpCode.AvalonEdit.Utils
}
}
}
/// <summary>
/// Gets the index of the first occurrence of any element in the specified array.
/// </summary>
/// <param name="rope">The target rope.</param>
/// <param name="anyOf">Array of characters being searched.</param>
/// <param name="startIndex">Start index of the search.</param>
/// <param name="length">Length of the area to search.</param>
/// <returns>The first index where any character was found; or -1 if no occurrence was found.</returns>
public static int IndexOfAny(this Rope<char> rope, char[] anyOf, int startIndex, int length)
{
if (rope == null)
throw new ArgumentNullException("rope");
if (anyOf == null)
throw new ArgumentNullException("anyOf");
rope.VerifyRange(startIndex, length);
while (length > 0) {
var entry = rope.FindNodeUsingCache(startIndex).UnsafePeek();
char[] contents = entry.node.contents;
int startWithinNode = startIndex - entry.nodeStartIndex;
int nodeLength = Math.Min(entry.node.length, startWithinNode + length);
for (int i = startIndex - entry.nodeStartIndex; i < nodeLength; i++) {
char element = contents[i];
foreach (char needle in anyOf) {
if (element == needle)
return entry.nodeStartIndex + i;
}
}
length -= nodeLength - startWithinNode;
startIndex = entry.nodeStartIndex + nodeLength;
}
return -1;
}
}
}

7
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ImmutableStack.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace ICSharpCode.AvalonEdit.Utils
@ -57,6 +58,12 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -57,6 +58,12 @@ namespace ICSharpCode.AvalonEdit.Utils
return value;
}
internal T UnsafePeek()
{
Debug.Assert(!IsEmpty);
return value;
}
/// <summary>
/// Gets the stack with the top item removed.
/// </summary>

13
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/Rope.cs

@ -407,7 +407,7 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -407,7 +407,7 @@ namespace ICSharpCode.AvalonEdit.Utils
}
#region Caches / Changed event
struct RopeCacheEntry
internal struct RopeCacheEntry
{
internal readonly RopeNode<T> node;
internal readonly int nodeStartIndex;
@ -451,7 +451,7 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -451,7 +451,7 @@ namespace ICSharpCode.AvalonEdit.Utils
if (unchecked((uint)index >= (uint)this.Length)) {
throw new ArgumentOutOfRangeException("index", index, "0 <= index < " + this.Length.ToString(CultureInfo.InvariantCulture));
}
RopeCacheEntry entry = FindNodeUsingCache(index).Peek();
RopeCacheEntry entry = FindNodeUsingCache(index).UnsafePeek();
return entry.node.contents[index - entry.nodeStartIndex];
}
set {
@ -500,7 +500,7 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -500,7 +500,7 @@ namespace ICSharpCode.AvalonEdit.Utils
}
}
ImmutableStack<RopeCacheEntry> FindNodeUsingCache(int index)
internal ImmutableStack<RopeCacheEntry> FindNodeUsingCache(int index)
{
Debug.Assert(index >= 0 && index < this.Length);
@ -511,10 +511,10 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -511,10 +511,10 @@ namespace ICSharpCode.AvalonEdit.Utils
if (stack == null) {
stack = ImmutableStack<RopeCacheEntry>.Empty.Push(new RopeCacheEntry(root, 0));
}
while (!stack.Peek().IsInside(index))
while (!stack.UnsafePeek().IsInside(index))
stack = stack.Pop();
while (true) {
RopeCacheEntry entry = stack.Peek();
RopeCacheEntry entry = stack.UnsafePeek();
// check if we've reached a leaf or function node
if (entry.node.height == 0) {
if (entry.node.contents == null) {
@ -622,9 +622,10 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -622,9 +622,10 @@ namespace ICSharpCode.AvalonEdit.Utils
/// </remarks>
public int IndexOf(T item)
{
var comparer = EqualityComparer<T>.Default;
int index = 0;
foreach (T element in this) {
if (object.Equals(item, element))
if (comparer.Equals(item, element))
return index;
index++;
}

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RopeNode.cs

@ -121,7 +121,7 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -121,7 +121,7 @@ namespace ICSharpCode.AvalonEdit.Utils
return node.StoreElements(0, arr, index, length);
}
static RopeNode<T> CreateNodes(int totalLength)
internal static RopeNode<T> CreateNodes(int totalLength)
{
int leafCount = (totalLength + NodeSize - 1) / NodeSize;
return CreateNodes(leafCount, totalLength);

13
src/Main/Base/Project/Src/Editor/DocumentUtilitites.cs

@ -265,6 +265,19 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -265,6 +265,19 @@ namespace ICSharpCode.SharpDevelop.Editor
{
return GetTextSource(textBuffer.CreateSnapshot(offset, length));
}
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
int endIndex = startIndex + count;
for (int i = startIndex; i < endIndex; i++) {
char c = textBuffer.GetCharAt(i);
foreach (char d in anyOf) {
if (c == d)
return i;
}
}
return -1;
}
}
#endregion
}

1
src/Main/StartUp/Project/StartUp.csproj

@ -78,6 +78,7 @@ @@ -78,6 +78,7 @@
</Compile>
</ItemGroup>
<ItemGroup>
<Content Include="ProfilingSessions\Session20101211_181028.sdps" />
<ProjectReference Include="..\..\Base\Project\ICSharpCode.SharpDevelop.csproj">
<Project>{2748AD25-9C63-4E12-877B-4DCE96FBED54}</Project>
<Name>ICSharpCode.SharpDevelop</Name>

Loading…
Cancel
Save