1 /* 2 Multimaps 3 */ 4 %include <std_map.i> 5 6 %fragment("StdMultimapTraits","header",fragment="StdMapCommonTraits") 7 { 8 namespace swig { 9 template <class RubySeq, class K, class T > 10 inline void 11 assign(const RubySeq& rubyseq, std::multimap<K,T > *multimap) { 12 typedef typename std::multimap<K,T>::value_type value_type; 13 typename RubySeq::const_iterator it = rubyseq.begin(); 14 for (;it != rubyseq.end(); ++it) { 15 multimap->insert(value_type(it->first, it->second)); 16 } 17 } 18 19 template <class K, class T> 20 struct traits_asptr<std::multimap<K,T> > { 21 typedef std::multimap<K,T> multimap_type; 22 static int asptr(VALUE obj, std::multimap<K,T> **val) { 23 int res = SWIG_ERROR; 24 if ( TYPE(obj) == T_HASH ) { 25 static ID id_to_a = rb_intern("to_a"); 26 VALUE items = rb_funcall(obj, id_to_a, 0); 27 return traits_asptr_stdseq<std::multimap<K,T>, std::pair<K, T> >::asptr(items, val); 28 } else { 29 multimap_type *p; 30 res = SWIG_ConvertPtr(obj,(void**)&p,swig::type_info<multimap_type>(),0); 31 if (SWIG_IsOK(res) && val) *val = p; 32 } 33 return res; 34 } 35 }; 36 37 template <class K, class T > 38 struct traits_from<std::multimap<K,T> > { 39 typedef std::multimap<K,T> multimap_type; 40 typedef typename multimap_type::const_iterator const_iterator; 41 typedef typename multimap_type::size_type size_type; 42 43 static VALUE from(const multimap_type& multimap) { 44 swig_type_info *desc = swig::type_info<multimap_type>(); 45 if (desc && desc->clientdata) { 46 return SWIG_NewPointerObj(new multimap_type(multimap), desc, SWIG_POINTER_OWN); 47 } else { 48 size_type size = multimap.size(); 49 int rubysize = (size <= (size_type) INT_MAX) ? (int) size : -1; 50 if (rubysize < 0) { 51 SWIG_RUBY_THREAD_BEGIN_BLOCK; 52 rb_raise(rb_eRuntimeError, 53 "multimap size not valid in Ruby"); 54 SWIG_RUBY_THREAD_END_BLOCK; 55 return Qnil; 56 } 57 VALUE obj = rb_hash_new(); 58 for (const_iterator i= multimap.begin(); i!= multimap.end(); ++i) { 59 VALUE key = swig::from(i->first); 60 VALUE val = swig::from(i->second); 61 62 VALUE oldval = rb_hash_aref( obj, key ); 63 if ( oldval == Qnil ) 64 rb_hash_aset(obj, key, val); 65 else { 66 // Multiple values for this key, create array if needed 67 // and add a new element to it. 68 VALUE ary; 69 if ( TYPE(oldval) == T_ARRAY ) 70 ary = oldval; 71 else 72 { 73 ary = rb_ary_new2(2); 74 rb_ary_push( ary, oldval ); 75 rb_hash_aset( obj, key, ary ); 76 } 77 rb_ary_push( ary, val ); 78 } 79 80 } 81 return obj; 82 } 83 } 84 }; 85 } 86 } 87 88 %define %swig_multimap_methods(MultiMap...) 89 %swig_map_common(%arg(MultiMap)); 90 91 %extend { 92 VALUE __getitem__(const key_type& key) const { 93 MultiMap::const_iterator i = self->find(key); 94 if ( i != self->end() ) 95 { 96 MultiMap::const_iterator e = $self->upper_bound(key); 97 VALUE ary = rb_ary_new(); 98 for ( ; i != e; ++i ) 99 { 100 rb_ary_push( ary, swig::from<MultiMap::mapped_type>( i->second ) ); 101 } 102 if ( RARRAY_LEN(ary) == 1 ) 103 return RARRAY_PTR(ary)[0]; 104 return ary; 105 } 106 else 107 return Qnil; 108 } 109 110 void __setitem__(const key_type& key, const mapped_type& x) throw (std::out_of_range) { 111 self->insert(MultiMap::value_type(key,x)); 112 } 113 114 VALUE inspect() 115 { 116 MultiMap::iterator i = $self->begin(); 117 MultiMap::iterator e = $self->end(); 118 const char *type_name = swig::type_name< MultiMap >(); 119 VALUE str = rb_str_new2( type_name ); 120 str = rb_str_cat2( str, " {" ); 121 VALUE tmp; 122 while ( i != e ) 123 { 124 const MultiMap::key_type& key = i->first; 125 const MultiMap::key_type& oldkey = key; 126 tmp = swig::from( key ); 127 str = rb_str_buf_append( str, rb_inspect(tmp) ); 128 str = rb_str_cat2( str, "=>" ); 129 130 VALUE vals = rb_ary_new(); 131 for ( ; i != e && key == oldkey; ++i ) 132 { 133 const MultiMap::mapped_type& val = i->second; 134 tmp = swig::from( val ); 135 rb_ary_push( vals, tmp ); 136 } 137 138 if ( RARRAY_LEN(vals) == 1 ) 139 { 140 str = rb_str_buf_append( str, rb_inspect(tmp) ); 141 } 142 else 143 { 144 str = rb_str_buf_append( str, rb_inspect(vals) ); 145 } 146 } 147 str = rb_str_cat2( str, "}" ); 148 return str; 149 } 150 151 VALUE to_a() 152 { 153 MultiMap::const_iterator i = $self->begin(); 154 MultiMap::const_iterator e = $self->end(); 155 VALUE ary = rb_ary_new2( std::distance( i, e ) ); 156 VALUE tmp; 157 while ( i != e ) 158 { 159 const MultiMap::key_type& key = i->first; 160 const MultiMap::key_type& oldkey = key; 161 tmp = swig::from( key ); 162 rb_ary_push( ary, tmp ); 163 164 VALUE vals = rb_ary_new(); 165 for ( ; i != e && key == oldkey; ++i ) 166 { 167 const MultiMap::mapped_type& val = i->second; 168 tmp = swig::from( val ); 169 rb_ary_push( vals, tmp ); 170 } 171 172 if ( RARRAY_LEN(vals) == 1 ) 173 { 174 rb_ary_push( ary, tmp ); 175 } 176 else 177 { 178 rb_ary_push( ary, vals ); 179 } 180 } 181 return ary; 182 } 183 184 VALUE to_s() 185 { 186 MultiMap::iterator i = $self->begin(); 187 MultiMap::iterator e = $self->end(); 188 VALUE str = rb_str_new2( "" ); 189 VALUE tmp; 190 while ( i != e ) 191 { 192 const MultiMap::key_type& key = i->first; 193 const MultiMap::key_type& oldkey = key; 194 tmp = swig::from( key ); 195 tmp = rb_obj_as_string( tmp ); 196 str = rb_str_buf_append( str, tmp ); 197 198 VALUE vals = rb_ary_new(); 199 for ( ; i != e && key == oldkey; ++i ) 200 { 201 const MultiMap::mapped_type& val = i->second; 202 tmp = swig::from( val ); 203 rb_ary_push( vals, tmp ); 204 } 205 206 tmp = rb_obj_as_string( vals ); 207 str = rb_str_buf_append( str, tmp ); 208 } 209 return str; 210 } 211 } 212 %enddef 213 214 215 %mixin std::multimap "Enumerable"; 216 217 %rename("delete") std::multimap::__delete__; 218 %rename("reject!") std::multimap::reject_bang; 219 %rename("map!") std::multimap::map_bang; 220 %rename("empty?") std::multimap::empty; 221 %rename("include?" ) std::multimap::__contains__ const; 222 %rename("has_key?" ) std::multimap::has_key const; 223 224 %alias std::multimap::push "<<"; 225 226 %include <std/std_multimap.i> 227 228