From: William S F. <ws...@fu...> - 2007-03-22 22:10:11
|
riemann tolow wrote: > Hi, > > I am trying to write Java/C# typemaps for std::vector. They should map the > vector into the language arrays. I know that there is an overhead of copying > between the types but that's ok for me. I intend to use the std::vector > wrapper generated by SWIG to do the marshal from/to array. > > The problem I am facing is that there is no way to insert code before the > $jnicall/$imcall or after (unless uisng javaout/csout). The typemaps > javain/csin are only one liner code that is embedded in the calls > $jnicall/$imcall. > > For example in C#: > %include std_vector.i > %typemap(cstype) std::vector<double>"double[]"; > %typemap(csin) std::vector<double> "DoubleVector.getCPtr(new > DoubleVector($csinput))"; > %template(DoubleVector) std::vector<double> > > If the vector is used as an output argument, there is no way to copy back > the result into the array (assume there is a "&" and "ref") > > Am I doing it wrong? Is there some other way to do it? I suppose using the > "in" typemap give better possibilities but this requires using the native > API of the language. > I'm afraid that the typemaps containing C#/Java code do not allow for temporary variables for parameters. For Java, use helper methods in the javain typemap, eg see the CheckForNaN example in Java.html. For C# this is a known problem for C# ref and out types. We need to modify SWIG to work better with ref and out values. What I propose is making changes to the csin/javain typemaps addin in two new optional attributes, 'pre' and 'post'. The idea is that the 'pre' attribute contains code that gets added before the $imcall and 'post' contains code executed after the $imcall call. Let's presume you are wrapping: void f(std::vector<double> & v); %template(DoubleVector) std::vector<double>; You probably want the C# code to look like this: public static bool f(double[] v) { DoubleVector dv = new DoubleVector(); foreach (double d in v) { dv.Add(d); } bool ret = examplePINVOKE.f(DoubleVector.getCPtr(dv)); if (examplePINVOKE.SWIGPendingException.Pending) throw examplePINVOKE.SWIGPendingException.Retrieve(); for (int i=0; i<v.Length; ++i) { v[i] = dv[i]; } return ret; } I can't see this being possible because it splits the current csout bool typemap (it inserts code between the "bool ret=..." and "return ret". Instead we could generate this: public static bool f(double[] v) { DoubleVector dv = new DoubleVector(); foreach (double d in v) { dv.Add(d); } try { bool ret = examplePINVOKE.f(DoubleVector.getCPtr(dv)); if (examplePINVOKE.SWIGPendingException.Pending) throw examplePINVOKE.SWIGPendingException.Retrieve(); return ret; } finally { for (int i=0; i<v.Length; ++i) { v[i] = dv[i]; } } } Current csin typemap: %typemap(csin) SWIGTYPE & "$csclassname.getCPtr($csinput)" Proposed new attributes in the csin typemap: %typemap(csin, pre=" DoubleVector dv = new DoubleVector();\n foreach (double d in $input) { \n dv.Add(d);\n }" post=" for (int i=0; i<$input.Length; ++i) {\n $input[i] = dv[i];\n }" ) std::vector<double> & "$csclassname.getCPtr(dv)" It looks a bit horrible formatted in this email, but is simply: %typemap(csin, pre="...code...", post="...code...") std::vector<double>& "$csclassname.getCPtr(dv)" and uses \n for line delimeters. The variable names will probably need $argnum or $input adding to them in the typemap, so that there are no duplicate variable names in when using a 2nd parameter of the same type. Fixing this issue is a bit overdue and I'll probably code it up in the next few days unless you see any problems. William |