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

6
src/Generator/Options.cs

@ -136,6 +136,12 @@ namespace CppSharp @@ -136,6 +136,12 @@ namespace CppSharp
/// </remarks>
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>
/// An internal convenience method that combines the effect of <see
/// cref="GenerateFinalizers"/> and <see cref="GenerateFinalizersFilter"/>.

6
tests/CSharp/CSharp.Gen.cs

@ -33,6 +33,12 @@ namespace CppSharp.Tests @@ -33,6 +33,12 @@ namespace CppSharp.Tests
driver.Options.MarshalCharAsManagedChar = true;
driver.Options.GenerateDefaultValuesForArguments = 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)

7
tests/CSharp/CSharp.Tests.cs

@ -1893,4 +1893,11 @@ public unsafe class CSharpTests @@ -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.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 @@ -1534,3 +1534,5 @@ DLL_API int TestFunctionToInstanceMethodStruct(FTIStruct* bb, FTIStruct defaultV
DLL_API int TestFunctionToInstanceMethodRefStruct(FTIStruct* bb, FTIStruct& defaultValue);
DLL_API int TestFunctionToInstanceMethodConstStruct(FTIStruct* bb, const FTIStruct defaultValue);
DLL_API int TestFunctionToInstanceMethodConstRefStruct(FTIStruct* bb, const FTIStruct& defaultValue);
class ClassWithoutNativeToManaged { };
Loading…
Cancel
Save