Browse Source

Added support for parameters with type a reference to a fixed-size array.

Signed-off-by: Dimitar Dobrev <dpldobrev@yahoo.com>
pull/560/head
Dimitar Dobrev 10 years ago
parent
commit
80643e0457
  1. 28
      src/Generator/Generators/CLI/CLIMarshal.cs
  2. 67
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  3. 28
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  4. 3
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  5. 12
      tests/CSharp/CSharp.Tests.cs
  6. 5
      tests/CSharp/CSharp.cpp
  7. 2
      tests/CSharp/CSharp.h

28
src/Generator/Generators/CLI/CLIMarshal.cs

@ -431,14 +431,26 @@ namespace CppSharp.Generators.CLI @@ -431,14 +431,26 @@ namespace CppSharp.Generators.CLI
switch (array.SizeType)
{
case ArrayType.ArraySize.Constant:
var supportBefore = Context.SupportBefore;
supportBefore.WriteLine("if ({0} != nullptr)", Context.ArgName);
supportBefore.WriteStartBraceIndent();
supportBefore.WriteLine("for (int i = 0; i < {0}; i++)", array.Size);
supportBefore.WriteLineIndent("{0}[i] = {1}[i]{2};",
Context.ReturnVarName, Context.ArgName,
array.Type.IsPointerToPrimitiveType(PrimitiveType.Void) ? ".ToPointer()" : string.Empty);
supportBefore.WriteCloseBraceIndent();
if (string.IsNullOrEmpty(Context.ReturnVarName))
{
const string pinnedPtr = "__pinnedPtr";
Context.SupportBefore.WriteLine("cli::pin_ptr<{0}> {1} = &{2}[0];",
array.Type, pinnedPtr, Context.Parameter.Name);
const string arrayPtr = "__arrayPtr";
Context.SupportBefore.WriteLine("{0}* {1} = {2};", array.Type, arrayPtr, pinnedPtr);
Context.Return.Write("({0} (&)[{1}]) {2}", array.Type, array.Size, arrayPtr);
}
else
{
var supportBefore = Context.SupportBefore;
supportBefore.WriteLine("if ({0} != nullptr)", Context.ArgName);
supportBefore.WriteStartBraceIndent();
supportBefore.WriteLine("for (int i = 0; i < {0}; i++)", array.Size);
supportBefore.WriteLineIndent("{0}[i] = {1}[i]{2};",
Context.ReturnVarName, Context.ArgName,
array.Type.IsPointerToPrimitiveType(PrimitiveType.Void) ? ".ToPointer()" : string.Empty);
supportBefore.WriteCloseBraceIndent();
}
break;
default:
Context.Return.Write("null");

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

@ -30,6 +30,7 @@ namespace CppSharp.Generators.CSharp @@ -30,6 +30,7 @@ namespace CppSharp.Generators.CSharp
public TextGenerator ArgumentPrefix { get; private set; }
public TextGenerator Cleanup { get; private set; }
public bool HasFixedBlock { get; set; }
}
public abstract class CSharpMarshalPrinter : MarshalPrinter
@ -390,28 +391,43 @@ namespace CppSharp.Generators.CSharp @@ -390,28 +391,43 @@ namespace CppSharp.Generators.CSharp
if (!VisitType(array, quals))
return false;
Class @class;
switch (array.SizeType)
{
case ArrayType.ArraySize.Constant:
var supportBefore = Context.SupportBefore;
supportBefore.WriteLine("if ({0} != null)", Context.ArgName);
supportBefore.WriteStartBraceIndent();
if (array.Type.Desugar().TryGetClass(out @class) && @class.IsRefType)
if (string.IsNullOrEmpty(Context.ReturnVarName))
{
supportBefore.WriteLine("if (value.Length != {0})", array.Size);
supportBefore.WriteLineIndent("throw new ArgumentOutOfRangeException(\"{0}\", \"The provided array's dimensions doesn't match the required size.\");",
Context.Parameter.Name);
Context.SupportBefore.WriteLine("if ({0} == null || {0}.Length != {1})", Context.Parameter.Name, array.Size);
ThrowArgumentOutOfRangeException();
const string ptr = "__ptr";
Context.SupportBefore.WriteLine("fixed ({0}* {1} = {2})", array.Type, ptr, Context.Parameter.Name);
Context.SupportBefore.WriteStartBraceIndent();
Context.Return.Write("new global::System.IntPtr({0})", ptr);
CSharpContext.HasFixedBlock = true;
}
supportBefore.WriteLine("for (int i = 0; i < {0}; i++)", array.Size);
if (@class != null && @class.IsRefType)
supportBefore.WriteLineIndent("{0}[i * sizeof({2}.Internal)] = *((byte*)({2}.Internal*){1}[i].__Instance);",
Context.ReturnVarName, Context.ArgName, array.Type);
else
supportBefore.WriteLineIndent("{0}[i] = {1}[i]{2};",
Context.ReturnVarName, Context.ArgName,
array.Type.IsPointerToPrimitiveType(PrimitiveType.Void) ? ".ToPointer()" : string.Empty);
supportBefore.WriteCloseBraceIndent();
{
var supportBefore = Context.SupportBefore;
supportBefore.WriteLine("if ({0} != null)", Context.ArgName);
supportBefore.WriteStartBraceIndent();
Class @class;
if (array.Type.Desugar().TryGetClass(out @class) && @class.IsRefType)
{
supportBefore.WriteLine("if (value.Length != {0})", array.Size);
ThrowArgumentOutOfRangeException();
}
supportBefore.WriteLine("for (int i = 0; i < {0}; i++)", array.Size);
if (@class != null && @class.IsRefType)
supportBefore.WriteLineIndent(
"{0}[i * sizeof({2}.Internal)] = *((byte*)({2}.Internal*){1}[i].__Instance);",
Context.ReturnVarName, Context.ArgName, array.Type);
else
supportBefore.WriteLineIndent("{0}[i] = {1}[i]{2};",
Context.ReturnVarName, Context.ArgName,
array.Type.IsPointerToPrimitiveType(PrimitiveType.Void)
? ".ToPointer()"
: string.Empty);
supportBefore.WriteCloseBraceIndent();
}
break;
default:
Context.Return.Write("null");
@ -420,6 +436,14 @@ namespace CppSharp.Generators.CSharp @@ -420,6 +436,14 @@ namespace CppSharp.Generators.CSharp
return true;
}
private void ThrowArgumentOutOfRangeException()
{
Context.SupportBefore.WriteLineIndent(
"throw new ArgumentOutOfRangeException(\"{0}\", " +
"\"The dimensions of the provided array don't match the required size.\");",
Context.Parameter.Name);
}
public bool VisitDelegateType(FunctionType function, string type)
{
Context.Return.Write("{0} == null ? global::System.IntPtr.Zero : Marshal.GetFunctionPointerForDelegate({0})",
@ -432,6 +456,17 @@ namespace CppSharp.Generators.CSharp @@ -432,6 +456,17 @@ namespace CppSharp.Generators.CSharp
if (!VisitType(pointer, quals))
return false;
if (Context.Function != null && pointer.IsPrimitiveTypeConvertibleToRef())
{
string refParamPtr = string.Format("__refParamPtr{0}", Context.ParameterIndex);
Context.SupportBefore.WriteLine("fixed ({0} {1} = &{2})",
pointer, refParamPtr, Context.Parameter.Name);
CSharpContext.HasFixedBlock = true;
Context.SupportBefore.WriteStartBraceIndent();
Context.Return.Write(refParamPtr);
return true;
}
var param = Context.Parameter;
var isRefParam = param != null && (param.IsInOut || param.IsOut);

28
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -2693,7 +2693,7 @@ namespace CppSharp.Generators.CSharp @@ -2693,7 +2693,7 @@ namespace CppSharp.Generators.CSharp
if ((paramType.GetFinalPointee() ?? paramType).Desugar().TryGetClass(out @class))
{
var qualifiedIdentifier = CSharpMarshalNativeToManagedPrinter.QualifiedIdentifier(
@class.OriginalClass ?? @class);
@class.OriginalClass ?? @class);
WriteLine("{0} = new {1}();", name, qualifiedIdentifier);
}
}
@ -2707,26 +2707,20 @@ namespace CppSharp.Generators.CSharp @@ -2707,26 +2707,20 @@ namespace CppSharp.Generators.CSharp
};
paramMarshal.Context = ctx;
var marshal = new CSharpMarshalManagedToNativePrinter(ctx);
param.CSharpMarshalToNative(marshal);
paramMarshal.HasFixedBlock = ctx.HasFixedBlock;
if (param.Type.IsPrimitiveTypeConvertibleToRef())
{
WriteLine("fixed ({0} {1} = &{2})", param.Type.CSharpType(TypePrinter), argName, name);
paramMarshal.HasFixedBlock = true;
WriteStartBraceIndent();
}
else
{
var marshal = new CSharpMarshalManagedToNativePrinter(ctx);
param.CSharpMarshalToNative(marshal);
if (string.IsNullOrEmpty(marshal.Context.Return))
throw new Exception("Cannot marshal argument of function");
if (string.IsNullOrEmpty(marshal.Context.Return))
throw new Exception("Cannot marshal argument of function");
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore);
if (paramMarshal.HasFixedBlock)
PushIndent();
WriteLine("var {0} = {1};", argName, marshal.Context.Return);
}
WriteLine("var {0} = {1};", argName, marshal.Context.Return);
return paramMarshal;
}

