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