From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001 From: TSR Berry <20988865+TSRBerry@users.noreply.github.com> Date: Sat, 8 Apr 2023 01:22:00 +0200 Subject: Move solution and projects to src --- .../Range/NonOverlappingRangeList.cs | 106 +++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs (limited to 'src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs') diff --git a/src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs b/src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs new file mode 100644 index 00000000..60b2b378 --- /dev/null +++ b/src/Ryujinx.Memory/Range/NonOverlappingRangeList.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; + +namespace Ryujinx.Memory.Range +{ + /// + /// A range list that assumes ranges are non-overlapping, with list items that can be split in two to avoid overlaps. + /// + /// Type of the range. + class NonOverlappingRangeList : RangeList where T : INonOverlappingRange + { + /// + /// Finds a list of regions that cover the desired (address, size) range. + /// If this range starts or ends in the middle of an existing region, it is split and only the relevant part is added. + /// If there is no matching region, or there is a gap, then new regions are created with the factory. + /// Regions are added to the list in address ascending order. + /// + /// List to add found regions to + /// Start address of the search region + /// Size of the search region + /// Factory for creating new ranges + public void GetOrAddRegions(List list, ulong address, ulong size, Func factory) + { + // (regarding the specific case this generalized function is used for) + // A new region may be split into multiple parts if multiple virtual regions have mapped to it. + // For instance, while a virtual mapping could cover 0-2 in physical space, the space 0-1 may have already been reserved... + // So we need to return both the split 0-1 and 1-2 ranges. + + var results = new T[1]; + int count = FindOverlapsNonOverlapping(address, size, ref results); + + if (count == 0) + { + // The region is fully unmapped. Create and add it to the range list. + T region = factory(address, size); + list.Add(region); + Add(region); + } + else + { + ulong lastAddress = address; + ulong endAddress = address + size; + + for (int i = 0; i < count; i++) + { + T region = results[i]; + if (count == 1 && region.Address == address && region.Size == size) + { + // Exact match, no splitting required. + list.Add(region); + return; + } + + if (lastAddress < region.Address) + { + // There is a gap between this region and the last. We need to fill it. + T fillRegion = factory(lastAddress, region.Address - lastAddress); + list.Add(fillRegion); + Add(fillRegion); + } + + if (region.Address < address) + { + // Split the region around our base address and take the high half. + + region = Split(region, address); + } + + if (region.EndAddress > address + size) + { + // Split the region around our end address and take the low half. + + Split(region, address + size); + } + + list.Add(region); + lastAddress = region.EndAddress; + } + + if (lastAddress < endAddress) + { + // There is a gap between this region and the end. We need to fill it. + T fillRegion = factory(lastAddress, endAddress - lastAddress); + list.Add(fillRegion); + Add(fillRegion); + } + } + } + + /// + /// Splits a region around a target point and updates the region list. + /// The original region's size is modified, but its address stays the same. + /// A new region starting from the split address is added to the region list and returned. + /// + /// The region to split + /// The address to split with + /// The new region (high part) + private T Split(T region, ulong splitAddress) + { + T newRegion = (T)region.Split(splitAddress); + Update(region); + Add(newRegion); + return newRegion; + } + } +} -- cgit v1.2.3