/* ----------------------------------------------------------------------------- * std_list.i * * SWIG typemaps for std::list * 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; * ----------------------------------------------------------------------------- */ %include // 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; 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 #include #include %} %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 list { SWIG_STD_LIST_MINIMUM_INTERNAL(IEnumerable, T) }; // specialization for pointers template class list { 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 SWIG_STD_LIST_ENHANCED(std::wstring) // also requires a %include