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