ValueRangeSet.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. using System.Collections.Generic;
  2. namespace Ryujinx.Graphics
  3. {
  4. class ValueRangeSet<T>
  5. {
  6. private List<ValueRange<T>> Ranges;
  7. public ValueRangeSet()
  8. {
  9. Ranges = new List<ValueRange<T>>();
  10. }
  11. public void Add(ValueRange<T> Range)
  12. {
  13. if (Range.End <= Range.Start)
  14. {
  15. //Empty or invalid range, do nothing.
  16. return;
  17. }
  18. int First = BinarySearchFirstIntersection(Range);
  19. if (First == -1)
  20. {
  21. //No intersections case.
  22. //Find first greater than range (after the current one).
  23. //If found, add before, otherwise add to the end of the list.
  24. int GtIndex = BinarySearchGt(Range);
  25. if (GtIndex != -1)
  26. {
  27. Ranges.Insert(GtIndex, Range);
  28. }
  29. else
  30. {
  31. Ranges.Add(Range);
  32. }
  33. return;
  34. }
  35. (int Start, int End) = GetAllIntersectionRanges(Range, First);
  36. ValueRange<T> Prev = Ranges[Start];
  37. ValueRange<T> Next = Ranges[End];
  38. Ranges.RemoveRange(Start, (End - Start) + 1);
  39. InsertNextNeighbour(Start, Range, Next);
  40. int NewIndex = Start;
  41. Ranges.Insert(Start, Range);
  42. InsertPrevNeighbour(Start, Range, Prev);
  43. //Try merging neighbours if the value is equal.
  44. if (NewIndex > 0)
  45. {
  46. Prev = Ranges[NewIndex - 1];
  47. if (Prev.End == Range.Start && CompareValues(Prev, Range))
  48. {
  49. Ranges.RemoveAt(--NewIndex);
  50. Ranges[NewIndex] = new ValueRange<T>(Prev.Start, Range.End, Range.Value);
  51. }
  52. }
  53. if (NewIndex < Ranges.Count - 1)
  54. {
  55. Next = Ranges[NewIndex + 1];
  56. if (Next.Start == Range.End && CompareValues(Next, Range))
  57. {
  58. Ranges.RemoveAt(NewIndex + 1);
  59. Ranges[NewIndex] = new ValueRange<T>(Range.Start, Next.End, Range.Value);
  60. }
  61. }
  62. }
  63. private bool CompareValues(ValueRange<T> LHS, ValueRange<T> RHS)
  64. {
  65. return LHS.Value?.Equals(RHS.Value) ?? RHS.Value == null;
  66. }
  67. public void Remove(ValueRange<T> Range)
  68. {
  69. int First = BinarySearchFirstIntersection(Range);
  70. if (First == -1)
  71. {
  72. //Nothing to remove.
  73. return;
  74. }
  75. (int Start, int End) = GetAllIntersectionRanges(Range, First);
  76. ValueRange<T> Prev = Ranges[Start];
  77. ValueRange<T> Next = Ranges[End];
  78. Ranges.RemoveRange(Start, (End - Start) + 1);
  79. InsertNextNeighbour(Start, Range, Next);
  80. InsertPrevNeighbour(Start, Range, Prev);
  81. }
  82. private void InsertNextNeighbour(int Index, ValueRange<T> Range, ValueRange<T> Next)
  83. {
  84. //Split last intersection (ordered by Start) if necessary.
  85. if (Range.End < Next.End)
  86. {
  87. InsertNewRange(Index, Range.End, Next.End, Next.Value);
  88. }
  89. }
  90. private void InsertPrevNeighbour(int Index, ValueRange<T> Range, ValueRange<T> Prev)
  91. {
  92. //Split first intersection (ordered by Start) if necessary.
  93. if (Range.Start > Prev.Start)
  94. {
  95. InsertNewRange(Index, Prev.Start, Range.Start, Prev.Value);
  96. }
  97. }
  98. private void InsertNewRange(int Index, long Start, long End, T Value)
  99. {
  100. Ranges.Insert(Index, new ValueRange<T>(Start, End, Value));
  101. }
  102. public ValueRange<T>[] GetAllIntersections(ValueRange<T> Range)
  103. {
  104. int First = BinarySearchFirstIntersection(Range);
  105. if (First == -1)
  106. {
  107. return new ValueRange<T>[0];
  108. }
  109. (int Start, int End) = GetAllIntersectionRanges(Range, First);
  110. return Ranges.GetRange(Start, (End - Start) + 1).ToArray();
  111. }
  112. private (int Start, int End) GetAllIntersectionRanges(ValueRange<T> Range, int BaseIndex)
  113. {
  114. int Start = BaseIndex;
  115. int End = BaseIndex;
  116. while (Start > 0 && Intersects(Range, Ranges[Start - 1]))
  117. {
  118. Start--;
  119. }
  120. while (End < Ranges.Count - 1 && Intersects(Range, Ranges[End + 1]))
  121. {
  122. End++;
  123. }
  124. return (Start, End);
  125. }
  126. private int BinarySearchFirstIntersection(ValueRange<T> Range)
  127. {
  128. int Left = 0;
  129. int Right = Ranges.Count - 1;
  130. while (Left <= Right)
  131. {
  132. int Size = Right - Left;
  133. int Middle = Left + (Size >> 1);
  134. ValueRange<T> Current = Ranges[Middle];
  135. if (Intersects(Range, Current))
  136. {
  137. return Middle;
  138. }
  139. if (Range.Start < Current.Start)
  140. {
  141. Right = Middle - 1;
  142. }
  143. else
  144. {
  145. Left = Middle + 1;
  146. }
  147. }
  148. return -1;
  149. }
  150. private int BinarySearchGt(ValueRange<T> Range)
  151. {
  152. int GtIndex = -1;
  153. int Left = 0;
  154. int Right = Ranges.Count - 1;
  155. while (Left <= Right)
  156. {
  157. int Size = Right - Left;
  158. int Middle = Left + (Size >> 1);
  159. ValueRange<T> Current = Ranges[Middle];
  160. if (Range.Start < Current.Start)
  161. {
  162. Right = Middle - 1;
  163. if (GtIndex == -1 || Current.Start < Ranges[GtIndex].Start)
  164. {
  165. GtIndex = Middle;
  166. }
  167. }
  168. else
  169. {
  170. Left = Middle + 1;
  171. }
  172. }
  173. return GtIndex;
  174. }
  175. private bool Intersects(ValueRange<T> LHS, ValueRange<T> RHS)
  176. {
  177. return LHS.Start < RHS.End && RHS.Start < LHS.End;
  178. }
  179. }
  180. }