Angelscript/angelscript/source/as_typeinfo.cpp

477 lines
11 KiB
C++

/*
AngelCode Scripting Library
Copyright (c) 2003-2020 Andreas Jonsson
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
The original version of this library can be located at:
http://www.angelcode.com/angelscript/
Andreas Jonsson
andreas@angelcode.com
*/
//
// as_typeinfo.cpp
//
#include "as_config.h"
#include "as_typeinfo.h"
#include "as_scriptengine.h"
BEGIN_AS_NAMESPACE
asCTypeInfo::asCTypeInfo()
{
externalRefCount.set(0);
internalRefCount.set(1); // start with one internal ref-count
engine = 0;
module = 0;
size = 0;
flags = 0;
typeId = -1; // start as -1 to signal that it hasn't been defined
scriptSectionIdx = -1;
declaredAt = 0;
accessMask = 0xFFFFFFFF;
nameSpace = 0;
}
asCTypeInfo::asCTypeInfo(asCScriptEngine *in_engine)
{
externalRefCount.set(0);
internalRefCount.set(1); // start with one internal ref count
engine = in_engine;
module = 0;
size = 0;
flags = 0;
typeId = -1; // start as -1 to signal that it hasn't been defined
scriptSectionIdx = -1;
declaredAt = 0;
accessMask = 0xFFFFFFFF;
nameSpace = engine->nameSpaces[0];
}
asCTypeInfo::~asCTypeInfo()
{
}
// interface
int asCTypeInfo::AddRef() const
{
return externalRefCount.atomicInc();
}
// interface
int asCTypeInfo::Release() const
{
int r = externalRefCount.atomicDec();
if (r == 0)
{
// There are no more external references, if there are also no
// internal references then it is time to delete the object type
if (internalRefCount.get() == 0)
{
// If the engine is no longer set, then it has already been
// released and we must take care of the deletion ourselves
asDELETE(const_cast<asCTypeInfo*>(this), asCTypeInfo);
}
}
return r;
}
int asCTypeInfo::AddRefInternal()
{
return internalRefCount.atomicInc();
}
int asCTypeInfo::ReleaseInternal()
{
int r = internalRefCount.atomicDec();
if (r == 0)
{
// There are no more internal references, if there are also no
// external references then it is time to delete the object type
if (externalRefCount.get() == 0)
{
// If the engine is no longer set, then it has already been
// released and we must take care of the deletion ourselves
asDELETE(const_cast<asCTypeInfo*>(this), asCTypeInfo);
}
}
return r;
}
// interface
asIScriptModule *asCTypeInfo::GetModule() const
{
return module;
}
void *asCTypeInfo::SetUserData(void *data, asPWORD type)
{
// As a thread might add a new new user data at the same time as another
// it is necessary to protect both read and write access to the userData member
ACQUIREEXCLUSIVE(engine->engineRWLock);
// It is not intended to store a lot of different types of userdata,
// so a more complex structure like a associative map would just have
// more overhead than a simple array.
for (asUINT n = 0; n < userData.GetLength(); n += 2)
{
if (userData[n] == type)
{
void *oldData = reinterpret_cast<void*>(userData[n + 1]);
userData[n + 1] = reinterpret_cast<asPWORD>(data);
RELEASEEXCLUSIVE(engine->engineRWLock);
return oldData;
}
}
userData.PushLast(type);
userData.PushLast(reinterpret_cast<asPWORD>(data));
RELEASEEXCLUSIVE(engine->engineRWLock);
return 0;
}
void *asCTypeInfo::GetUserData(asPWORD type) const
{
// There may be multiple threads reading, but when
// setting the user data nobody must be reading.
ACQUIRESHARED(engine->engineRWLock);
for (asUINT n = 0; n < userData.GetLength(); n += 2)
{
if (userData[n] == type)
{
RELEASESHARED(engine->engineRWLock);
return reinterpret_cast<void*>(userData[n + 1]);
}
}
RELEASESHARED(engine->engineRWLock);
return 0;
}
// interface
const char *asCTypeInfo::GetName() const
{
return name.AddressOf();
}
// interface
const char *asCTypeInfo::GetNamespace() const
{
if( nameSpace )
return nameSpace->name.AddressOf();
return 0;
}
// interface
asDWORD asCTypeInfo::GetFlags() const
{
return flags;
}
// interface
asUINT asCTypeInfo::GetSize() const
{
return size;
}
// interface
int asCTypeInfo::GetTypeId() const
{
if (typeId == -1)
{
// We need a non const pointer to create the asCDataType object.
// We're not breaking anything here because this function is not
// modifying the object, so this const cast is safe.
asCTypeInfo *ot = const_cast<asCTypeInfo*>(this);
// The engine will define the typeId for this object type
engine->GetTypeIdFromDataType(asCDataType::CreateType(ot, false));
}
return typeId;
}
// interface
asIScriptEngine *asCTypeInfo::GetEngine() const
{
return engine;
}
// interface
const char *asCTypeInfo::GetConfigGroup() const
{
asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(this);
if (group == 0)
return 0;
return group->groupName.AddressOf();
}
// interface
asDWORD asCTypeInfo::GetAccessMask() const
{
return accessMask;
}
// interface
int asCTypeInfo::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const
{
UNUSED_VAR(index);
if (out_name) *out_name = 0;
if (out_typeId) *out_typeId = 0;
if (out_isPrivate) *out_isPrivate = false;
if (out_isProtected) *out_isProtected = false;
if (out_offset) *out_offset = 0;
if (out_isReference) *out_isReference = false;
if (out_accessMask) *out_accessMask = 0;
if (out_compositeOffset) *out_compositeOffset = 0;
if (out_isCompositeIndirect) *out_isCompositeIndirect = false;
return -1;
}
// internal
asCObjectType *CastToObjectType(asCTypeInfo *ti)
{
// Allow call on null pointer
if (ti == 0) return 0;
// TODO: type: Should List pattern have its own type class?
if ((ti->flags & (asOBJ_VALUE | asOBJ_REF | asOBJ_LIST_PATTERN)) && !(ti->flags & asOBJ_FUNCDEF))
return reinterpret_cast<asCObjectType*>(ti);
return 0;
}
// internal
asCEnumType *CastToEnumType(asCTypeInfo *ti)
{
// Allow call on null pointer
if (ti == 0) return 0;
if (ti->flags & (asOBJ_ENUM))
return reinterpret_cast<asCEnumType*>(ti);
return 0;
}
// internal
asCTypedefType *CastToTypedefType(asCTypeInfo *ti)
{
// Allow call on null pointer
if (ti == 0) return 0;
if (ti->flags & (asOBJ_TYPEDEF))
return reinterpret_cast<asCTypedefType*>(ti);
return 0;
}
// internal
asCFuncdefType *CastToFuncdefType(asCTypeInfo *ti)
{
// Allow call on null pointer
if (ti == 0) return 0;
if (ti->flags & (asOBJ_FUNCDEF))
return reinterpret_cast<asCFuncdefType*>(ti);
return 0;
}
// internal
void asCTypeInfo::CleanUserData()
{
asASSERT(engine);
for (asUINT n = 0; n < userData.GetLength(); n += 2)
{
if (userData[n + 1])
{
for (asUINT c = 0; c < engine->cleanTypeInfoFuncs.GetLength(); c++)
if (engine->cleanTypeInfoFuncs[c].type == userData[n])
engine->cleanTypeInfoFuncs[c].cleanFunc(this);
}
}
userData.SetLength(0);
}
// internal
bool asCTypeInfo::IsShared() const
{
// Types that can be declared by scripts need to have the explicit flag asOBJ_SHARED
if (flags & (asOBJ_SCRIPT_OBJECT | asOBJ_ENUM)) return flags & asOBJ_SHARED ? true : false;
// Otherwise we assume the type to be shared
return true;
}
////////////////////////////////////////////////////////////////////////////////////////
asCEnumType::~asCEnumType()
{
asUINT n;
for (n = 0; n < enumValues.GetLength(); n++)
{
if (enumValues[n])
asDELETE(enumValues[n], asSEnumValue);
}
enumValues.SetLength(0);
}
// interface
asUINT asCEnumType::GetEnumValueCount() const
{
return enumValues.GetLength();
}
// interface
const char *asCEnumType::GetEnumValueByIndex(asUINT index, int *outValue) const
{
if (outValue)
*outValue = 0;
if (index >= enumValues.GetLength())
return 0;
if (outValue)
*outValue = enumValues[index]->value;
return enumValues[index]->name.AddressOf();
}
//////////////////////////////////////////////////////////////////////////////////////////
asCTypedefType::~asCTypedefType()
{
DestroyInternal();
}
void asCTypedefType::DestroyInternal()
{
if (engine == 0) return;
// Release the object types held by the alias
if (aliasForType.GetTypeInfo())
aliasForType.GetTypeInfo()->ReleaseInternal();
aliasForType = asCDataType::CreatePrimitive(ttVoid, false);
CleanUserData();
// Remove the type from the engine
if (typeId != -1)
engine->RemoveFromTypeIdMap(this);
// Clear the engine pointer to mark the object type as invalid
engine = 0;
}
// interface
int asCTypedefType::GetTypedefTypeId() const
{
return engine->GetTypeIdFromDataType(aliasForType);
}
//////////////////////////////////////////////////////////////////////////////////////////
asCFuncdefType::asCFuncdefType(asCScriptEngine *en, asCScriptFunction *func) : asCTypeInfo(en)
{
asASSERT(func->funcType == asFUNC_FUNCDEF);
asASSERT(func->funcdefType == 0);
// A function pointer is special kind of reference type
// It must be possible to garbage collect, as funcdefs can form circular references if used as delegates
flags = asOBJ_REF | asOBJ_GC | asOBJ_FUNCDEF | (func->IsShared() ? asOBJ_SHARED : 0);
name = func->name;
nameSpace = func->nameSpace;
module = func->module;
accessMask = func->accessMask;
funcdef = func; // reference already counted by the asCScriptFunction constructor
parentClass = 0;
func->funcdefType = this;
}
asCFuncdefType::~asCFuncdefType()
{
DestroyInternal();
}
void asCFuncdefType::DestroyInternal()
{
if (engine == 0) return;
// Release the funcdef
if( funcdef )
funcdef->ReleaseInternal();
funcdef = 0;
// Detach from parent class
if (parentClass)
{
parentClass->childFuncDefs.RemoveValue(this);
parentClass = 0;
}
CleanUserData();
// Remove the type from the engine
if (typeId != -1)
engine->RemoveFromTypeIdMap(this);
// Clear the engine pointer to mark the object type as invalid
engine = 0;
}
// interface
asIScriptFunction *asCFuncdefType::GetFuncdefSignature() const
{
return funcdef;
}
// interface
asITypeInfo *asCFuncdefType::GetParentType() const
{
return parentClass;
}
END_AS_NAMESPACE