Skip to content

Commit

Permalink
Merge pull request #272 from tannergooding/improvements
Browse files Browse the repository at this point in the history
Updating Cursor and Type to avoid repeated hot path allocations
  • Loading branch information
tannergooding authored Sep 29, 2021
2 parents 1fe801a + 8faf434 commit 20d281c
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 21 deletions.
72 changes: 54 additions & 18 deletions sources/ClangSharp/Cursors/Cursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ClangSharp.Interop;

namespace ClangSharp
{
[DebuggerDisplay("{Handle.DebuggerDisplayString,nq}")]
public unsafe class Cursor : IEquatable<Cursor>
{
private readonly Lazy<IReadOnlyList<Cursor>> _cursorChildren;
private readonly Lazy<string> _kindSpelling;
private readonly Lazy<Cursor> _lexicalParentCursor;
private readonly Lazy<Cursor> _semanticParentCursor;
private readonly Lazy<string> _spelling;
private readonly Lazy<TranslationUnit> _translationUnit;
private List<Cursor> _cursorChildren;

private protected Cursor(CXCursor handle, CXCursorKind expectedCursorKind)
{
Expand All @@ -23,28 +27,60 @@ private protected Cursor(CXCursor handle, CXCursorKind expectedCursorKind)
}
Handle = handle;

_cursorChildren = new Lazy<IReadOnlyList<Cursor>>(() => {
var cursors = new List<Cursor>();

_ = Handle.VisitChildren((cursor, parent, clientData) => {
var cursorChild = TranslationUnit.GetOrCreate<Cursor>(cursor);
cursors.Add(cursorChild);
return CXChildVisitResult.CXChildVisit_Continue;
}, clientData: default);

return cursors;
});

_kindSpelling = new Lazy<string>(() => Handle.KindSpelling.ToString());
_lexicalParentCursor = new Lazy<Cursor>(() => TranslationUnit.GetOrCreate<Cursor>(Handle.LexicalParent));
_semanticParentCursor = new Lazy<Cursor>(() => TranslationUnit.GetOrCreate<Cursor>(Handle.SemanticParent));
_spelling = new Lazy<string>(() => Handle.Spelling.ToString());
_translationUnit = new Lazy<TranslationUnit>(() => TranslationUnit.GetOrCreate(Handle.TranslationUnit));
}

public IReadOnlyList<Cursor> CursorChildren => _cursorChildren.Value;
public IReadOnlyList<Cursor> CursorChildren
{
get
{
if (_cursorChildren is null)
{
var cursorChildren = GCHandle.Alloc(new List<Cursor>());

#if !NET5_0_OR_GREATER
var visitor = (CXCursorVisitor)Visitor;
var pVisitor = Marshal.GetFunctionPointerForDelegate(visitor);
#else
var pVisitor = (delegate* unmanaged[Cdecl]<CXCursor, CXCursor, nint*, CXChildVisitResult>)&Visitor;
#endif

var client_data = stackalloc nint[2] {
GCHandle.ToIntPtr(cursorChildren),
TranslationUnit.Handle.Handle
};

_ = clang.visitChildren(Handle, (IntPtr)pVisitor, client_data);

_cursorChildren = (List<Cursor>)cursorChildren.Target;
cursorChildren.Free();

#if !NET5_0_OR_GREATER
GC.KeepAlive(visitor);
#else
[UnmanagedCallersOnly(CallConvs = new System.Type[] { typeof(CallConvCdecl) })]
#endif
static CXChildVisitResult Visitor(CXCursor cursor, CXCursor parent, void* client_data)
{
var cursorChildren = (List<Cursor>)GCHandle.FromIntPtr(((nint*)client_data)[0]).Target;
var translationUnit = TranslationUnit.GetOrCreate((CXTranslationUnitImpl*)((nint*)client_data)[1]);

var cursorChild = translationUnit.GetOrCreate<Cursor>(cursor);
cursorChildren.Add(cursorChild);
return CXChildVisitResult.CXChildVisit_Continue;
}
}
return _cursorChildren;
}
}

public CXCursorKind CursorKind => Handle.Kind;
public CXCursorKind CursorKind => Handle.kind;

public string CursorKindSpelling => Handle.KindSpelling.ToString();
public string CursorKindSpelling => _kindSpelling.Value;

public CXSourceRange Extent => Handle.Extent;

Expand All @@ -56,7 +92,7 @@ private protected Cursor(CXCursor handle, CXCursorKind expectedCursorKind)

public Cursor SemanticParentCursor => _semanticParentCursor.Value;

public string Spelling => Handle.Spelling.ToString();
public string Spelling => _spelling.Value;

public TranslationUnit TranslationUnit => _translationUnit.Value;

Expand Down Expand Up @@ -103,6 +139,6 @@ internal static Cursor Create(CXCursor handle)

public override int GetHashCode() => Handle.GetHashCode();

public override string ToString() => Handle.ToString();
public override string ToString() => Spelling;
}
}
10 changes: 7 additions & 3 deletions sources/ClangSharp/Types/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ namespace ClangSharp
[DebuggerDisplay("{Handle.DebuggerDisplayString,nq}")]
public unsafe class Type : IEquatable<Type>
{
private readonly Lazy<string> _asString;
private readonly Lazy<Type> _canonicalType;
private readonly Lazy<Type> _desugar;
private readonly Lazy<string> _kindSpelling;
private readonly Lazy<Type> _pointeeType;
private readonly Lazy<TranslationUnit> _translationUnit;

Expand All @@ -27,15 +29,17 @@ protected Type(CXType handle, CXTypeKind expectedKind, CX_TypeClass expectedType
}
Handle = handle;

_asString = new Lazy<string>(() => Handle.Spelling.ToString());
_canonicalType = new Lazy<Type>(() => TranslationUnit.GetOrCreate<Type>(Handle.CanonicalType));
_desugar = new Lazy<Type>(() => TranslationUnit.GetOrCreate<Type>(Handle.Desugar));
_kindSpelling = new Lazy<string>(() => Handle.KindSpelling.ToString());
_pointeeType = new Lazy<Type>(() => TranslationUnit.GetOrCreate<Type>(Handle.PointeeType));
_translationUnit = new Lazy<TranslationUnit>(() => TranslationUnit.GetOrCreate((CXTranslationUnit)Handle.data[1]));
}

public CXXRecordDecl AsCXXRecordDecl => AsTagDecl as CXXRecordDecl;

public string AsString => Handle.Spelling.ToString();
public string AsString => _asString.Value;

public TagDecl AsTagDecl
{
Expand Down Expand Up @@ -79,7 +83,7 @@ public bool IsIntegralOrEnumerationType

public CXTypeKind Kind => Handle.kind;

public string KindSpelling => Handle.KindSpelling.ToString();
public string KindSpelling => _kindSpelling.Value;

public Type PointeeType => _pointeeType.Value;

Expand Down Expand Up @@ -191,6 +195,6 @@ public T GetAs<T>()

public override int GetHashCode() => Handle.GetHashCode();

public override string ToString() => Handle.ToString();
public override string ToString() => AsString;
}
}

0 comments on commit 20d281c

Please sign in to comment.