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