Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,480 @@
|
||||
#include "scriptany.h"
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// We'll use the generic interface for the factories as we need the engine pointer
|
||||
static void ScriptAnyFactory_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asIScriptEngine *engine = gen->GetEngine();
|
||||
|
||||
*(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(engine);
|
||||
}
|
||||
|
||||
static void ScriptAnyFactory2_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asIScriptEngine *engine = gen->GetEngine();
|
||||
void *ref = (void*)gen->GetArgAddress(0);
|
||||
int refType = gen->GetArgTypeId(0);
|
||||
|
||||
*(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(ref,refType,engine);
|
||||
}
|
||||
|
||||
static CScriptAny &ScriptAnyAssignment(CScriptAny *other, CScriptAny *self)
|
||||
{
|
||||
return *self = *other;
|
||||
}
|
||||
|
||||
static void ScriptAnyAssignment_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptAny *other = (CScriptAny*)gen->GetArgObject(0);
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
|
||||
*self = *other;
|
||||
|
||||
gen->SetReturnObject(self);
|
||||
}
|
||||
|
||||
static void ScriptAny_Store_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void *ref = (void*)gen->GetArgAddress(0);
|
||||
int refTypeId = gen->GetArgTypeId(0);
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
|
||||
self->Store(ref, refTypeId);
|
||||
}
|
||||
|
||||
static void ScriptAny_StoreInt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asINT64 *ref = (asINT64*)gen->GetArgAddress(0);
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
|
||||
self->Store(*ref);
|
||||
}
|
||||
|
||||
static void ScriptAny_StoreFlt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
double *ref = (double*)gen->GetArgAddress(0);
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
|
||||
self->Store(*ref);
|
||||
}
|
||||
|
||||
static void ScriptAny_Retrieve_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void *ref = (void*)gen->GetArgAddress(0);
|
||||
int refTypeId = gen->GetArgTypeId(0);
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(ref, refTypeId);
|
||||
}
|
||||
|
||||
static void ScriptAny_RetrieveInt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
asINT64 *ref = (asINT64*)gen->GetArgAddress(0);
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref);
|
||||
}
|
||||
|
||||
static void ScriptAny_RetrieveFlt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
double *ref = (double*)gen->GetArgAddress(0);
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref);
|
||||
}
|
||||
|
||||
static void ScriptAny_AddRef_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
self->AddRef();
|
||||
}
|
||||
|
||||
static void ScriptAny_Release_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
self->Release();
|
||||
}
|
||||
|
||||
static void ScriptAny_GetRefCount_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
|
||||
}
|
||||
|
||||
static void ScriptAny_SetFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
self->SetFlag();
|
||||
}
|
||||
|
||||
static void ScriptAny_GetFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag();
|
||||
}
|
||||
|
||||
static void ScriptAny_EnumReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->EnumReferences(engine);
|
||||
}
|
||||
|
||||
static void ScriptAny_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptAny *self = (CScriptAny*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->ReleaseAllHandles(engine);
|
||||
}
|
||||
|
||||
void RegisterScriptAny(asIScriptEngine *engine)
|
||||
{
|
||||
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
|
||||
RegisterScriptAny_Generic(engine);
|
||||
else
|
||||
RegisterScriptAny_Native(engine);
|
||||
}
|
||||
|
||||
void RegisterScriptAny_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF/* | asOBJ_GC*/); assert( r >= 0 );
|
||||
|
||||
// We'll use the generic interface for the constructor as we need the engine pointer
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptAny,AddRef), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptAny,Release), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "void store(?&in)", asMETHODPR(CScriptAny,Store,(void*,int),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asMETHODPR(CScriptAny,Store,(asINT64&),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "void store(const double&in)", asMETHODPR(CScriptAny,Store,(double&),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "bool retrieve(?&out)", asMETHODPR(CScriptAny,Retrieve,(void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out)", asMETHODPR(CScriptAny,Retrieve,(asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "bool retrieve(double&out)", asMETHODPR(CScriptAny,Retrieve,(double&) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
// Register GC behaviours
|
||||
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptAny,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
|
||||
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptAny,SetFlag), asCALL_THISCALL); assert( r >= 0 );
|
||||
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptAny,GetFlag), asCALL_THISCALL); assert( r >= 0 );
|
||||
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptAny,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
|
||||
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptAny,ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 );
|
||||
}
|
||||
|
||||
void RegisterScriptAny_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
|
||||
|
||||
// We'll use the generic interface for the constructor as we need the engine pointer
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptAny_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptAny_Release_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "void store(?&in)", asFUNCTION(ScriptAny_Store_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asFUNCTION(ScriptAny_StoreInt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "void store(const double&in)", asFUNCTION(ScriptAny_StoreFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "bool retrieve(?&out) const", asFUNCTION(ScriptAny_Retrieve_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out) const", asFUNCTION(ScriptAny_RetrieveInt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("any", "bool retrieve(double&out) const", asFUNCTION(ScriptAny_RetrieveFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Register GC behaviours
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptAny_GetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptAny_SetFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptAny_GetFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptAny_EnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptAny_ReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
}
|
||||
|
||||
|
||||
CScriptAny &CScriptAny::operator=(const CScriptAny &other)
|
||||
{
|
||||
// Hold on to the object type reference so it isn't destroyed too early
|
||||
if( other.value.typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
asITypeInfo *ti = engine->GetTypeInfoById(other.value.typeId);
|
||||
if( ti )
|
||||
ti->AddRef();
|
||||
}
|
||||
|
||||
FreeObject();
|
||||
|
||||
value.typeId = other.value.typeId;
|
||||
if( value.typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// For handles, copy the pointer and increment the reference count
|
||||
value.valueObj = other.value.valueObj;
|
||||
engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
|
||||
}
|
||||
else if( value.typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Create a copy of the object
|
||||
value.valueObj = engine->CreateScriptObjectCopy(other.value.valueObj, engine->GetTypeInfoById(value.typeId));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Primitives can be copied directly
|
||||
value.valueInt = other.value.valueInt;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
int CScriptAny::CopyFrom(const CScriptAny *other)
|
||||
{
|
||||
if( other == 0 ) return asINVALID_ARG;
|
||||
|
||||
*this = *(CScriptAny*)other;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CScriptAny::CScriptAny(asIScriptEngine *engine)
|
||||
{
|
||||
this->engine = engine;
|
||||
refCount = 1;
|
||||
gcFlag = false;
|
||||
|
||||
value.typeId = 0;
|
||||
value.valueInt = 0;
|
||||
|
||||
// Notify the garbage collector of this object
|
||||
//engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any"));
|
||||
}
|
||||
|
||||
CScriptAny::CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine)
|
||||
{
|
||||
this->engine = engine;
|
||||
refCount = 1;
|
||||
gcFlag = false;
|
||||
|
||||
value.typeId = 0;
|
||||
value.valueInt = 0;
|
||||
|
||||
// Notify the garbage collector of this object
|
||||
//engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any"));
|
||||
|
||||
Store(ref, refTypeId);
|
||||
}
|
||||
|
||||
CScriptAny::~CScriptAny()
|
||||
{
|
||||
FreeObject();
|
||||
}
|
||||
|
||||
void CScriptAny::Store(void *ref, int refTypeId)
|
||||
{
|
||||
// This method is not expected to be used for primitive types, except for bool, int64, or double
|
||||
assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_VOID || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE );
|
||||
|
||||
// Hold on to the object type reference so it isn't destroyed too early
|
||||
if( refTypeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
asITypeInfo *ti = engine->GetTypeInfoById(refTypeId);
|
||||
if( ti )
|
||||
ti->AddRef();
|
||||
}
|
||||
|
||||
FreeObject();
|
||||
|
||||
value.typeId = refTypeId;
|
||||
if( value.typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// We're receiving a reference to the handle, so we need to dereference it
|
||||
value.valueObj = *(void**)ref;
|
||||
engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
|
||||
}
|
||||
else if( value.typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Create a copy of the object
|
||||
value.valueObj = engine->CreateScriptObjectCopy(ref, engine->GetTypeInfoById(value.typeId));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Primitives can be copied directly
|
||||
value.valueInt = 0;
|
||||
|
||||
// Copy the primitive value
|
||||
// We receive a pointer to the value.
|
||||
int size = engine->GetSizeOfPrimitiveType(value.typeId);
|
||||
memcpy(&value.valueInt, ref, size);
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptAny::Store(double &ref)
|
||||
{
|
||||
Store(&ref, asTYPEID_DOUBLE);
|
||||
}
|
||||
|
||||
void CScriptAny::Store(asINT64 &ref)
|
||||
{
|
||||
Store(&ref, asTYPEID_INT64);
|
||||
}
|
||||
|
||||
|
||||
bool CScriptAny::Retrieve(void *ref, int refTypeId) const
|
||||
{
|
||||
// This method is not expected to be used for primitive types, except for bool, int64, or double
|
||||
assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE );
|
||||
|
||||
if( refTypeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// Is the handle type compatible with the stored value?
|
||||
|
||||
// A handle can be retrieved if the stored type is a handle of same or compatible type
|
||||
// or if the stored type is an object that implements the interface that the handle refer to.
|
||||
if( (value.typeId & asTYPEID_MASK_OBJECT) )
|
||||
{
|
||||
// Don't allow the retrieval if the stored handle is to a const object but not the wanted handle
|
||||
if( (value.typeId & asTYPEID_HANDLETOCONST) && !(refTypeId & asTYPEID_HANDLETOCONST) )
|
||||
return false;
|
||||
|
||||
// RefCastObject will increment the refCount of the returned pointer if successful
|
||||
engine->RefCastObject(value.valueObj, engine->GetTypeInfoById(value.typeId), engine->GetTypeInfoById(refTypeId), reinterpret_cast<void**>(ref));
|
||||
if( *(asPWORD*)ref == 0 )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if( refTypeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Is the object type compatible with the stored value?
|
||||
|
||||
// Copy the object into the given reference
|
||||
if( value.typeId == refTypeId )
|
||||
{
|
||||
engine->AssignScriptObject(ref, value.valueObj, engine->GetTypeInfoById(value.typeId));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is the primitive type compatible with the stored value?
|
||||
|
||||
if( value.typeId == refTypeId )
|
||||
{
|
||||
int size = engine->GetSizeOfPrimitiveType(refTypeId);
|
||||
memcpy(ref, &value.valueInt, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
|
||||
if( value.typeId == asTYPEID_INT64 && refTypeId == asTYPEID_DOUBLE )
|
||||
{
|
||||
*(double*)ref = double(value.valueInt);
|
||||
return true;
|
||||
}
|
||||
else if( value.typeId == asTYPEID_DOUBLE && refTypeId == asTYPEID_INT64 )
|
||||
{
|
||||
*(asINT64*)ref = asINT64(value.valueFlt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptAny::Retrieve(asINT64 &outValue) const
|
||||
{
|
||||
return Retrieve(&outValue, asTYPEID_INT64);
|
||||
}
|
||||
|
||||
bool CScriptAny::Retrieve(double &outValue) const
|
||||
{
|
||||
return Retrieve(&outValue, asTYPEID_DOUBLE);
|
||||
}
|
||||
|
||||
int CScriptAny::GetTypeId() const
|
||||
{
|
||||
return value.typeId;
|
||||
}
|
||||
|
||||
void CScriptAny::FreeObject()
|
||||
{
|
||||
// If it is a handle or a ref counted object, call release
|
||||
if( value.typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Let the engine release the object
|
||||
asITypeInfo *ti = engine->GetTypeInfoById(value.typeId);
|
||||
engine->ReleaseScriptObject(value.valueObj, ti);
|
||||
|
||||
// Release the object type info
|
||||
if( ti )
|
||||
ti->Release();
|
||||
|
||||
value.valueObj = 0;
|
||||
value.typeId = 0;
|
||||
}
|
||||
|
||||
// For primitives, there's nothing to do
|
||||
}
|
||||
|
||||
|
||||
void CScriptAny::EnumReferences(asIScriptEngine *inEngine)
|
||||
{
|
||||
// If we're holding a reference, we'll notify the garbage collector of it
|
||||
if( value.valueObj && (value.typeId & asTYPEID_MASK_OBJECT) )
|
||||
{
|
||||
inEngine->GCEnumCallback(value.valueObj);
|
||||
|
||||
// The object type itself is also garbage collected
|
||||
asITypeInfo *ti = inEngine->GetTypeInfoById(value.typeId);
|
||||
if( ti )
|
||||
inEngine->GCEnumCallback(ti);
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptAny::ReleaseAllHandles(asIScriptEngine * /*engine*/)
|
||||
{
|
||||
FreeObject();
|
||||
}
|
||||
|
||||
int CScriptAny::AddRef() const
|
||||
{
|
||||
// Increase counter and clear flag set by GC
|
||||
gcFlag = false;
|
||||
return asAtomicInc(refCount);
|
||||
}
|
||||
|
||||
int CScriptAny::Release() const
|
||||
{
|
||||
// Decrease the ref counter
|
||||
gcFlag = false;
|
||||
if( asAtomicDec(refCount) == 0 )
|
||||
{
|
||||
// Delete this object as no more references to it exists
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return refCount;
|
||||
}
|
||||
|
||||
int CScriptAny::GetRefCount()
|
||||
{
|
||||
return refCount;
|
||||
}
|
||||
|
||||
void CScriptAny::SetFlag()
|
||||
{
|
||||
gcFlag = true;
|
||||
}
|
||||
|
||||
bool CScriptAny::GetFlag()
|
||||
{
|
||||
return gcFlag;
|
||||
}
|
||||
|
||||
|
||||
END_AS_NAMESPACE
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,771 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "scriptdictionary.h"
|
||||
#include "scriptarray.h"
|
||||
|
||||
#include "../source/as_scriptengine.h"
|
||||
#include "../source/as_scriptobject.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool IsHandleCompatibleWithObject(asCScriptEngine* engine, void *obj, int objTypeId, int handleTypeId)
|
||||
{
|
||||
// if equal, then it is obvious they are compatible
|
||||
if( objTypeId == handleTypeId )
|
||||
return true;
|
||||
|
||||
// Get the actual data types from the type ids
|
||||
asCDataType objDt = engine->GetDataTypeFromTypeId(objTypeId);
|
||||
asCDataType hdlDt = engine->GetDataTypeFromTypeId(handleTypeId);
|
||||
|
||||
// A handle to const cannot be passed to a handle that is not referencing a const object
|
||||
if( objDt.IsHandleToConst() && !hdlDt.IsHandleToConst() )
|
||||
return false;
|
||||
|
||||
if( objDt.GetTypeInfo() == hdlDt.GetTypeInfo() )
|
||||
{
|
||||
// The object type is equal
|
||||
return true;
|
||||
}
|
||||
else if( objDt.IsScriptObject() && obj )
|
||||
{
|
||||
// Get the true type from the object instance
|
||||
asITypeInfo *objType = ((asCScriptObject*)obj)->GetObjectType();
|
||||
|
||||
// Check if the object implements the interface, or derives from the base class
|
||||
// This will also return true, if the requested handle type is an exact match for the object type
|
||||
if( objType->Implements(hdlDt.GetTypeInfo()) ||
|
||||
objType->DerivesFrom(hdlDt.GetTypeInfo()) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// CScriptDictionary implementation
|
||||
|
||||
CScriptDictionary::CScriptDictionary(asIScriptEngine *engine)
|
||||
{
|
||||
// We start with one reference
|
||||
refCount.set(1);
|
||||
gcFlag = false;
|
||||
|
||||
// Start at the zeroth modification
|
||||
modCount = 0;
|
||||
|
||||
// Keep a reference to the engine for as long as we live
|
||||
// We don't increment the reference counter, because the
|
||||
// engine will hold a pointer to the object.
|
||||
this->engine = engine;
|
||||
|
||||
// Notify the garbage collector of this object
|
||||
// TODO: The type id should be cached
|
||||
engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("dictionary"));
|
||||
}
|
||||
|
||||
CScriptDictionary::~CScriptDictionary()
|
||||
{
|
||||
// Delete all keys and values
|
||||
DeleteAll();
|
||||
}
|
||||
|
||||
void CScriptDictionary::AddRef() const
|
||||
{
|
||||
// We need to clear the GC flag
|
||||
gcFlag = false;
|
||||
refCount.atomicInc();
|
||||
}
|
||||
|
||||
void CScriptDictionary::Release() const
|
||||
{
|
||||
// We need to clear the GC flag
|
||||
gcFlag = false;
|
||||
if( refCount.atomicDec() == 0 )
|
||||
delete this;
|
||||
}
|
||||
|
||||
int CScriptDictionary::GetRefCount()
|
||||
{
|
||||
return refCount.get();
|
||||
}
|
||||
|
||||
void CScriptDictionary::SetGCFlag()
|
||||
{
|
||||
gcFlag = true;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::GetGCFlag()
|
||||
{
|
||||
return gcFlag;
|
||||
}
|
||||
|
||||
void CScriptDictionary::EnumReferences(asIScriptEngine *engine)
|
||||
{
|
||||
// Call the gc enum callback for each of the objects
|
||||
mapType::iterator it;
|
||||
for( it = dict.begin(); it != dict.end(); it++ )
|
||||
{
|
||||
if( it->second.typeId & asTYPEID_MASK_OBJECT )
|
||||
engine->GCEnumCallback(it->second.valueObj);
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptDictionary::ReleaseAllReferences(asIScriptEngine * /*engine*/)
|
||||
{
|
||||
// We're being told to release all references in
|
||||
// order to break circular references for dead objects
|
||||
DeleteAll();
|
||||
}
|
||||
|
||||
CScriptDictionary &CScriptDictionary::operator =(const CScriptDictionary &other)
|
||||
{
|
||||
// Clear everything we had before
|
||||
DeleteAll();
|
||||
|
||||
// Do a shallow copy of the dictionary
|
||||
mapType::const_iterator it;
|
||||
for( it = other.dict.begin(); it != other.dict.end(); it++ )
|
||||
{
|
||||
if( it->second.typeId & asTYPEID_OBJHANDLE )
|
||||
Set(it->first, (void*)&it->second.valueObj, it->second.typeId);
|
||||
else if( it->second.typeId & asTYPEID_MASK_OBJECT )
|
||||
Set(it->first, (void*)it->second.valueObj, it->second.typeId);
|
||||
else
|
||||
Set(it->first, (void*)&it->second.valueInt, it->second.typeId);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CScriptDictionary::Set(const string &key, void *value, int typeId)
|
||||
{
|
||||
valueStruct valStruct = {{0},0};
|
||||
valStruct.typeId = typeId;
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// We're receiving a reference to the handle, so we need to dereference it
|
||||
valStruct.valueObj = *(void**)value;
|
||||
engine->AddRefScriptObject(valStruct.valueObj, engine->GetTypeInfoById(typeId));
|
||||
}
|
||||
else if( typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Create a copy of the object
|
||||
valStruct.valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the primitive value
|
||||
// We receive a pointer to the value.
|
||||
int size = engine->GetSizeOfPrimitiveType(typeId);
|
||||
memcpy(&valStruct.valueInt, value, size);
|
||||
}
|
||||
|
||||
mapType::iterator it;
|
||||
it = dict.find(key);
|
||||
if( it != dict.end() )
|
||||
{
|
||||
FreeValue(it->second);
|
||||
|
||||
// Insert the new value
|
||||
it->second = valStruct;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict.insert(mapType::value_type(key, valStruct));
|
||||
++modCount;
|
||||
}
|
||||
}
|
||||
|
||||
// This overloaded method is implemented so that all integer and
|
||||
// unsigned integers types will be stored in the dictionary as int64
|
||||
// through implicit conversions. This simplifies the management of the
|
||||
// numeric types when the script retrieves the stored value using a
|
||||
// different type.
|
||||
void CScriptDictionary::Set(const string &key, asINT64 &value)
|
||||
{
|
||||
Set(key, &value, asTYPEID_INT64);
|
||||
}
|
||||
|
||||
// This overloaded method is implemented so that all floating point types
|
||||
// will be stored in the dictionary as double through implicit conversions.
|
||||
// This simplifies the management of the numeric types when the script
|
||||
// retrieves the stored value using a different type.
|
||||
void CScriptDictionary::Set(const string &key, double &value)
|
||||
{
|
||||
Set(key, &value, asTYPEID_DOUBLE);
|
||||
}
|
||||
|
||||
// This helper function exists to assist various dictionary and iterator
|
||||
// methods that want to retrieve a value from a standard iterator
|
||||
bool CScriptDictionary::Iterator_GetValue(CScriptDictionary::mapType::const_iterator &it, void *value, int typeId) const {
|
||||
// Return the value
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// A handle can be retrieved if the stored type is a handle of same or compatible type
|
||||
// or if the stored type is an object that implements the interface that the handle refer to.
|
||||
if( (it->second.typeId & asTYPEID_MASK_OBJECT) &&
|
||||
IsHandleCompatibleWithObject((asCScriptEngine*)engine, it->second.valueObj, it->second.typeId, typeId) )
|
||||
{
|
||||
engine->AddRefScriptObject(it->second.valueObj, engine->GetTypeInfoById(it->second.typeId));
|
||||
*(void**)value = it->second.valueObj;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if( typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Verify that the copy can be made
|
||||
bool isCompatible = false;
|
||||
if( it->second.typeId == typeId )
|
||||
isCompatible = true;
|
||||
|
||||
// Copy the object into the given reference
|
||||
if( isCompatible )
|
||||
{
|
||||
engine->AssignScriptObject(value, it->second.valueObj, engine->GetTypeInfoById(typeId));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( it->second.typeId == typeId )
|
||||
{
|
||||
int size = engine->GetSizeOfPrimitiveType(typeId);
|
||||
memcpy(value, &it->second.valueInt, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
|
||||
if( it->second.typeId == asTYPEID_INT64 && typeId == asTYPEID_DOUBLE )
|
||||
{
|
||||
*(double*)value = double(it->second.valueInt);
|
||||
return true;
|
||||
}
|
||||
else if( it->second.typeId == asTYPEID_DOUBLE && typeId == asTYPEID_INT64 )
|
||||
{
|
||||
*(asINT64*)value = asINT64(it->second.valueFlt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// AngelScript has already initialized the value with a default value,
|
||||
// so we don't have to do anything if we don't find the element, or if
|
||||
// the element is incompatible with the requested type.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if the value was successfully retrieved
|
||||
bool CScriptDictionary::Get(const string &key, void *value, int typeId) const
|
||||
{
|
||||
mapType::const_iterator it;
|
||||
it = dict.find(key);
|
||||
if( it != dict.end() )
|
||||
{
|
||||
// This logic is already implemented in the iterator wrapper,
|
||||
// so defer to that function from here
|
||||
return Iterator_GetValue(it, value, typeId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::Get(const string &key, asINT64 &value) const
|
||||
{
|
||||
return Get(key, &value, asTYPEID_INT64);
|
||||
}
|
||||
|
||||
bool CScriptDictionary::Get(const string &key, double &value) const
|
||||
{
|
||||
return Get(key, &value, asTYPEID_DOUBLE);
|
||||
}
|
||||
|
||||
bool CScriptDictionary::Exists(const string &key) const
|
||||
{
|
||||
mapType::const_iterator it;
|
||||
it = dict.find(key);
|
||||
if( it != dict.end() )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::IsEmpty() const
|
||||
{
|
||||
if( dict.size() == 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
asUINT CScriptDictionary::GetSize() const
|
||||
{
|
||||
return asUINT(dict.size());
|
||||
}
|
||||
|
||||
void CScriptDictionary::Delete(const string &key)
|
||||
{
|
||||
mapType::iterator it;
|
||||
it = dict.find(key);
|
||||
if( it != dict.end() )
|
||||
{
|
||||
FreeValue(it->second);
|
||||
dict.erase(it);
|
||||
++modCount;
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptDictionary::DeleteAll()
|
||||
{
|
||||
mapType::iterator it;
|
||||
for( it = dict.begin(); it != dict.end(); it++ )
|
||||
FreeValue(it->second);
|
||||
|
||||
dict.clear();
|
||||
}
|
||||
|
||||
void CScriptDictionary::DeleteNulls()
|
||||
{
|
||||
mapType::iterator it;
|
||||
for( it = dict.begin(); it != dict.end(); it++ )
|
||||
{
|
||||
if( it->second.typeId & asTYPEID_OBJHANDLE )
|
||||
if( it->second.valueObj == 0 )
|
||||
it = dict.erase(it);
|
||||
}
|
||||
++modCount;
|
||||
}
|
||||
|
||||
void CScriptDictionary::FreeValue(valueStruct &value)
|
||||
{
|
||||
// If it is a handle or a ref counted object, call release
|
||||
if( value.typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Let the engine release the object
|
||||
engine->ReleaseScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
|
||||
value.valueObj = 0;
|
||||
value.typeId = 0;
|
||||
}
|
||||
|
||||
// For primitives, there's nothing to do
|
||||
}
|
||||
|
||||
CScriptArray* CScriptDictionary::GetKeys() const
|
||||
{
|
||||
// TODO: optimize: The string array type should only be determined once.
|
||||
// It should be recomputed when registering the dictionary class.
|
||||
// Only problem is if multiple engines are used, as they may not
|
||||
// share the same type id. Alternatively it can be stored in the
|
||||
// user data for the dictionary type.
|
||||
int stringArrayType = engine->GetTypeIdByDecl("array<string>");
|
||||
asITypeInfo *ot = engine->GetTypeInfoById(stringArrayType);
|
||||
|
||||
// Create the array object
|
||||
CScriptArray *array = new CScriptArray(dict.size(), ot);
|
||||
long current = -1;
|
||||
mapType::const_iterator it;
|
||||
for( it = dict.begin(); it != dict.end(); it++ )
|
||||
{
|
||||
current++;
|
||||
*(string*)array->At(current) = it->first;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
CScriptDictionary::Iterator CScriptDictionary::GetIterator() const {
|
||||
return Iterator(this);
|
||||
}
|
||||
|
||||
void CScriptDictionary::Delete(CScriptDictionary::Iterator& it) {
|
||||
if( it.container != this ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Mismatched script container and iterator.");
|
||||
return;
|
||||
}
|
||||
|
||||
if( it.it == dict.end() ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Deleting invalid iterator.");
|
||||
return;
|
||||
}
|
||||
|
||||
it.it = dict.erase(it.it);
|
||||
it.first = true;
|
||||
++modCount;
|
||||
it.modCount = modCount;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Iterator implementation
|
||||
|
||||
static const std::string errorString = "(error)";
|
||||
|
||||
CScriptDictionary::Iterator::Iterator() {
|
||||
container = 0;
|
||||
}
|
||||
|
||||
CScriptDictionary::Iterator::Iterator(const CScriptDictionary *container) {
|
||||
this->container = container;
|
||||
|
||||
// Start the iteration
|
||||
it = container->dict.begin();
|
||||
first = true;
|
||||
|
||||
// Track the modification count of the dictionary
|
||||
// so we can safely fail when the dictionary is altered
|
||||
modCount = container->modCount;
|
||||
|
||||
// Keep a reference to the dictionary so it doesn't
|
||||
// get destroyed from under us
|
||||
container->AddRef();
|
||||
}
|
||||
|
||||
CScriptDictionary::Iterator::~Iterator() {
|
||||
// Release dictionary reference
|
||||
if(container)
|
||||
container->Release();
|
||||
}
|
||||
|
||||
static void DefaultConstructIterator(void *memory) {
|
||||
new(memory) CScriptDictionary::Iterator();
|
||||
}
|
||||
|
||||
static void ConstructIterator(void *memory, const CScriptDictionary *container) {
|
||||
new(memory) CScriptDictionary::Iterator(container);
|
||||
}
|
||||
|
||||
static void DestructIterator(CScriptDictionary::Iterator &it) {
|
||||
it.~Iterator();
|
||||
}
|
||||
|
||||
const std::string &CScriptDictionary::Iterator::GetKey() {
|
||||
if( !container || modCount != container->modCount || it == container->dict.end() ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Iterator not valid or dictionary changed.");
|
||||
|
||||
return errorString;
|
||||
}
|
||||
|
||||
return it->first;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::Iterator::Iterate(void *value, int typeId) {
|
||||
return Iterate(0, value, typeId);
|
||||
}
|
||||
|
||||
bool CScriptDictionary::Iterator::Iterate(string* key, void *value, int typeId) {
|
||||
if( !container ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Iterating on invalid iterator.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if( modCount != container->modCount ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Dictionary changed during iteration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if( it == container->dict.end() )
|
||||
return false;
|
||||
|
||||
if( first )
|
||||
first = false;
|
||||
else
|
||||
++it;
|
||||
|
||||
if( it == container->dict.end() )
|
||||
return false;
|
||||
|
||||
if( key )
|
||||
*key = it->first;
|
||||
|
||||
if( container->Iterator_GetValue(it, value, typeId) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The caller can check IsValid to see if the iteration can still
|
||||
// continue because the type was wrong, or whether it has really ended
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CScriptDictionary::Iterator::IsValid() {
|
||||
return container && modCount == container->modCount && it != container->dict.end();
|
||||
}
|
||||
|
||||
CScriptDictionary::Iterator &CScriptDictionary::Iterator::operator =(const CScriptDictionary::Iterator &other) {
|
||||
if(other.container)
|
||||
other.container->AddRef();
|
||||
if(container)
|
||||
container->Release();
|
||||
|
||||
modCount = other.modCount;
|
||||
container = other.container;
|
||||
it = other.it;
|
||||
first = other.first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Generic wrappers
|
||||
|
||||
void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
*(CScriptDictionary**)gen->GetAddressOfReturnLocation() = new CScriptDictionary(gen->GetEngine());
|
||||
}
|
||||
|
||||
void ScriptDictionaryAddRef_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
dict->AddRef();
|
||||
}
|
||||
|
||||
void ScriptDictionaryRelease_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
dict->Release();
|
||||
}
|
||||
|
||||
void ScriptDictionaryAssign_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
CScriptDictionary *other = *(CScriptDictionary**)gen->GetAddressOfArg(0);
|
||||
*dict = *other;
|
||||
*(CScriptDictionary**)gen->GetAddressOfReturnLocation() = dict;
|
||||
}
|
||||
|
||||
void ScriptDictionarySet_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
string *key = *(string**)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
int typeId = gen->GetArgTypeId(1);
|
||||
dict->Set(*key, ref, typeId);
|
||||
}
|
||||
|
||||
void ScriptDictionarySetInt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
string *key = *(string**)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
dict->Set(*key, *(asINT64*)ref);
|
||||
}
|
||||
|
||||
void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
string *key = *(string**)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
dict->Set(*key, *(double*)ref);
|
||||
}
|
||||
|
||||
void ScriptDictionaryGet_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
string *key = *(string**)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
int typeId = gen->GetArgTypeId(1);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId);
|
||||
}
|
||||
|
||||
void ScriptDictionaryGetInt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
string *key = *(string**)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref);
|
||||
}
|
||||
|
||||
void ScriptDictionaryGetFlt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
string *key = *(string**)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref);
|
||||
}
|
||||
|
||||
void ScriptDictionaryExists_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
string *key = *(string**)gen->GetAddressOfArg(0);
|
||||
bool ret = dict->Exists(*key);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = ret;
|
||||
}
|
||||
|
||||
void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
string *key = *(string**)gen->GetAddressOfArg(0);
|
||||
dict->Delete(*key);
|
||||
}
|
||||
|
||||
void ScriptDictionaryDeleteAll_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
|
||||
dict->DeleteAll();
|
||||
}
|
||||
|
||||
static void ScriptDictionaryGetRefCount_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
|
||||
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
|
||||
}
|
||||
|
||||
static void ScriptDictionarySetGCFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
|
||||
self->SetGCFlag();
|
||||
}
|
||||
|
||||
static void ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag();
|
||||
}
|
||||
|
||||
static void ScriptDictionaryEnumReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->EnumReferences(engine);
|
||||
}
|
||||
|
||||
static void ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->ReleaseAllReferences(engine);
|
||||
}
|
||||
|
||||
static void CScriptDictionaryGetKeys_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptDictionary *self = (CScriptDictionary*)gen->GetObject();
|
||||
*(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Register the type
|
||||
|
||||
void RegisterScriptDictionary(asIScriptEngine *engine)
|
||||
{
|
||||
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
|
||||
RegisterScriptDictionary_Generic(engine);
|
||||
else
|
||||
RegisterScriptDictionary_Native(engine);
|
||||
}
|
||||
|
||||
void RegisterScriptDictionary_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
//Register iterator type so we can use it later
|
||||
r = engine->RegisterObjectType("dictionary_iterator", sizeof(CScriptDictionary::Iterator), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
|
||||
// Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const string&,void*,int),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, int64&in)", asMETHODPR(CScriptDictionary,Set,(const string&,asINT64&),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, double&in)", asMETHODPR(CScriptDictionary,Set,(const string&,double&),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "void delete(const string &in)", asMETHODPR(CScriptDictionary, Delete, (const string&), void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "void delete(dictionary_iterator&)", asMETHODPR(CScriptDictionary, Delete, (CScriptDictionary::Iterator&), void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "void deleteNulls()", asMETHOD(CScriptDictionary,DeleteNulls), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "dictionary_iterator iterator()", asMETHOD(CScriptDictionary,GetIterator), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "array<string> @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
// Register GC behaviours
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
#if AS_USE_STLNAMES == 1
|
||||
// Same as isEmpty
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 );
|
||||
// Same as getSize
|
||||
r = engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 );
|
||||
// Same as delete
|
||||
r = engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 );
|
||||
// Same as deleteAll
|
||||
r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
|
||||
#endif
|
||||
|
||||
// Register iterator methods
|
||||
r = engine->RegisterObjectBehaviour("dictionary_iterator", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(DefaultConstructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary_iterator", asBEHAVE_CONSTRUCT, "void f(const dictionary &in)", asFUNCTION(ConstructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary_iterator", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary_iterator", "const string& get_key()", asMETHOD(CScriptDictionary::Iterator, GetKey), asCALL_THISCALL); assert( r>= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary_iterator", "bool iterate(?&out)", asMETHODPR(CScriptDictionary::Iterator, Iterate, (void*,int), bool), asCALL_THISCALL); assert( r>= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary_iterator", "bool iterate(string &out, ?&out)", asMETHODPR(CScriptDictionary::Iterator, Iterate, (string*,void*,int), bool), asCALL_THISCALL); assert( r>= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary_iterator", "bool get_valid()", asMETHOD(CScriptDictionary::Iterator, IsValid), asCALL_THISCALL); assert( r>= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary_iterator", "dictionary_iterator& opAssign(const dictionary_iterator &in)", asMETHOD(CScriptDictionary::Iterator, operator=), asCALL_THISCALL); assert( r>= 0 );
|
||||
}
|
||||
|
||||
void RegisterScriptDictionary_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "void delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "array<string> @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Register GC behaviours
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
#include "scripthandle.h"
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
static void Construct(CScriptHandle *self) { new(self) CScriptHandle(); }
|
||||
static void Construct(CScriptHandle *self, const CScriptHandle &o) { new(self) CScriptHandle(o); }
|
||||
// This one is not static because it needs to be friend with the CScriptHandle class
|
||||
void Construct(CScriptHandle *self, void *ref, int typeId) { new(self) CScriptHandle(ref, typeId); }
|
||||
static void Destruct(CScriptHandle *self) { self->~CScriptHandle(); }
|
||||
|
||||
CScriptHandle::CScriptHandle()
|
||||
{
|
||||
m_ref = 0;
|
||||
m_type = 0;
|
||||
}
|
||||
|
||||
CScriptHandle::CScriptHandle(const CScriptHandle &other)
|
||||
{
|
||||
m_ref = other.m_ref;
|
||||
m_type = other.m_type;
|
||||
|
||||
AddRefHandle();
|
||||
}
|
||||
|
||||
CScriptHandle::CScriptHandle(void *ref, asITypeInfo *type)
|
||||
{
|
||||
m_ref = ref;
|
||||
m_type = type;
|
||||
|
||||
AddRefHandle();
|
||||
}
|
||||
|
||||
// This constructor shouldn't be called from the application
|
||||
// directly as it requires an active script context
|
||||
CScriptHandle::CScriptHandle(void *ref, int typeId)
|
||||
{
|
||||
m_ref = 0;
|
||||
m_type = 0;
|
||||
|
||||
Assign(ref, typeId);
|
||||
}
|
||||
|
||||
CScriptHandle::~CScriptHandle()
|
||||
{
|
||||
ReleaseHandle();
|
||||
}
|
||||
|
||||
void CScriptHandle::ReleaseHandle()
|
||||
{
|
||||
if( m_ref && m_type )
|
||||
{
|
||||
asIScriptEngine *engine = m_type->GetEngine();
|
||||
engine->ReleaseScriptObject(m_ref, m_type);
|
||||
|
||||
engine->Release();
|
||||
|
||||
m_ref = 0;
|
||||
m_type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptHandle::AddRefHandle()
|
||||
{
|
||||
if( m_ref && m_type )
|
||||
{
|
||||
asIScriptEngine *engine = m_type->GetEngine();
|
||||
engine->AddRefScriptObject(m_ref, m_type);
|
||||
|
||||
// Hold on to the engine so it isn't destroyed while
|
||||
// a reference to a script object is still held
|
||||
engine->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
CScriptHandle &CScriptHandle::operator =(const CScriptHandle &other)
|
||||
{
|
||||
Set(other.m_ref, other.m_type);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CScriptHandle::Set(void *ref, asITypeInfo *type)
|
||||
{
|
||||
if( m_ref == ref ) return;
|
||||
|
||||
ReleaseHandle();
|
||||
|
||||
m_ref = ref;
|
||||
m_type = type;
|
||||
|
||||
AddRefHandle();
|
||||
}
|
||||
|
||||
void *CScriptHandle::GetRef()
|
||||
{
|
||||
return m_ref;
|
||||
}
|
||||
|
||||
asITypeInfo *CScriptHandle::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
int CScriptHandle::GetTypeId() const
|
||||
{
|
||||
if( m_type == 0 ) return 0;
|
||||
|
||||
return m_type->GetTypeId() | asTYPEID_OBJHANDLE;
|
||||
}
|
||||
|
||||
// This method shouldn't be called from the application
|
||||
// directly as it requires an active script context
|
||||
CScriptHandle &CScriptHandle::Assign(void *ref, int typeId)
|
||||
{
|
||||
// When receiving a null handle we just clear our memory
|
||||
if( typeId == 0 )
|
||||
{
|
||||
Set(0, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Dereference received handles to get the object
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// Store the actual reference
|
||||
ref = *(void**)ref;
|
||||
typeId &= ~asTYPEID_OBJHANDLE;
|
||||
}
|
||||
|
||||
// Get the object type
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
asIScriptEngine *engine = ctx->GetEngine();
|
||||
asITypeInfo *type = engine->GetTypeInfoById(typeId);
|
||||
|
||||
// If the argument is another CScriptHandle, we should copy the content instead
|
||||
if( type && strcmp(type->GetName(), "ref") == 0 )
|
||||
{
|
||||
CScriptHandle *r = (CScriptHandle*)ref;
|
||||
ref = r->m_ref;
|
||||
type = r->m_type;
|
||||
}
|
||||
|
||||
Set(ref, type);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CScriptHandle::operator==(const CScriptHandle &o) const
|
||||
{
|
||||
if( m_ref == o.m_ref &&
|
||||
m_type == o.m_type )
|
||||
return true;
|
||||
|
||||
// TODO: If type is not the same, we should attempt to do a dynamic cast,
|
||||
// which may change the pointer for application registered classes
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptHandle::operator!=(const CScriptHandle &o) const
|
||||
{
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
bool CScriptHandle::Equals(void *ref, int typeId) const
|
||||
{
|
||||
// Null handles are received as reference to a null handle
|
||||
if( typeId == 0 )
|
||||
ref = 0;
|
||||
|
||||
// Dereference handles to get the object
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// Compare the actual reference
|
||||
ref = *(void**)ref;
|
||||
typeId &= ~asTYPEID_OBJHANDLE;
|
||||
}
|
||||
|
||||
// TODO: If typeId is not the same, we should attempt to do a dynamic cast,
|
||||
// which may change the pointer for application registered classes
|
||||
|
||||
if( ref == m_ref ) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// AngelScript: used as '@obj = cast<obj>(ref);'
|
||||
void CScriptHandle::Cast(void **outRef, int typeId)
|
||||
{
|
||||
// If we hold a null handle, then just return null
|
||||
if( m_type == 0 )
|
||||
{
|
||||
*outRef = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// It is expected that the outRef is always a handle
|
||||
assert( typeId & asTYPEID_OBJHANDLE );
|
||||
|
||||
// Compare the type id of the actual object
|
||||
typeId &= ~asTYPEID_OBJHANDLE;
|
||||
asIScriptEngine *engine = m_type->GetEngine();
|
||||
asITypeInfo *type = engine->GetTypeInfoById(typeId);
|
||||
|
||||
*outRef = 0;
|
||||
|
||||
// RefCastObject will increment the refCount of the returned object if successful
|
||||
engine->RefCastObject(m_ref, m_type, type, outRef);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RegisterScriptHandle_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
#if AS_CAN_USE_CPP11
|
||||
// With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class
|
||||
r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asGetTypeTraits<CScriptHandle>()); assert( r >= 0 );
|
||||
#else
|
||||
r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
|
||||
#endif
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(Construct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTIONPR(Construct, (CScriptHandle *, const CScriptHandle &), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTIONPR(Construct, (CScriptHandle *, void *, int), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTIONPR(Destruct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asMETHODPR(CScriptHandle, Cast, (void **, int), void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asMETHOD(CScriptHandle, operator=), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
}
|
||||
|
||||
void CScriptHandle_Construct_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
new(self) CScriptHandle();
|
||||
}
|
||||
|
||||
void CScriptHandle_ConstructCopy_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
new(self) CScriptHandle(*other);
|
||||
}
|
||||
|
||||
void CScriptHandle_ConstructVar_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void *ref = gen->GetArgAddress(0);
|
||||
int typeId = gen->GetArgTypeId(0);
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
Construct(self, ref, typeId);
|
||||
}
|
||||
|
||||
void CScriptHandle_Destruct_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
self->~CScriptHandle();
|
||||
}
|
||||
|
||||
void CScriptHandle_Cast_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void **ref = reinterpret_cast<void**>(gen->GetArgAddress(0));
|
||||
int typeId = gen->GetArgTypeId(0);
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
self->Cast(ref, typeId);
|
||||
}
|
||||
|
||||
void CScriptHandle_Assign_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
*self = *other;
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void *ref = gen->GetArgAddress(0);
|
||||
int typeId = gen->GetArgTypeId(0);
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
self->Assign(ref, typeId);
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
void CScriptHandle_Equals_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
gen->SetReturnByte(*self == *other);
|
||||
}
|
||||
|
||||
void CScriptHandle_EqualsVar_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
void *ref = gen->GetArgAddress(0);
|
||||
int typeId = gen->GetArgTypeId(0);
|
||||
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
|
||||
gen->SetReturnByte(self->Equals(ref, typeId));
|
||||
}
|
||||
|
||||
void RegisterScriptHandle_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptHandle_Construct_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTION(CScriptHandle_ConstructCopy_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTION(CScriptHandle_ConstructVar_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptHandle_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
}
|
||||
|
||||
void RegisterScriptHandle(asIScriptEngine *engine)
|
||||
{
|
||||
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
|
||||
RegisterScriptHandle_Generic(engine);
|
||||
else
|
||||
RegisterScriptHandle_Native(engine);
|
||||
}
|
||||
|
||||
|
||||
END_AS_NAMESPACE
|
||||
@@ -0,0 +1,937 @@
|
||||
#include <string.h>
|
||||
#include "scripthelper.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result)
|
||||
{
|
||||
// TODO: If a lot of script objects are going to be compared, e.g. when sorting an array,
|
||||
// then the method id and context should be cached between calls.
|
||||
|
||||
int retval = -1;
|
||||
asIScriptFunction *func = 0;
|
||||
|
||||
asITypeInfo *ti = engine->GetTypeInfoById(typeId);
|
||||
if( ti )
|
||||
{
|
||||
// Check if the object type has a compatible opCmp method
|
||||
for( asUINT n = 0; n < ti->GetMethodCount(); n++ )
|
||||
{
|
||||
asIScriptFunction *f = ti->GetMethodByIndex(n);
|
||||
asDWORD flags;
|
||||
if( strcmp(f->GetName(), "opCmp") == 0 &&
|
||||
f->GetReturnTypeId(&flags) == asTYPEID_INT32 &&
|
||||
flags == asTM_NONE &&
|
||||
f->GetParamCount() == 1 )
|
||||
{
|
||||
int paramTypeId;
|
||||
f->GetParam(0, ¶mTypeId, &flags);
|
||||
|
||||
// The parameter must be an input reference of the same type
|
||||
// If the reference is a inout reference, then it must also be read-only
|
||||
if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) )
|
||||
break;
|
||||
|
||||
// Found the method
|
||||
func = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( func )
|
||||
{
|
||||
// Call the method
|
||||
asIScriptContext *ctx = engine->CreateContext();
|
||||
ctx->Prepare(func);
|
||||
ctx->SetObject(lobj);
|
||||
ctx->SetArgAddress(0, robj);
|
||||
int r = ctx->Execute();
|
||||
if( r == asEXECUTION_FINISHED )
|
||||
{
|
||||
result = (int)ctx->GetReturnDWord();
|
||||
|
||||
// The comparison was successful
|
||||
retval = 0;
|
||||
}
|
||||
ctx->Release();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result)
|
||||
{
|
||||
// TODO: If a lot of script objects are going to be compared, e.g. when searching for an
|
||||
// entry in a set, then the method and context should be cached between calls.
|
||||
|
||||
int retval = -1;
|
||||
asIScriptFunction *func = 0;
|
||||
|
||||
asITypeInfo *ti = engine->GetTypeInfoById(typeId);
|
||||
if( ti )
|
||||
{
|
||||
// Check if the object type has a compatible opEquals method
|
||||
for( asUINT n = 0; n < ti->GetMethodCount(); n++ )
|
||||
{
|
||||
asIScriptFunction *f = ti->GetMethodByIndex(n);
|
||||
asDWORD flags;
|
||||
if( strcmp(f->GetName(), "opEquals") == 0 &&
|
||||
f->GetReturnTypeId(&flags) == asTYPEID_BOOL &&
|
||||
flags == asTM_NONE &&
|
||||
f->GetParamCount() == 1 )
|
||||
{
|
||||
int paramTypeId;
|
||||
f->GetParam(0, ¶mTypeId, &flags);
|
||||
|
||||
// The parameter must be an input reference of the same type
|
||||
// If the reference is a inout reference, then it must also be read-only
|
||||
if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) )
|
||||
break;
|
||||
|
||||
// Found the method
|
||||
func = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( func )
|
||||
{
|
||||
// Call the method
|
||||
asIScriptContext *ctx = engine->CreateContext();
|
||||
ctx->Prepare(func);
|
||||
ctx->SetObject(lobj);
|
||||
ctx->SetArgAddress(0, robj);
|
||||
int r = ctx->Execute();
|
||||
if( r == asEXECUTION_FINISHED )
|
||||
{
|
||||
result = ctx->GetReturnByte() ? true : false;
|
||||
|
||||
// The comparison was successful
|
||||
retval = 0;
|
||||
}
|
||||
ctx->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the opEquals method doesn't exist, then we try with opCmp instead
|
||||
int relation;
|
||||
retval = CompareRelation(engine, lobj, robj, typeId, relation);
|
||||
if( retval >= 0 )
|
||||
result = relation == 0 ? true : false;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod, asIScriptContext *ctx)
|
||||
{
|
||||
return ExecuteString(engine, code, 0, asTYPEID_VOID, mod, ctx);
|
||||
}
|
||||
|
||||
int ExecuteString(asIScriptEngine *engine, const char *code, void *ref, int refTypeId, asIScriptModule *mod, asIScriptContext *ctx)
|
||||
{
|
||||
// Wrap the code in a function so that it can be compiled and executed
|
||||
string funcCode = " ExecuteString() {\n";
|
||||
funcCode += code;
|
||||
funcCode += "\n;}";
|
||||
|
||||
// Determine the return type based on the type of the ref arg
|
||||
funcCode = engine->GetTypeDeclaration(refTypeId, true) + funcCode;
|
||||
|
||||
// GetModule will free unused types, so to be on the safe side we'll hold on to a reference to the type
|
||||
asITypeInfo *type = 0;
|
||||
if( refTypeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
type = engine->GetTypeInfoById(refTypeId);
|
||||
if( type )
|
||||
type->AddRef();
|
||||
}
|
||||
|
||||
// If no module was provided, get a dummy from the engine
|
||||
asIScriptModule *execMod = mod ? mod : engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE);
|
||||
|
||||
// Now it's ok to release the type
|
||||
if( type )
|
||||
type->Release();
|
||||
|
||||
// Compile the function that can be executed
|
||||
asIScriptFunction *func = 0;
|
||||
int r = execMod->CompileFunction("ExecuteString", funcCode.c_str(), -1, 0, &func);
|
||||
if( r < 0 )
|
||||
return r;
|
||||
|
||||
// If no context was provided, request a new one from the engine
|
||||
asIScriptContext *execCtx = ctx ? ctx : engine->RequestContext();
|
||||
r = execCtx->Prepare(func);
|
||||
if( r < 0 )
|
||||
{
|
||||
func->Release();
|
||||
if( !ctx ) execCtx->Release();
|
||||
return r;
|
||||
}
|
||||
|
||||
// Execute the function
|
||||
r = execCtx->Execute();
|
||||
|
||||
// Unless the provided type was void retrieve it's value
|
||||
if( ref != 0 && refTypeId != asTYPEID_VOID )
|
||||
{
|
||||
if( refTypeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// Expect the pointer to be null to start with
|
||||
assert( *reinterpret_cast<void**>(ref) == 0 );
|
||||
*reinterpret_cast<void**>(ref) = *reinterpret_cast<void**>(execCtx->GetAddressOfReturnValue());
|
||||
engine->AddRefScriptObject(*reinterpret_cast<void**>(ref), engine->GetTypeInfoById(refTypeId));
|
||||
}
|
||||
else if( refTypeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Expect the pointer to point to a valid object
|
||||
assert( *reinterpret_cast<void**>(ref) != 0 );
|
||||
engine->AssignScriptObject(ref, execCtx->GetAddressOfReturnValue(), engine->GetTypeInfoById(refTypeId));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the primitive value
|
||||
memcpy(ref, execCtx->GetAddressOfReturnValue(), engine->GetSizeOfPrimitiveType(refTypeId));
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
func->Release();
|
||||
if( !ctx ) engine->ReturnContext(execCtx);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int WriteConfigToFile(asIScriptEngine *engine, const char *filename)
|
||||
{
|
||||
ofstream strm;
|
||||
strm.open(filename);
|
||||
|
||||
return WriteConfigToStream(engine, strm);
|
||||
}
|
||||
|
||||
int WriteConfigToStream(asIScriptEngine *engine, ostream &strm)
|
||||
{
|
||||
// A helper function for escaping quotes in default arguments
|
||||
struct Escape
|
||||
{
|
||||
static string Quotes(const char *decl)
|
||||
{
|
||||
string str = decl;
|
||||
size_t pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
// Find " characters
|
||||
pos = str.find("\"",pos);
|
||||
if( pos == string::npos )
|
||||
break;
|
||||
|
||||
// Add a \ to escape them
|
||||
str.insert(pos, "\\");
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
int c, n;
|
||||
|
||||
asDWORD currAccessMask = 0;
|
||||
string currNamespace = "";
|
||||
engine->SetDefaultNamespace(currNamespace.c_str());
|
||||
|
||||
// Export the engine version, just for info
|
||||
strm << "// AngelScript " << asGetLibraryVersion() << "\n";
|
||||
strm << "// Lib options " << asGetLibraryOptions() << "\n";
|
||||
|
||||
// Export the relevant engine properties
|
||||
strm << "// Engine properties\n";
|
||||
for( n = 0; n < asEP_LAST_PROPERTY; n++ )
|
||||
strm << "ep " << n << " " << engine->GetEngineProperty(asEEngineProp(n)) << "\n";
|
||||
|
||||
// Make sure the default array type is expanded to the template form
|
||||
bool expandDefArrayToTempl = engine->GetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL) ? true : false;
|
||||
engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true);
|
||||
|
||||
// Write enum types and their values
|
||||
strm << "\n// Enums\n";
|
||||
c = engine->GetEnumCount();
|
||||
for( n = 0; n < c; n++ )
|
||||
{
|
||||
asITypeInfo *ti = engine->GetEnumByIndex(n);
|
||||
asDWORD accessMask = ti->GetAccessMask();
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
const char *nameSpace = ti->GetNamespace();
|
||||
if( nameSpace != currNamespace )
|
||||
{
|
||||
strm << "namespace \"" << nameSpace << "\"\n";
|
||||
currNamespace = nameSpace;
|
||||
engine->SetDefaultNamespace(currNamespace.c_str());
|
||||
}
|
||||
const char *enumName = ti->GetName();
|
||||
strm << "enum " << enumName << "\n";
|
||||
for( asUINT m = 0; m < ti->GetEnumValueCount(); m++ )
|
||||
{
|
||||
const char *valName;
|
||||
int val;
|
||||
valName = ti->GetEnumValueByIndex(m, &val);
|
||||
strm << "enumval " << enumName << " " << valName << " " << val << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Enumerate all types
|
||||
strm << "\n// Types\n";
|
||||
|
||||
// Keep a list of the template types, as the methods for these need to be exported first
|
||||
set<asITypeInfo*> templateTypes;
|
||||
|
||||
c = engine->GetObjectTypeCount();
|
||||
for( n = 0; n < c; n++ )
|
||||
{
|
||||
asITypeInfo *type = engine->GetObjectTypeByIndex(n);
|
||||
asDWORD accessMask = type->GetAccessMask();
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
const char *nameSpace = type->GetNamespace();
|
||||
if( nameSpace != currNamespace )
|
||||
{
|
||||
strm << "namespace \"" << nameSpace << "\"\n";
|
||||
currNamespace = nameSpace;
|
||||
engine->SetDefaultNamespace(currNamespace.c_str());
|
||||
}
|
||||
if( type->GetFlags() & asOBJ_SCRIPT_OBJECT )
|
||||
{
|
||||
// This should only be interfaces
|
||||
assert( type->GetSize() == 0 );
|
||||
|
||||
strm << "intf " << type->GetName() << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only the type flags are necessary. The application flags are application
|
||||
// specific and doesn't matter to the offline compiler. The object size is also
|
||||
// unnecessary for the offline compiler
|
||||
strm << "objtype \"" << engine->GetTypeDeclaration(type->GetTypeId()) << "\" " << (unsigned int)(type->GetFlags() & asOBJ_MASK_VALID_FLAGS) << "\n";
|
||||
|
||||
// Store the template types (but not template instances)
|
||||
if( (type->GetFlags() & asOBJ_TEMPLATE) && type->GetSubType() && (type->GetSubType()->GetFlags() & asOBJ_TEMPLATE_SUBTYPE) )
|
||||
templateTypes.insert(type);
|
||||
}
|
||||
}
|
||||
|
||||
c = engine->GetTypedefCount();
|
||||
for( n = 0; n < c; n++ )
|
||||
{
|
||||
asITypeInfo *ti = engine->GetTypedefByIndex(n);
|
||||
const char *nameSpace = ti->GetNamespace();
|
||||
if( nameSpace != currNamespace )
|
||||
{
|
||||
strm << "namespace \"" << nameSpace << "\"\n";
|
||||
currNamespace = nameSpace;
|
||||
engine->SetDefaultNamespace(currNamespace.c_str());
|
||||
}
|
||||
asDWORD accessMask = ti->GetAccessMask();
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
strm << "typedef " << ti->GetName() << " \"" << engine->GetTypeDeclaration(ti->GetTypedefTypeId()) << "\"\n";
|
||||
}
|
||||
|
||||
c = engine->GetFuncdefCount();
|
||||
for( n = 0; n < c; n++ )
|
||||
{
|
||||
asITypeInfo *funcDef = engine->GetFuncdefByIndex(n);
|
||||
asDWORD accessMask = funcDef->GetAccessMask();
|
||||
const char *nameSpace = funcDef->GetNamespace();
|
||||
// Child funcdefs do not have any namespace, as they belong to the parent object
|
||||
if( nameSpace && nameSpace != currNamespace )
|
||||
{
|
||||
strm << "namespace \"" << nameSpace << "\"\n";
|
||||
currNamespace = nameSpace;
|
||||
engine->SetDefaultNamespace(currNamespace.c_str());
|
||||
}
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
strm << "funcdef \"" << funcDef->GetFuncdefSignature()->GetDeclaration() << "\"\n";
|
||||
}
|
||||
|
||||
// A helper for writing object type members
|
||||
struct TypeWriter
|
||||
{
|
||||
static void Write(asIScriptEngine *engine, ostream &strm, asITypeInfo *type, string &currNamespace, asDWORD &currAccessMask)
|
||||
{
|
||||
const char *nameSpace = type->GetNamespace();
|
||||
if( nameSpace != currNamespace )
|
||||
{
|
||||
strm << "namespace \"" << nameSpace << "\"\n";
|
||||
currNamespace = nameSpace;
|
||||
engine->SetDefaultNamespace(currNamespace.c_str());
|
||||
}
|
||||
string typeDecl = engine->GetTypeDeclaration(type->GetTypeId());
|
||||
if( type->GetFlags() & asOBJ_SCRIPT_OBJECT )
|
||||
{
|
||||
for( asUINT m = 0; m < type->GetMethodCount(); m++ )
|
||||
{
|
||||
asIScriptFunction *func = type->GetMethodByIndex(m);
|
||||
asDWORD accessMask = func->GetAccessMask();
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
strm << "intfmthd " << typeDecl.c_str() << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asUINT m;
|
||||
for( m = 0; m < type->GetFactoryCount(); m++ )
|
||||
{
|
||||
asIScriptFunction *func = type->GetFactoryByIndex(m);
|
||||
asDWORD accessMask = func->GetAccessMask();
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
strm << "objbeh \"" << typeDecl.c_str() << "\" " << asBEHAVE_FACTORY << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n";
|
||||
}
|
||||
for( m = 0; m < type->GetBehaviourCount(); m++ )
|
||||
{
|
||||
asEBehaviours beh;
|
||||
asIScriptFunction *func = type->GetBehaviourByIndex(m, &beh);
|
||||
|
||||
if( beh == asBEHAVE_CONSTRUCT )
|
||||
// Prefix 'void'
|
||||
strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n";
|
||||
else if( beh == asBEHAVE_DESTRUCT )
|
||||
// Prefix 'void' and remove ~
|
||||
strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str()+1 << "\"\n";
|
||||
else
|
||||
strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n";
|
||||
}
|
||||
for( m = 0; m < type->GetMethodCount(); m++ )
|
||||
{
|
||||
asIScriptFunction *func = type->GetMethodByIndex(m);
|
||||
asDWORD accessMask = func->GetAccessMask();
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
strm << "objmthd \"" << typeDecl.c_str() << "\" \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n";
|
||||
}
|
||||
for( m = 0; m < type->GetPropertyCount(); m++ )
|
||||
{
|
||||
asDWORD accessMask;
|
||||
type->GetProperty(m, 0, 0, 0, 0, 0, 0, &accessMask);
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
strm << "objprop \"" << typeDecl.c_str() << "\" \"" << type->GetPropertyDeclaration(m) << "\"\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Write the members of the template types, so they can be fully registered before any other type uses them
|
||||
// TODO: Order the template types based on dependency to avoid failure if one type uses instances of another
|
||||
strm << "\n// Template type members\n";
|
||||
for( set<asITypeInfo*>::iterator it = templateTypes.begin(); it != templateTypes.end(); ++it )
|
||||
{
|
||||
asITypeInfo *type = *it;
|
||||
TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask);
|
||||
}
|
||||
|
||||
// Write the object types members
|
||||
strm << "\n// Type members\n";
|
||||
|
||||
c = engine->GetObjectTypeCount();
|
||||
for( n = 0; n < c; n++ )
|
||||
{
|
||||
asITypeInfo *type = engine->GetObjectTypeByIndex(n);
|
||||
if( templateTypes.find(type) == templateTypes.end() )
|
||||
TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask);
|
||||
}
|
||||
|
||||
// Write functions
|
||||
strm << "\n// Functions\n";
|
||||
|
||||
c = engine->GetGlobalFunctionCount();
|
||||
for( n = 0; n < c; n++ )
|
||||
{
|
||||
asIScriptFunction *func = engine->GetGlobalFunctionByIndex(n);
|
||||
const char *nameSpace = func->GetNamespace();
|
||||
if( nameSpace != currNamespace )
|
||||
{
|
||||
strm << "namespace \"" << nameSpace << "\"\n";
|
||||
currNamespace = nameSpace;
|
||||
engine->SetDefaultNamespace(currNamespace.c_str());
|
||||
}
|
||||
asDWORD accessMask = func->GetAccessMask();
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
strm << "func \"" << Escape::Quotes(func->GetDeclaration()).c_str() << "\"\n";
|
||||
}
|
||||
|
||||
// Write global properties
|
||||
strm << "\n// Properties\n";
|
||||
|
||||
c = engine->GetGlobalPropertyCount();
|
||||
for( n = 0; n < c; n++ )
|
||||
{
|
||||
const char *name;
|
||||
int typeId;
|
||||
bool isConst;
|
||||
asDWORD accessMask;
|
||||
const char *nameSpace;
|
||||
engine->GetGlobalPropertyByIndex(n, &name, &nameSpace, &typeId, &isConst, 0, 0, &accessMask);
|
||||
if( accessMask != currAccessMask )
|
||||
{
|
||||
strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n";
|
||||
currAccessMask = accessMask;
|
||||
}
|
||||
if( nameSpace != currNamespace )
|
||||
{
|
||||
strm << "namespace \"" << nameSpace << "\"\n";
|
||||
currNamespace = nameSpace;
|
||||
engine->SetDefaultNamespace(currNamespace.c_str());
|
||||
}
|
||||
strm << "prop \"" << (isConst ? "const " : "") << engine->GetTypeDeclaration(typeId) << " " << name << "\"\n";
|
||||
}
|
||||
|
||||
engine->SetDefaultNamespace("");
|
||||
|
||||
// Write string factory
|
||||
strm << "\n// String factory\n";
|
||||
asDWORD flags = 0;
|
||||
int typeId = engine->GetStringFactoryReturnTypeId(&flags);
|
||||
if( typeId > 0 )
|
||||
strm << "strfactory \"" << ((flags & asTM_CONST) ? "const " : "") << engine->GetTypeDeclaration(typeId) << ((flags & asTM_INOUTREF) ? "&" : "") << "\"\n";
|
||||
|
||||
// Write default array type
|
||||
strm << "\n// Default array type\n";
|
||||
typeId = engine->GetDefaultArrayTypeId();
|
||||
if( typeId > 0 )
|
||||
strm << "defarray \"" << engine->GetTypeDeclaration(typeId) << "\"\n";
|
||||
|
||||
// Restore original settings
|
||||
engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, expandDefArrayToTempl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ConfigEngineFromStream(asIScriptEngine *engine, istream &strm, const char *configFile)
|
||||
{
|
||||
int r;
|
||||
|
||||
// Some helper functions for parsing the configuration
|
||||
struct in
|
||||
{
|
||||
static asETokenClass GetToken(asIScriptEngine *engine, string &token, const string &text, asUINT &pos)
|
||||
{
|
||||
asUINT len = 0;
|
||||
asETokenClass t = engine->ParseToken(&text[pos], text.length() - pos, &len);
|
||||
while( (t == asTC_WHITESPACE || t == asTC_COMMENT) && pos < text.length() )
|
||||
{
|
||||
pos += len;
|
||||
t = engine->ParseToken(&text[pos], text.length() - pos, &len);
|
||||
}
|
||||
|
||||
token.assign(&text[pos], len);
|
||||
|
||||
pos += len;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void ReplaceSlashQuote(string &str)
|
||||
{
|
||||
size_t pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
// Search for \" in the string
|
||||
pos = str.find("\\\"", pos);
|
||||
if( pos == string::npos )
|
||||
break;
|
||||
|
||||
// Remove the \ character
|
||||
str.erase(pos, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static asUINT GetLineNumber(const string &text, asUINT pos)
|
||||
{
|
||||
asUINT count = 1;
|
||||
for( asUINT n = 0; n < pos; n++ )
|
||||
if( text[n] == '\n' )
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
// Since we are only going to compile the script and never actually execute it,
|
||||
// we turn off the initialization of global variables, so that the compiler can
|
||||
// just register dummy types and functions for the application interface.
|
||||
r = engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false); assert( r >= 0 );
|
||||
|
||||
// Read the entire file
|
||||
char buffer[1000];
|
||||
string config;
|
||||
do {
|
||||
strm.getline(buffer, 1000);
|
||||
config += buffer;
|
||||
config += "\n";
|
||||
} while( !strm.eof() );
|
||||
|
||||
// Process the configuration file and register each entity
|
||||
asUINT pos = 0;
|
||||
while( pos < config.length() )
|
||||
{
|
||||
string token;
|
||||
// TODO: The position where the initial token is found should be stored for error messages
|
||||
in::GetToken(engine, token, config, pos);
|
||||
if( token == "ep" )
|
||||
{
|
||||
string tmp;
|
||||
in::GetToken(engine, tmp, config, pos);
|
||||
|
||||
asEEngineProp ep = asEEngineProp(atol(tmp.c_str()));
|
||||
|
||||
// Only set properties that affect the compiler
|
||||
if( ep != asEP_COPY_SCRIPT_SECTIONS &&
|
||||
ep != asEP_MAX_STACK_SIZE &&
|
||||
ep != asEP_INIT_GLOBAL_VARS_AFTER_BUILD &&
|
||||
ep != asEP_EXPAND_DEF_ARRAY_TO_TMPL &&
|
||||
ep != asEP_AUTO_GARBAGE_COLLECT )
|
||||
{
|
||||
// Get the value for the property
|
||||
in::GetToken(engine, tmp, config, pos);
|
||||
stringstream s(tmp);
|
||||
asPWORD value;
|
||||
|
||||
s >> value;
|
||||
|
||||
engine->SetEngineProperty(ep, value);
|
||||
}
|
||||
}
|
||||
else if( token == "namespace" )
|
||||
{
|
||||
string ns;
|
||||
in::GetToken(engine, ns, config, pos);
|
||||
ns = ns.substr(1, ns.length() - 2);
|
||||
|
||||
r = engine->SetDefaultNamespace(ns.c_str());
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to set namespace");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "access" )
|
||||
{
|
||||
string maskStr;
|
||||
in::GetToken(engine, maskStr, config, pos);
|
||||
asDWORD mask = strtoul(maskStr.c_str(), 0, 16);
|
||||
engine->SetDefaultAccessMask(mask);
|
||||
}
|
||||
else if( token == "objtype" )
|
||||
{
|
||||
string name, flags;
|
||||
in::GetToken(engine, name, config, pos);
|
||||
name = name.substr(1, name.length() - 2);
|
||||
in::GetToken(engine, flags, config, pos);
|
||||
|
||||
// The size of the value type doesn't matter, because the
|
||||
// engine must adjust it anyway for different platforms
|
||||
r = engine->RegisterObjectType(name.c_str(), (atol(flags.c_str()) & asOBJ_VALUE) ? 1 : 0, atol(flags.c_str()));
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object type");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "objbeh" )
|
||||
{
|
||||
string name, behaviour, decl;
|
||||
in::GetToken(engine, name, config, pos);
|
||||
name = name.substr(1, name.length() - 2);
|
||||
in::GetToken(engine, behaviour, config, pos);
|
||||
in::GetToken(engine, decl, config, pos);
|
||||
decl = decl.substr(1, decl.length() - 2);
|
||||
in::ReplaceSlashQuote(decl);
|
||||
|
||||
// Remove the $ that the engine prefixes the behaviours with
|
||||
size_t n = decl.find("$");
|
||||
if( n != string::npos )
|
||||
decl[n] = ' ';
|
||||
|
||||
asEBehaviours behave = static_cast<asEBehaviours>(atol(behaviour.c_str()));
|
||||
if( behave == asBEHAVE_TEMPLATE_CALLBACK )
|
||||
{
|
||||
// TODO: How can we let the compiler register this? Maybe through a plug-in system? Or maybe by implementing the callback as a script itself
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register template callback without the actual implementation");
|
||||
}
|
||||
else
|
||||
{
|
||||
r = engine->RegisterObjectBehaviour(name.c_str(), behave, decl.c_str(), asFUNCTION(0), asCALL_GENERIC);
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register behaviour");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( token == "objmthd" )
|
||||
{
|
||||
string name, decl;
|
||||
in::GetToken(engine, name, config, pos);
|
||||
name = name.substr(1, name.length() - 2);
|
||||
in::GetToken(engine, decl, config, pos);
|
||||
decl = decl.substr(1, decl.length() - 2);
|
||||
in::ReplaceSlashQuote(decl);
|
||||
|
||||
r = engine->RegisterObjectMethod(name.c_str(), decl.c_str(), asFUNCTION(0), asCALL_GENERIC);
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object method");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "objprop" )
|
||||
{
|
||||
string name, decl;
|
||||
in::GetToken(engine, name, config, pos);
|
||||
name = name.substr(1, name.length() - 2);
|
||||
in::GetToken(engine, decl, config, pos);
|
||||
decl = decl.substr(1, decl.length() - 2);
|
||||
|
||||
asITypeInfo *type = engine->GetTypeInfoById(engine->GetTypeIdByDecl(name.c_str()));
|
||||
if( type == 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Type doesn't exist for property registration");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// All properties must have different offsets in order to make them
|
||||
// distinct, so we simply register them with an incremental offset
|
||||
r = engine->RegisterObjectProperty(name.c_str(), decl.c_str(), type->GetPropertyCount());
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object property");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "intf" )
|
||||
{
|
||||
string name, size, flags;
|
||||
in::GetToken(engine, name, config, pos);
|
||||
|
||||
r = engine->RegisterInterface(name.c_str());
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "intfmthd" )
|
||||
{
|
||||
string name, decl;
|
||||
in::GetToken(engine, name, config, pos);
|
||||
in::GetToken(engine, decl, config, pos);
|
||||
decl = decl.substr(1, decl.length() - 2);
|
||||
in::ReplaceSlashQuote(decl);
|
||||
|
||||
r = engine->RegisterInterfaceMethod(name.c_str(), decl.c_str());
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface method");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "func" )
|
||||
{
|
||||
string decl;
|
||||
in::GetToken(engine, decl, config, pos);
|
||||
decl = decl.substr(1, decl.length() - 2);
|
||||
in::ReplaceSlashQuote(decl);
|
||||
|
||||
r = engine->RegisterGlobalFunction(decl.c_str(), asFUNCTION(0), asCALL_GENERIC);
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global function");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "prop" )
|
||||
{
|
||||
string decl;
|
||||
in::GetToken(engine, decl, config, pos);
|
||||
decl = decl.substr(1, decl.length() - 2);
|
||||
|
||||
// All properties must have different offsets in order to make them
|
||||
// distinct, so we simply register them with an incremental offset.
|
||||
// The pointer must also be non-null so we add 1 to have a value.
|
||||
r = engine->RegisterGlobalProperty(decl.c_str(), reinterpret_cast<void*>(asPWORD(engine->GetGlobalPropertyCount()+1)));
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global property");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "strfactory" )
|
||||
{
|
||||
string type;
|
||||
in::GetToken(engine, type, config, pos);
|
||||
type = type.substr(1, type.length() - 2);
|
||||
|
||||
r = engine->RegisterStringFactory(type.c_str(), asFUNCTION(0), asCALL_GENERIC);
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register string factory");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "defarray" )
|
||||
{
|
||||
string type;
|
||||
in::GetToken(engine, type, config, pos);
|
||||
type = type.substr(1, type.length() - 2);
|
||||
|
||||
r = engine->RegisterDefaultArrayType(type.c_str());
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register the default array type");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "enum" )
|
||||
{
|
||||
string type;
|
||||
in::GetToken(engine, type, config, pos);
|
||||
|
||||
r = engine->RegisterEnum(type.c_str());
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum type");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "enumval" )
|
||||
{
|
||||
string type, name, value;
|
||||
in::GetToken(engine, type, config, pos);
|
||||
in::GetToken(engine, name, config, pos);
|
||||
in::GetToken(engine, value, config, pos);
|
||||
|
||||
r = engine->RegisterEnumValue(type.c_str(), name.c_str(), atol(value.c_str()));
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum value");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "typedef" )
|
||||
{
|
||||
string type, decl;
|
||||
in::GetToken(engine, type, config, pos);
|
||||
in::GetToken(engine, decl, config, pos);
|
||||
decl = decl.substr(1, decl.length() - 2);
|
||||
|
||||
r = engine->RegisterTypedef(type.c_str(), decl.c_str());
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register typedef");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( token == "funcdef" )
|
||||
{
|
||||
string decl;
|
||||
in::GetToken(engine, decl, config, pos);
|
||||
decl = decl.substr(1, decl.length() - 2);
|
||||
|
||||
r = engine->RegisterFuncdef(decl.c_str());
|
||||
if( r < 0 )
|
||||
{
|
||||
engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register funcdef");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string GetExceptionInfo(asIScriptContext *ctx, bool showStack)
|
||||
{
|
||||
if( ctx->GetState() != asEXECUTION_EXCEPTION ) return "";
|
||||
|
||||
stringstream text;
|
||||
|
||||
const asIScriptFunction *function = ctx->GetExceptionFunction();
|
||||
text << "func: " << function->GetDeclaration() << "\n";
|
||||
text << "modl: " << function->GetModuleName() << "\n";
|
||||
text << "sect: " << function->GetScriptSectionName() << "\n";
|
||||
text << "line: " << ctx->GetExceptionLineNumber() << "\n";
|
||||
text << "desc: " << ctx->GetExceptionString() << "\n";
|
||||
|
||||
if( showStack )
|
||||
{
|
||||
text << "--- call stack ---\n";
|
||||
for( asUINT n = 1; n < ctx->GetCallstackSize(); n++ )
|
||||
{
|
||||
function = ctx->GetFunction(n);
|
||||
if( function )
|
||||
{
|
||||
if( function->GetFuncType() == asFUNC_SCRIPT )
|
||||
{
|
||||
text << function->GetScriptSectionName() << " (" << ctx->GetLineNumber(n) << "): " << function->GetDeclaration() << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
// The context is being reused by the application for a nested call
|
||||
text << "{...application...}: " << function->GetDeclaration() << "\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The context is being reused by the script engine for a nested call
|
||||
text << "{...script engine...}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return text.str();
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
@@ -0,0 +1,743 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "scriptmap.h"
|
||||
#include "scriptarray.h"
|
||||
|
||||
#include "../source/as_scriptengine.h"
|
||||
#include "../source/as_scriptobject.h"
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern bool IsHandleCompatibleWithObject(asCScriptEngine* engine, void *obj, int objTypeId, int handleTypeId);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// CScriptMap implementation
|
||||
|
||||
CScriptMap::CScriptMap(asIScriptEngine *engine)
|
||||
{
|
||||
// We start with one reference
|
||||
refCount.set(1);
|
||||
gcFlag = false;
|
||||
|
||||
// Start at the zeroth modification
|
||||
modCount = 0;
|
||||
|
||||
// Keep a reference to the engine for as long as we live
|
||||
// We don't increment the reference counter, because the
|
||||
// engine will hold a pointer to the object.
|
||||
this->engine = engine;
|
||||
|
||||
// Notify the garbage collector of this object
|
||||
// TODO: The type id should be cached
|
||||
engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("map"));
|
||||
}
|
||||
|
||||
CScriptMap::~CScriptMap()
|
||||
{
|
||||
// Delete all keys and values
|
||||
DeleteAll();
|
||||
}
|
||||
|
||||
void CScriptMap::AddRef() const
|
||||
{
|
||||
// We need to clear the GC flag
|
||||
gcFlag = false;
|
||||
refCount.atomicInc();
|
||||
}
|
||||
|
||||
void CScriptMap::Release() const
|
||||
{
|
||||
// We need to clear the GC flag
|
||||
gcFlag = false;
|
||||
if( refCount.atomicDec() == 0 )
|
||||
delete this;
|
||||
}
|
||||
|
||||
int CScriptMap::GetRefCount()
|
||||
{
|
||||
return refCount.get();
|
||||
}
|
||||
|
||||
void CScriptMap::SetGCFlag()
|
||||
{
|
||||
gcFlag = true;
|
||||
}
|
||||
|
||||
bool CScriptMap::GetGCFlag()
|
||||
{
|
||||
return gcFlag;
|
||||
}
|
||||
|
||||
void CScriptMap::EnumReferences(asIScriptEngine *engine)
|
||||
{
|
||||
// Call the gc enum callback for each of the objects
|
||||
mapType::iterator it;
|
||||
for( it = dict.begin(); it != dict.end(); it++ )
|
||||
{
|
||||
if( it->second.typeId & asTYPEID_MASK_OBJECT )
|
||||
engine->GCEnumCallback(it->second.valueObj);
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptMap::ReleaseAllReferences(asIScriptEngine * /*engine*/)
|
||||
{
|
||||
// We're being told to release all references in
|
||||
// order to break circular references for dead objects
|
||||
DeleteAll();
|
||||
}
|
||||
|
||||
CScriptMap &CScriptMap::operator =(const CScriptMap &other)
|
||||
{
|
||||
// Clear everything we had before
|
||||
DeleteAll();
|
||||
|
||||
// Do a shallow copy of the map
|
||||
mapType::const_iterator it;
|
||||
for( it = other.dict.begin(); it != other.dict.end(); it++ )
|
||||
{
|
||||
if( it->second.typeId & asTYPEID_OBJHANDLE )
|
||||
Set(it->first, (void*)&it->second.valueObj, it->second.typeId);
|
||||
else if( it->second.typeId & asTYPEID_MASK_OBJECT )
|
||||
Set(it->first, (void*)it->second.valueObj, it->second.typeId);
|
||||
else
|
||||
Set(it->first, (void*)&it->second.valueInt, it->second.typeId);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CScriptMap::Set(asINT64 key, void *value, int typeId)
|
||||
{
|
||||
valueStruct valStruct = {{0},0};
|
||||
valStruct.typeId = typeId;
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// We're receiving a reference to the handle, so we need to dereference it
|
||||
valStruct.valueObj = *(void**)value;
|
||||
engine->AddRefScriptObject(valStruct.valueObj, engine->GetTypeInfoById(typeId));
|
||||
}
|
||||
else if( typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Create a copy of the object
|
||||
valStruct.valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the primitive value
|
||||
// We receive a pointer to the value.
|
||||
int size = engine->GetSizeOfPrimitiveType(typeId);
|
||||
memcpy(&valStruct.valueInt, value, size);
|
||||
}
|
||||
|
||||
mapType::iterator it;
|
||||
it = dict.find(key);
|
||||
if( it != dict.end() )
|
||||
{
|
||||
FreeValue(it->second);
|
||||
|
||||
// Insert the new value
|
||||
it->second = valStruct;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict.insert(mapType::value_type(key, valStruct));
|
||||
++modCount;
|
||||
}
|
||||
}
|
||||
|
||||
// This overloaded method is implemented so that all integer and
|
||||
// unsigned integers types will be stored in the map as int64
|
||||
// through implicit conversions. This simplifies the management of the
|
||||
// numeric types when the script retrieves the stored value using a
|
||||
// different type.
|
||||
void CScriptMap::Set(asINT64 key, asINT64 &value)
|
||||
{
|
||||
Set(key, &value, asTYPEID_INT64);
|
||||
}
|
||||
|
||||
// This overloaded method is implemented so that all floating point types
|
||||
// will be stored in the map as double through implicit conversions.
|
||||
// This simplifies the management of the numeric types when the script
|
||||
// retrieves the stored value using a different type.
|
||||
void CScriptMap::Set(asINT64 key, double &value)
|
||||
{
|
||||
Set(key, &value, asTYPEID_DOUBLE);
|
||||
}
|
||||
|
||||
// This helper function exists to assist various map and iterator
|
||||
// methods that want to retrieve a value from a standard iterator
|
||||
bool CScriptMap::Iterator_GetValue(CScriptMap::mapType::const_iterator &it, void *value, int typeId) const {
|
||||
// Return the value
|
||||
if( typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// A handle can be retrieved if the stored type is a handle of same or compatible type
|
||||
// or if the stored type is an object that implements the interface that the handle refer to.
|
||||
if( (it->second.typeId & asTYPEID_MASK_OBJECT) &&
|
||||
IsHandleCompatibleWithObject((asCScriptEngine*)engine, it->second.valueObj, it->second.typeId, typeId) )
|
||||
{
|
||||
engine->AddRefScriptObject(it->second.valueObj, engine->GetTypeInfoById(it->second.typeId));
|
||||
*(void**)value = it->second.valueObj;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if( typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Verify that the copy can be made
|
||||
bool isCompatible = false;
|
||||
if( it->second.typeId == typeId )
|
||||
isCompatible = true;
|
||||
|
||||
// Copy the object into the given reference
|
||||
if( isCompatible )
|
||||
{
|
||||
engine->AssignScriptObject(value, it->second.valueObj, engine->GetTypeInfoById(typeId));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( it->second.typeId == typeId )
|
||||
{
|
||||
int size = engine->GetSizeOfPrimitiveType(typeId);
|
||||
memcpy(value, &it->second.valueInt, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
|
||||
if( it->second.typeId == asTYPEID_INT64 && typeId == asTYPEID_DOUBLE )
|
||||
{
|
||||
*(double*)value = double(it->second.valueInt);
|
||||
return true;
|
||||
}
|
||||
else if( it->second.typeId == asTYPEID_DOUBLE && typeId == asTYPEID_INT64 )
|
||||
{
|
||||
*(asINT64*)value = asINT64(it->second.valueFlt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// AngelScript has already initialized the value with a default value,
|
||||
// so we don't have to do anything if we don't find the element, or if
|
||||
// the element is incompatible with the requested type.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if the value was successfully retrieved
|
||||
bool CScriptMap::Get(asINT64 key, void *value, int typeId) const
|
||||
{
|
||||
mapType::const_iterator it;
|
||||
it = dict.find(key);
|
||||
if( it != dict.end() )
|
||||
{
|
||||
// This logic is already implemented in the iterator wrapper,
|
||||
// so defer to that function from here
|
||||
return Iterator_GetValue(it, value, typeId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptMap::Get(asINT64 key, asINT64 &value) const
|
||||
{
|
||||
return Get(key, &value, asTYPEID_INT64);
|
||||
}
|
||||
|
||||
bool CScriptMap::Get(asINT64 key, double &value) const
|
||||
{
|
||||
return Get(key, &value, asTYPEID_DOUBLE);
|
||||
}
|
||||
|
||||
bool CScriptMap::Exists(asINT64 key) const
|
||||
{
|
||||
mapType::const_iterator it;
|
||||
it = dict.find(key);
|
||||
if( it != dict.end() )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CScriptMap::IsEmpty() const
|
||||
{
|
||||
if( dict.size() == 0 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
asUINT CScriptMap::GetSize() const
|
||||
{
|
||||
return asUINT(dict.size());
|
||||
}
|
||||
|
||||
void CScriptMap::Delete(asINT64 key)
|
||||
{
|
||||
mapType::iterator it;
|
||||
it = dict.find(key);
|
||||
if( it != dict.end() )
|
||||
{
|
||||
FreeValue(it->second);
|
||||
dict.erase(it);
|
||||
++modCount;
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptMap::DeleteAll()
|
||||
{
|
||||
mapType::iterator it;
|
||||
for( it = dict.begin(); it != dict.end(); it++ )
|
||||
FreeValue(it->second);
|
||||
|
||||
dict.clear();
|
||||
}
|
||||
|
||||
void CScriptMap::DeleteNulls()
|
||||
{
|
||||
mapType::iterator it;
|
||||
for( it = dict.begin(); it != dict.end(); it++ )
|
||||
{
|
||||
if( it->second.typeId & asTYPEID_OBJHANDLE )
|
||||
if( it->second.valueObj == 0 )
|
||||
it = dict.erase(it);
|
||||
}
|
||||
++modCount;
|
||||
}
|
||||
|
||||
void CScriptMap::FreeValue(valueStruct &value)
|
||||
{
|
||||
// If it is a handle or a ref counted object, call release
|
||||
if( value.typeId & asTYPEID_MASK_OBJECT )
|
||||
{
|
||||
// Let the engine release the object
|
||||
engine->ReleaseScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
|
||||
value.valueObj = 0;
|
||||
value.typeId = 0;
|
||||
}
|
||||
|
||||
// For primitives, there's nothing to do
|
||||
}
|
||||
|
||||
CScriptArray* CScriptMap::GetKeys() const
|
||||
{
|
||||
// TODO: optimize: The string array type should only be determined once.
|
||||
// It should be recomputed when registering the map class.
|
||||
// Only problem is if multiple engines are used, as they may not
|
||||
// share the same type id. Alternatively it can be stored in the
|
||||
// user data for the map type.
|
||||
int stringArrayType = engine->GetTypeIdByDecl("array<int64>");
|
||||
asITypeInfo *ot = engine->GetTypeInfoById(stringArrayType);
|
||||
|
||||
// Create the array object
|
||||
CScriptArray *array = new CScriptArray(dict.size(), ot);
|
||||
long current = -1;
|
||||
mapType::const_iterator it;
|
||||
for( it = dict.begin(); it != dict.end(); it++ )
|
||||
{
|
||||
current++;
|
||||
*(asINT64*)array->At(current) = it->first;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
CScriptMap::Iterator CScriptMap::GetIterator() const {
|
||||
return Iterator(this);
|
||||
}
|
||||
|
||||
void CScriptMap::Delete(CScriptMap::Iterator& it) {
|
||||
if( it.container != this ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Mismatched script container and iterator.");
|
||||
return;
|
||||
}
|
||||
|
||||
if( it.it == dict.end() ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Deleting invalid iterator.");
|
||||
return;
|
||||
}
|
||||
|
||||
it.it = dict.erase(it.it);
|
||||
it.first = true;
|
||||
++modCount;
|
||||
it.modCount = modCount;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Iterator implementation
|
||||
|
||||
CScriptMap::Iterator::Iterator() {
|
||||
container = 0;
|
||||
}
|
||||
|
||||
CScriptMap::Iterator::Iterator(const CScriptMap *container) {
|
||||
this->container = container;
|
||||
|
||||
// Start the iteration
|
||||
it = container->dict.begin();
|
||||
first = true;
|
||||
|
||||
// Track the modification count of the map
|
||||
// so we can safely fail when the map is altered
|
||||
modCount = container->modCount;
|
||||
|
||||
// Keep a reference to the map so it doesn't
|
||||
// get destroyed from under us
|
||||
container->AddRef();
|
||||
}
|
||||
|
||||
CScriptMap::Iterator::~Iterator() {
|
||||
// Release map reference
|
||||
if(container)
|
||||
container->Release();
|
||||
}
|
||||
|
||||
static void DefaultConstructIterator(void *memory) {
|
||||
new(memory) CScriptMap::Iterator();
|
||||
}
|
||||
|
||||
static void ConstructIterator(void *memory, const CScriptMap *container) {
|
||||
new(memory) CScriptMap::Iterator(container);
|
||||
}
|
||||
|
||||
static void DestructIterator(CScriptMap::Iterator &it) {
|
||||
it.~Iterator();
|
||||
}
|
||||
|
||||
asINT64 CScriptMap::Iterator::GetKey() {
|
||||
if( !container || modCount != container->modCount || it == container->dict.end() ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Iterator not valid or map changed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return it->first;
|
||||
}
|
||||
|
||||
bool CScriptMap::Iterator::Iterate(void *value, int typeId) {
|
||||
return Iterate(0, value, typeId);
|
||||
}
|
||||
|
||||
bool CScriptMap::Iterator::Iterate(asINT64* key, void *value, int typeId) {
|
||||
if( !container ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Iterating on invalid iterator.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if( modCount != container->modCount ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Dictionary changed during iteration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if( it == container->dict.end() )
|
||||
return false;
|
||||
|
||||
if( first )
|
||||
first = false;
|
||||
else
|
||||
++it;
|
||||
|
||||
if( it == container->dict.end() )
|
||||
return false;
|
||||
|
||||
if( key )
|
||||
*key = it->first;
|
||||
|
||||
if( container->Iterator_GetValue(it, value, typeId) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The caller can check IsValid to see if the iteration can still
|
||||
// continue because the type was wrong, or whether it has really ended
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CScriptMap::Iterator::IsValid() {
|
||||
if( !container || modCount != container->modCount ) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if( ctx )
|
||||
ctx->SetException("Map changed during iteration.");
|
||||
}
|
||||
|
||||
return it != container->dict.end();
|
||||
}
|
||||
|
||||
CScriptMap::Iterator &CScriptMap::Iterator::operator =(const CScriptMap::Iterator &other) {
|
||||
if(other.container)
|
||||
other.container->AddRef();
|
||||
if(container)
|
||||
container->Release();
|
||||
|
||||
modCount = other.modCount;
|
||||
container = other.container;
|
||||
first = other.first;
|
||||
it = other.it;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Generic wrappers
|
||||
|
||||
void ScriptMapFactory_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
*(CScriptMap**)gen->GetAddressOfReturnLocation() = new CScriptMap(gen->GetEngine());
|
||||
}
|
||||
|
||||
void ScriptMapAddRef_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
dict->AddRef();
|
||||
}
|
||||
|
||||
void ScriptMapRelease_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
dict->Release();
|
||||
}
|
||||
|
||||
void ScriptMapAssign_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
CScriptMap *other = *(CScriptMap**)gen->GetAddressOfArg(0);
|
||||
*dict = *other;
|
||||
*(CScriptMap**)gen->GetAddressOfReturnLocation() = dict;
|
||||
}
|
||||
|
||||
void ScriptMapSet_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
int typeId = gen->GetArgTypeId(1);
|
||||
dict->Set(key, ref, typeId);
|
||||
}
|
||||
|
||||
void ScriptMapSetInt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
dict->Set(key, *(asINT64*)ref);
|
||||
}
|
||||
|
||||
void ScriptMapSetFlt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
dict->Set(key, *(double*)ref);
|
||||
}
|
||||
|
||||
void ScriptMapGet_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
int typeId = gen->GetArgTypeId(1);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(key, ref, typeId);
|
||||
}
|
||||
|
||||
void ScriptMapGetInt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(key, *(asINT64*)ref);
|
||||
}
|
||||
|
||||
void ScriptMapGetFlt_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
|
||||
void *ref = *(void**)gen->GetAddressOfArg(1);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(key, *(double*)ref);
|
||||
}
|
||||
|
||||
void ScriptMapExists_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
|
||||
bool ret = dict->Exists(key);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = ret;
|
||||
}
|
||||
|
||||
void ScriptMapDelete_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
|
||||
dict->Delete(key);
|
||||
}
|
||||
|
||||
void ScriptMapDeleteAll_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *dict = (CScriptMap*)gen->GetObject();
|
||||
dict->DeleteAll();
|
||||
}
|
||||
|
||||
static void ScriptMapGetRefCount_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *self = (CScriptMap*)gen->GetObject();
|
||||
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
|
||||
}
|
||||
|
||||
static void ScriptMapSetGCFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *self = (CScriptMap*)gen->GetObject();
|
||||
self->SetGCFlag();
|
||||
}
|
||||
|
||||
static void ScriptMapGetGCFlag_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *self = (CScriptMap*)gen->GetObject();
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag();
|
||||
}
|
||||
|
||||
static void ScriptMapEnumReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *self = (CScriptMap*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->EnumReferences(engine);
|
||||
}
|
||||
|
||||
static void ScriptMapReleaseAllReferences_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *self = (CScriptMap*)gen->GetObject();
|
||||
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
||||
self->ReleaseAllReferences(engine);
|
||||
}
|
||||
|
||||
static void CScriptMapGetKeys_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
CScriptMap *self = (CScriptMap*)gen->GetObject();
|
||||
*(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Register the type
|
||||
|
||||
void RegisterScriptMap(asIScriptEngine *engine)
|
||||
{
|
||||
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
|
||||
RegisterScriptMap_Generic(engine);
|
||||
else
|
||||
RegisterScriptMap_Native(engine);
|
||||
}
|
||||
|
||||
void RegisterScriptMap_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
//Register iterator type so we can use it later
|
||||
r = engine->RegisterObjectType("map_iterator", sizeof(CScriptMap::Iterator), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectType("map", sizeof(CScriptMap), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
|
||||
// Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_FACTORY, "map@ f()", asFUNCTION(ScriptMapFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptMap,AddRef), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptMap,Release), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "map &opAssign(const map &in)", asMETHODPR(CScriptMap, operator=, (const CScriptMap &), CScriptMap&), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "void set(int64, const ?&in)", asMETHODPR(CScriptMap,Set,(asINT64,void*,int),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "bool get(int64, ?&out) const", asMETHODPR(CScriptMap,Get,(asINT64,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "void set(int64, int64&in)", asMETHODPR(CScriptMap,Set,(asINT64,asINT64&),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "bool get(int64, int64&out) const", asMETHODPR(CScriptMap,Get,(asINT64,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "void set(int64, double&in)", asMETHODPR(CScriptMap,Set,(asINT64,double&),void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "bool get(int64, double&out) const", asMETHODPR(CScriptMap,Get,(asINT64,double&) const,bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "bool exists(int64) const", asMETHOD(CScriptMap,Exists), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "bool isEmpty() const", asMETHOD(CScriptMap, IsEmpty), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "uint getSize() const", asMETHOD(CScriptMap, GetSize), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "void delete(int64)", asMETHODPR(CScriptMap, Delete, (asINT64), void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "void delete(map_iterator&)", asMETHODPR(CScriptMap, Delete, (CScriptMap::Iterator&), void), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "void deleteAll()", asMETHOD(CScriptMap,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "void deleteNulls()", asMETHOD(CScriptMap,DeleteNulls), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "map_iterator iterator()", asMETHOD(CScriptMap,GetIterator), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "array<int64> @getKeys() const", asMETHOD(CScriptMap,GetKeys), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
// Register GC behaviours
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptMap,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptMap,SetGCFlag), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptMap,GetGCFlag), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptMap,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptMap,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
#if AS_USE_STLNAMES == 1
|
||||
// Same as isEmpty
|
||||
r = engine->RegisterObjectMethod("map", "bool empty() const", asMETHOD(CScriptMap, IsEmpty), asCALL_THISCALL); assert( r >= 0 );
|
||||
// Same as getSize
|
||||
r = engine->RegisterObjectMethod("map", "uint size() const", asMETHOD(CScriptMap, GetSize), asCALL_THISCALL); assert( r >= 0 );
|
||||
// Same as delete
|
||||
r = engine->RegisterObjectMethod("map", "void erase(asINT64 in)", asMETHOD(CScriptMap,Delete), asCALL_THISCALL); assert( r >= 0 );
|
||||
// Same as deleteAll
|
||||
r = engine->RegisterObjectMethod("map", "void clear()", asMETHOD(CScriptMap,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
|
||||
#endif
|
||||
|
||||
// Register iterator methods
|
||||
r = engine->RegisterObjectBehaviour("map_iterator", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(DefaultConstructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map_iterator", asBEHAVE_CONSTRUCT, "void f(const map &in)", asFUNCTION(ConstructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map_iterator", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map_iterator", "int64 get_key()", asMETHOD(CScriptMap::Iterator, GetKey), asCALL_THISCALL); assert( r>= 0 );
|
||||
r = engine->RegisterObjectMethod("map_iterator", "bool iterate(?&out)", asMETHODPR(CScriptMap::Iterator, Iterate, (void*,int), bool), asCALL_THISCALL); assert( r>= 0 );
|
||||
r = engine->RegisterObjectMethod("map_iterator", "bool iterate(int64 &out, ?&out)", asMETHODPR(CScriptMap::Iterator, Iterate, (asINT64*,void*,int), bool), asCALL_THISCALL); assert( r>= 0 );
|
||||
r = engine->RegisterObjectMethod("map_iterator", "bool get_valid()", asMETHOD(CScriptMap::Iterator, IsValid), asCALL_THISCALL); assert( r>= 0 );
|
||||
r = engine->RegisterObjectMethod("map_iterator", "map_iterator& opAssign(const map_iterator &in)", asMETHOD(CScriptMap::Iterator, operator=), asCALL_THISCALL); assert( r>= 0 );
|
||||
}
|
||||
|
||||
void RegisterScriptMap_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = engine->RegisterObjectType("map", sizeof(CScriptMap), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_FACTORY, "map@ f()", asFUNCTION(ScriptMapFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptMapAddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptMapRelease_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "map &opAssign(const map &in)", asFUNCTION(ScriptMapAssign_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "void set(int64, ?&in)", asFUNCTION(ScriptMapSet_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "bool get(int64, ?&out) const", asFUNCTION(ScriptMapGet_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "void set(int64, int64&in)", asFUNCTION(ScriptMapSetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "bool get(int64, int64&out) const", asFUNCTION(ScriptMapGetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "void set(int64, double&in)", asFUNCTION(ScriptMapSetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "bool get(int64, double&out) const", asFUNCTION(ScriptMapGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "bool exists(asINT64 in) const", asFUNCTION(ScriptMapExists_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "void delete(asINT64 in)", asFUNCTION(ScriptMapDelete_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("map", "void deleteAll()", asFUNCTION(ScriptMapDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("map", "array<int64> @getKeys() const", asFUNCTION(CScriptMapGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Register GC behaviours
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptMapGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptMapSetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptMapGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptMapEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("map", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptMapReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include "scriptmath.h"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#include <cmath>
|
||||
|
||||
// The C++Builder RTL doesn't pull the *f functions into the global namespace per default.
|
||||
using namespace std;
|
||||
|
||||
#if __BORLANDC__ < 0x580
|
||||
// C++Builder 6 and earlier don't come with any *f variants of the math functions at all.
|
||||
inline float cosf (float arg) { return std::cos (arg); }
|
||||
inline float sinf (float arg) { return std::sin (arg); }
|
||||
inline float tanf (float arg) { return std::tan (arg); }
|
||||
inline float atan2f (float y, float x) { return std::atan2 (y, x); }
|
||||
inline float logf (float arg) { return std::log (arg); }
|
||||
inline float powf (float x, float y) { return std::pow (x, y); }
|
||||
inline float sqrtf (float arg) { return std::sqrt (arg); }
|
||||
#endif
|
||||
|
||||
// C++Builder doesn't define most of the non-standard float-specific math functions with
|
||||
// "*f" suffix; instead it provides overloads for the standard math functions which take
|
||||
// "float" arguments.
|
||||
inline float acosf (float arg) { return std::acos (arg); }
|
||||
inline float asinf (float arg) { return std::asin (arg); }
|
||||
inline float atanf (float arg) { return std::atan (arg); }
|
||||
inline float coshf (float arg) { return std::cosh (arg); }
|
||||
inline float sinhf (float arg) { return std::sinh (arg); }
|
||||
inline float tanhf (float arg) { return std::tanh (arg); }
|
||||
inline float log10f (float arg) { return std::log10 (arg); }
|
||||
inline float ceilf (float arg) { return std::ceil (arg); }
|
||||
inline float fabsf (float arg) { return std::fabs (arg); }
|
||||
inline float floorf (float arg) { return std::floor (arg); }
|
||||
|
||||
// C++Builder doesn't define a non-standard "modff" function but rather an overload of "modf"
|
||||
// for float arguments. However, BCC's float overload of fmod() is broken (QC #74816; fixed
|
||||
// in C++Builder 2010).
|
||||
inline float modff (float x, float *y)
|
||||
{
|
||||
double d;
|
||||
float f = (float) modf((double) x, &d);
|
||||
*y = (float) d;
|
||||
return f;
|
||||
}
|
||||
#endif
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// Determine whether the float version should be registered, or the double version
|
||||
#ifndef AS_USE_FLOAT
|
||||
#if !defined(_WIN32_WCE) // WinCE doesn't have the float versions of the math functions
|
||||
#define AS_USE_FLOAT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The modf function doesn't seem very intuitive, so I'm writing this
|
||||
// function that simply returns the fractional part of the float value
|
||||
#if AS_USE_FLOAT
|
||||
float fractionf(float v)
|
||||
{
|
||||
float intPart;
|
||||
return modff(v, &intPart);
|
||||
}
|
||||
#else
|
||||
double fraction(double v)
|
||||
{
|
||||
double intPart;
|
||||
return modf(v, &intPart);
|
||||
}
|
||||
#endif
|
||||
|
||||
// As AngelScript doesn't allow bitwise manipulation of float types we'll provide a couple of
|
||||
// functions for converting float values to IEEE 754 formatted values etc. This also allow us to
|
||||
// provide a platform agnostic representation to the script so the scripts don't have to worry
|
||||
// about whether the CPU uses IEEE 754 floats or some other representation
|
||||
float fpFromIEEE(asUINT raw)
|
||||
{
|
||||
// TODO: Identify CPU family to provide proper conversion
|
||||
// if the CPU doesn't natively use IEEE style floats
|
||||
return *reinterpret_cast<float*>(&raw);
|
||||
}
|
||||
asUINT fpToIEEE(float fp)
|
||||
{
|
||||
return *reinterpret_cast<asUINT*>(&fp);
|
||||
}
|
||||
double fpFromIEEE(asQWORD raw)
|
||||
{
|
||||
return *reinterpret_cast<double*>(&raw);
|
||||
}
|
||||
asQWORD fpToIEEE(double fp)
|
||||
{
|
||||
return *reinterpret_cast<asQWORD*>(&fp);
|
||||
}
|
||||
|
||||
float _round(float v) {
|
||||
return floorf(v + 0.5f);
|
||||
}
|
||||
|
||||
double _round(double v) {
|
||||
return floorl(v + 0.5);
|
||||
}
|
||||
|
||||
// closeTo() is used to determine if the binary representation of two numbers are
|
||||
// relatively close to each other. Numerical errors due to rounding errors build
|
||||
// up over many operations, so it is almost impossible to get exact numbers and
|
||||
// this is where closeTo() comes in.
|
||||
//
|
||||
// It shouldn't be used to determine if two numbers are mathematically close to
|
||||
// each other.
|
||||
//
|
||||
// ref: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
|
||||
// ref: http://www.gamedev.net/topic/653449-scriptmath-and-closeto/
|
||||
bool closeTo(float a, float b, float epsilon)
|
||||
{
|
||||
// Equal numbers and infinity will return immediately
|
||||
if( a == b ) return true;
|
||||
|
||||
// When very close to 0, we can use the absolute comparison
|
||||
float diff = fabsf(a - b);
|
||||
if( (a == 0 || b == 0) && (diff < epsilon) )
|
||||
return true;
|
||||
|
||||
// Otherwise we need to use relative comparison to account for precision
|
||||
return diff / (fabs(a) + fabs(b)) < epsilon;
|
||||
}
|
||||
|
||||
bool closeTo(double a, double b, double epsilon)
|
||||
{
|
||||
if( a == b ) return true;
|
||||
|
||||
double diff = fabs(a - b);
|
||||
if( (a == 0 || b == 0) && (diff < epsilon) )
|
||||
return true;
|
||||
|
||||
return diff / (fabs(a) + fabs(b)) < epsilon;
|
||||
}
|
||||
|
||||
void RegisterScriptMath_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
// Conversion between floating point and IEEE bits representations
|
||||
r = engine->RegisterGlobalFunction("float fpFromIEEE(uint)", asFUNCTIONPR(fpFromIEEE, (asUINT), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("uint fpToIEEE(float)", asFUNCTIONPR(fpToIEEE, (float), asUINT), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double fpFromIEEE(uint64)", asFUNCTIONPR(fpFromIEEE, (asQWORD), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("uint64 fpToIEEE(double)", asFUNCTIONPR(fpToIEEE, (double), asQWORD), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Close to comparison with epsilon
|
||||
r = engine->RegisterGlobalFunction("bool closeTo(float, float, float = 0.00001f)", asFUNCTIONPR(closeTo, (float, float, float), bool), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("bool closeTo(double, double, double = 0.0000000001)", asFUNCTIONPR(closeTo, (double, double, double), bool), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
#if AS_USE_FLOAT
|
||||
// Trigonometric functions
|
||||
r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTIONPR(cosf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTIONPR(sinf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTIONPR(tanf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTIONPR(acosf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTIONPR(asinf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTIONPR(atanf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTIONPR(atan2f, (float, float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Hyberbolic functions
|
||||
r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTIONPR(coshf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTIONPR(sinhf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTIONPR(tanhf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Exponential and logarithmic functions
|
||||
r = engine->RegisterGlobalFunction("float log(float)", asFUNCTIONPR(logf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTIONPR(log10f, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Power functions
|
||||
r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTIONPR(powf, (float, float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTIONPR(sqrtf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Nearest integer, absolute value, and remainder functions
|
||||
r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTIONPR(ceilf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTIONPR(fabsf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTIONPR(floorf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float round(float)", asFUNCTIONPR(_round, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTIONPR(fractionf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Don't register modf because AngelScript already supports the % operator
|
||||
#else
|
||||
// double versions of the same
|
||||
r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTIONPR(cos, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTIONPR(sin, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTIONPR(tan, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTIONPR(acos, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTIONPR(asin, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTIONPR(atan, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTIONPR(atan2, (double, double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTIONPR(cosh, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTIONPR(sinh, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTIONPR(tanh, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double log(double)", asFUNCTIONPR(log, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTIONPR(log10, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTIONPR(pow, (double, double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTIONPR(sqrt, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTIONPR(ceil, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTIONPR(fabs, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double round(double)", asFUNCTIONPR(_round, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
#if AS_USE_FLOAT
|
||||
// This macro creates simple generic wrappers for functions of type 'float func(float)'
|
||||
#define GENERICff(x) \
|
||||
void x##_generic(asIScriptGeneric *gen) \
|
||||
{ \
|
||||
float f = *(float*)gen->GetAddressOfArg(0); \
|
||||
*(float*)gen->GetAddressOfReturnLocation() = x(f); \
|
||||
}
|
||||
|
||||
GENERICff(cosf)
|
||||
GENERICff(sinf)
|
||||
GENERICff(tanf)
|
||||
GENERICff(acosf)
|
||||
GENERICff(asinf)
|
||||
GENERICff(atanf)
|
||||
GENERICff(coshf)
|
||||
GENERICff(sinhf)
|
||||
GENERICff(tanhf)
|
||||
GENERICff(logf)
|
||||
GENERICff(log10f)
|
||||
GENERICff(sqrtf)
|
||||
GENERICff(ceilf)
|
||||
GENERICff(fabsf)
|
||||
GENERICff(floorf)
|
||||
GENERICff(fractionf)
|
||||
|
||||
void powf_generic(asIScriptGeneric *gen)
|
||||
{
|
||||
float f1 = *(float*)gen->GetAddressOfArg(0);
|
||||
float f2 = *(float*)gen->GetAddressOfArg(1);
|
||||
*(float*)gen->GetAddressOfReturnLocation() = powf(f1, f2);
|
||||
}
|
||||
void atan2f_generic(asIScriptGeneric *gen)
|
||||
{
|
||||
float f1 = *(float*)gen->GetAddressOfArg(0);
|
||||
float f2 = *(float*)gen->GetAddressOfArg(1);
|
||||
*(float*)gen->GetAddressOfReturnLocation() = atan2f(f1, f2);
|
||||
}
|
||||
|
||||
#else
|
||||
// This macro creates simple generic wrappers for functions of type 'double func(double)'
|
||||
#define GENERICdd(x) \
|
||||
void x##_generic(asIScriptGeneric *gen) \
|
||||
{ \
|
||||
double f = *(double*)gen->GetAddressOfArg(0); \
|
||||
*(double*)gen->GetAddressOfReturnLocation() = x(f); \
|
||||
}
|
||||
|
||||
GENERICdd(cos)
|
||||
GENERICdd(sin)
|
||||
GENERICdd(tan)
|
||||
GENERICdd(acos)
|
||||
GENERICdd(asin)
|
||||
GENERICdd(atan)
|
||||
GENERICdd(cosh)
|
||||
GENERICdd(sinh)
|
||||
GENERICdd(tanh)
|
||||
GENERICdd(log)
|
||||
GENERICdd(log10)
|
||||
GENERICdd(sqrt)
|
||||
GENERICdd(ceil)
|
||||
GENERICdd(fabs)
|
||||
GENERICdd(floor)
|
||||
GENERICdd(fraction)
|
||||
|
||||
void pow_generic(asIScriptGeneric *gen)
|
||||
{
|
||||
double f1 = *(double*)gen->GetAddressOfArg(0);
|
||||
double f2 = *(double*)gen->GetAddressOfArg(1);
|
||||
*(double*)gen->GetAddressOfReturnLocation() = pow(f1, f2);
|
||||
}
|
||||
void atan2_generic(asIScriptGeneric *gen)
|
||||
{
|
||||
double f1 = *(double*)gen->GetAddressOfArg(0);
|
||||
double f2 = *(double*)gen->GetAddressOfArg(1);
|
||||
*(double*)gen->GetAddressOfReturnLocation() = atan2(f1, f2);
|
||||
}
|
||||
#endif
|
||||
void RegisterScriptMath_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
#if AS_USE_FLOAT
|
||||
// Trigonometric functions
|
||||
r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTION(tanf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTION(acosf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTION(asinf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTION(atanf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTION(atan2f_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Hyberbolic functions
|
||||
r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTION(coshf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTION(sinhf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTION(tanhf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Exponential and logarithmic functions
|
||||
r = engine->RegisterGlobalFunction("float log(float)", asFUNCTION(logf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTION(log10f_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Power functions
|
||||
r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTION(powf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTION(sqrtf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Nearest integer, absolute value, and remainder functions
|
||||
r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTION(fabsf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTION(fractionf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Don't register modf because AngelScript already supports the % operator
|
||||
#else
|
||||
// double versions of the same
|
||||
r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTION(cos_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTION(sin_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTION(tan_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTION(acos_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTION(asin_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTION(atan_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTION(atan2_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTION(cosh_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTION(sinh_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTION(tanh_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double log(double)", asFUNCTION(log_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTION(log10_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTION(pow_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTION(sqrt_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTION(ceil_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTION(fabs_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void RegisterScriptMath(asIScriptEngine *engine)
|
||||
{
|
||||
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
|
||||
RegisterScriptMath_Generic(engine);
|
||||
else
|
||||
RegisterScriptMath_Native(engine);
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
@@ -0,0 +1,639 @@
|
||||
#include <assert.h>
|
||||
#include <sstream>
|
||||
#include "scriptstdstring.h"
|
||||
#include <string.h> // strstr
|
||||
|
||||
using namespace std;
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
static void StringFactoryGeneric(asIScriptGeneric *gen) {
|
||||
asUINT length = gen->GetArgDWord(0);
|
||||
const char *s = (const char*)gen->GetArgAddress(1);
|
||||
string str(s, length);
|
||||
gen->SetReturnObject(&str);
|
||||
}
|
||||
|
||||
static void ConstructStringGeneric(asIScriptGeneric * gen) {
|
||||
new (gen->GetObject()) string();
|
||||
}
|
||||
|
||||
static void CopyConstructStringGeneric(asIScriptGeneric * gen) {
|
||||
string * a = static_cast<string *>(gen->GetArgObject(0));
|
||||
new (gen->GetObject()) string(*a);
|
||||
}
|
||||
|
||||
static void DestructStringGeneric(asIScriptGeneric * gen) {
|
||||
string * ptr = static_cast<string *>(gen->GetObject());
|
||||
ptr->~string();
|
||||
}
|
||||
|
||||
static void AssignStringGeneric(asIScriptGeneric *gen) {
|
||||
string * a = static_cast<string *>(gen->GetArgObject(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
*self = *a;
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AddAssignStringGeneric(asIScriptGeneric *gen) {
|
||||
string * a = static_cast<string *>(gen->GetArgObject(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
*self += *a;
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void StringEqualsGeneric(asIScriptGeneric * gen) {
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
string * b = static_cast<string *>(gen->GetArgAddress(0));
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = (*a == *b);
|
||||
}
|
||||
|
||||
static void StringCmpGeneric(asIScriptGeneric * gen) {
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
string * b = static_cast<string *>(gen->GetArgAddress(0));
|
||||
|
||||
int cmp = 0;
|
||||
if( *a < *b ) cmp = -1;
|
||||
else if( *a > *b ) cmp = 1;
|
||||
|
||||
*(int*)gen->GetAddressOfReturnLocation() = cmp;
|
||||
}
|
||||
|
||||
static void StringAddGeneric(asIScriptGeneric * gen) {
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
string * b = static_cast<string *>(gen->GetArgAddress(0));
|
||||
string ret_val = *a + *b;
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void StringLengthGeneric(asIScriptGeneric * gen) {
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
*static_cast<asUINT *>(gen->GetAddressOfReturnLocation()) = (asUINT)self->length();
|
||||
}
|
||||
|
||||
static void StringResizeGeneric(asIScriptGeneric * gen) {
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
self->resize(*static_cast<asUINT *>(gen->GetAddressOfArg(0)));
|
||||
}
|
||||
|
||||
static void StringCharAtGeneric(asIScriptGeneric * gen) {
|
||||
unsigned int index = gen->GetArgDWord(0);
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
|
||||
if (index >= self->size()) {
|
||||
// Set a script exception
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
ctx->SetException("Out of range");
|
||||
|
||||
gen->SetReturnAddress(0);
|
||||
} else {
|
||||
gen->SetReturnAddress(&(self->operator [](index)));
|
||||
}
|
||||
}
|
||||
|
||||
static void AssignInt2StringGeneric(asIScriptGeneric *gen)
|
||||
{
|
||||
int *a = static_cast<int*>(gen->GetAddressOfArg(0));
|
||||
string *self = static_cast<string*>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
*self = sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AssignUInt2StringGeneric(asIScriptGeneric *gen)
|
||||
{
|
||||
unsigned int *a = static_cast<unsigned int*>(gen->GetAddressOfArg(0));
|
||||
string *self = static_cast<string*>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
*self = sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AssignDouble2StringGeneric(asIScriptGeneric *gen)
|
||||
{
|
||||
double *a = static_cast<double*>(gen->GetAddressOfArg(0));
|
||||
string *self = static_cast<string*>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
*self = sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AssignBool2StringGeneric(asIScriptGeneric *gen)
|
||||
{
|
||||
bool *a = static_cast<bool*>(gen->GetAddressOfArg(0));
|
||||
string *self = static_cast<string*>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << (*a ? "true" : "false");
|
||||
*self = sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AddAssignDouble2StringGeneric(asIScriptGeneric * gen) {
|
||||
double * a = static_cast<double *>(gen->GetAddressOfArg(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
*self += sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AddAssignInt2StringGeneric(asIScriptGeneric * gen) {
|
||||
int * a = static_cast<int *>(gen->GetAddressOfArg(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
*self += sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AddAssignUInt2StringGeneric(asIScriptGeneric * gen) {
|
||||
unsigned int * a = static_cast<unsigned int *>(gen->GetAddressOfArg(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a;
|
||||
*self += sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AddAssignBool2StringGeneric(asIScriptGeneric * gen) {
|
||||
bool * a = static_cast<bool *>(gen->GetAddressOfArg(0));
|
||||
string * self = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << (*a ? "true" : "false");
|
||||
*self += sstr.str();
|
||||
gen->SetReturnAddress(self);
|
||||
}
|
||||
|
||||
static void AddString2DoubleGeneric(asIScriptGeneric * gen) {
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
double * b = static_cast<double *>(gen->GetAddressOfArg(0));
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddString2IntGeneric(asIScriptGeneric * gen) {
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
int * b = static_cast<int *>(gen->GetAddressOfArg(0));
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddString2UIntGeneric(asIScriptGeneric * gen) {
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
unsigned int * b = static_cast<unsigned int *>(gen->GetAddressOfArg(0));
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddString2BoolGeneric(asIScriptGeneric * gen) {
|
||||
string * a = static_cast<string *>(gen->GetObject());
|
||||
bool * b = static_cast<bool *>(gen->GetAddressOfArg(0));
|
||||
std::stringstream sstr;
|
||||
sstr << *a << (*b ? "true" : "false");
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddDouble2StringGeneric(asIScriptGeneric * gen) {
|
||||
double* a = static_cast<double *>(gen->GetAddressOfArg(0));
|
||||
string * b = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddInt2StringGeneric(asIScriptGeneric * gen) {
|
||||
int* a = static_cast<int *>(gen->GetAddressOfArg(0));
|
||||
string * b = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddUInt2StringGeneric(asIScriptGeneric * gen) {
|
||||
unsigned int* a = static_cast<unsigned int *>(gen->GetAddressOfArg(0));
|
||||
string * b = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << *a << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
static void AddBool2StringGeneric(asIScriptGeneric * gen) {
|
||||
bool* a = static_cast<bool *>(gen->GetAddressOfArg(0));
|
||||
string * b = static_cast<string *>(gen->GetObject());
|
||||
std::stringstream sstr;
|
||||
sstr << (*a ? "true" : "false") << *b;
|
||||
std::string ret_val = sstr.str();
|
||||
gen->SetReturnObject(&ret_val);
|
||||
}
|
||||
|
||||
// This function returns a string containing the substring of the input string
|
||||
// determined by the starting index and count of characters.
|
||||
//
|
||||
// AngelScript signature:
|
||||
// string string::substr(uint start = 0, int count = -1) const
|
||||
static void StringSubString_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
// Get the arguments
|
||||
string *str = (string*)gen->GetObject();
|
||||
asUINT start = *(int*)gen->GetAddressOfArg(0);
|
||||
int count = *(int*)gen->GetAddressOfArg(1);
|
||||
|
||||
// Check for out-of-bounds
|
||||
string ret;
|
||||
if( start < str->length() && count != 0 )
|
||||
ret = str->substr(start, count);
|
||||
|
||||
// Return the substring
|
||||
new(gen->GetAddressOfReturnLocation()) string(ret);
|
||||
}
|
||||
|
||||
void RegisterStdString_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
// Register the string type
|
||||
r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
|
||||
|
||||
// Register the string factory
|
||||
r = engine->RegisterStringFactory("string", asFUNCTION(StringFactoryGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Register the object operator overloads
|
||||
r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructStringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asFUNCTION(AssignStringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTION(StringEqualsGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmpGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTION(StringAddGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Register the object methods
|
||||
r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Register the index operator, both as a mutator and as an inspector
|
||||
r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Automatic conversion from values
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddString2DoubleGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(int)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(int) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(int) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(uint)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(uint) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint) const", asFUNCTION(AddUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddString2BoolGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
}
|
||||
|
||||
static string StringFactory(asUINT length, const char *s)
|
||||
{
|
||||
return string(s, length);
|
||||
}
|
||||
|
||||
static void ConstructString(string *thisPointer)
|
||||
{
|
||||
new(thisPointer) string();
|
||||
}
|
||||
|
||||
static void CopyConstructString(const string &other, string *thisPointer)
|
||||
{
|
||||
new(thisPointer) string(other);
|
||||
}
|
||||
|
||||
static void DestructString(string *thisPointer)
|
||||
{
|
||||
thisPointer->~string();
|
||||
}
|
||||
|
||||
static string &AssignUIntToString(unsigned int i, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
dest = stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AddAssignUIntToString(unsigned int i, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
dest += stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string AddStringUInt(const string &str, unsigned int i)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddStringUInt64(const string &str, unsigned long long i)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddIntString(int i, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static string AddInt64String(long long i, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static string &AssignIntToString(int i, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
dest = stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AddAssignIntToString(int i, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
dest += stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string AddStringInt(const string &str, int i)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddStringInt64(const string &str, long long i)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddUIntString(unsigned int i, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static string AddUInt64String(unsigned long long i, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << i;
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static string &AssignDoubleToString(double f, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << f;
|
||||
dest = stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AddAssignDoubleToString(double f, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << f;
|
||||
dest += stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AssignBoolToString(bool b, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << (b ? "true" : "false");
|
||||
dest = stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string &AddAssignBoolToString(bool b, string &dest)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << (b ? "true" : "false");
|
||||
dest += stream.str();
|
||||
return dest;
|
||||
}
|
||||
|
||||
static string AddStringDouble(const string &str, double f)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << f;
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddDoubleString(double f, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << f;
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static string AddStringBool(const string &str, bool b)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << (b ? "true" : "false");
|
||||
return str + stream.str();
|
||||
}
|
||||
|
||||
static string AddBoolString(bool b, const string &str)
|
||||
{
|
||||
ostringstream stream;
|
||||
stream << (b ? "true" : "false");
|
||||
return stream.str() + str;
|
||||
}
|
||||
|
||||
static char *StringCharAt(unsigned int i, string &str)
|
||||
{
|
||||
if( i >= str.size() )
|
||||
{
|
||||
// Set a script exception
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
ctx->SetException("Out of range");
|
||||
|
||||
// Return a null pointer
|
||||
return 0;
|
||||
}
|
||||
|
||||
return &str[i];
|
||||
}
|
||||
|
||||
|
||||
// AngelScript signature:
|
||||
// int string::opCmp(const string &in) const
|
||||
static int StringCmp(const string &a, const string &b)
|
||||
{
|
||||
int cmp = 0;
|
||||
if( a < b ) cmp = -1;
|
||||
else if( a > b ) cmp = 1;
|
||||
return cmp;
|
||||
}
|
||||
|
||||
static bool StringEq(const string &a, const string &b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
// This function returns the index of the first position where the substring
|
||||
// exists in the input string. If the substring doesn't exist in the input
|
||||
// string -1 is returned.
|
||||
//
|
||||
// AngelScript signature:
|
||||
// int string::findFirst(const string &in sub, uint start = 0) const
|
||||
static int StringFindFirst(const string &sub, asUINT start, const string &str)
|
||||
{
|
||||
// We don't register the method directly because the argument types change between 32bit and 64bit platforms
|
||||
return (int)str.find(sub, start);
|
||||
}
|
||||
|
||||
// This function returns the index of the last position where the substring
|
||||
// exists in the input string. If the substring doesn't exist in the input
|
||||
// string -1 is returned.
|
||||
//
|
||||
// AngelScript signature:
|
||||
// int string::findLast(const string &in sub, int start = -1) const
|
||||
static int StringFindLast(const string &sub, int start, const string &str)
|
||||
{
|
||||
// We don't register the method directly because the argument types change between 32bit and 64bit platforms
|
||||
return (int)str.rfind(sub, (size_t)start);
|
||||
}
|
||||
|
||||
// AngelScript signature:
|
||||
// uint string::length() const
|
||||
static asUINT StringLength(const string &str)
|
||||
{
|
||||
// We don't register the method directly because the return type changes between 32bit and 64bit platforms
|
||||
return (asUINT)str.length();
|
||||
}
|
||||
|
||||
|
||||
// AngelScript signature:
|
||||
// void string::resize(uint l)
|
||||
static void StringResize(asUINT l, string &str)
|
||||
{
|
||||
// We don't register the method directly because the argument types change between 32bit and 64bit platforms
|
||||
str.resize(l);
|
||||
}
|
||||
|
||||
|
||||
void RegisterStdString_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
// Register the string type
|
||||
r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
|
||||
|
||||
// Register the string factory
|
||||
r = engine->RegisterStringFactory("string", asFUNCTION(StringFactory), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Register the object operator overloads
|
||||
r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asMETHODPR(string, operator =, (const string&), string&), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asMETHODPR(string, operator+=, (const string&), string&), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTION(StringEq), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmp), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTIONPR(operator +, (const string &, const string &), string), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
|
||||
// Register the object methods
|
||||
r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "uint get_length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
// Register the index operator, both as a mutator and as an inspector
|
||||
// Note that we don't register the operator[] directory, as it doesn't do bounds checking
|
||||
r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
// Automatic conversion from values
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddStringDouble), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDoubleString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(int)", asFUNCTION(AssignIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int)", asFUNCTION(AddAssignIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddStringInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(uint)", asFUNCTION(AssignUIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint)", asFUNCTION(AddAssignUIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddStringUInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddStringBool), asCALL_CDECL_OBJFIRST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBoolString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
// TODO: Implement the following
|
||||
// findFirstOf
|
||||
// findLastOf
|
||||
// findFirstNotOf
|
||||
// findLastNotOf
|
||||
// parseInt
|
||||
// parseFloat
|
||||
// formatInt - maybe as string::string(int64 value, const string &in format)
|
||||
// formatFloat
|
||||
// replace - replaces a text found in the string
|
||||
// replaceRange - replaces a range of bytes in the string
|
||||
// trim
|
||||
// multiply/times - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----"
|
||||
}
|
||||
|
||||
void RegisterStdString(asIScriptEngine * engine)
|
||||
{
|
||||
if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY"))
|
||||
RegisterStdString_Generic(engine);
|
||||
else
|
||||
RegisterStdString_Native(engine);
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#include <assert.h>
|
||||
#include "scriptstdstring.h"
|
||||
#include "scriptarray.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
|
||||
// This function takes an input string and splits it into parts by looking
|
||||
// for a specified delimiter. Example:
|
||||
//
|
||||
// string str = "A|B||D";
|
||||
// array<string>@ array = str.split("|");
|
||||
//
|
||||
// The resulting array has the following elements:
|
||||
//
|
||||
// {"A", "B", "", "D"}
|
||||
//
|
||||
// AngelScript signature:
|
||||
// array<string>@ string::split(const string &in delim) const
|
||||
static void StringSplit_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
// Obtain a pointer to the engine
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
asIScriptEngine *engine = ctx->GetEngine();
|
||||
|
||||
// TODO: This should only be done once
|
||||
// TODO: This assumes that CScriptArray was already registered
|
||||
asITypeInfo *arrayType = engine->GetTypeInfoById(engine->GetTypeIdByDecl("array<string>"));
|
||||
|
||||
// Create the array object
|
||||
CScriptArray *array = new CScriptArray(0, arrayType);
|
||||
|
||||
// Get the arguments
|
||||
string *str = (string*)gen->GetObject();
|
||||
string *delim = *(string**)gen->GetAddressOfArg(0);
|
||||
|
||||
// Find the existence of the delimiter in the input string
|
||||
int pos = 0, prev = 0, count = 0;
|
||||
while( (pos = (int)str->find(*delim, prev)) != (int)string::npos )
|
||||
{
|
||||
// Add the part to the array
|
||||
array->Resize(array->GetSize()+1);
|
||||
((string*)array->At(count))->assign(&(*str)[prev], pos-prev);
|
||||
|
||||
// Find the next part
|
||||
count++;
|
||||
prev = pos + (int)delim->length();
|
||||
}
|
||||
|
||||
// Add the remaining part
|
||||
array->Resize(array->GetSize()+1);
|
||||
((string*)array->At(count))->assign(&(*str)[prev]);
|
||||
|
||||
// Return the array by handle
|
||||
*(CScriptArray**)gen->GetAddressOfReturnLocation() = array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This function takes as input an array of string handles as well as a
|
||||
// delimiter and concatenates the array elements into one delimited string.
|
||||
// Example:
|
||||
//
|
||||
// array<string> array = {"A", "B", "", "D"};
|
||||
// string str = join(array, "|");
|
||||
//
|
||||
// The resulting string is:
|
||||
//
|
||||
// "A|B||D"
|
||||
//
|
||||
// AngelScript signature:
|
||||
// string join(const array<string> &in array, const string &in delim)
|
||||
static void StringJoin_Generic(asIScriptGeneric *gen)
|
||||
{
|
||||
// Get the arguments
|
||||
CScriptArray *array = *(CScriptArray**)gen->GetAddressOfArg(0);
|
||||
string *delim = *(string**)gen->GetAddressOfArg(1);
|
||||
|
||||
// Create the new string
|
||||
string str = "";
|
||||
if( array->GetSize() )
|
||||
{
|
||||
int n;
|
||||
for( n = 0; n < (int)array->GetSize() - 1; n++ )
|
||||
{
|
||||
str += *(string*)array->At(n);
|
||||
str += *delim;
|
||||
}
|
||||
|
||||
// Add the last part
|
||||
str += *(string*)array->At(n);
|
||||
}
|
||||
|
||||
// Return the string
|
||||
new(gen->GetAddressOfReturnLocation()) string(str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// This is where the utility functions are registered.
|
||||
// The string type must have been registered first.
|
||||
void RegisterStdStringUtils(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = engine->RegisterObjectMethod("string", "array<string>@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string join(const array<string> &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
Reference in New Issue
Block a user