Skip to content

Commit f28fdd0

Browse files
authored
Merge pull request #553 from Sergio0694/dev/drop-d2d1-regex
Remove Regex.Replace call in D3DCompiler
2 parents 68d6793 + 1a6a129 commit f28fdd0

File tree

1 file changed

+35
-6
lines changed

1 file changed

+35
-6
lines changed

src/ComputeSharp.D2D1/Shaders/Translation/D3DCompiler.cs

+35-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Runtime.CompilerServices;
55
using System.Runtime.InteropServices;
66
using System.Text;
7-
using System.Text.RegularExpressions;
87
using ComputeSharp.D2D1.Exceptions;
98
using ComputeSharp.D2D1.Extensions;
109
using TerraFX.Interop.DirectX;
@@ -191,16 +190,46 @@ private static void ThrowHslsCompilationException(ID3DBlob* d3DOperationResult)
191190
// The error message will be in a format like this:
192191
// "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\Roslyn\Shader@0x0000019AD1B4BA70(22,32-35): error X3004: undeclared identifier 'this'"
193192
// This regex tries to match the unnecessary header and remove it, if present. This doesn't need to be bulletproof, and this regex should match all cases anyway.
194-
message = Regex.Replace(message, @"^[A-Z]:\\[^:]+: (\w+ \w+:)", static m => m.Groups[1].Value, RegexOptions.Multiline).Trim();
193+
//
194+
// We cannot use Regex (this method was originally using Regex.Replace(message, @"^[A-Z]:\\[^:]+: (\w+ \w+:)", ...)), because that
195+
// causes significant binary size increase, as it's the only thing rooting all the Regex stack across the whole library. So this
196+
// code reimplements equivalent logic in a simple way. Because this is a throw helper, allocating a little bit of garbage is fine.
197+
string[] lines = message.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
198+
199+
// Go over each (non empty) line and look for the leading file path to trim away
200+
foreach (ref string line in lines.AsSpan())
201+
{
202+
ReadOnlySpan<char> span = line.AsSpan().Trim();
203+
204+
// Check whether the trimmed line starts with a drive letter path (eg. 'C:\') and get the rest
205+
if (span is [>= 'A' and <= 'Z', ':', '\\', .. { Length: > 0 } tail])
206+
{
207+
int indexOfColon = tail.IndexOf(':');
208+
209+
// We're looking for the color at the end of the file path. If we find it, and the line
210+
// has at least another character (ie. there's content after that, which should always
211+
// be the case), then we take that slice, trim its start to skip the leading whitespace,
212+
// and finally allocate a string to replace the current line.
213+
if (indexOfColon != -1 &&
214+
tail.Length > indexOfColon)
215+
{
216+
ReadOnlySpan<char> trimmedLine = tail.Slice(indexOfColon + 1).TrimStart();
217+
218+
line = trimmedLine.ToString();
219+
}
220+
}
221+
}
222+
223+
// Merge the message again with normalized newlines
224+
string updatedMessage = string.Join("\r\n", lines);
195225

196226
// Add a trailing '.' if not present
197-
if (message is { Length: > 0 } &&
198-
message[message.Length - 1] != '.')
227+
if (updatedMessage is not [.., '.'])
199228
{
200-
message += '.';
229+
updatedMessage += '.';
201230
}
202231

203-
throw new FxcCompilationException(message);
232+
throw new FxcCompilationException(updatedMessage);
204233
}
205234

206235
/// <summary>

0 commit comments

Comments
 (0)