Home | History | Annotate | Download | only in csharp
      1 /* -----------------------------------------------------------------------------
      2  * std_vector.i
      3  *
      4  * SWIG typemaps for std::vector<T>
      5  * C# implementation
      6  * The C# wrapper is made to look and feel like a C# System.Collections.Generic.List<> collection.
      7  * For .NET 1 compatibility, define SWIG_DOTNET_1 when compiling the C# code; then the C# wrapper is
      8  * made to look and feel like a typesafe C# System.Collections.ArrayList.
      9  *
     10  * Note that IEnumerable<> is implemented in the proxy class which is useful for using LINQ with
     11  * C++ std::vector wrappers. The IList<> interface is also implemented to provide enhanced functionality
     12  * whenever we are confident that the required C++ operator== is available. This is the case for when
     13  * T is a primitive type or a pointer. If T does define an operator==, then use the SWIG_STD_VECTOR_ENHANCED
     14  * macro to obtain this enhanced functionality, for example:
     15  *
     16  *   SWIG_STD_VECTOR_ENHANCED(SomeNamespace::Klass)
     17  *   %template(VectKlass) std::vector<SomeNamespace::Klass>;
     18  *
     19  * Warning: heavy macro usage in this file. Use swig -E to get a sane view on the real file contents!
     20  * ----------------------------------------------------------------------------- */
     21 
     22 // Warning: Use the typemaps here in the expectation that the macros they are in will change name.
     23 
     24 
     25 %include <std_common.i>
     26 
     27 // MACRO for use within the std::vector class body
     28 %define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CSINTERFACE, CONST_REFERENCE, CTYPE...)
     29 %typemap(csinterfaces) std::vector< CTYPE > "IDisposable, System.Collections.IEnumerable\n#if !SWIG_DOTNET_1\n    , System.Collections.Generic.CSINTERFACE<$typemap(cstype, CTYPE)>\n#endif\n";
     30 %typemap(cscode) std::vector< CTYPE > %{
     31   public $csclassname(System.Collections.ICollection c) : this() {
     32     if (c == null)
     33       throw new ArgumentNullException("c");
     34     foreach ($typemap(cstype, CTYPE) element in c) {
     35       this.Add(element);
     36     }
     37   }
     38 
     39   public bool IsFixedSize {
     40     get {
     41       return false;
     42     }
     43   }
     44 
     45   public bool IsReadOnly {
     46     get {
     47       return false;
     48     }
     49   }
     50 
     51   public $typemap(cstype, CTYPE) this[int index]  {
     52     get {
     53       return getitem(index);
     54     }
     55     set {
     56       setitem(index, value);
     57     }
     58   }
     59 
     60   public int Capacity {
     61     get {
     62       return (int)capacity();
     63     }
     64     set {
     65       if (value < size())
     66         throw new ArgumentOutOfRangeException("Capacity");
     67       reserve((uint)value);
     68     }
     69   }
     70 
     71   public int Count {
     72     get {
     73       return (int)size();
     74     }
     75   }
     76 
     77   public bool IsSynchronized {
     78     get {
     79       return false;
     80     }
     81   }
     82 
     83 #if SWIG_DOTNET_1
     84   public void CopyTo(System.Array array)
     85 #else
     86   public void CopyTo($typemap(cstype, CTYPE)[] array)
     87 #endif
     88   {
     89     CopyTo(0, array, 0, this.Count);
     90   }
     91 
     92 #if SWIG_DOTNET_1
     93   public void CopyTo(System.Array array, int arrayIndex)
     94 #else
     95   public void CopyTo($typemap(cstype, CTYPE)[] array, int arrayIndex)
     96 #endif
     97   {
     98     CopyTo(0, array, arrayIndex, this.Count);
     99   }
    100 
    101 #if SWIG_DOTNET_1
    102   public void CopyTo(int index, System.Array array, int arrayIndex, int count)
    103 #else
    104   public void CopyTo(int index, $typemap(cstype, CTYPE)[] array, int arrayIndex, int count)
    105 #endif
    106   {
    107     if (array == null)
    108       throw new ArgumentNullException("array");
    109     if (index < 0)
    110       throw new ArgumentOutOfRangeException("index", "Value is less than zero");
    111     if (arrayIndex < 0)
    112       throw new ArgumentOutOfRangeException("arrayIndex", "Value is less than zero");
    113     if (count < 0)
    114       throw new ArgumentOutOfRangeException("count", "Value is less than zero");
    115     if (array.Rank > 1)
    116       throw new ArgumentException("Multi dimensional array.", "array");
    117     if (index+count > this.Count || arrayIndex+count > array.Length)
    118       throw new ArgumentException("Number of elements to copy is too large.");
    119     for (int i=0; i<count; i++)
    120       array.SetValue(getitemcopy(index+i), arrayIndex+i);
    121   }
    122 
    123 #if !SWIG_DOTNET_1
    124   System.Collections.Generic.IEnumerator<$typemap(cstype, CTYPE)> System.Collections.Generic.IEnumerable<$typemap(cstype, CTYPE)>.GetEnumerator() {
    125     return new $csclassnameEnumerator(this);
    126   }
    127 #endif
    128 
    129   System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
    130     return new $csclassnameEnumerator(this);
    131   }
    132 
    133   public $csclassnameEnumerator GetEnumerator() {
    134     return new $csclassnameEnumerator(this);
    135   }
    136 
    137   // Type-safe enumerator
    138   /// Note that the IEnumerator documentation requires an InvalidOperationException to be thrown
    139   /// whenever the collection is modified. This has been done for changes in the size of the
    140   /// collection but not when one of the elements of the collection is modified as it is a bit
    141   /// tricky to detect unmanaged code that modifies the collection under our feet.
    142   public sealed class $csclassnameEnumerator : System.Collections.IEnumerator
    143 #if !SWIG_DOTNET_1
    144     , System.Collections.Generic.IEnumerator<$typemap(cstype, CTYPE)>
    145 #endif
    146   {
    147     private $csclassname collectionRef;
    148     private int currentIndex;
    149     private object currentObject;
    150     private int currentSize;
    151 
    152     public $csclassnameEnumerator($csclassname collection) {
    153       collectionRef = collection;
    154       currentIndex = -1;
    155       currentObject = null;
    156       currentSize = collectionRef.Count;
    157     }
    158 
    159     // Type-safe iterator Current
    160     public $typemap(cstype, CTYPE) Current {
    161       get {
    162         if (currentIndex == -1)
    163           throw new InvalidOperationException("Enumeration not started.");
    164         if (currentIndex > currentSize - 1)
    165           throw new InvalidOperationException("Enumeration finished.");
    166         if (currentObject == null)
    167           throw new InvalidOperationException("Collection modified.");
    168         return ($typemap(cstype, CTYPE))currentObject;
    169       }
    170     }
    171 
    172     // Type-unsafe IEnumerator.Current
    173     object System.Collections.IEnumerator.Current {
    174       get {
    175         return Current;
    176       }
    177     }
    178 
    179     public bool MoveNext() {
    180       int size = collectionRef.Count;
    181       bool moveOkay = (currentIndex+1 < size) && (size == currentSize);
    182       if (moveOkay) {
    183         currentIndex++;
    184         currentObject = collectionRef[currentIndex];
    185       } else {
    186         currentObject = null;
    187       }
    188       return moveOkay;
    189     }
    190 
    191     public void Reset() {
    192       currentIndex = -1;
    193       currentObject = null;
    194       if (collectionRef.Count != currentSize) {
    195         throw new InvalidOperationException("Collection modified.");
    196       }
    197     }
    198 
    199 #if !SWIG_DOTNET_1
    200     public void Dispose() {
    201         currentIndex = -1;
    202         currentObject = null;
    203     }
    204 #endif
    205   }
    206 %}
    207 
    208   public:
    209     typedef size_t size_type;
    210     typedef CTYPE value_type;
    211     typedef CONST_REFERENCE const_reference;
    212     %rename(Clear) clear;
    213     void clear();
    214     %rename(Add) push_back;
    215     void push_back(CTYPE const& x);
    216     size_type size() const;
    217     size_type capacity() const;
    218     void reserve(size_type n);
    219     %newobject GetRange(int index, int count);
    220     %newobject Repeat(CTYPE const& value, int count);
    221     vector();
    222     vector(const vector &other);
    223     %extend {
    224       vector(int capacity) throw (std::out_of_range) {
    225         std::vector< CTYPE >* pv = 0;
    226         if (capacity >= 0) {
    227           pv = new std::vector< CTYPE >();
    228           pv->reserve(capacity);
    229        } else {
    230           throw std::out_of_range("capacity");
    231        }
    232        return pv;
    233       }
    234       CTYPE getitemcopy(int index) throw (std::out_of_range) {
    235         if (index>=0 && index<(int)$self->size())
    236           return (*$self)[index];
    237         else
    238           throw std::out_of_range("index");
    239       }
    240       const_reference getitem(int index) throw (std::out_of_range) {
    241         if (index>=0 && index<(int)$self->size())
    242           return (*$self)[index];
    243         else
    244           throw std::out_of_range("index");
    245       }
    246       void setitem(int index, CTYPE const& val) throw (std::out_of_range) {
    247         if (index>=0 && index<(int)$self->size())
    248           (*$self)[index] = val;
    249         else
    250           throw std::out_of_range("index");
    251       }
    252       // Takes a deep copy of the elements unlike ArrayList.AddRange
    253       void AddRange(const std::vector< CTYPE >& values) {
    254         $self->insert($self->end(), values.begin(), values.end());
    255       }
    256       // Takes a deep copy of the elements unlike ArrayList.GetRange
    257       std::vector< CTYPE > *GetRange(int index, int count) throw (std::out_of_range, std::invalid_argument) {
    258         if (index < 0)
    259           throw std::out_of_range("index");
    260         if (count < 0)
    261           throw std::out_of_range("count");
    262         if (index >= (int)$self->size()+1 || index+count > (int)$self->size())
    263           throw std::invalid_argument("invalid range");
    264         return new std::vector< CTYPE >($self->begin()+index, $self->begin()+index+count);
    265       }
    266       void Insert(int index, CTYPE const& x) throw (std::out_of_range) {
    267         if (index>=0 && index<(int)$self->size()+1)
    268           $self->insert($self->begin()+index, x);
    269         else
    270           throw std::out_of_range("index");
    271       }
    272       // Takes a deep copy of the elements unlike ArrayList.InsertRange
    273       void InsertRange(int index, const std::vector< CTYPE >& values) throw (std::out_of_range) {
    274         if (index>=0 && index<(int)$self->size()+1)
    275           $self->insert($self->begin()+index, values.begin(), values.end());
    276         else
    277           throw std::out_of_range("index");
    278       }
    279       void RemoveAt(int index) throw (std::out_of_range) {
    280         if (index>=0 && index<(int)$self->size())
    281           $self->erase($self->begin() + index);
    282         else
    283           throw std::out_of_range("index");
    284       }
    285       void RemoveRange(int index, int count) throw (std::out_of_range, std::invalid_argument) {
    286         if (index < 0)
    287           throw std::out_of_range("index");
    288         if (count < 0)
    289           throw std::out_of_range("count");
    290         if (index >= (int)$self->size()+1 || index+count > (int)$self->size())
    291           throw std::invalid_argument("invalid range");
    292         $self->erase($self->begin()+index, $self->begin()+index+count);
    293       }
    294       static std::vector< CTYPE > *Repeat(CTYPE const& value, int count) throw (std::out_of_range) {
    295         if (count < 0)
    296           throw std::out_of_range("count");
    297         return new std::vector< CTYPE >(count, value);
    298       }
    299       void Reverse() {
    300         std::reverse($self->begin(), $self->end());
    301       }
    302       void Reverse(int index, int count) throw (std::out_of_range, std::invalid_argument) {
    303         if (index < 0)
    304           throw std::out_of_range("index");
    305         if (count < 0)
    306           throw std::out_of_range("count");
    307         if (index >= (int)$self->size()+1 || index+count > (int)$self->size())
    308           throw std::invalid_argument("invalid range");
    309         std::reverse($self->begin()+index, $self->begin()+index+count);
    310       }
    311       // Takes a deep copy of the elements unlike ArrayList.SetRange
    312       void SetRange(int index, const std::vector< CTYPE >& values) throw (std::out_of_range) {
    313         if (index < 0)
    314           throw std::out_of_range("index");
    315         if (index+values.size() > $self->size())
    316           throw std::out_of_range("index");
    317         std::copy(values.begin(), values.end(), $self->begin()+index);
    318       }
    319     }
    320 %enddef
    321 
    322 // Extra methods added to the collection class if operator== is defined for the class being wrapped
    323 // The class will then implement IList<>, which adds extra functionality
    324 %define SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(CTYPE...)
    325     %extend {
    326       bool Contains(CTYPE const& value) {
    327         return std::find($self->begin(), $self->end(), value) != $self->end();
    328       }
    329       int IndexOf(CTYPE const& value) {
    330         int index = -1;
    331         std::vector< CTYPE >::iterator it = std::find($self->begin(), $self->end(), value);
    332         if (it != $self->end())
    333           index = (int)(it - $self->begin());
    334         return index;
    335       }
    336       int LastIndexOf(CTYPE const& value) {
    337         int index = -1;
    338         std::vector< CTYPE >::reverse_iterator rit = std::find($self->rbegin(), $self->rend(), value);
    339         if (rit != $self->rend())
    340           index = (int)($self->rend() - 1 - rit);
    341         return index;
    342       }
    343       bool Remove(CTYPE const& value) {
    344         std::vector< CTYPE >::iterator it = std::find($self->begin(), $self->end(), value);
    345         if (it != $self->end()) {
    346           $self->erase(it);
    347 	  return true;
    348         }
    349         return false;
    350       }
    351     }
    352 %enddef
    353 
    354 // Macros for std::vector class specializations/enhancements
    355 %define SWIG_STD_VECTOR_ENHANCED(CTYPE...)
    356 namespace std {
    357   template<> class vector< CTYPE > {
    358     SWIG_STD_VECTOR_MINIMUM_INTERNAL(IList, %arg(CTYPE const&), %arg(CTYPE))
    359     SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(CTYPE)
    360   };
    361 }
    362 %enddef
    363 
    364 // Legacy macros
    365 %define SWIG_STD_VECTOR_SPECIALIZE(CSTYPE, CTYPE...)
    366 #warning SWIG_STD_VECTOR_SPECIALIZE macro deprecated, please see csharp/std_vector.i and switch to SWIG_STD_VECTOR_ENHANCED
    367 SWIG_STD_VECTOR_ENHANCED(CTYPE)
    368 %enddef
    369 
    370 %define SWIG_STD_VECTOR_SPECIALIZE_MINIMUM(CSTYPE, CTYPE...)
    371 #warning SWIG_STD_VECTOR_SPECIALIZE_MINIMUM macro deprecated, it is no longer required
    372 %enddef
    373 
    374 %{
    375 #include <vector>
    376 #include <algorithm>
    377 #include <stdexcept>
    378 %}
    379 
    380 %csmethodmodifiers std::vector::getitemcopy "private"
    381 %csmethodmodifiers std::vector::getitem "private"
    382 %csmethodmodifiers std::vector::setitem "private"
    383 %csmethodmodifiers std::vector::size "private"
    384 %csmethodmodifiers std::vector::capacity "private"
    385 %csmethodmodifiers std::vector::reserve "private"
    386 
    387 namespace std {
    388   // primary (unspecialized) class template for std::vector
    389   // does not require operator== to be defined
    390   template<class T> class vector {
    391     SWIG_STD_VECTOR_MINIMUM_INTERNAL(IEnumerable, T const&, T)
    392   };
    393   // specialization for pointers
    394   template<class T> class vector<T *> {
    395     SWIG_STD_VECTOR_MINIMUM_INTERNAL(IList, T *const&, T *)
    396     SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(T *)
    397   };
    398   // bool is specialized in the C++ standard - const_reference in particular
    399   template<> class vector<bool> {
    400     SWIG_STD_VECTOR_MINIMUM_INTERNAL(IList, bool, bool)
    401     SWIG_STD_VECTOR_EXTRA_OP_EQUALS_EQUALS(bool)
    402   };
    403 }
    404 
    405 // template specializations for std::vector
    406 // these provide extra collections methods as operator== is defined
    407 SWIG_STD_VECTOR_ENHANCED(char)
    408 SWIG_STD_VECTOR_ENHANCED(signed char)
    409 SWIG_STD_VECTOR_ENHANCED(unsigned char)
    410 SWIG_STD_VECTOR_ENHANCED(short)
    411 SWIG_STD_VECTOR_ENHANCED(unsigned short)
    412 SWIG_STD_VECTOR_ENHANCED(int)
    413 SWIG_STD_VECTOR_ENHANCED(unsigned int)
    414 SWIG_STD_VECTOR_ENHANCED(long)
    415 SWIG_STD_VECTOR_ENHANCED(unsigned long)
    416 SWIG_STD_VECTOR_ENHANCED(long long)
    417 SWIG_STD_VECTOR_ENHANCED(unsigned long long)
    418 SWIG_STD_VECTOR_ENHANCED(float)
    419 SWIG_STD_VECTOR_ENHANCED(double)
    420 SWIG_STD_VECTOR_ENHANCED(std::string) // also requires a %include <std_string.i>
    421 
    422