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.
161 lines
4.4 KiB
C++
161 lines
4.4 KiB
C++
/* see copyright notice in squirrel.h */
|
|
#ifndef _SQCLASS_H_
|
|
#define _SQCLASS_H_
|
|
|
|
struct SQInstance;
|
|
|
|
struct SQClassMember {
|
|
SQClassMember(){}
|
|
SQClassMember(const SQClassMember &o) {
|
|
val = o.val;
|
|
attrs = o.attrs;
|
|
}
|
|
SQClassMember& operator=(SQClassMember &o) = delete;
|
|
SQObjectPtr val;
|
|
SQObjectPtr attrs;
|
|
};
|
|
|
|
typedef sqvector<SQClassMember> SQClassMemberVec;
|
|
|
|
#define MEMBER_TYPE_METHOD 0x01000000
|
|
#define MEMBER_TYPE_FIELD 0x02000000
|
|
#define MEMBER_MAX_COUNT 0x00FFFFFF
|
|
|
|
#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD)
|
|
#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD)
|
|
#define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|i))
|
|
#define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|i))
|
|
#define _member_type(o) (_integer(o)&0xFF000000)
|
|
#define _member_idx(o) (_integer(o)&0x00FFFFFF)
|
|
|
|
struct SQClass : public CHAINABLE_OBJ
|
|
{
|
|
SQClass(SQSharedState *ss,SQClass *base);
|
|
public:
|
|
static SQClass* Create(SQSharedState *ss,SQClass *base) {
|
|
SQClass *newclass = new (SQAllocationTag{}) SQClass(ss, base);
|
|
return newclass;
|
|
}
|
|
~SQClass();
|
|
bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic);
|
|
bool Get(const SQObjectPtr &key,SQObjectPtr &val) {
|
|
if(_members->Get(key,val)) {
|
|
if(_isfield(val)) {
|
|
SQObjectPtr &o = _defaultvalues[_member_idx(val)].val;
|
|
val = _realval(o);
|
|
}
|
|
else {
|
|
val = _methods[_member_idx(val)].val;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val);
|
|
bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval);
|
|
void Lock() { _locked = true; if(_base) _base->Lock(); }
|
|
void Release() override {
|
|
if (_hook) { _hook(_typetag,0);}
|
|
sq_delete_refcounted(this, SQClass);
|
|
}
|
|
void Finalize() override;
|
|
#ifndef NO_GARBAGE_COLLECTOR
|
|
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override;
|
|
#endif
|
|
SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);
|
|
SQInstance *CreateInstance();
|
|
SQTable *_members;
|
|
SQClass *_base;
|
|
SQClassMemberVec _defaultvalues;
|
|
SQClassMemberVec _methods;
|
|
SQObjectPtrVec _metamethods;
|
|
SQObjectPtr _attributes;
|
|
SQUserPointer _typetag;
|
|
SQRELEASEHOOK _hook;
|
|
bool _locked;
|
|
SQInteger _udsize;
|
|
};
|
|
|
|
#define calcinstancesize(_theclass_) \
|
|
(_theclass_->_udsize + sizeof(SQInstance) + (sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0)))
|
|
|
|
struct SQInstance : public SQDelegable
|
|
{
|
|
void Init(SQSharedState *ss);
|
|
SQInstance(SQSharedState *ss, SQClass *c);
|
|
SQInstance(SQSharedState *ss, SQInstance *c);
|
|
public:
|
|
static SQInstance* Create(SQSharedState *ss,SQClass *theclass) {
|
|
|
|
SQInteger size = calcinstancesize(theclass);
|
|
SQInstance *newinst = new (SQSizedAllocationTag(size)) SQInstance(ss, theclass);
|
|
if(theclass->_udsize) {
|
|
newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize);
|
|
}
|
|
return newinst;
|
|
}
|
|
SQInstance *Clone(SQSharedState *ss)
|
|
{
|
|
SQInteger size = calcinstancesize(_class);
|
|
SQInstance *newinst = new (SQSizedAllocationTag(size)) SQInstance(ss, this);
|
|
if(_class->_udsize) {
|
|
newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize);
|
|
}
|
|
return newinst;
|
|
}
|
|
~SQInstance();
|
|
bool Get(const SQObjectPtr &key,SQObjectPtr &val) {
|
|
if(_class->_members->Get(key,val)) {
|
|
if(_isfield(val)) {
|
|
SQObjectPtr &o = _values[_member_idx(val)];
|
|
val = _realval(o);
|
|
}
|
|
else {
|
|
val = _class->_methods[_member_idx(val)].val;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool Set(const SQObjectPtr &key,const SQObjectPtr &val) {
|
|
SQObjectPtr idx;
|
|
if(_class->_members->Get(key,idx) && _isfield(idx)) {
|
|
_values[_member_idx(idx)] = val;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
void Release() override {
|
|
_uiRef++;
|
|
try {
|
|
if (_hook) { _hook(_userpointer,0);}
|
|
} catch (...) {
|
|
_uiRef--;
|
|
if (_uiRef == 0) {
|
|
this->_sharedstate->DelayFinalFree(this);
|
|
}
|
|
throw;
|
|
}
|
|
_uiRef--;
|
|
if(_uiRef > 0) return;
|
|
this->_sharedstate->DelayFinalFree(this);
|
|
}
|
|
void FinalFree() override
|
|
{
|
|
sq_delete_refcounted(this, SQInstance);
|
|
}
|
|
void Finalize() override;
|
|
#ifndef NO_GARBAGE_COLLECTOR
|
|
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override;
|
|
#endif
|
|
bool InstanceOf(SQClass *trg);
|
|
bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) override;
|
|
|
|
SQClass *_class;
|
|
SQUserPointer _userpointer;
|
|
SQRELEASEHOOK _hook;
|
|
SQObjectPtr _values[1];
|
|
};
|
|
|
|
#endif //_SQCLASS_H_
|