Skip to content

Commit

Permalink
refactor: Refactor types
Browse files Browse the repository at this point in the history
  • Loading branch information
Pd233 committed May 8, 2024
1 parent 8e699e5 commit 4dced29
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 165 deletions.
9 changes: 0 additions & 9 deletions src/Generation/ITypeReferenceProvider.cs

This file was deleted.

5 changes: 3 additions & 2 deletions src/Generation/PredefinedTypeAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Hosihikari.NativeInterop.Generation;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)]
public sealed class PredefinedTypeAttribute : Attribute
{
public string? NativeTypeName { get; set; }
public string? NativeTypeNamespace { get; set; }
public string TypeName { get; set; } = string.Empty;

public bool IgnoreTemplateArgs { get; set; } = false;
}
150 changes: 61 additions & 89 deletions src/Unmanaged/CppTypeSystem.cs
Original file line number Diff line number Diff line change
@@ -1,55 +1,54 @@
using Hosihikari.NativeInterop.Unmanaged.Attributes;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Hosihikari.NativeInterop.Unmanaged;

public static class CppTypeSystem
{
public static unsafe void* GetVTable(void* ptr)
public static unsafe void* GetVTable(void* ptr, int offset = 0)
{
return *(void**)ptr;
return *(void**)((long)ptr + offset);
}

public static unsafe TVtable* GetVTable<TVtable>(void* ptr)
public static unsafe TVtable* GetVTable<TVtable>(void* ptr, int offset = 0)
where TVtable : unmanaged, ICppVtable
{
return (TVtable*)GetVTable(ptr);
return (TVtable*)GetVTable(ptr, offset);
}

public static unsafe TVtable* GetVTable<T, TVtable>(nint ptr, bool cheekAttribute = true)
public static unsafe TVtable* GetVTable<T, TVtable>(nint ptr, int offset = 0, bool cheekAttribute = true)
where T : class, ICppInstance<T>
where TVtable : unmanaged, ICppVtable
{
if (!cheekAttribute || typeof(T).GetCustomAttribute<VirtualCppClassAttribute>() is not null)
{
return GetVTable<TVtable>((void*)ptr);
return GetVTable<TVtable>((void*)ptr, offset);
}

throw new NullReferenceException();
}

public static unsafe ValuePointer<TVtable> GetVTable<T, TVtable>(Pointer<T> ptr, bool cheekAttribute = true)
public static unsafe ValuePointer<TVtable> GetVTable<T, TVtable>(Pointer<T> ptr, int offset = 0, bool cheekAttribute = true)
where T : class, ICppInstance<T>
where TVtable : unmanaged, ICppVtable
{
return GetVTable<T, TVtable>((nint)ptr, cheekAttribute);
return GetVTable<T, TVtable>((nint)ptr, offset, cheekAttribute);
}

public static unsafe ref TVtable GetVTable<T, TVtable>(T obj, bool cheekAttribute = true)
public static unsafe ref TVtable GetVTable<T, TVtable>(T obj, int offset = 0, bool cheekAttribute = true)
where T : class, ICppInstance<T>
where TVtable : unmanaged, ICppVtable
{
return ref *GetVTable<T, TVtable>(obj.Pointer, cheekAttribute);
return ref *GetVTable<T, TVtable>(obj.Pointer, offset, cheekAttribute);
}

public static T As<T>(this ICppInstanceNonGeneric @this, bool releaseSrc = false)
where T : class, IDisposable, ICppInstance<T>
{
if (!releaseSrc)
{
return T.ConstructInstance(@this.Pointer, false, true);
return T.ConstructInstance(@this.Pointer, false, false);
}

T temp = T.ConstructInstance(@this.Pointer, @this.OwnsInstance, @this.OwnsMemory);
Expand All @@ -60,104 +59,77 @@ public static T As<T>(this ICppInstanceNonGeneric @this, bool releaseSrc = false
return temp;
}

public static unsafe void* GetVurtualFunctionPointerByIndex(nint ptr, int index)
{
long* vtable = *(long**)ptr;
long fptr = *(vtable + index);
return (void*)fptr;
}
public static unsafe void* GetVurtualFunctionPointerByIndex(void* vtable, int index)
=> (void*)*((long*)vtable + index);
}

public interface IOverrideAttributeGeneric
{
public abstract int Index { get; }
public abstract int Offset { get; }

public abstract ulong VTableLength { get; }
}

[AttributeUsage(AttributeTargets.Method)]
public sealed class OverrideAttribute(int virtualMethodIndex) : Attribute
public sealed class OverrideAttribute<TVtable>(int virtualMethodIndex) : Attribute, IOverrideAttributeGeneric
where TVtable : ICppVtable
{
public int VirtualMethodIndex { get; } = virtualMethodIndex;
public int Index => virtualMethodIndex;
public int Offset => TVtable.Offset;
public ulong VTableLength => TVtable.VtableLength;
}

public unsafe interface INativeVirtualMethodOverrideProvider<T, TVtable>
where T : class, ICppInstance<T>
where TVtable : unmanaged, ICppVtable
public unsafe interface INativeVirtualMethodOverrideProvider<TSelf>
where TSelf : class, ICppInstance<TSelf>, INativeVirtualMethodOverrideProvider<TSelf>
{
private static readonly bool isVirtualCppClass;
private static readonly (int, nint)[]? virtFptrs;
private static readonly VtableHandle vtableHandle;

static INativeVirtualMethodOverrideProvider()
{
isVirtualCppClass = typeof(T).GetCustomAttribute<VirtualCppClassAttribute>() is not null;
if (isVirtualCppClass)
{
return;
}

List<(int, nint)> list = [];
foreach (MethodInfo method in typeof(T).GetMethods(BindingFlags.Public | BindingFlags.NonPublic))
{
OverrideAttribute? overrideAttr = method.GetCustomAttribute<OverrideAttribute>();
if (overrideAttr is null)
{
continue;
}

if (method.GetCustomAttribute<UnmanagedCallersOnlyAttribute>() is null)
{
throw new InvalidProgramException();
}
throw new NotImplementedException();

var query = from method in typeof(TSelf).GetRuntimeMethods()

Check warning on line 92 in src/Unmanaged/CppTypeSystem.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected
let attrs = method.GetCustomAttributes(false).ToList()
let overrideAttr = attrs.FirstOrDefault(a => a is IOverrideAttributeGeneric) as IOverrideAttributeGeneric
let unmanagedCallersOnlyAttr = attrs.OfType<UnmanagedCallersOnlyAttribute>().FirstOrDefault()
where overrideAttr != null && unmanagedCallersOnlyAttr != null
group (method.MethodHandle.GetFunctionPointer(), overrideAttr.Index, overrideAttr.Offset, overrideAttr.VTableLength)
by (overrideAttr.Offset, overrideAttr.VTableLength) into g
select (g.Key, g.Select(t => (t.Item1, t.Index)).ToArray());

vtableHandle = new(query);
}
}

list.Add((overrideAttr.VirtualMethodIndex, method.MethodHandle.GetFunctionPointer()));
}
internal unsafe struct VTable
{
public int offset;

Check warning on line 107 in src/Unmanaged/CppTypeSystem.cs

View workflow job for this annotation

GitHub Actions / build

Field 'VTable.offset' is never assigned to, and will always have its default value 0
public void* ptr;

Check warning on line 108 in src/Unmanaged/CppTypeSystem.cs

View workflow job for this annotation

GitHub Actions / build

Field 'VTable.ptr' is never assigned to, and will always have its default value
}

virtFptrs = [.. list];
}
internal unsafe class VtableHandle
{
VTable[] vtables;

Check warning on line 113 in src/Unmanaged/CppTypeSystem.cs

View workflow job for this annotation

GitHub Actions / build

The field 'VtableHandle.vtables' is never used

static VTableHandle? SetupVtable(ICppInstanceNonGeneric ins)
public VtableHandle(IEnumerable<((int offset, ulong vtableLength), (nint ptr, int index)[])> values)
{
if (isVirtualCppClass is false || virtFptrs is null)
{
return null;
}
throw new NotImplementedException();

VTableHandle handle = new();
Unsafe.CopyBlock(handle.VTable, CppTypeSystem.GetVTable((void*)ins.Pointer), (uint)sizeof(TVtable));
foreach ((int index, nint fptr) in virtFptrs)
{
*(void**)((long)handle.VTable + (index * sizeof(void*))) = (void*)fptr;
}
List<VTable> list = [];

Check warning on line 119 in src/Unmanaged/CppTypeSystem.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected

*(void**)(void*)ins.Pointer = handle.VTable;
return handle;
}

public class VTableHandle : SafeHandle
{
public VTableHandle() : base(0, true)
foreach (var ((offset, vtblLength), ptrs) in values)
{
TVtable* ptr = null;
try
var vtblPtr = NativeAlloc<nint>.NewArray(vtblLength);
for (int i = 0; i < (int)vtblLength; ++i)
{
ptr = HeapAlloc<TVtable>.New(default);
}
finally
{
if (ptr is not null)
{
HeapAlloc.Delete(ptr);
}
vtblPtr[i] = ptrs[i].ptr;
}
}
}

public override bool IsInvalid => false;
public TVtable* VTable => (TVtable*)handle;

protected override bool ReleaseHandle()
{
if (handle is 0)
{
return true;
}
~VtableHandle()
{

HeapAlloc<TVtable>.Delete((TVtable*)handle);
handle = 0;
return true;
}
}
}
4 changes: 2 additions & 2 deletions src/Unmanaged/ICppInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ public interface ICppInstanceNonGeneric : IDisposable

