Added overloads to Path.Join (dotnet/coreclr#24307)
authorBlake Hensley <jbhensley@users.noreply.github.com>
Thu, 2 May 2019 04:07:07 +0000 (21:07 -0700)
committerAnirudh Agnihotry <anirudhagnihotry098@gmail.com>
Thu, 2 May 2019 04:07:07 +0000 (21:07 -0700)
* 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

Commit migrated from https://github.com/dotnet/coreclr/commit/886b81692e13861cd1aa80e72e726792093ca671

src/libraries/System.Private.CoreLib/src/System/IO/Path.cs

index db491bf..27741b9 100644 (file)
@@ -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<char> 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<char> path1, ReadOnlySpan<char> path2, ReadOnlySpan<char> path3, ReadOnlySpan<char> 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<char> 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<char> path1, ReadOnlySpan<char> path2, Span<char> destination, out int charsWritten)
         {
             charsWritten = 0;