3
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -276,7 +276,8 @@ namespace CppSharp.Generators.CSharp @@ -276,7 +276,8 @@ namespace CppSharp.Generators.CSharp
}
Class @class;
if ((desugared.IsDependent || desugared.TryGetClass(out @class))
if ((desugared.IsDependent || desugared.TryGetClass(out @class) ||
(desugared is ArrayType && Context.Parameter != null))
&& ContextKind == CSharpTypePrinterContextKind.Native)
{
return "global::System.IntPtr";

12
tests/CSharp/CSharp.Tests.cs

@ -415,7 +415,7 @@ public class CSharpTests : GeneratorTestFixture @@ -415,7 +415,7 @@ public class CSharpTests : GeneratorTestFixture
foosMore[1] = new Foo();
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => bar.Foos = foosMore);
Assert.AreEqual("value", ex.ParamName);
Assert.AreEqual("The provided array's dimensions doesn't match the required size." + Environment.NewLine +"Parameter name: value", ex.Message);
Assert.AreEqual("The dimensions of the provided array don't match the required size." + Environment.NewLine + "Parameter name: value", ex.Message);
}
[Test]
@ -443,4 +443,14 @@ public class CSharpTests : GeneratorTestFixture @@ -443,4 +443,14 @@ public class CSharpTests : GeneratorTestFixture
{
Assert.That(sizeof(DerivesFromTemplateInstantiation.Internal), Is.EqualTo(sizeof(int)));
}
[Test]
public void TestReferenceToArrayWithConstSize()
{
int[] incorrectlySizedArray = { 1 };
Assert.Catch<ArgumentOutOfRangeException>(() => CSharp.CSharp.PassConstantArrayRef(incorrectlySizedArray));
int[] array = { 1, 2 };
var result = CSharp.CSharp.PassConstantArrayRef(array);
Assert.That(result, Is.EqualTo(array[0]));
}
}

5
tests/CSharp/CSharp.cpp

@ -798,3 +798,8 @@ TemplateWithDependentField<T>::TemplateWithDependentField() @@ -798,3 +798,8 @@ TemplateWithDependentField<T>::TemplateWithDependentField()
DerivesFromTemplateInstantiation::DerivesFromTemplateInstantiation()
{
}
int PassConstantArrayRef(int(&arr)[2])
{
return arr[0];
}

2
tests/CSharp/CSharp.h

@ -731,3 +731,5 @@ class DerivesFromTemplateInstantiation : public TemplateWithDependentField<int> @@ -731,3 +731,5 @@ class DerivesFromTemplateInstantiation : public TemplateWithDependentField<int>
public:
DerivesFromTemplateInstantiation();
};
DLL_API int PassConstantArrayRef(int(&arr)[2]);

Loading…
Cancel
Save