PageRenderTime 25ms CodeModel.GetById 14ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RopeTextReader.cs

http://github.com/icsharpcode/ILSpy
C# | 120 lines | 76 code | 10 blank | 34 comment | 22 complexity | 79aeee8f07221a06870803149aa079e3 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.Collections.Generic;
 21using System.Diagnostics;
 22using System.IO;
 23
 24namespace ICSharpCode.AvalonEdit.Utils
 25{
 26	/// <summary>
 27	/// TextReader implementation that reads text from a rope.
 28	/// </summary>
 29	public sealed class RopeTextReader : TextReader
 30	{
 31		Stack<RopeNode<char>> stack = new Stack<RopeNode<char>>();
 32		RopeNode<char> currentNode;
 33		int indexInsideNode;
 34		
 35		/// <summary>
 36		/// Creates a new RopeTextReader.
 37		/// Internally, this method creates a Clone of the rope; so the text reader will always read through the old
 38		/// version of the rope if it is modified. <seealso cref="Rope{T}.Clone()"/>
 39		/// </summary>
 40		public RopeTextReader(Rope<char> rope)
 41		{
 42			if (rope == null)
 43				throw new ArgumentNullException("rope");
 44			
 45			// We force the user to iterate through a clone of the rope to keep the API contract of RopeTextReader simple
 46			// (what happens when a rope is modified while iterating through it?)
 47			rope.root.Publish();
 48			
 49			// special case for the empty rope:
 50			// leave currentNode initialized to null (RopeTextReader doesn't support empty nodes)
 51			if (rope.Length != 0) {
 52				currentNode = rope.root;
 53				GoToLeftMostLeaf();
 54			}
 55		}
 56		
 57		void GoToLeftMostLeaf()
 58		{
 59			while (currentNode.contents == null) {
 60				if (currentNode.height == 0) {
 61					// this is a function node - move to its contained rope
 62					currentNode = currentNode.GetContentNode();
 63					continue;
 64				}
 65				Debug.Assert(currentNode.right != null);
 66				stack.Push(currentNode.right);
 67				currentNode = currentNode.left;
 68			}
 69			Debug.Assert(currentNode.height == 0);
 70		}
 71		
 72		/// <inheritdoc/>
 73		public override int Peek()
 74		{
 75			if (currentNode == null)
 76				return -1;
 77			return currentNode.contents[indexInsideNode];
 78		}
 79		
 80		/// <inheritdoc/>
 81		public override int Read()
 82		{
 83			if (currentNode == null)
 84				return -1;
 85			char result = currentNode.contents[indexInsideNode++];
 86			if (indexInsideNode >= currentNode.length)
 87				GoToNextNode();
 88			return result;
 89		}
 90		
 91		void GoToNextNode()
 92		{
 93			if (stack.Count == 0) {
 94				currentNode = null;
 95			} else {
 96				indexInsideNode = 0;
 97				currentNode = stack.Pop();
 98				GoToLeftMostLeaf();
 99			}
100		}
101		
102		/// <inheritdoc/>
103		public override int Read(char[] buffer, int index, int count)
104		{
105			if (currentNode == null)
106				return 0;
107			int amountInCurrentNode = currentNode.length - indexInsideNode;
108			if (count < amountInCurrentNode) {
109				Array.Copy(currentNode.contents, indexInsideNode, buffer, index, count);
110				indexInsideNode += count;
111				return count;
112			} else {
113				// read to end of current node
114				Array.Copy(currentNode.contents, indexInsideNode, buffer, index, amountInCurrentNode);
115				GoToNextNode();
116				return amountInCurrentNode;
117			}
118		}
119	}
120}