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