Skip to content

Commit 3998616

Browse files
committed
Reduced number of branches
1 parent ee3e368 commit 3998616

File tree

1 file changed

+28
-30
lines changed

1 file changed

+28
-30
lines changed

src/DotNext/IO/FileUri.cs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Buffers;
22
using System.Diagnostics;
33
using System.Runtime.CompilerServices;
4-
using System.Runtime.InteropServices;
54
using System.Text.Encodings.Web;
65

76
namespace DotNext.IO;
@@ -20,10 +19,6 @@ public static class FileUri
2019
// \\.\folder => file://./folder
2120
private const string FileScheme = "file://";
2221
private const string UncPrefix = @"\\";
23-
private const char DriveSeparatorChar = ':';
24-
25-
private static readonly SearchValues<char> Delimiters =
26-
SearchValues.Create(OperatingSystem.IsWindows() ? [Path.DirectorySeparatorChar, DriveSeparatorChar] : [Path.DirectorySeparatorChar]);
2722

2823
/// <summary>
2924
/// Encodes file name as URI.
@@ -86,9 +81,12 @@ private static void ThrowIfPartiallyQualified(ReadOnlySpan<char> fileName)
8681
private static bool TryEncodeCore(ReadOnlySpan<char> fileName, UrlEncoder encoder, Span<char> output, out int charsWritten)
8782
{
8883
const char slash = '/';
84+
const char driveSeparator = ':';
8985
const char escapedDriveSeparatorChar = '|';
9086
var writer = new SpanWriter<char>(output);
9187
writer.Write(FileScheme);
88+
89+
bool endsWithTrailingSeparator;
9290
if (!OperatingSystem.IsWindows())
9391
{
9492
// nothing to do
@@ -97,42 +95,42 @@ private static bool TryEncodeCore(ReadOnlySpan<char> fileName, UrlEncoder encode
9795
{
9896
fileName = fileName.Slice(UncPrefix.Length);
9997
}
100-
else
98+
else if (GetPathComponent(ref fileName, out endsWithTrailingSeparator) is [.. var drive, driveSeparator])
10199
{
102-
writer.Add(slash);
100+
writer.Write(drive);
101+
writer.Write(endsWithTrailingSeparator ? [escapedDriveSeparatorChar, slash] : [escapedDriveSeparatorChar]);
103102
}
104103

105-
while (!fileName.IsEmpty)
104+
for (;; writer.Add(slash))
106105
{
107-
var index = fileName.IndexOfAny(Delimiters);
108-
char replacement;
109-
ReadOnlySpan<char> component;
110-
if (index >= 0)
111-
{
112-
component = fileName.Slice(0, index);
113-
114-
// skip bounds check
115-
replacement = OperatingSystem.IsWindows() && Unsafe.Add(ref MemoryMarshal.GetReference(fileName), index) is DriveSeparatorChar
116-
? escapedDriveSeparatorChar
117-
: slash;
118-
fileName = fileName.Slice(index + 1);
119-
}
120-
else
121-
{
122-
component = fileName;
123-
fileName = default;
124-
replacement = '\0';
125-
}
126-
106+
var component = GetPathComponent(ref fileName, out endsWithTrailingSeparator);
127107
if (encoder.Encode(component, writer.RemainingSpan, out _, out charsWritten) is not OperationStatus.Done)
128108
return false;
129109

130110
writer.Advance(charsWritten);
131-
if (replacement is not '\0')
132-
writer.Add(replacement);
111+
if (!endsWithTrailingSeparator)
112+
break;
133113
}
134114

135115
charsWritten = writer.WrittenCount;
136116
return true;
137117
}
118+
119+
private static ReadOnlySpan<char> GetPathComponent(ref ReadOnlySpan<char> fileName, out bool endsWithTrailingSeparator)
120+
{
121+
ReadOnlySpan<char> component;
122+
var index = fileName.IndexOf(Path.DirectorySeparatorChar);
123+
if (endsWithTrailingSeparator = index >= 0)
124+
{
125+
component = fileName.Slice(0, index);
126+
fileName = fileName.Slice(index + 1);
127+
}
128+
else
129+
{
130+
component = fileName;
131+
fileName = default;
132+
}
133+
134+
return component;
135+
}
138136
}

0 commit comments

Comments
 (0)