Home | History | Annotate | Download | only in csharp
      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