Skip to content

Commit

Permalink
.Parts was returning parts in reverse order, reworked code to be fast…
Browse files Browse the repository at this point in the history
…er (via spans) and return values in the correct order.
  • Loading branch information
halgari committed Aug 30, 2023
1 parent c0f4fd1 commit 8586a7e
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 6 deletions.
33 changes: 29 additions & 4 deletions src/NexusMods.Paths/RelativePath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
using NexusMods.Paths.Extensions;
using NexusMods.Paths.HighPerformance.CommunityToolkit;
using NexusMods.Paths.Utilities;

namespace NexusMods.Paths;
Expand Down Expand Up @@ -72,12 +73,36 @@ public IEnumerable<RelativePath> Parts
{
get
{
var currentPath = this;
while (currentPath.Path != Empty)
// Double iteration because we can't have iterators and spans in the same method.
ReadOnlySpan<char> path = Path;

if (path.Length == 0)
return Array.Empty<RelativePath>();

// Find the number of parts.
var partCount = 0;
for (var idx = 0; idx < path.Length; idx++)
if (path.DangerousGetReferenceAt(idx) == PathHelpers.DirectorySeparatorChar)
partCount++;

// Allocate the array and fill it.
var parts = new RelativePath[partCount + 1];

var prev = 0;
var partIdx = 0;
for (var idx = 0; idx < path.Length; idx++)
{
yield return currentPath.Name;
currentPath = currentPath.Parent;
var ch = path.DangerousGetReferenceAt(idx);
if (ch != PathHelpers.DirectorySeparatorChar) continue;

parts[partIdx] = new RelativePath(new string(path.SliceFast(prev, idx - prev)));
partIdx += 1;
idx += 1;
prev = idx;
}

parts[partIdx] = new RelativePath(new string(path.SliceFast(prev)));
return parts;
}
}

Expand Down
3 changes: 2 additions & 1 deletion tests/NexusMods.Paths.Tests/AbsolutePathTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ public void Test_Parts(bool isUnix, string input, string[] expectedParts)
{
var path = CreatePath(input, isUnix);
var actualParts = path.Parts;
actualParts.Should().BeEquivalentTo(expectedParts.Select(p => new RelativePath(p)));
actualParts.Should().BeEquivalentTo(expectedParts.Select(p => new RelativePath(p)),
opts => opts.WithStrictOrdering());
}

[Theory]
Expand Down
3 changes: 2 additions & 1 deletion tests/NexusMods.Paths.Tests/RelativePathTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ public void Test_GetRootComponent(string input, string expectedRootComponent)
public void Test_Parts(string input, string[] expectedParts)
{
var path = new RelativePath(input);
path.Parts.Should().BeEquivalentTo(expectedParts.Select(x => new RelativePath(x)));
path.Parts.Should().BeEquivalentTo(expectedParts.Select(x => new RelativePath(x)),
opts => opts.WithStrictOrdering());
}

[Theory]
Expand Down

0 comments on commit 8586a7e

Please sign in to comment.