Browse Source

Value types can also be copied using memcpy

pg
josetr 3 years ago
parent
commit
2955b9fc30
  1. 92
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  2. 12
      src/Runtime/MarshalUtil.cs

92
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -15,6 +15,12 @@ namespace CppSharp.Generators.CSharp @@ -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<CSharpMarshalContext, CSharpTypePrinter>
@ -68,7 +74,7 @@ namespace CppSharp.Generators.CSharp @@ -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 @@ -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 @@ -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);

12
src/Runtime/MarshalUtil.cs

@ -62,5 +62,17 @@ namespace CppSharp.Runtime @@ -62,5 +62,17 @@ namespace CppSharp.Runtime
var slot = *(IntPtr*)(vtables[table] + i * sizeof(IntPtr));
return Marshal.GetDelegateForFunctionPointer<T>(slot);
}
public static void SetArray<T>(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);
}
}
}

Loading…
Cancel
Save