Skip to content

Reduce allocations and improve throughput #619

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ dotnet_style_qualification_for_method = false:error
dotnet_style_qualification_for_property = false:error

dotnet_style_readonly_field = true:error
dotnet_style_require_accessibility_modifiers = always:error
dotnet_style_require_accessibility_modifiers = for_non_interface_members:error

###############################################################################
# Set dotnet style options to:
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.100",
"version": "10.0.100-preview",
"allowPrerelease": true,
"rollForward": "latestFeature"
}
Expand Down
2 changes: 1 addition & 1 deletion scripts/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ try {
$DotNetInstallDirectory = Join-Path -Path $ArtifactsDir -ChildPath "dotnet"
Create-Directory -Path $DotNetInstallDirectory

& $DotNetInstallScript -Channel 8.0 -Version latest -InstallDir $DotNetInstallDirectory -Architecture $architecture
& $DotNetInstallScript -Channel 10.0 -Version latest -InstallDir $DotNetInstallDirectory -Architecture $architecture

$env:PATH="$DotNetInstallDirectory;$env:PATH"
}
Expand Down
2 changes: 1 addition & 1 deletion scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ if [[ ! -z "$architecture" ]]; then
DotNetInstallDirectory="$ArtifactsDir/dotnet"
CreateDirectory "$DotNetInstallDirectory"

. "$DotNetInstallScript" --channel 8.0 --version latest --install-dir "$DotNetInstallDirectory" --architecture "$architecture"
. "$DotNetInstallScript" --channel 10.0 --version latest --install-dir "$DotNetInstallDirectory" --architecture "$architecture"

PATH="$DotNetInstallDirectory:$PATH:"
fi
Expand Down
2 changes: 1 addition & 1 deletion sources/ClangSharp.Interop/ClangSharp.Interop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net10.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
14 changes: 7 additions & 7 deletions sources/ClangSharp.Interop/Extensions/CXCursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public readonly string AttrKindSpelling
Debug.Assert(CX_AttrKind_FirstTypeAttr == CX_AttrKind_AddressSpace);
Debug.Assert(CX_AttrKind_LastTypeAttr == CX_AttrKind_WebAssemblyFuncref);

Debug.Assert(CX_AttrKind_FirstStmtAttr == CX_AttrKind_CodeAlign);
Debug.Assert(CX_AttrKind_FirstStmtAttr == CX_AttrKind_CXXAssume);
Debug.Assert(CX_AttrKind_LastStmtAttr == CX_AttrKind_Unlikely);

Debug.Assert(CX_AttrKind_FirstDeclOrStmtAttr == CX_AttrKind_AlwaysInline);
Expand All @@ -49,14 +49,14 @@ public readonly string AttrKindSpelling
Debug.Assert(CX_AttrKind_FirstDeclOrTypeAttr == CX_AttrKind_AArch64SVEPcs);
Debug.Assert(CX_AttrKind_LastDeclOrTypeAttr == CX_AttrKind_VectorCall);

Debug.Assert(CX_AttrKind_FirstInheritableParamAttr == CX_AttrKind_SwiftAsyncContext);
Debug.Assert(CX_AttrKind_FirstInheritableParamAttr == CX_AttrKind_Annotate);
Debug.Assert(CX_AttrKind_LastInheritableParamAttr == CX_AttrKind_UseHandle);

Debug.Assert(CX_AttrKind_FirstParameterABIAttr == CX_AttrKind_SwiftAsyncContext);
Debug.Assert(CX_AttrKind_FirstParameterABIAttr == CX_AttrKind_HLSLParamModifier);
Debug.Assert(CX_AttrKind_LastParameterABIAttr == CX_AttrKind_SwiftIndirectResult);

Debug.Assert(CX_AttrKind_FirstHLSLAnnotationAttr == CX_AttrKind_HLSLSV_DispatchThreadID);
Debug.Assert(CX_AttrKind_LastHLSLAnnotationAttr == CX_AttrKind_HLSLSV_GroupIndex);
Debug.Assert(CX_AttrKind_FirstHLSLAnnotationAttr == CX_AttrKind_HLSLPackOffset);
Debug.Assert(CX_AttrKind_LastHLSLAnnotationAttr == CX_AttrKind_HLSLSV_GroupThreadID);

