// SqPlus.h // Created by John Schultz 9/05/05, major update 10/05/05. // Template function call design from LuaPlusCD by Joshua C. Jensen, // inspired by luabind which was inspired by boost::python. // Const argument, const member functions, and Mac OS-X changes by Simon Michelmore. // DECLARE_INSTANCE_TYPE_NAME changes by Ben (Project5) from http://www.squirrel-lang.org/forums/. // Added Kamaitati's changes 5/28/06. // Free for any use. #ifndef _SQ_PLUS_H_ #define _SQ_PLUS_H_ #include #include #ifdef __APPLE__ #include #else #include #endif #include #include #include // For INT_MAX on GCC #include "squirrel.h" // Include to get SQUNICODE setting from here #ifndef _SC #error No _SC macro - Usually defined in squirrel.h #endif // Provide a _sqT(...) macros also (same as _SC but easier to know its for Squirrel) #ifndef _sqT #define _sqT _SC #endif // For backward compatibility, define _T if outside of Windows platform. // (really, _SC() or _sqT() are better, since that leaves us free to run // Squirrel in ASCII or wchar_t mode, regardless of the app being built). #if !defined(_WIN32) && !defined(_WIN64) #ifndef _T #define _T _SC #endif #endif // A comment about strings. We let squirrel.h determine whether to use // char or wchar_t strings. So here we follow the define SQUNICODE. This // opens up for using Unicode system calls on Windows while having the script // engine in ASCII mode, or vice versa. To enable this, also the macro // _SC("some string") is used instead of _T("some string"). // // To handle the case where function parameters are given in the opposite // character mode (char if SQChar is wchar_t and vice versa), such strings // can be converted on the fly to the other mode in the function call, if // the define SQPLUS_AUTOCONVERT_OTHER_CHAR is set below. Buffers are // allocated and kept around for the duration of the function call. The // same applies to returned strings of the opposite type. #if defined(_MSC_VER) || defined(__BORLANDC__) #include #ifndef SQUNICODE #define SCSNPRINTF _snprintf #define SCPUTS puts #else #define SCSNPRINTF _snwprintf #define SCPUTS _putws #endif #if defined(_MSC_VER) #ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE // Disable warnings around various sprintf #endif #pragma warning(disable: 4996) // When above does not work #endif #else #ifdef SQUNICODE #define SCSNPRINTF _snwprintf #define SCPUTS _putws #include // for snprintf #else #define SCSNPRINTF snprintf #include // for snprintf #define SCPUTS puts #endif #endif #ifndef _WINDEF_ typedef int BOOL; typedef int INT; typedef float FLOAT; #define TRUE 1 #define FALSE 0 #endif #if 1 #define SQ_CALL_RAISE_ERROR SQTrue #else #define SQ_CALL_RAISE_ERROR SQFalse #endif #include "SquirrelObject.h" #include "SquirrelVM.h" #include "SquirrelBindingsUtils.h" // All setup defines have moved to its own file #include "SqPlusSetup.h" #ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR #define SQPLUS_AUTOCONVERT_MAX_INSTANCES 8 // In argument conversion, don't keep more than this alive #include "SqPlusOCharBuf.h" #endif #if defined(SQPLUS_SUPPORT_STD_STRING) && defined(SQUNICODE) #ifdef _MSC_VER #pragma message("std::string and SQChar as wchar_t is not compatible!") #else #warning std::string and SQChar as wchar_t is not compatible! #endif #endif namespace SqPlus { template struct TypeWrapper {}; struct SquirrelNull {}; struct SQNoBaseClass {}; // For scripted classes with no base class (or no scripted base class) struct SQAnything { void * anything; }; // Needed for binding pointers to variables (cannot dereference void *). typedef SQAnything * SQAnythingPtr; typedef SQChar * SQCharPtr; // Helper struct to (sometimes) store a temporary return value as another type. // Useful when returning const char* and other types that require temp allocation. // For primitive types, it just maps onto itself. template struct Temporary { typedef T type; }; // References are tricky, but they should just be filtered out usually template struct SqAssignableRef { SqAssignableRef( ) : m_pt(0) { } void operator = (T& tr){ m_pt=&tr; } operator T& () { return *m_pt; } T *m_pt; }; template struct Temporary { typedef SqAssignableRef type; }; // === Do not use directly: use one of the predefined sizes below === struct ScriptStringVarBase { const unsigned char MaxLength; // Real length is MaxLength+1. SQChar s[1]; ScriptStringVarBase(int _MaxLength) : MaxLength(_MaxLength) {} operator SQChar * () { return &s[0]; } operator void * () { return (void *)&s[0]; } const SQChar * operator = (const SQChar * _s) { return safeStringCopy(s,_s,MaxLength); } // Special safe string copy where MaxLength is 1 less than true buffer length. // strncpy() pads out nulls for the full length of the buffer specified by MaxLength. static inline SQChar * safeStringCopy(SQChar * d,const SQChar * s,int MaxLength) { int i=0; while (s[i]) { d[i] = s[i]; i++; if (i == MaxLength) break; } // while d[i] = 0; // Null terminate. return d; } // safeStringCopy }; // === Do not use directly: use one of the predefined sizes below === template // MAXLENGTH is max printable characters (trailing NULL is accounted for in ScriptStringVarBase::s[1]). struct ScriptStringVar : ScriptStringVarBase { SQChar ps[MAXLENGTH]; ScriptStringVar() : ScriptStringVarBase(MAXLENGTH) { s[0] = 0; } ScriptStringVar(const SQChar * _s) : ScriptStringVarBase(MAXLENGTH) { *this = _s; } const SQChar * operator = (const SQChar * _s) { return safeStringCopy(s,_s,MaxLength); } const SQChar * operator = (const ScriptStringVar & _s) { return safeStringCopy(s,_s.s,MaxLength); } bool operator == (const ScriptStringVar & _s) { return _strcmp(s,_s.s) == 0; } bool compareCaseInsensitive(const ScriptStringVar & _s) { return _stricmp(s,_s.s) == 0; } }; // === Fixed size strings for scripting === typedef ScriptStringVar<8> ScriptStringVar8; typedef ScriptStringVar<16> ScriptStringVar16; typedef ScriptStringVar<32> ScriptStringVar32; typedef ScriptStringVar<64> ScriptStringVar64; typedef ScriptStringVar<128> ScriptStringVar128; typedef ScriptStringVar<256> ScriptStringVar256; // === Script Variable Types === enum ScriptVarType { VAR_TYPE_NONE = -1, VAR_TYPE_INT = 0, VAR_TYPE_UINT, VAR_TYPE_FLOAT, VAR_TYPE_BOOL, VAR_TYPE_CONST_STRING, VAR_TYPE_STRING, VAR_TYPE_USER_POINTER, VAR_TYPE_INSTANCE, #ifdef SQPLUS_SUPPORT_STD_STRING VAR_TYPE_STD_STRING, #endif }; template struct TypeInfo { const SQChar * typeName; enum {TypeID=VAR_TYPE_NONE, Size=0, TypeMask='?', IsInstance=0}; }; // === Common Variable Types === template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("int")) {} enum {TypeID=VAR_TYPE_INT,Size=sizeof(INT),TypeMask='i', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("uint")) {} enum {TypeID=VAR_TYPE_UINT,Size=sizeof(unsigned), IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("float")) {} enum {TypeID=VAR_TYPE_FLOAT,Size=sizeof(FLOAT),TypeMask='f', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("bool")) {} enum {TypeID=VAR_TYPE_BOOL,Size=sizeof(bool),TypeMask='b', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("short")) {} enum {TypeID=VAR_TYPE_INT,Size=sizeof(short),TypeMask='i', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("char")) {} enum {TypeID=VAR_TYPE_INT,Size=sizeof(char),TypeMask='i', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("SQUserPointer")) {} enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(SQUserPointer),TypeMask='u', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("SQUserPointer")) {} enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(SQUserPointer),TypeMask='u', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(0) {} enum {TypeID=-1,Size=0,TypeMask=' ', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("const SQChar *")) {} enum {TypeID=VAR_TYPE_CONST_STRING,Size=sizeof(const SQChar *),TypeMask='s', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; #ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("const SQOtherChar *")) {} enum {TypeID=VAR_TYPE_CONST_STRING,Size=sizeof(const SQOtherChar *),TypeMask='s', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template<> struct Temporary { typedef SQOthCharBuf type; }; template<> struct Temporary { typedef SQOthCharBuf type; }; #endif // SQPLUS_AUTOCONVERT_OTHER_CHAR // base case: raw pointer template struct TypeInfoPtrBase { const SQChar * typeName; TypeInfoPtrBase() : typeName(TypeInfo().typeName) {} enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(T*),TypeMask='u'}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; template struct TypeInfoPtrBase : public TypeInfo { }; // Partial specialization for pointers (to access type without pointer / or instance typeinfo) template struct TypeInfo : public TypeInfoPtrBase::IsInstance> { }; // Same thing for references template struct TypeInfo : public TypeInfoPtrBase::IsInstance> { }; #ifdef SQPLUS_SUPPORT_STD_STRING template<> struct TypeInfo { const SQChar *typeName; TypeInfo() : typeName(_SC("std::string")) {} enum {TypeID=SqPlus::VAR_TYPE_STD_STRING,Size=sizeof(std::string),TypeMask='s'}; operator ScriptVarType() {return ScriptVarType(TypeID);} }; #endif template<> struct TypeInfo { const SQChar * typeName; TypeInfo() : typeName(_SC("ScriptStringVarBase")) {} enum {TypeID=VAR_TYPE_STRING,Size=sizeof(ScriptStringVarBase),TypeMask='s', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; // === Fixed String Variants === template struct TypeInfo > { SQChar typeName[24]; TypeInfo() { scsprintf(typeName,_SC("ScriptStringVar<%d>"),N); } enum {TypeID=VAR_TYPE_STRING,Size=N*sizeof(ScriptStringVar),TypeMask='s', IsInstance=0}; operator ScriptVarType() { return ScriptVarType(TypeID); } }; #ifdef SQPLUS_SMARTPOINTER_OPT #define SQPLUS_SMARTPOINTER_ACCESSTYPE #include "SqPlusSmartPointer.h" #else enum VarAccessType {VAR_ACCESS_READ_WRITE=0,VAR_ACCESS_READ_ONLY=1<<0,VAR_ACCESS_CONSTANT=1<<1,VAR_ACCESS_STATIC=1<<2}; #endif // SQPLUS_SMARTPOINTER_OPT // See VarRef and ClassType<> below: for instance assignment. typedef void (*CopyVarFunc)(void * dst,void * src); // === Class Type Helper class: returns an ID for each class type and provides base class pointer offset === struct ClassTypeBase { ClassTypeBase() : m_pbase(0), m_name(0), m_offset(0), m_may_have_offset(-1) { } // Many types cannot have offset, since "this" is the same for all base classes of // an instance. Detect this, to avoid sum up base offsets all the time. int MayHaveOffset( ) { if( m_may_have_offset<0 ){ if( m_offset ) m_may_have_offset = 1; else m_may_have_offset = m_pbase ? m_pbase->MayHaveOffset() : 0; } return m_may_have_offset; } int GetOffsetTo( ClassTypeBase *pbase ){ if( !m_pbase ) { /*printf("ClassTypeBase::getOffsetTo - Warning - Base type pointer is NULL!\n" );*/ return 0; } return m_pbase==pbase ? m_offset : m_offset+m_pbase->GetOffsetTo(pbase); } virtual CopyVarFunc vgetCopyFunc(void) = 0; virtual const SQChar* GetTypeName() = 0; ClassTypeBase *m_pbase; const SQChar *m_name; // Name of type int m_offset; // Adjustment of this pointer between this type and its base class int m_may_have_offset; // Set to 0 for types that cannot possibly have offset }; // This level handles instance copying in different ways template struct ClassTypeCopyImpl; // Helper struct to decide if type is copyable or not template struct IsCopyable { enum { value=true }; }; #define DECLARE_NONCOPY_TYPE_INTERN(TYPE) \ template<> struct IsCopyable { enum { value=false }; }; // Macro to declare a type that should _not_ be copied using ordinary // c++ copy expresssion: *(T*)pt1 = *(T*)pt2; #define DECLARE_NONCOPY_TYPE(TYPE) namespace SqPlus { \ template<> struct IsCopyable { enum { value=false }; }; \ } // Base class to do copying in ordinary C++ way template struct ClassTypeCopyImpl : public ClassTypeBase { static void copy(T * dst,T * src) { *dst = *src; // This works types with copy ctor / assign operator } // copy }; // Base class to do copying with memcpy template struct ClassTypeCopyImpl : public ClassTypeBase { static void copy(T * dst,T * src) { memcpy(dst,src,sizeof(T)); // This works for raw data types } // copy }; // Base classes to do avoid copying altogether (void case) template<> struct ClassTypeCopyImpl : public ClassTypeBase { static void copy(void * dst,void * src) { } // copy }; template<> struct ClassTypeCopyImpl : public ClassTypeBase { static void copy(void * dst,void * src) { } // copy }; template struct ClassType : public ClassTypeCopyImpl::value> { typedef ClassTypeCopyImpl::value> ClassTypeBase; ClassType( ) { this->m_name=stGetName(); } virtual CopyVarFunc vgetCopyFunc(void) { return (CopyVarFunc)&ClassTypeBase::copy; } virtual const SQChar* GetTypeName(){ return this->m_name; } template void SetBase(TypeWrapper) { this->m_pbase = ClassType::Get(); T* pt = reinterpret_cast(this); this->m_offset = ((char*)pt)-((char*)static_cast(pt)); } static ClassType* Get(){ static ClassType st_ct; return &st_ct; } static ClassTypeBase* type() { return Get(); } static CopyVarFunc getCopyFunc(void) { return (CopyVarFunc)&ClassTypeBase::copy; } static const SQChar* stGetName(){ return TypeInfo().typeName; } #ifdef SQPLUS_OVERLOAD_OPT #define SQPLUS_OVERLOAD_RELEASE_HOOK #include "SqPlusOverload.h" #endif }; // === Variable references for script access === #define SQ_PLUS_TYPE_TABLE _SC("__SqTypes") struct VarRef { // In this case 'offsetOrAddrOrConst' is simpler than using an anonymous union. void * offsetOrAddrOrConst; // Instance member variable offset from 'this' pointer base (as size_t), or address if static variable (void *), or constant value. ScriptVarType m_type; // Variable type (from enum above). ClassTypeBase* instanceType; // Class type of the containing class instance (for member vars only). ClassTypeBase* varType; // The class type of the variable itself short m_size; // ATS: Use for short and char support. For debugging only (size of item when pointer to item is dereferenced). Could be used for variable max string buffer length. short m_access; // VarAccessType. VarRef() : offsetOrAddrOrConst(0), m_type(VAR_TYPE_NONE), instanceType(0/*(SQUserPointer)-1*/), /*copyFunc(0),*/ m_size(0), m_access(VAR_ACCESS_READ_WRITE) {} VarRef(void * _offsetOrAddrOrConst, ScriptVarType _type, ClassTypeBase* _instanceType, ClassTypeBase* _varType, int _size, VarAccessType _access) : offsetOrAddrOrConst(_offsetOrAddrOrConst), m_type(_type), instanceType(_instanceType), varType(_varType), m_size(_size), m_access(_access) { #ifdef SQ_SUPPORT_INSTANCE_TYPE_INFO SquirrelObject typeTable = SquirrelVM::GetRootTable().GetValue(SQ_PLUS_TYPE_TABLE); if (typeTable.IsNull()) { typeTable = SquirrelVM::CreateTable(); SquirrelObject root = SquirrelVM::GetRootTable(); root.SetValue(SQ_PLUS_TYPE_TABLE,typeTable); } // if typeTable.SetValue(INT((size_t)varType),varType->GetTypeName()); #endif // SQ_SUPPORT_INSTANCE_TYPE_INFO } }; typedef VarRef * VarRefPtr; // Internal use only. inline void getVarNameTag(SQChar * buff,INT maxSize,const SQChar * scriptName) { // assert(maxSize > 3); #if 1 SQChar * d = buff; d[0] = '_'; d[1] = 'v'; d = &d[2]; maxSize -= (2+1); // +1 = space for null. int pos=0; while (scriptName[pos] && pos < maxSize) { d[pos] = scriptName[pos]; pos++; } // while d[pos] = 0; // null terminate. #else SCSNPRINTF(buff,maxSize,_SC("_v%s"),scriptName); #endif } // getVarNameTag // Internal use only. int setVarFunc(HSQUIRRELVM v); int getVarFunc(HSQUIRRELVM v); int setInstanceVarFunc(HSQUIRRELVM v); int getInstanceVarFunc(HSQUIRRELVM v); // === BEGIN Helpers === inline void createTableSetGetHandlers(SquirrelObject & so) { SquirrelObject delegate = so.GetDelegate(); if (!delegate.Exists(_SC("_set"))) { delegate = SquirrelVM::CreateTable(); SquirrelVM::CreateFunction(delegate,setVarFunc,_SC("_set"),_SC("sn|b|s")); // String var name = number(int or float) or bool or string. SquirrelVM::CreateFunction(delegate,getVarFunc,_SC("_get"),_SC("s")); // String var name. so.SetDelegate(delegate); } // if } // createTableSetGetHandlers inline VarRefPtr createVarRef(SquirrelObject & so,const SQChar * scriptVarName) { VarRefPtr pvr=0; ScriptStringVar256 scriptVarTagName; getVarNameTag(scriptVarTagName,sizeof(scriptVarTagName),scriptVarName); if (!so.GetUserData(scriptVarTagName,(SQUserPointer *)&pvr)) { so.NewUserData(scriptVarTagName,sizeof(*pvr)); if (!so.GetUserData(scriptVarTagName,(SQUserPointer *)&pvr)) throw SquirrelError(_SC("Could not create UserData.")); } // if return pvr; } // createVarRef template void validateConstantType(T constant) { switch(TypeInfo()) { case VAR_TYPE_INT: case VAR_TYPE_FLOAT: case VAR_TYPE_BOOL: case VAR_TYPE_CONST_STRING: break; default: throw SquirrelError(_SC("validateConstantType(): type must be INT, FLOAT, BOOL, or CONST CHAR *.")); } // case } // validateConstantType inline void createInstanceSetGetHandlers(SquirrelObject & so) { if (!so.Exists(_SC("_set"))) { SquirrelVM::CreateFunction(so,setInstanceVarFunc,_SC("_set"),_SC("sn|b|s|x")); // String var name = number(int or float) or bool or string or instance. SquirrelVM::CreateFunction(so,getInstanceVarFunc,_SC("_get"),_SC("s")); // String var name. } // if } // createInstanceSetGetHandlers // === END Helpers === // Provide an overridable way of copying / deleting objects template struct ObjectCloner { static T* Clone(T* src){ return new T(src); } static void Delete(T* dst){ if(dst) delete dst; } }; // specialization for void type //template<> inline void ClassType::copy(void *dst, void *src) {} DECLARE_NONCOPY_TYPE_INTERN(void) // === Bind a global or pre-allocated (not instance) class member variable or constant (for tables only (not classes)) === template void BindVariable(SquirrelObject & so,T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { VarRefPtr pvr = createVarRef(so,scriptVarName); *pvr = VarRef(var,TypeInfo(),NULL,ClassType::type(),sizeof(*var),access); createTableSetGetHandlers(so); } // BindVariable // === Bind a constant by value: INT, FLOAT, BOOL, or CONST CHAR * (for tables only (not classes)) === template void BindConstant(SquirrelObject & so,T constant,const SQChar * scriptVarName) { validateConstantType(constant); VarRefPtr pvr = createVarRef(so,scriptVarName); struct CV { T var; } cv; // Cast Variable helper. cv.var = constant; *pvr = VarRef(*(void **)&cv,TypeInfo(),NULL,ClassType::type(),sizeof(constant),VAR_ACCESS_CONSTANT); createTableSetGetHandlers(so); } // BindConstant template void BindVariable(T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { SquirrelObject so = SquirrelVM::GetRootTable(); BindVariable(so,var,scriptVarName,access); } // BindVariable template void BindConstant(T constant,const SQChar * scriptVarName) { SquirrelObject so = SquirrelVM::GetRootTable(); BindConstant(so,constant,scriptVarName); } // BindConstant // === Register a class instance member variable or constant. var argument provides type and offset ( effectively &((ClassType *)0)->var ) === // classType is the type of the member variable's containing class. template void RegisterInstanceVariable(SquirrelObject & so,ClassTypeBase* classType,T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) { VarRef * pvr = createVarRef(so,scriptVarName); void * offsetOrAddrOrConst = (void *)var; // var must be passed in as &obj->var, where obj = 0 (the address is the offset), or as static/global address. *pvr = VarRef(offsetOrAddrOrConst,TypeInfo(),classType,ClassType::type(),sizeof(*var),access); createInstanceSetGetHandlers(so); } // RegisterInstanceVariable #ifdef SQPLUS_SMARTPOINTER_OPT #define SQPLUS_SMARTPOINTER_REGISTER_VARIABLE #include "SqPlusSmartPointer.h" #endif template void RegisterInstanceConstant(SquirrelObject & so,ClassTypeBase *classType,T constant,const SQChar * scriptVarName) { validateConstantType(constant); VarRef * pvr = createVarRef(so,scriptVarName); struct CV { T var; size_t pad; } cv; // Cast Variable helper. cv.var = constant; *pvr = VarRef(*(void **)&cv,TypeInfo(),classType,ClassType::type(),sizeof(constant),VAR_ACCESS_CONSTANT); createInstanceSetGetHandlers(so); } // RegisterInstanceConstant ////////////////////////////////////////////////////////////////////////// /////////// BEGIN Generalized Class/Struct Instance Support ////////////// ////////////////////////////////////////////////////////////////////////// // Was previously in SqPlus namespace //BOOL CreateNativeClassInstance(HSQUIRRELVM v,const SQChar * classname,SQUserPointer ud,SQRELEASEHOOK hook); // In SquirrelBindingUtils.cpp. // Create native class instance and leave on stack. //BOOL CreateConstructNativeClassInstance(HSQUIRRELVM v,const SQChar * className); // Create new instance, copy 'classToCopy', and store result on stack. template inline BOOL CreateCopyInstance(HSQUIRRELVM v, const SQChar * className,const T & classToCopy) { #ifndef SQPLUS_DISABLE_COPY_INSTANCES if (!CreateConstructNativeClassInstance(v,className)) { return FALSE; } // if SQUserPointer up=0; sq_getinstanceup(v,-1,&up,ClassType::type()); if (!up) return FALSE; T * newClass = (T *)up; *newClass = classToCopy; // Optimized version that uses the copy constructor. return TRUE; #else return FALSE; #endif } // CreateCopyInstance // Create a new copy of type 'className' and copy 'classToCopy', return result via SquirrelObject. template inline SquirrelObject NewClassCopy(HSQUIRRELVM v, const SQChar * className,const T & classToCopy) { if (CreateCopyInstance(v, className,classToCopy)) { HSQOBJECT t; sq_getstackobj(v,-1,&t); SquirrelObject obj(t); sq_poptop(v); return obj; } else { throw SquirrelError(_SC("NewClassCopy(): could not create class")); } // if return SquirrelObject(); } // NewClassCopy // Return a new class copy on the stack from a varArgs function call. template inline int ReturnCopy(HSQUIRRELVM v,const T & classToCopy) { SquirrelObject so(NewClassCopy(v,GetTypeName(classToCopy),classToCopy)); return StackHandler(v).Return(so); } // ReturnCopy // Katsuaki Kawachi's GetInstance<> exception change. 6/27/06 jcs // Get an instance of type T from the stack at idx (for function calls). template T * GetInstance(HSQUIRRELVM v,SQInteger idx) { SQUserPointer up=0; if (SQ_FAILED(sq_getinstanceup(v,idx,&up,ClassType::type()))) { up = 0; } if (ExceptionOnError) { // This code block should be compiled out when ExceptionOnError is false. In any case, the compiler should not generate a test condition (include or exclude the enclosed code block). if (!up) { throw SquirrelError(_SC("GetInstance: Invalid argument type")); } } // if return (T *)up; } // GetInstance template void Push(HSQUIRRELVM v, T* pt); template void Push(HSQUIRRELVM v, T& t); template bool Match(TypeWrapper, HSQUIRRELVM v, int ix); template bool Match(TypeWrapper, HSQUIRRELVM v, int ix); template T &Get(TypeWrapper, HSQUIRRELVM v, int ix); template T *Get(TypeWrapper, HSQUIRRELVM v, int ix); #ifdef SQPLUS_USE_GENERIC_HANDLERS // With template specialization, we get Push handlers per 'precise type match' // This adds a fallback level after that, where we can delegate the work to // wider C-style functions that can do something for a whole class hierarchy. // (GenPush, GenGet, GenMatch). // This macro allows for a a last generic cast operation before giving control // to one of GenPush/GenMatch/GenGet. #ifndef SQPLUS_GEN_CAST #define SQPLUS_GEN_CAST(TYPE,value) ((TYPE*)value) #endif template void Push(HSQUIRRELVM v, T* pt){ GenPush(v,SQPLUS_GEN_CAST(T,pt)); } template void Push(HSQUIRRELVM v, T& t){ GenPush(v,SQPLUS_GEN_CAST(T,&t)); } template bool Match(TypeWrapper, HSQUIRRELVM v, int ix){ if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) return GenMatch(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); else return false; } template bool Match(TypeWrapper, HSQUIRRELVM v, int ix){ if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) return GenMatch(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); else return false; } template T &Get(TypeWrapper, HSQUIRRELVM v, int ix){ if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) return *(T*)GenGet(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); else return *SQPLUS_GEN_CAST(T,0); } template T *Get(TypeWrapper, HSQUIRRELVM v, int ix){ if((ScriptVarType)TypeInfo::TypeID!=VAR_TYPE_NONE) return (T*)GenGet(SQPLUS_GEN_CAST(T*,0),TypeInfo().typeName,v,ix); else return NULL; } #endif // SQPLUS_USE_GENERIC_HANDLERS // === BEGIN Function Call Handler Prototypes === void Push(HSQUIRRELVM v, char value); void Push(HSQUIRRELVM v, unsigned char value); void Push(HSQUIRRELVM v, short value); void Push(HSQUIRRELVM v, unsigned short value); void Push(HSQUIRRELVM v, int value); void Push(HSQUIRRELVM v, unsigned int value); void Push(HSQUIRRELVM v, long value); void Push(HSQUIRRELVM v, unsigned long value); void Push(HSQUIRRELVM v, double value); void Push(HSQUIRRELVM v, float value); void Push(HSQUIRRELVM v, const SQChar *value); void Push(HSQUIRRELVM v, SQChar *value); void Push(HSQUIRRELVM v, const SquirrelNull &); void Push(HSQUIRRELVM v, SQFUNCTION value); void Push(HSQUIRRELVM v, SQAnythingPtr value); // Cast to SQAnythingPtr instead of void * if USE_ARGUMENT_DEPENDANT_OVERLOADS can't be used by your compiler. void Push(HSQUIRRELVM v, SquirrelObject &so); #define USE_ARGUMENT_DEPENDANT_OVERLOADS #ifdef USE_ARGUMENT_DEPENDANT_OVERLOADS #ifdef _MSC_VER #pragma warning(disable:4675) // Disable warning: "resolved overload was found by argument-dependent lookup" when class/struct pointers are used as function arguments. #endif // === BEGIN Argument Dependent Overloads === void Push(HSQUIRRELVM v, bool value); // Pass bool as int if USE_ARGUMENT_DEPENDANT_OVERLOADS can't be used by your compiler. void Push(HSQUIRRELVM v, const void *value); // Pass SQAnythingPtr instead of void * " " void Push(HSQUIRRELVM v, const SQUserPointer &value); // === END Argument Dependent Overloads === #endif #define SQPLUS_CHECK_GET(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(_SC("sq_get*() failed (type error)")) bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); // See Get() for HSQUIRRELVM below (v is always present). bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); // See sq_getstackobj(): always returns true. void Get(TypeWrapper, HSQUIRRELVM v, int); bool Get(TypeWrapper, HSQUIRRELVM v, int idx); char Get(TypeWrapper, HSQUIRRELVM v, int idx); unsigned char Get(TypeWrapper, HSQUIRRELVM v, int idx); short Get(TypeWrapper, HSQUIRRELVM v, int idx); unsigned short Get(TypeWrapper, HSQUIRRELVM v, int idx); int Get(TypeWrapper, HSQUIRRELVM v, int idx); unsigned int Get(TypeWrapper, HSQUIRRELVM v, int idx); long Get(TypeWrapper, HSQUIRRELVM v, int idx); unsigned long Get(TypeWrapper, HSQUIRRELVM v, int idx); float Get(TypeWrapper, HSQUIRRELVM v, int idx); double Get(TypeWrapper, HSQUIRRELVM v, int idx); const SQChar *Get(TypeWrapper, HSQUIRRELVM v, int idx); SquirrelNull Get(TypeWrapper, HSQUIRRELVM v, int idx); void *Get(TypeWrapper, HSQUIRRELVM v, int idx); HSQUIRRELVM Get(TypeWrapper, HSQUIRRELVM v, int /*idx*/); // sq_poptop(v): remove UserData from stack so GetParamCount() matches normal behavior. SquirrelObject Get(TypeWrapper, HSQUIRRELVM v, int idx); #ifdef SQPLUS_AUTOCONVERT_OTHER_CHAR void Push(HSQUIRRELVM v, const SQOtherChar *value); void Push(HSQUIRRELVM v, SQOtherChar *value); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); SQOthCharBuf Get(TypeWrapper, HSQUIRRELVM v, int idx); #endif // SQPLUS_AUTOCONVERT_OTHER_CHAR #ifdef SQPLUS_SUPPORT_STD_STRING void Push(HSQUIRRELVM v, const std::string& value); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); std::string Get(TypeWrapper, HSQUIRRELVM v, int idx); #endif // Added jflanglois suggestion, 8/20/06. jcs #ifdef SQPLUS_SUPPORT_SQ_STD_STRING typedef std::basic_string sq_std_string; void Push(HSQUIRRELVM v,const sq_std_string & value); bool Match(TypeWrapper, HSQUIRRELVM v, int idx); sq_std_string Get(TypeWrapper, HSQUIRRELVM v, int idx); #endif // Specialization to support void return type. void GetRet(TypeWrapper, HSQUIRRELVM v,int idx); // GetRet() restores the stack for SquirrelFunction<>() calls. // Hold on to a reference since return value might be temporary string/instance template inline RT GetRet(TypeWrapper,HSQUIRRELVM v,int idx) { static SquirrelObject st_sq_ret; static typename Temporary::type st_ret; st_ret = Get(TypeWrapper(),v,idx); st_sq_ret.AttachToStackObject(idx); sq_pop(v,2); // restore stack after function call. return st_ret; } #ifndef GCC_INLINE_WORKAROUND # include "SqPlusFunctionCallImpl.h" #endif // GCC_INLINE_WORKAROUND // === END Function Call Handlers === // Helper, only implement function bodies #define IMPLEMENT_ENUM_TYPE(TYPE) namespace SqPlus { \ bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return Match(TypeWrapper(),v,idx); } \ TYPE Get(TypeWrapper,HSQUIRRELVM v,int idx) { return (TYPE)Get(TypeWrapper(),v,idx); } \ void Push(HSQUIRRELVM v,TYPE value) { sq_pushinteger(v,(int)value); } \ } // nameSpace SqPlus // To register simple types (like enums) so they can be used as arguments // (however, this does not handle enums as return values correctly, since // we C++ gets problems with references to temporaries) #define DECLARE_ENUM_TYPE(TYPE) IMPLEMENT_ENUM_TYPE(TYPE) \ namespace SqPlus { \ template<> struct TypeInfo : public TypeInfo { }; \ } // nameSpace SqPlus // As above but use when function bodies should not be generated // (for a header file). #define PROTOS_ENUM_TYPE(TYPE) namespace SqPlus { \ bool Match(TypeWrapper,HSQUIRRELVM v,int idx); \ TYPE Get(TypeWrapper,HSQUIRRELVM v,int idx); \ void Push(HSQUIRRELVM v,TYPE value); \ template<> struct TypeInfo : public TypeInfo { }; \ } // nameSpace SqPlus // NAME and macro changes from Ben's (Project5) forum post. 2/26/06 jcs // Kamaitati's NULL_INSTANCE support. 5/28/06 jcs // ATS: Splitting the macros in different parts to support custom Push implementation (covariant return type) #define DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ inline const SQChar * GetTypeName(const TYPE & n) { return _SC(#NAME); } \ template<> \ struct TypeInfo { \ const SQChar * typeName; \ TypeInfo() : typeName( _SC(#NAME)) {} \ enum {TypeID=VAR_TYPE_INSTANCE,Size=sizeof(TYPE),TypeMask='x', IsInstance=1}; \ operator ScriptVarType() { return ScriptVarType(TypeID); } \ }; #define DECLARE_INSTANCE_TYPEINFO(TYPE) namespace SqPlus { \ DECLARE_INSTANCE_TYPEINFO_(TYPE,TYPE) \ } // namespace SqPlus #define DECLARE_INSTANCE_TYPEINFO_NAME(TYPE,NAME) namespace SqPlus { \ DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ } // namespace SqPlus #ifdef SQPLUS_SUPPORT_NULL_INSTANCES // Macro part shared by 'derived' macros #define DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { \ return (sq_gettype(v,idx)==OT_NULL) || (GetInstance(v,idx) != NULL); } \ template<> inline TYPE & Get(TypeWrapper,HSQUIRRELVM v,int idx) { return *GetInstance(v,idx); } \ template<> inline TYPE * Get(TypeWrapper,HSQUIRRELVM v,int idx) { \ if (sq_gettype(v,idx)==OT_NULL) return NULL; \ return GetInstance(v,idx); } // Ordinary case #define DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) namespace SqPlus { \ DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ template<> inline void Push(HSQUIRRELVM v,TYPE * value) { \ if (!value) sq_pushnull(v); \ else if (!CreateNativeClassInstance(v,GetTypeName(*value),value,0)) \ throw SquirrelError( _SC( "Push(): could not create INSTANCE (check registration name)")); } \ template<> inline void Push(HSQUIRRELVM v,TYPE & value) { if (!CreateCopyInstance(v,GetTypeName(value),value)) throw SquirrelError( _SC( "Push(): could not create INSTANCE copy (check registration name)")); } \ } // nameSpace SqPlus // Allows for providing custom Push handlers (protos here, impl must be provided by app) #define DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,NAME) namespace SqPlus { \ DECLARE_INSTANCE_TYPE_BASE_(TYPE,NAME) \ template<> void Push(HSQUIRRELVM v,TYPE * value); \ template<> void Push(HSQUIRRELVM v,TYPE & value); \ } // nameSpace SqPlus #else #define DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) namespace SqPlus { \ DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ template<> inline void Push(HSQUIRRELVM v,TYPE * value) { if (!CreateNativeClassInstance(v,GetTypeName(*value),value,0)) throw SquirrelError( _SC( "Push(): could not create INSTANCE (check registration name)")); } \ template<> inline void Push(HSQUIRRELVM v,TYPE & value) { if (!CreateCopyInstance(v,GetTypeName(value),value)) throw SquirrelError( _SC( "Push(): could not create INSTANCE copy (check registration name)")); } \ template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ template<> inline bool Match(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx) != NULL; } \ template<> inline TYPE & Get(TypeWrapper,HSQUIRRELVM v,int idx) { return *GetInstance(v,idx); } \ template<> inline TYPE * Get(TypeWrapper,HSQUIRRELVM v,int idx) { return GetInstance(v,idx); } \ } // nameSpace SqPlus #endif // TYPE or NAME below must match the string name used in SQClassDef<>, otherwise name lookup won't match and Squirrel will throw a "can't create instance" error. #ifndef SQPLUS_CONST_OPT #define DECLARE_INSTANCE_TYPE(TYPE) DECLARE_INSTANCE_TYPE_NAME_(TYPE,TYPE) #define DECLARE_INSTANCE_TYPE_NAME(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) #define DECLARE_INSTANCE_TYPE_CUSTOM(TYPE) DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,TYPE) #define DECLARE_INSTANCE_TYPE_NAME_CUSTOM(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_CUSTOM_(TYPE,NAME) #else #define SQPLUS_DECLARE_INSTANCE_TYPE_CONST #include "SqPlusConst.h" #endif #ifdef SQPLUS_OVERLOAD_OPT #define SQPLUS_OVERLOAD_DECLARATION #include "SqPlusOverload.h" #endif // Versions of above for types that aren't copy constructable #define DECLARE_INSTANCE_TYPEINFO_NOCOPY(TYPE) \ DECLARE_INSTANCE_TYPEINFO(TYPE) \ DECLARE_NONCOPY_TYPE(TYPE) #define DECLARE_INSTANCE_TYPEINFO_NOCOPY_NAME(TYPE,NAME) namespace SqPlus { \ DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ DECLARE_NONCOPY_TYPE(TYPE) #define DECLARE_INSTANCE_TYPE_NOCOPY(TYPE) \ DECLARE_INSTANCE_TYPE(TYPE) \ DECLARE_NONCOPY_TYPE(TYPE) #define DECLARE_INSTANCE_TYPE_NOCOPY_NAME(TYPE,NAME) namespace SqPlus { \ DECLARE_INSTANCE_TYPEINFO_(TYPE,NAME) \ DECLARE_NONCOPY_TYPE(TYPE) ////////////////////////////////////////////////////////////////////////// //////////// END Generalized Class/Struct Instance Support /////////////// ////////////////////////////////////////////////////////////////////////// #ifndef SQ_SKIP_ARG_ASSERT #define sq_argassert(arg,_index_) if (!Match(TypeWrapper(),v,_index_)) return sq_throwerror(v,_SC("Incorrect function argument")) #else #define sq_argassert(arg,_index_) #endif // === Return value variants === template struct ReturnSpecialization { // === Standard Function calls === static int Call(RT (*func)(),HSQUIRRELVM v,int /*index*/) { RT ret = func(); Push(v,ret); return 1; } template static int Call(RT (*func)(P1),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); RT ret = func( Get(TypeWrapper(),v,index + 0) ); Push(v,ret); return 1; } template static int Call(RT (*func)(P1,P2),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); RT ret = func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1) ); Push(v,ret); return 1; } template static int Call(RT (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); RT ret = func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2) ); Push(v,ret); return 1; } template static int Call(RT (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); sq_argassert(4,index + 3); RT ret = func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2), Get(TypeWrapper(),v,index + 3) ); Push(v,ret); return 1; } template static int Call(RT (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); sq_argassert(4,index + 3); sq_argassert(5,index + 4); RT ret = func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2), Get(TypeWrapper(),v,index + 3), Get(TypeWrapper(),v,index + 4) ); Push(v,ret); return 1; } template static int Call(RT (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); sq_argassert(4,index + 3); sq_argassert(5,index + 4); sq_argassert(6,index + 5); RT ret = func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2), Get(TypeWrapper(),v,index + 3), Get(TypeWrapper(),v,index + 4), Get(TypeWrapper(),v,index + 5) ); Push(v,ret); return 1; } template static int Call(RT (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); sq_argassert(4,index + 3); sq_argassert(5,index + 4); sq_argassert(6,index + 5); sq_argassert(7,index + 6); RT ret = func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2), Get(TypeWrapper(),v,index + 3), Get(TypeWrapper(),v,index + 4), Get(TypeWrapper(),v,index + 5), Get(TypeWrapper(),v,index + 6) ); Push(v,ret); return 1; } // === Member Function calls === #define SQPLUS_CALL_MFUNC_RET0 #include "SqPlusCallTemplates.h" #ifdef SQPLUS_CONST_OPT #define SQPLUS_CALL_MFUNC_RET0 #include "SqPlusConst.h" #endif }; // === No return value variants === template<> struct ReturnSpecialization { // === Standard function calls === static int Call(void (*func)(),HSQUIRRELVM v,int /*index*/) { (void)v; func(); return 0; } template static int Call(void (*func)(P1),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); func( Get(TypeWrapper(),v,index + 0) ); return 0; } template static int Call(void (*func)(P1,P2),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1) ); return 0; } template static int Call(void (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2) ); return 0; } template static int Call(void (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); sq_argassert(4,index + 3); func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2), Get(TypeWrapper(),v,index + 3) ); return 0; } template static int Call(void (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); sq_argassert(4,index + 3); sq_argassert(5,index + 4); func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2), Get(TypeWrapper(),v,index + 3), Get(TypeWrapper(),v,index + 4) ); return 0; } template static int Call(void (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); sq_argassert(4,index + 3); sq_argassert(5,index + 4); sq_argassert(6,index + 5); func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2), Get(TypeWrapper(),v,index + 3), Get(TypeWrapper(),v,index + 4), Get(TypeWrapper(),v,index + 5) ); return 0; } template static int Call(void (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { sq_argassert(1,index + 0); sq_argassert(2,index + 1); sq_argassert(3,index + 2); sq_argassert(4,index + 3); sq_argassert(5,index + 4); sq_argassert(6,index + 5); sq_argassert(7,index + 6); func( Get(TypeWrapper(),v,index + 0), Get(TypeWrapper(),v,index + 1), Get(TypeWrapper(),v,index + 2), Get(TypeWrapper(),v,index + 3), Get(TypeWrapper(),v,index + 4), Get(TypeWrapper(),v,index + 5), Get(TypeWrapper(),v,index + 6) ); return 0; } // === Member function calls === #define SQPLUS_CALL_MFUNC_NORET #include "SqPlusCallTemplates.h" #ifdef SQPLUS_CONST_OPT #define SQPLUS_CALL_MFUNC_NORET #include "SqPlusConst.h" #endif }; // === STANDARD Function return value specialized call handlers === template int Call(RT (*func)(),HSQUIRRELVM v,int index) { return ReturnSpecialization::Call(func,v,index); } template int Call(RT (*func)(P1),HSQUIRRELVM v,int index) { return ReturnSpecialization::Call(func,v,index); } template int Call(RT (*func)(P1,P2),HSQUIRRELVM v,int index) { return ReturnSpecialization::Call(func,v,index); } template int Call(RT (*func)(P1,P2,P3),HSQUIRRELVM v,int index) { return ReturnSpecialization::Call(func,v,index); } template int Call(RT (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) { return ReturnSpecialization::Call(func,v,index); } template int Call(RT (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) { return ReturnSpecialization::Call(func,v,index); } template int Call(RT (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) { return ReturnSpecialization::Call(func,v,index); } template int Call(RT (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) { return ReturnSpecialization::Call(func,v,index); } // === MEMBER Function return value specialized call handlers === #define SQPLUS_CALL_MFUNC_RET1 #include "SqPlusCallTemplates.h" #ifdef SQPLUS_CONST_OPT #define SQPLUS_CALL_MFUNC_RET1 #include "SqPlusConst.h" #endif // === Direct Call Standard Function handler === template struct DirectCallFunction { static inline int Dispatch(HSQUIRRELVM v) { #ifdef SQPLUS_USE_SANDBOX_VM if( v==SquirrelVM::GetSandboxVMPtr() ){ return sq_throwerror(v, _SC("SqPlus: Cannot exec function from sandbox VM")); } #endif StackHandler sa(v); int paramCount = sa.GetParamCount(); Func * func = (Func *)sa.GetUserData(paramCount); return Call(*func,v,2); } // Dispatch }; // === Direct Call Member Function handler === template class DirectCallMemberFunction { public: static inline int Dispatch(HSQUIRRELVM v) { #ifdef SQPLUS_USE_SANDBOX_VM if( v==SquirrelVM::GetSandboxVMPtr() ){ return sq_throwerror(v, _SC("SqPlus: Cannot exec function from sandbox VM")); } #endif StackHandler sa(v); int paramCount = sa.GetParamCount(); unsigned char * ud = (unsigned char *)sa.GetUserData(paramCount); return Call(**(Callee**)ud,*(Func*)(ud + sizeof(Callee*)),v,2); } // Dispatch }; // === Direct Call Function handlers === #define SQ_CLASS_OBJECT_TABLE_NAME _SC("__ot") #define SQ_CLASS_HIER_ARRAY _SC("__ca") template struct DirectCallInstanceFuncPicker { Callee *instance; Func *func; DirectCallInstanceFuncPicker(HSQUIRRELVM v) { #ifdef SQPLUS_USE_SANDBOX_VM if( v==SquirrelVM::GetSandboxVMPtr() ){ instance = NULL; func = NULL; return; } #endif StackHandler sa(v); instance = static_cast(sa.GetInstanceUp(1, 0)); const int paramCount = sa.GetParamCount(); func = static_cast(sa.GetUserData(paramCount)); #ifdef SQ_USE_CLASS_INHERITANCE SquirrelObject so(sa.GetObjectHandle(1)); // 'this' SQUserPointer typetag; so.GetTypeTag(&typetag); SQUserPointer calleeType = ClassType::type(); if (typetag != calleeType) { SquirrelObject typeTable = so.GetValue(SQ_CLASS_OBJECT_TABLE_NAME); instance = static_cast( // 64-bit compatible version. typeTable.GetUserPointer(INT((size_t)ClassType::type())) ); } #elif defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) SquirrelObject so(sa.GetObjectHandle(1)); // 'this' ClassTypeBase *instType; so.GetTypeTag((SQUserPointer*)&instType); ClassTypeBase *calleeType = ClassType::type(); if (instType!=calleeType && instType->MayHaveOffset() ) { // instance type is nore derived than callee, adjust pointer int offset = instType->GetOffsetTo(calleeType); instance = (Callee*)((char*)instance-offset); } #endif } }; // === Direct Call Instance Member Function handler === template class DirectCallInstanceMemberFunction { public: static inline int Dispatch(HSQUIRRELVM v) { DirectCallInstanceFuncPicker p(v); return p.instance && p.func ? Call(*(p.instance), *(p.func), v, 2) : sq_throwerror(v, _SC("Invalid Instance Type")); } }; // === Direct Call Instance Global Function handler === template class DirectCallInstanceGlobalFunction { public: static inline int Dispatch(HSQUIRRELVM v) { DirectCallInstanceFuncPicker p(v); return p.func ? Call(*(p.func), v, 1) : sq_throwerror(v, _SC("Invalid Instance Type")); } }; // === Direct Call Instance Global Function Var Args handler === template class DirectCallInstanceGlobalFunctionVarArgs { public: static inline int Dispatch(HSQUIRRELVM v) { DirectCallInstanceFuncPicker p(v); return p.func && p.instance ? (*p.func)(p.instance,v) : sq_throwerror(v, _SC("Invalid Instance Type")); } }; // === Direct Call Instance Member Function Variable Argument handler === template class DirectCallInstanceMemberFunctionVarArgs { public: static inline int Dispatch(HSQUIRRELVM v) { DirectCallInstanceFuncPicker p(v); sq_poptop(v); // Remove UserData from stack: so sa.GetParamCount() returns actual param count. return p.func && p.instance ? (p.instance->*(*p.func))(v) : sq_throwerror(v, _SC("Invalid Instance Type")); } }; #ifdef SQPLUS_SMARTPOINTER_OPT #define SQPLUS_SMARTPOINTER_DISPATCH #include "SqPlusSmartPointer.h" #endif // Code fragment useful for debugging new implementations. #if 0 HSQOBJECT ho = sa.GetObjectHandle(paramCount); SquirrelObject so(ho); SQObjectType sot = so.GetType(); #endif #ifdef SQPLUS_ENABLE_AUTO_TYPEMASK #include "SqPlusTypeMask.h" #endif // === Standard function call === template inline void sq_pushdirectclosure(HSQUIRRELVM v,Func func,SQUnsignedInteger nupvalues) { SQUserPointer up = sq_newuserdata(v,sizeof(func)); // Also pushed on stack. memcpy(up,&func,sizeof(func)); sq_newclosure(v,DirectCallFunction::Dispatch,nupvalues+1); #ifdef SQPLUS_ENABLE_AUTO_TYPEMASK sq_setparamscheck(v,0,sqTypeMask::Get()); #endif } // sq_pushdirectclosure // === Fixed Class pointer call (always calls with object pointer that was registered) === template inline void sq_pushdirectclosure(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(Callee*)+sizeof(func)); // Also pushed on stack. const SQUserPointer pCallee = (SQUserPointer)&callee; memcpy(up,&pCallee,sizeof(Callee*)); memcpy(up + sizeof(Callee*),&func,sizeof(func)); sq_newclosure(v,DirectCallMemberFunction::Dispatch,nupvalues+1); #ifdef SQPLUS_ENABLE_AUTO_TYPEMASK sq_setparamscheck(v,0,sqTypeMask::Get()); #endif } // sq_pushdirectclosure #ifdef SQPLUS_SMARTPOINTER_OPT #define SQPLUS_SMARTPOINTER_DIRECT_CLOSURE #include "SqPlusSmartPointer.h" #endif // === Class Instance call: class pointer retrieved from script class instance === template inline void sq_pushdirectinstanceclosure(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. memcpy(up,&func,sizeof(func)); sq_newclosure(v,DirectCallInstanceMemberFunction::Dispatch,nupvalues+1); #ifdef SQPLUS_ENABLE_AUTO_TYPEMASK sq_setparamscheck(v,0,sqTypeMask::Get()); #endif } // sq_pushdirectinstanceclosure // === Global function using this: class pointer retrieved from script class instance === template inline void sq_pushdirectinstanceclosureglobal(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. memcpy(up,&func,sizeof(func)); // Could check that 1st arg of Func is a Callee sq_newclosure(v,DirectCallInstanceGlobalFunction::Dispatch,nupvalues+1); #ifdef SQPLUS_ENABLE_AUTO_TYPEMASK SQChar *tm = (SQChar*)sqTypeMask::Get(); if( tm ) { // Censor out the 1st arg, since SqPlus adds that automatically tm[1] = _SC('x'); //tm[0]; tm++; } sq_setparamscheck(v,0,tm?tm:_SC("")); #endif } // sq_pushdirectinstanceclosureglobal // === Global function using this: class pointer retrieved from script class instance === template inline void sq_pushdirectinstanceclosureglobalvarargs(HSQUIRRELVM v,const Callee & callee,Func func,SQUnsignedInteger nupvalues) { unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. memcpy(up,&func,sizeof(func)); // Could check that 1st arg of Func is a Callee sq_newclosure(v,DirectCallInstanceGlobalFunctionVarArgs::Dispatch,nupvalues+1); #ifdef SQPLUS_ENABLE_AUTO_TYPEMASK sq_setparamscheck(v,-1,_SC("x")); #endif } // sq_pushdirectinstanceclosureglobal // === Class Instance call: class pointer retrieved from script class instance (variable arguments) === template inline void sq_pushdirectinstanceclosurevarargs(HSQUIRRELVM v,const Callee & callee,int (Callee::*func)(HSQUIRRELVM),SQUnsignedInteger nupvalues) { unsigned char * up = (unsigned char *)sq_newuserdata(v,sizeof(func)); // Also pushed on stack. memcpy(up,&func,sizeof(func)); typedef int (Callee::*FuncType)(HSQUIRRELVM); sq_newclosure(v,DirectCallInstanceMemberFunctionVarArgs::Dispatch,nupvalues+1); } // sq_pushdirectinstanceclosurevarargs // === Register a STANDARD function (table or class on stack) === template inline void Register(HSQUIRRELVM v,Func func,const SQChar * name) { sq_pushstring(v,name,-1); sq_pushdirectclosure(v,func,0); sq_createslot(v,-3); // Stack is restored after this call (same state as before Register() call). } // Register // === Register a MEMBER function (table or class on stack) === template inline void Register(HSQUIRRELVM v,Callee & callee,Func func,const SQChar * name) { sq_pushstring(v,name,-1); sq_pushdirectclosure(v,callee,func,0); sq_createslot(v,-3); // Stack is restored after this call (same state as before Register() call). } // Register // === Register a STANDARD global function (root table) === template inline void RegisterGlobal(HSQUIRRELVM v,Func func,const SQChar * name) { sq_pushroottable(v); Register(v,func,name); sq_poptop(v); // Remove root table. } // RegisterGlobal template inline void RegisterGlobal(Func func,const SQChar * name) { RegisterGlobal(SquirrelVM::GetVMPtr(),func,name); } // RegisterGlobal // === Register a MEMBER global function (root table) === template inline void RegisterGlobal(HSQUIRRELVM v,Callee & callee,Func func,const SQChar * name) { sq_pushroottable(v); Register(v,callee,func,name); sq_poptop(v); // Remove root table. } // RegisterGlobal template inline void RegisterGlobal(Callee & callee,Func func,const SQChar * name) { RegisterGlobal(SquirrelVM::GetVMPtr(),callee,func,name); } // RegisterGlobal // === Register a STANDARD function (hso is table or class) === template inline void Register(HSQUIRRELVM v,HSQOBJECT hso,Func func,const SQChar * name) { sq_pushobject(v,hso); Register(v,func,name); sq_poptop(v); // Remove hso. } // Register // === Register a MEMBER function (hso is table or class) === // === Fixed Class pointer call (always calls with object pointer that was registered) === template inline void Register(HSQUIRRELVM v,HSQOBJECT hso,Callee & callee,Func func,const SQChar * name) { sq_pushobject(v,hso); Register(v,callee,func,name); sq_poptop(v); // Remove hso. } // Register // === Register an INSTANCE MEMBER function === // === Class Instance call: class pointer retrieved from script class instance === template inline void RegisterInstance(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { sq_pushobject(v,hclass); sq_pushstring(v,name,-1); sq_pushdirectinstanceclosure(v,callee,func,0); sq_createslot(v,-3); sq_poptop(v); // Remove hclass. } // RegisterInstance // === Register an INSTANCE GLOBAL MEMBER function === // === Class Instance call: class pointer retrieved from script class instance === // Allows embedding global func that takes Callee as 1st arg as a member func template inline void RegisterInstanceGlobalFunc(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { sq_pushobject(v,hclass); sq_pushstring(v,name,-1); sq_pushdirectinstanceclosureglobal(v,callee,func,0); sq_createslot(v,-3); sq_poptop(v); // Remove hclass. } // RegisterInstanceGlobaFunc // === Register an INSTANCE GLOBAL MEMBER WITH VAR ARGS function === // === Class Instance call: class pointer retrieved from script class instance === // Allows embedding global func that takes Callee as 1st arg as a member func template inline void RegisterInstanceGlobalFuncVarArgs(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,Func func,const SQChar * name) { sq_pushobject(v,hclass); sq_pushstring(v,name,-1); sq_pushdirectinstanceclosureglobalvarargs(v,callee,func,0); sq_createslot(v,-3); sq_poptop(v); // Remove hclass. } // RegisterInstanceGlobaFunc #ifdef SQPLUS_SMARTPOINTER_OPT #define SQPLUS_SMARTPOINTER_REGISTER_INSTANCE #include "SqPlusSmartPointer.h" #endif #ifdef _MSC_VER #pragma warning(disable : 4995) // Deprecated _snprintf #endif // === Register an INSTANCE MEMBER function Variable Arguments === // typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). // All the other Squirrel type-masks are passed normally. template inline void RegisterInstanceVarArgs(HSQUIRRELVM v,HSQOBJECT hclass,Callee & callee,int (Callee::*func)(HSQUIRRELVM),const SQChar * name,const SQChar * typeMask=_SC("*")) { sq_pushobject(v,hclass); sq_pushstring(v,name,-1); sq_pushdirectinstanceclosurevarargs(v,callee,func,0); SQChar tm[64]; SQChar * ptm = tm; int numParams = SQ_MATCHTYPEMASKSTRING; if (typeMask) { if (typeMask[0] == '*') { ptm = 0; // Variable args: don't check parameters. // numParams = 0; // Clear SQ_MATCHTYPEMASKSTRING (does not mean match 0 params. See sq_setparamscheck()). } else { if (SCSNPRINTF(tm,sizeof(tm),_SC("x%s"),typeMask) < 0) { // Must be an instance. throw SquirrelError(_SC("RegisterInstanceVarArgs: typeMask string too long.")); } // if } // if } else { // Need to check object type on stack: table, class, instance, etc. // _snprintf(tm,sizeof(tm),"x"); // instance. tm[0] = 'x'; tm[1] = 0; } // if if (ptm) { // If ptm == 0, don't check type. sq_setparamscheck(v,numParams,ptm); // Determine arg count from type string. } // if #ifdef _DEBUG sq_setnativeclosurename(v,-1,name); // For debugging only. #endif sq_createslot(v,-3); sq_poptop(v); // Remove hclass. } // RegisterInstanceVarArgs #ifdef _MSC_VER #pragma warning(default : 4995) #endif // === Call Squirrel Functions from C/C++ === // No type checking is performed for Squirrel functions as Squirrel types are dynamic: // Incoming types are passed unchanged to Squirrel functions. The parameter count is checked: an exception is thrown if mismatched. // Return values must match the RT template argument type, else an exception can be thrown on return. template struct SquirrelFunction { HSQUIRRELVM v; SquirrelObject object; // Table or class. SquirrelObject func; SquirrelFunction() : v(0) {} SquirrelFunction(HSQUIRRELVM _v,const SquirrelObject & _object,const SquirrelObject & _func) : v(_v), object(_object), func(_func) {} SquirrelFunction(const SquirrelObject & _object,const SquirrelObject & _func) : v(SquirrelVM::GetVMPtr()), object(_object), func(_func) {} SquirrelFunction(const SquirrelObject & _object,const SQChar * name) { v = SquirrelVM::GetVMPtr(); object = _object; func = object.GetValue(name); } SquirrelFunction(const SQChar * name) { v = SquirrelVM::GetVMPtr(); object = SquirrelVM::GetRootTable(); func = object.GetValue(name); } // Release references and reset internal objects to null. void reset(void) { func.Reset(); object.Reset(); } // Reset #define SQPLUS_CHECK_FNCALL(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(_SC("SquirrelFunction<> call failed")) RT operator()(void) { sq_pushobject(v,func.GetObjectHandle()); sq_pushobject(v,object.GetObjectHandle()); SQPLUS_CHECK_FNCALL(sq_call(v,1,SQTrue,SQ_CALL_RAISE_ERROR)); return GetRet(TypeWrapper(),v,-1); } template RT operator()(P1 p1) { sq_pushobject(v,func.GetObjectHandle()); sq_pushobject(v,object.GetObjectHandle()); Push(v,p1); SQPLUS_CHECK_FNCALL(sq_call(v,2,SQTrue,SQ_CALL_RAISE_ERROR)); return GetRet(TypeWrapper(),v,-1); } template RT operator()(P1 p1,P2 p2) { sq_pushobject(v,func.GetObjectHandle()); sq_pushobject(v,object.GetObjectHandle()); Push(v,p1); Push(v,p2); SQPLUS_CHECK_FNCALL(sq_call(v,3,SQTrue,SQ_CALL_RAISE_ERROR)); return GetRet(TypeWrapper(),v,-1); } template RT operator()(P1 p1,P2 p2,P3 p3) { sq_pushobject(v,func.GetObjectHandle()); sq_pushobject(v,object.GetObjectHandle()); Push(v,p1); Push(v,p2); Push(v,p3); SQPLUS_CHECK_FNCALL(sq_call(v,4,SQTrue,SQ_CALL_RAISE_ERROR)); return GetRet(TypeWrapper(),v,-1); } template RT operator()(P1 p1,P2 p2,P3 p3,P4 p4) { sq_pushobject(v,func.GetObjectHandle()); sq_pushobject(v,object.GetObjectHandle()); Push(v,p1); Push(v,p2); Push(v,p3); Push(v,p4); SQPLUS_CHECK_FNCALL(sq_call(v,5,SQTrue,SQ_CALL_RAISE_ERROR)); return GetRet(TypeWrapper(),v,-1); } template RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) { sq_pushobject(v,func.GetObjectHandle()); sq_pushobject(v,object.GetObjectHandle()); Push(v,p1); Push(v,p2); Push(v,p3); Push(v,p4); Push(v,p5); SQPLUS_CHECK_FNCALL(sq_call(v,6,SQTrue,SQ_CALL_RAISE_ERROR)); return GetRet(TypeWrapper(),v,-1); } template RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6) { sq_pushobject(v,func.GetObjectHandle()); sq_pushobject(v,object.GetObjectHandle()); Push(v,p1); Push(v,p2); Push(v,p3); Push(v,p4); Push(v,p5); Push(v,p6); SQPLUS_CHECK_FNCALL(sq_call(v,7,SQTrue,SQ_CALL_RAISE_ERROR)); return GetRet(TypeWrapper(),v,-1); } template RT operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7) { sq_pushobject(v,func.GetObjectHandle()); sq_pushobject(v,object.GetObjectHandle()); Push(v,p1); Push(v,p2); Push(v,p3); Push(v,p4); Push(v,p5); Push(v,p6); Push(v,p7); SQPLUS_CHECK_FNCALL(sq_call(v,8,SQTrue,SQ_CALL_RAISE_ERROR)); return GetRet(TypeWrapper(),v,-1); } }; // === Class/Struct registration === #define SQ_DELETE_CLASS(CLASSTYPE) if (up) { CLASSTYPE * self = (CLASSTYPE *)up; delete self;} return 0 #define SQ_DECLARE_RELEASE(CLASSTYPE) \ static int release(SQUserPointer up,SQInteger size) { \ SQ_DELETE_CLASS(CLASSTYPE); \ } template struct ReleaseClassPtrPtr { static int release(SQUserPointer up,SQInteger size) { if (up) { T ** self = (T **)up; delete *self; } // if return 0; } // release }; template struct ReleaseClassPtr { static int release(SQUserPointer up,SQInteger size) { if (up) { T * self = (T *)up; delete self; } // if return 0; } // release }; BOOL CreateClass(HSQUIRRELVM v,SquirrelObject & newClass,SQUserPointer classType,const SQChar * name,const SQChar * baseName=0); template inline void PopulateAncestry(HSQUIRRELVM v, SquirrelObject &instance, T *newClass) { // 11/2/05: Create a new table for this instance. SquirrelObject newObjectTable = SquirrelVM::CreateTable(); // 64-bit compatible version. newObjectTable.SetUserPointer(INT((size_t)ClassType::type()), newClass); instance.SetValue(SQ_CLASS_OBJECT_TABLE_NAME, newObjectTable); SquirrelObject classHierArray = instance.GetValue(SQ_CLASS_HIER_ARRAY); INT count = classHierArray.Len(); // This will be true when more than one C/C++ class is in the hierarchy. if (count > 1) { --count; // Skip the most-derived class. for (INT i = 0; i < count; i++) { // Kamaitati's changes for C++ inheritance support. jcs 5/28/06 SquirrelObject so = classHierArray.GetValue(i); sq_pushobject(v,so.GetObjectHandle()); SQUserPointer typeTag; sq_gettypetag(v,-1,&typeTag); newObjectTable.SetUserPointer(INT(size_t(typeTag)),newClass); sq_poptop(v); } } } // Call PostConstruct() at the end of custom constructors. template inline int PostConstruct(HSQUIRRELVM v, T *newClass, SQRELEASEHOOK hook) { #ifdef SQ_USE_CLASS_INHERITANCE StackHandler sa(v); HSQOBJECT ho = sa.GetObjectHandle(1); // OT_INSTANCE SquirrelObject instance(ho); PopulateAncestry(v, instance, newClass); #endif // SQ_USE_CLASS_INHERITANCE sq_setinstanceup(v, 1, newClass); sq_setreleasehook(v, 1, hook); return TRUE; } // PostConstruct inline int PostConstructSimple(HSQUIRRELVM v, void *newClass, SQRELEASEHOOK hook){ sq_setinstanceup(v, 1, newClass); sq_setreleasehook(v, 1, hook); return TRUE; } // PostConstructSimple template struct ConstructReleaseClass { static int construct(HSQUIRRELVM v) { return PostConstruct(v,new T(),release); } // construct SQ_DECLARE_RELEASE(T) }; # ifdef SQPLUS_ENABLE_TYPEOF template int sq_typeof(HSQUIRRELVM v) { sq_pushstring(v,TypeInfo().typeName,-1); return 1; } # endif // === Helper for RegisterClassType*() === inline void setupClassHierarchy(SquirrelObject newClass) { // New member vars cannot be added to instances (OT_INSTANCE): additions must occur on the defining class (OT_CLASS), before any instances are instantiated. if (!newClass.Exists(SQ_CLASS_OBJECT_TABLE_NAME)) { // Will always get table from most-derived registered class. SquirrelObject objectTable = SquirrelVM::CreateTable(); newClass.SetValue(SQ_CLASS_OBJECT_TABLE_NAME,objectTable); // Constructors must add their 'this' pointer indexed by type to this table. See PostConstruct() above. // 11/2/05: This table will behave as a static global for each instance unless overwritten during construction (see PostConstruct() above). } // if SquirrelObject classHierArray; if (!newClass.Exists(SQ_CLASS_HIER_ARRAY)) { // Will always get table from most-derived registered class. classHierArray = SquirrelVM::CreateArray(0); // The only constructor called will be the most-derived class: this array contains all classes in the hierarchy to be constructed. newClass.SetValue(SQ_CLASS_HIER_ARRAY,classHierArray); } else { classHierArray = newClass.GetValue(SQ_CLASS_HIER_ARRAY); } // if classHierArray.ArrayAppend(newClass); // Add the class to the hierarchy array. The array values will be released and replaced with UserData to free created ancestor classes. } // setupClassHierarchy template inline SquirrelObject RegisterClassType(HSQUIRRELVM v,const SQChar * scriptClassName,const SQChar * baseScriptClassName=0) { int top = sq_gettop(v); SquirrelObject newClass; if (CreateClass(v,newClass,(SQUserPointer)ClassType::type(),scriptClassName,baseScriptClassName)) { SquirrelVM::CreateFunction(newClass,&ConstructReleaseClass::construct,_SC("constructor")); # ifdef SQ_USE_CLASS_INHERITANCE setupClassHierarchy(newClass); # endif # ifdef SQPLUS_ENABLE_TYPEOF SquirrelVM::CreateFunction(newClass,&sq_typeof,_SC("_typeof")); # endif } // if sq_settop(v,top); return newClass; } // RegisterClassType template inline SquirrelObject RegisterClassTypeNoConstructor(HSQUIRRELVM v,const SQChar * scriptClassName,const SQChar * baseScriptClassName=0) { int top = sq_gettop(v); SquirrelObject newClass; if (CreateClass(v,newClass,(SQUserPointer)ClassType::type(),scriptClassName,baseScriptClassName)) { # ifdef SQ_USE_CLASS_INHERITANCE setupClassHierarchy(newClass); # endif # ifdef SQPLUS_ENABLE_TYPEOF SquirrelVM::CreateFunction(newClass,&sq_typeof,_SC("_typeof")); # endif } // if sq_settop(v,top); return newClass; } // RegisterClassTypeNoConstructor // === Define and register a C++ class and its members for use with Squirrel === // Constructors+destructors are automatically created. Custom constructors must use the // standard SQFUNCTION signature if variable argument types are required (overloads). // See testSqPlus2.cpp for examples. // Do not use SQClassDefBase<> directly, use SQClassDef<> or SQClassDefNoConstructor<>, below. template struct SQClassDefBase { HSQUIRRELVM v; const SQChar * name; SquirrelObject newClass; #if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) const SQChar * base; // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). SQClassDefBase(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : v(_v), name(_name), base(_base) {InitBase();} // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). SQClassDefBase(const SQChar * _name=0,const SQChar * _base=0) : v(SquirrelVM::GetVMPtr()), name(_name), base(_base) {InitBase(TypeWrapper());} template void InitBase(TypeWrapper){ /*assert(base);*/ ClassType::Get()->SetBase(TypeWrapper()); CheckInitDefaultNames(); } void InitBase(TypeWrapper){ /*assert(!base);*/ CheckInitDefaultNames(); } void CheckInitDefaultNames(){ if( !name ) name=TypeInfo().typeName; if( !base ) base=TypeInfo().typeName; } #else SQClassDefBase(HSQUIRRELVM _v,const SQChar * _name=0) : v(_v), name(_name) { CheckInitDefaultName(); } SQClassDefBase(const SQChar * _name=0) : v(SquirrelVM::GetVMPtr()), name(_name) { CheckInitDefaultName(); } void CheckInitDefaultName(){ if( !name ) name=TypeInfo().typeName; } #endif // Register a member function. template SQClassDefBase & func(Func pfunc,const SQChar * name) { RegisterInstance(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); return *this; } // func // Register a global function as a member function (the global takes a Callee*/& as first arg). template SQClassDefBase & globMembFunc(Func pfunc,const SQChar * name) { RegisterInstanceGlobalFunc(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); return *this; } // globMemberFunc // Register a global function as a member function (the global takes a Callee*/& as first arg and SQVM* as 2nd). template SQClassDefBase & globMembFuncVarArgs(Func pfunc,const SQChar * name) { RegisterInstanceGlobalFuncVarArgs(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name); return *this; } // globMemberFuncVarArgs #ifdef SQPLUS_SMARTPOINTER_OPT #define SQPLUS_SMARTPOINTER_CLASS_DEF_FUNC #include "SqPlusSmartPointer.h" #endif // Register a variable-argument member function (supports variable+multiple return values). // typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). // All the other Squirrel type-masks are passed normally. template SQClassDefBase & funcVarArgs(Func pfunc,const SQChar * name,const SQChar * typeMask=_SC("*")) { RegisterInstanceVarArgs(v,newClass.GetObjectHandle(),*(TClassType *)0,pfunc,name,typeMask); return *this; } // funcVarArgs // === BEGIN static-member+global function registration === // === This version is for static member functions only, such as custom constructors where 'this' is not yet valid === // typeMask: "*" means don't check parameters, typeMask=0 means function takes no arguments (and is type checked for that case). // All the other Squirrel type-masks are passed normally. template SQClassDefBase & staticFuncVarArgs(Func pfunc,const SQChar * name,const SQChar * typeMask=_SC("*")) { SquirrelVM::PushObject(newClass); SquirrelVM::CreateFunction(pfunc,name,typeMask); SquirrelVM::Pop(1); return *this; } // staticFuncVarArgs // Register a standard global function (effectively embedding a global function in TClassType's script namespace: does not need or use a 'this' pointer). template SQClassDefBase & staticFunc(Func pfunc,const SQChar * name) { Register(v,newClass.GetObjectHandle(),pfunc,name); return *this; } // staticFunc // Register a function to a pre-allocated class/struct member function: will use callee's 'this' (effectively embedding a global function in TClassType's script namespace). template SQClassDefBase & staticFunc(Callee & callee,Func pfunc,const SQChar * name) { Register(v,newClass.GetObjectHandle(),callee,pfunc,name); return *this; } // staticFunc // === END static+global function registration === // Register a member variable. template SQClassDefBase & var(VarType TClassType::* pvar,const SQChar * name,VarAccessType access=VAR_ACCESS_READ_WRITE) { struct CV { VarType TClassType::* var; } cv; // Cast Variable helper. cv.var = pvar; RegisterInstanceVariable(newClass,ClassType::type(),*(VarType **)&cv,name,access); return *this; } // var // Register a member variable as a UserPointer (read only). template SQClassDefBase & varAsUserPointer(VarType TClassType::* pvar,const SQChar * name) { struct CV { VarType TClassType::* var; } cv; // Cast Variable helper. cv.var = pvar; RegisterInstanceVariable(newClass,ClassType::type(),*(SQAnything **)&cv,name,VAR_ACCESS_READ_ONLY); return *this; } // varAsUserPointer #ifdef SQPLUS_SMARTPOINTER_OPT #define SQPLUS_SMARTPOINTER_CLASS_DEF_VAR #include "SqPlusSmartPointer.h" #endif template SQClassDefBase & staticVar(VarType * pvar,const SQChar * name,VarAccessType access=VAR_ACCESS_READ_WRITE) { struct CV { VarType * var; } cv; // Cast Variable helper. cv.var = pvar; RegisterInstanceVariable(newClass,ClassType::type(),*(VarType **)&cv,name,VarAccessType(access|VAR_ACCESS_STATIC)); return *this; } // staticVar #ifdef SQPLUS_CONST_OPT #define SQ_REG_CONST_STATIC_VAR #include "SqPlusConst.h" #endif // Member / static member script vars (ordinary Squirrel vars) SQClassDefBase & scriptVar( const SQChar* name, int ival, SQBool static_var=SQFalse ) { HSQUIRRELVM v = SquirrelVM::GetVMPtr(); sq_pushobject(v,newClass.GetObjectHandle()); sq_pushstring(v,name,-1); sq_pushinteger(v,ival); sq_newslot(v,-3,static_var); sq_pop(v,1); return *this; } SQClassDefBase & scriptVar( const SQChar* name, double fval, SQBool static_var=SQFalse ) { HSQUIRRELVM v = SquirrelVM::GetVMPtr(); sq_pushobject(v,newClass.GetObjectHandle()); sq_pushstring(v,name,-1); sq_pushfloat(v,fval); sq_newslot(v,-3,static_var); sq_pop(v,1); return *this; } SQClassDefBase & scriptVar( const SQChar* name, const SQChar* sval, SQBool static_var=SQFalse ) { HSQUIRRELVM v = SquirrelVM::GetVMPtr(); sq_pushobject(v,newClass.GetObjectHandle()); sq_pushstring(v,name,-1); sq_pushstring(v,sval,-1); sq_newslot(v,-3,static_var); sq_pop(v,1); return *this; } // Register a constant (read-only in script, passed by value (only INT, FLOAT, or BOOL types)). template SQClassDefBase & constant(ConstantType constant,const SQChar * name) { RegisterInstanceConstant(newClass,ClassType::type(),constant,name); return *this; } // constant // Register an enum as an integer (read-only in script). SQClassDefBase & enumInt(int constant,const SQChar * name) { RegisterInstanceConstant(newClass,ClassType::type(),constant,name); return *this; } // enumInt #ifdef SQPLUS_OVERLOAD_OPT #define SQPLUS_OVERLOAD_IMPLEMENTATION #include "SqPlusOverload.h" #endif }; #ifdef SQPLUS_OVERLOAD_OPT #define SQPLUS_OVERLOAD_FUNCTIONS #include "SqPlusOverload.h" #endif template struct SQClassDef : public SQClassDefBase { #if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). SQClassDef(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_v,_name,_base) { SQClassDefBase::newClass = RegisterClassType( SQClassDefBase::v, SQClassDefBase::name, SQClassDefBase::base ); } // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). SQClassDef(const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_name,_base) { SQClassDefBase::newClass = RegisterClassType< TClassType>( SQClassDefBase::v, SQClassDefBase::name, SQClassDefBase::base ); } #else SQClassDef(HSQUIRRELVM _v,const SQChar * _name=0) : SQClassDefBase(_v,_name) { SQClassDefBase::newClass = RegisterClassType(SQClassDefBase::v, SQClassDefBase::name ); } SQClassDef(const SQChar * _name=0) : SQClassDefBase(_name) { SQClassDefBase::newClass = RegisterClassType(SQClassDefBase::v, SQClassDefBase::name ); } #endif }; template struct SQClassDefNoConstructor : public SQClassDefBase { #if defined(SQ_USE_CLASS_INHERITANCE) || defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). SQClassDefNoConstructor(HSQUIRRELVM _v,const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_v,_name,_base) { SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name,SQClassDefBase::base); } // Optional base arg is the name of a base class to inherit from (must already be defined in the Squirrel VM). SQClassDefNoConstructor(const SQChar * _name=0,const SQChar * _base=0) : SQClassDefBase(_name,_base) { SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name,SQClassDefBase::base); } #else SQClassDefNoConstructor(HSQUIRRELVM _v,const SQChar * _name=0) : SQClassDefBase(_v,_name) { SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name); } SQClassDefNoConstructor(const SQChar * _name=0) : SQClassDefBase(_name) { SQClassDefBase::newClass = RegisterClassTypeNoConstructor(SQClassDefBase::v,SQClassDefBase::name); } #endif }; // === Macros for old style registration. SQClassDef registration is now easier to use (SQ_DECLARE_CLASS() is not needed) === #define SQ_DECLARE_CLASS(CLASSNAME) \ static int _##CLASSNAME##_release(SQUserPointer up,SQInteger size) { \ if (up) { \ CLASSNAME * self = (CLASSNAME *)up; \ delete self; \ } \ return 0; \ } \ static int _##CLASSNAME##_constructor(HSQUIRRELVM v) { \ CLASSNAME * pc = new CLASSNAME(); \ sq_setinstanceup(v,1,pc); \ sq_setreleasehook(v,1,_##CLASSNAME##_release); \ return 1; \ } #define SQ_REGISTER_CLASS(CLASSNAME) \ RegisterClassType(SquirrelVM::GetVMPtr(),_SC(#CLASSNAME),_##CLASSNAME##_constructor) #define SQ_REGISTER_INSTANCE(NEWSQCLASS,CCLASS,FUNCNAME) \ RegisterInstance(SquirrelVM::GetVMPtr(),NEWSQCLASS.GetObjectHandle(),*(CCLASS *)0,&CCLASS::FUNCNAME,_SC(#FUNCNAME)); #define SQ_REGISTER_INSTANCE_VARARGS(NEWSQCLASS,CCLASS,FUNCNAME) \ RegisterInstanceVarArgs(SquirrelVM::GetVMPtr(),NEWSQCLASS.GetObjectHandle(),*(CCLASS *)0,&CCLASS::FUNCNAME,_SC(#FUNCNAME)); #define SQ_REGISTER_INSTANCE_VARIABLE(NEWSQCLASS,CCLASS,VARNAME) \ RegisterInstanceVariable(NEWSQCLASS,&((CCLASS *)0)->VARNAME,_SC(#VARNAME)); #if defined(USE_ARGUMENT_DEPENDANT_OVERLOADS) && defined(_MSC_VER) #pragma warning (default:4675) #endif }; // namespace SqPlus // === BEGIN code suggestion from the Wiki === // Get any bound type from this SquirrelObject. Note that Squirrel's // handling of references and pointers still holds here. template inline _ty SquirrelObject::Get(void) { sq_pushobject(SquirrelVM::_VM,GetObjectHandle()); _ty val = SqPlus::Get(SqPlus::TypeWrapper<_ty>(),SquirrelVM::_VM,-1); sq_poptop(SquirrelVM::_VM); return val; } // Set any bound type to this SquirrelObject. Note that Squirrel's // handling of references and pointers still holds here. template inline SquirrelObject SquirrelObject::SetByValue(_ty val) { // classes/structs should be passed by ref (below) to avoid an extra copy. SqPlus::Push(SquirrelVM::_VM,val); AttachToStackObject(-1); sq_poptop(SquirrelVM::_VM); return *this; } // Set any bound type to this SquirrelObject. Note that Squirrel's // handling of references and pointers still holds here. template inline SquirrelObject &SquirrelObject::Set(_ty & val) { SqPlus::Push(SquirrelVM::_VM,val); AttachToStackObject(-1); sq_poptop(SquirrelVM::_VM); return *this; } // === END code suggestion from the Wiki === #endif //_SQ_PLUS_H_