From 911ce43e070893851f2bbe2e0f8b370e821cc162 Mon Sep 17 00:00:00 2001 From: Elias Holzer Date: Tue, 6 May 2014 02:56:59 +0200 Subject: [PATCH 1/2] Use List when mapping a std::vector where T is a primitive type. Pointers are not allowed in generic arguments. --- .../Generators/CLI/CLITypePrinter.cs | 5 ++- src/Generator/Types/ITypePrinter.cs | 5 ++- src/Generator/Types/Std/Stdlib.cs | 27 ++++++++++++--- tests/STL/STL.Tests.cs | 33 ++++++++++++++++++- tests/STL/STL.cpp | 11 +++++++ tests/STL/STL.cs | 1 + tests/STL/STL.h | 22 ++++++++++++- 7 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/Generator/Generators/CLI/CLITypePrinter.cs b/src/Generator/Generators/CLI/CLITypePrinter.cs index a98431d6..88dc9c83 100644 --- a/src/Generator/Generators/CLI/CLITypePrinter.cs +++ b/src/Generator/Generators/CLI/CLITypePrinter.cs @@ -284,7 +284,10 @@ namespace CppSharp.Generators.CLI public string VisitCILType(CILType type, TypeQualifiers quals) { - return type.Type.FullName.Replace(".", "::") + "^"; + var result = type.Type.FullName.Replace(".", "::"); + if (!type.Type.IsValueType) + result += "^"; + return result; } public string VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals) diff --git a/src/Generator/Types/ITypePrinter.cs b/src/Generator/Types/ITypePrinter.cs index 14758e45..6ea44a81 100644 --- a/src/Generator/Types/ITypePrinter.cs +++ b/src/Generator/Types/ITypePrinter.cs @@ -39,7 +39,10 @@ namespace CppSharp.Types { if (arg.Kind != TemplateArgument.ArgumentKind.Type) continue; - paramsList.Add(arg.Type.ToString()); + var argType = arg.Type.Type.IsPointerToPrimitiveType() + ? new CILType(typeof(System.IntPtr)) + : arg.Type.Type; + paramsList.Add(argType.ToString()); } } diff --git a/src/Generator/Types/Std/Stdlib.cs b/src/Generator/Types/Std/Stdlib.cs index 6dad9599..14a88abd 100644 --- a/src/Generator/Types/Std/Stdlib.cs +++ b/src/Generator/Types/Std/Stdlib.cs @@ -1,4 +1,5 @@ using CppSharp.AST; +using CppSharp.AST.Extensions; using CppSharp.Generators; using CppSharp.Generators.CLI; using CppSharp.Generators.CSharp; @@ -113,6 +114,10 @@ namespace CppSharp.Types.Std { var templateType = Type as TemplateSpecializationType; var type = templateType.Arguments[0].Type; + var isPointerToPrimitive = type.Type.IsPointerToPrimitiveType(); + var managedType = isPointerToPrimitive + ? new CILType(typeof(System.IntPtr)) + : type.Type; var entryString = (ctx.Parameter != null) ? ctx.Parameter.Name : ctx.ArgName; @@ -125,7 +130,7 @@ namespace CppSharp.Types.Std ctx.SupportBefore.WriteLine("auto {0} = std::vector<{1}>();", tmpVarName, nativeType); ctx.SupportBefore.WriteLine("for each({0} _element in {1})", - type.ToString(), entryString); + managedType, entryString); ctx.SupportBefore.WriteStartBraceIndent(); { var param = new Parameter @@ -146,7 +151,11 @@ namespace CppSharp.Types.Std if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) ctx.SupportBefore.Write(marshal.Context.SupportBefore); - ctx.SupportBefore.WriteLine("auto _marshalElement = {0};", + if (isPointerToPrimitive) + ctx.SupportBefore.WriteLine("auto _marshalElement = {0}.ToPointer();", + marshal.Context.Return); + else + ctx.SupportBefore.WriteLine("auto _marshalElement = {0};", marshal.Context.Return); ctx.SupportBefore.WriteLine("{0}.push_back(_marshalElement);", @@ -162,11 +171,15 @@ namespace CppSharp.Types.Std { var templateType = Type as TemplateSpecializationType; var type = templateType.Arguments[0].Type; + var isPointerToPrimitive = type.Type.IsPointerToPrimitiveType(); + var managedType = isPointerToPrimitive + ? new CILType(typeof(System.IntPtr)) + : type.Type; var tmpVarName = "_tmp" + ctx.ArgName; ctx.SupportBefore.WriteLine( "auto {0} = gcnew System::Collections::Generic::List<{1}>();", - tmpVarName, type.ToString()); + tmpVarName, managedType); ctx.SupportBefore.WriteLine("for(auto _element : {0})", ctx.ReturnVarName); ctx.SupportBefore.WriteStartBraceIndent(); @@ -186,8 +199,12 @@ namespace CppSharp.Types.Std ctx.SupportBefore.WriteLine("auto _marshalElement = {0};", marshal.Context.Return); - ctx.SupportBefore.WriteLine("{0}->Add(_marshalElement);", - tmpVarName); + if (isPointerToPrimitive) + ctx.SupportBefore.WriteLine("{0}->Add({1}(_marshalElement));", + tmpVarName, managedType); + else + ctx.SupportBefore.WriteLine("{0}->Add(_marshalElement);", + tmpVarName); } ctx.SupportBefore.WriteCloseBraceIndent(); diff --git a/tests/STL/STL.Tests.cs b/tests/STL/STL.Tests.cs index a033c3aa..c8f6a961 100644 --- a/tests/STL/STL.Tests.cs +++ b/tests/STL/STL.Tests.cs @@ -1,7 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using CppSharp.Utils; using NUnit.Framework; +using System.Runtime.InteropServices; +using STL; public class STLTests : GeneratorTestFixture { @@ -15,6 +18,34 @@ public class STLTests : GeneratorTestFixture var list = vectors.GetIntVector(); Assert.True(list.SequenceEqual(new List { 2, 3, 4 })); + + var ptrList = vectors.IntPtrVector; + var intList = ptrList.Select(ptr => Marshal.ReadInt32(ptr)); + Assert.True(intList.SequenceEqual(new List { 2, 3, 4 })); + + var wrapperList = new List(); + for (int i = 0; i < 3; i++) + wrapperList.Add(new IntWrapper() { Value = i }); + vectors.IntWrapperVector = wrapperList; + wrapperList = vectors.IntWrapperVector; + for (int i = 0; i < 3; i++) + Assert.AreEqual(i, wrapperList[i].Value); + + for (int i = 0; i < 3; i++) + wrapperList[i].Value += i; + + vectors.IntWrapperPtrVector = wrapperList; + wrapperList = vectors.IntWrapperPtrVector; + for (int i = 0; i < 3; i++) + Assert.AreEqual(i * 2, wrapperList[i].Value); + + var valueTypeWrapperList = new List(); + for (int i = 0; i < 3; i++) + valueTypeWrapperList.Add(new IntWrapperValueType() { Value = i }); + vectors.IntWrapperValueTypeVector = valueTypeWrapperList; + valueTypeWrapperList = vectors.IntWrapperValueTypeVector; + for (int i = 0; i < 3; i++) + Assert.AreEqual(i, valueTypeWrapperList[i].Value); } } \ No newline at end of file diff --git a/tests/STL/STL.cpp b/tests/STL/STL.cpp index 0c4f0712..6b6706c9 100644 --- a/tests/STL/STL.cpp +++ b/tests/STL/STL.cpp @@ -1,5 +1,16 @@ #include "STL.h" +TestVectors::TestVectors() +{ + IntVector.push_back(2); + IntVector.push_back(3); + IntVector.push_back(4); + + IntPtrVector.push_back(&IntVector[0]); + IntPtrVector.push_back(&IntVector[1]); + IntPtrVector.push_back(&IntVector[2]); +} + std::vector TestVectors::GetIntVector() { std::vector vec; diff --git a/tests/STL/STL.cs b/tests/STL/STL.cs index 1aea1ed7..d87e2d70 100644 --- a/tests/STL/STL.cs +++ b/tests/STL/STL.cs @@ -13,6 +13,7 @@ namespace CppSharp.Tests public override void Preprocess(Driver driver, ASTContext ctx) { + ctx.SetClassAsValueType("IntWrapperValueType"); } public static void Main(string[] args) diff --git a/tests/STL/STL.h b/tests/STL/STL.h index b67e5b2e..3a344fc2 100644 --- a/tests/STL/STL.h +++ b/tests/STL/STL.h @@ -1,10 +1,30 @@ #include "../Tests.h" #include +struct DLL_API IntWrapper +{ + int Value; +}; + +struct DLL_API IntWrapperValueType +{ + int Value; +}; + struct DLL_API TestVectors { + TestVectors(); std::vector GetIntVector(); int SumIntVector(std::vector& vec); - + + // Should get mapped to List std::vector IntVector; + // Should get mapped to List + std::vector IntPtrVector; + // Should get mapped to List + std::vector IntWrapperVector; + // Should get mapped to List + std::vector IntWrapperPtrVector; + // Should get mapped to List + std::vector IntWrapperValueTypeVector; }; From a72c43fd2fe7c2ce1713cecdb072b7f9ee269a71 Mon Sep 17 00:00:00 2001 From: Elias Holzer Date: Mon, 28 Apr 2014 15:18:58 +0200 Subject: [PATCH 2/2] Added marshaling code for std::ostream using a System.TextWriter to CLI backend. --- include/CppSharp.h | 79 +++++++++++++++++++++++++++++++ src/Generator/Types/Std/Stdlib.cs | 19 ++++++++ tests/STL/STL.Tests.cs | 17 +++++-- tests/STL/STL.h | 9 ++++ 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/include/CppSharp.h b/include/CppSharp.h index 9941a936..f84c1378 100644 --- a/include/CppSharp.h +++ b/include/CppSharp.h @@ -9,7 +9,9 @@ #pragma once #include +#include #include +#include public interface class ICppInstance { @@ -212,3 +214,80 @@ namespace clix { } } // namespace clix + +// std::ostream marshaling using a System::IO::TextWriter +namespace msclr { + namespace interop { + namespace details { + class text_writer_streambuf : public std::streambuf + { + public: + text_writer_streambuf(const gcroot & tw) + : std::streambuf() + { + m_tw = tw; + } + ~text_writer_streambuf() + { + m_tw->Flush(); + } + int_type overflow(int_type ch) + { + if (traits_type::not_eof(ch)) + { + auto c = traits_type::to_char_type(ch); + xsputn(&c, 1); + } + return traits_type::not_eof(ch); + } + std::streamsize xsputn(const char *_Ptr, std::streamsize _Count) + { + auto s = gcnew System::String(_Ptr, 0, _Count, System::Text::Encoding::UTF8); + m_tw->Write(s); + return _Count; + } + private: + gcroot m_tw; + }; + + class text_writer_ostream : public std::ostream { + public: + text_writer_ostream(const gcroot & s) : + std::ios(), + std::ostream(0), + m_sbuf(s) + { + init(&m_sbuf); + } + private: + text_writer_streambuf m_sbuf; + }; + } + + template<> + ref class context_node : public context_node_base + { + private: + std::ostream* toPtr; + public: + context_node(std::ostream*& toObject, System::IO::TextWriter^ fromObject) + { + // (Step 4) Initialize toPtr to the appropriate empty value. + toPtr = new details::text_writer_ostream(fromObject); + // (Step 5) Insert conversion logic here. + // (Step 6) Set toObject to the converted parameter. + toObject = toPtr; + } + ~context_node() + { + this->!context_node(); + } + protected: + !context_node() + { + // (Step 7) Clean up native resources. + delete toPtr; + } + }; + } +} // namespace msclr diff --git a/src/Generator/Types/Std/Stdlib.cs b/src/Generator/Types/Std/Stdlib.cs index 14a88abd..f06cfcd4 100644 --- a/src/Generator/Types/Std/Stdlib.cs +++ b/src/Generator/Types/Std/Stdlib.cs @@ -293,4 +293,23 @@ namespace CppSharp.Types.Std throw new System.NotImplementedException(); } } + + [TypeMap("std::ostream")] + public class OStream : TypeMap + { + public override string CLISignature(CLITypePrinterContext ctx) + { + return "System::IO::TextWriter^"; + } + + public override void CLIMarshalToNative(MarshalContext ctx) + { + var marshal = ctx.MarshalToNative as CLIMarshalManagedToNativePrinter; + marshal.ArgumentPrefix.Write("*"); + var marshalCtxName = string.Format("ctx_{0}", ctx.Parameter.Name); + ctx.SupportBefore.WriteLine("msclr::interop::marshal_context {0};", marshalCtxName); + ctx.Return.Write("{0}.marshal_as({1})", + marshalCtxName, ctx.Parameter.Name); + } + } } diff --git a/tests/STL/STL.Tests.cs b/tests/STL/STL.Tests.cs index c8f6a961..b3fd19ed 100644 --- a/tests/STL/STL.Tests.cs +++ b/tests/STL/STL.Tests.cs @@ -1,10 +1,10 @@ -using System; +using CppSharp.Utils; +using NUnit.Framework; +using STL; using System.Collections.Generic; +using System.IO; using System.Linq; -using CppSharp.Utils; -using NUnit.Framework; using System.Runtime.InteropServices; -using STL; public class STLTests : GeneratorTestFixture { @@ -47,5 +47,14 @@ public class STLTests : GeneratorTestFixture for (int i = 0; i < 3; i++) Assert.AreEqual(i, valueTypeWrapperList[i].Value); } + + [Test] + public void TestOStream() + { + const string testString = "hello wörld"; + var stringWriter = new StringWriter(); + OStreamTest.WriteToOStream(stringWriter, testString); + Assert.AreEqual(testString, stringWriter.ToString()); + } } \ No newline at end of file diff --git a/tests/STL/STL.h b/tests/STL/STL.h index 3a344fc2..e9c04dea 100644 --- a/tests/STL/STL.h +++ b/tests/STL/STL.h @@ -1,5 +1,6 @@ #include "../Tests.h" #include +#include struct DLL_API IntWrapper { @@ -28,3 +29,11 @@ struct DLL_API TestVectors // Should get mapped to List std::vector IntWrapperValueTypeVector; }; + +struct DLL_API OStreamTest +{ + static void WriteToOStream(std::ostream& stream, const char* s) + { + stream << s; + }; +}; \ No newline at end of file