From 2955b9fc30fcc3e8835e6a9b67cbb516eb52f73f Mon Sep 17 00:00:00 2001 From: josetr <37419832+josetr@users.noreply.github.com> Date: Mon, 14 Mar 2022 11:33:15 +0000 Subject: [PATCH] Value types can also be copied using memcpy --- .../Generators/CSharp/CSharpMarshal.cs | 92 ++++++++++--------- src/Runtime/MarshalUtil.cs | 12 +++ 2 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 6b6e6534..1c2b5b46 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -15,6 +15,12 @@ namespace CppSharp.Generators.CSharp } public bool HasCodeBlock { get; set; } + + public bool CheckIfArrayCanBeCopiedUsingMemoryCopy(ArrayType array) + { + return (array.Type.IsPrimitiveType(out var primitive) && (!Context.Options.MarshalCharAsManagedChar || primitive != PrimitiveType.Char)) + || (array.Type.TryGetDeclaration(out Class decl) && decl.IsValueType); + } } public abstract class CSharpMarshalPrinter : MarshalPrinter @@ -68,7 +74,7 @@ namespace CppSharp.Generators.CSharp var arrayType = array.Type.Desugar(); - if (CheckIfArrayCanBeCopiedUsingMemoryCopy(array)) + if (Context.CheckIfArrayCanBeCopiedUsingMemoryCopy(array)) { if (Context.Context.Options.UseSpan) Context.Return.Write($"new Span<{arrayType}>({Context.ReturnVarName}, {array.Size})"); @@ -449,12 +455,6 @@ namespace CppSharp.Generators.CSharp Context.Return.Write(intermediateArray); } - - public bool CheckIfArrayCanBeCopiedUsingMemoryCopy(ArrayType array) - { - return array.Type.IsPrimitiveType(out var primitive) && - (!Context.Context.Options.MarshalCharAsManagedChar || primitive != PrimitiveType.Char); - } } public class CSharpMarshalManagedToNativePrinter : CSharpMarshalPrinter @@ -490,47 +490,53 @@ namespace CppSharp.Generators.CSharp goto case ArrayType.ArraySize.Incomplete; var supportBefore = Context.Before; - supportBefore.WriteLine($"if ({Context.ArgName} != null)"); - supportBefore.WriteOpenBraceAndIndent(); - Class @class; var arrayType = array.Type.Desugar(); - var finalArrayType = arrayType.GetPointee() ?? arrayType; - if (finalArrayType.TryGetClass(out @class) && @class.IsRefType) - { - supportBefore.WriteLine($"if (value.Length != {array.Size})"); - ThrowArgumentOutOfRangeException(); - } - supportBefore.WriteLine($"for (int i = 0; i < {array.Size}; i++)"); - if (@class != null && @class.IsRefType) - { - if (finalArrayType == arrayType) - supportBefore.WriteLineIndent( - "*({1}.{2}*) &{0}[i * sizeof({1}.{2})] = *({1}.{2}*){3}[i].{4};", - Context.ReturnVarName, arrayType, Helpers.InternalStruct, - Context.ArgName, Helpers.InstanceIdentifier); - else - supportBefore.WriteLineIndent($@"{Context.ReturnVarName}[i] = ({ - (Context.Context.TargetInfo.PointerWidth == 64 ? "long" : "int")}) { - Context.ArgName}[i].{Helpers.InstanceIdentifier};"); - } + + if (Context.CheckIfArrayCanBeCopiedUsingMemoryCopy(array)) + supportBefore.WriteLine($"CppSharp.Runtime.MarshalUtil.SetArray<{arrayType}>(value, {Context.ReturnVarName}, {array.Size});"); else { - if (arrayType.IsPrimitiveType(PrimitiveType.Bool)) - supportBefore.WriteLineIndent($@"{ - Context.ReturnVarName}[i] = (byte)({ - Context.ArgName}[i] ? 1 : 0);"); - else if (arrayType.IsPrimitiveType(PrimitiveType.Char) && - Context.Context.Options.MarshalCharAsManagedChar) - supportBefore.WriteLineIndent($@"{ - Context.ReturnVarName}[i] = global::System.Convert.ToSByte({ - Context.ArgName}[i]);"); + supportBefore.WriteLine($"if ({Context.ArgName} != null)"); + supportBefore.WriteOpenBraceAndIndent(); + Class @class; + var finalArrayType = arrayType.GetPointee() ?? arrayType; + if (finalArrayType.TryGetClass(out @class) && @class.IsRefType) + { + supportBefore.WriteLine($"if (value.Length != {array.Size})"); + ThrowArgumentOutOfRangeException(); + } + supportBefore.WriteLine($"for (int i = 0; i < {array.Size}; i++)"); + if (@class != null && @class.IsRefType) + { + if (finalArrayType == arrayType) + supportBefore.WriteLineIndent( + "*({1}.{2}*) &{0}[i * sizeof({1}.{2})] = *({1}.{2}*){3}[i].{4};", + Context.ReturnVarName, arrayType, Helpers.InternalStruct, + Context.ArgName, Helpers.InstanceIdentifier); + else + supportBefore.WriteLineIndent($@"{Context.ReturnVarName}[i] = ({ + (Context.Context.TargetInfo.PointerWidth == 64 ? "long" : "int")}) { + Context.ArgName}[i].{Helpers.InstanceIdentifier};"); + } else - supportBefore.WriteLineIndent($@"{Context.ReturnVarName}[i] = { - Context.ArgName}[i]{ - (arrayType.IsPointerToPrimitiveType(PrimitiveType.Void) ? - ".ToPointer()" : string.Empty)};"); + { + if (arrayType.IsPrimitiveType(PrimitiveType.Bool)) + supportBefore.WriteLineIndent($@"{ + Context.ReturnVarName}[i] = (byte)({ + Context.ArgName}[i] ? 1 : 0);"); + else if (arrayType.IsPrimitiveType(PrimitiveType.Char) && + Context.Context.Options.MarshalCharAsManagedChar) + supportBefore.WriteLineIndent($@"{ + Context.ReturnVarName}[i] = global::System.Convert.ToSByte({ + Context.ArgName}[i]);"); + else + supportBefore.WriteLineIndent($@"{Context.ReturnVarName}[i] = { + Context.ArgName}[i]{ + (arrayType.IsPointerToPrimitiveType(PrimitiveType.Void) ? + ".ToPointer()" : string.Empty)};"); + } + supportBefore.UnindentAndWriteCloseBrace(); } - supportBefore.UnindentAndWriteCloseBrace(); break; case ArrayType.ArraySize.Incomplete: MarshalArray(array); diff --git a/src/Runtime/MarshalUtil.cs b/src/Runtime/MarshalUtil.cs index 7ba1c6f8..79e3a1dd 100644 --- a/src/Runtime/MarshalUtil.cs +++ b/src/Runtime/MarshalUtil.cs @@ -62,5 +62,17 @@ namespace CppSharp.Runtime var slot = *(IntPtr*)(vtables[table] + i * sizeof(IntPtr)); return Marshal.GetDelegateForFunctionPointer(slot); } + + public static void SetArray(T[] src, void* dest, int destSize) where T : unmanaged + { + if (src == null) + return; + + if (src.Length != destSize) + throw new ArgumentOutOfRangeException("The dimensions of the provided array don't match the required size."); + + fixed (void* srcPtr = src) + Buffer.MemoryCopy(srcPtr, dest, sizeof(T) * src.Length, sizeof(T) * src.Length); + } } }