From c6ae35ff7d7fe7140bfa44a8127fc8f3b2c26585 Mon Sep 17 00:00:00 2001 From: Abhinav Tripathi Date: Thu, 13 Aug 2015 23:02:31 +0530 Subject: [PATCH] Added marshalling of fixed size ref type arrays. --- .../Generators/CSharp/CSharpMarshal.cs | 21 ++++++++++++-- src/Generator/Passes/CheckIgnoredDecls.cs | 4 ++- tests/CSharpTemp/CSharpTemp.Tests.cs | 29 +++++++++++++++++++ tests/CSharpTemp/CSharpTemp.h | 2 +- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 85bfa8b1..e77c0f61 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -111,6 +111,7 @@ namespace CppSharp.Generators.CSharp if (!VisitType(array, quals)) return false; + Class @class; switch (array.SizeType) { case ArrayType.ArraySize.Constant: @@ -124,6 +125,9 @@ namespace CppSharp.Generators.CSharp if (array.Type.IsPointerToPrimitiveType(PrimitiveType.Void)) supportBefore.WriteLineIndent("{0}[i] = new global::System.IntPtr({1}[i]);", value, Context.ReturnVarName); + else if (array.Type.Desugar().TryGetClass(out @class) && @class.IsRefType) + supportBefore.WriteLineIndent("{0}[i] = {1}.{2}(*(({1}.Internal*)&({3}[i * sizeof({1}.Internal)])));", + value, array.Type, Helpers.CreateInstanceIdentifier, Context.ReturnVarName); else supportBefore.WriteLineIndent("{0}[i] = {1}[i];", value, Context.ReturnVarName); supportBefore.WriteCloseBraceIndent(); @@ -382,16 +386,27 @@ 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) + { + 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); + } 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); + 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: diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index ccbfc717..29b38352 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -341,11 +341,13 @@ namespace CppSharp.Passes return true; } + Class @class; var arrayType = type as ArrayType; PrimitiveType primitive; if (arrayType != null && arrayType.SizeType == ArrayType.ArraySize.Constant && !arrayType.Type.IsPrimitiveType(out primitive) && - !arrayType.Type.Desugar().IsPointerToPrimitiveType()) + !arrayType.Type.Desugar().IsPointerToPrimitiveType() && + !(arrayType.Type.Desugar().TryGetClass(out @class) && @class.IsRefType)) { msg = "unsupported"; return true; diff --git a/tests/CSharpTemp/CSharpTemp.Tests.cs b/tests/CSharpTemp/CSharpTemp.Tests.cs index fd8da077..83b136f6 100644 --- a/tests/CSharpTemp/CSharpTemp.Tests.cs +++ b/tests/CSharpTemp/CSharpTemp.Tests.cs @@ -393,4 +393,33 @@ public class CSharpTempTests : GeneratorTestFixture obj.FuncPrimitivePtrToRefWithDefVal(ref refInt, null, null, ref refInt); obj.FuncPrimitivePtrToRefWithMultiOverload(ref refInt, null, null, ref refInt); } + + [Test] + public void TestFixedArrayRefType() + { + Foo[] foos = new Foo[4]; + foos[0] = new Foo(); + foos[0].A = 5; + foos[1] = new Foo(); + foos[1].A = 6; + foos[2] = new Foo(); + foos[2].A = 7; + foos[3] = new Foo(); + foos[3].A = 8; + Bar bar = new Bar(); + bar.Foos = foos; + + Foo[] retFoos = bar.Foos; + Assert.AreEqual(5, retFoos[0].A); + Assert.AreEqual(6, retFoos[1].A); + Assert.AreEqual(7, retFoos[2].A); + Assert.AreEqual(8, retFoos[3].A); + + Foo[] foosMore = new Foo[2]; + foosMore[0] = new Foo(); + foosMore[1] = new Foo(); + var ex = Assert.Throws(() => bar.Foos = foosMore); + Assert.AreEqual("value", ex.ParamName); + Assert.AreEqual("The provided array's dimensions doesn't match the required size.\r\nParameter name: value", ex.Message); + } } diff --git a/tests/CSharpTemp/CSharpTemp.h b/tests/CSharpTemp/CSharpTemp.h index bb4c5edf..11a75c2d 100644 --- a/tests/CSharpTemp/CSharpTemp.h +++ b/tests/CSharpTemp/CSharpTemp.h @@ -65,11 +65,11 @@ public: const Bar& operator++(); Bar operator++(int i); void* arrayOfPrimitivePointers[1]; + Foo foos[4]; private: int index; Foo m_foo; - Foo foos[4]; }; Bar::Bar() {}