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