Browse Source

Merge pull request #236 from azeno/stl-typemaps

STL type maps
pull/237/head
João Matos 11 years ago
parent
commit
20bd612ced
  1. 79
      include/CppSharp.h
  2. 5
      src/Generator/Generators/CLI/CLITypePrinter.cs
  3. 5
      src/Generator/Types/ITypePrinter.cs
  4. 46
      src/Generator/Types/Std/Stdlib.cs
  5. 46
      tests/STL/STL.Tests.cs
  6. 11
      tests/STL/STL.cpp
  7. 1
      tests/STL/STL.cs
  8. 29
      tests/STL/STL.h

79
include/CppSharp.h

@ -9,7 +9,9 @@ @@ -9,7 +9,9 @@
#pragma once
#include <string>
#include <ostream>
#include <vcclr.h>
#include <msclr/marshal.h>
public interface class ICppInstance
{
@ -212,3 +214,80 @@ namespace clix { @@ -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<System::IO::TextWriter^> & 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<System::IO::TextWriter^> m_tw;
};
class text_writer_ostream : public std::ostream {
public:
text_writer_ostream(const gcroot<System::IO::TextWriter^> & s) :
std::ios(),
std::ostream(0),
m_sbuf(s)
{
init(&m_sbuf);
}
private:
text_writer_streambuf m_sbuf;
};
}
template<>
ref class context_node<std::ostream*, System::IO::TextWriter^> : 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

5
src/Generator/Generators/CLI/CLITypePrinter.cs

@ -284,7 +284,10 @@ namespace CppSharp.Generators.CLI @@ -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)

5
src/Generator/Types/ITypePrinter.cs

@ -39,7 +39,10 @@ namespace CppSharp.Types @@ -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());
}
}

46
src/Generator/Types/Std/Stdlib.cs

@ -1,4 +1,5 @@ @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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();
@ -276,4 +293,23 @@ namespace CppSharp.Types.Std @@ -276,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<std::ostream*>({1})",
marshalCtxName, ctx.Parameter.Name);
}
}
}

46
tests/STL/STL.Tests.cs

@ -1,7 +1,10 @@ @@ -1,7 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using CppSharp.Utils;
using CppSharp.Utils;
using NUnit.Framework;
using STL;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
public class STLTests : GeneratorTestFixture
{
@ -15,6 +18,43 @@ public class STLTests : GeneratorTestFixture @@ -15,6 +18,43 @@ public class STLTests : GeneratorTestFixture
var list = vectors.GetIntVector();
Assert.True(list.SequenceEqual(new List<int> { 2, 3, 4 }));
var ptrList = vectors.IntPtrVector;
var intList = ptrList.Select(ptr => Marshal.ReadInt32(ptr));
Assert.True(intList.SequenceEqual(new List<int> { 2, 3, 4 }));
var wrapperList = new List<IntWrapper>();
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<IntWrapperValueType>();
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);
}
[Test]
public void TestOStream()
{
const string testString = "hello wörld";
var stringWriter = new StringWriter();
OStreamTest.WriteToOStream(stringWriter, testString);
Assert.AreEqual(testString, stringWriter.ToString());
}
}

11
tests/STL/STL.cpp

@ -1,5 +1,16 @@ @@ -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<int> TestVectors::GetIntVector()
{
std::vector<int> vec;

1
tests/STL/STL.cs

@ -13,6 +13,7 @@ namespace CppSharp.Tests @@ -13,6 +13,7 @@ namespace CppSharp.Tests
public override void Preprocess(Driver driver, ASTContext ctx)
{
ctx.SetClassAsValueType("IntWrapperValueType");
}
public static void Main(string[] args)

29
tests/STL/STL.h

@ -1,10 +1,39 @@ @@ -1,10 +1,39 @@
#include "../Tests.h"
#include <vector>
#include <ostream>
struct DLL_API IntWrapper
{
int Value;
};
struct DLL_API IntWrapperValueType
{
int Value;
};
struct DLL_API TestVectors
{
TestVectors();
std::vector<int> GetIntVector();
int SumIntVector(std::vector<int>& vec);
// Should get mapped to List<int>
std::vector<int> IntVector;
// Should get mapped to List<IntPtr>
std::vector<int*> IntPtrVector;
// Should get mapped to List<IntWrapper>
std::vector<IntWrapper> IntWrapperVector;
// Should get mapped to List<IntWrapper>
std::vector<IntWrapper*> IntWrapperPtrVector;
// Should get mapped to List<IntWrapperValueType>
std::vector<IntWrapperValueType> IntWrapperValueTypeVector;
};
struct DLL_API OStreamTest
{
static void WriteToOStream(std::ostream& stream, const char* s)
{
stream << s;
};
};
Loading…
Cancel
Save