// 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 <stdlib.h>
#include <assert.h>
#ifdef __APPLE__
#include <malloc/malloc.h>
#else
#include <malloc.h>
#endif
#include <memory.h>
#include <memory>
#include <limits.h> // 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 <tchar.h>
#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 <stdio.h> // for snprintf
#else
#define SCSNPRINTF snprintf
#include <stdio.h> // 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<class T> 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<class T>
struct Temporary {
typedef T type;
};
// References are tricky, but they should just be filtered out usually
template<class T>
struct SqAssignableRef {
SqAssignableRef( ) : m_pt(0) { }
void operator = (T& tr){ m_pt=&tr; }
operator T& () { return *m_pt; }
T *m_pt;
};
template<class T>
struct Temporary<T&> {
typedef SqAssignableRef<T> 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<int MAXLENGTH> // 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 <typename T>
struct TypeInfo {
const SQChar * typeName;
enum {TypeID=VAR_TYPE_NONE, Size=0, TypeMask='?', IsInstance=0};
};
// === Common Variable Types ===
template<>
struct TypeInfo<INT> {
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<unsigned> {
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<FLOAT> {
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<bool> {
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<short> {
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<char> {
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<SQUserPointer> {
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<SQAnything> {
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<SQNoBaseClass> {
const SQChar * typeName;
TypeInfo() : typeName(0) {}
enum {TypeID=-1,Size=0,TypeMask=' ', IsInstance=0};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template<>
struct TypeInfo<const SQChar *> {
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 SQOtherChar *> {
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<SQOtherChar*> {
typedef SQOthCharBuf type;
};
template<>
struct Temporary<const SQOtherChar*> {
typedef SQOthCharBuf type;
};
#endif // SQPLUS_AUTOCONVERT_OTHER_CHAR
// base case: raw pointer
template<typename T, int is_inst>
struct TypeInfoPtrBase {
const SQChar * typeName;
TypeInfoPtrBase() : typeName(TypeInfo<T>().typeName) {}
enum {TypeID=VAR_TYPE_USER_POINTER,Size=sizeof(T*),TypeMask='u'};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template<typename T>
struct TypeInfoPtrBase<T,1> : public TypeInfo<T> { };
// Partial specialization for pointers (to access type without pointer / or instance typeinfo)
template<class T>
struct TypeInfo<T*> : public TypeInfoPtrBase<T,TypeInfo<T>::IsInstance> { };
// Same thing for references
template<class T>
struct TypeInfo<T&> : public TypeInfoPtrBase<T,TypeInfo<T>::IsInstance> { };
#ifdef SQPLUS_SUPPORT_STD_STRING
template<>
struct TypeInfo<std::string> {
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<ScriptStringVarBase> {
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<int N>
struct TypeInfo<ScriptStringVar<N> > {
SQChar typeName[24];
TypeInfo() { scsprintf(typeName,_SC("ScriptStringVar<%d>"),N); }
enum {TypeID=VAR_TYPE_STRING,Size=N*sizeof(ScriptStringVar<N>),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<typename T,bool copyable>
struct ClassTypeCopyImpl;
// Helper struct to decide if type is copyable or not
template<typename T>
struct IsCopyable { enum { value=true }; };
#define DECLARE_NONCOPY_TYPE_INTERN(TYPE) \
template<> struct IsCopyable<TYPE> { 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<TYPE> { enum { value=false }; }; \
}
// Base class to do copying in ordinary C++ way
template<typename T>
struct ClassTypeCopyImpl<T,true> : 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<typename T>
struct ClassTypeCopyImpl<T,false> : 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<void,true> : public ClassTypeBase {
static void copy(void * dst,void * src) { } // copy
};
template<>
struct ClassTypeCopyImpl<void,false> : public ClassTypeBase {
static void copy(void * dst,void * src) { } // copy
};
template<typename T>
struct ClassType : public ClassTypeCopyImpl<T,IsCopyable<T>::value> {
typedef ClassTypeCopyImpl<T,IsCopyable<T>::value> ClassTypeBase;
ClassType( ) { this->m_name=stGetName(); }
virtual CopyVarFunc vgetCopyFunc(void) { return (CopyVarFunc)&ClassTypeBase::copy; }
virtual const SQChar* GetTypeName(){ return this->m_name; }
template<class BC>
void SetBase(TypeWrapper<BC>) {
this->m_pbase = ClassType<BC>::Get();
T* pt = reinterpret_cast<T*>(this);
this->m_offset = ((char*)pt)-((char*)static_cast<BC*>(pt));
}
static ClassType* Get(){ static ClassType<T> st_ct; return &st_ct; }
static ClassTypeBase* type() { return Get(); }
static CopyVarFunc getCopyFunc(void) { return (CopyVarFunc)&ClassTypeBase::copy; }
static const SQChar* stGetName(){ return TypeInfo<T>().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<typename T>
void validateConstantType(T constant) {
switch(TypeInfo<T>()) {
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<typename T>
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<void>::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<typename T>
void BindVariable(SquirrelObject & so,T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) {
VarRefPtr pvr = createVarRef(so,scriptVarName);
*pvr = VarRef(var,TypeInfo<T>(),NULL,ClassType<T>::type(),sizeof(*var),access);
createTableSetGetHandlers(so);
} // BindVariable
// === Bind a constant by value: INT, FLOAT, BOOL, or CONST CHAR * (for tables only (not classes)) ===
template<typename T>
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<T>(),NULL,ClassType<T>::type(),sizeof(constant),VAR_ACCESS_CONSTANT);
createTableSetGetHandlers(so);
} // BindConstant
template<typename T>
void BindVariable(T * var,const SQChar * scriptVarName,VarAccessType access=VAR_ACCESS_READ_WRITE) {
SquirrelObject so = SquirrelVM::GetRootTable();
BindVariable(so,var,scriptVarName,access);
} // BindVariable
template<typename T>
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<typename T>
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<T>(),classType,ClassType<T>::type(),sizeof(*var),access);
createInstanceSetGetHandlers(so);
} // RegisterInstanceVariable
#ifdef SQPLUS_SMARTPOINTER_OPT
#define SQPLUS_SMARTPOINTER_REGISTER_VARIABLE
#include "SqPlusSmartPointer.h"
#endif
template<typename T>
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<T>(),classType,ClassType<T>::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<typename T>
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<T>::type());
if (!up) return FALSE;
T * newClass = (T *)up;
*newClass = classToCopy; // <TODO> 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<typename T>
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<typename T>
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<typename T,bool ExceptionOnError>
T * GetInstance(HSQUIRRELVM v,SQInteger idx) {
SQUserPointer up=0;
if (SQ_FAILED(sq_getinstanceup(v,idx,&up,ClassType<T>::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<typename T> void Push(HSQUIRRELVM v, T* pt);
template<typename T> void Push(HSQUIRRELVM v, T& t);
template<typename T> bool Match(TypeWrapper<T&>, HSQUIRRELVM v, int ix);
template<typename T> bool Match(TypeWrapper<T*>, HSQUIRRELVM v, int ix);
template<typename T> T &Get(TypeWrapper<T&>, HSQUIRRELVM v, int ix);
template<typename T> T *Get(TypeWrapper<T*>, 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<typename T> void Push(HSQUIRRELVM v, T* pt){ GenPush(v,SQPLUS_GEN_CAST(T,pt)); }
template<typename T> void Push(HSQUIRRELVM v, T& t){ GenPush(v,SQPLUS_GEN_CAST(T,&t)); }
template<typename T> bool Match(TypeWrapper<T&>, HSQUIRRELVM v, int ix){
if((ScriptVarType)TypeInfo<T>::TypeID!=VAR_TYPE_NONE)
return GenMatch(SQPLUS_GEN_CAST(T*,0),TypeInfo<T>().typeName,v,ix);
else return false;
}
template<typename T> bool Match(TypeWrapper<T*>, HSQUIRRELVM v, int ix){
if((ScriptVarType)TypeInfo<T>::TypeID!=VAR_TYPE_NONE)
return GenMatch(SQPLUS_GEN_CAST(T*,0),TypeInfo<T>().typeName,v,ix);
else return false;
}
template<typename T> T &Get(TypeWrapper<T&>, HSQUIRRELVM v, int ix){
if((ScriptVarType)TypeInfo<T>::TypeID!=VAR_TYPE_NONE)
return *(T*)GenGet(SQPLUS_GEN_CAST(T*,0),TypeInfo<T>().typeName,v,ix);
else return *SQPLUS_GEN_CAST(T,0);
}
template<typename T> T *Get(TypeWrapper<T*>, HSQUIRRELVM v, int ix){
if((ScriptVarType)TypeInfo<T>::TypeID!=VAR_TYPE_NONE)
return (T*)GenGet(SQPLUS_GEN_CAST(T*,0),TypeInfo<T>().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<bool>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<char>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<unsigned char>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<short>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<unsigned short>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<int>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<unsigned int>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<long>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<unsigned long>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<float>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<double>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<const SQChar *>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<SQChar *>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<HSQUIRRELVM>, HSQUIRRELVM v, int idx); // See Get() for HSQUIRRELVM below (v is always present).
bool Match(TypeWrapper<void*>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<SquirrelObject>, HSQUIRRELVM v, int idx); // See sq_getstackobj(): always returns true.
void Get(TypeWrapper<void>, HSQUIRRELVM v, int);
bool Get(TypeWrapper<bool>, HSQUIRRELVM v, int idx);
char Get(TypeWrapper<char>, HSQUIRRELVM v, int idx);
unsigned char Get(TypeWrapper<unsigned char>, HSQUIRRELVM v, int idx);
short Get(TypeWrapper<short>, HSQUIRRELVM v, int idx);
unsigned short Get(TypeWrapper<unsigned short>, HSQUIRRELVM v, int idx);
int Get(TypeWrapper<int>, HSQUIRRELVM v, int idx);
unsigned int Get(TypeWrapper<unsigned int>, HSQUIRRELVM v, int idx);
long Get(TypeWrapper<long>, HSQUIRRELVM v, int idx);
unsigned long Get(TypeWrapper<unsigned long>, HSQUIRRELVM v, int idx);
float Get(TypeWrapper<float>, HSQUIRRELVM v, int idx);
double Get(TypeWrapper<double>, HSQUIRRELVM v, int idx);
const SQChar *Get(TypeWrapper<const SQChar *>, HSQUIRRELVM v, int idx);
SquirrelNull Get(TypeWrapper<SquirrelNull>, HSQUIRRELVM v, int idx);
void *Get(TypeWrapper<void *>, HSQUIRRELVM v, int idx);
HSQUIRRELVM Get(TypeWrapper<HSQUIRRELVM>, HSQUIRRELVM v, int /*idx*/); // sq_poptop(v): remove UserData from stack so GetParamCount() matches normal behavior.
SquirrelObject Get(TypeWrapper<SquirrelObject>, 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<const SQOtherChar *>, HSQUIRRELVM v, int idx);
bool Match(TypeWrapper<SQOtherChar *>, HSQUIRRELVM v, int idx);
SQOthCharBuf Get(TypeWrapper<const SQOtherChar *>, 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<const std::string&>, HSQUIRRELVM v, int idx);
std::string Get(TypeWrapper<const std::string&>, HSQUIRRELVM v, int idx);
#endif
// Added jflanglois suggestion, 8/20/06. jcs
#ifdef SQPLUS_SUPPORT_SQ_STD_STRING
typedef std::basic_string<SQChar> sq_std_string;
void Push(HSQUIRRELVM v,const sq_std_string & value);
bool Match(TypeWrapper<const sq_std_string &>, HSQUIRRELVM v, int idx);
sq_std_string Get(TypeWrapper<const sq_std_string &>, HSQUIRRELVM v, int idx);
#endif
// Specialization to support void return type.
void GetRet(TypeWrapper<void>, 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<typename RT>
inline RT GetRet(TypeWrapper<RT>,HSQUIRRELVM v,int idx) {
static SquirrelObject st_sq_ret;
static typename Temporary<RT>::type st_ret;
st_ret = Get(TypeWrapper<RT>(),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<TYPE>,HSQUIRRELVM v,int idx) { return Match(TypeWrapper<int>(),v,idx); } \
TYPE Get(TypeWrapper<TYPE>,HSQUIRRELVM v,int idx) { return (TYPE)Get(TypeWrapper<int>(),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<TYPE> : public TypeInfo<int> { }; \
} // 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<TYPE>,HSQUIRRELVM v,int idx); \
TYPE Get(TypeWrapper<TYPE>,HSQUIRRELVM v,int idx); \
void Push(HSQUIRRELVM v,TYPE value); \
template<> struct TypeInfo<TYPE> : public TypeInfo<int> { }; \
} // 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<TYPE> { \
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<TYPE &>,HSQUIRRELVM v,int idx) { return GetInstance<TYPE,false>(v,idx) != NULL; } \
template<> inline bool Match(TypeWrapper<TYPE *>,HSQUIRRELVM v,int idx) { \
return (sq_gettype(v,idx)==OT_NULL) || (GetInstance<TYPE,false>(v,idx) != NULL); } \
template<> inline TYPE & Get(TypeWrapper<TYPE &>,HSQUIRRELVM v,int idx) { return *GetInstance<TYPE,true>(v,idx); } \
template<> inline TYPE * Get(TypeWrapper<TYPE *>,HSQUIRRELVM v,int idx) { \
if (sq_gettype(v,idx)==OT_NULL) return NULL; \
return GetInstance<TYPE,true>(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<TYPE &>,HSQUIRRELVM v,int idx) { return GetInstance<TYPE,false>(v,idx) != NULL; } \
template<> inline bool Match(TypeWrapper<TYPE *>,HSQUIRRELVM v,int idx) { return GetInstance<TYPE,false>(v,idx) != NULL; } \
template<> inline TYPE & Get(TypeWrapper<TYPE &>,HSQUIRRELVM v,int idx) { return *GetInstance<TYPE,true>(v,idx); } \
template<> inline TYPE * Get(TypeWrapper<TYPE *>,HSQUIRRELVM v,int idx) { return GetInstance<TYPE,true>(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<P##arg>(),v,_index_)) return sq_throwerror(v,_SC("Incorrect function argument"))
#else
#define sq_argassert(arg,_index_)
#endif
// === Return value variants ===
template<class RT>
struct ReturnSpecialization {
// === Standard Function calls ===
static int Call(RT (*func)(),HSQUIRRELVM v,int /*index*/) {
RT ret = func();
Push(v,ret);
return 1;
}
template<typename P1>
static int Call(RT (*func)(P1),HSQUIRRELVM v,int index) {
sq_argassert(1,index + 0);
RT ret = func(
Get(TypeWrapper<P1>(),v,index + 0)
);
Push(v,ret);
return 1;
}
template<typename P1,typename P2>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1)
);
Push(v,ret);
return 1;
}
template<typename P1,typename P2,typename P3>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2)
);
Push(v,ret);
return 1;
}
template<typename P1,typename P2,typename P3,typename P4>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2),
Get(TypeWrapper<P4>(),v,index + 3)
);
Push(v,ret);
return 1;
}
template<typename P1,typename P2,typename P3,typename P4,typename P5>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2),
Get(TypeWrapper<P4>(),v,index + 3),
Get(TypeWrapper<P5>(),v,index + 4)
);
Push(v,ret);
return 1;
}
template<typename P1,typename P2,typename P3,typename P4,typename P5,typename P6>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2),
Get(TypeWrapper<P4>(),v,index + 3),
Get(TypeWrapper<P5>(),v,index + 4),
Get(TypeWrapper<P6>(),v,index + 5)
);
Push(v,ret);
return 1;
}
template<typename P1,typename P2,typename P3,typename P4,typename P5,typename P6,typename P7>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2),
Get(TypeWrapper<P4>(),v,index + 3),
Get(TypeWrapper<P5>(),v,index + 4),
Get(TypeWrapper<P6>(),v,index + 5),
Get(TypeWrapper<P7>(),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<void> {
// === Standard function calls ===
static int Call(void (*func)(),HSQUIRRELVM v,int /*index*/) {
(void)v;
func();
return 0;
}
template<typename P1>
static int Call(void (*func)(P1),HSQUIRRELVM v,int index) {
sq_argassert(1,index + 0);
func(
Get(TypeWrapper<P1>(),v,index + 0)
);
return 0;
}
template<typename P1,typename P2>
static int Call(void (*func)(P1,P2),HSQUIRRELVM v,int index) {
sq_argassert(1,index + 0);
sq_argassert(2,index + 1);
func(
Get(TypeWrapper<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1)
);
return 0;
}
template<typename P1,typename P2,typename P3>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2)
);
return 0;
}
template<typename P1,typename P2,typename P3,typename P4>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2),
Get(TypeWrapper<P4>(),v,index + 3)
);
return 0;
}
template<typename P1,typename P2,typename P3,typename P4,typename P5>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2),
Get(TypeWrapper<P4>(),v,index + 3),
Get(TypeWrapper<P5>(),v,index + 4)
);
return 0;
}
template<typename P1,typename P2,typename P3,typename P4,typename P5,typename P6>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2),
Get(TypeWrapper<P4>(),v,index + 3),
Get(TypeWrapper<P5>(),v,index + 4),
Get(TypeWrapper<P6>(),v,index + 5)
);
return 0;
}
template<typename P1,typename P2,typename P3,typename P4,typename P5,typename P6,typename P7>
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<P1>(),v,index + 0),
Get(TypeWrapper<P2>(),v,index + 1),
Get(TypeWrapper<P3>(),v,index + 2),
Get(TypeWrapper<P4>(),v,index + 3),
Get(TypeWrapper<P5>(),v,index + 4),
Get(TypeWrapper<P6>(),v,index + 5),
Get(TypeWrapper<P7>(),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<typename RT>
int Call(RT (*func)(),HSQUIRRELVM v,int index) {
return ReturnSpecialization<RT>::Call(func,v,index);
}
template<typename RT,typename P1>
int Call(RT (*func)(P1),HSQUIRRELVM v,int index) {
return ReturnSpecialization<RT>::Call(func,v,index);
}
template<typename RT,typename P1,typename P2>
int Call(RT (*func)(P1,P2),HSQUIRRELVM v,int index) {
return ReturnSpecialization<RT>::Call(func,v,index);
}
template<typename RT,typename P1,typename P2,typename P3>
int Call(RT (*func)(P1,P2,P3),HSQUIRRELVM v,int index) {
return ReturnSpecialization<RT>::Call(func,v,index);
}
template<typename RT,typename P1,typename P2,typename P3,typename P4>
int Call(RT (*func)(P1,P2,P3,P4),HSQUIRRELVM v,int index) {
return ReturnSpecialization<RT>::Call(func,v,index);
}
template<typename RT,typename P1,typename P2,typename P3,typename P4,typename P5>
int Call(RT (*func)(P1,P2,P3,P4,P5),HSQUIRRELVM v,int index) {
return ReturnSpecialization<RT>::Call(func,v,index);
}
template<typename RT,typename P1,typename P2,typename P3,typename P4,typename P5,typename P6>
int Call(RT (*func)(P1,P2,P3,P4,P5,P6),HSQUIRRELVM v,int index) {
return ReturnSpecialization<RT>::Call(func,v,index);
}
template<typename RT,typename P1,typename P2,typename P3,typename P4,typename P5,typename P6,typename P7>
int Call(RT (*func)(P1,P2,P3,P4,P5,P6,P7),HSQUIRRELVM v,int index) {
return ReturnSpecialization<RT>::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<typename Func>
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<typename Callee,typename Func>
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<typename Callee, typename Func>
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<Callee*>(sa.GetInstanceUp(1, 0));
const int paramCount = sa.GetParamCount();
func = static_cast<Func*>(sa.GetUserData(paramCount));
#ifdef SQ_USE_CLASS_INHERITANCE
SquirrelObject so(sa.GetObjectHandle(1)); // 'this'
SQUserPointer typetag; so.GetTypeTag(&typetag);
SQUserPointer calleeType = ClassType<Callee>::type();
if (typetag != calleeType) {
SquirrelObject typeTable = so.GetValue(SQ_CLASS_OBJECT_TABLE_NAME);
instance = static_cast<Callee*>(
// <TODO> 64-bit compatible version.
typeTable.GetUserPointer(INT((size_t)ClassType<Callee>::type()))
);
}
#elif defined(SQ_USE_CLASS_INHERITANCE_SIMPLE)
SquirrelObject so(sa.GetObjectHandle(1)); // 'this'
ClassTypeBase *instType; so.GetTypeTag((SQUserPointer*)&instType);
ClassTypeBase *calleeType = ClassType<Callee>::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<typename Callee,typename Func>
class DirectCallInstanceMemberFunction {
public:
static inline int Dispatch(HSQUIRRELVM v) {
DirectCallInstanceFuncPicker<Callee, Func> 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<typename Callee,typename Func>
class DirectCallInstanceGlobalFunction {
public:
static inline int Dispatch(HSQUIRRELVM v) {
DirectCallInstanceFuncPicker<Callee, Func> 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<typename Callee,typename Func>
class DirectCallInstanceGlobalFunctionVarArgs {
public:
static inline int Dispatch(HSQUIRRELVM v) {
DirectCallInstanceFuncPicker<Callee, Func> 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<typename Callee,typename Func>
class DirectCallInstanceMemberFunctionVarArgs {
public:
static inline int Dispatch(HSQUIRRELVM v) {
DirectCallInstanceFuncPicker<Callee, Func> 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<typename Func>
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<Func>::Dispatch,nupvalues+1);
#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK
sq_setparamscheck(v,0,sqTypeMask<Func>::Get());
#endif
} // sq_pushdirectclosure
// === Fixed Class pointer call (always calls with object pointer that was registered) ===
template<typename Callee,typename Func>
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<Callee,Func>::Dispatch,nupvalues+1);
#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK
sq_setparamscheck(v,0,sqTypeMask<Func>::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<typename Callee,typename Func>
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<Callee,Func>::Dispatch,nupvalues+1);
#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK
sq_setparamscheck(v,0,sqTypeMask<Func>::Get());
#endif
} // sq_pushdirectinstanceclosure
// === Global function using this: class pointer retrieved from script class instance ===
template<typename Callee,typename Func>
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<Callee,Func>::Dispatch,nupvalues+1);
#ifdef SQPLUS_ENABLE_AUTO_TYPEMASK
SQChar *tm = (SQChar*)sqTypeMask<Func>::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<typename Callee,typename Func>
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<Callee,Func>::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<typename Callee>
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<Callee, FuncType>::Dispatch,nupvalues+1);
} // sq_pushdirectinstanceclosurevarargs
// === Register a STANDARD function (table or class on stack) ===
template<typename Func>
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<typename Callee,typename Func>
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<typename Func>
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<typename Func>
inline void RegisterGlobal(Func func,const SQChar * name) {
RegisterGlobal(SquirrelVM::GetVMPtr(),func,name);
} // RegisterGlobal
// === Register a MEMBER global function (root table) ===
template<typename Callee,typename Func>
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<typename Callee,typename Func>
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<typename Func>
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<typename Callee,typename Func>
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<typename Callee,typename Func>
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<typename Callee,typename Func>
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<typename Callee,typename Func>
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<typename Callee>
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 { // <TODO> 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<typename RT>
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<RT>(),v,-1);
}
template<typename P1>
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<RT>(),v,-1);
}
template<typename P1,typename P2>
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<RT>(),v,-1);
}
template<typename P1,typename P2,typename P3>
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<RT>(),v,-1);
}
template<typename P1,typename P2,typename P3,typename P4>
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<RT>(),v,-1);
}
template<typename P1,typename P2,typename P3,typename P4,typename P5>
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<RT>(),v,-1);
}
template<typename P1,typename P2,typename P3,typename P4,typename P5,typename P6>
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<RT>(),v,-1);
}
template<typename P1,typename P2,typename P3,typename P4,typename P5,typename P6,typename P7>
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<RT>(),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<typename T>
struct ReleaseClassPtrPtr {
static int release(SQUserPointer up,SQInteger size) {
if (up) {
T ** self = (T **)up;
delete *self;
} // if
return 0;
} // release
};
template<typename T>
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<typename T>
inline void PopulateAncestry(HSQUIRRELVM v,
SquirrelObject &instance,
T *newClass)
{
// 11/2/05: Create a new table for this instance.
SquirrelObject newObjectTable = SquirrelVM::CreateTable();
// <TODO> 64-bit compatible version.
newObjectTable.SetUserPointer(INT((size_t)ClassType<T>::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<typename T>
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<typename T>
struct ConstructReleaseClass {
static int construct(HSQUIRRELVM v) {
return PostConstruct<T>(v,new T(),release);
} // construct
SQ_DECLARE_RELEASE(T)
};
# ifdef SQPLUS_ENABLE_TYPEOF
template<typename T>
int sq_typeof(HSQUIRRELVM v) {
sq_pushstring(v,TypeInfo<T>().typeName,-1);
return 1;
}
# endif
// === Helper for RegisterClassType*() ===
inline void setupClassHierarchy(SquirrelObject newClass) {
// <NOTE> 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<typename T>
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<T>::type(),scriptClassName,baseScriptClassName)) {
SquirrelVM::CreateFunction(newClass,&ConstructReleaseClass<T>::construct,_SC("constructor"));
# ifdef SQ_USE_CLASS_INHERITANCE
setupClassHierarchy(newClass);
# endif
# ifdef SQPLUS_ENABLE_TYPEOF
SquirrelVM::CreateFunction(newClass,&sq_typeof<T>,_SC("_typeof"));
# endif
} // if
sq_settop(v,top);
return newClass;
} // RegisterClassType
template<typename T>
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<T>::type(),scriptClassName,baseScriptClassName)) {
# ifdef SQ_USE_CLASS_INHERITANCE
setupClassHierarchy(newClass);
# endif
# ifdef SQPLUS_ENABLE_TYPEOF
SquirrelVM::CreateFunction(newClass,&sq_typeof<T>,_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.
// <NOTE> Do not use SQClassDefBase<> directly, use SQClassDef<> or SQClassDefNoConstructor<>, below.
template<typename TClassType, typename TClassBase>
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<TClassBase>());}
template<class Base>
void InitBase(TypeWrapper<Base>){ /*assert(base);*/ ClassType<TClassType>::Get()->SetBase(TypeWrapper<Base>()); CheckInitDefaultNames(); }
void InitBase(TypeWrapper<SQNoBaseClass>){ /*assert(!base);*/ CheckInitDefaultNames(); }
void CheckInitDefaultNames(){ if( !name ) name=TypeInfo<TClassType>().typeName; if( !base ) base=TypeInfo<TClassBase>().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<TClassType>().typeName; }
#endif
// Register a member function.
template<typename Func>
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<typename Func>
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<typename Func>
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<typename Func>
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<typename Func>
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<typename Func>
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<typename Callee,typename Func>
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<typename VarType>
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<TClassType>::type(),*(VarType **)&cv,name,access);
return *this;
} // var
// Register a member variable as a UserPointer (read only).
template<typename VarType>
SQClassDefBase & varAsUserPointer(VarType TClassType::* pvar,const SQChar * name) {
struct CV {
VarType TClassType::* var;
} cv; // Cast Variable helper.
cv.var = pvar;
RegisterInstanceVariable(newClass,ClassType<TClassType>::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<typename VarType>
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<TClassType>::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<typename ConstantType>
SQClassDefBase & constant(ConstantType constant,const SQChar * name) {
RegisterInstanceConstant(newClass,ClassType<TClassType>::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<TClassType>::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<typename TClassType, typename TClassBase=SQNoBaseClass>
struct SQClassDef : public SQClassDefBase<TClassType,TClassBase> {
#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<TClassType,TClassBase>(_v,_name,_base) {
SQClassDefBase<TClassType,TClassBase>::newClass =
RegisterClassType<TClassType>( SQClassDefBase<TClassType,TClassBase>::v,
SQClassDefBase<TClassType,TClassBase>::name,
SQClassDefBase<TClassType,TClassBase>::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<TClassType,TClassBase>(_name,_base) {
SQClassDefBase<TClassType,TClassBase>::newClass =
RegisterClassType< TClassType>( SQClassDefBase<TClassType,TClassBase>::v,
SQClassDefBase<TClassType,TClassBase>::name,
SQClassDefBase<TClassType,TClassBase>::base );
}
#else
SQClassDef(HSQUIRRELVM _v,const SQChar * _name=0) : SQClassDefBase<TClassType,TClassBase>(_v,_name) {
SQClassDefBase<TClassType,TClassBase>::newClass =
RegisterClassType<TClassType>(SQClassDefBase<TClassType,TClassBase>::v,
SQClassDefBase<TClassType,TClassBase>::name );
}
SQClassDef(const SQChar * _name=0) : SQClassDefBase<TClassType,TClassBase>(_name) {
SQClassDefBase<TClassType,TClassBase>::newClass =
RegisterClassType<TClassType>(SQClassDefBase<TClassType,TClassBase>::v,
SQClassDefBase<TClassType,TClassBase>::name );
}
#endif
};
template<typename TClassType, typename TClassBase=SQNoBaseClass>
struct SQClassDefNoConstructor : public SQClassDefBase<TClassType,TClassBase> {
#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<TClassType,TClassBase>(_v,_name,_base) {
SQClassDefBase<TClassType,TClassBase>::newClass = RegisterClassTypeNoConstructor<TClassType>(SQClassDefBase<TClassType,TClassBase>::v,SQClassDefBase<TClassType,TClassBase>::name,SQClassDefBase<TClassType,TClassBase>::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<TClassType,TClassBase>(_name,_base) {
SQClassDefBase<TClassType,TClassBase>::newClass = RegisterClassTypeNoConstructor<TClassType>(SQClassDefBase<TClassType,TClassBase>::v,SQClassDefBase<TClassType,TClassBase>::name,SQClassDefBase<TClassType,TClassBase>::base);
}
#else
SQClassDefNoConstructor(HSQUIRRELVM _v,const SQChar * _name=0) : SQClassDefBase<TClassType,TClassBase>(_v,_name) {
SQClassDefBase<TClassType,TClassBase>::newClass = RegisterClassTypeNoConstructor<TClassType>(SQClassDefBase<TClassType,TClassBase>::v,SQClassDefBase<TClassType,TClassBase>::name);
}
SQClassDefNoConstructor(const SQChar * _name=0) : SQClassDefBase<TClassType,TClassBase>(_name) {
SQClassDefBase<TClassType,TClassBase>::newClass = RegisterClassTypeNoConstructor<TClassType>(SQClassDefBase<TClassType,TClassBase>::v,SQClassDefBase<TClassType,TClassBase>::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<typename _ty>
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<typename _ty>
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<typename _ty>
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_