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