MultiRangeList.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. using Ryujinx.Common.Collections;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. namespace Ryujinx.Memory.Range
  5. {
  6. public class MultiRangeList<T> : IEnumerable<T> where T : IMultiRangeItem
  7. {
  8. private readonly IntervalTree<ulong, T> _items;
  9. public int Count { get; private set; }
  10. /// <summary>
  11. /// Creates a new range list.
  12. /// </summary>
  13. public MultiRangeList()
  14. {
  15. _items = new IntervalTree<ulong, T>();
  16. }
  17. /// <summary>
  18. /// Adds a new item to the list.
  19. /// </summary>
  20. /// <param name="item">The item to be added</param>
  21. public void Add(T item)
  22. {
  23. MultiRange range = item.Range;
  24. for (int i = 0; i < range.Count; i++)
  25. {
  26. var subrange = range.GetSubRange(i);
  27. _items.Add(subrange.Address, subrange.EndAddress, item);
  28. }
  29. Count++;
  30. }
  31. /// <summary>
  32. /// Removes an item from the list.
  33. /// </summary>
  34. /// <param name="item">The item to be removed</param>
  35. /// <returns>True if the item was removed, or false if it was not found</returns>
  36. public bool Remove(T item)
  37. {
  38. MultiRange range = item.Range;
  39. int removed = 0;
  40. for (int i = 0; i < range.Count; i++)
  41. {
  42. var subrange = range.GetSubRange(i);
  43. removed += _items.Remove(subrange.Address, item);
  44. }
  45. if (removed > 0)
  46. {
  47. // All deleted intervals are for the same item - the one we removed.
  48. Count--;
  49. }
  50. return removed > 0;
  51. }
  52. /// <summary>
  53. /// Gets all items on the list overlapping the specified memory range.
  54. /// </summary>
  55. /// <param name="address">Start address of the range</param>
  56. /// <param name="size">Size in bytes of the range</param>
  57. /// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param>
  58. /// <returns>The number of overlapping items found</returns>
  59. public int FindOverlaps(ulong address, ulong size, ref T[] output)
  60. {
  61. return FindOverlaps(new MultiRange(address, size), ref output);
  62. }
  63. /// <summary>
  64. /// Gets all items on the list overlapping the specified memory ranges.
  65. /// </summary>
  66. /// <param name="range">Ranges of memory being searched</param>
  67. /// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param>
  68. /// <returns>The number of overlapping items found</returns>
  69. public int FindOverlaps(MultiRange range, ref T[] output)
  70. {
  71. int overlapCount = 0;
  72. for (int i = 0; i < range.Count; i++)
  73. {
  74. var subrange = range.GetSubRange(i);
  75. overlapCount = _items.Get(subrange.Address, subrange.EndAddress, ref output, overlapCount);
  76. }
  77. // Remove any duplicates, caused by items having multiple sub range nodes in the tree.
  78. if (overlapCount > 1)
  79. {
  80. int insertPtr = 0;
  81. for (int i = 0; i < overlapCount; i++)
  82. {
  83. T item = output[i];
  84. bool duplicate = false;
  85. for (int j = insertPtr - 1; j >= 0; j--)
  86. {
  87. if (item.Equals(output[j]))
  88. {
  89. duplicate = true;
  90. break;
  91. }
  92. }
  93. if (!duplicate)
  94. {
  95. if (insertPtr != i)
  96. {
  97. output[insertPtr] = item;
  98. }
  99. insertPtr++;
  100. }
  101. }
  102. overlapCount = insertPtr;
  103. }
  104. return overlapCount;
  105. }
  106. /// <summary>
  107. /// Gets all items on the list starting at the specified memory address.
  108. /// </summary>
  109. /// <param name="baseAddress">Base address to find</param>
  110. /// <param name="output">Output array where matches will be written. It is automatically resized to fit the results</param>
  111. /// <returns>The number of matches found</returns>
  112. public int FindOverlaps(ulong baseAddress, ref T[] output)
  113. {
  114. int count = _items.Get(baseAddress, ref output);
  115. // Only output items with matching base address
  116. int insertPtr = 0;
  117. for (int i = 0; i < count; i++)
  118. {
  119. if (output[i].BaseAddress == baseAddress)
  120. {
  121. if (i != insertPtr)
  122. {
  123. output[insertPtr] = output[i];
  124. }
  125. insertPtr++;
  126. }
  127. }
  128. return insertPtr;
  129. }
  130. private List<T> GetList()
  131. {
  132. var items = _items.AsList();
  133. var result = new List<T>();
  134. foreach (RangeNode<ulong, T> item in items)
  135. {
  136. if (item.Start == item.Value.BaseAddress)
  137. {
  138. result.Add(item.Value);
  139. }
  140. }
  141. return result;
  142. }
  143. public IEnumerator<T> GetEnumerator()
  144. {
  145. return GetList().GetEnumerator();
  146. }
  147. IEnumerator IEnumerable.GetEnumerator()
  148. {
  149. return GetList().GetEnumerator();
  150. }
  151. }
  152. }