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...)
356namespace 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
367SWIG_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
387namespace 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
407SWIG_STD_VECTOR_ENHANCED(char)
408SWIG_STD_VECTOR_ENHANCED(signed char)
409SWIG_STD_VECTOR_ENHANCED(unsigned char)
410SWIG_STD_VECTOR_ENHANCED(short)
411SWIG_STD_VECTOR_ENHANCED(unsigned short)
412SWIG_STD_VECTOR_ENHANCED(int)
413SWIG_STD_VECTOR_ENHANCED(unsigned int)
414SWIG_STD_VECTOR_ENHANCED(long)
415SWIG_STD_VECTOR_ENHANCED(unsigned long)
416SWIG_STD_VECTOR_ENHANCED(long long)
417SWIG_STD_VECTOR_ENHANCED(unsigned long long)
418SWIG_STD_VECTOR_ENHANCED(float)
419SWIG_STD_VECTOR_ENHANCED(double)
420SWIG_STD_VECTOR_ENHANCED(std::string) // also requires a %include <std_string.i>
421
422