std::vector<T> wrapper improvements for .NET 2 implementing IEnumerable<T>

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@11156 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2009-03-18 23:30:57 +00:00
commit 6975ecd65c
3 changed files with 93 additions and 17 deletions

View file

@ -1,6 +1,16 @@
Version 1.3.39 (in progress) Version 1.3.39 (in progress)
============================ ============================
2008-03-18: wsfulton
[C#] std::vector<T> wrapper improvements for .NET 2 and also providing the
necessary machinery to use the std::vector<T> wrappers with more advanced features such
as LINQ - the C# proxy class now derives from IEnumerable<>. The default is now to
generate code requiring .NET 2 as a minimum, although the C# code can be compiled
for .NET 1 by defining the SWIG_DOTNET_1 C# preprocessor constant. See the
std_vector.i file for more details.
*** POTENTIAL INCOMPATIBILITY ***
2008-03-12: wsfulton 2008-03-12: wsfulton
[Ruby] Fix #2676738 SWIG generated symbol name clashes. [Ruby] Fix #2676738 SWIG generated symbol name clashes.

View file

@ -82,14 +82,17 @@ public class li_std_vector_runme {
} catch (ArgumentException) { } catch (ArgumentException) {
} }
} }
#if SWIG_DOTNET_1
{ {
// runtime check that 2D arrays fail
double[,] outputarray = new double[collectionSize,collectionSize]; double[,] outputarray = new double[collectionSize,collectionSize];
try { try {
vect.CopyTo(outputarray); vect.CopyTo(outputarray);
throw new Exception("CopyTo (5) test failed"); throw new Exception("CopyTo (5a) test failed");
} catch (ArgumentException) { } catch (ArgumentException) {
} }
} }
#endif
{ {
StructVector inputvector = new StructVector(); StructVector inputvector = new StructVector();
int arrayLen = 10; int arrayLen = 10;
@ -154,6 +157,9 @@ public class li_std_vector_runme {
throw new Exception("ICollection constructor null test failed"); throw new Exception("ICollection constructor null test failed");
} catch (ArgumentNullException) { } catch (ArgumentNullException) {
} }
{
myDoubleVector = new DoubleVector() { 123.4, 567.8, 901.2 };
}
// IndexOf() test // IndexOf() test
for (int i=0; i<collectionSize; i++) { for (int i=0; i<collectionSize; i++) {
@ -187,11 +193,22 @@ public class li_std_vector_runme {
throw new Exception("Repeat count test failed"); throw new Exception("Repeat count test failed");
// Also tests enumerator // Also tests enumerator
System.Collections.IEnumerator myEnumerator = dv.GetEnumerator(); {
while ( myEnumerator.MoveNext() ) { System.Collections.IEnumerator myEnumerator = dv.GetEnumerator();
if ((double)myEnumerator.Current != 77.7) while ( myEnumerator.MoveNext() ) {
throw new Exception("Repeat test failed"); if ((double)myEnumerator.Current != 77.7)
throw new Exception("Repeat (1) test failed");
}
} }
#if !SWIG_DOTNET_1
{
System.Collections.Generic.IEnumerator<double> myEnumerator = dv.GetEnumerator();
while ( myEnumerator.MoveNext() ) {
if (myEnumerator.Current != 77.7)
throw new Exception("Repeat (2) test failed");
}
}
#endif
} }
{ {
@ -516,6 +533,13 @@ public class li_std_vector_runme {
li_std_vector.halve_in_place(dvec); li_std_vector.halve_in_place(dvec);
} }
// Dispose()
{
using (StructVector vs = new StructVector() { new Struct(0.0), new Struct(11.1) } )
using (DoubleVector vd = new DoubleVector() { 0.0, 11.1 } ) {
}
}
// More wrapped methods // More wrapped methods
{ {
RealVector v0 = li_std_vector.vecreal(new RealVector()); RealVector v0 = li_std_vector.vecreal(new RealVector());

View file

@ -6,15 +6,22 @@
* *
* SWIG typemaps for std::vector * SWIG typemaps for std::vector
* C# implementation * C# implementation
* The C# wrapper is made to look and feel like a typesafe C# System.Collections.ArrayList * The C# wrapper is made to look and feel like a C# System.Collections.Generic.List<> collection.
* All the methods in IList are defined, but we don't derive from IList as this is a typesafe collection. * For .NET 1 compatibility, define SWIG_DOTNET_1 when compiling the C# code; then the C# wrapper is
* Warning: heavy macro usage in this file. Use swig -E to get a sane view on the real file contents! * made to look and feel like a typesafe C# System.Collections.ArrayList. All the methods in IList
* are defined, but we don't derive from IList as this is a typesafe collection and the C++ operator==
* must always be defined for the collection type (which it isn't).
* *
* Very often the C# generated code will not compile as the C++ template type is not the same as the C# * Very often the C# generated code will not compile as the C++ template type is not the same as the C#
* proxy type, so use the SWIG_STD_VECTOR_SPECIALIZE or SWIG_STD_VECTOR_SPECIALIZE_MINIMUM macro, eg * proxy type, so use the SWIG_STD_VECTOR_SPECIALIZE or SWIG_STD_VECTOR_SPECIALIZE_MINIMUM macro, eg
* *
* SWIG_STD_VECTOR_SPECIALIZE_MINIMUM(Klass, SomeNamespace::Klass) * SWIG_STD_VECTOR_SPECIALIZE_MINIMUM(Klass, SomeNamespace::Klass)
* %template(VectKlass) std::vector<SomeNamespace::Klass>; * %template(VectKlass) std::vector<SomeNamespace::Klass>;
*
* Note that IEnumerable<> is implemented in the proxy class which is useful for using LINQ with
* C++ std::vector wrappers.
*
* Warning: heavy macro usage in this file. Use swig -E to get a sane view on the real file contents!
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
// Warning: Use the typemaps here in the expectation that the macros they are in will change name. // Warning: Use the typemaps here in the expectation that the macros they are in will change name.
@ -25,7 +32,7 @@
// MACRO for use within the std::vector class body // MACRO for use within the std::vector class body
// CSTYPE and CTYPE respectively correspond to the types in the cstype and ctype typemaps // CSTYPE and CTYPE respectively correspond to the types in the cstype and ctype typemaps
%define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CONST_REFERENCE_TYPE, CSTYPE, CTYPE...) %define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CONST_REFERENCE_TYPE, CSTYPE, CTYPE...)
%typemap(csinterfaces) std::vector<CTYPE > "IDisposable, System.Collections.IEnumerable"; %typemap(csinterfaces) std::vector<CTYPE > "IDisposable, System.Collections.IEnumerable\n#if !SWIG_DOTNET_1\n , System.Collections.Generic.IEnumerable<CSTYPE>\n#endif\n";
%typemap(cscode) std::vector<CTYPE > %{ %typemap(cscode) std::vector<CTYPE > %{
public $csclassname(System.Collections.ICollection c) : this() { public $csclassname(System.Collections.ICollection c) : this() {
if (c == null) if (c == null)
@ -79,15 +86,30 @@
} }
} }
public void CopyTo(System.Array array) { #if SWIG_DOTNET_1
public void CopyTo(System.Array array)
#else
public void CopyTo(CSTYPE[] array)
#endif
{
CopyTo(0, array, 0, this.Count); CopyTo(0, array, 0, this.Count);
} }
public void CopyTo(System.Array array, int arrayIndex) { #if SWIG_DOTNET_1
public void CopyTo(System.Array array, int arrayIndex)
#else
public void CopyTo(CSTYPE[] array, int arrayIndex)
#endif
{
CopyTo(0, array, arrayIndex, this.Count); CopyTo(0, array, arrayIndex, this.Count);
} }
public void CopyTo(int index, System.Array array, int arrayIndex, int count) { #if SWIG_DOTNET_1
public void CopyTo(int index, System.Array array, int arrayIndex, int count)
#else
public void CopyTo(int index, CSTYPE[] array, int arrayIndex, int count)
#endif
{
if (array == null) if (array == null)
throw new ArgumentNullException("array"); throw new ArgumentNullException("array");
if (index < 0) if (index < 0)
@ -97,14 +119,19 @@
if (count < 0) if (count < 0)
throw new ArgumentOutOfRangeException("count", "Value is less than zero"); throw new ArgumentOutOfRangeException("count", "Value is less than zero");
if (array.Rank > 1) if (array.Rank > 1)
throw new ArgumentException("Multi dimensional array."); throw new ArgumentException("Multi dimensional array.", "array");
if (index+count > this.Count || arrayIndex+count > array.Length) if (index+count > this.Count || arrayIndex+count > array.Length)
throw new ArgumentException("Number of elements to copy is too large."); throw new ArgumentException("Number of elements to copy is too large.");
for (int i=0; i<count; i++) for (int i=0; i<count; i++)
array.SetValue(getitemcopy(index+i), arrayIndex+i); array.SetValue(getitemcopy(index+i), arrayIndex+i);
} }
// Type-safe version of IEnumerable.GetEnumerator #if !SWIG_DOTNET_1
System.Collections.Generic.IEnumerator<CSTYPE> System.Collections.Generic.IEnumerable<CSTYPE>.GetEnumerator() {
return new $csclassnameEnumerator(this);
}
#endif
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return new $csclassnameEnumerator(this); return new $csclassnameEnumerator(this);
} }
@ -118,7 +145,11 @@
/// whenever the collection is modified. This has been done for changes in the size of the /// whenever the collection is modified. This has been done for changes in the size of the
/// collection but not when one of the elements of the collection is modified as it is a bit /// collection but not when one of the elements of the collection is modified as it is a bit
/// tricky to detect unmanaged code that modifies the collection under our feet. /// tricky to detect unmanaged code that modifies the collection under our feet.
public sealed class $csclassnameEnumerator : System.Collections.IEnumerator { public sealed class $csclassnameEnumerator : System.Collections.IEnumerator
#if !SWIG_DOTNET_1
, System.Collections.Generic.IEnumerator<CSTYPE>
#endif
{
private $csclassname collectionRef; private $csclassname collectionRef;
private int currentIndex; private int currentIndex;
private object currentObject; private object currentObject;
@ -170,6 +201,13 @@
throw new InvalidOperationException("Collection modified."); throw new InvalidOperationException("Collection modified.");
} }
} }
#if !SWIG_DOTNET_1
public void Dispose() {
currentIndex = -1;
currentObject = null;
}
#endif
} }
%} %}
@ -293,6 +331,7 @@ SWIG_STD_VECTOR_MINIMUM_INTERNAL(const value_type&, CSTYPE, CTYPE)
// Extra methods added to the collection class if operator== is defined for the class being wrapped // Extra methods added to the collection class if operator== is defined for the class being wrapped
// CSTYPE and CTYPE respectively correspond to the types in the cstype and ctype typemaps // CSTYPE and CTYPE respectively correspond to the types in the cstype and ctype typemaps
// The class will then implement IList<>, which adds extra functionality
%define SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(CSTYPE, CTYPE...) %define SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(CSTYPE, CTYPE...)
%extend { %extend {
bool Contains(const value_type& value) { bool Contains(const value_type& value) {
@ -312,10 +351,13 @@ SWIG_STD_VECTOR_MINIMUM_INTERNAL(const value_type&, CSTYPE, CTYPE)
index = (int)(self->rend() - 1 - rit); index = (int)(self->rend() - 1 - rit);
return index; return index;
} }
void Remove(const value_type& value) { bool Remove(const value_type& value) {
std::vector<CTYPE >::iterator it = std::find(self->begin(), self->end(), value); std::vector<CTYPE >::iterator it = std::find(self->begin(), self->end(), value);
if (it != self->end()) if (it != self->end()) {
self->erase(it); self->erase(it);
return true;
}
return false;
} }
} }
%enddef %enddef