diff --git a/src/NexusMods.Paths/RelativePath.cs b/src/NexusMods.Paths/RelativePath.cs index 5e761c1..3332190 100644 --- a/src/NexusMods.Paths/RelativePath.cs +++ b/src/NexusMods.Paths/RelativePath.cs @@ -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; @@ -72,12 +73,36 @@ public IEnumerable Parts { get { - var currentPath = this; - while (currentPath.Path != Empty) + // Double iteration because we can't have iterators and spans in the same method. + ReadOnlySpan path = Path; + + if (path.Length == 0) + return Array.Empty(); + + // 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; } } diff --git a/tests/NexusMods.Paths.Tests/AbsolutePathTests.cs b/tests/NexusMods.Paths.Tests/AbsolutePathTests.cs index 5fe3c3e..bc1cca3 100644 --- a/tests/NexusMods.Paths.Tests/AbsolutePathTests.cs +++ b/tests/NexusMods.Paths.Tests/AbsolutePathTests.cs @@ -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] diff --git a/tests/NexusMods.Paths.Tests/RelativePathTests.cs b/tests/NexusMods.Paths.Tests/RelativePathTests.cs index e8bde9c..467f556 100644 --- a/tests/NexusMods.Paths.Tests/RelativePathTests.cs +++ b/tests/NexusMods.Paths.Tests/RelativePathTests.cs @@ -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]