| /* ----------------------------------------------------------------------------- | |
| * std_list.i | |
| * | |
| * SWIG typemaps for std::list<T> | |
| * C# implementation | |
| * The C# wrapper is made to look and feel like a C# System.Collections.Generic.LinkedList<> collection. | |
| * | |
| * Note that IEnumerable<> is implemented in the proxy class which is useful for using LINQ with | |
| * C++ std::list wrappers. The ICollection<> interface is also implemented to provide enhanced functionality | |
| * whenever we are confident that the required C++ operator== is available. This is the case for when | |
| * T is a primitive type or a pointer. If T does define an operator==, then use the SWIG_STD_LIST_ENHANCED | |
| * macro to obtain this enhanced functionality, for example: | |
| * | |
| * SWIG_STD_LIST_ENHANCED(SomeNamespace::Klass) | |
| * %template(ListKlass) std::list<SomeNamespace::Klass>; | |
| * ----------------------------------------------------------------------------- */ | |
| %include <std_common.i> | |
| // MACRO for use within the std::list class body | |
| %define SWIG_STD_LIST_MINIMUM_INTERNAL(CSINTERFACE, CTYPE...) | |
| %typemap(csinterfaces) std::list< CTYPE > "global::System.IDisposable, global::System.Collections.IEnumerable, global::System.Collections.Generic.CSINTERFACE<$typemap(cstype, CTYPE)>\n" | |
| %apply void *VOID_INT_PTR { std::list< CTYPE >::iterator * }; | |
| %proxycode %{ | |
| public $csclassname(global::System.Collections.IEnumerable c) : this() { | |
| if (c == null) | |
| throw new global::System.ArgumentNullException("c"); | |
| foreach ($typemap(cstype, CTYPE) element in c) { | |
| this.AddLast(element); | |
| } | |
| } | |
| public bool IsReadOnly { | |
| get { | |
| return false; | |
| } | |
| } | |
| public int Count { | |
| get { | |
| return (int)size(); | |
| } | |
| } | |
| public $csclassnameNode First { | |
| get { | |
| if (Count == 0) | |
| return null; | |
| return new $csclassnameNode(getFirstIter(), this); | |
| } | |
| } | |
| public $csclassnameNode Last { | |
| get { | |
| if (Count == 0) | |
| return null; | |
| return new $csclassnameNode(getLastIter(), this); | |
| } | |
| } | |
| public $csclassnameNode AddFirst($typemap(cstype, CTYPE) value) { | |
| push_front(value); | |
| return new $csclassnameNode(getFirstIter(), this); | |
| } | |
| public void AddFirst($csclassnameNode newNode) { | |
| ValidateNewNode(newNode); | |
| if (!newNode.inlist) { | |
| push_front(newNode.csharpvalue); | |
| newNode.iter = getFirstIter(); | |
| newNode.inlist = true; | |
| } else { | |
| throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name); | |
| } | |
| } | |
| public $csclassnameNode AddLast($typemap(cstype, CTYPE) value) { | |
| push_back(value); | |
| return new $csclassnameNode(getLastIter(), this); | |
| } | |
| public void AddLast($csclassnameNode newNode) { | |
| ValidateNewNode(newNode); | |
| if (!newNode.inlist) { | |
| push_back(newNode.csharpvalue); | |
| newNode.iter = getLastIter(); | |
| newNode.inlist = true; | |
| } else { | |
| throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name); | |
| } | |
| } | |
| public $csclassnameNode AddBefore($csclassnameNode node, $typemap(cstype, CTYPE) value) { | |
| return new $csclassnameNode(insertNode(node.iter, value), this); | |
| } | |
| public void AddBefore($csclassnameNode node, $csclassnameNode newNode) { | |
| ValidateNode(node); | |
| ValidateNewNode(newNode); | |
| if (!newNode.inlist) { | |
| newNode.iter = insertNode(node.iter, newNode.csharpvalue); | |
| newNode.inlist = true; | |
| } else { | |
| throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name); | |
| } | |
| } | |
| public $csclassnameNode AddAfter($csclassnameNode node, $typemap(cstype, CTYPE) value) { | |
| node = node.Next; | |
| return new $csclassnameNode(insertNode(node.iter, value), this); | |
| } | |
| public void AddAfter($csclassnameNode node, $csclassnameNode newNode) { | |
| ValidateNode(node); | |
| ValidateNewNode(newNode); | |
| if (!newNode.inlist) { | |
| if (node == this.Last) | |
| AddLast(newNode); | |
| else | |
| { | |
| node = node.Next; | |
| newNode.iter = insertNode(node.iter, newNode.csharpvalue); | |
| newNode.inlist = true; | |
| } | |
| } else { | |
| throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name); | |
| } | |
| } | |
| public void Add($typemap(cstype, CTYPE) value) { | |
| AddLast(value); | |
| } | |
| public void Remove($csclassnameNode node) { | |
| ValidateNode(node); | |
| eraseIter(node.iter); | |
| } | |
| public void CopyTo($typemap(cstype, CTYPE)[] array, int index) { | |
| if (array == null) | |
| throw new global::System.ArgumentNullException("array"); | |
| if (index < 0 || index > array.Length) | |
| throw new global::System.ArgumentOutOfRangeException("index", "Value is less than zero"); | |
| if (array.Rank > 1) | |
| throw new global::System.ArgumentException("Multi dimensional array.", "array"); | |
| $csclassnameNode node = this.First; | |
| if (node != null) { | |
| do { | |
| array[index++] = node.Value; | |
| node = node.Next; | |
| } while (node != null); | |
| } | |
| } | |
| internal void ValidateNode($csclassnameNode node) { | |
| if (node == null) { | |
| throw new System.ArgumentNullException("node"); | |
| } | |
| if (!node.inlist || node.list != this) { | |
| throw new System.InvalidOperationException("node"); | |
| } | |
| } | |
| internal void ValidateNewNode($csclassnameNode node) { | |
| if (node == null) { | |
| throw new System.ArgumentNullException("node"); | |
| } | |
| } | |
| global::System.Collections.Generic.IEnumerator<$typemap(cstype, CTYPE)> global::System.Collections.Generic.IEnumerable<$typemap(cstype, CTYPE)>.GetEnumerator() { | |
| return new $csclassnameEnumerator(this); | |
| } | |
| global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() { | |
| return new $csclassnameEnumerator(this); | |
| } | |
| public $csclassnameEnumerator GetEnumerator() { | |
| return new $csclassnameEnumerator(this); | |
| } | |
| public sealed class $csclassnameEnumerator : global::System.Collections.IEnumerator, | |
| global::System.Collections.Generic.IEnumerator<$typemap(cstype, CTYPE)> | |
| { | |
| private $csclassname collectionRef; | |
| private $csclassnameNode currentNode; | |
| private int currentIndex; | |
| private object currentObject; | |
| private int currentSize; | |
| public $csclassnameEnumerator($csclassname collection) { | |
| collectionRef = collection; | |
| currentNode = collection.First; | |
| currentIndex = 0; | |
| currentObject = null; | |
| currentSize = collectionRef.Count; | |
| } | |
| // Type-safe iterator Current | |
| public $typemap(cstype, CTYPE) Current { | |
| get { | |
| if (currentIndex == -1) | |
| throw new global::System.InvalidOperationException("Enumeration not started."); | |
| if (currentIndex > currentSize) | |
| throw new global::System.InvalidOperationException("Enumeration finished."); | |
| if (currentObject == null) | |
| throw new global::System.InvalidOperationException("Collection modified."); | |
| return ($typemap(cstype, CTYPE))currentObject; | |
| } | |
| } | |
| // Type-unsafe IEnumerator.Current | |
| object global::System.Collections.IEnumerator.Current { | |
| get { | |
| return Current; | |
| } | |
| } | |
| public bool MoveNext() { | |
| if (currentNode == null) { | |
| currentIndex = collectionRef.Count + 1; | |
| return false; | |
| } | |
| ++currentIndex; | |
| currentObject = currentNode.Value; | |
| currentNode = currentNode.Next; | |
| return true; | |
| } | |
| public void Reset() { | |
| currentIndex = -1; | |
| currentObject = null; | |
| if (collectionRef.Count != currentSize) { | |
| throw new global::System.InvalidOperationException("Collection modified."); | |
| } | |
| } | |
| public void Dispose() { | |
| currentIndex = -1; | |
| currentObject = null; | |
| } | |
| } | |
| public sealed class $csclassnameNode { | |
| internal $csclassname list; | |
| internal System.IntPtr iter; | |
| internal $typemap(cstype, CTYPE) csharpvalue; | |
| internal bool inlist; | |
| public $csclassnameNode($typemap(cstype, CTYPE) value) { | |
| csharpvalue = value; | |
| inlist = false; | |
| } | |
| internal $csclassnameNode(System.IntPtr iter, $csclassname list) { | |
| this.list = list; | |
| this.iter = iter; | |
| inlist = true; | |
| } | |
| public $csclassname List { | |
| get { | |
| return this.list; | |
| } | |
| } | |
| public $csclassnameNode Next { | |
| get { | |
| if (list.getNextIter(iter) == System.IntPtr.Zero) | |
| return null; | |
| return new $csclassnameNode(list.getNextIter(iter), list); | |
| } | |
| } | |
| public $csclassnameNode Previous { | |
| get { | |
| if (list.getPrevIter(iter) == System.IntPtr.Zero) | |
| return null; | |
| return new $csclassnameNode(list.getPrevIter(iter), list); | |
| } | |
| } | |
| public $typemap(cstype, CTYPE) Value { | |
| get { | |
| return list.getItem(this.iter); | |
| } | |
| set { | |
| list.setItem(this.iter, value); | |
| } | |
| } | |
| public static bool operator==($csclassnameNode node1, $csclassnameNode node2) { | |
| if (object.ReferenceEquals(node1, null) && object.ReferenceEquals(node2, null)) | |
| return true; | |
| if (object.ReferenceEquals(node1, null) || object.ReferenceEquals(node2, null)) | |
| return false; | |
| return node1.Equals(node2); | |
| } | |
| public static bool operator!=($csclassnameNode node1, $csclassnameNode node2) { | |
| if (node1 == null && node2 == null) | |
| return false; | |
| if (node1 == null || node2 == null) | |
| return true; | |
| return !node1.Equals(node2); | |
| } | |
| public bool Equals($csclassnameNode node) { | |
| if (node == null) | |
| return false; | |
| if (!node.inlist || !this.inlist) | |
| return object.ReferenceEquals(this, node); | |
| return list.equals(this.iter, node.iter); | |
| } | |
| public override bool Equals(object node) { | |
| return Equals(($csclassnameNode)node); | |
| } | |
| public override int GetHashCode() { | |
| int hash = 13; | |
| if (inlist) { | |
| hash = (hash * 7) + this.list.GetHashCode(); | |
| hash = (hash * 7) + this.Value.GetHashCode(); | |
| hash = (hash * 7) + this.list.getNextIter(this.iter).GetHashCode(); | |
| hash = (hash * 7) + this.list.getPrevIter(this.iter).GetHashCode(); | |
| } else { | |
| hash = (hash * 7) + this.csharpvalue.GetHashCode(); | |
| } | |
| return hash; | |
| } | |
| public void Dispose() { | |
| list.deleteIter(this.iter); | |
| } | |
| } | |
| %} | |
| public: | |
| typedef size_t size_type; | |
| typedef ptrdiff_t difference_type; | |
| typedef CTYPE value_type; | |
| typedef value_type* pointer; | |
| typedef const value_type* const_pointer; | |
| typedef value_type& reference; | |
| typedef const value_type& const_reference; | |
| class iterator; | |
| void push_front(CTYPE const& x); | |
| void push_back(CTYPE const& x); | |
| %rename(RemoveFirst) pop_front; | |
| void pop_front(); | |
| %rename(RemoveLast) pop_back; | |
| void pop_back(); | |
| size_type size() const; | |
| %rename(Clear) clear; | |
| void clear(); | |
| %extend { | |
| const_reference getItem(iterator *iter) { | |
| return **iter; | |
| } | |
| void setItem(iterator *iter, CTYPE const& val) { | |
| *(*iter) = val; | |
| } | |
| iterator *getFirstIter() { | |
| if ($self->size() == 0) | |
| return NULL; | |
| return new std::list< CTYPE >::iterator($self->begin()); | |
| } | |
| iterator *getLastIter() { | |
| if ($self->size() == 0) | |
| return NULL; | |
| return new std::list< CTYPE >::iterator(--$self->end()); | |
| } | |
| iterator *getNextIter(iterator *iter) { | |
| std::list< CTYPE >::iterator it = *iter; | |
| if (std::distance(it, --$self->end()) != 0) { | |
| std::list< CTYPE >::iterator* itnext = new std::list< CTYPE >::iterator(++it); | |
| return itnext; | |
| } | |
| return NULL; | |
| } | |
| iterator *getPrevIter(iterator *iter) { | |
| std::list< CTYPE >::iterator it = *iter; | |
| if (std::distance($self->begin(), it) != 0) { | |
| std::list< CTYPE >::iterator* itprev = new std::list< CTYPE >::iterator(--it); | |
| return itprev; | |
| } | |
| return NULL; | |
| } | |
| iterator *insertNode(iterator *iter, CTYPE const& value) { | |
| std::list< CTYPE >::iterator it = $self->insert(*iter, value); | |
| return new std::list< CTYPE >::iterator(it); | |
| } | |
| void eraseIter(iterator *iter) { | |
| std::list< CTYPE >::iterator it = *iter; | |
| $self->erase(it); | |
| } | |
| void deleteIter(iterator *iter) { | |
| delete iter; | |
| } | |
| bool equals(iterator *iter1, iterator *iter2) { | |
| if (iter1 == NULL && iter2 == NULL) | |
| return true; | |
| if (iter1 == NULL || iter2 == NULL) | |
| return false; | |
| std::list< CTYPE >::iterator it1 = *iter1; | |
| std::list< CTYPE >::iterator it2 = *iter2; | |
| return it1 == it2; | |
| } | |
| } | |
| %enddef | |
| // Extra methods added to the collection class if operator== is defined for the class being wrapped | |
| // The class will then implement ICollection<>, which adds extra functionality | |
| %define SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(CTYPE...) | |
| %extend { | |
| bool Contains(CTYPE const& value) { | |
| return std::find($self->begin(), $self->end(), value) != $self->end(); | |
| } | |
| bool Remove(CTYPE const& value) { | |
| std::list< CTYPE >::iterator it = std::find($self->begin(), $self->end(), value); | |
| if (it != $self->end()) { | |
| $self->erase(it); | |
| return true; | |
| } | |
| return false; | |
| } | |
| iterator *find(CTYPE const& value) { | |
| if (std::find($self->begin(), $self->end(), value) != $self->end()) { | |
| return new std::list< CTYPE >::iterator(std::find($self->begin(), $self->end(), value)); | |
| } | |
| return NULL; | |
| } | |
| } | |
| %proxycode %{ | |
| public $csclassnameNode Find($typemap(cstype, CTYPE) value) { | |
| System.IntPtr tmp = find(value); | |
| if (tmp != System.IntPtr.Zero) { | |
| return new $csclassnameNode(tmp, this); | |
| } | |
| return null; | |
| } | |
| %} | |
| %enddef | |
| // Macros for std::list class specializations/enhancements | |
| %define SWIG_STD_LIST_ENHANCED(CTYPE...) | |
| namespace std { | |
| template<> class list< CTYPE > { | |
| SWIG_STD_LIST_MINIMUM_INTERNAL(ICollection, %arg(CTYPE)); | |
| SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(CTYPE) | |
| }; | |
| } | |
| %enddef | |
| %{ | |
| #include <list> | |
| #include <algorithm> | |
| %} | |
| %csmethodmodifiers std::list::size "private" | |
| %csmethodmodifiers std::list::getItem "private" | |
| %csmethodmodifiers std::list::setItem "private" | |
| %csmethodmodifiers std::list::push_front "private" | |
| %csmethodmodifiers std::list::push_back "private" | |
| %csmethodmodifiers std::list::getFirstIter "private" | |
| %csmethodmodifiers std::list::getNextIter "private" | |
| %csmethodmodifiers std::list::getPrevIter "private" | |
| %csmethodmodifiers std::list::getLastIter "private" | |
| %csmethodmodifiers std::list::find "private" | |
| %csmethodmodifiers std::list::deleteIter "private" | |
| namespace std { | |
| // primary (unspecialized) class template for std::list | |
| // does not require operator== to be defined | |
| template<class T> | |
| class list { | |
| SWIG_STD_LIST_MINIMUM_INTERNAL(IEnumerable, T) | |
| }; | |
| // specialization for pointers | |
| template<class T> | |
| class list<T *> { | |
| SWIG_STD_LIST_MINIMUM_INTERNAL(ICollection, T *) | |
| SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(T *) | |
| }; | |
| } | |
| // template specializations for std::list | |
| // these provide extra collections methods as operator== is defined | |
| SWIG_STD_LIST_ENHANCED(char) | |
| SWIG_STD_LIST_ENHANCED(signed char) | |
| SWIG_STD_LIST_ENHANCED(unsigned char) | |
| SWIG_STD_LIST_ENHANCED(short) | |
| SWIG_STD_LIST_ENHANCED(unsigned short) | |
| SWIG_STD_LIST_ENHANCED(int) | |
| SWIG_STD_LIST_ENHANCED(unsigned int) | |
| SWIG_STD_LIST_ENHANCED(long) | |
| SWIG_STD_LIST_ENHANCED(unsigned long) | |
| SWIG_STD_LIST_ENHANCED(long long) | |
| SWIG_STD_LIST_ENHANCED(unsigned long long) | |
| SWIG_STD_LIST_ENHANCED(float) | |
| SWIG_STD_LIST_ENHANCED(double) | |
| SWIG_STD_LIST_ENHANCED(std::string) // also requires a %include <std_string.i> | |
| SWIG_STD_LIST_ENHANCED(std::wstring) // also requires a %include <std_wstring.i> |