Skip to content

Commit c5f0b65

Browse files
perf: optimise IgnoreFile using ValueTask and Span.Replace
1 parent 8363c47 commit c5f0b65

File tree

2 files changed

+55
-26
lines changed

2 files changed

+55
-26
lines changed

Src/CSharpier.Cli/IgnoreFile.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Concurrent;
12
using System.Diagnostics;
23
using System.IO.Abstractions;
34
using System.Text.RegularExpressions;
@@ -31,7 +32,15 @@ private IgnoreFile(List<IgnoreWithBasePath> ignores)
3132

3233
public bool IsIgnored(string filePath)
3334
{
34-
filePath = filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
35+
Span<char> pathRelativeToIgnoreFile =
36+
filePath.Length <= 256 ? stackalloc char[256] : new char[filePath.Length];
37+
38+
pathRelativeToIgnoreFile = pathRelativeToIgnoreFile[..filePath.Length];
39+
filePath.CopyTo(pathRelativeToIgnoreFile);
40+
pathRelativeToIgnoreFile.Replace(
41+
Path.AltDirectorySeparatorChar,
42+
Path.DirectorySeparatorChar
43+
);
3544

3645
foreach (var ignore in this.Ignores)
3746
{
@@ -185,10 +194,19 @@ private class IgnoreWithBasePath(string basePath)
185194
return (false, false);
186195
}
187196

188-
var pathRelativeToIgnoreFile =
189-
path.Length > basePath.Length
190-
? path[basePath.Length..].Replace('\\', '/')
191-
: string.Empty;
197+
var relativePathLength = path.Length - basePath.Length;
198+
Span<char> pathRelativeToIgnoreFile =
199+
relativePathLength <= 256 ? stackalloc char[256] : new char[path.Length];
200+
if (path.Length > basePath.Length)
201+
{
202+
path.AsSpan()[basePath.Length..].CopyTo(pathRelativeToIgnoreFile);
203+
pathRelativeToIgnoreFile = pathRelativeToIgnoreFile[..relativePathLength];
204+
pathRelativeToIgnoreFile.Replace('\\', '/');
205+
}
206+
else
207+
{
208+
pathRelativeToIgnoreFile = [];
209+
}
192210

193211
var isIgnored = false;
194212
var hasMatchingRule = false;

Src/CSharpier.Cli/Options/OptionsProvider.cs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ ILogger logger
3434
this.logger = logger;
3535
}
3636

