1 /* ----------------------------------------------------------------------------- 2 * std_list.i 3 * 4 * SWIG typemaps for std::list<T> 5 * C# implementation 6 * The C# wrapper is made to look and feel like a C# System.Collections.Generic.LinkedList<> collection. 7 * 8 * Note that IEnumerable<> is implemented in the proxy class which is useful for using LINQ with 9 * C++ std::list wrappers. The ICollection<> interface is also implemented to provide enhanced functionality 10 * whenever we are confident that the required C++ operator== is available. This is the case for when 11 * T is a primitive type or a pointer. If T does define an operator==, then use the SWIG_STD_LIST_ENHANCED 12 * macro to obtain this enhanced functionality, for example: 13 * 14 * SWIG_STD_LIST_ENHANCED(SomeNamespace::Klass) 15 * %template(ListKlass) std::list<SomeNamespace::Klass>; 16 * ----------------------------------------------------------------------------- */ 17 18 %include <std_common.i> 19 20 // MACRO for use within the std::list class body 21 %define SWIG_STD_LIST_MINIMUM_INTERNAL(CSINTERFACE, CTYPE...) 22 %typemap(csinterfaces) std::list< CTYPE > "global::System.IDisposable, global::System.Collections.IEnumerable, global::System.Collections.Generic.CSINTERFACE<$typemap(cstype, CTYPE)>\n"; 23 24 %apply void *VOID_INT_PTR { std::list< CTYPE >::iterator * }; 25 26 %proxycode %{ this()27 public $csclassname(global::System.Collections.IEnumerable c) : this() { 28 if (c == null) 29 throw new global::System.ArgumentNullException("c"); 30 foreach ($typemap(cstype, CTYPE) element in c) { 31 this.AddLast(element); 32 } 33 } 34 35 public bool IsReadOnly { 36 get { 37 return false; 38 } 39 } 40 41 public int Count { 42 get { 43 return (int)size(); 44 } 45 } 46 47 public $csclassnameNode First { 48 get { 49 if (Count == 0) 50 return null; 51 return new $csclassnameNode(getFirstIter(), this); 52 } 53 } 54 55 public $csclassnameNode Last { 56 get { 57 if (Count == 0) 58 return null; 59 return new $csclassnameNode(getLastIter(), this); 60 } 61 } 62 AddFirst($typemap (cstype,CTYPE)value)63 public $csclassnameNode AddFirst($typemap(cstype, CTYPE) value) { 64 push_front(value); 65 return new $csclassnameNode(getFirstIter(), this); 66 } 67 AddFirst($csclassnameNode newNode)68 public void AddFirst($csclassnameNode newNode) { 69 ValidateNewNode(newNode); 70 if (!newNode.inlist) { 71 push_front(newNode.csharpvalue); 72 newNode.iter = getFirstIter(); 73 newNode.inlist = true; 74 } else { 75 throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name); 76 } 77 } 78 AddLast($typemap (cstype,CTYPE)value)79 public $csclassnameNode AddLast($typemap(cstype, CTYPE) value) { 80 push_back(value); 81 return new $csclassnameNode(getLastIter(), this); 82 } 83 AddLast($csclassnameNode newNode)84 public void AddLast($csclassnameNode newNode) { 85 ValidateNewNode(newNode); 86 if (!newNode.inlist) { 87 push_back(newNode.csharpvalue); 88 newNode.iter = getLastIter(); 89 newNode.inlist = true; 90 } else { 91 throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name); 92 } 93 } 94 AddBefore($csclassnameNode node,$typemap (cstype,CTYPE)value)95 public $csclassnameNode AddBefore($csclassnameNode node, $typemap(cstype, CTYPE) value) { 96 return new $csclassnameNode(insertNode(node.iter, value), this); 97 } 98 AddBefore($csclassnameNode node,$csclassnameNode newNode)99 public void AddBefore($csclassnameNode node, $csclassnameNode newNode) { 100 ValidateNode(node); 101 ValidateNewNode(newNode); 102 if (!newNode.inlist) { 103 newNode.iter = insertNode(node.iter, newNode.csharpvalue); 104 newNode.inlist = true; 105 } else { 106 throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name); 107 } 108 } 109 AddAfter($csclassnameNode node,$typemap (cstype,CTYPE)value)110 public $csclassnameNode AddAfter($csclassnameNode node, $typemap(cstype, CTYPE) value) { 111 node = node.Next; 112 return new $csclassnameNode(insertNode(node.iter, value), this); 113 } 114 AddAfter($csclassnameNode node,$csclassnameNode newNode)115 public void AddAfter($csclassnameNode node, $csclassnameNode newNode) { 116 ValidateNode(node); 117 ValidateNewNode(newNode); 118 if (!newNode.inlist) { 119 if (node == this.Last) 120 AddLast(newNode); 121 else 122 { 123 node = node.Next; 124 newNode.iter = insertNode(node.iter, newNode.csharpvalue); 125 newNode.inlist = true; 126 } 127 } else { 128 throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name); 129 } 130 } 131 Add($typemap (cstype,CTYPE)value)132 public void Add($typemap(cstype, CTYPE) value) { 133 AddLast(value); 134 } 135 Remove($csclassnameNode node)136 public void Remove($csclassnameNode node) { 137 ValidateNode(node); 138 eraseIter(node.iter); 139 } 140 CopyTo($typemap (cstype,CTYPE)[]array,int index)141 public void CopyTo($typemap(cstype, CTYPE)[] array, int index) { 142 if (array == null) 143 throw new global::System.ArgumentNullException("array"); 144 if (index < 0 || index > array.Length) 145 throw new global::System.ArgumentOutOfRangeException("index", "Value is less than zero"); 146 if (array.Rank > 1) 147 throw new global::System.ArgumentException("Multi dimensional array.", "array"); 148 $csclassnameNode node = this.First; 149 if (node != null) { 150 do { 151 array[index++] = node.Value; 152 node = node.Next; 153 } while (node != null); 154 } 155 } 156 ValidateNode($csclassnameNode node)157 internal void ValidateNode($csclassnameNode node) { 158 if (node == null) { 159 throw new System.ArgumentNullException("node"); 160 } 161 if (!node.inlist || node.list != this) { 162 throw new System.InvalidOperationException("node"); 163 } 164 } 165 ValidateNewNode($csclassnameNode node)166 internal void ValidateNewNode($csclassnameNode node) { 167 if (node == null) { 168 throw new System.ArgumentNullException("node"); 169 } 170 } 171 GetEnumerator()172 global::System.Collections.Generic.IEnumerator<$typemap(cstype, CTYPE)> global::System.Collections.Generic.IEnumerable<$typemap(cstype, CTYPE)>.GetEnumerator() { 173 return new $csclassnameEnumerator(this); 174 } 175 GetEnumerator()176 global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() { 177 return new $csclassnameEnumerator(this); 178 } 179 GetEnumerator()180 public $csclassnameEnumerator GetEnumerator() { 181 return new $csclassnameEnumerator(this); 182 } 183 184 public sealed class $csclassnameEnumerator : global::System.Collections.IEnumerator, 185 global::System.Collections.Generic.IEnumerator<$typemap(cstype, CTYPE)> 186 { 187 private $csclassname collectionRef; 188 private $csclassnameNode currentNode; 189 private int currentIndex; 190 private object currentObject; 191 private int currentSize; 192 $csclassnameEnumerator($csclassname collection)193 public $csclassnameEnumerator($csclassname collection) { 194 collectionRef = collection; 195 currentNode = collection.First; 196 currentIndex = 0; 197 currentObject = null; 198 currentSize = collectionRef.Count; 199 } 200 201 // Type-safe iterator Current $typemap(cstype,CTYPE)202 public $typemap(cstype, CTYPE) Current { 203 get { 204 if (currentIndex == -1) 205 throw new global::System.InvalidOperationException("Enumeration not started."); 206 if (currentIndex > currentSize) 207 throw new global::System.InvalidOperationException("Enumeration finished."); 208 if (currentObject == null) 209 throw new global::System.InvalidOperationException("Collection modified."); 210 return ($typemap(cstype, CTYPE))currentObject; 211 } 212 } 213 214 // Type-unsafe IEnumerator.Current 215 object global::System.Collections.IEnumerator.Current { 216 get { 217 return Current; 218 } 219 } 220 MoveNext()221 public bool MoveNext() { 222 if (currentNode == null) { 223 currentIndex = collectionRef.Count + 1; 224 return false; 225 } 226 ++currentIndex; 227 currentObject = currentNode.Value; 228 currentNode = currentNode.Next; 229 return true; 230 } 231 Reset()232 public void Reset() { 233 currentIndex = -1; 234 currentObject = null; 235 if (collectionRef.Count != currentSize) { 236 throw new global::System.InvalidOperationException("Collection modified."); 237 } 238 } 239 Dispose()240 public void Dispose() { 241 currentIndex = -1; 242 currentObject = null; 243 } 244 } 245 246 public sealed class $csclassnameNode { 247 internal $csclassname list; 248 internal System.IntPtr iter; 249 internal $typemap(cstype, CTYPE) csharpvalue; 250 internal bool inlist; 251 $csclassnameNode($typemap (cstype,CTYPE)value)252 public $csclassnameNode($typemap(cstype, CTYPE) value) { 253 csharpvalue = value; 254 inlist = false; 255 } 256 257 internal $csclassnameNode(System.IntPtr iter, $csclassname list) { 258 this.list = list; 259 this.iter = iter; 260 inlist = true; 261 } 262 263 public $csclassname List { 264 get { 265 return this.list; 266 } 267 } 268 269 public $csclassnameNode Next { 270 get { 271 if (list.getNextIter(iter) == System.IntPtr.Zero) 272 return null; 273 return new $csclassnameNode(list.getNextIter(iter), list); 274 } 275 } 276 277 public $csclassnameNode Previous { 278 get { 279 if (list.getPrevIter(iter) == System.IntPtr.Zero) 280 return null; 281 return new $csclassnameNode(list.getPrevIter(iter), list); 282 } 283 } 284 $typemap(cstype,CTYPE)285 public $typemap(cstype, CTYPE) Value { 286 get { 287 return list.getItem(this.iter); 288 } 289 set { 290 list.setItem(this.iter, value); 291 } 292 } 293 294 public static bool operator==($csclassnameNode node1, $csclassnameNode node2) { 295 if (object.ReferenceEquals(node1, null) && object.ReferenceEquals(node2, null)) 296 return true; 297 if (object.ReferenceEquals(node1, null) || object.ReferenceEquals(node2, null)) 298 return false; 299 return node1.Equals(node2); 300 } 301 302 public static bool operator!=($csclassnameNode node1, $csclassnameNode node2) { 303 if (node1 == null && node2 == null) 304 return false; 305 if (node1 == null || node2 == null) 306 return true; 307 return !node1.Equals(node2); 308 } 309 Equals($csclassnameNode node)310 public bool Equals($csclassnameNode node) { 311 if (node == null) 312 return false; 313 if (!node.inlist || !this.inlist) 314 return object.ReferenceEquals(this, node); 315 return list.equals(this.iter, node.iter); 316 } 317 Equals(object node)318 public override bool Equals(object node) { 319 return Equals(($csclassnameNode)node); 320 } 321 GetHashCode()322 public override int GetHashCode() { 323 int hash = 13; 324 if (inlist) { 325 hash = (hash * 7) + this.list.GetHashCode(); 326 hash = (hash * 7) + this.Value.GetHashCode(); 327 hash = (hash * 7) + this.list.getNextIter(this.iter).GetHashCode(); 328 hash = (hash * 7) + this.list.getPrevIter(this.iter).GetHashCode(); 329 } else { 330 hash = (hash * 7) + this.csharpvalue.GetHashCode(); 331 } 332 return hash; 333 } 334 Dispose()335 public void Dispose() { 336 list.deleteIter(this.iter); 337 } 338 } 339 %} 340 341 public: 342 typedef size_t size_type; 343 typedef ptrdiff_t difference_type; 344 typedef CTYPE value_type; 345 typedef value_type* pointer; 346 typedef const value_type* const_pointer; 347 typedef value_type& reference; 348 typedef const value_type& const_reference; 349 350 class iterator; 351 352 void push_front(CTYPE const& x); 353 void push_back(CTYPE const& x); 354 %rename(RemoveFirst) pop_front; 355 void pop_front(); 356 %rename(RemoveLast) pop_back; 357 void pop_back(); 358 size_type size() const; 359 %rename(Clear) clear; 360 void clear(); 361 %extend { getItem(iterator * iter)362 const_reference getItem(iterator *iter) { 363 return **iter; 364 } 365 setItem(iterator * iter,CTYPE const & val)366 void setItem(iterator *iter, CTYPE const& val) { 367 *(*iter) = val; 368 } 369 getFirstIter()370 iterator *getFirstIter() { 371 if ($self->size() == 0) 372 return NULL; 373 return new std::list< CTYPE >::iterator($self->begin()); 374 } 375 getLastIter()376 iterator *getLastIter() { 377 if ($self->size() == 0) 378 return NULL; 379 return new std::list< CTYPE >::iterator(--$self->end()); 380 } 381 getNextIter(iterator * iter)382 iterator *getNextIter(iterator *iter) { 383 std::list< CTYPE >::iterator it = *iter; 384 if (std::distance(it, --$self->end()) != 0) { 385 std::list< CTYPE >::iterator* itnext = new std::list< CTYPE >::iterator(++it); 386 return itnext; 387 } 388 return NULL; 389 } 390 getPrevIter(iterator * iter)391 iterator *getPrevIter(iterator *iter) { 392 std::list< CTYPE >::iterator it = *iter; 393 if (std::distance($self->begin(), it) != 0) { 394 std::list< CTYPE >::iterator* itprev = new std::list< CTYPE >::iterator(--it); 395 return itprev; 396 } 397 return NULL; 398 } 399 insertNode(iterator * iter,CTYPE const & value)400 iterator *insertNode(iterator *iter, CTYPE const& value) { 401 std::list< CTYPE >::iterator it = $self->insert(*iter, value); 402 return new std::list< CTYPE >::iterator(it); 403 } 404 eraseIter(iterator * iter)405 void eraseIter(iterator *iter) { 406 std::list< CTYPE >::iterator it = *iter; 407 $self->erase(it); 408 } 409 deleteIter(iterator * iter)410 void deleteIter(iterator *iter) { 411 delete iter; 412 } 413 equals(iterator * iter1,iterator * iter2)414 bool equals(iterator *iter1, iterator *iter2) { 415 if (iter1 == NULL && iter2 == NULL) 416 return true; 417 std::list< CTYPE >::iterator it1 = *iter1; 418 std::list< CTYPE >::iterator it2 = *iter2; 419 return it1 == it2; 420 } 421 } 422 %enddef 423 424 // Extra methods added to the collection class if operator== is defined for the class being wrapped 425 // The class will then implement ICollection<>, which adds extra functionality 426 %define SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(CTYPE...) 427 %extend { Contains(CTYPE const & value)428 bool Contains(CTYPE const& value) { 429 return std::find($self->begin(), $self->end(), value) != $self->end(); 430 } 431 Remove(CTYPE const & value)432 bool Remove(CTYPE const& value) { 433 std::list< CTYPE >::iterator it = std::find($self->begin(), $self->end(), value); 434 if (it != $self->end()) { 435 $self->erase(it); 436 return true; 437 } 438 return false; 439 } 440 find(CTYPE const & value)441 iterator *find(CTYPE const& value) { 442 if (std::find($self->begin(), $self->end(), value) != $self->end()) { 443 return new std::list< CTYPE >::iterator(std::find($self->begin(), $self->end(), value)); 444 } 445 return NULL; 446 } 447 } 448 %proxycode %{ Find($typemap (cstype,CTYPE)value)449 public $csclassnameNode Find($typemap(cstype, CTYPE) value) { 450 System.IntPtr tmp = find(value); 451 if (tmp != System.IntPtr.Zero) { 452 return new $csclassnameNode(tmp, this); 453 } 454 return null; 455 } 456 %} 457 %enddef 458 459 // Macros for std::list class specializations/enhancements 460 %define SWIG_STD_LIST_ENHANCED(CTYPE...) 461 namespace std { 462 template<> class list< CTYPE > { 463 SWIG_STD_LIST_MINIMUM_INTERNAL(ICollection, %arg(CTYPE)); 464 SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(CTYPE) 465 }; 466 } 467 %enddef 468 469 470 %{ 471 #include <list> 472 #include <algorithm> 473 #include <stdexcept> 474 %} 475 476 %csmethodmodifiers std::list::size "private" 477 %csmethodmodifiers std::list::getItem "private" 478 %csmethodmodifiers std::list::setItem "private" 479 %csmethodmodifiers std::list::push_front "private" 480 %csmethodmodifiers std::list::push_back "private" 481 %csmethodmodifiers std::list::getFirstIter "private" 482 %csmethodmodifiers std::list::getNextIter "private" 483 %csmethodmodifiers std::list::getPrevIter "private" 484 %csmethodmodifiers std::list::getLastIter "private" 485 %csmethodmodifiers std::list::find "private" 486 %csmethodmodifiers std::list::deleteIter "private" 487 488 namespace std { 489 // primary (unspecialized) class template for std::list 490 // does not require operator== to be defined 491 template<class T> 492 class list { 493 SWIG_STD_LIST_MINIMUM_INTERNAL(IEnumerable, T) 494 }; 495 // specialization for pointers 496 template<class T> 497 class list<T *> { 498 SWIG_STD_LIST_MINIMUM_INTERNAL(ICollection, T *) 499 SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(T *) 500 }; 501 } 502 503 // template specializations for std::list 504 // these provide extra collections methods as operator== is defined 505 SWIG_STD_LIST_ENHANCED(char) 506 SWIG_STD_LIST_ENHANCED(signed char) 507 SWIG_STD_LIST_ENHANCED(unsigned char) 508 SWIG_STD_LIST_ENHANCED(short) 509 SWIG_STD_LIST_ENHANCED(unsigned short) 510 SWIG_STD_LIST_ENHANCED(int) 511 SWIG_STD_LIST_ENHANCED(unsigned int) 512 SWIG_STD_LIST_ENHANCED(long) 513 SWIG_STD_LIST_ENHANCED(unsigned long) 514 SWIG_STD_LIST_ENHANCED(long long) 515 SWIG_STD_LIST_ENHANCED(unsigned long long) 516 SWIG_STD_LIST_ENHANCED(float) 517 SWIG_STD_LIST_ENHANCED(double) 518 SWIG_STD_LIST_ENHANCED(std::string) // also requires a %include <std_string.i> 519 SWIG_STD_LIST_ENHANCED(std::wstring) // also requires a %include <std_wstring.i> 520