1 /* ----------------------------------------------------------------------------- 2 * std_map.i 3 * 4 * SWIG typemaps for std::map< K, T, C > 5 * 6 * The C# wrapper is made to look and feel like a C# System.Collections.Generic.IDictionary<>. 7 * 8 * Using this wrapper is fairly simple. For example, to create a map from integers to doubles use: 9 * 10 * %include <std_map.i> 11 * %template(MapIntDouble) std::map<int, double> 12 * 13 * Notes: 14 * 1) For .NET 1 compatibility, define SWIG_DOTNET_1 when compiling the C# code. In this case 15 * the C# wrapper has only basic functionality. 16 * 2) IEnumerable<> is implemented in the proxy class which is useful for using LINQ with 17 * C++ std::map wrappers. 18 * 19 * Warning: heavy macro usage in this file. Use swig -E to get a sane view on the real file contents! 20 * ----------------------------------------------------------------------------- */ 21 22 %{ 23 #include <map> 24 #include <algorithm> 25 #include <stdexcept> 26 %} 27 28 /* K is the C++ key type, T is the C++ value type */ 29 %define SWIG_STD_MAP_INTERNAL(K, T, C) 30 31 %typemap(csinterfaces) std::map< K, T, C > "IDisposable \n#if !SWIG_DOTNET_1\n , System.Collections.Generic.IDictionary<$typemap(cstype, K), $typemap(cstype, T)>\n#endif\n"; 32 %typemap(cscode) std::map<K, T, C > %{ 33 34 public $typemap(cstype, T) this[$typemap(cstype, K) key] { 35 get { 36 return getitem(key); 37 } 38 39 set { 40 setitem(key, value); 41 } 42 } 43 44 public bool TryGetValue($typemap(cstype, K) key, out $typemap(cstype, T) value) { 45 if (this.ContainsKey(key)) { 46 value = this[key]; 47 return true; 48 } 49 value = default($typemap(cstype, T)); 50 return false; 51 } 52 53 public int Count { 54 get { 55 return (int)size(); 56 } 57 } 58 59 public bool IsReadOnly { 60 get { 61 return false; 62 } 63 } 64 65 #if !SWIG_DOTNET_1 66 67 public System.Collections.Generic.ICollection<$typemap(cstype, K)> Keys { 68 get { 69 System.Collections.Generic.ICollection<$typemap(cstype, K)> keys = new System.Collections.Generic.List<$typemap(cstype, K)>(); 70 int size = this.Count; 71 if (size > 0) { 72 IntPtr iter = create_iterator_begin(); 73 for (int i = 0; i < size; i++) { 74 keys.Add(get_next_key(iter)); 75 } 76 destroy_iterator(iter); 77 } 78 return keys; 79 } 80 } 81 82 public System.Collections.Generic.ICollection<$typemap(cstype, T)> Values { 83 get { 84 System.Collections.Generic.ICollection<$typemap(cstype, T)> vals = new System.Collections.Generic.List<$typemap(cstype, T)>(); 85 foreach (System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> pair in this) { 86 vals.Add(pair.Value); 87 } 88 return vals; 89 } 90 } 91 92 public void Add(System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) { 93 Add(item.Key, item.Value); 94 } 95 96 public bool Remove(System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) { 97 if (Contains(item)) { 98 return Remove(item.Key); 99 } else { 100 return false; 101 } 102 } 103 104 public bool Contains(System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) { 105 if (this[item.Key] == item.Value) { 106 return true; 107 } else { 108 return false; 109 } 110 } 111 112 public void CopyTo(System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>[] array) { 113 CopyTo(array, 0); 114 } 115 116 public void CopyTo(System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>[] array, int arrayIndex) { 117 if (array == null) 118 throw new ArgumentNullException("array"); 119 if (arrayIndex < 0) 120 throw new ArgumentOutOfRangeException("arrayIndex", "Value is less than zero"); 121 if (array.Rank > 1) 122 throw new ArgumentException("Multi dimensional array.", "array"); 123 if (arrayIndex+this.Count > array.Length) 124 throw new ArgumentException("Number of elements to copy is too large."); 125 126 System.Collections.Generic.IList<$typemap(cstype, K)> keyList = new System.Collections.Generic.List<$typemap(cstype, K)>(this.Keys); 127 for (int i = 0; i < keyList.Count; i++) { 128 $typemap(cstype, K) currentKey = keyList[i]; 129 array.SetValue(new System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>(currentKey, this[currentKey]), arrayIndex+i); 130 } 131 } 132 133 System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>> System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>>.GetEnumerator() { 134 return new $csclassnameEnumerator(this); 135 } 136 137 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { 138 return new $csclassnameEnumerator(this); 139 } 140 141 public $csclassnameEnumerator GetEnumerator() { 142 return new $csclassnameEnumerator(this); 143 } 144 145 // Type-safe enumerator 146 /// Note that the IEnumerator documentation requires an InvalidOperationException to be thrown 147 /// whenever the collection is modified. This has been done for changes in the size of the 148 /// collection but not when one of the elements of the collection is modified as it is a bit 149 /// tricky to detect unmanaged code that modifies the collection under our feet. 150 public sealed class $csclassnameEnumerator : System.Collections.IEnumerator, 151 System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>> 152 { 153 private $csclassname collectionRef; 154 private System.Collections.Generic.IList<$typemap(cstype, K)> keyCollection; 155 private int currentIndex; 156 private object currentObject; 157 private int currentSize; 158 159 public $csclassnameEnumerator($csclassname collection) { 160 collectionRef = collection; 161 keyCollection = new System.Collections.Generic.List<$typemap(cstype, K)>(collection.Keys); 162 currentIndex = -1; 163 currentObject = null; 164 currentSize = collectionRef.Count; 165 } 166 167 // Type-safe iterator Current 168 public System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> Current { 169 get { 170 if (currentIndex == -1) 171 throw new InvalidOperationException("Enumeration not started."); 172 if (currentIndex > currentSize - 1) 173 throw new InvalidOperationException("Enumeration finished."); 174 if (currentObject == null) 175 throw new InvalidOperationException("Collection modified."); 176 return (System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>)currentObject; 177 } 178 } 179 180 // Type-unsafe IEnumerator.Current 181 object System.Collections.IEnumerator.Current { 182 get { 183 return Current; 184 } 185 } 186 187 public bool MoveNext() { 188 int size = collectionRef.Count; 189 bool moveOkay = (currentIndex+1 < size) && (size == currentSize); 190 if (moveOkay) { 191 currentIndex++; 192 $typemap(cstype, K) currentKey = keyCollection[currentIndex]; 193 currentObject = new System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>(currentKey, collectionRef[currentKey]); 194 } else { 195 currentObject = null; 196 } 197 return moveOkay; 198 } 199 200 public void Reset() { 201 currentIndex = -1; 202 currentObject = null; 203 if (collectionRef.Count != currentSize) { 204 throw new InvalidOperationException("Collection modified."); 205 } 206 } 207 208 public void Dispose() { 209 currentIndex = -1; 210 currentObject = null; 211 } 212 } 213 #endif 214 215 %} 216 217 public: 218 typedef size_t size_type; 219 typedef ptrdiff_t difference_type; 220 typedef K key_type; 221 typedef T mapped_type; 222 223 map(); 224 map(const map< K, T, C > &other); 225 size_type size() const; 226 bool empty() const; 227 %rename(Clear) clear; 228 void clear(); 229 %extend { 230 const mapped_type& getitem(const key_type& key) throw (std::out_of_range) { 231 std::map< K, T, C >::iterator iter = $self->find(key); 232 if (iter != $self->end()) 233 return iter->second; 234 else 235 throw std::out_of_range("key not found"); 236 } 237 238 void setitem(const key_type& key, const mapped_type& x) { 239 (*$self)[key] = x; 240 } 241 242 bool ContainsKey(const key_type& key) { 243 std::map< K, T, C >::iterator iter = $self->find(key); 244 return iter != $self->end(); 245 } 246 247 void Add(const key_type& key, const mapped_type& val) throw (std::out_of_range) { 248 std::map< K, T, C >::iterator iter = $self->find(key); 249 if (iter != $self->end()) 250 throw std::out_of_range("key already exists"); 251 $self->insert(std::pair< K, T >(key, val)); 252 } 253 254 bool Remove(const key_type& key) { 255 std::map< K, T, C >::iterator iter = $self->find(key); 256 if (iter != $self->end()) { 257 $self->erase(iter); 258 return true; 259 } 260 return false; 261 } 262 263 // create_iterator_begin(), get_next_key() and destroy_iterator work together to provide a collection of keys to C# 264 %apply void *VOID_INT_PTR { std::map< K, T, C >::iterator *create_iterator_begin } 265 %apply void *VOID_INT_PTR { std::map< K, T, C >::iterator *swigiterator } 266 267 std::map< K, T, C >::iterator *create_iterator_begin() { 268 return new std::map< K, T, C >::iterator($self->begin()); 269 } 270 271 const key_type& get_next_key(std::map< K, T, C >::iterator *swigiterator) { 272 std::map< K, T, C >::iterator iter = *swigiterator; 273 (*swigiterator)++; 274 return (*iter).first; 275 } 276 277 void destroy_iterator(std::map< K, T, C >::iterator *swigiterator) { 278 delete swigiterator; 279 } 280 } 281 282 283 %enddef 284 285 %csmethodmodifiers std::map::size "private" 286 %csmethodmodifiers std::map::getitem "private" 287 %csmethodmodifiers std::map::setitem "private" 288 %csmethodmodifiers std::map::create_iterator_begin "private" 289 %csmethodmodifiers std::map::get_next_key "private" 290 %csmethodmodifiers std::map::destroy_iterator "private" 291 292 // Default implementation 293 namespace std { 294 template<class K, class T, class C = std::less<K> > class map { 295 SWIG_STD_MAP_INTERNAL(K, T, C) 296 }; 297 } 298 299 300 // Legacy macros (deprecated) 301 %define specialize_std_map_on_key(K,CHECK,CONVERT_FROM,CONVERT_TO) 302 #warning "specialize_std_map_on_key ignored - macro is deprecated and no longer necessary" 303 %enddef 304 305 %define specialize_std_map_on_value(T,CHECK,CONVERT_FROM,CONVERT_TO) 306 #warning "specialize_std_map_on_value ignored - macro is deprecated and no longer necessary" 307 %enddef 308 309 %define specialize_std_map_on_both(K,CHECK_K,CONVERT_K_FROM,CONVERT_K_TO, T,CHECK_T,CONVERT_T_FROM,CONVERT_T_TO) 310 #warning "specialize_std_map_on_both ignored - macro is deprecated and no longer necessary" 311 %enddef 312 313