You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebindings/tqtruby/rubylib/tqtruby/smokeruby.h

322 lines
9.1 KiB

#ifndef SMOKERUBY_H
#define SMOKERUBY_H
#include "smoke.h"
#undef DEBUG
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_POSIX
#define __USE_POSIX
#endif
#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif
#include "ruby.h"
#include <tqcstring.h>
#include "tqtruby.h"
#include "marshall.h"
class SmokeRuby;
class SmokeType {
Smoke::Type *_t; // derived from _smoke and _id, but cached
Smoke *_smoke;
Smoke::Index _id;
public:
SmokeType() : _t(0), _smoke(0), _id(0) {}
SmokeType(Smoke *s, Smoke::Index i) : _smoke(s), _id(i) {
if(_id < 0 || _id > _smoke->numTypes) _id = 0;
_t = _smoke->types + _id;
}
// default copy constructors are fine, this is a constant structure
// mutators
void set(Smoke *s, Smoke::Index i) {
_smoke = s;
_id = i;
_t = _smoke->types + _id;
}
// accessors
Smoke *smoke() const { return _smoke; }
Smoke::Index typeId() const { return _id; }
const Smoke::Type &type() const { return *_t; }
unsigned short flags() const { return _t->flags; }
unsigned short elem() const { return _t->flags & Smoke::tf_elem; }
const char *name() const { return _t->name; }
Smoke::Index classId() const { return _t->classId; }
// tests
bool isStack() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_stack); }
bool isPtr() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_ptr); }
bool isRef() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_ref); }
bool isConst() const { return (flags() & Smoke::tf_const); }
bool isClass() const {
if(elem() == Smoke::t_class)
return classId() ? true : false;
return false;
}
bool operator ==(const SmokeType &b) const {
const SmokeType &a = *this;
if(a.name() == b.name()) return true;
if(a.name() && b.name() && tqstrcmp(a.name(), b.name()) == 0)
return true;
return false;
}
bool operator !=(const SmokeType &b) const {
const SmokeType &a = *this;
return !(a == b);
}
};
class SmokeClass {
Smoke::Class *_c;
Smoke *_smoke;
Smoke::Index _id;
public:
SmokeClass(const SmokeType &t) {
_smoke = t.smoke();
_id = t.classId();
_c = _smoke->classes + _id;
}
SmokeClass(Smoke *smoke, Smoke::Index id) : _smoke(smoke), _id(id) {
_c = _smoke->classes + _id;
}
Smoke *smoke() const { return _smoke; }
const Smoke::Class &c() const { return *_c; }
Smoke::Index classId() const { return _id; }
const char *className() const { return _c->className; }
Smoke::ClassFn classFn() const { return _c->classFn; }
Smoke::EnumFn enumFn() const { return _c->enumFn; }
bool operator ==(const SmokeClass &b) const {
const SmokeClass &a = *this;
if(a.className() == b.className()) return true;
if(a.className() && b.className() && tqstrcmp(a.className(), b.className()) == 0)
return true;
return false;
}
bool operator !=(const SmokeClass &b) const {
const SmokeClass &a = *this;
return !(a == b);
}
bool isa(const SmokeClass &sc) const {
// This is a sick function, if I do say so myself
if(*this == sc) return true;
Smoke::Index *parents = _smoke->inheritanceList + _c->parents;
for(int i = 0; parents[i]; i++) {
if(SmokeClass(_smoke, parents[i]).isa(sc)) return true;
}
return false;
}
unsigned short flags() const { return _c->flags; }
bool hasConstructor() const { return flags() & Smoke::cf_constructor; }
bool hasCopy() const { return flags() & Smoke::cf_deepcopy; }
bool hasVirtual() const { return flags() & Smoke::cf_virtual; }
bool hasFire() const { return !(flags() & Smoke::cf_undefined); }
};
class SmokeMethod {
Smoke::Method *_m;
Smoke *_smoke;
Smoke::Index _id;
public:
SmokeMethod(Smoke *smoke, Smoke::Index id) : _smoke(smoke), _id(id) {
_m = _smoke->methods + _id;
}
Smoke *smoke() const { return _smoke; }
const Smoke::Method &m() const { return *_m; }
SmokeClass c() const { return SmokeClass(_smoke, _m->classId); }
const char *name() const { return _smoke->methodNames[_m->name]; }
int numArgs() const { return _m->numArgs; }
unsigned short flags() const { return _m->flags; }
SmokeType arg(int i) const {
if(i >= numArgs()) return SmokeType();
return SmokeType(_smoke, _smoke->argumentList[_m->args + i]);
}
SmokeType ret() const { return SmokeType(_smoke, _m->ret); }
Smoke::Index methodId() const { return _id; }
Smoke::Index method() const { return _m->method; }
bool isStatic() const { return flags() & Smoke::mf_static; }
bool isConst() const { return flags() & Smoke::mf_const; }
void call(Smoke::Stack args, void *ptr = 0) const {
Smoke::ClassFn fn = c().classFn();
(*fn)(method(), ptr, args);
}
};
class Smoke_MAGIC { // to be rewritten
SmokeClass _c;
void *_ptr;
bool _isAllocated;
public:
Smoke_MAGIC(void *p, const SmokeClass &c) :
_c(c), _ptr(p), _isAllocated(false) {}
const SmokeClass &c() const { return _c; }
void *ptr() const { return _ptr; }
bool isAllocated() const { return _isAllocated; }
void setAllocated(bool isAllocated) { _isAllocated = isAllocated; }
};
/**
* SmokeObject is a thin wrapper around VALUE objects. Each SmokeObject instance
* increments the refcount of its VALUE for the duration of its existance.
*
* SmokeObject instances are only returned from SmokeRuby, since the method
* of binding data to the scalar must be consistent across all modules.
*/
class SmokeObject {
VALUE rv;
Smoke_MAGIC *m;
public:
SmokeObject(VALUE obj, Smoke_MAGIC *mag) : rv(obj), m(mag) {
rb_gc_register_address(&rv);
}
~SmokeObject() {
rb_gc_unregister_address(&rv);
}
SmokeObject(const SmokeObject &other) {
rv = other.rv;
m = other.m;
rb_gc_register_address(&rv);
}
SmokeObject &operator =(const SmokeObject &other) {
rv = other.rv;
m = other.m;
rb_gc_register_address(&rv);
return *this;
}
const SmokeClass &c() { return m->c(); }
Smoke *smoke() { return c().smoke(); }
VALUE * var() { return &rv; }
void *ptr() { return m->ptr(); }
Smoke::Index classId() { return c().classId(); }
void *cast(const SmokeClass &toc) {
return smoke()->cast(
ptr(),
classId(),
smoke()->idClass(toc.className())
);
}
const char *className() { return c().className(); }
bool isValid() const { return !NIL_P(rv); }
bool isAllocated() const { return m->isAllocated(); }
void setAllocated(bool i) { m->setAllocated(i); }
};
/**
* Since it's not easy to share functions between Ruby modules, the common
* interface between all Smoked libraries and Ruby will be defined in this
* class. There will be only one SmokeRuby instance loaded for an entire Ruby
* process. It has no data members here -- this is only an abstract interface.
*/
class SmokeRuby {
void *future_extension;
public:
SmokeRuby() : future_extension(0) {}
// don't need this, we're only defining an interface
virtual ~SmokeRuby() = 0;
/**
* Registers a Smoke object
*/
virtual void registerSmoke(const char *name, Smoke *smoke) = 0;
/**
* Gets a smoke object from its name
*/
virtual Smoke *getSmoke(const char *name) = 0;
/**
* Determines if the named smoke is registered.
*/
bool isSmokeRegistered(const char *name) { return getSmoke(name) ? true : false; }
virtual void registerHandlers(TypeHandler *handlers) = 0;
/**
* Returns a new blessed SV referring to the pointer passed.
* Use sv_2mortal() before passing it around.
*
* @param p pointer to the C++ object. The pointer isn't automatically deleted by SmokePerl.
* @param c class of the pointer
* @see #getObject
* @see #deleteObject
*/
virtual SmokeObject newObject(void *p, const SmokeClass &c) = 0;
/**
* Same as newObject(), except it doesn't treat p as owned by Perl
*/
virtual SmokeObject wrapObject(void *p, const SmokeClass &c) = 0;
/**
* Any SV* created with newObject() on a class with virtual methods can be
* retrieved again.
*/
virtual SmokeObject getObject(void *p) = 0;
/**
* Create a SmokeObject from the given VALUE
*/
virtual SmokeObject getObject(VALUE value) = 0;
};
/*
* Type handling by moc is simple.
*
* If the type name matches /^(?:const\s+)?\Q$types\E&?$/, use the
* static_QUType, where $types is join('|', qw(bool int double char* TQString);
*
* Everything else is passed as a pointer! There are types which aren't
* Smoke::tf_ptr but will have to be passed as a pointer. Make sure to keep
* track of what's what.
*/
/*
* Simply using typeids isn't enough for signals/slots. It will be possible
* to declare signals and slots which use arguments which can't all be
* found in a single smoke object. Instead, we need to store smoke => typeid
* pairs. We also need additional informatation, such as whether we're passing
* a pointer to the union element.
*/
enum MocArgumentType {
xmoc_ptr,
xmoc_bool,
xmoc_int,
xmoc_double,
xmoc_charstar,
xmoc_QString
};
struct MocArgument {
// smoke object and associated typeid
SmokeType st;
MocArgumentType argType;
};
#endif // SMOKERUBY_H