return AttrKind switch {
CX_AttrKind_Invalid => "Invalid",
Expand Down Expand Up @@ -1353,7 +1353,7 @@ public readonly string StmtClassSpelling
Debug.Assert(CX_StmtClass_LastSwitchCase == CX_StmtClass_CaseStmt);

Debug.Assert(CX_StmtClass_FirstOMPLoopTransformationDirective == CX_StmtClass_OMPUnrollDirective);
Debug.Assert(CX_StmtClass_LastOMPLoopTransformationDirective == CX_StmtClass_OMPTileDirective);
Debug.Assert(CX_StmtClass_LastOMPLoopTransformationDirective == CX_StmtClass_OMPInterchangeDirective);

Debug.Assert(CX_StmtClass_FirstOMPLoopDirective == CX_StmtClass_OMPTeamsGenericLoopDirective);
Debug.Assert(CX_StmtClass_LastOMPLoopDirective == CX_StmtClass_OMPDistributeDirective);
Expand All @@ -1362,7 +1362,7 @@ public readonly string StmtClassSpelling
Debug.Assert(CX_StmtClass_LastOMPLoopBasedDirective == CX_StmtClass_OMPDistributeDirective);

Debug.Assert(CX_StmtClass_FirstOMPExecutableDirective == CX_StmtClass_OMPTeamsDirective);
Debug.Assert(CX_StmtClass_LastOMPExecutableDirective == CX_StmtClass_OMPAtomicDirective);
Debug.Assert(CX_StmtClass_LastOMPExecutableDirective == CX_StmtClass_OMPAssumeDirective);

Debug.Assert(CX_StmtClass_FirstAsmStmt == CX_StmtClass_MSAsmStmt);
Debug.Assert(CX_StmtClass_LastAsmStmt == CX_StmtClass_GCCAsmStmt);
Expand Down
35 changes: 35 additions & 0 deletions sources/ClangSharp.Interop/Extensions/CXUnsavedFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,41 @@ public static CXUnsavedFile Create(string filename, string contents)
};
}

public static CXUnsavedFile Create(string filename, CXTranslationUnit translationUnit, CXFile baseFile, string additionalContents)
{
sbyte* pFilename, pContents;
nuint contentsLength;

if (string.IsNullOrEmpty(filename))
{
pFilename = null;
}
else
{
var maxFilenameLength = Encoding.UTF8.GetMaxByteCount(filename.Length);
pFilename = (sbyte*)NativeMemory.Alloc((uint)maxFilenameLength + 1);
var filenameLength = (uint)Encoding.UTF8.GetBytes(filename, new Span<byte>(pFilename, maxFilenameLength));
pFilename[filenameLength] = 0;
}

var baseFileContents = translationUnit.GetFileContents(baseFile, out _);
var maxContentsLength = baseFileContents.Length + Encoding.UTF8.GetMaxByteCount((additionalContents?.Length).GetValueOrDefault());

pContents = (sbyte*)NativeMemory.Alloc((uint)maxContentsLength + 1);

var contents = new Span<byte>(pContents, maxContentsLength);
baseFileContents.CopyTo(contents);

contentsLength = (uint)(baseFileContents.Length + Encoding.UTF8.GetBytes(additionalContents, contents[baseFileContents.Length..]));
pContents[contentsLength] = 0;

return new CXUnsavedFile() {
Filename = pFilename,
Contents = pContents,
Length = contentsLength
};
}

