/* ----------------------------------------------------------------------------- * std_unordered_set.i * * SWIG typemaps for std::unordered_set. * * Note that ISet<> used here requires .NET 4 or later. * * The C# wrapper implements ISet<> interface and is similar in * characteristics to the C# System.Collections.Generic.HashSet<> class, but * doesn't provide quite all of its methods. * ----------------------------------------------------------------------------- */ %{ #include #include #include %} %csmethodmodifiers std::unordered_set::empty "private" %csmethodmodifiers std::unordered_set::size "private" %csmethodmodifiers std::unordered_set::getitem "private" %csmethodmodifiers std::unordered_set::create_iterator_begin "private" %csmethodmodifiers std::unordered_set::get_next "private" %csmethodmodifiers std::unordered_set::destroy_iterator "private" namespace std { // TODO: Add support for comparator and allocator template parameters. template class unordered_set { %typemap(csinterfaces) std::unordered_set "global::System.IDisposable, global::System.Collections.Generic.ISet<$typemap(cstype, T)>\n" %proxycode %{ void global::System.Collections.Generic.ICollection<$typemap(cstype, T)>.Add($typemap(cstype, T) item) { ((global::System.Collections.Generic.ISet<$typemap(cstype, T)>)this).Add(item); } public bool TryGetValue($typemap(cstype, T) equalValue, out $typemap(cstype, T) actualValue) { try { actualValue = getitem(equalValue); return true; } catch { actualValue = default($typemap(cstype, T)); return false; } } public bool IsEmpty { get { return empty(); } } public int Count { get { return (int)size(); } } public bool IsReadOnly { get { return false; } } public void CopyTo($typemap(cstype, T)[] array) { CopyTo(array, 0); } public void CopyTo($typemap(cstype, T)[] array, int arrayIndex) { if (array == null) throw new global::System.ArgumentNullException("array"); if (arrayIndex < 0) throw new global::System.ArgumentOutOfRangeException("arrayIndex", "Value is less than zero"); if (array.Rank > 1) throw new global::System.ArgumentException("Multi dimensional array.", "array"); if (arrayIndex+this.Count > array.Length) throw new global::System.ArgumentException("Number of elements to copy is too large."); foreach ($typemap(cstype, T) item in this) { array.SetValue(item, arrayIndex++); } } public void ExceptWith(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { foreach ($typemap(cstype, T) item in other) { Remove(item); } } public void IntersectWith(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { $csclassname old = new $csclassname(this); Clear(); foreach ($typemap(cstype, T) item in other) { if (old.Contains(item)) Add(item); } } private static int count_enum(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { int count = 0; foreach ($typemap(cstype, T) item in other) { count++; } return count; } public bool IsProperSubsetOf(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { return IsSubsetOf(other) && Count < count_enum(other); } public bool IsProperSupersetOf(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { return IsSupersetOf(other) && Count > count_enum(other); } public bool IsSubsetOf(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { int countContained = 0; foreach ($typemap(cstype, T) item in other) { if (Contains(item)) countContained++; } return countContained == Count; } public bool IsSupersetOf(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { foreach ($typemap(cstype, T) item in other) { if (!Contains(item)) return false; } return true; } public bool Overlaps(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { foreach ($typemap(cstype, T) item in other) { if (Contains(item)) return true; } return false; } public bool SetEquals(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { return IsSupersetOf(other) && Count == count_enum(other); } public void SymmetricExceptWith(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { foreach ($typemap(cstype, T) item in other) { if (!Remove(item)) Add(item); } } public void UnionWith(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) { foreach ($typemap(cstype, T) item in other) { Add(item); } } private global::System.Collections.Generic.ICollection<$typemap(cstype, T)> Items { get { global::System.Collections.Generic.ICollection<$typemap(cstype, T)> items = new global::System.Collections.Generic.List<$typemap(cstype, T)>(); int size = this.Count; if (size > 0) { global::System.IntPtr iter = create_iterator_begin(); for (int i = 0; i < size; i++) { items.Add(get_next(iter)); } destroy_iterator(iter); } return items; } } global::System.Collections.Generic.IEnumerator<$typemap(cstype, T)> global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)>.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); } // Type-safe enumerator /// Note that the IEnumerator documentation requires an InvalidOperationException to be thrown /// whenever the collection is modified. This has been done for changes in the size of the /// collection but not when one of the elements of the collection is modified as it is a bit /// tricky to detect unmanaged code that modifies the collection under our feet. public sealed class $csclassnameEnumerator : global::System.Collections.IEnumerator, global::System.Collections.Generic.IEnumerator<$typemap(cstype, T)> { private $csclassname collectionRef; private global::System.Collections.Generic.IList<$typemap(cstype, T)> ItemsCollection; private int currentIndex; private object currentObject; private int currentSize; public $csclassnameEnumerator($csclassname collection) { collectionRef = collection; ItemsCollection = new global::System.Collections.Generic.List<$typemap(cstype, T)>(collection.Items); currentIndex = -1; currentObject = null; currentSize = collectionRef.Count; } // Type-safe iterator Current public $typemap(cstype, T) Current { get { if (currentIndex == -1) throw new global::System.InvalidOperationException("Enumeration not started."); if (currentIndex > currentSize - 1) throw new global::System.InvalidOperationException("Enumeration finished."); if (currentObject == null) throw new global::System.InvalidOperationException("Collection modified."); return ($typemap(cstype, T))currentObject; } } // Type-unsafe IEnumerator.Current object global::System.Collections.IEnumerator.Current { get { return Current; } } public bool MoveNext() { int size = collectionRef.Count; bool moveOkay = (currentIndex+1 < size) && (size == currentSize); if (moveOkay) { currentIndex++; currentObject = ItemsCollection[currentIndex]; } else { currentObject = null; } return moveOkay; } 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: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T key_type; typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; unordered_set(); unordered_set(const unordered_set& other); size_type size() const; bool empty() const; %rename(Clear) clear; void clear(); %extend { bool Add(const value_type& item) { return $self->insert(item).second; } bool Contains(const value_type& item) { return $self->count(item) != 0; } bool Remove(const value_type& item) { return $self->erase(item) != 0; } const value_type& getitem(const value_type& item) throw (std::out_of_range) { std::unordered_set::iterator iter = $self->find(item); if (iter == $self->end()) throw std::out_of_range("item not found"); return *iter; } // create_iterator_begin(), get_next() and destroy_iterator work together to provide a collection of items to C# %apply void *VOID_INT_PTR { std::unordered_set::iterator *create_iterator_begin } %apply void *VOID_INT_PTR { std::unordered_set::iterator *swigiterator } std::unordered_set::iterator *create_iterator_begin() { return new std::unordered_set::iterator($self->begin()); } const key_type& get_next(std::unordered_set::iterator *swigiterator) { (void)$self; std::unordered_set::iterator iter = *swigiterator; (*swigiterator)++; return *iter; } void destroy_iterator(std::unordered_set::iterator *swigiterator) { (void)$self; delete swigiterator; } } }; }