You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			282 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
			
		
		
	
	
			282 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
| #ifndef SMOKEPERL_H
 | |
| #define SMOKEPERL_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 "EXTERN.h"
 | |
| #include "perl.h"
 | |
| #include "XSUB.h"
 | |
| 
 | |
| #include "perlqt.h"
 | |
| #include "marshall.h"
 | |
| 
 | |
| class SmokePerl;
 | |
| 
 | |
| 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() && !strcmp(a.name(), b.name()))
 | |
| 	    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() && !strcmp(a.className(), b.className()))
 | |
| 	    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 SV* objects. Each SmokeObject instance
 | |
|  * increments the refcount of its SV* for the duration of its existance.
 | |
|  *
 | |
|  * SmokeObject instances are only returned from SmokePerl, since the method
 | |
|  * of binding data to the scalar must be consistent across all modules.
 | |
|  */
 | |
| class SmokeObject {
 | |
|     SV *sv;
 | |
|     Smoke_MAGIC *m;
 | |
|     
 | |
| public:
 | |
|     SmokeObject(SV *obj, Smoke_MAGIC *mag) : sv(obj), m(mag) {
 | |
| 	SvREFCNT_inc(sv);
 | |
|     }
 | |
|     ~SmokeObject() {
 | |
| 	SvREFCNT_dec(sv);
 | |
|     }
 | |
|     SmokeObject(const SmokeObject &other) {
 | |
| 	sv = other.sv;
 | |
| 	m = other.m;
 | |
| 	SvREFCNT_inc(sv);
 | |
|     }
 | |
|     SmokeObject &operator =(const SmokeObject &other) {
 | |
| 	sv = other.sv;
 | |
| 	m = other.m;
 | |
| 	SvREFCNT_inc(sv);
 | |
| 	return *this;
 | |
|     }
 | |
|     
 | |
|     const SmokeClass &c() { return m->c(); }
 | |
|     Smoke *smoke() { return c().smoke(); }
 | |
|     SV *var() { return sv; }
 | |
|     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 SvOK(sv) ? true : false; }
 | |
|     bool isAllocated() const { return m->isAllocated(); }
 | |
|     void setAllocated(bool i) { m->setAllocated(i); }
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Since it's not easy to share functions between Perl modules, the common
 | |
|  * interface between all Smoked libraries and Perl will be defined in this
 | |
|  * class. There will be only one SmokePerl instance loaded for an entire Perl
 | |
|  * process. It has no data members here -- this is only an abstract interface.
 | |
|  */
 | |
| 
 | |
| class SmokePerl {
 | |
|     void *future_extension;
 | |
| public:
 | |
|     SmokePerl() : future_extension(0) {}
 | |
| 
 | |
|     // don't need this, we're only defining an interface
 | |
|     virtual ~SmokePerl() = 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 SV
 | |
|      */
 | |
|     virtual SmokeObject getObject(SV *sv) = 0;
 | |
| };
 | |
| 
 | |
| #endif // SMOKEPERL_H
 |