PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Workspaces/Core/Portable/Shared/Collections/IntervalTree`1.cs

https://gitlab.com/sharadag/Roslyn
C# | 302 lines | 232 code | 48 blank | 22 comment | 47 complexity | 332254b4f728ff7a11dbfdb00d25ebdc MD5 | raw file
  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using Microsoft.CodeAnalysis.Text;
  8. using Roslyn.Utilities;
  9. namespace Microsoft.CodeAnalysis.Shared.Collections
  10. {
  11. /// <summary>
  12. /// An interval tree represents an ordered tree data structure to store intervals of the form [start, end). It
  13. /// allows you to efficiently find all intervals that intersect or overlap a provided interval.
  14. /// </summary>
  15. internal partial class IntervalTree<T> : IEnumerable<T>
  16. {
  17. public static readonly IntervalTree<T> Empty = new IntervalTree<T>();
  18. protected Node root;
  19. private delegate bool TestInterval(T value, int start, int length, IIntervalIntrospector<T> introspector);
  20. private static readonly TestInterval s_intersectsWithTest = IntersectsWith;
  21. private static readonly TestInterval s_containsTest = Contains;
  22. private static readonly TestInterval s_overlapsWithTest = OverlapsWith;
  23. public IntervalTree()
  24. {
  25. }
  26. public IntervalTree(IIntervalIntrospector<T> introspector, IEnumerable<T> values)
  27. {
  28. foreach (var value in values)
  29. {
  30. root = Insert(root, new Node(value), introspector);
  31. }
  32. }
  33. protected static bool Contains(T value, int start, int length, IIntervalIntrospector<T> introspector)
  34. {
  35. var otherStart = start;
  36. var otherEnd = start + length;
  37. var thisEnd = GetEnd(value, introspector);
  38. var thisStart = introspector.GetStart(value);
  39. // make sure "Contains" test to be same as what TextSpan does
  40. if (length == 0)
  41. {
  42. return thisStart <= otherStart && otherEnd < thisEnd;
  43. }
  44. return thisStart <= otherStart && otherEnd <= thisEnd;
  45. }
  46. private static bool IntersectsWith(T value, int start, int length, IIntervalIntrospector<T> introspector)
  47. {
  48. var otherStart = start;
  49. var otherEnd = start + length;
  50. var thisEnd = GetEnd(value, introspector);
  51. var thisStart = introspector.GetStart(value);
  52. return otherStart <= thisEnd && otherEnd >= thisStart;
  53. }
  54. private static bool OverlapsWith(T value, int start, int length, IIntervalIntrospector<T> introspector)
  55. {
  56. var otherStart = start;
  57. var otherEnd = start + length;
  58. var thisEnd = GetEnd(value, introspector);
  59. var thisStart = introspector.GetStart(value);
  60. if (length == 0)
  61. {
  62. return thisStart < otherStart && otherStart < thisEnd;
  63. }
  64. int overlapStart = Math.Max(thisStart, otherStart);
  65. int overlapEnd = Math.Min(thisEnd, otherEnd);
  66. return overlapStart < overlapEnd;
  67. }
  68. public IEnumerable<T> GetOverlappingIntervals(int start, int length, IIntervalIntrospector<T> introspector)
  69. {
  70. return this.GetInOrderIntervals(start, length, s_overlapsWithTest, introspector);
  71. }
  72. public IEnumerable<T> GetIntersectingIntervals(int start, int length, IIntervalIntrospector<T> introspector)
  73. {
  74. return this.GetInOrderIntervals(start, length, s_intersectsWithTest, introspector);
  75. }
  76. public IEnumerable<T> GetContainingIntervals(int start, int length, IIntervalIntrospector<T> introspector)
  77. {
  78. return this.GetInOrderIntervals(start, length, s_containsTest, introspector);
  79. }
  80. public bool IntersectsWith(int position, IIntervalIntrospector<T> introspector)
  81. {
  82. return GetIntersectingIntervals(position, 0, introspector).Any();
  83. }
  84. private IEnumerable<T> GetInOrderIntervals(int start, int length, TestInterval testInterval, IIntervalIntrospector<T> introspector)
  85. {
  86. if (root == null)
  87. {
  88. yield break;
  89. }
  90. var end = start + length;
  91. // The bool indicates if this is the first time we are seeing the node.
  92. var candidates = new Stack<ValueTuple<Node, bool>>();
  93. candidates.Push(ValueTuple.Create(root, true));
  94. while (candidates.Count > 0)
  95. {
  96. var currentTuple = candidates.Pop();
  97. var currentNode = currentTuple.Item1;
  98. Debug.Assert(currentNode != null);
  99. var firstTime = currentTuple.Item2;
  100. if (!firstTime)
  101. {
  102. // We're seeing this node for the second time (as we walk back up the left
  103. // side of it). Now see if it matches our test, and if so return it out.
  104. if (testInterval(currentNode.Value, start, length, introspector))
  105. {
  106. yield return currentNode.Value;
  107. }
  108. }
  109. else
  110. {
  111. // First time we're seeing this node. In order to see the node 'in-order',
  112. // we push the right side, then the node again, then the left side. This
  113. // time we mark the current node with 'false' to indicate that it's the
  114. // second time we're seeing it the next time it comes around.
  115. // right children's starts will never be to the left of the parent's start
  116. // so we should consider right subtree only if root's start overlaps with
  117. // interval's End,
  118. if (introspector.GetStart(currentNode.Value) <= end)
  119. {
  120. var right = currentNode.Right;
  121. if (right != null && GetEnd(right.MaxEndNode.Value, introspector) >= start)
  122. {
  123. candidates.Push(ValueTuple.Create(right, true));
  124. }
  125. }
  126. candidates.Push(ValueTuple.Create(currentNode, false));
  127. // only if left's maxVal overlaps with interval's start, we should consider
  128. // left subtree
  129. var left = currentNode.Left;
  130. if (left != null && GetEnd(left.MaxEndNode.Value, introspector) >= start)
  131. {
  132. candidates.Push(ValueTuple.Create(left, true));
  133. }
  134. }
  135. }
  136. }
  137. public bool IsEmpty()
  138. {
  139. return this.root == null;
  140. }
  141. protected static Node Insert(Node root, Node newNode, IIntervalIntrospector<T> introspector)
  142. {
  143. var newNodeStart = introspector.GetStart(newNode.Value);
  144. return Insert(root, newNode, newNodeStart, introspector);
  145. }
  146. private static Node Insert(Node root, Node newNode, int newNodeStart, IIntervalIntrospector<T> introspector)
  147. {
  148. if (root == null)
  149. {
  150. return newNode;
  151. }
  152. Node newLeft, newRight;
  153. if (newNodeStart < introspector.GetStart(root.Value))
  154. {
  155. newLeft = Insert(root.Left, newNode, newNodeStart, introspector);
  156. newRight = root.Right;
  157. }
  158. else
  159. {
  160. newLeft = root.Left;
  161. newRight = Insert(root.Right, newNode, newNodeStart, introspector);
  162. }
  163. root.SetLeftRight(newLeft, newRight, introspector);
  164. var newRoot = root;
  165. return Balance(newRoot, introspector);
  166. }
  167. private static Node Balance(Node node, IIntervalIntrospector<T> introspector)
  168. {
  169. int balanceFactor = BalanceFactor(node);
  170. if (balanceFactor == -2)
  171. {
  172. int rightBalance = BalanceFactor(node.Right);
  173. if (rightBalance == -1)
  174. {
  175. return node.LeftRotation(introspector);
  176. }
  177. else
  178. {
  179. Contract.Requires(rightBalance == 1);
  180. return node.InnerRightOuterLeftRotation(introspector);
  181. }
  182. }
  183. else if (balanceFactor == 2)
  184. {
  185. int leftBalance = BalanceFactor(node.Left);
  186. if (leftBalance == 1)
  187. {
  188. return node.RightRotation(introspector);
  189. }
  190. else
  191. {
  192. Contract.Requires(leftBalance == -1);
  193. return node.InnerLeftOuterRightRotation(introspector);
  194. }
  195. }
  196. return node;
  197. }
  198. public IEnumerator<T> GetEnumerator()
  199. {
  200. if (root == null)
  201. {
  202. yield break;
  203. }
  204. // The bool indicates if this is the first time we are seeing the node.
  205. var candidates = new Stack<ValueTuple<Node, bool>>();
  206. candidates.Push(ValueTuple.Create(root, true));
  207. while (candidates.Count != 0)
  208. {
  209. var currentTuple = candidates.Pop();
  210. var currentNode = currentTuple.Item1;
  211. if (currentNode != null)
  212. {
  213. if (currentTuple.Item2)
  214. {
  215. // First time seeing this node. Mark that we've been seen and recurse
  216. // down the left side. The next time we see this node we'll yield it
  217. // out.
  218. candidates.Push(ValueTuple.Create(currentNode.Right, true));
  219. candidates.Push(ValueTuple.Create(currentNode, false));
  220. candidates.Push(ValueTuple.Create(currentNode.Left, true));
  221. }
  222. else
  223. {
  224. yield return currentNode.Value;
  225. }
  226. }
  227. }
  228. }
  229. IEnumerator IEnumerable.GetEnumerator()
  230. {
  231. return this.GetEnumerator();
  232. }
  233. protected static int GetEnd(T value, IIntervalIntrospector<T> introspector)
  234. {
  235. return introspector.GetStart(value) + introspector.GetLength(value);
  236. }
  237. protected static int MaxEndValue(Node node, IIntervalIntrospector<T> arg)
  238. {
  239. return node == null ? 0 : GetEnd(node.MaxEndNode.Value, arg);
  240. }
  241. private static int Height(Node node)
  242. {
  243. return node == null ? 0 : node.Height;
  244. }
  245. private static int BalanceFactor(Node node)
  246. {
  247. if (node == null)
  248. {
  249. return 0;
  250. }
  251. return Height(node.Left) - Height(node.Right);
  252. }
  253. }
  254. }