Skip to content

Commit b8a50b9

Browse files
committed
Reduce cost of getting file contents
1 parent 8ef29cf commit b8a50b9

File tree

2 files changed

+59
-13
lines changed

2 files changed

+59
-13
lines changed

sources/ClangSharp.Interop/Extensions/CXUnsavedFile.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,41 @@ public static CXUnsavedFile Create(string filename, string contents)
4646
};
4747
}
4848

49+
public static CXUnsavedFile Create(string filename, CXTranslationUnit translationUnit, CXFile baseFile, string additionalContents)
50+
{
51+
sbyte* pFilename, pContents;
52+
nuint contentsLength;
53+
54+
if (string.IsNullOrEmpty(filename))
55+
{
56+
pFilename = null;
57+
}
58+
else
59+
{
60+
var maxFilenameLength = Encoding.UTF8.GetMaxByteCount(filename.Length);
61+
pFilename = (sbyte*)NativeMemory.Alloc((uint)maxFilenameLength + 1);
62+
var filenameLength = (uint)Encoding.UTF8.GetBytes(filename, new Span<byte>(pFilename, maxFilenameLength));
63+
pFilename[filenameLength] = 0;
64+
}
65+
66+
var baseFileContents = translationUnit.GetFileContents(baseFile, out _);
67+
var maxContentsLength = baseFileContents.Length + Encoding.UTF8.GetMaxByteCount((additionalContents?.Length).GetValueOrDefault());
68+
69+
pContents = (sbyte*)NativeMemory.Alloc((uint)maxContentsLength + 1);
70+
71+
var contents = new Span<byte>(pContents, maxContentsLength);
72+
baseFileContents.CopyTo(contents);
73+
74+
contentsLength = (uint)(baseFileContents.Length + Encoding.UTF8.GetBytes(additionalContents, contents[baseFileContents.Length..]));
75+
pContents[contentsLength] = 0;
76+
77+
return new CXUnsavedFile() {
78+
Filename = pFilename,
79+
Contents = pContents,
80+
Length = contentsLength
81+
};
82+
}
83+
4984
public void Dispose()
5085
{
5186
if (Filename != null)

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@
1515
using ClangSharp.Interop;
1616
using ClangSharp.XML;
1717
using static ClangSharp.Interop.CX_AttrKind;
18-
using static ClangSharp.Interop.CXBinaryOperatorKind;
1918
using static ClangSharp.Interop.CX_CXXAccessSpecifier;
2019
using static ClangSharp.Interop.CX_StmtClass;
2120
using static ClangSharp.Interop.CX_UnaryExprOrTypeTrait;
22-
using static ClangSharp.Interop.CXUnaryOperatorKind;
21+
using static ClangSharp.Interop.CXBinaryOperatorKind;
2322
using static ClangSharp.Interop.CXCallingConv;
2423
using static ClangSharp.Interop.CXDiagnosticSeverity;
2524
using static ClangSharp.Interop.CXEvalResultKind;
2625
using static ClangSharp.Interop.CXTemplateArgumentKind;
2726
using static ClangSharp.Interop.CXTranslationUnit_Flags;
2827
using static ClangSharp.Interop.CXTypeKind;
28+
using static ClangSharp.Interop.CXUnaryOperatorKind;
2929

3030
namespace ClangSharp;
3131

@@ -61,6 +61,7 @@ public sealed partial class PInvokeGenerator : IDisposable
6161
private readonly Dictionary<string, bool> _topLevelClassIsUnsafe;
6262
private readonly Dictionary<string, HashSet<string>> _topLevelClassUsings;
6363
private readonly Dictionary<string, List<string>> _topLevelClassAttributes;
64+
private readonly Dictionary<CXFile, (nuint Address, nuint Length)> _fileContents;
6465
private readonly HashSet<string> _topLevelClassNames;
6566
private readonly HashSet<string> _usedRemappings;
6667
private readonly string _placeholderMacroType;
@@ -158,6 +159,7 @@ public PInvokeGenerator(PInvokeGeneratorConfiguration config, Func<string, Strea
158159
_topLevelClassIsUnsafe = [];
159160
_topLevelClassNames = [];
160161
_topLevelClassAttributes = [];
162+
_fileContents = [];
161163
_topLevelClassUsings = [];
162164
_usedRemappings = [];
163165
_filePath = "";
@@ -1697,14 +1699,8 @@ public void GenerateBindings(TranslationUnit translationUnit, string filePath, s
16971699
{
16981700
if (_config.GenerateMacroBindings)
16991701
{
1700-
var translationUnitHandle = translationUnit.Handle;
1701-
1702-
var file = translationUnitHandle.GetFile(_filePath);
1703-
var fileContents = translationUnitHandle.GetFileContents(file, out var size);
17041702
var fileContentsBuilder = _fileContentsBuilder;
17051703

1706-
_ = fileContentsBuilder.Append(Encoding.UTF8.GetString(fileContents));
1707-
17081704
foreach (var cursor in translationUnit.TranslationUnitDecl.CursorChildren)
17091705
{
17101706
if (cursor is PreprocessedEntity preprocessedEntity)
@@ -1716,7 +1712,10 @@ public void GenerateBindings(TranslationUnit translationUnit, string filePath, s
17161712
var unsavedFileContents = fileContentsBuilder.ToString();
17171713
_ = fileContentsBuilder.Clear();
17181714

1719-
using var unsavedFile = CXUnsavedFile.Create(_filePath, unsavedFileContents);
1715+
var translationUnitHandle = translationUnit.Handle;
1716+
var file = translationUnitHandle.GetFile(_filePath);
1717+
1718+
using var unsavedFile = CXUnsavedFile.Create(_filePath, translationUnitHandle, file, unsavedFileContents);
17201719
var unsavedFiles = new CXUnsavedFile[] { unsavedFile };
17211720

17221721
translationFlags = _translationFlags & ~CXTranslationUnit_DetailedPreprocessingRecord;
@@ -3418,7 +3417,19 @@ private string GetRemappedTypeName(Cursor? cursor, Cursor? context, Type type, o
34183417
return remappedName;
34193418
}
34203419

3421-
private static string GetSourceRangeContents(CXTranslationUnit translationUnit, CXSourceRange sourceRange)
3420+
private unsafe ReadOnlySpan<byte> GetFileContents(CXTranslationUnit translationUnit, CXFile file)
3421+
{
3422+
if (!_fileContents.TryGetValue(file, out var fileContentsMetadata))
3423+
{
3424+
var fileContents = translationUnit.GetFileContents(file, out _);
3425+
fileContentsMetadata = ((nuint)Unsafe.AsPointer(ref MemoryMarshal.GetReference(fileContents)), (uint)fileContents.Length);
3426+
_fileContents.Add(file, fileContentsMetadata);
3427+
}
3428+
3429+
return new ReadOnlySpan<byte>((byte*)fileContentsMetadata.Address, (int)fileContentsMetadata.Length);
3430+
}
3431+
3432+
private string GetSourceRangeContents(CXTranslationUnit translationUnit, CXSourceRange sourceRange)
34223433
{
34233434
sourceRange.Start.GetFileLocation(out var startFile, out _, out _, out var startOffset);
34243435
sourceRange.End.GetFileLocation(out var endFile, out _, out _, out var endOffset);
@@ -3428,9 +3439,9 @@ private static string GetSourceRangeContents(CXTranslationUnit translationUnit,
34283439
return string.Empty;
34293440
}
34303441

3431-
var fileContents = translationUnit.GetFileContents(startFile, out _);
3432-
fileContents = fileContents.Slice(unchecked((int)startOffset), unchecked((int)(endOffset - startOffset)));
3433-
return Encoding.UTF8.GetString(fileContents);
3442+
var contents = GetFileContents(translationUnit, startFile);
3443+
contents = contents.Slice(unchecked((int)startOffset), unchecked((int)(endOffset - startOffset)));
3444+
return Encoding.UTF8.GetString(contents);
34343445
}
34353446

34363447
private string GetTargetTypeName(Cursor cursor, out string nativeTypeName)

0 commit comments

Comments
 (0)