1/* 2 Multimaps 3*/ 4%include <std_map.i> 5 6%fragment("StdMultimapTraits","header",fragment="StdSequenceTraits") 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 VALUE str = rb_str_new2( swig::type_name< MultiMap >() ); 119 str = rb_str_cat2( str, " {" ); 120 VALUE tmp; 121 while ( i != e ) 122 { 123 const MultiMap::key_type& key = i->first; 124 const MultiMap::key_type& oldkey = key; 125 tmp = swig::from( key ); 126 str = rb_str_buf_append( str, rb_inspect(tmp) ); 127 str = rb_str_cat2( str, "=>" ); 128 129 VALUE vals = rb_ary_new(); 130 for ( ; i != e && key == oldkey; ++i ) 131 { 132 const MultiMap::mapped_type& val = i->second; 133 tmp = swig::from( val ); 134 rb_ary_push( vals, tmp ); 135 } 136 137 if ( RARRAY_LEN(vals) == 1 ) 138 { 139 str = rb_str_buf_append( str, rb_inspect(tmp) ); 140 } 141 else 142 { 143 str = rb_str_buf_append( str, rb_inspect(vals) ); 144 } 145 } 146 str = rb_str_cat2( str, "}" ); 147 return str; 148 } 149 150 VALUE to_a() 151 { 152 MultiMap::const_iterator i = $self->begin(); 153 MultiMap::const_iterator e = $self->end(); 154 VALUE ary = rb_ary_new2( std::distance( i, e ) ); 155 VALUE tmp; 156 while ( i != e ) 157 { 158 const MultiMap::key_type& key = i->first; 159 const MultiMap::key_type& oldkey = key; 160 tmp = swig::from( key ); 161 rb_ary_push( ary, tmp ); 162 163 VALUE vals = rb_ary_new(); 164 for ( ; i != e && key == oldkey; ++i ) 165 { 166 const MultiMap::mapped_type& val = i->second; 167 tmp = swig::from( val ); 168 rb_ary_push( vals, tmp ); 169 } 170 171 if ( RARRAY_LEN(vals) == 1 ) 172 { 173 rb_ary_push( ary, tmp ); 174 } 175 else 176 { 177 rb_ary_push( ary, vals ); 178 } 179 } 180 return ary; 181 } 182 183 VALUE to_s() 184 { 185 MultiMap::iterator i = $self->begin(); 186 MultiMap::iterator e = $self->end(); 187 VALUE str = rb_str_new2( "" ); 188 VALUE tmp; 189 while ( i != e ) 190 { 191 const MultiMap::key_type& key = i->first; 192 const MultiMap::key_type& oldkey = key; 193 tmp = swig::from( key ); 194 tmp = rb_obj_as_string( tmp ); 195 str = rb_str_buf_append( str, tmp ); 196 197 VALUE vals = rb_ary_new(); 198 for ( ; i != e && key == oldkey; ++i ) 199 { 200 const MultiMap::mapped_type& val = i->second; 201 tmp = swig::from( val ); 202 rb_ary_push( vals, tmp ); 203 } 204 205 tmp = rb_obj_as_string( vals ); 206 str = rb_str_buf_append( str, tmp ); 207 } 208 return str; 209 } 210 } 211%enddef 212 213 214%mixin std::multimap "Enumerable"; 215 216%rename("delete") std::multimap::__delete__; 217%rename("reject!") std::multimap::reject_bang; 218%rename("map!") std::multimap::map_bang; 219%rename("empty?") std::multimap::empty; 220%rename("include?" ) std::multimap::__contains__ const; 221%rename("has_key?" ) std::multimap::has_key const; 222 223%alias std::multimap::push "<<"; 224 225%include <std/std_multimap.i> 226 227