37-
public static async Task<OptionsProvider> Create(
37+
public static async ValueTask<OptionsProvider> Create(
3838
string directoryName,
3939
string? configPath,
4040
string? ignorePath,
@@ -109,7 +109,7 @@ await EditorConfigLocator.FindForDirectoryNameAsync(
109109
return optionsProvider;
110110
}
111111

112-
public async Task<PrinterOptions?> GetPrinterOptionsForAsync(
112+
public async ValueTask<PrinterOptions?> GetPrinterOptionsForAsync(
113113
string filePath,
114114
CancellationToken cancellationToken
115115
)
@@ -147,64 +147,73 @@ CancellationToken cancellationToken
147147
return formatter != Formatter.Unknown ? new PrinterOptions(formatter) : null;
148148
}
149149

150-
private Task<CSharpierConfigData?> FindCSharpierConfigAsync(string directoryName)
150+
private ValueTask<CSharpierConfigData?> FindCSharpierConfigAsync(string directoryName)
151151
{
152152
return this.FindFileAsync(
153153
directoryName,
154154
this.csharpierConfigsByDirectory,
155-
searchingDirectory =>
156-
this.fileSystem.Directory.EnumerateFiles(
155+
(searchingDirectory, cancellationToken) =>
156+
this
157+
.fileSystem.Directory.EnumerateFiles(
157158
searchingDirectory,
158159
".csharpierrc*",
159160
SearchOption.TopDirectoryOnly
160161
)
161162
.Any(),
162-
searchingDirectory =>
163+
(searchingDirectory, cancellationToken) =>
163164
Task.FromResult(
164165
CSharpierConfigParser.FindForDirectoryName(
165166
searchingDirectory,
166167
this.fileSystem,
167168
this.logger
168169
)
169-
)
170+
),
171+
CancellationToken.None
170172
);
171173
}
172174

173-
private async Task<EditorConfigSections?> FindEditorConfigAsync(
175+
private async ValueTask<EditorConfigSections?> FindEditorConfigAsync(
174176
string directoryName,
175177
CancellationToken cancellationToken
176178
)
177179
{
178180
return await this.FindFileAsync(
179181
directoryName,
180182
this.editorConfigByDirectory,
181-
searchingDirectory =>
183+
(searchingDirectory, cancellationToken) =>
182184
this.fileSystem.File.Exists(Path.Combine(searchingDirectory, ".editorconfig")),
183-
async searchingDirectory =>
185+
async (searchingDirectory, cancellationToken) =>
184186
await EditorConfigLocator.FindForDirectoryNameAsync(
185187
searchingDirectory,
186188
this.fileSystem,
187189
await this.FindIgnoreFileAsync(searchingDirectory, cancellationToken),
188190
cancellationToken
189-
)
191+
),
192+
cancellationToken
190193
);
191194
}
192195

193-
private async Task<IgnoreFile> FindIgnoreFileAsync(
196+
private async ValueTask<IgnoreFile> FindIgnoreFileAsync(
194197
string directoryName,
195198
CancellationToken cancellationToken
196199
)
197200
{
198201
var ignoreFile = await this.FindFileAsync(
199202
directoryName,
200203
this.ignoreFilesByDirectory,
201-
(searchingDirectory) =>
204+
(searchingDirectory, cancellationToken) =>
202205
this.fileSystem.File.Exists(Path.Combine(searchingDirectory, ".gitignore"))
203206
|| this.fileSystem.File.Exists(
204207
Path.Combine(searchingDirectory, ".csharpierignore")
205208
),
206-
(searchingDirectory) =>
207-
IgnoreFile.CreateAsync(searchingDirectory, this.fileSystem, null, cancellationToken)
209+
(searchingDirectory, cancellationToken) =>
210+
IgnoreFile.CreateAsync(
211+
searchingDirectory,
212+
this.fileSystem,
213+
null,
214+
cancellationToken
215+
),
216+
cancellationToken
208217
);
209218

210219
#pragma warning disable IDE0270
@@ -223,11 +232,12 @@ CancellationToken cancellationToken
223232
/// When trying to format a file in a given subdirectory if we've already found the appropriate file type then return it
224233
/// otherwise track it down (parsing if we need to) and set the references for any parent directories
225234
/// </summary>
226-
private async Task<T?> FindFileAsync<T>(
235+
private async ValueTask<T?> FindFileAsync<T>(
227236
string directoryName,
228237
ConcurrentDictionary<string, T?> dictionary,
229-
Func<string, bool> shouldConsiderDirectory,
230-
Func<string, Task<T?>> createFileAsync
238+
Func<string, CancellationToken, bool> shouldConsiderDirectory,
239+
Func<string, CancellationToken, Task<T?>> createFileAsync,
240+
CancellationToken cancellationToken
231241
)
232242
{
233243
if (dictionary.TryGetValue(directoryName, out var result))
@@ -242,10 +252,11 @@ searchingDirectory is not null
242252
&& !dictionary.TryGetValue(searchingDirectory.FullName, out result)
243253
)
244254
{
245-
if (shouldConsiderDirectory(searchingDirectory.FullName))
255+
if (shouldConsiderDirectory(searchingDirectory.FullName, cancellationToken))
246256
{
247257
dictionary[searchingDirectory.FullName] = result = await createFileAsync(
248-
searchingDirectory.FullName
258+
searchingDirectory.FullName,
259+
cancellationToken
249260
);
250261
break;
251262
}
@@ -262,7 +273,7 @@ searchingDirectory is not null
262273
return result;
263274
}
264275

265-
public async Task<bool> IsIgnoredAsync(
276+
public async ValueTask<bool> IsIgnoredAsync(
266277
string actualFilePath,
267278
CancellationToken cancellationToken
268279
)

0 commit comments

Comments
 (0)