Browse Source

Add `GenerateNativeToManaged` per-class option

refactor
josetr 3 years ago
parent
commit
37bd7e0155
  1. 7
      src/Generator/ClassOptions.cs
  2. 24
      src/Generator/Generators/CSharp/CSharpSources.cs
  3. 6
      src/Generator/Options.cs
  4. 6
      tests/CSharp/CSharp.Gen.cs
  5. 7
      tests/CSharp/CSharp.Tests.cs
  6. 2
      tests/CSharp/CSharp.h

7
src/Generator/ClassOptions.cs

@ -0,0 +1,7 @@
namespace CppSharp
{
public class ClassGenerationOptions
{
public bool GenerateNativeToManaged { get; set; }
}
}

24
src/Generator/Generators/CSharp/CSharpSources.cs

@ -438,6 +438,8 @@ namespace CppSharp.Generators.CSharp
var valueType = Options.GenerateFinalizerFor(@class) ? $"global::System.WeakReference<{printedClass}>" : $"{printedClass}"; var valueType = Options.GenerateFinalizerFor(@class) ? $"global::System.WeakReference<{printedClass}>" : $"{printedClass}";
var dict = $@"global::System.Collections.Concurrent.ConcurrentDictionary<IntPtr, {valueType}>"; var dict = $@"global::System.Collections.Concurrent.ConcurrentDictionary<IntPtr, {valueType}>";
var generateNativeToManaged = Options.GenerateNativeToManagedFor(@class);
if (generateNativeToManaged)
WriteLine("internal static readonly {0} NativeToManagedMap = new {0}();", dict); WriteLine("internal static readonly {0} NativeToManagedMap = new {0}();", dict);
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
@ -446,6 +448,8 @@ namespace CppSharp.Generators.CSharp
// will never get invoked: unless the managed object is Disposed, there will always be a reference // will never get invoked: unless the managed object is Disposed, there will always be a reference
// in the dictionary. // in the dictionary.
PushBlock(BlockKind.Method); PushBlock(BlockKind.Method);
if (generateNativeToManaged)
{
if (Options.GenerateFinalizerFor(@class)) if (Options.GenerateFinalizerFor(@class))
{ {
WriteLines($@" WriteLines($@"
@ -474,6 +478,7 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat
}}"); }}");
} }
} }
}
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
} }
@ -2270,6 +2275,7 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat
WriteLineIndent("return;"); WriteLineIndent("return;");
// The local var must be of the exact type in the object map because of TryRemove // The local var must be of the exact type in the object map because of TryRemove
if (Options.GenerateNativeToManagedFor(@class))
WriteLine("NativeToManagedMap.TryRemove({0}, out _);", Helpers.InstanceIdentifier); WriteLine("NativeToManagedMap.TryRemove({0}, out _);", Helpers.InstanceIdentifier);
var realClass = @class.IsTemplate ? @class.Specializations[0] : @class; var realClass = @class.IsTemplate ? @class.Specializations[0] : @class;
var classInternal = TypePrinter.PrintNative(realClass); var classInternal = TypePrinter.PrintNative(realClass);
@ -2402,6 +2408,9 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat
{ {
var @new = @class.HasBase && @class.HasRefBase(); var @new = @class.HasBase && @class.HasRefBase();
bool generateNativeToManaged = Options.GenerateNativeToManagedFor(@class);
if (generateNativeToManaged)
{
WriteLines($@" WriteLines($@"
internal static{(@new ? " new" : string.Empty)} {printedClass} __GetOrCreateInstance({TypePrinter.IntPtrType} native, bool saveInstance = false, bool skipVTables = false) internal static{(@new ? " new" : string.Empty)} {printedClass} __GetOrCreateInstance({TypePrinter.IntPtrType} native, bool saveInstance = false, bool skipVTables = false)
{{ {{
@ -2415,6 +2424,7 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetOrCreateInst
return result; return result;
}}"); }}");
NewLine(); NewLine();
}
if (HasVirtualTables(@class)) if (HasVirtualTables(@class))
{ {
@ -2422,9 +2432,16 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetOrCreateInst
WriteLines($@" WriteLines($@"
internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({TypePrinter.IntPtrType} native) internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({TypePrinter.IntPtrType} native)
{{ {{");
if (generateNativeToManaged)
{
WriteLines($@"
if (!{Helpers.TryGetNativeToManagedMappingIdentifier}(native, out var managed)) if (!{Helpers.TryGetNativeToManagedMappingIdentifier}(native, out var managed))
throw new global::System.Exception(""No managed instance was found""); throw new global::System.Exception(""No managed instance was found"");");
}
WriteLines($@"
var result = ({printedClass})managed; var result = ({printedClass})managed;
if (result.{Helpers.OwnsNativeInstanceIdentifier}) if (result.{Helpers.OwnsNativeInstanceIdentifier})
result.SetupVTables(); result.SetupVTables();
@ -2540,6 +2557,7 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty
if (@class.IsRefType) if (@class.IsRefType)
{ {
WriteLine($"{Helpers.OwnsNativeInstanceIdentifier} = true;"); WriteLine($"{Helpers.OwnsNativeInstanceIdentifier} = true;");
if (Options.GenerateNativeToManagedFor(@class))
WriteLine($"{Helpers.RecordNativeToManagedMappingIdentifier}({Helpers.InstanceIdentifier}, this);"); WriteLine($"{Helpers.RecordNativeToManagedMappingIdentifier}({Helpers.InstanceIdentifier}, this);");
} }
else else
@ -2985,6 +3003,8 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty
@class.IsAbstractImpl ? @class.BaseClass : @class); @class.IsAbstractImpl ? @class.BaseClass : @class);
WriteLine($"{Helpers.InstanceIdentifier} = Marshal.AllocHGlobal(sizeof({@internal}));"); WriteLine($"{Helpers.InstanceIdentifier} = Marshal.AllocHGlobal(sizeof({@internal}));");
WriteLine($"{Helpers.OwnsNativeInstanceIdentifier} = true;"); WriteLine($"{Helpers.OwnsNativeInstanceIdentifier} = true;");
if (Options.GenerateNativeToManagedFor(@class))
WriteLine($"{Helpers.RecordNativeToManagedMappingIdentifier}({Helpers.InstanceIdentifier}, this);"); WriteLine($"{Helpers.RecordNativeToManagedMappingIdentifier}({Helpers.InstanceIdentifier}, this);");
if (method.IsCopyConstructor) if (method.IsCopyConstructor)

6
src/Generator/Options.cs

@ -136,6 +136,12 @@ namespace CppSharp
/// </remarks> /// </remarks>
public Func<Class, bool> GenerateFinalizersFilter = (@class) => true; public Func<Class, bool> GenerateFinalizersFilter = (@class) => true;
/// <summary>
/// A callback that allows the user to provide generator options per-class.
/// </summary>
public Func<Class, ClassGenerationOptions> GetClassGenerationOptions = null;
internal bool GenerateNativeToManagedFor(Class @class) => GetClassGenerationOptions?.Invoke(@class)?.GenerateNativeToManaged ?? true;
/// <summary> /// <summary>
/// An internal convenience method that combines the effect of <see /// An internal convenience method that combines the effect of <see
/// cref="GenerateFinalizers"/> and <see cref="GenerateFinalizersFilter"/>. /// cref="GenerateFinalizers"/> and <see cref="GenerateFinalizersFilter"/>.

6
tests/CSharp/CSharp.Gen.cs

@ -33,6 +33,12 @@ namespace CppSharp.Tests
driver.Options.MarshalCharAsManagedChar = true; driver.Options.MarshalCharAsManagedChar = true;
driver.Options.GenerateDefaultValuesForArguments = true; driver.Options.GenerateDefaultValuesForArguments = true;
driver.Options.GenerateClassTemplates = true; driver.Options.GenerateClassTemplates = true;
var disableNativeToManaged = new ClassGenerationOptions { GenerateNativeToManaged = false };
driver.Options.GetClassGenerationOptions = e =>
{
return e.Name == "ClassWithoutNativeToManaged" ? disableNativeToManaged : null;
};
} }
public override void Preprocess(Driver driver, ASTContext ctx) public override void Preprocess(Driver driver, ASTContext ctx)

7
tests/CSharp/CSharp.Tests.cs

@ -1893,4 +1893,11 @@ public unsafe class CSharpTests
Assert.That(CSharp.CSharp.TestFunctionToInstanceMethodConstStruct(new FTIStruct(), new FTIStruct() { A = 6 }), Is.EqualTo(6)); Assert.That(CSharp.CSharp.TestFunctionToInstanceMethodConstStruct(new FTIStruct(), new FTIStruct() { A = 6 }), Is.EqualTo(6));
Assert.That(CSharp.CSharp.TestFunctionToInstanceMethodConstRefStruct(new FTIStruct(), new FTIStruct() { A = 6 }), Is.EqualTo(6)); Assert.That(CSharp.CSharp.TestFunctionToInstanceMethodConstRefStruct(new FTIStruct(), new FTIStruct() { A = 6 }), Is.EqualTo(6));
} }
[TestCase(typeof(FTIStruct), ExpectedResult = true)]
[TestCase(typeof(ClassWithoutNativeToManaged), ExpectedResult = false)]
public bool TestClassGenerateNativeToManaged(Type type)
{
return type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Any(x => x.Name.Contains("NativeToManaged"));
}
} }

2
tests/CSharp/CSharp.h

@ -1534,3 +1534,5 @@ DLL_API int TestFunctionToInstanceMethodStruct(FTIStruct* bb, FTIStruct defaultV
DLL_API int TestFunctionToInstanceMethodRefStruct(FTIStruct* bb, FTIStruct& defaultValue); DLL_API int TestFunctionToInstanceMethodRefStruct(FTIStruct* bb, FTIStruct& defaultValue);
DLL_API int TestFunctionToInstanceMethodConstStruct(FTIStruct* bb, const FTIStruct defaultValue); DLL_API int TestFunctionToInstanceMethodConstStruct(FTIStruct* bb, const FTIStruct defaultValue);
DLL_API int TestFunctionToInstanceMethodConstRefStruct(FTIStruct* bb, const FTIStruct& defaultValue); DLL_API int TestFunctionToInstanceMethodConstRefStruct(FTIStruct* bb, const FTIStruct& defaultValue);
class ClassWithoutNativeToManaged { };
Loading…
Cancel
Save