/main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/PieceTable.cs

https://github.com/zgramana/monodevelop · C# · 325 lines · 252 code · 46 blank · 27 comment · 59 complexity · 6826e8d02b7c9615dbd266aa27ebab14 MD5 · raw file

  1. //
  2. // PieceTable.cs
  3. //
  4. // Author:
  5. // Mike Krüger <mkrueger@novell.com>
  6. //
  7. // Copyright (c) 2009 Novell, Inc (http://www.novell.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. using System;
  27. namespace Mono.MHex.Data
  28. {
  29. public class PieceTable
  30. {
  31. public abstract class TreeNode
  32. {
  33. public long TotalLength {
  34. get;
  35. set;
  36. }
  37. public long CalcOffset (RedBlackTree<TreeNode>.RedBlackTreeNode Node)
  38. {
  39. RedBlackTree<TreeNode>.RedBlackTreeNode cur = Node;
  40. long offset = cur.left != null ? cur.left.value.TotalLength : 0;
  41. while (cur.parent != null) {
  42. if (cur == cur.parent.right) {
  43. if (cur.parent.left != null && cur.parent.left.value != null)
  44. offset += cur.parent.left.value.TotalLength;
  45. if (Node.parent.value != null)
  46. offset += cur.parent.value.Length;
  47. }
  48. cur = cur.parent;
  49. }
  50. return offset;
  51. }
  52. public long Length {
  53. get;
  54. set;
  55. }
  56. public TreeNode (long length)
  57. {
  58. this.Length = length;
  59. }
  60. public abstract byte[] GetBytes (HexEditorData hexEditorData, long myOffset, long offset, int count);
  61. public TreeNode SplitRight (long leftLength)
  62. {
  63. return InternalSplitRight (System.Math.Min (Length, System.Math.Max (0, leftLength)));
  64. }
  65. protected abstract TreeNode InternalSplitRight (long leftLength);
  66. }
  67. public class OriginalTreeNode : TreeNode, ICloneable
  68. {
  69. long BufferOffset {
  70. get;
  71. set;
  72. }
  73. public OriginalTreeNode (long bufferOffset, long length) : base (length)
  74. {
  75. this.BufferOffset = bufferOffset;
  76. }
  77. public override byte[] GetBytes (HexEditorData hexEditorData, long myOffset, long offset, int count)
  78. {
  79. return hexEditorData.buffer.GetBytes (BufferOffset + offset - myOffset, count);
  80. }
  81. protected override TreeNode InternalSplitRight (long leftLength)
  82. {
  83. return new OriginalTreeNode (BufferOffset + leftLength, Length - leftLength);
  84. }
  85. public override string ToString ()
  86. {
  87. return string.Format ("[OriginalTreeNode: Length={0}, bufferOffset={1}, TotalLength={2}]", Length, BufferOffset, TotalLength);
  88. }
  89. public object Clone ()
  90. {
  91. OriginalTreeNode result = new OriginalTreeNode (BufferOffset, Length);
  92. result.TotalLength = TotalLength;
  93. return result;
  94. }
  95. }
  96. public class DataTreeNode : TreeNode, ICloneable
  97. {
  98. int AddBufferOffset {
  99. get;
  100. set;
  101. }
  102. public DataTreeNode (int addBufferOffset, long length) : base (length)
  103. {
  104. this.AddBufferOffset = addBufferOffset;
  105. }
  106. public override byte[] GetBytes (HexEditorData hexEditorData, long myOffset, long offset, int count)
  107. {
  108. byte[] result = new byte[count];
  109. for (int i = 0, j = (int)(AddBufferOffset + offset - myOffset); i < result.Length; i++, j++) {
  110. result[i] = hexEditorData.addBuffer [j];
  111. }
  112. return result;
  113. }
  114. protected override TreeNode InternalSplitRight (long leftLength)
  115. {
  116. return new DataTreeNode (AddBufferOffset + (int)leftLength, Length - leftLength);
  117. }
  118. public override string ToString ()
  119. {
  120. return string.Format ("[DataTreeNode: Length={0}, addBufferOffset={1}, TotalLength={2}]", Length, AddBufferOffset, TotalLength);
  121. }
  122. public object Clone ()
  123. {
  124. DataTreeNode result = new DataTreeNode (AddBufferOffset, Length);
  125. result.TotalLength = TotalLength;
  126. return result;
  127. }
  128. }
  129. internal RedBlackTree<TreeNode> tree = new RedBlackTree<TreeNode> ();
  130. public int Count {
  131. get {
  132. return tree.Count;
  133. }
  134. }
  135. public long Length {
  136. get {
  137. return tree.Root.value.TotalLength;
  138. }
  139. }
  140. public PieceTable ()
  141. {
  142. tree.ChildrenChanged += delegate (object sender, RedBlackTree<TreeNode>.RedBlackTreeNodeEventArgs args) {
  143. UpdateNode (args.Node);
  144. };
  145. tree.NodeRotateLeft += delegate (object sender, RedBlackTree<TreeNode>.RedBlackTreeNodeEventArgs args) {
  146. UpdateNode (args.Node);
  147. UpdateNode (args.Node.parent);
  148. };
  149. tree.NodeRotateRight += delegate (object sender, RedBlackTree<TreeNode>.RedBlackTreeNodeEventArgs args) {
  150. UpdateNode (args.Node);
  151. UpdateNode (args.Node.parent);
  152. };
  153. Clear ();
  154. }
  155. void UpdateNode (RedBlackTree<TreeNode>.RedBlackTreeNode node)
  156. {
  157. if (node == null)
  158. return;
  159. long currentTotalLength = node.value.Length;
  160. if (node.left != null)
  161. currentTotalLength += node.left.value.TotalLength;
  162. if (node.right != null)
  163. currentTotalLength += node.right.value.TotalLength;
  164. if (currentTotalLength != node.value.TotalLength) {
  165. node.value.TotalLength = currentTotalLength;
  166. UpdateNode (node.parent);
  167. }
  168. }
  169. void ChangeLength (RedBlackTree<TreeNode>.RedBlackTreeNode node, long newLength)
  170. {
  171. node.value.Length = newLength;
  172. UpdateNode (node);
  173. }
  174. void RemoveNode (RedBlackTree<TreeNode>.RedBlackTreeNode node)
  175. {
  176. RedBlackTree<TreeNode>.RedBlackTreeNode parent = node.parent;
  177. tree.RemoveNode (node);
  178. UpdateNode (parent);
  179. if (tree.Root == null)
  180. Clear ();
  181. }
  182. RedBlackTree<TreeNode>.RedBlackTreeNode InsertAfter (RedBlackTree<TreeNode>.RedBlackTreeNode node, TreeNode nodeToInsert)
  183. {
  184. RedBlackTree<TreeNode>.RedBlackTreeNode newNode = new RedBlackTree<TreeNode>.RedBlackTreeNode (nodeToInsert);
  185. RedBlackTree<TreeNode>.RedBlackTreeIterator iter = new RedBlackTree<TreeNode>.RedBlackTreeIterator (node);
  186. if (iter.node.right == null) {
  187. tree.Insert (iter.node, newNode, false);
  188. } else {
  189. tree.Insert (iter.node.right.OuterLeft, newNode, true);
  190. }
  191. UpdateNode (newNode);
  192. return newNode;
  193. }
  194. public void Clear ()
  195. {
  196. PieceTable.TreeNode node = new OriginalTreeNode (0, 0);
  197. tree.Root = new RedBlackTree<TreeNode>.RedBlackTreeNode (node);
  198. tree.Count = 1;
  199. }
  200. public RedBlackTree<TreeNode>.RedBlackTreeNode GetTreeNodeAtOffset (long offset)
  201. {
  202. if (offset == tree.Root.value.TotalLength)
  203. return tree.Root.OuterRight;
  204. RedBlackTree<TreeNode>.RedBlackTreeNode node = tree.Root;
  205. long i = offset;
  206. while (true) {
  207. if (node == null)
  208. return null;
  209. if (node.left != null && i < node.left.value.TotalLength) {
  210. node = node.left;
  211. } else {
  212. if (node.left != null)
  213. i -= node.left.value.TotalLength;
  214. i -= node.value.Length;
  215. if (i < 0)
  216. return node;
  217. node = node.right;
  218. }
  219. }
  220. }
  221. public void Remove (long offset, long length)
  222. {
  223. if (length == 0 || Length == 0)
  224. return;
  225. RedBlackTree<TreeNode>.RedBlackTreeNode startNode = GetTreeNodeAtOffset (offset);
  226. RedBlackTree<TreeNode>.RedBlackTreeNode endNode = GetTreeNodeAtOffset (offset + length);
  227. long newLength = offset - startNode.value.CalcOffset (startNode);
  228. if (startNode == endNode) {
  229. TreeNode splittedNode = startNode.value.SplitRight (newLength + length);
  230. ChangeLength (startNode, newLength);
  231. if (splittedNode.Length > 0)
  232. InsertAfter (startNode, splittedNode);
  233. return;
  234. }
  235. long endSegmentLength = endNode != null ? offset + length - endNode.value.CalcOffset (endNode) : 0;
  236. RedBlackTree<TreeNode>.RedBlackTreeIterator iter = new RedBlackTree<TreeNode>.RedBlackTreeIterator (startNode);
  237. RedBlackTree<TreeNode>.RedBlackTreeNode node;
  238. do {
  239. node = iter.CurrentNode;
  240. iter.MoveNext ();
  241. if (node == null)
  242. break;
  243. if (node == startNode) {
  244. // has no right side, otherwise it would be startNode == endNode
  245. length -= node.value.Length;
  246. ChangeLength (node, newLength);
  247. } else if (node == endNode) {
  248. // has no left side, otherwise it would be startNode == endNode
  249. TreeNode rightSide = node.value.SplitRight (endSegmentLength);
  250. if (rightSide.Length > 0)
  251. InsertAfter (node, rightSide);
  252. RemoveNode (node);
  253. } else { // nodes in between
  254. length -= node.value.Length;
  255. RemoveNode (node);
  256. }
  257. } while (node != endNode);
  258. }
  259. public void Insert (long offset, int addBufferOffset, long addLength)
  260. {
  261. RedBlackTree<TreeNode>.RedBlackTreeNode node = GetTreeNodeAtOffset (offset);
  262. long oldNodeOffset = node.value.CalcOffset (node);
  263. long newLength = offset - oldNodeOffset;
  264. TreeNode splittedNode = node.value.SplitRight (newLength);
  265. ChangeLength (node, newLength);
  266. RedBlackTree<TreeNode>.RedBlackTreeNode newNode = InsertAfter (node, new DataTreeNode (addBufferOffset, addLength));
  267. if (splittedNode.Length > 0)
  268. InsertAfter (newNode, splittedNode);
  269. if (newLength == 0)
  270. RemoveNode (node);
  271. }
  272. public void SetBuffer (IBuffer buffer)
  273. {
  274. tree.Root = new RedBlackTree<TreeNode>.RedBlackTreeNode (new OriginalTreeNode (0, buffer.Length));
  275. tree.Root.value.TotalLength = buffer.Length;
  276. tree.Count = 1;
  277. }
  278. }
  279. }