Skip to content

Commit 4b6bab3

Browse files
stevenawpeterrsongg
authored andcommitted
Optimize GetExtension execution time on NET8 (#3359)
1 parent a4a77f1 commit 4b6bab3

File tree

3 files changed

+69
-11
lines changed

3 files changed

+69
-11
lines changed

sdk/src/Core/Amazon.Util/AWSSDKUtils.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,31 @@ private static string DetermineValidPathCharacters()
195195
/// <returns></returns>
196196
public static string GetExtension(string path)
197197
{
198-
if (path == null)
198+
if (path is null)
199199
return null;
200+
201+
#if NET8_0_OR_GREATER
202+
// LastIndexOf and LastIndexOfAny is vectorized on .NET8+ and is
203+
// significantly faster for cases where 'path' does not end with a short file
204+
// extension, such as GUIDs
205+
ReadOnlySpan<char> pathSpan = path.AsSpan();
206+
int extensionIndex = pathSpan.LastIndexOf('.');
207+
if (extensionIndex == -1)
208+
{
209+
return string.Empty;
210+
}
211+
212+
int directoryIndex = pathSpan.LastIndexOfAny('/', '\\', ':');
213+
214+
// extension separator is found and exists before path separator or path separator doesn't exist
215+
// AND it's not the last one in the string
216+
if (directoryIndex < extensionIndex && extensionIndex < pathSpan.Length - 1)
217+
{
218+
return pathSpan.Slice(extensionIndex).ToString();
219+
}
220+
221+
return string.Empty;
222+
#else
200223
int length = path.Length;
201224
int index = length;
202225

@@ -213,15 +236,16 @@ public static string GetExtension(string path)
213236
else if (IsPathSeparator(ch))
214237
break;
215238
}
239+
216240
return string.Empty;
217-
}
218241

219-
// Checks if the character is one \ / :
220-
private static bool IsPathSeparator(char ch)
221-
{
222-
return (ch == '\\' ||
223-
ch == '/' ||
224-
ch == ':');
242+
bool IsPathSeparator(char ch)
243+
{
244+
return (ch == '\\' ||
245+
ch == '/' ||
246+
ch == ':');
247+
}
248+
#endif
225249
}
226250

227251
/*

sdk/test/NetStandard/UnitTests/Core/AWSSDKUtilsTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,22 @@ public void UrlEncodeWithPath(string input, string expected)
8484

8585
Assert.Equal(expected, encoded);
8686
}
87+
88+
[Theory]
89+
[InlineData(null, null)]
90+
[InlineData("no-delimiters-at-all", "")]
91+
[InlineData("delimiter-end-of-string.", "")]
92+
[InlineData("relative-path/no-file-extension", "")]
93+
[InlineData("relative-path\\no-file-extension", "")]
94+
[InlineData("relative-path:no-file-extension", "")]
95+
[InlineData("simple-file.pdf", ".pdf")]
96+
[InlineData("relative-path/with-file-extension.pdf", ".pdf")]
97+
[InlineData("relative-path.with-dot/with-file-extension.pdf", ".pdf")]
98+
public void GetExtension(string input, string expected)
99+
{
100+
var actual = AWSSDKUtils.GetExtension(input);
101+
102+
Assert.Equal(expected, actual);
103+
}
87104
}
88105
}

sdk/test/UnitTests/Custom/Util/AWSSDKUtilsTests.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@
1212
* express or implied. See the License for the specific language governing
1313
* permissions and limitations under the License.
1414
*/
15+
using Amazon.Util;
1516
using Microsoft.VisualStudio.TestTools.UnitTesting;
1617
using System;
1718
using System.IO;
18-
using Amazon.Util;
1919
using System.Reflection;
20-
using Moq;
21-
using Amazon.Util.Internal;
2220
using System.Text;
2321

2422
namespace AWSSDK.UnitTests
@@ -178,5 +176,24 @@ public void ToHex(string input, bool lowercase, string expectedResult)
178176

179177
Assert.AreEqual(expectedResult, hexString);
180178
}
179+
180+
[TestCategory("UnitTest")]
181+
[TestCategory("Util")]
182+
[DataTestMethod]
183+
[DataRow(null, null)]
184+
[DataRow("no-delimiters-at-all", "")]
185+
[DataRow("delimiter-end-of-string.", "")]
186+
[DataRow("relative-path/no-file-extension", "")]
187+
[DataRow("relative-path\\no-file-extension", "")]
188+
[DataRow("relative-path:no-file-extension", "")]
189+
[DataRow("simple-file.pdf", ".pdf")]
190+
[DataRow("relative-path/with-file-extension.pdf", ".pdf")]
191+
[DataRow("relative-path.with-dot/with-file-extension.pdf", ".pdf")]
192+
public void GetExtension(string input, string expected)
193+
{
194+
var actual = AWSSDKUtils.GetExtension(input);
195+
196+
Assert.AreEqual(expected, actual);
197+
}
181198
}
182199
}

0 commit comments

Comments
 (0)