public void Destruct();
public static abstract void DestructInstance(nint ptr);
public static abstract object ConstructInstance(nint ptr, bool owns, bool isTempStackValue);
public static abstract object ConstructInstance(nint ptr, bool owns, bool ownsMemory);
}

public interface ICppInstance<TSelf> : ICppInstanceNonGeneric
where TSelf : class, ICppInstance<TSelf>
{
public new static abstract TSelf ConstructInstance(nint ptr, bool owns, bool isTempStackValue);
public new static abstract TSelf ConstructInstance(nint ptr, bool owns, bool ownsMemory);

/// <summary>
/// noexcept
Expand Down
1 change: 1 addition & 0 deletions src/Unmanaged/ICppVtable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ namespace Hosihikari.NativeInterop.Unmanaged;
public interface ICppVtable
{
public static abstract ulong VtableLength { get; }
public static abstract int Offset { get; }
}
3 changes: 1 addition & 2 deletions src/Unmanaged/INativeTypeFiller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ public static unsafe bool TryGetDestructorFunctionPointer<TFiller>(out delegate*
.Any(t => t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(INativeTypeFiller<,>))))
{
result = (delegate* managed<TFiller*, void>)
type
.GetMethod("Destruct", BindingFlags.Public | BindingFlags.Static, [typeof(TFiller*)])!
type.GetMethod("Destruct", BindingFlags.Public | BindingFlags.Static, [typeof(TFiller*)])!
.MethodHandle
.GetFunctionPointer()
.ToPointer();
Expand Down
6 changes: 3 additions & 3 deletions src/Unmanaged/HeapAlloc.cs → src/Unmanaged/NativeAlloc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Hosihikari.NativeInterop.Unmanaged;

public readonly unsafe ref struct HeapAlloc<T> where T : unmanaged
public readonly unsafe ref struct NativeAlloc<T> where T : unmanaged
{
private static readonly ulong s_size = (ulong)sizeof(T);

Expand Down Expand Up @@ -40,7 +40,7 @@ public static void Delete(T* ptr)
LibNative.operator_delete(ptr);
}

public static void DeleteAsRef(ref T val)
public static void DeleteByRef(ref T val)
{
fixed (T* ptr = &val)
{
Expand All @@ -49,7 +49,7 @@ public static void DeleteAsRef(ref T val)
}
}

public readonly unsafe ref struct HeapAlloc
public readonly unsafe ref struct NativeAlloc
{
public static void* New(ulong size)
{
Expand Down
15 changes: 9 additions & 6 deletions src/Unmanaged/STL/StdErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,26 @@ public unsafe struct StdErrorCategory
public readonly struct VTable : ICppVtable
{
// 0
public readonly delegate* unmanaged<StdErrorCategory*, void> destructor;
public readonly delegate* unmanaged[Cdecl]<StdErrorCategory*, void> destructor;

// 1
public readonly delegate* unmanaged<StdErrorCategory*, byte*> name;
public readonly delegate* unmanaged[Cdecl]<StdErrorCategory*, byte*> name;

// 2
public readonly delegate* unmanaged<StdErrorCategory*, int, StdString> message;
public readonly delegate* unmanaged[Cdecl]<StdErrorCategory*, int, StdString> message;

// 3
public readonly delegate* unmanaged<StdErrorCategory*, int, StdErrorCondition> default_error_condition;
public readonly delegate* unmanaged[Cdecl]<StdErrorCategory*, int, StdErrorCondition> default_error_condition;

// 4
public readonly delegate* unmanaged<StdErrorCategory*, int, in StdErrorCondition, bool> equivalent;
public readonly delegate* unmanaged[Cdecl]<StdErrorCategory*, int, in StdErrorCondition, bool> equivalent;

// 5
public readonly delegate* unmanaged<StdErrorCategory*, in StdErrorCode, int, bool> equivalent_overload;
public readonly delegate* unmanaged[Cdecl]<StdErrorCategory*, in StdErrorCode, int, bool> equivalent_overload;

public static ulong VtableLength => 6;

public static int Offset => 0;
}
}

Expand Down
16 changes: 3 additions & 13 deletions src/Unmanaged/STL/StdSharedPtr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,16 @@

namespace Hosihikari.NativeInterop.Unmanaged.STL;

[PredefinedType(TypeName = "class std::shared_ptr", IgnoreTemplateArgs = true)]
[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct StdSharedPtr : ITypeReferenceProvider
public unsafe partial struct StdSharedPtr
{
public void* ptr;
public void* ctr;

[SupportedOSPlatform("windows")]
[GeneratedRegex("^class std::shared_ptr<(?<class_type>.*)>")]
private static partial Regex StdSharedPtrRegex();

[SupportedOSPlatform("windows")] public static Regex Regex => StdSharedPtrRegex();

public static Type Matched(Match match)
{
return typeof(StdSharedPtr);
}

public readonly void* Target<T>() where T : class, ICppInstance<T>
{
return T.ConstructInstance((nint)ptr, false, true);
return T.ConstructInstance((nint)ptr, false, false);
}
}

Expand Down
Loading

0 comments on commit 4dced29

Please sign in to comment.