public void Dispose()
{
if (Filename != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ internal sealed partial class CSharpOutputBuilder(string name, PInvokeGenerator
private readonly PInvokeGenerator _generator = generator;
private readonly List<string> _contents = [];
private readonly StringBuilder _currentLine = new StringBuilder();
private readonly SortedSet<string> _usingDirectives = [];
private readonly SortedSet<string> _staticUsingDirectives = [];
private readonly SortedSet<string> _usingDirectives = new SortedSet<string>(StringComparer.Ordinal);
private readonly SortedSet<string> _staticUsingDirectives = new SortedSet<string>(StringComparer.Ordinal);
private readonly string _indentationString = indentationString;
private readonly bool _isTestOutput = isTestOutput;

Expand Down Expand Up @@ -80,6 +80,8 @@ public void WriteBlockEnd()

public void Write<T>(T value) => _ = _currentLine.Append(value);

public void Write(ReadOnlySpan<char> value) => _ = _currentLine.Append(value);

public void WriteIndentation()
{
WriteNewlineIfNeeded();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<PropertyGroup>
<RootNamespace>ClangSharp</RootNamespace>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net10.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace ClangSharp;
internal sealed class OutputBuilderFactory(PInvokeGenerator generator)
{
private readonly bool _writeSourceLocation = generator.Config.GenerateSourceLocationAttribute;
private readonly Dictionary<string, IOutputBuilder> _outputBuilders = [];
private readonly Dictionary<string, IOutputBuilder> _outputBuilders = new Dictionary<string, IOutputBuilder>(StringComparer.Ordinal);

public IEnumerable<IOutputBuilder> OutputBuilders => _outputBuilders.Values;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ private void VisitFunctionDecl(FunctionDecl functionDecl)
}
},
CustomAttrGeneratorData = (functionDecl, _outputBuilder, this),
ParameterTypes = overloadCount > 1 ? functionDecl.Parameters.Select(param => GetTargetTypeName(param, out var _)).ToArray() : null,
ParameterTypes = overloadCount > 1 ? [.. functionDecl.Parameters.Select(param => GetTargetTypeName(param, out var _))] : null,
};
Debug.Assert(_outputBuilder is not null);

Expand Down Expand Up @@ -1116,7 +1116,7 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl)

if (arraySize == 1)
{
if (TryGetRemappedValue(indirectFieldDecl, _config.WithLengths, out var length))
if (TryGetRemappedValue(indirectFieldDecl, _config._withLengths, out var length))
{
code.Write(length);
}
Expand Down Expand Up @@ -1510,7 +1510,7 @@ private void VisitRecordDecl(RecordDecl recordDecl)
baseTypeNames = [.. baseTypeNamesBuilder];
}

if (!TryGetRemappedValue(recordDecl, _config.WithPackings, out var pack))
if (!TryGetRemappedValue(recordDecl, _config._withPackings, out var pack))
{
pack = alignment < maxAlignm ? alignment.ToString(CultureInfo.InvariantCulture) : null;
}
Expand Down Expand Up @@ -1558,7 +1558,7 @@ private void VisitRecordDecl(RecordDecl recordDecl)

if (!_topLevelClassUsings.TryGetValue(name, out var withUsings))
{
withUsings = [];
withUsings = new HashSet<string>(StringComparer.Ordinal);
}

if (desc.LayoutAttribute is not null)
Expand Down Expand Up @@ -3311,7 +3311,7 @@ void ForUnderlyingType(TypedefDecl typedefDecl, Type underlyingType, bool onlyHa
{
if (!_allValidNameRemappings.TryGetValue(underlyingName, out var allRemappings))
{
allRemappings = [];
allRemappings = new HashSet<string>(QualifiedNameComparer.Default);
_allValidNameRemappings[underlyingName] = allRemappings;
}
_ = allRemappings.Add(typedefName);
Expand All @@ -3321,7 +3321,7 @@ void ForUnderlyingType(TypedefDecl typedefDecl, Type underlyingType, bool onlyHa
{
if (!_traversedValidNameRemappings.TryGetValue(underlyingName, out var traversedRemappings))
{
traversedRemappings = [];
traversedRemappings = new HashSet<string>(QualifiedNameComparer.Default);
_traversedValidNameRemappings[underlyingName] = traversedRemappings;
}
_ = traversedRemappings.Add(typedefName);
Expand Down
47 changes: 28 additions & 19 deletions sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ private void VisitCXXOperatorCallExpr(CXXOperatorCallExpr cxxOperatorCallExpr)
{
Visit(args[0]);
outputBuilder.Write(' ');
outputBuilder.Write(functionDeclName[8..]);
outputBuilder.Write(functionDeclName.AsSpan()[8..]);
outputBuilder.Write(' ');
Visit(args[1]);
StopCSharpCode();
Expand All @@ -813,7 +813,7 @@ private void VisitCXXOperatorCallExpr(CXXOperatorCallExpr cxxOperatorCallExpr)

case "operator~":
{
outputBuilder.Write(functionDeclName[8..]);
outputBuilder.Write(functionDeclName.AsSpan()[8..]);
Visit(args[0]);
StopCSharpCode();
return;
Expand Down Expand Up @@ -1161,7 +1161,7 @@ private void VisitFloatingLiteral(FloatingLiteral floatingLiteral)
var outputBuilder = StartCSharpCode();
if (floatingLiteral.ValueString.EndsWith(".f", StringComparison.Ordinal))
{
outputBuilder.Write(floatingLiteral.ValueString[0..^1]);
outputBuilder.Write(floatingLiteral.ValueString.AsSpan()[..^1]);
outputBuilder.Write("0f");
}
else
Expand Down Expand Up @@ -1954,67 +1954,76 @@ void HandleUnmanagedConstant(CSharpOutputBuilder outputBuilder, InitListExpr ini

private void VisitIntegerLiteral(IntegerLiteral integerLiteral)
{
var valueString = integerLiteral.ValueString;
var valueString = integerLiteral.ValueString.AsSpan();
var valueSuffix = "";

if (valueString.EndsWith("ui8", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^3];
valueString = valueString[..^3];
}
else if (valueString.EndsWith("i8", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^2];
valueString = valueString[..^2];
}
else if (valueString.EndsWith("ui16", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^4];
valueString = valueString[..^4];
}
else if (valueString.EndsWith("i16", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^3];
valueString = valueString[..^3];
}
else if (valueString.EndsWith("ui32", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^4] + "U";
valueString = valueString[..^4];
valueSuffix = "U";
}
else if (valueString.EndsWith("i32", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^3];
valueString = valueString[..^3];
}
else if (valueString.EndsWith("ui64", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^4] + "UL";
valueString = valueString[..^4];
valueSuffix = "UL";
}
else if (valueString.EndsWith("i64", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^3] + "L";
valueString = valueString[..^3];
valueSuffix = "L";
}
else if (
valueString.EndsWith("ull", StringComparison.OrdinalIgnoreCase) ||
valueString.EndsWith("llu", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^3] + "UL";
valueString = valueString[..^3];
valueSuffix = "UL";
}
else if (valueString.EndsWith("ll", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^2] + "L";
valueString = valueString[..^2];
valueSuffix = "L";
}
else if (
valueString.EndsWith("ul", StringComparison.OrdinalIgnoreCase) ||
valueString.EndsWith("lu", StringComparison.OrdinalIgnoreCase))
{
valueString = valueString[0..^2] + "U";
valueString = valueString[..^2];
valueSuffix = "U";
}
else if (valueString.EndsWith('u') || valueString.EndsWith('U'))
{
valueString = valueString[0..^1] + "U";
valueString = valueString[..^1];
valueSuffix = "U";
}
else if (valueString.EndsWith('l') || valueString.EndsWith('L'))
{
valueString = valueString[0..^1];
valueString = valueString[..^1];
}

var outputBuilder = StartCSharpCode();
outputBuilder.Write(valueString);
outputBuilder.Write(valueSuffix);
StopCSharpCode();
}

Expand Down Expand Up @@ -2997,12 +3006,12 @@ private void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr unaryExprOrT
{
if ((parentType.Handle.SizeOf == 8) && IsPrevContextDecl<VarDecl>(out var varDecl, out _))
{
var cursorName = GetCursorName(varDecl);
var cursorName = GetCursorName(varDecl).AsSpan();

if (cursorName.StartsWith("ClangSharpMacro_", StringComparison.Ordinal))
{
cursorName = cursorName["ClangSharpMacro_".Length..];
parentTypeIsVariableSized |= _config.WithTypes.TryGetValue(cursorName, out var remappedTypeName) && (remappedTypeName.Equals("int", StringComparison.Ordinal) || remappedTypeName.Equals("uint", StringComparison.Ordinal));
parentTypeIsVariableSized |= _config._withTypes.GetAlternateLookup<ReadOnlySpan<char>>().TryGetValue(cursorName, out var remappedTypeName) && (remappedTypeName.Equals("int", StringComparison.Ordinal) || remappedTypeName.Equals("uint", StringComparison.Ordinal));
}
}

Expand Down
Loading
Loading