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