mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-23 14:46:53 +00:00
396 lines
8.8 KiB
Plaintext
396 lines
8.8 KiB
Plaintext
#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.
|
|
|
|
*/
|
|
|
|
namespace swig {
|
|
|
|
%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 {};
|
|
|
|
|
|
%apply VALUE {GC_VALUE};
|
|
|
|
// Make sure this is the last typecheck done
|
|
%typecheck(999999,noblock=1) GC_VALUE, GC_VALUE&,
|
|
const GC_VALUE& { $1 = 1; };
|
|
|
|
/* For input */
|
|
%typemap(in,noblock=1) GC_VALUE* (GC_VALUE r), GC_VALUE& (GC_VALUE r) {
|
|
r = $input; $1 = &r;
|
|
}
|
|
|
|
/* For output */
|
|
%typemap(out,noblock=1) GC_VALUE {
|
|
$result = (VALUE)$1;
|
|
}
|
|
|
|
%typemap(out,noblock=1) GC_VALUE*, GC_VALUE const & {
|
|
$result = (VALUE)*$1;
|
|
}
|
|
|
|
%ignore LANGUAGE_OBJ;
|
|
typedef GC_VALUE LANGUAGE_OBJ;
|
|
}
|
|
|
|
|
|
%{
|
|
namespace swig {
|
|
class GC_VALUE {
|
|
protected:
|
|
// Hash of all GC_VALUE's currently in use
|
|
static VALUE _hash;
|
|
|
|
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:
|
|
static void initialize()
|
|
{
|
|
if ( _hash == Qnil )
|
|
{
|
|
_hash = rb_hash_new();
|
|
rb_gc_register_address( &_hash );
|
|
}
|
|
}
|
|
|
|
// this function is never called. Provided for symmetry only.
|
|
static void cleanup()
|
|
{
|
|
rb_gc_unregister_address( &_hash );
|
|
}
|
|
|
|
GC_VALUE() : _obj( Qnil )
|
|
{
|
|
}
|
|
|
|
GC_VALUE(const GC_VALUE& item) : _obj(item._obj)
|
|
{
|
|
GC_register();
|
|
}
|
|
|
|
GC_VALUE(VALUE obj) :_obj(obj)
|
|
{
|
|
GC_register();
|
|
}
|
|
|
|
~GC_VALUE()
|
|
{
|
|
GC_unregister();
|
|
}
|
|
|
|
GC_VALUE & operator=(const GC_VALUE& item)
|
|
{
|
|
GC_unregister();
|
|
_obj = item._obj;
|
|
GC_register();
|
|
return *this;
|
|
}
|
|
|
|
void GC_register()
|
|
{
|
|
if ( FIXNUM_P(_obj) || SPECIAL_CONST_P(_obj) || SYMBOL_P(_obj) )
|
|
return;
|
|
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()
|
|
{
|
|
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;
|
|
|
|
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 );
|
|
}
|
|
|
|
operator VALUE() const
|
|
{
|
|
return _obj;
|
|
}
|
|
|
|
VALUE inspect() const
|
|
{
|
|
return rb_inspect(_obj);
|
|
}
|
|
|
|
VALUE to_s() const
|
|
{
|
|
return rb_inspect(_obj);
|
|
}
|
|
|
|
static VALUE swig_protect_funcall( VALUE p )
|
|
{
|
|
OpArgs* args = (OpArgs*) p;
|
|
return rb_funcall( args->src, args->id, args->nargs, args->target );
|
|
}
|
|
|
|
|
|
#define GC_VALUE_CMP( op_id, op, cmp, cmpval ) \
|
|
bool op( const GC_VALUE& other ) const \
|
|
{ \
|
|
if ( FIXNUM_P(_obj) && FIXNUM_P(other._obj) ) \
|
|
{ \
|
|
return _obj cmp other._obj; \
|
|
} \
|
|
bool res = false; \
|
|
VALUE ret = Qnil; \
|
|
SWIG_RUBY_THREAD_BEGIN_BLOCK; \
|
|
if ( rb_respond_to( _obj, op_id ) == Qtrue ) \
|
|
{ \
|
|
int status; \
|
|
OpArgs args; \
|
|
args.src = _obj; \
|
|
args.id = op_id; \
|
|
args.nargs = 1; \
|
|
args.target = VALUE(other); \
|
|
ret = rb_protect( PROTECTFUNC(swig_protect_funcall), \
|
|
VALUE(&args), &status ); \
|
|
} \
|
|
if ( ret == Qnil ) { \
|
|
VALUE a = rb_funcall( _obj, hash_id, 0 ); \
|
|
VALUE b = rb_funcall( VALUE(other), hash_id, 0 ); \
|
|
res = a cmp b; \
|
|
} \
|
|
else \
|
|
{ \
|
|
res = RTEST( ret ); \
|
|
} \
|
|
SWIG_RUBY_THREAD_END_BLOCK; \
|
|
return res; \
|
|
}
|
|
|
|
|
|
GC_VALUE_CMP( eq_id, operator==, ==, == 0 )
|
|
GC_VALUE_CMP( lt_id, operator<, < , < 0 )
|
|
GC_VALUE_CMP( le_id, operator<=, <=, <= 0 )
|
|
GC_VALUE_CMP( gt_id, operator>, > , > 0 )
|
|
GC_VALUE_CMP( ge_id, operator>=, >=, >= 0 )
|
|
#undef GC_VALUE_CMP
|
|
|
|
bool operator!=( const GC_VALUE& other )
|
|
{
|
|
return !(this->operator==(other));
|
|
}
|
|
|
|
#define GC_VALUE_UNARY( proc_id, op ) \
|
|
GC_VALUE op() const \
|
|
{ \
|
|
VALUE ret = Qnil; \
|
|
SWIG_RUBY_THREAD_BEGIN_BLOCK; \
|
|
int status; \
|
|
OpArgs args; \
|
|
args.src = _obj; \
|
|
args.id = proc_id; \
|
|
args.nargs = 0; \
|
|
args.target = Qnil; \
|
|
ret = rb_protect( PROTECTFUNC(swig_protect_funcall), VALUE(&args), \
|
|
&status ); \
|
|
SWIG_RUBY_THREAD_END_BLOCK; \
|
|
return ret; \
|
|
}
|
|
|
|
GC_VALUE_UNARY( pos_id, operator+ )
|
|
GC_VALUE_UNARY( neg_id, operator- )
|
|
GC_VALUE_UNARY( inv_id, operator~ )
|
|
#undef GC_VALUE_BINARY
|
|
|
|
#define GC_VALUE_BINARY( proc_id, op ) \
|
|
GC_VALUE op( const GC_VALUE& other ) const \
|
|
{ \
|
|
VALUE ret = Qnil; \
|
|
SWIG_RUBY_THREAD_BEGIN_BLOCK; \
|
|
int status; \
|
|
OpArgs args; \
|
|
args.src = _obj; \
|
|
args.id = proc_id; \
|
|
args.nargs = 1; \
|
|
args.target = VALUE(other); \
|
|
ret = rb_protect( PROTECTFUNC(swig_protect_funcall), VALUE(&args), \
|
|
&status ); \
|
|
SWIG_RUBY_THREAD_END_BLOCK; \
|
|
return GC_VALUE(ret); \
|
|
}
|
|
|
|
GC_VALUE_BINARY( add_id, operator+ );
|
|
GC_VALUE_BINARY( sub_id, operator- );
|
|
GC_VALUE_BINARY( mul_id, operator* );
|
|
GC_VALUE_BINARY( div_id, operator/ );
|
|
GC_VALUE_BINARY( mod_id, operator% );
|
|
|
|
GC_VALUE_BINARY( and_id, operator& );
|
|
GC_VALUE_BINARY( xor_id, operator^ );
|
|
GC_VALUE_BINARY( or_id, operator| );
|
|
|
|
GC_VALUE_BINARY( lshift_id, operator<< );
|
|
GC_VALUE_BINARY( rshift_id, operator>> );
|
|
#undef GC_VALUE_BINARY
|
|
|
|
};
|
|
|
|
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(">>");
|
|
|
|
VALUE GC_VALUE::_hash = Qnil;
|
|
|
|
typedef GC_VALUE LANGUAGE_OBJ;
|
|
|
|
} // namespace swig
|
|
|
|
%}
|
|
|
|
|
|
%init {
|
|
swig::GC_VALUE::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") {
|
|
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
|
|
|