From 886b81692e13861cd1aa80e72e726792093ca671 Mon Sep 17 00:00:00 2001 From: Blake Hensley Date: Wed, 1 May 2019 21:07:07 -0700 Subject: [PATCH] Added overloads to Path.Join (#24307) * Added overloads to Path.Join * Refactor Path.Join and Path.Combine to use ValueStringBuilder * Use proper defined const for empty string * Fix Windows-specific const --- .../shared/System/IO/Path.cs | 96 +++++++++++++++++++--- 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/src/System.Private.CoreLib/shared/System/IO/Path.cs b/src/System.Private.CoreLib/shared/System/IO/Path.cs index db491bf..27741b9 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Path.cs +++ b/src/System.Private.CoreLib/shared/System/IO/Path.cs @@ -346,7 +346,7 @@ namespace System.IO throw new ArgumentNullException(nameof(paths)); } - int finalSize = 0; + int maxSize = 0; int firstComponent = 0; // We have two passes, the first calculates how large a buffer to allocate and does some precondition @@ -367,19 +367,21 @@ namespace System.IO if (IsPathRooted(paths[i])) { firstComponent = i; - finalSize = paths[i].Length; + maxSize = paths[i].Length; } else { - finalSize += paths[i].Length; + maxSize += paths[i].Length; } char ch = paths[i][paths[i].Length - 1]; if (!PathInternal.IsDirectorySeparator(ch)) - finalSize++; + maxSize++; } - StringBuilder finalPath = StringBuilderCache.Acquire(finalSize); + Span initialBuffer = stackalloc char[260]; // MaxShortPath on Windows + var builder = new ValueStringBuilder(initialBuffer); + builder.EnsureCapacity(maxSize); for (int i = firstComponent; i < paths.Length; i++) { @@ -388,23 +390,23 @@ namespace System.IO continue; } - if (finalPath.Length == 0) + if (builder.Length == 0) { - finalPath.Append(paths[i]); + builder.Append(paths[i]); } else { - char ch = finalPath[finalPath.Length - 1]; + char ch = builder[builder.Length - 1]; if (!PathInternal.IsDirectorySeparator(ch)) { - finalPath.Append(PathInternal.DirectorySeparatorChar); + builder.Append(PathInternal.DirectorySeparatorChar); } - finalPath.Append(paths[i]); + builder.Append(paths[i]); } } - return StringBuilderCache.GetStringAndRelease(finalPath); + return builder.ToString(); } // Unlike Combine(), Join() methods do not consider rooting. They simply combine paths, ensuring that there @@ -434,6 +436,23 @@ namespace System.IO return JoinInternal(path1, path2, path3); } + public static string Join(ReadOnlySpan path1, ReadOnlySpan path2, ReadOnlySpan path3, ReadOnlySpan path4) + { + if (path1.Length == 0) + return Join(path2, path3, path4); + + if (path2.Length == 0) + return Join(path1, path3, path4); + + if (path3.Length == 0) + return Join(path1, path2, path4); + + if (path4.Length == 0) + return Join(path1, path2, path3); + + return JoinInternal(path1, path2, path3, path4); + } + public static string Join(string? path1, string? path2) { return Join(path1.AsSpan(), path2.AsSpan()); @@ -444,6 +463,61 @@ namespace System.IO return Join(path1.AsSpan(), path2.AsSpan(), path3.AsSpan()); } + public static string Join(string? path1, string? path2, string? path3, string? path4) + { + return Join(path1.AsSpan(), path2.AsSpan(), path3.AsSpan(), path4.AsSpan()); + } + + public static string Join(params string[] paths) + { + if (paths == null) + { + throw new ArgumentNullException(nameof(paths)); + } + + if (paths.Length == 0) + { + return string.Empty; + } + + int maxSize = 0; + foreach (string path in paths) + { + maxSize += path?.Length ?? 0; + } + maxSize += paths.Length - 1; + + Span initialBuffer = stackalloc char[260]; // MaxShortPath on Windows + var builder = new ValueStringBuilder(initialBuffer); + builder.EnsureCapacity(maxSize); + + for (int i = 0; i < paths.Length; i++) + { + if ((paths[i]?.Length ?? 0) == 0) + { + continue; + } + + string path = paths[i]; + + if (builder.Length == 0) + { + builder.Append(path); + } + else + { + if (!PathInternal.IsDirectorySeparator(builder[builder.Length - 1]) && !PathInternal.IsDirectorySeparator(path[0])) + { + builder.Append(PathInternal.DirectorySeparatorChar); + } + + builder.Append(path); + } + } + + return builder.ToString(); + } + public static bool TryJoin(ReadOnlySpan path1, ReadOnlySpan path2, Span destination, out int charsWritten) { charsWritten = 0; -- 2.7.4