/* ----------------------------------------------------------------------------- * std_map.i * * SWIG typemaps for std::map< K, T, C > * * The C# wrapper is made to look and feel like a C# System.Collections.Generic.IDictionary<>. * * Using this wrapper is fairly simple. For example, to create a map from integers to doubles use: * * %include * %template(MapIntDouble) std::map * * Notes: * 1) IEnumerable<> is implemented in the proxy class which is useful for using LINQ with * C++ std::map wrappers. * * Warning: heavy macro usage in this file. Use swig -E to get a sane view on the real file contents! * ----------------------------------------------------------------------------- */ %{ #include #include #include %} /* K is the C++ key type, T is the C++ value type */ %define SWIG_STD_MAP_INTERNAL(K, T, C) %typemap(csinterfaces) std::map< K, T, C > "global::System.IDisposable \n , global::System.Collections.Generic.IDictionary<$typemap(cstype, K), $typemap(cstype, T)>\n" %proxycode %{ public $typemap(cstype, T) this[$typemap(cstype, K) key] { get { return getitem(key); } set { setitem(key, value); } } public bool TryGetValue($typemap(cstype, K) key, out $typemap(cstype, T) value) { if (this.ContainsKey(key)) { value = this[key]; return true; } value = default($typemap(cstype, T)); return false; } public int Count { get { return (int)size(); } } public bool IsReadOnly { get { return false; } } public global::System.Collections.Generic.ICollection<$typemap(cstype, K)> Keys { get { global::System.Collections.Generic.ICollection<$typemap(cstype, K)> keys = new global::System.Collections.Generic.List<$typemap(cstype, K)>(); int size = this.Count; if (size > 0) { global::System.IntPtr iter = create_iterator_begin(); for (int i = 0; i < size; i++) { keys.Add(get_next_key(iter)); } destroy_iterator(iter); } return keys; } } public global::System.Collections.Generic.ICollection<$typemap(cstype, T)> Values { get { global::System.Collections.Generic.ICollection<$typemap(cstype, T)> vals = new global::System.Collections.Generic.List<$typemap(cstype, T)>(); foreach (global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> pair in this) { vals.Add(pair.Value); } return vals; } } public void Add(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) { Add(item.Key, item.Value); } public bool Remove(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) { if (Contains(item)) { return Remove(item.Key); } else { return false; } } public bool Contains(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) { if (this[item.Key] == item.Value) { return true; } else { return false; } } public void CopyTo(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>[] array) { CopyTo(array, 0); } public void CopyTo(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $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."); global::System.Collections.Generic.IList<$typemap(cstype, K)> keyList = new global::System.Collections.Generic.List<$typemap(cstype, K)>(this.Keys); for (int i = 0; i < keyList.Count; i++) { $typemap(cstype, K) currentKey = keyList[i]; array.SetValue(new global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>(currentKey, this[currentKey]), arrayIndex+i); } } global::System.Collections.Generic.IEnumerator> global::System.Collections.Generic.IEnumerable>.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> { private $csclassname collectionRef; private global::System.Collections.Generic.IList<$typemap(cstype, K)> keyCollection; private int currentIndex; private object currentObject; private int currentSize; public $csclassnameEnumerator($csclassname collection) { collectionRef = collection; keyCollection = new global::System.Collections.Generic.List<$typemap(cstype, K)>(collection.Keys); currentIndex = -1; currentObject = null; currentSize = collectionRef.Count; } // Type-safe iterator Current public global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $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 (global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $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++; $typemap(cstype, K) currentKey = keyCollection[currentIndex]; currentObject = new global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>(currentKey, collectionRef[currentKey]); } 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 K key_type; typedef T mapped_type; typedef std::pair< const K, T > value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; map(); map(const map& other); size_type size() const; bool empty() const; %rename(Clear) clear; void clear(); %extend { const mapped_type& getitem(const key_type& key) throw (std::out_of_range) { std::map< K, T, C >::iterator iter = $self->find(key); if (iter != $self->end()) return iter->second; else throw std::out_of_range("key not found"); } void setitem(const key_type& key, const mapped_type& x) { (*$self)[key] = x; } bool ContainsKey(const key_type& key) { std::map< K, T, C >::iterator iter = $self->find(key); return iter != $self->end(); } void Add(const key_type& key, const mapped_type& value) throw (std::out_of_range) { std::map< K, T, C >::iterator iter = $self->find(key); if (iter != $self->end()) throw std::out_of_range("key already exists"); $self->insert(std::pair< K, T >(key, value)); } bool Remove(const key_type& key) { std::map< K, T, C >::iterator iter = $self->find(key); if (iter != $self->end()) { $self->erase(iter); return true; } return false; } // create_iterator_begin(), get_next_key() and destroy_iterator work together to provide a collection of keys to C# %apply void *VOID_INT_PTR { std::map< K, T, C >::iterator *create_iterator_begin } %apply void *VOID_INT_PTR { std::map< K, T, C >::iterator *swigiterator } std::map< K, T, C >::iterator *create_iterator_begin() { return new std::map< K, T, C >::iterator($self->begin()); } const key_type& get_next_key(std::map< K, T, C >::iterator *swigiterator) { (void)$self; std::map< K, T, C >::iterator iter = *swigiterator; (*swigiterator)++; return (*iter).first; } void destroy_iterator(std::map< K, T, C >::iterator *swigiterator) { (void)$self; delete swigiterator; } } %enddef %csmethodmodifiers std::map::size "private" %csmethodmodifiers std::map::getitem "private" %csmethodmodifiers std::map::setitem "private" %csmethodmodifiers std::map::create_iterator_begin "private" %csmethodmodifiers std::map::get_next_key "private" %csmethodmodifiers std::map::destroy_iterator "private" // Default implementation namespace std { template > class map { SWIG_STD_MAP_INTERNAL(K, T, C) }; } // Legacy macros (deprecated) %define specialize_std_map_on_key(K,CHECK,CONVERT_FROM,CONVERT_TO) #warning "specialize_std_map_on_key ignored - macro is deprecated and no longer necessary" %enddef %define specialize_std_map_on_value(T,CHECK,CONVERT_FROM,CONVERT_TO) #warning "specialize_std_map_on_value ignored - macro is deprecated and no longer necessary" %enddef %define specialize_std_map_on_both(K,CHECK_K,CONVERT_K_FROM,CONVERT_K_TO, T,CHECK_T,CONVERT_T_FROM,CONVERT_T_TO) #warning "specialize_std_map_on_both ignored - macro is deprecated and no longer necessary" %enddef