PageRenderTime 7ms CodeModel.GetById 2ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/Lib/ruby/rubyclasses.swg

#
Unknown | 396 lines | 315 code | 81 blank | 0 comment | 0 complexity | 6c659a4b001fb19b91633282bf7dd498 MD5 | raw file
  1#ifdef __cplusplus
  2
  3/*
  4  GC_VALUE is used as a replacement of Ruby's VALUE.
  5  GC_VALUE automatically handles registering and unregistering
  6  of the underlying Ruby object with the GC.
  7
  8  It can be used if you want to create STL containers of VALUEs, such as:
  9  
 10     std::vector< GC_VALUE >;
 11
 12  or as a member variable:
 13  
 14     struct A {
 15       GC_VALUE _obj;
 16       A(VALUE o) : _obj(o) {
 17       }
 18     };
 19
 20   or as a input/output value (not much use for this, as VALUE works just as
 21   well here, thou):
 22
 23     GC_VALUE func(GC_VALUE obj) { 
 24       GC_VALUE out = rb_obj_classname(obj);
 25       return out;
 26     }
 27
 28
 29   GC_VALUE is 'visible' at the wrapped side, so you can do:
 30
 31      %template(RubyVector) std::vector<swig::GC_VALUE>;
 32
 33   and all the proper typemaps will be used.
 34   
 35*/
 36
 37%fragment("GC_VALUE_definition","header") {
 38namespace swig {
 39  class GC_VALUE {
 40  protected:
 41    // Hash of all GC_VALUE's currently in use
 42    static VALUE _hash;
 43
 44    VALUE  _obj;
 45
 46    static ID hash_id;
 47    static ID   lt_id;
 48    static ID   gt_id;
 49    static ID   eq_id;
 50    static ID   le_id;
 51    static ID   ge_id;
 52
 53    static ID  pos_id;
 54    static ID  neg_id;
 55    static ID  inv_id;
 56
 57    static ID  add_id;
 58    static ID  sub_id;
 59    static ID  mul_id;
 60    static ID  div_id;
 61    static ID  mod_id;
 62
 63    static ID  and_id;
 64    static ID   or_id;
 65    static ID  xor_id;
 66
 67    static ID  lshift_id;
 68    static ID  rshift_id;
 69
 70    struct OpArgs
 71    {
 72      VALUE src;
 73      ID    id;
 74      int   nargs;
 75      VALUE target;
 76    };
 77
 78
 79  public:
 80    static void initialize()
 81    {
 82      if ( _hash == Qnil ) 
 83	{ 
 84	  _hash = rb_hash_new();
 85	  rb_gc_register_address( &_hash );
 86	}
 87    }
 88
 89    // this function is never called.  Provided for symmetry only.
 90    static void cleanup()
 91    {
 92      rb_gc_unregister_address( &_hash );
 93    }
 94
 95    GC_VALUE() : _obj( Qnil )
 96    {
 97    }
 98
 99    GC_VALUE(const GC_VALUE& item) : _obj(item._obj)
100    {
101      GC_register();
102    }
103    
104    GC_VALUE(VALUE obj) :_obj(obj)
105    {
106      GC_register();
107    }
108    
109    ~GC_VALUE() 
110    {
111      GC_unregister();
112    }
113    
114    GC_VALUE & operator=(const GC_VALUE& item) 
115    {
116      GC_unregister();
117      _obj = item._obj;
118      GC_register();
119      return *this;
120    }
121
122    void GC_register()
123    {
124      if ( FIXNUM_P(_obj) || SPECIAL_CONST_P(_obj) || SYMBOL_P(_obj) ) 
125	return;
126      VALUE val = rb_hash_aref( _hash, _obj );
127      unsigned n = FIXNUM_P(val) ? NUM2UINT(val) : 0;
128      ++n;
129      rb_hash_aset( _hash, _obj, INT2NUM(n) );
130    }
131
132    void GC_unregister()
133    {
134      if ( FIXNUM_P(_obj) || SPECIAL_CONST_P(_obj) || SYMBOL_P(_obj) ) 
135	return;
136      // this test should not be needed but I've noticed some very erratic
137      // behavior of none being unregistered in some very rare situations.
138      if ( BUILTIN_TYPE(_obj) == T_NONE ) return;
139
140      VALUE val = rb_hash_aref( _hash, _obj );
141      unsigned n = FIXNUM_P(val) ? NUM2UINT(val) : 1;
142      --n;
143      if ( n )
144	rb_hash_aset( _hash, _obj, INT2NUM(n) );
145      else
146	rb_hash_delete( _hash, _obj );
147    }
148    
149    operator VALUE() const
150    {
151      return _obj;
152    }
153
154    VALUE inspect() const
155    {
156      return rb_inspect(_obj);
157    }
158
159    VALUE to_s() const
160    {
161      return rb_inspect(_obj);
162    }
163
164    static VALUE swig_protect_funcall( VALUE p )
165    {
166      OpArgs* args = (OpArgs*) p;
167      return rb_funcall( args->src, args->id, args->nargs, args->target );
168    }
169
170
171%#define GC_VALUE_CMP( op_id, op, cmp, cmpval ) \
172    bool op( const GC_VALUE& other ) const \
173    { \
174      if ( FIXNUM_P(_obj) && FIXNUM_P(other._obj) ) \
175      { \
176	return _obj cmp other._obj; \
177      } \
178      bool  res = false; \
179      VALUE ret = Qnil; \
180      SWIG_RUBY_THREAD_BEGIN_BLOCK; \
181      if ( rb_respond_to( _obj, op_id ) == Qtrue ) \
182	{ \
183	  int status; \
184	  OpArgs  args; \
185          args.src    = _obj; \
186	  args.id     = op_id; \
187	  args.nargs  = 1; \
188	  args.target = VALUE(other); \
189	  ret = rb_protect( PROTECTFUNC(swig_protect_funcall), \
190                            VALUE(&args), &status ); \
191	} \
192      if ( ret == Qnil ) { \
193	VALUE a = rb_funcall(         _obj, hash_id, 0 ); \
194	VALUE b = rb_funcall( VALUE(other), hash_id, 0 ); \
195	res = a cmp b; \
196      } \
197      else \
198	{ \
199	  res = RTEST( ret ); \
200	} \
201      SWIG_RUBY_THREAD_END_BLOCK; \
202      return res; \
203    }
204
205
206    GC_VALUE_CMP( eq_id, operator==, ==, == 0 )
207    GC_VALUE_CMP( lt_id, operator<,  < , <  0 )
208    GC_VALUE_CMP( le_id, operator<=, <=, <= 0 )
209    GC_VALUE_CMP( gt_id, operator>,  > , >  0 )
210    GC_VALUE_CMP( ge_id, operator>=, >=, >= 0 )
211%#undef GC_VALUE_CMP
212
213    bool operator!=( const GC_VALUE& other )
214    {
215      return !(this->operator==(other));
216    }
217
218%#define GC_VALUE_UNARY( proc_id, op ) \
219    GC_VALUE op() const \
220    { \
221      VALUE ret = Qnil; \
222      SWIG_RUBY_THREAD_BEGIN_BLOCK; \
223      int status; \
224      OpArgs  args; \
225      args.src    = _obj; \
226      args.id     = proc_id; \
227      args.nargs  = 0; \
228      args.target = Qnil; \
229      ret = rb_protect( PROTECTFUNC(swig_protect_funcall), VALUE(&args), \
230			&status ); \
231      SWIG_RUBY_THREAD_END_BLOCK; \
232      return ret; \
233    }
234
235    GC_VALUE_UNARY( pos_id, operator+ )
236    GC_VALUE_UNARY( neg_id, operator- )
237    GC_VALUE_UNARY( inv_id, operator~ )
238%#undef GC_VALUE_BINARY
239
240%#define GC_VALUE_BINARY( proc_id, op ) \
241    GC_VALUE op( const GC_VALUE& other ) const \
242    { \
243      VALUE ret = Qnil; \
244      SWIG_RUBY_THREAD_BEGIN_BLOCK; \
245      int status; \
246      OpArgs  args; \
247      args.src    = _obj; \
248      args.id     = proc_id; \
249      args.nargs  = 1; \
250      args.target = VALUE(other); \
251      ret = rb_protect( PROTECTFUNC(swig_protect_funcall), VALUE(&args), \
252			&status ); \
253      SWIG_RUBY_THREAD_END_BLOCK; \
254      return GC_VALUE(ret); \
255    }
256
257    GC_VALUE_BINARY( add_id, operator+ );
258    GC_VALUE_BINARY( sub_id, operator- );
259    GC_VALUE_BINARY( mul_id, operator* );
260    GC_VALUE_BINARY( div_id, operator/ );
261    GC_VALUE_BINARY( mod_id, operator% );
262    
263    GC_VALUE_BINARY( and_id, operator& );
264    GC_VALUE_BINARY( xor_id, operator^ );
265    GC_VALUE_BINARY(  or_id, operator| );
266
267    GC_VALUE_BINARY( lshift_id, operator<< );
268    GC_VALUE_BINARY( rshift_id, operator>> );
269%#undef GC_VALUE_BINARY
270
271  };
272
273  ID  GC_VALUE::hash_id = rb_intern("hash");
274  ID  GC_VALUE::lt_id = rb_intern("<");
275  ID  GC_VALUE::gt_id = rb_intern(">");
276  ID  GC_VALUE::eq_id = rb_intern("==");
277  ID  GC_VALUE::le_id = rb_intern("<=");
278  ID  GC_VALUE::ge_id = rb_intern(">=");
279
280  ID  GC_VALUE::pos_id = rb_intern("+@");
281  ID  GC_VALUE::neg_id = rb_intern("-@");
282  ID  GC_VALUE::inv_id = rb_intern("~");
283
284  ID  GC_VALUE::add_id = rb_intern("+");
285  ID  GC_VALUE::sub_id = rb_intern("-");
286  ID  GC_VALUE::mul_id = rb_intern("*");
287  ID  GC_VALUE::div_id = rb_intern("/");
288  ID  GC_VALUE::mod_id = rb_intern("%");
289
290  ID  GC_VALUE::and_id = rb_intern("&");
291  ID  GC_VALUE::or_id  = rb_intern("|");
292  ID  GC_VALUE::xor_id = rb_intern("^");
293
294  ID  GC_VALUE::lshift_id = rb_intern("<<");
295  ID  GC_VALUE::rshift_id = rb_intern(">>");
296
297  VALUE GC_VALUE::_hash = Qnil;
298
299  typedef GC_VALUE LANGUAGE_OBJ;
300
301} // namespace swig
302
303} // %fragment(GC_VALUE_definition)
304
305
306
307namespace swig {
308
309  %apply VALUE   {GC_VALUE};
310
311  // Make sure this is the last typecheck done
312  %typecheck(999999,fragment="GC_VALUE_definition",noblock=1) GC_VALUE, GC_VALUE&, 
313    const GC_VALUE& { $1 = 1; };
314
315  /* For input */
316  %typemap(in,fragment="GC_VALUE_definition",noblock=1) GC_VALUE* (GC_VALUE r), GC_VALUE& (GC_VALUE r)  {
317     r = $input; $1 = &r;
318   }
319
320  /* For output */
321  %typemap(out,fragment="GC_VALUE_definition",noblock=1)  GC_VALUE {
322    $result = (VALUE)$1;
323  }
324  
325  %typemap(out,fragment="GC_VALUE_definition",noblock=1)  GC_VALUE*, GC_VALUE const & {
326    $result = (VALUE)*$1;
327  }
328
329  %nodirector GC_VALUE;
330
331  // We ignore the constructor so that user can never create a GC_VALUE 
332  // manually
333  %ignore GC_VALUE::GC_VALUE;
334
335  struct GC_VALUE {
336    VALUE inspect() const;
337    VALUE to_s() const;
338    GC_VALUE();
339  protected:
340    GC_VALUE( const GC_VALUE& );
341    ~GC_VALUE();
342  };
343
344  %exception GC_VALUE {};
345
346
347  %ignore LANGUAGE_OBJ;
348  typedef GC_VALUE LANGUAGE_OBJ;
349}
350
351
352%init {
353  swig::GC_VALUE::initialize();
354}
355
356
357
358//
359// Fragment that contains traits to properly deal with GC_VALUE.
360// These functions may be invoked as a need of the from(), asval(),
361// asptr() and as() template functors, usually used in %typemaps.
362//
363%fragment(SWIG_Traits_frag(swig::GC_VALUE),"header",fragment="StdTraits",fragment="GC_VALUE_definition") {
364namespace swig {
365  template <>  struct traits<GC_VALUE > {
366    typedef value_category category;
367    static const char* type_name() { return "GC_VALUE"; }
368  };
369  
370  template <>  struct traits_from<GC_VALUE> {
371    typedef GC_VALUE value_type;
372    static VALUE from(const value_type& val) {
373      return static_cast<VALUE>(val);
374    }
375  };
376  
377  template <> 
378  struct traits_check<GC_VALUE, value_category> {
379    static bool check(GC_VALUE) {
380      return true;
381    }
382  };
383  
384  template <>  struct traits_asval<GC_VALUE > {   
385    typedef GC_VALUE value_type;
386    static int asval(VALUE obj, value_type *val) {
387      if (val) *val = obj;
388      return SWIG_OK;
389    }
390  };
391} // swig
392} // %fragment(traits for swig::GC_VALUE)
393
394
395#endif  // __cplusplus
396