rubyclasses.swg 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  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 SwigGCReferences {
  27. VALUE _hash;
  28. SwigGCReferences() : _hash(Qnil) {
  29. }
  30. ~SwigGCReferences() {
  31. if (_hash != Qnil)
  32. rb_gc_unregister_address(&_hash);
  33. }
  34. static void EndProcHandler(VALUE) {
  35. // Ruby interpreter ending - _hash can no longer be accessed.
  36. SwigGCReferences &s_references = instance();
  37. s_references._hash = Qnil;
  38. }
  39. public:
  40. static SwigGCReferences& instance() {
  41. // Hash of all GC_VALUE's currently in use
  42. static SwigGCReferences s_references;
  43. return s_references;
  44. }
  45. static void initialize() {
  46. SwigGCReferences &s_references = instance();
  47. if (s_references._hash == Qnil) {
  48. rb_set_end_proc(&EndProcHandler, Qnil);
  49. s_references._hash = rb_hash_new();
  50. rb_gc_register_address(&s_references._hash);
  51. }
  52. }
  53. void GC_register(VALUE& obj) {
  54. if (FIXNUM_P(obj) || SPECIAL_CONST_P(obj) || SYMBOL_P(obj))
  55. return;
  56. if (_hash != Qnil) {
  57. VALUE val = rb_hash_aref(_hash, obj);
  58. unsigned n = FIXNUM_P(val) ? NUM2UINT(val) : 0;
  59. ++n;
  60. rb_hash_aset(_hash, obj, INT2NUM(n));
  61. }
  62. }
  63. void GC_unregister(const VALUE& obj) {
  64. if (FIXNUM_P(obj) || SPECIAL_CONST_P(obj) || SYMBOL_P(obj))
  65. return;
  66. // this test should not be needed but I've noticed some very erratic
  67. // behavior of none being unregistered in some very rare situations.
  68. if (BUILTIN_TYPE(obj) == T_NONE)
  69. return;
  70. if (_hash != Qnil) {
  71. VALUE val = rb_hash_aref(_hash, obj);
  72. unsigned n = FIXNUM_P(val) ? NUM2UINT(val) : 1;
  73. --n;
  74. if (n)
  75. rb_hash_aset(_hash, obj, INT2NUM(n));
  76. else
  77. rb_hash_delete(_hash, obj);
  78. }
  79. }
  80. };
  81. class GC_VALUE {
  82. protected:
  83. VALUE _obj;
  84. static ID hash_id;
  85. static ID lt_id;
  86. static ID gt_id;
  87. static ID eq_id;
  88. static ID le_id;
  89. static ID ge_id;
  90. static ID pos_id;
  91. static ID neg_id;
  92. static ID inv_id;
  93. static ID add_id;
  94. static ID sub_id;
  95. static ID mul_id;
  96. static ID div_id;
  97. static ID mod_id;
  98. static ID and_id;
  99. static ID or_id;
  100. static ID xor_id;
  101. static ID lshift_id;
  102. static ID rshift_id;
  103. struct OpArgs
  104. {
  105. VALUE src;
  106. ID id;
  107. int nargs;
  108. VALUE target;
  109. };
  110. public:
  111. GC_VALUE() : _obj(Qnil)
  112. {
  113. }
  114. GC_VALUE(const GC_VALUE& item) : _obj(item._obj)
  115. {
  116. SwigGCReferences::instance().GC_register(_obj);
  117. }
  118. GC_VALUE(VALUE obj) :_obj(obj)
  119. {
  120. SwigGCReferences::instance().GC_register(_obj);
  121. }
  122. ~GC_VALUE()
  123. {
  124. SwigGCReferences::instance().GC_unregister(_obj);
  125. }
  126. GC_VALUE & operator=(const GC_VALUE& item)
  127. {
  128. SwigGCReferences::instance().GC_unregister(_obj);
  129. _obj = item._obj;
  130. SwigGCReferences::instance().GC_register(_obj);
  131. return *this;
  132. }
  133. operator VALUE() const
  134. {
  135. return _obj;
  136. }
  137. VALUE inspect() const
  138. {
  139. return rb_inspect(_obj);
  140. }
  141. VALUE to_s() const
  142. {
  143. return rb_inspect(_obj);
  144. }
  145. static VALUE swig_rescue_swallow(VALUE)
  146. {
  147. /*
  148. VALUE errstr = rb_obj_as_string(rb_errinfo());
  149. printf("Swallowing error: '%s'\n", RSTRING_PTR(StringValue(errstr)));
  150. */
  151. return Qnil; /* Swallow Ruby exception */
  152. }
  153. static VALUE swig_rescue_funcall(VALUE p)
  154. {
  155. OpArgs* args = (OpArgs*) p;
  156. return rb_funcall(args->src, args->id, args->nargs, args->target);
  157. }
  158. bool relational_equal_op(const GC_VALUE& other, const ID& op_id, bool (*op_func)(const VALUE& a, const VALUE& b)) const
  159. {
  160. if (FIXNUM_P(_obj) && FIXNUM_P(other._obj)) {
  161. return op_func(_obj, other._obj);
  162. }
  163. bool res = false;
  164. VALUE ret = Qnil;
  165. SWIG_RUBY_THREAD_BEGIN_BLOCK;
  166. if (rb_respond_to(_obj, op_id)) {
  167. OpArgs args;
  168. args.src = _obj;
  169. args.id = op_id;
  170. args.nargs = 1;
  171. args.target = VALUE(other);
  172. ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
  173. (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
  174. }
  175. if (ret == Qnil) {
  176. VALUE a = rb_funcall( _obj, hash_id, 0 );
  177. VALUE b = rb_funcall( VALUE(other), hash_id, 0 );
  178. res = op_func(a, b);
  179. } else {
  180. res = RTEST(ret);
  181. }
  182. SWIG_RUBY_THREAD_END_BLOCK;
  183. return res;
  184. }
  185. static bool operator_eq(const VALUE& a, const VALUE& b) { return a == b; }
  186. static bool operator_lt(const VALUE& a, const VALUE& b) { return a < b; }
  187. static bool operator_le(const VALUE& a, const VALUE& b) { return a <= b; }
  188. static bool operator_gt(const VALUE& a, const VALUE& b) { return a > b; }
  189. static bool operator_ge(const VALUE& a, const VALUE& b) { return a >= b; }
  190. bool operator==(const GC_VALUE& other) const { return relational_equal_op(other, eq_id, operator_eq); }
  191. bool operator<(const GC_VALUE& other) const { return relational_equal_op(other, lt_id, operator_lt); }
  192. bool operator<=(const GC_VALUE& other) const { return relational_equal_op(other, le_id, operator_le); }
  193. bool operator>(const GC_VALUE& other) const { return relational_equal_op(other, gt_id, operator_gt); }
  194. bool operator>=(const GC_VALUE& other) const { return relational_equal_op(other, ge_id, operator_ge); }
  195. bool operator!=(const GC_VALUE& other) const
  196. {
  197. return !(this->operator==(other));
  198. }
  199. GC_VALUE unary_op(const ID& op_id) const
  200. {
  201. VALUE ret = Qnil;
  202. SWIG_RUBY_THREAD_BEGIN_BLOCK;
  203. OpArgs args;
  204. args.src = _obj;
  205. args.id = op_id;
  206. args.nargs = 0;
  207. args.target = Qnil;
  208. ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
  209. (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
  210. SWIG_RUBY_THREAD_END_BLOCK;
  211. return ret;
  212. }
  213. GC_VALUE operator+() const { return unary_op(pos_id); }
  214. GC_VALUE operator-() const { return unary_op(neg_id); }
  215. GC_VALUE operator~() const { return unary_op(inv_id); }
  216. GC_VALUE binary_op(const GC_VALUE& other, const ID& op_id) const
  217. {
  218. VALUE ret = Qnil;
  219. SWIG_RUBY_THREAD_BEGIN_BLOCK;
  220. OpArgs args;
  221. args.src = _obj;
  222. args.id = op_id;
  223. args.nargs = 1;
  224. args.target = VALUE(other);
  225. ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
  226. (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
  227. SWIG_RUBY_THREAD_END_BLOCK;
  228. return GC_VALUE(ret);
  229. }
  230. GC_VALUE operator+(const GC_VALUE& other) const { return binary_op(other, add_id); }
  231. GC_VALUE operator-(const GC_VALUE& other) const { return binary_op(other, sub_id); }
  232. GC_VALUE operator*(const GC_VALUE& other) const { return binary_op(other, mul_id); }
  233. GC_VALUE operator/(const GC_VALUE& other) const { return binary_op(other, div_id); }
  234. GC_VALUE operator%(const GC_VALUE& other) const { return binary_op(other, mod_id); }
  235. GC_VALUE operator&(const GC_VALUE& other) const { return binary_op(other, and_id); }
  236. GC_VALUE operator^(const GC_VALUE& other) const { return binary_op(other, xor_id); }
  237. GC_VALUE operator|(const GC_VALUE& other) const { return binary_op(other, or_id); }
  238. GC_VALUE operator<<(const GC_VALUE& other) const { return binary_op(other, lshift_id); }
  239. GC_VALUE operator>>(const GC_VALUE& other) const { return binary_op(other, rshift_id); }
  240. };
  241. ID GC_VALUE::hash_id = rb_intern("hash");
  242. ID GC_VALUE::lt_id = rb_intern("<");
  243. ID GC_VALUE::gt_id = rb_intern(">");
  244. ID GC_VALUE::eq_id = rb_intern("==");
  245. ID GC_VALUE::le_id = rb_intern("<=");
  246. ID GC_VALUE::ge_id = rb_intern(">=");
  247. ID GC_VALUE::pos_id = rb_intern("+@");
  248. ID GC_VALUE::neg_id = rb_intern("-@");
  249. ID GC_VALUE::inv_id = rb_intern("~");
  250. ID GC_VALUE::add_id = rb_intern("+");
  251. ID GC_VALUE::sub_id = rb_intern("-");
  252. ID GC_VALUE::mul_id = rb_intern("*");
  253. ID GC_VALUE::div_id = rb_intern("/");
  254. ID GC_VALUE::mod_id = rb_intern("%");
  255. ID GC_VALUE::and_id = rb_intern("&");
  256. ID GC_VALUE::or_id = rb_intern("|");
  257. ID GC_VALUE::xor_id = rb_intern("^");
  258. ID GC_VALUE::lshift_id = rb_intern("<<");
  259. ID GC_VALUE::rshift_id = rb_intern(">>");
  260. typedef GC_VALUE LANGUAGE_OBJ;
  261. } // namespace swig
  262. } // %fragment(GC_VALUE_definition)
  263. namespace swig {
  264. %apply VALUE {GC_VALUE};
  265. // Make sure this is the last typecheck done
  266. %typecheck(999999,fragment="GC_VALUE_definition",noblock=1) GC_VALUE, GC_VALUE&,
  267. const GC_VALUE& { $1 = 1; };
  268. /* For input */
  269. %typemap(in,fragment="GC_VALUE_definition",noblock=1) GC_VALUE* (GC_VALUE r), GC_VALUE& (GC_VALUE r) {
  270. r = $input; $1 = &r;
  271. }
  272. /* For output */
  273. %typemap(out,fragment="GC_VALUE_definition",noblock=1) GC_VALUE {
  274. $result = (VALUE)$1;
  275. }
  276. %typemap(out,fragment="GC_VALUE_definition",noblock=1) GC_VALUE*, GC_VALUE const & {
  277. $result = (VALUE)*$1;
  278. }
  279. %nodirector GC_VALUE;
  280. // We ignore the constructor so that user can never create a GC_VALUE
  281. // manually
  282. %ignore GC_VALUE::GC_VALUE;
  283. struct GC_VALUE {
  284. VALUE inspect() const;
  285. VALUE to_s() const;
  286. GC_VALUE();
  287. protected:
  288. GC_VALUE(const GC_VALUE&);
  289. ~GC_VALUE();
  290. };
  291. %exception GC_VALUE {};
  292. %ignore LANGUAGE_OBJ;
  293. typedef GC_VALUE LANGUAGE_OBJ;
  294. }
  295. %init {
  296. swig::SwigGCReferences::initialize();
  297. }
  298. //
  299. // Fragment that contains traits to properly deal with GC_VALUE.
  300. // These functions may be invoked as a need of the from(), asval(),
  301. // asptr() and as() template functors, usually used in %typemaps.
  302. //
  303. %fragment(SWIG_Traits_frag(swig::GC_VALUE),"header",fragment="StdTraits",fragment="GC_VALUE_definition") {
  304. namespace swig {
  305. template <> struct traits<GC_VALUE > {
  306. typedef value_category category;
  307. static const char* type_name() { return "GC_VALUE"; }
  308. };
  309. template <> struct traits_from<GC_VALUE> {
  310. typedef GC_VALUE value_type;
  311. static VALUE from(const value_type& val) {
  312. return static_cast<VALUE>(val);
  313. }
  314. };
  315. template <>
  316. struct traits_check<GC_VALUE, value_category> {
  317. static bool check(GC_VALUE) {
  318. return true;
  319. }
  320. };
  321. template <> struct traits_asval<GC_VALUE > {
  322. typedef GC_VALUE value_type;
  323. static int asval(VALUE obj, value_type *val) {
  324. if (val) *val = obj;
  325. return SWIG_OK;
  326. }
  327. };
  328. } // swig
  329. } // %fragment(traits for swig::GC_VALUE)
  330. #endif // __cplusplus