1// 2// Maps 3// 4%fragment("StdMapTraits","header",fragment="StdSequenceTraits") 5{ 6 namespace swig { 7 template <class RubySeq, class K, class T > 8 inline void 9 assign(const RubySeq& rubyseq, std::map<K,T > *map) { 10 typedef typename std::map<K,T>::value_type value_type; 11 typename RubySeq::const_iterator it = rubyseq.begin(); 12 for (;it != rubyseq.end(); ++it) { 13 map->insert(value_type(it->first, it->second)); 14 } 15 } 16 17 template <class K, class T> 18 struct traits_asptr<std::map<K,T> > { 19 typedef std::map<K,T> map_type; 20 static int asptr(VALUE obj, map_type **val) { 21 int res = SWIG_ERROR; 22 if ( TYPE(obj) == T_HASH ) { 23 static ID id_to_a = rb_intern("to_a"); 24 VALUE items = rb_funcall(obj, id_to_a, 0); 25 res = traits_asptr_stdseq<std::map<K,T>, std::pair<K, T> >::asptr(items, val); 26 } else { 27 map_type *p; 28 res = SWIG_ConvertPtr(obj,(void**)&p,swig::type_info<map_type>(),0); 29 if (SWIG_IsOK(res) && val) *val = p; 30 } 31 return res; 32 } 33 }; 34 35 template <class K, class T > 36 struct traits_from<std::map<K,T> > { 37 typedef std::map<K,T> map_type; 38 typedef typename map_type::const_iterator const_iterator; 39 typedef typename map_type::size_type size_type; 40 41 static VALUE from(const map_type& map) { 42 swig_type_info *desc = swig::type_info<map_type>(); 43 if (desc && desc->clientdata) { 44 return SWIG_NewPointerObj(new map_type(map), desc, SWIG_POINTER_OWN); 45 } else { 46 size_type size = map.size(); 47 int rubysize = (size <= (size_type) INT_MAX) ? (int) size : -1; 48 if (rubysize < 0) { 49 SWIG_RUBY_THREAD_BEGIN_BLOCK; 50 rb_raise( rb_eRuntimeError, "map size not valid in Ruby"); 51 SWIG_RUBY_THREAD_END_BLOCK; 52 return Qnil; 53 } 54 VALUE obj = rb_hash_new(); 55 for (const_iterator i= map.begin(); i!= map.end(); ++i) { 56 VALUE key = swig::from(i->first); 57 VALUE val = swig::from(i->second); 58 rb_hash_aset(obj, key, val); 59 } 60 return obj; 61 } 62 } 63 }; 64 65 template <class ValueType> 66 struct from_key_oper 67 { 68 typedef const ValueType& argument_type; 69 typedef VALUE result_type; 70 result_type operator()(argument_type v) const 71 { 72 return swig::from(v.first); 73 } 74 }; 75 76 template <class ValueType> 77 struct from_value_oper 78 { 79 typedef const ValueType& argument_type; 80 typedef VALUE result_type; 81 result_type operator()(argument_type v) const 82 { 83 return swig::from(v.second); 84 } 85 }; 86 87 template<class OutIterator, class FromOper, 88 class ValueType = typename OutIterator::value_type> 89 struct MapIterator_T : ConstIteratorClosed_T<OutIterator, ValueType, FromOper> 90 { 91 MapIterator_T(OutIterator curr, OutIterator first, OutIterator last, VALUE seq) 92 : ConstIteratorClosed_T<OutIterator,ValueType,FromOper>(curr, first, last, seq) 93 { 94 } 95 }; 96 97 98 template<class OutIterator, 99 class FromOper = from_key_oper<typename OutIterator::value_type> > 100 struct MapKeyIterator_T : MapIterator_T<OutIterator, FromOper> 101 { 102 MapKeyIterator_T(OutIterator curr, OutIterator first, OutIterator last, VALUE seq) 103 : MapIterator_T<OutIterator, FromOper>(curr, first, last, seq) 104 { 105 } 106 }; 107 108 template<typename OutIter> 109 inline ConstIterator* 110 make_output_key_iterator(const OutIter& current, const OutIter& begin, 111 const OutIter& end, VALUE seq = 0) 112 { 113 return new MapKeyIterator_T<OutIter>(current, begin, end, seq); 114 } 115 116 template<class OutIterator, 117 class FromOper = from_value_oper<typename OutIterator::value_type> > 118 struct MapValueIterator_T : MapIterator_T<OutIterator, FromOper> 119 { 120 MapValueIterator_T(OutIterator curr, OutIterator first, OutIterator last, VALUE seq) 121 : MapIterator_T<OutIterator, FromOper>(curr, first, last, seq) 122 { 123 } 124 }; 125 126 127 template<typename OutIter> 128 inline ConstIterator* 129 make_output_value_iterator(const OutIter& current, const OutIter& begin, 130 const OutIter& end, VALUE seq = 0) 131 { 132 return new MapValueIterator_T<OutIter>(current, begin, end, seq); 133 } 134 } 135} 136 137%define %swig_map_common(Map...) 138 %swig_container_methods(%arg(Map)); 139 // %swig_sequence_iterator(%arg(Map)); 140 141 %extend { 142 143 VALUE __delete__(const key_type& key) { 144 Map::iterator i = self->find(key); 145 if (i != self->end()) { 146 self->erase(i); 147 return swig::from( key ); 148 } 149 else { 150 return Qnil; 151 } 152 } 153 154 bool has_key(const key_type& key) const { 155 Map::const_iterator i = self->find(key); 156 return i != self->end(); 157 } 158 159 VALUE keys() { 160 Map::size_type size = self->size(); 161 int rubysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1; 162 if (rubysize < 0) { 163 SWIG_RUBY_THREAD_BEGIN_BLOCK; 164 rb_raise(rb_eRuntimeError, "map size not valid in Ruby"); 165 SWIG_RUBY_THREAD_END_BLOCK; 166 return Qnil; 167 } 168 VALUE ary = rb_ary_new2(rubysize); 169 Map::const_iterator i = self->begin(); 170 Map::const_iterator e = self->end(); 171 for ( ; i != e; ++i ) { 172 rb_ary_push( ary, swig::from(i->first) ); 173 } 174 return ary; 175 } 176 177 Map* each() 178 { 179 if ( !rb_block_given_p() ) 180 rb_raise( rb_eArgError, "no block given"); 181 182 VALUE k, v; 183 Map::iterator i = self->begin(); 184 Map::iterator e = self->end(); 185 for ( ; i != e; ++i ) 186 { 187 const Map::key_type& key = i->first; 188 const Map::mapped_type& val = i->second; 189 190 k = swig::from<Map::key_type>(key); 191 v = swig::from<Map::mapped_type>(val); 192 rb_yield_values(2, k, v); 193 } 194 195 return self; 196 } 197 198 %newobject select; 199 Map* select() { 200 if ( !rb_block_given_p() ) 201 rb_raise( rb_eArgError, "no block given" ); 202 203 Map* r = new Map; 204 Map::iterator i = $self->begin(); 205 Map::iterator e = $self->end(); 206 for ( ; i != e; ++i ) 207 { 208 VALUE k = swig::from<Map::key_type>(i->first); 209 VALUE v = swig::from<Map::mapped_type>(i->second); 210 if ( RTEST( rb_yield_values(2, k, v) ) ) 211 $self->insert(r->end(), *i); 212 } 213 214 return r; 215 } 216 217 %typemap(in) (int argc, VALUE* argv) { 218 $1 = argc; 219 $2 = argv; 220 } 221 222 VALUE values_at(int argc, VALUE* argv, ...) { 223 224 VALUE r = rb_ary_new(); 225 ID id = rb_intern("[]"); 226 swig_type_info* type = swig::type_info< Map >(); 227 VALUE me = SWIG_NewPointerObj( $self, type, 0 ); 228 for ( int i = 0; i < argc; ++i ) 229 { 230 VALUE key = argv[i]; 231 VALUE tmp = rb_funcall( me, id, 1, key ); 232 rb_ary_push( r, tmp ); 233 } 234 235 return r; 236 } 237 238 239 Map* each_key() 240 { 241 if ( !rb_block_given_p() ) 242 rb_raise( rb_eArgError, "no block given"); 243 244 VALUE r; 245 Map::iterator i = self->begin(); 246 Map::iterator e = self->end(); 247 for ( ; i != e; ++i ) 248 { 249 r = swig::from( i->first ); 250 rb_yield(r); 251 } 252 253 return self; 254 } 255 256 VALUE values() { 257 Map::size_type size = self->size(); 258 int rubysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1; 259 if (rubysize < 0) { 260 SWIG_RUBY_THREAD_BEGIN_BLOCK; 261 rb_raise(rb_eRuntimeError, "map size not valid in Ruby"); 262 SWIG_RUBY_THREAD_END_BLOCK; 263 return Qnil; 264 } 265 VALUE ary = rb_ary_new2(rubysize); 266 Map::const_iterator i = self->begin(); 267 Map::const_iterator e = self->end(); 268 for ( ; i != e; ++i ) { 269 rb_ary_push( ary, swig::from(i->second) ); 270 } 271 return ary; 272 } 273 274 Map* each_value() 275 { 276 if ( !rb_block_given_p() ) 277 rb_raise( rb_eArgError, "no block given"); 278 279 VALUE r; 280 Map::iterator i = self->begin(); 281 Map::iterator e = self->end(); 282 for ( ; i != e; ++i ) 283 { 284 r = swig::from( i->second ); 285 rb_yield(r); 286 } 287 288 return self; 289 } 290 291 VALUE entries() { 292 Map::size_type size = self->size(); 293 int rubysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1; 294 if (rubysize < 0) { 295 SWIG_RUBY_THREAD_BEGIN_BLOCK; 296 rb_raise(rb_eRuntimeError, "map size not valid in Ruby"); 297 SWIG_RUBY_THREAD_END_BLOCK; 298 return Qnil; 299 } 300 VALUE ary = rb_ary_new2(rubysize); 301 Map::const_iterator i = self->begin(); 302 Map::const_iterator e = self->end(); 303 for ( ; i != e; ++i ) { 304 rb_ary_push( ary, swig::from<std::pair<Map::key_type, 305 Map::mapped_type> >(*i) ); 306 } 307 return ary; 308 } 309 310 bool __contains__(const key_type& key) { 311 return self->find(key) != self->end(); 312 } 313 314 %newobject key_iterator(VALUE *RUBY_SELF); 315 swig::ConstIterator* key_iterator(VALUE *RUBY_SELF) { 316 return swig::make_output_key_iterator($self->begin(), $self->begin(), 317 $self->end(), *RUBY_SELF); 318 } 319 320 %newobject value_iterator(VALUE *RUBY_SELF); 321 swig::ConstIterator* value_iterator(VALUE *RUBY_SELF) { 322 return swig::make_output_value_iterator($self->begin(), $self->begin(), 323 $self->end(), *RUBY_SELF); 324 } 325 326 } 327%enddef 328 329%define %swig_map_methods(Map...) 330 %swig_map_common(Map) 331 %extend { 332 VALUE __getitem__(const key_type& key) const { 333 Map::const_iterator i = self->find(key); 334 if ( i != self->end() ) 335 return swig::from<Map::mapped_type>( i->second ); 336 else 337 return Qnil; 338 } 339 340 void __setitem__(const key_type& key, const mapped_type& x) throw (std::out_of_range) { 341 (*self)[key] = x; 342 } 343 344 VALUE inspect() 345 { 346 Map::const_iterator i = $self->begin(); 347 Map::const_iterator e = $self->end(); 348 VALUE str = rb_str_new2( swig::type_name< Map >() ); 349 str = rb_str_cat2( str, " {" ); 350 bool comma = false; 351 VALUE tmp; 352 for ( ; i != e; ++i, comma = true ) 353 { 354 if (comma) str = rb_str_cat2( str, "," ); 355 tmp = swig::from< Map::key_type >( i->first ); 356 tmp = rb_inspect( tmp ); 357 str = rb_str_buf_append( str, tmp ); 358 str = rb_str_cat2( str, "=>" ); 359 tmp = swig::from< Map::mapped_type >( i->second ); 360 tmp = rb_inspect( tmp ); 361 str = rb_str_buf_append( str, tmp ); 362 } 363 str = rb_str_cat2( str, "}" ); 364 return str; 365 } 366 367 VALUE to_a() 368 { 369 Map::const_iterator i = $self->begin(); 370 Map::const_iterator e = $self->end(); 371 VALUE ary = rb_ary_new2( std::distance( i, e ) ); 372 VALUE tmp; 373 for ( ; i != e; ++i ) 374 { 375 // @todo: improve -- this should just be swig::from(*i) 376 tmp = swig::from< std::pair<Map::key_type, 377 Map::mapped_type> >( *i ); 378 rb_ary_push( ary, tmp ); 379 } 380 return ary; 381 } 382 383 VALUE to_s() 384 { 385 Map::iterator i = $self->begin(); 386 Map::iterator e = $self->end(); 387 VALUE str = rb_str_new2( "" ); 388 VALUE tmp; 389 for ( ; i != e; ++i ) 390 { 391 // @todo: improve -- this should just be swig::from(*i) 392 tmp = swig::from< std::pair<Map::key_type, 393 Map::mapped_type> >( *i ); 394 tmp = rb_obj_as_string( tmp ); 395 str = rb_str_buf_append( str, tmp ); 396 } 397 return str; 398 } 399 400 } 401%enddef 402 403 404%mixin std::map "Enumerable"; 405 406 407%rename("delete") std::map::__delete__; 408%rename("reject!") std::map::reject_bang; 409%rename("map!") std::map::map_bang; 410%rename("empty?") std::map::empty; 411%rename("include?" ) std::map::__contains__ const; 412%rename("has_key?" ) std::map::has_key const; 413 414%alias std::map::push "<<"; 415 416 417%include <std/std_map.i> 418