NonOverlappingRangeList.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Ryujinx.Memory.Range
  4. {
  5. /// <summary>
  6. /// A range list that assumes ranges are non-overlapping, with list items that can be split in two to avoid overlaps.
  7. /// </summary>
  8. /// <typeparam name="T">Type of the range.</typeparam>
  9. class NonOverlappingRangeList<T> : RangeList<T> where T : INonOverlappingRange
  10. {
  11. /// <summary>
  12. /// Finds a list of regions that cover the desired (address, size) range.
  13. /// If this range starts or ends in the middle of an existing region, it is split and only the relevant part is added.
  14. /// If there is no matching region, or there is a gap, then new regions are created with the factory.
  15. /// Regions are added to the list in address ascending order.
  16. /// </summary>
  17. /// <param name="list">List to add found regions to</param>
  18. /// <param name="address">Start address of the search region</param>
  19. /// <param name="size">Size of the search region</param>
  20. /// <param name="factory">Factory for creating new ranges</param>
  21. public void GetOrAddRegions(List<T> list, ulong address, ulong size, Func<ulong, ulong, T> factory)
  22. {
  23. // (regarding the specific case this generalized function is used for)
  24. // A new region may be split into multiple parts if multiple virtual regions have mapped to it.
  25. // For instance, while a virtual mapping could cover 0-2 in physical space, the space 0-1 may have already been reserved...
  26. // So we need to return both the split 0-1 and 1-2 ranges.
  27. var results = new T[1];
  28. int count = FindOverlapsNonOverlapping(address, size, ref results);
  29. if (count == 0)
  30. {
  31. // The region is fully unmapped. Create and add it to the range list.
  32. T region = factory(address, size);
  33. list.Add(region);
  34. Add(region);
  35. }
  36. else
  37. {
  38. ulong lastAddress = address;
  39. ulong endAddress = address + size;
  40. for (int i = 0; i < count; i++)
  41. {
  42. T region = results[i];
  43. if (count == 1 && region.Address == address && region.Size == size)
  44. {
  45. // Exact match, no splitting required.
  46. list.Add(region);
  47. return;
  48. }
  49. if (lastAddress < region.Address)
  50. {
  51. // There is a gap between this region and the last. We need to fill it.
  52. T fillRegion = factory(lastAddress, region.Address - lastAddress);
  53. list.Add(fillRegion);
  54. Add(fillRegion);
  55. }
  56. if (region.Address < address)
  57. {
  58. // Split the region around our base address and take the high half.
  59. region = Split(region, address);
  60. }
  61. if (region.EndAddress > address + size)
  62. {
  63. // Split the region around our end address and take the low half.
  64. Split(region, address + size);
  65. }
  66. list.Add(region);
  67. lastAddress = region.EndAddress;
  68. }
  69. if (lastAddress < endAddress)
  70. {
  71. // There is a gap between this region and the end. We need to fill it.
  72. T fillRegion = factory(lastAddress, endAddress - lastAddress);
  73. list.Add(fillRegion);
  74. Add(fillRegion);
  75. }
  76. }
  77. }
  78. /// <summary>
  79. /// Splits a region around a target point and updates the region list.
  80. /// The original region's size is modified, but its address stays the same.
  81. /// A new region starting from the split address is added to the region list and returned.
  82. /// </summary>
  83. /// <param name="region">The region to split</param>
  84. /// <param name="splitAddress">The address to split with</param>
  85. /// <returns>The new region (high part)</returns>
  86. private T Split(T region, ulong splitAddress)
  87. {
  88. T newRegion = (T)region.Split(splitAddress);
  89. Update(region);
  90. Add(newRegion);
  91. return newRegion;
  92. }
  93. }
  94. }