diff options
Diffstat (limited to 'Lib/csharp/std_list.i')
-rw-r--r-- | Lib/csharp/std_list.i | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/Lib/csharp/std_list.i b/Lib/csharp/std_list.i new file mode 100644 index 000000000..674aba0ab --- /dev/null +++ b/Lib/csharp/std_list.i @@ -0,0 +1,519 @@ +/* ----------------------------------------------------------------------------- + * 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; + 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> +#include <stdexcept> +%} + +%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> |