Add C# array typemaps provided by Antti Karanta.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10872 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2008-09-18 20:32:28 +00:00
parent 1ebd0466f5
commit 09915566bc
12 changed files with 428 additions and 8 deletions

View File

@ -1,6 +1,12 @@
Version 1.3.37 (in progress)
=============================
2008-09-17: wsfulton
[C#] Added C# array typemaps provided by Antti Karanta.
The arrays provide a way to use MarshalAs(UnmanagedType.LPArray)
and pinning the array using 'fixed'. See arrays_csharp.i library file
for details.
2008-09-18: wsfulton
Document the optional module attribute in the %import directive,
see Modules.html. Add a warning for Python wrappers when the
@ -49,10 +55,10 @@ Version 1.3.37 (in progress)
- some minor aesthetic changes.
2008-09-12: bhy
[Python] Python 3.0 support branch merged into SWIG trunk. Thanks
Google Summer of Code 2008 for support this project! By default
[Python] Python 3.0 support branch merged into SWIG trunk. Thanks to
Google Summer of Code 2008 for supporting this project! By default
SWIG will generate interface files compatible with both Python 2.x
and 3.0. And there's also some Python 3 new features could be
and 3.0. And there's also some Python 3 new features that can be
enabled by passing a "-py3" command line option to SWIG. These
features are:
@ -64,7 +70,7 @@ Version 1.3.37 (in progress)
- Abstract base class support
For details of Python 3 support and these features, please see the
"Python 3 Support" section in the "SWIG and Python" chapter of SWIG
"Python 3 Support" section in the "SWIG and Python" chapter of the SWIG
documentation.
The "-apply" command line option and support of generating codes

View File

@ -201,7 +201,12 @@ $jnicall -> $imcall
<li>
<p>
Unlike the "javain" typemap, the "csin" typemap does not support the 'pgcpp' attribute as the C# module does not have a premature garbage collection prevention parameter. The "csin" typemap supports an additional optional attribute called 'cshin'. It should contain the parameter type and name whenever a <a href="Java.html#java_constructor_helper_function">constructor helper function</a> is generated due to the 'pre' or 'post' attributes. Note that 'pre', 'post' and 'cshin' attributes are not used for marshalling the property set. Please see the <a href="#csharp_date_marshalling">Date marshalling example</a> and <a href="#CSharp.html#csharp_date_properties">Date marshalling of properties example</a> for further understanding.
Unlike the "javain" typemap, the "csin" typemap does not support the 'pgcpp' attribute as the C# module does not have a premature garbage collection prevention parameter.
The "csin" typemap supports additional optional attributes called 'cshin' and 'terminator'.
The 'cshin' attribute should contain the parameter type and name whenever a <a href="Java.html#java_constructor_helper_function">constructor helper function</a> is generated due to the 'pre' or 'post' attributes.
The 'terminator' attribute normally just contains a closing brace for when the 'pre' attribute contains an opening brace, such as when a C# <tt>using</tt> or <tt>fixed</tt> block is started.
Note that 'pre', 'post', 'terminator' and 'cshin' attributes are not used for marshalling the property set.
Please see the <a href="#csharp_date_marshalling">Date marshalling example</a> and <a href="#CSharp.html#csharp_date_properties">Date marshalling of properties example</a> for further understanding of these "csin" applicable attributes.
</p>
</li>

View File

@ -0,0 +1,20 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
SRCS = example.c
TARGET = example
INTERFACE = example.i
SWIGOPT =
CSHARPSRCS = *.cs
CSHARPFLAGS= -nologo -unsafe -out:runme.exe
all:: csharp
csharp::
$(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \
SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' csharp
$(MAKE) -f $(TOP)/Makefile CSHARPSRCS='$(CSHARPSRCS)' CSHARPFLAGS='$(CSHARPFLAGS)' csharp_compile
clean::
$(MAKE) -f $(TOP)/Makefile csharp_clean
check: all

View File

@ -0,0 +1,22 @@
/* File : example.c */
#include "example.h"
/* copy the contents of the first array to the second */
void myArrayCopy( int* sourceArray, int* targetArray, int nitems ) {
int i;
for ( i = 0; i < nitems; i++ ) {
targetArray[ i ] = sourceArray[ i ];
}
}
/* swap the contents of the two arrays */
void myArraySwap( int* array1, int* array2, int nitems ) {
int i, temp;
for ( i = 0; i < nitems; i++ ) {
temp = array1[ i ];
array1[ i ] = array2[ i ];
array2[ i ] = temp;
}
}

View File

@ -0,0 +1,4 @@
void myArrayCopy( int *sourceArray, int* targetArray, int nitems );
void myArraySwap( int* array1, int* array2, int nitems );

View File

@ -0,0 +1,42 @@
/* File : example.i */
%module example
%include "arrays_csharp.i"
%apply int INPUT[] { int* sourceArray }
%apply int OUTPUT[] { int* targetArray }
%apply int INOUT[] { int* array1 }
%apply int INOUT[] { int* array2 }
%include "example.h"
%clear int* sourceArray;
%clear int* targetArray;
%clear int* array1;
%clear int* array2;
// Below replicates the above array handling but this time using the pinned (fixed) array typemaps
%csmethodmodifiers "public unsafe";
%apply int FIXED[] { int* sourceArray }
%apply int FIXED[] { int* targetArray }
%inline %{
void myArrayCopyUsingFixedArrays( int *sourceArray, int* targetArray, int nitems ) {
myArrayCopy(sourceArray, targetArray, nitems);
}
%}
%apply int FIXED[] { int* array1 }
%apply int FIXED[] { int* array2 }
%inline %{
void myArraySwapUsingFixedArrays( int* array1, int* array2, int nitems ) {
myArraySwap(array1, array2, nitems);
}
%}

View File

@ -0,0 +1,43 @@
using System;
public class runme
{
static void Main()
{
int[] source = { 1, 2, 3 };
int[] target = new int[ source.Length ];
example.myArrayCopy( source, target, target.Length );
Console.WriteLine( "Contents of copy target array using default marshaling" );
PrintArray( target );
target = new int[ source.Length ];
example.myArrayCopyUsingFixedArrays( source, target, target.Length );
Console.WriteLine( "Contents of copy target array using fixed arrays" );
PrintArray( target );
target = new int[] { 4, 5, 6 };
example.myArraySwap( source, target, target.Length );
Console.WriteLine( "Contents of arrays after swapping using default marshaling" );
PrintArray( source );
PrintArray( target );
source = new int[] { 1, 2, 3 };
target = new int[] { 4, 5, 6 };
example.myArraySwapUsingFixedArrays( source, target, target.Length );
Console.WriteLine( "Contents of arrays after swapping using fixed arrays" );
PrintArray( source );
PrintArray( target );
}
static void PrintArray( int[] a )
{
foreach ( int i in a )
Console.Write( "{0} ", i );
Console.WriteLine();
}
}

View File

@ -1,4 +1,5 @@
# see top-level Makefile.in
arrays
callback
class
enum

View File

@ -21,13 +21,17 @@ CPP_TEST_CASES = \
enum_thorough_typesafe \
exception_partial_info
CUSTOM_TEST_CASES = intermediary_classname
CUSTOM_TEST_CASES = \
csharp_lib_arrays \
intermediary_classname
include $(srcdir)/../common.mk
# Overridden variables here
SWIGOPT += -namespace $*Namespace $(SWIGOPTSPECIAL)
CSHARPFLAGSSPECIAL =
# Rules for the different types of tests
%.cpptest:
$(setup)
@ -47,6 +51,8 @@ SWIGOPT += -namespace $*Namespace $(SWIGOPTSPECIAL)
# Rules for custom tests
intermediary_classname.customtest:
$(MAKE) intermediary_classname.cpptest SWIGOPTSPECIAL="-dllimport intermediary_classname"
csharp_lib_arrays.customtest:
$(MAKE) csharp_lib_arrays.cpptest CSHARPFLAGSSPECIAL="-unsafe"
# Makes a directory for the testcase if it does not exist
setup = \
@ -65,14 +71,14 @@ setup = \
run_testcase = \
if [ -f $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then ( \
$(MAKE) -f $*/$(top_builddir)/$(EXAMPLES)/Makefile \
CSHARPFLAGS='-nologo -out:$*_runme.exe' \
CSHARPFLAGS='-nologo $(CSHARPFLAGSSPECIAL) -out:$*_runme.exe' \
CSHARPSRCS='`$(CSHARPCYGPATH_W) $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX)` \
$*$(CSHARPPATHSEPARATOR)*.cs' csharp_compile && \
env LD_LIBRARY_PATH="$*:$$LD_LIBRARY_PATH" PATH="$*:$$PATH" SHLIB_PATH="$*:$$SHLIB_PATH" $(RUNTOOL) $(INTERPRETER) $*_runme.exe; ) \
else ( \
cd $* && \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile \
CSHARPFLAGS='-nologo -t:module -out:$*.netmodule' \
CSHARPFLAGS='-nologo $(CSHARPFLAGSSPECIAL) -t:module -out:$*.netmodule' \
CSHARPSRCS='*.cs' csharp_compile; ); \
fi;

View File

@ -0,0 +1,70 @@
using System;
using csharp_lib_arraysNamespace;
public class runme
{
static void Main()
{
{
int[] source = { 1, 2, 3, 4, 5 };
int[] target = new int[ source.Length ];
csharp_lib_arrays.myArrayCopy( source, target, target.Length );
CompareArrays(source, target);
}
{
int[] source = { 1, 2, 3, 4, 5 };
int[] target = new int[ source.Length ];
csharp_lib_arrays.myArrayCopyUsingFixedArrays( source, target, target.Length );
CompareArrays(source, target);
}
{
int[] source = { 1, 2, 3, 4, 5 };
int[] target = new int[] { 6, 7, 8, 9, 10 };
csharp_lib_arrays.myArraySwap( source, target, target.Length );
for (int i=0; i<target.Length; ++i)
target[i] += 5;
CompareArrays(source, target);
}
{
int[] source = { 1, 2, 3, 4, 5 };
int[] target = new int[] { 6, 7, 8, 9, 10 };
csharp_lib_arrays.myArraySwapUsingFixedArrays( source, target, target.Length );
for (int i=0; i<target.Length; ++i)
target[i] += 5;
CompareArrays(source, target);
}
}
static void CompareArrays( int[] a, int[] b )
{
if (a.Length != b.Length)
throw new Exception("size mismatch");
for(int i=0; i<a.Length; ++i) {
if (a[i] != b[i]) {
Console.Error.WriteLine("a:");
PrintArray(a);
Console.Error.WriteLine("b:");
PrintArray(b);
throw new Exception("element mismatch");
}
}
}
static void PrintArray( int[] a )
{
foreach ( int i in a )
Console.Error.Write( "{0} ", i );
Console.Error.WriteLine();
}
}

View File

@ -0,0 +1,61 @@
%module csharp_lib_arrays
%include "arrays_csharp.i"
%apply int INPUT[] { int* sourceArray }
%apply int OUTPUT[] { int* targetArray }
%apply int INOUT[] { int* array1 }
%apply int INOUT[] { int* array2 }
%inline %{
/* copy the contents of the first array to the second */
void myArrayCopy( int* sourceArray, int* targetArray, int nitems ) {
int i;
for ( i = 0; i < nitems; i++ ) {
targetArray[ i ] = sourceArray[ i ];
}
}
/* swap the contents of the two arrays */
void myArraySwap( int* array1, int* array2, int nitems ) {
int i, temp;
for ( i = 0; i < nitems; i++ ) {
temp = array1[ i ];
array1[ i ] = array2[ i ];
array2[ i ] = temp;
}
}
%}
%clear int* sourceArray;
%clear int* targetArray;
%clear int* array1;
%clear int* array2;
// Below replicates the above array handling but this time using the pinned (fixed) array typemaps
%csmethodmodifiers myArrayCopyUsingFixedArrays "public unsafe";
%csmethodmodifiers myArraySwapUsingFixedArrays "public unsafe";
%apply int FIXED[] { int* sourceArray }
%apply int FIXED[] { int* targetArray }
%inline %{
void myArrayCopyUsingFixedArrays( int *sourceArray, int* targetArray, int nitems ) {
myArrayCopy(sourceArray, targetArray, nitems);
}
%}
%apply int FIXED[] { int* array1 }
%apply int FIXED[] { int* array2 }
%inline %{
void myArraySwapUsingFixedArrays( int* array1, int* array2, int nitems ) {
myArraySwap(array1, array2, nitems);
}
%}

140
Lib/csharp/arrays_csharp.i Normal file
View File

@ -0,0 +1,140 @@
/* -----------------------------------------------------------------------------
* See the LICENSE file for information on copyright, usage and redistribution
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
*
* arrays_csharp.i
*
* This file contains a two approaches to marshaling arrays. The first uses
* default p/invoke marshaling and the second uses pinning of the arrays.
*
* Default marshalling approach
* ----------------------------
* Array typemaps using default p/invoke marshaling. The data is copied to a separately
* allocated buffer when passing over the managed-native boundary.
*
* There are separate typemaps for in, out and inout arrays to enable avoiding
* unnecessary copying.
*
* Example usage:
*
* %include "arrays_csharp.i"
* %apply int INPUT[] { int* sourceArray }
* %apply int OUTPUT[] { int* targetArray }
* void myArrayCopy( int* sourceArray, int* targetArray, int nitems );
*
* %apply int INOUT[] { int* array1, int *array2 }
* void myArraySwap( int* array1, int* array2, int nitems );
*
* If handling large arrays you should consider using the pinning array typemaps
* described next.
*
* Pinning approach
* ----------------
* Array typemaps using pinning. These typemaps pin the managed array given
* as parameter and pass a pointer to it to the c/c++ side. This is very
* efficient as no copying is done (unlike in the default array marshalling),
* but it makes garbage collection more difficult. When considering using
* these typemaps, think carefully whether you have callbacks that may cause
* the control to re-enter the managed side from within the call (and produce
* garbage for the gc) or whether other threads may produce enough garbage to
* trigger gc while the call is being executed. In those cases it may be
* wiser to use.
*
* Please note that when using fixed arrays, you have to mark your corresponding
* module class method unsafe using
* %csmethodmodifiers "public unsafe"
* (the visibility of the method is up to you).
*
* Example usage:
*
* %include "arrays_csharp.i"
* %apply int FIXED[] { int* sourceArray, int *targetArray }
* %csmethodmodifiers myArrayCopy "public unsafe";
* void myArrayCopy( int *sourceArray, int* targetArray, int nitems );
*
* ----------------------------------------------------------------------------- */
%define CSHARP_ARRAYS( CTYPE, CSTYPE )
// input only arrays
%typemap(ctype) CTYPE INPUT[] "CTYPE*"
%typemap(cstype) CTYPE INPUT[] "CSTYPE[]"
%typemap(imtype, inattributes="[In, MarshalAs(UnmanagedType.LPArray)]") CTYPE INPUT[] "CSTYPE[]"
%typemap(csin) CTYPE INPUT[] "$csinput"
%typemap(in) CTYPE INPUT[] "$1 = $input;"
%typemap(freearg) CTYPE INPUT[] ""
%typemap(argout) CTYPE INPUT[] ""
// output only arrays
%typemap(ctype) CTYPE OUTPUT[] "CTYPE*"
%typemap(cstype) CTYPE OUTPUT[] "CSTYPE[]"
%typemap(imtype, inattributes="[Out, MarshalAs(UnmanagedType.LPArray)]") CTYPE OUTPUT[] "CSTYPE[]"
%typemap(csin) CTYPE OUTPUT[] "$csinput"
%typemap(in) CTYPE OUTPUT[] "$1 = $input;"
%typemap(freearg) CTYPE OUTPUT[] ""
%typemap(argout) CTYPE OUTPUT[] ""
// inout arrays
%typemap(ctype) CTYPE INOUT[] "CTYPE*"
%typemap(cstype) CTYPE INOUT[] "CSTYPE[]"
%typemap(imtype, inattributes="[In, Out, MarshalAs(UnmanagedType.LPArray)]") CTYPE INOUT[] "CSTYPE[]"
%typemap(csin) CTYPE INOUT[] "$csinput"
%typemap(in) CTYPE INOUT[] "$1 = $input;"
%typemap(freearg) CTYPE INOUT[] ""
%typemap(argout) CTYPE INOUT[] ""
%enddef // CSHARP_ARRAYS
CSHARP_ARRAYS(signed char, sbyte)
CSHARP_ARRAYS(unsigned char, byte)
CSHARP_ARRAYS(short, short)
CSHARP_ARRAYS(unsigned short, ushort)
CSHARP_ARRAYS(int, int)
CSHARP_ARRAYS(unsigned int, uint)
// FIXME - on Unix 64 bit, long is 8 bytes but is 4 bytes on Windows 64 bit.
// How can this be handled sensibly?
// See e.g. http://www.xml.com/ldd/chapter/book/ch10.html
CSHARP_ARRAYS(long, int)
CSHARP_ARRAYS(unsigned long, uint)
CSHARP_ARRAYS(long long, long)
CSHARP_ARRAYS(unsigned long long, ulong)
CSHARP_ARRAYS(float, float)
CSHARP_ARRAYS(double, double)
%define CSHARP_ARRAYS_FIXED( CTYPE, CSTYPE )
%typemap(ctype) CTYPE FIXED[] "CTYPE*"
%typemap(imtype) CTYPE FIXED[] "IntPtr"
%typemap(cstype) CTYPE FIXED[] "CSTYPE[]"
%typemap(csin,
pre= " fixed ( CSTYPE* swig_ptrTo_$csinput = $csinput ) {",
terminator=" }")
CTYPE FIXED[] "(IntPtr)swig_ptrTo_$csinput"
%typemap(in) CTYPE FIXED[] "$1 = $input;"
%typemap(freearg) CTYPE FIXED[] ""
%typemap(argout) CTYPE FIXED[] ""
%enddef // CSHARP_ARRAYS_FIXED
CSHARP_ARRAYS_FIXED(signed char, sbyte)
CSHARP_ARRAYS_FIXED(unsigned char, byte)
CSHARP_ARRAYS_FIXED(short, short)
CSHARP_ARRAYS_FIXED(unsigned short, ushort)
CSHARP_ARRAYS_FIXED(int, int)
CSHARP_ARRAYS_FIXED(unsigned int, uint)
CSHARP_ARRAYS_FIXED(long, int)
CSHARP_ARRAYS_FIXED(unsigned long, uint)
CSHARP_ARRAYS_FIXED(long long, long)
CSHARP_ARRAYS_FIXED(unsigned long long, ulong)
CSHARP_ARRAYS_FIXED(float, float)
CSHARP_ARRAYS_FIXED(double, double)