Angelscript/add_on/scriptgrid/scriptgrid.cpp

808 lines
23 KiB
C++

#include <new>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h> // sprintf
#include "scriptgrid.h"
using namespace std;
BEGIN_AS_NAMESPACE
// Set the default memory routines
// Use the angelscript engine's memory routines by default
static asALLOCFUNC_t userAlloc = asAllocMem;
static asFREEFUNC_t userFree = asFreeMem;
// Allows the application to set which memory routines should be used by the array object
void CScriptGrid::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc)
{
userAlloc = allocFunc;
userFree = freeFunc;
}
static void RegisterScriptGrid_Native(asIScriptEngine *engine);
struct SGridBuffer
{
asDWORD width;
asDWORD height;
asBYTE data[1];
};
CScriptGrid *CScriptGrid::Create(asITypeInfo *ti)
{
return CScriptGrid::Create(ti, 0, 0);
}
CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h)
{
// Allocate the memory
void *mem = userAlloc(sizeof(CScriptGrid));
if( mem == 0 )
{
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Out of memory");
return 0;
}
// Initialize the object
CScriptGrid *a = new(mem) CScriptGrid(w, h, ti);
return a;
}
CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, void *initList)
{
// Allocate the memory
void *mem = userAlloc(sizeof(CScriptGrid));
if( mem == 0 )
{
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Out of memory");
return 0;
}
// Initialize the object
CScriptGrid *a = new(mem) CScriptGrid(ti, initList);
return a;
}
CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h, void *defVal)
{
// Allocate the memory
void *mem = userAlloc(sizeof(CScriptGrid));
if( mem == 0 )
{
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Out of memory");
return 0;
}
// Initialize the object
CScriptGrid *a = new(mem) CScriptGrid(w, h, defVal, ti);
return a;
}
// This optional callback is called when the template type is first used by the compiler.
// It allows the application to validate if the template can be instantiated for the requested
// subtype at compile time, instead of at runtime. The output argument dontGarbageCollect
// allow the callback to tell the engine if the template instance type shouldn't be garbage collected,
// i.e. no asOBJ_GC flag.
static bool ScriptGridTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect)
{
// Make sure the subtype can be instantiated with a default factory/constructor,
// otherwise we won't be able to instantiate the elements.
int typeId = ti->GetSubTypeId();
if( typeId == asTYPEID_VOID )
return false;
if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) )
{
asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId);
asDWORD flags = subtype->GetFlags();
if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) )
{
// Verify that there is a default constructor
bool found = false;
for( asUINT n = 0; n < subtype->GetBehaviourCount(); n++ )
{
asEBehaviours beh;
asIScriptFunction *func = subtype->GetBehaviourByIndex(n, &beh);
if( beh != asBEHAVE_CONSTRUCT ) continue;
if( func->GetParamCount() == 0 )
{
// Found the default constructor
found = true;
break;
}
}
if( !found )
{
// There is no default constructor
ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor");
return false;
}
}
else if( (flags & asOBJ_REF) )
{
bool found = false;
// If value assignment for ref type has been disabled then the array
// can be created if the type has a default factory function
if( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) )
{
// Verify that there is a default factory
for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ )
{
asIScriptFunction *func = subtype->GetFactoryByIndex(n);
if( func->GetParamCount() == 0 )
{
// Found the default factory
found = true;
break;
}
}
}
if( !found )
{
// No default factory
ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory");
return false;
}
}
// If the object type is not garbage collected then the array also doesn't need to be
if( !(flags & asOBJ_GC) )
dontGarbageCollect = true;
}
else if( !(typeId & asTYPEID_OBJHANDLE) )
{
// Arrays with primitives cannot form circular references,
// thus there is no need to garbage collect them
dontGarbageCollect = true;
}
else
{
assert( typeId & asTYPEID_OBJHANDLE );
// It is not necessary to set the array as garbage collected for all handle types.
// If it is possible to determine that the handle cannot refer to an object type
// that can potentially form a circular reference with the array then it is not
// necessary to make the array garbage collected.
asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId);
asDWORD flags = subtype->GetFlags();
if( !(flags & asOBJ_GC) )
{
if( (flags & asOBJ_SCRIPT_OBJECT) )
{
// Even if a script class is by itself not garbage collected, it is possible
// that classes that derive from it may be, so it is not possible to know
// that no circular reference can occur.
if( (flags & asOBJ_NOINHERIT) )
{
// A script class declared as final cannot be inherited from, thus
// we can be certain that the object cannot be garbage collected.
dontGarbageCollect = true;
}
}
else
{
// For application registered classes we assume the application knows
// what it is doing and don't mark the array as garbage collected unless
// the type is also garbage collected.
dontGarbageCollect = true;
}
}
}
// The type is ok
return true;
}
// Registers the template array type
void RegisterScriptGrid(asIScriptEngine *engine)
{
// TODO: Implement the generic calling convention
RegisterScriptGrid_Native(engine);
}
static void RegisterScriptGrid_Native(asIScriptEngine *engine)
{
int r;
// Register the grid type as a template
r = engine->RegisterObjectType("grid<class T>", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 );
// Register a callback for validating the subtype before it is used
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptGridTemplateCallback), asCALL_CDECL); assert( r >= 0 );
// Templates receive the object type as the first parameter. To the script writer this is hidden
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_FACTORY, "grid<T>@ f(int&in)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_FACTORY, "grid<T>@ f(int&in, uint, uint)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, asUINT, asUINT), CScriptGrid*), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_FACTORY, "grid<T>@ f(int&in, uint, uint, const T &in)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, asUINT, asUINT, void *), CScriptGrid*), asCALL_CDECL); assert( r >= 0 );
// Register the factory that will be used for initialization lists
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_LIST_FACTORY, "grid<T>@ f(int&in type, int&in list) {repeat {repeat_same T}}", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, void*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 );
// The memory management methods
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptGrid,AddRef), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptGrid,Release), asCALL_THISCALL); assert( r >= 0 );
// The index operator returns the template subtype
r = engine->RegisterObjectMethod("grid<T>", "T &opIndex(uint, uint)", asMETHODPR(CScriptGrid, At, (asUINT, asUINT), void*), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("grid<T>", "const T &opIndex(uint, uint) const", asMETHODPR(CScriptGrid, At, (asUINT, asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 );
// Other methods
r = engine->RegisterObjectMethod("grid<T>", "void resize(uint width, uint height)", asMETHODPR(CScriptGrid, Resize, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("grid<T>", "uint width() const", asMETHOD(CScriptGrid, GetWidth), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("grid<T>", "uint height() const", asMETHOD(CScriptGrid, GetHeight), asCALL_THISCALL); assert( r >= 0 );
// Register GC behaviours in case the array needs to be garbage collected
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptGrid, GetRefCount), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptGrid, SetFlag), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptGrid, GetFlag), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptGrid, EnumReferences), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("grid<T>", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptGrid, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 );
}
CScriptGrid::CScriptGrid(asITypeInfo *ti, void *buf)
{
refCount = 1;
gcFlag = false;
objType = ti;
objType->AddRef();
buffer = 0;
subTypeId = objType->GetSubTypeId();
asIScriptEngine *engine = ti->GetEngine();
// Determine element size
if( subTypeId & asTYPEID_MASK_OBJECT )
elementSize = sizeof(asPWORD);
else
elementSize = engine->GetSizeOfPrimitiveType(subTypeId);
// Determine the initial size from the buffer
asUINT height = *(asUINT*)buf;
asUINT width = height ? *(asUINT*)((char*)(buf)+4) : 0;
// Make sure the grid size isn't too large for us to handle
if( !CheckMaxSize(width, height) )
{
// Don't continue with the initialization
return;
}
// Skip the height value at the start of the buffer
buf = (asUINT*)(buf)+1;
// Copy the values of the grid elements from the buffer
if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 )
{
CreateBuffer(&buffer, width, height);
// Copy the values of the primitive type into the internal buffer
for( asUINT y = 0; y < height; y++ )
{
// Skip the length value at the start of each row
buf = (asUINT*)(buf)+1;
// Copy the line
if( width > 0 )
memcpy(At(0,y), buf, width*elementSize);
// Move to next line
buf = (char*)(buf) + width*elementSize;
// Align to 4 byte boundary
if( asPWORD(buf) & 0x3 )
buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3);
}
}
else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE )
{
CreateBuffer(&buffer, width, height);
// Copy the handles into the internal buffer
for( asUINT y = 0; y < height; y++ )
{
// Skip the length value at the start of each row
buf = (asUINT*)(buf)+1;
// Copy the line
if( width > 0 )
memcpy(At(0,y), buf, width*elementSize);
// With object handles it is safe to clear the memory in the received buffer
// instead of increasing the ref count. It will save time both by avoiding the
// call the increase ref, and also relieve the engine from having to release
// its references too
memset(buf, 0, width*elementSize);
// Move to next line
buf = (char*)(buf) + width*elementSize;
// Align to 4 byte boundary
if( asPWORD(buf) & 0x3 )
buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3);
}
}
else if( ti->GetSubType()->GetFlags() & asOBJ_REF )
{
// Only allocate the buffer, but not the objects
subTypeId |= asTYPEID_OBJHANDLE;
CreateBuffer(&buffer, width, height);
subTypeId &= ~asTYPEID_OBJHANDLE;
// Copy the handles into the internal buffer
for( asUINT y = 0; y < height; y++ )
{
// Skip the length value at the start of each row
buf = (asUINT*)(buf)+1;
// Copy the line
if( width > 0 )
memcpy(At(0,y), buf, width*elementSize);
// With object handles it is safe to clear the memory in the received buffer
// instead of increasing the ref count. It will save time both by avoiding the
// call the increase ref, and also relieve the engine from having to release
// its references too
memset(buf, 0, width*elementSize);
// Move to next line
buf = (char*)(buf) + width*elementSize;
// Align to 4 byte boundary
if( asPWORD(buf) & 0x3 )
buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3);
}
}
else
{
// TODO: Optimize by calling the copy constructor of the object instead of
// constructing with the default constructor and then assigning the value
// TODO: With C++11 ideally we should be calling the move constructor, instead
// of the copy constructor as the engine will just discard the objects in the
// buffer afterwards.
CreateBuffer(&buffer, width, height);
// For value types we need to call the opAssign for each individual object
asITypeInfo *subType = ti->GetSubType();
asUINT subTypeSize = subType->GetSize();
for( asUINT y = 0;y < height; y++ )
{
// Skip the length value at the start of each row
buf = (asUINT*)(buf)+1;
// Call opAssign for each of the objects on the row
for( asUINT x = 0; x < width; x++ )
{
void *obj = At(x,y);
asBYTE *srcObj = (asBYTE*)(buf) + x*subTypeSize;
engine->AssignScriptObject(obj, srcObj, subType);
}
// Move to next line
buf = (char*)(buf) + width*subTypeSize;
// Align to 4 byte boundary
if( asPWORD(buf) & 0x3 )
buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3);
}
}
// Notify the GC of the successful creation
if( objType->GetFlags() & asOBJ_GC )
objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
}
CScriptGrid::CScriptGrid(asUINT width, asUINT height, asITypeInfo *ti)
{
refCount = 1;
gcFlag = false;
objType = ti;
objType->AddRef();
buffer = 0;
subTypeId = objType->GetSubTypeId();
// Determine element size
if( subTypeId & asTYPEID_MASK_OBJECT )
elementSize = sizeof(asPWORD);
else
elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId);
// Make sure the array size isn't too large for us to handle
if( !CheckMaxSize(width, height) )
{
// Don't continue with the initialization
return;
}
CreateBuffer(&buffer, width, height);
// Notify the GC of the successful creation
if( objType->GetFlags() & asOBJ_GC )
objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
}
void CScriptGrid::Resize(asUINT width, asUINT height)
{
// Make sure the size isn't too large for us to handle
if( !CheckMaxSize(width, height) )
return;
// Create a new buffer
SGridBuffer *tmpBuffer = 0;
CreateBuffer(&tmpBuffer, width, height);
if( tmpBuffer == 0 )
return;
if( buffer )
{
// Copy the existing values to the new buffer
asUINT w = width > buffer->width ? buffer->width : width;
asUINT h = height > buffer->height ? buffer->height : height;
for( asUINT y = 0; y < h; y++ )
for( asUINT x = 0; x < w; x++ )
SetValue(tmpBuffer, x, y, At(buffer, x, y));
// Replace the internal buffer
DeleteBuffer(buffer);
}
buffer = tmpBuffer;
}
CScriptGrid::CScriptGrid(asUINT width, asUINT height, void *defVal, asITypeInfo *ti)
{
refCount = 1;
gcFlag = false;
objType = ti;
objType->AddRef();
buffer = 0;
subTypeId = objType->GetSubTypeId();
// Determine element size
if( subTypeId & asTYPEID_MASK_OBJECT )
elementSize = sizeof(asPWORD);
else
elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId);
// Make sure the array size isn't too large for us to handle
if( !CheckMaxSize(width, height) )
{
// Don't continue with the initialization
return;
}
CreateBuffer(&buffer, width, height);
// Notify the GC of the successful creation
if( objType->GetFlags() & asOBJ_GC )
objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType);
// Initialize the elements with the default value
for( asUINT y = 0; y < GetHeight(); y++ )
for( asUINT x = 0; x < GetWidth(); x++ )
SetValue(x, y, defVal);
}
void CScriptGrid::SetValue(asUINT x, asUINT y, void *value)
{
SetValue(buffer, x, y, value);
}
void CScriptGrid::SetValue(SGridBuffer *buf, asUINT x, asUINT y, void *value)
{
// At() will take care of the out-of-bounds checking, though
// if called from the application then nothing will be done
void *ptr = At(buf, x, y);
if( ptr == 0 ) return;
if( (subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE) )
objType->GetEngine()->AssignScriptObject(ptr, value, objType->GetSubType());
else if( subTypeId & asTYPEID_OBJHANDLE )
{
void *tmp = *(void**)ptr;
*(void**)ptr = *(void**)value;
objType->GetEngine()->AddRefScriptObject(*(void**)value, objType->GetSubType());
if( tmp )
objType->GetEngine()->ReleaseScriptObject(tmp, objType->GetSubType());
}
else if( subTypeId == asTYPEID_BOOL ||
subTypeId == asTYPEID_INT8 ||
subTypeId == asTYPEID_UINT8 )
*(char*)ptr = *(char*)value;
else if( subTypeId == asTYPEID_INT16 ||
subTypeId == asTYPEID_UINT16 )
*(short*)ptr = *(short*)value;
else if( subTypeId == asTYPEID_INT32 ||
subTypeId == asTYPEID_UINT32 ||
subTypeId == asTYPEID_FLOAT ||
subTypeId > asTYPEID_DOUBLE ) // enums have a type id larger than doubles
*(int*)ptr = *(int*)value;
else if( subTypeId == asTYPEID_INT64 ||
subTypeId == asTYPEID_UINT64 ||
subTypeId == asTYPEID_DOUBLE )
*(double*)ptr = *(double*)value;
}
CScriptGrid::~CScriptGrid()
{
if( buffer )
{
DeleteBuffer(buffer);
buffer = 0;
}
if( objType ) objType->Release();
}
asUINT CScriptGrid::GetWidth() const
{
if( buffer )
return buffer->width;
return 0;
}
asUINT CScriptGrid::GetHeight() const
{
if( buffer )
return buffer->height;
return 0;
}
// internal
bool CScriptGrid::CheckMaxSize(asUINT width, asUINT height)
{
// This code makes sure the size of the buffer that is allocated
// for the array doesn't overflow and becomes smaller than requested
asUINT maxSize = 0xFFFFFFFFul - sizeof(SGridBuffer) + 1;
if( elementSize > 0 )
maxSize /= elementSize;
asINT64 numElements = width * height;
if( (numElements >> 32) || numElements > maxSize )
{
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Too large grid size");
return false;
}
// OK
return true;
}
asITypeInfo *CScriptGrid::GetGridObjectType() const
{
return objType;
}
int CScriptGrid::GetGridTypeId() const
{
return objType->GetTypeId();
}
int CScriptGrid::GetElementTypeId() const
{
return subTypeId;
}
void *CScriptGrid::At(asUINT x, asUINT y)
{
return At(buffer, x, y);
}
// Return a pointer to the array element. Returns 0 if the index is out of bounds
void *CScriptGrid::At(SGridBuffer *buf, asUINT x, asUINT y)
{
if( buf == 0 || x >= buf->width || y >= buf->height )
{
// If this is called from a script we raise a script exception
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Index out of bounds");
return 0;
}
asUINT index = x+y*buf->width;
if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) )
return *(void**)(buf->data + elementSize*index);
else
return buf->data + elementSize*index;
}
const void *CScriptGrid::At(asUINT x, asUINT y) const
{
return const_cast<CScriptGrid*>(this)->At(const_cast<SGridBuffer*>(buffer), x, y);
}
// internal
void CScriptGrid::CreateBuffer(SGridBuffer **buf, asUINT w, asUINT h)
{
asUINT numElements = w * h;
*buf = reinterpret_cast<SGridBuffer*>(userAlloc(sizeof(SGridBuffer)-1+elementSize*numElements));
if( *buf )
{
(*buf)->width = w;
(*buf)->height = h;
Construct(*buf);
}
else
{
// Oops, out of memory
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Out of memory");
}
}
// internal
void CScriptGrid::DeleteBuffer(SGridBuffer *buf)
{
assert( buf );
Destruct(buf);
// Free the buffer
userFree(buf);
}
// internal
void CScriptGrid::Construct(SGridBuffer *buf)
{
assert( buf );
if( subTypeId & asTYPEID_OBJHANDLE )
{
// Set all object handles to null
void *d = (void*)(buf->data);
memset(d, 0, (buf->width*buf->height)*sizeof(void*));
}
else if( subTypeId & asTYPEID_MASK_OBJECT )
{
void **max = (void**)(buf->data + (buf->width*buf->height) * sizeof(void*));
void **d = (void**)(buf->data);
asIScriptEngine *engine = objType->GetEngine();
asITypeInfo *subType = objType->GetSubType();
for( ; d < max; d++ )
{
*d = (void*)engine->CreateScriptObject(subType);
if( *d == 0 )
{
// Set the remaining entries to null so the destructor
// won't attempt to destroy invalid objects later
memset(d, 0, sizeof(void*)*(max-d));
// There is no need to set an exception on the context,
// as CreateScriptObject has already done that
return;
}
}
}
}
// internal
void CScriptGrid::Destruct(SGridBuffer *buf)
{
assert( buf );
if( subTypeId & asTYPEID_MASK_OBJECT )
{
asIScriptEngine *engine = objType->GetEngine();
void **max = (void**)(buf->data + (buf->width*buf->height) * sizeof(void*));
void **d = (void**)(buf->data);
for( ; d < max; d++ )
{
if( *d )
engine->ReleaseScriptObject(*d, objType->GetSubType());
}
}
}
// GC behaviour
void CScriptGrid::EnumReferences(asIScriptEngine *engine)
{
if( buffer == 0 ) return;
// If the grid is holding handles, then we need to notify the GC of them
if (subTypeId & asTYPEID_MASK_OBJECT)
{
asUINT numElements = buffer->width * buffer->height;
void **d = (void**)buffer->data;
asITypeInfo *subType = engine->GetTypeInfoById(subTypeId);
if ((subType->GetFlags() & asOBJ_REF))
{
// For reference types we need to notify the GC of each instance
for (asUINT n = 0; n < numElements; n++)
{
if (d[n])
engine->GCEnumCallback(d[n]);
}
}
else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC))
{
// For value types we need to forward the enum callback
// to the object so it can decide what to do
for (asUINT n = 0; n < numElements; n++)
{
if (d[n])
engine->ForwardGCEnumReferences(d[n], subType);
}
}
}
}
// GC behaviour
void CScriptGrid::ReleaseAllHandles(asIScriptEngine*)
{
if( buffer == 0 ) return;
DeleteBuffer(buffer);
buffer = 0;
}
void CScriptGrid::AddRef() const
{
// Clear the GC flag then increase the counter
gcFlag = false;
asAtomicInc(refCount);
}
void CScriptGrid::Release() const
{
// Clearing the GC flag then descrease the counter
gcFlag = false;
if( asAtomicDec(refCount) == 0 )
{
// When reaching 0 no more references to this instance
// exists and the object should be destroyed
this->~CScriptGrid();
userFree(const_cast<CScriptGrid*>(this));
}
}
// GC behaviour
int CScriptGrid::GetRefCount()
{
return refCount;
}
// GC behaviour
void CScriptGrid::SetFlag()
{
gcFlag = true;
}
// GC behaviour
bool CScriptGrid::GetFlag()
{
return gcFlag;
}
END_AS_NAMESPACE