mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-12-19 17:37:42 -05:00
631 lines
19 KiB
C++
631 lines
19 KiB
C++
/*
|
|
AngelCode Scripting Library
|
|
Copyright (c) 2003-2009 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
|
|
*/
|
|
|
|
|
|
#include <new>
|
|
#include <stdlib.h>
|
|
|
|
#include "as_config.h"
|
|
#include "as_arrayobject.h"
|
|
#include "as_texts.h"
|
|
|
|
BEGIN_AS_NAMESPACE
|
|
|
|
struct sArrayBuffer
|
|
{
|
|
asDWORD numElements;
|
|
asBYTE data[1];
|
|
};
|
|
|
|
static asCArrayObject* ArrayObjectFactory2(asIObjectType *ot, asUINT length)
|
|
{
|
|
asCArrayObject *a = asNEW(asCArrayObject)(length, ot);
|
|
|
|
// It's possible the constructor raised a script exception, in which case we
|
|
// need to free the memory and return null instead, else we get a memory leak.
|
|
asIScriptContext *ctx = asGetActiveContext();
|
|
if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION )
|
|
{
|
|
asDELETE(a, asCArrayObject);
|
|
return 0;
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
asCArrayObject* ArrayObjectFactory(asIObjectType *ot)
|
|
{
|
|
return ArrayObjectFactory2(ot, 0);
|
|
}
|
|
|
|
#ifndef AS_MAX_PORTABILITY
|
|
|
|
static asCArrayObject &ArrayObjectAssignment(asCArrayObject *other, asCArrayObject *self)
|
|
{
|
|
return *self = *other;
|
|
}
|
|
|
|
static void *ArrayObjectAt(asUINT index, asCArrayObject *self)
|
|
{
|
|
return self->at(index);
|
|
}
|
|
|
|
static asUINT ArrayObjectLength(asCArrayObject *self)
|
|
{
|
|
return self->GetElementCount();
|
|
}
|
|
static void ArrayObjectResize(asUINT size, asCArrayObject *self)
|
|
{
|
|
self->Resize(size);
|
|
}
|
|
|
|
#else
|
|
|
|
static void ArrayObjectFactory_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0);
|
|
|
|
*(asCArrayObject**)gen->GetAddressOfReturnLocation() = ArrayObjectFactory(ot);
|
|
}
|
|
|
|
static void ArrayObjectFactory2_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0);
|
|
asUINT length = gen->GetArgDWord(1);
|
|
|
|
*(asCArrayObject**)gen->GetAddressOfReturnLocation() = ArrayObjectFactory2(ot, length);
|
|
}
|
|
|
|
static void ArrayObjectAssignment_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *other = (asCArrayObject*)gen->GetArgObject(0);
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
|
|
*self = *other;
|
|
|
|
gen->SetReturnObject(self);
|
|
}
|
|
|
|
static void ArrayObjectAt_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asUINT index = gen->GetArgDWord(0);
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
|
|
gen->SetReturnAddress(self->at(index));
|
|
}
|
|
|
|
static void ArrayObjectLength_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
|
|
gen->SetReturnDWord(self->GetElementCount());
|
|
}
|
|
|
|
static void ArrayObjectResize_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asUINT size = gen->GetArgDWord(0);
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
|
|
self->Resize(size);
|
|
}
|
|
|
|
static void ArrayObject_AddRef_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
self->AddRef();
|
|
}
|
|
|
|
static void ArrayObject_Release_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
self->Release();
|
|
}
|
|
|
|
static void ArrayObject_GetRefCount_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
|
|
}
|
|
|
|
static void ArrayObject_SetFlag_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
self->SetFlag();
|
|
}
|
|
|
|
static void ArrayObject_GetFlag_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
*(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag();
|
|
}
|
|
|
|
static void ArrayObject_EnumReferences_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
|
self->EnumReferences(engine);
|
|
}
|
|
|
|
static void ArrayObject_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
|
|
{
|
|
asCArrayObject *self = (asCArrayObject*)gen->GetObject();
|
|
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
|
|
self->ReleaseAllHandles(engine);
|
|
}
|
|
|
|
#endif
|
|
|
|
void RegisterArrayObject(asIScriptEngine *engine)
|
|
{
|
|
int r;
|
|
|
|
r = engine->RegisterObjectType("_builtin_array_<class T>", sizeof(asCArrayObject), asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); asASSERT( r >= 0 );
|
|
#ifndef AS_MAX_PORTABILITY
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_FACTORY, "_builtin_array_<T>@ f(int&in)", asFUNCTIONPR(ArrayObjectFactory, (asIObjectType*), asCArrayObject*), asCALL_CDECL); asASSERT( r >= 0 );
|
|
// TODO: initlist: Need a special behaviour for this
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_FACTORY, "_builtin_array_<T>@ f(int&in, uint)", asFUNCTIONPR(ArrayObjectFactory2, (asIObjectType*, asUINT), asCArrayObject*), asCALL_CDECL); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(asCArrayObject,AddRef), asCALL_THISCALL); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_RELEASE, "void f()", asMETHOD(asCArrayObject,Release), asCALL_THISCALL); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectMethod("_builtin_array_<T>", "_builtin_array_<T> &opAssign(const _builtin_array_<T>&in)", asFUNCTION(ArrayObjectAssignment), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_INDEX, "T &f(uint)", asFUNCTION(ArrayObjectAt), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_INDEX, "const T &f(uint) const", asFUNCTION(ArrayObjectAt), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectMethod("_builtin_array_<T>", "uint length() const", asFUNCTION(ArrayObjectLength), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectMethod("_builtin_array_<T>", "void resize(uint)", asFUNCTION(ArrayObjectResize), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 );
|
|
|
|
// Register GC behaviours
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCArrayObject,GetRefCount), asCALL_THISCALL); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCArrayObject,SetFlag), asCALL_THISCALL); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCArrayObject,GetFlag), asCALL_THISCALL); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCArrayObject,EnumReferences), asCALL_THISCALL); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCArrayObject,ReleaseAllHandles), asCALL_THISCALL); asASSERT( r >= 0 );
|
|
#else
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_FACTORY, "_builtin_array_<T>@ f(int&in)", asFUNCTION(ArrayObjectFactory_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
// TODO: initlist: Need a special behaviour for this
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_FACTORY, "_builtin_array_<T>@ f(int&in, uint)", asFUNCTION(ArrayObjectFactory2_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_ADDREF, "void f()", asFUNCTION(ArrayObject_AddRef_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_RELEASE, "void f()", asFUNCTION(ArrayObject_Release_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectMethod("_builtin_array_<T>", "_builtin_array_<T> &opAssign(const _builtin_array_<T>&in)", asFUNCTION(ArrayObjectAssignment_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_INDEX, "T &f(uint)", asFUNCTION(ArrayObjectAt_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_INDEX, "const T &f(uint) const", asFUNCTION(ArrayObjectAt_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectMethod("_builtin_array_<T>", "uint length() const", asFUNCTION(ArrayObjectLength_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectMethod("_builtin_array_<T>", "void resize(uint)", asFUNCTION(ArrayObjectResize_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
|
|
// Register GC behaviours
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ArrayObject_GetRefCount_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ArrayObject_SetFlag_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ArrayObject_GetFlag_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ArrayObject_EnumReferences_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
r = engine->RegisterObjectBehaviour("_builtin_array_<T>", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ArrayObject_ReleaseAllHandles_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
|
|
#endif
|
|
}
|
|
|
|
asCArrayObject &asCArrayObject::operator=(asCArrayObject &other)
|
|
{
|
|
if( &other != this )
|
|
{
|
|
if( buffer )
|
|
{
|
|
DeleteBuffer(buffer);
|
|
buffer = 0;
|
|
}
|
|
|
|
// Copy all elements from the other array
|
|
CreateBuffer(&buffer, other.buffer->numElements);
|
|
CopyBuffer(buffer, other.buffer);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
int asCArrayObject::CopyFrom(asIScriptArray *other)
|
|
{
|
|
if( other == 0 ) return asINVALID_ARG;
|
|
|
|
// Verify that the types are equal
|
|
if( GetArrayTypeId() != other->GetArrayTypeId() )
|
|
return asINVALID_TYPE;
|
|
|
|
*this = *(asCArrayObject*)other;
|
|
|
|
return 0;
|
|
}
|
|
|
|
asCArrayObject::asCArrayObject(asUINT length, asIObjectType *ot)
|
|
{
|
|
refCount.set(1);
|
|
gcFlag = false;
|
|
objType = ot;
|
|
objType->AddRef();
|
|
buffer = 0;
|
|
|
|
// Determine element size
|
|
int typeId = objType->GetSubTypeId();
|
|
if( typeId & asTYPEID_MASK_OBJECT )
|
|
{
|
|
elementSize = sizeof(asPWORD);
|
|
}
|
|
else
|
|
{
|
|
elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(typeId);
|
|
}
|
|
|
|
isArrayOfHandles = typeId & asTYPEID_OBJHANDLE ? true : false;
|
|
|
|
// Make sure the array size isn't too large for us to handle
|
|
if( !CheckMaxSize(length) )
|
|
{
|
|
// Don't continue with the initialization
|
|
return;
|
|
}
|
|
|
|
CreateBuffer(&buffer, length);
|
|
|
|
// Notify the GC of the successful creation
|
|
if( objType->GetFlags() & asOBJ_GC )
|
|
objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType->GetTypeId());
|
|
}
|
|
|
|
asCArrayObject::~asCArrayObject()
|
|
{
|
|
if( buffer )
|
|
{
|
|
DeleteBuffer(buffer);
|
|
buffer = 0;
|
|
}
|
|
if( objType ) objType->Release();
|
|
}
|
|
|
|
asIScriptEngine *asCArrayObject::GetEngine() const
|
|
{
|
|
return objType->GetEngine();
|
|
}
|
|
|
|
asUINT asCArrayObject::GetElementCount()
|
|
{
|
|
return buffer->numElements;
|
|
}
|
|
|
|
void asCArrayObject::Resize(asUINT numElements)
|
|
{
|
|
// Don't do anything if the size is already correct
|
|
if( numElements == buffer->numElements )
|
|
return;
|
|
|
|
// Make sure the array size isn't too large for us to handle
|
|
if( !CheckMaxSize(numElements) )
|
|
{
|
|
// Don't resize the array
|
|
return;
|
|
}
|
|
|
|
sArrayBuffer *newBuffer;
|
|
int typeId = objType->GetSubTypeId();
|
|
if( typeId & asTYPEID_MASK_OBJECT )
|
|
{
|
|
// Allocate memory for the buffer
|
|
newBuffer = (sArrayBuffer*)asNEWARRAY(asBYTE, sizeof(sArrayBuffer)-1+sizeof(void*)*numElements);
|
|
newBuffer->numElements = numElements;
|
|
|
|
// Copy the elements from the old buffer
|
|
int c = numElements > buffer->numElements ? buffer->numElements : numElements;
|
|
asDWORD **d = (asDWORD**)newBuffer->data;
|
|
asDWORD **s = (asDWORD**)buffer->data;
|
|
for( int n = 0; n < c; n++ )
|
|
d[n] = s[n];
|
|
|
|
if( numElements > buffer->numElements )
|
|
{
|
|
Construct(newBuffer, buffer->numElements, numElements);
|
|
}
|
|
else if( numElements < buffer->numElements )
|
|
{
|
|
Destruct(buffer, numElements, buffer->numElements);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Allocate memory for the buffer
|
|
newBuffer = (sArrayBuffer*)asNEWARRAY(asBYTE, sizeof(sArrayBuffer)-1+elementSize*numElements);
|
|
newBuffer->numElements = numElements;
|
|
|
|
int c = numElements > buffer->numElements ? buffer->numElements : numElements;
|
|
memcpy(newBuffer->data, buffer->data, c*elementSize);
|
|
}
|
|
|
|
// Release the old buffer
|
|
userFree(buffer);
|
|
|
|
buffer = newBuffer;
|
|
}
|
|
|
|
// internal
|
|
bool asCArrayObject::CheckMaxSize(asUINT numElements)
|
|
{
|
|
// 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(sArrayBuffer) + 1;
|
|
if( objType->GetSubTypeId() & asTYPEID_MASK_OBJECT )
|
|
{
|
|
maxSize /= sizeof(void*);
|
|
}
|
|
else
|
|
{
|
|
maxSize /= elementSize;
|
|
}
|
|
|
|
if( numElements > maxSize )
|
|
{
|
|
asIScriptContext *ctx = asGetActiveContext();
|
|
if( ctx )
|
|
{
|
|
// Set a script exception
|
|
ctx->SetException("Too large array size");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// OK
|
|
return true;
|
|
}
|
|
|
|
int asCArrayObject::GetArrayTypeId()
|
|
{
|
|
return objType->GetTypeId();
|
|
}
|
|
|
|
int asCArrayObject::GetElementTypeId()
|
|
{
|
|
return objType->GetSubTypeId();
|
|
}
|
|
|
|
void *asCArrayObject::GetElementPointer(asUINT index)
|
|
{
|
|
if( index >= buffer->numElements ) return 0;
|
|
|
|
int typeId = objType->GetSubTypeId();
|
|
if( (typeId & asTYPEID_MASK_OBJECT) && !isArrayOfHandles )
|
|
return (void*)((size_t*)buffer->data)[index];
|
|
else
|
|
return buffer->data + elementSize*index;
|
|
}
|
|
|
|
void *asCArrayObject::at(asUINT index)
|
|
{
|
|
if( index >= buffer->numElements )
|
|
{
|
|
asIScriptContext *ctx = asGetActiveContext();
|
|
if( ctx )
|
|
ctx->SetException(TXT_OUT_OF_BOUNDS);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
int typeId = objType->GetSubTypeId();
|
|
if( (typeId & asTYPEID_MASK_OBJECT) && !isArrayOfHandles )
|
|
return (void*)((size_t*)buffer->data)[index];
|
|
else
|
|
return buffer->data + elementSize*index;
|
|
}
|
|
}
|
|
|
|
void asCArrayObject::CreateBuffer(sArrayBuffer **buf, asUINT numElements)
|
|
{
|
|
int typeId = objType->GetSubTypeId();
|
|
if( typeId & asTYPEID_MASK_OBJECT )
|
|
{
|
|
*buf = (sArrayBuffer*)asNEWARRAY(asBYTE, sizeof(sArrayBuffer)-1+sizeof(void*)*numElements);
|
|
(*buf)->numElements = numElements;
|
|
}
|
|
else
|
|
{
|
|
*buf = (sArrayBuffer*)asNEWARRAY(asBYTE, sizeof(sArrayBuffer)-1+elementSize*numElements);
|
|
(*buf)->numElements = numElements;
|
|
}
|
|
|
|
Construct(*buf, 0, numElements);
|
|
}
|
|
|
|
void asCArrayObject::DeleteBuffer(sArrayBuffer *buf)
|
|
{
|
|
Destruct(buf, 0, buf->numElements);
|
|
|
|
// Free the buffer
|
|
asDELETEARRAY(buf);
|
|
}
|
|
|
|
void asCArrayObject::Construct(sArrayBuffer *buf, asUINT start, asUINT end)
|
|
{
|
|
int typeId = objType->GetSubTypeId();
|
|
if( isArrayOfHandles )
|
|
{
|
|
// Set all object handles to null
|
|
asDWORD *d = (asDWORD*)(buf->data + start * sizeof(void*));
|
|
memset(d, 0, (end-start)*sizeof(void*));
|
|
}
|
|
else if( typeId & asTYPEID_MASK_OBJECT )
|
|
{
|
|
asDWORD **max = (asDWORD**)(buf->data + end * sizeof(void*));
|
|
asDWORD **d = (asDWORD**)(buf->data + start * sizeof(void*));
|
|
|
|
asIScriptEngine *engine = objType->GetEngine();
|
|
|
|
for( ; d < max; d++ )
|
|
*d = (asDWORD*)engine->CreateScriptObject(typeId);
|
|
}
|
|
}
|
|
|
|
void asCArrayObject::Destruct(sArrayBuffer *buf, asUINT start, asUINT end)
|
|
{
|
|
int typeId = objType->GetSubTypeId();
|
|
if( typeId & asTYPEID_MASK_OBJECT )
|
|
{
|
|
asIScriptEngine *engine = objType->GetEngine();
|
|
|
|
asDWORD **max = (asDWORD**)(buf->data + end * sizeof(void*));
|
|
asDWORD **d = (asDWORD**)(buf->data + start * sizeof(void*));
|
|
|
|
for( ; d < max; d++ )
|
|
{
|
|
if( *d )
|
|
engine->ReleaseScriptObject(*d, typeId);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void asCArrayObject::CopyBuffer(sArrayBuffer *dst, sArrayBuffer *src)
|
|
{
|
|
asIScriptEngine *engine = objType->GetEngine();
|
|
if( isArrayOfHandles )
|
|
{
|
|
// Copy the references and increase the reference counters
|
|
if( dst->numElements > 0 && src->numElements > 0 )
|
|
{
|
|
int typeId = objType->GetSubTypeId();
|
|
int count = dst->numElements > src->numElements ? src->numElements : dst->numElements;
|
|
|
|
asDWORD **max = (asDWORD**)(dst->data + count * sizeof(void*));
|
|
asDWORD **d = (asDWORD**)dst->data;
|
|
asDWORD **s = (asDWORD**)src->data;
|
|
|
|
for( ; d < max; d++, s++ )
|
|
{
|
|
*d = *s;
|
|
if( *d )
|
|
engine->AddRefScriptObject(*d, typeId);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int typeId = objType->GetSubTypeId();
|
|
|
|
if( dst->numElements > 0 && src->numElements > 0 )
|
|
{
|
|
int count = dst->numElements > src->numElements ? src->numElements : dst->numElements;
|
|
if( typeId & asTYPEID_MASK_OBJECT )
|
|
{
|
|
// Call the assignment operator on all of the objects
|
|
asDWORD **max = (asDWORD**)(dst->data + count * sizeof(void*));
|
|
asDWORD **d = (asDWORD**)dst->data;
|
|
asDWORD **s = (asDWORD**)src->data;
|
|
|
|
for( ; d < max; d++, s++ )
|
|
engine->CopyScriptObject(*d, *s, typeId);
|
|
}
|
|
else
|
|
{
|
|
// Primitives are copied byte for byte
|
|
memcpy(dst->data, src->data, count*elementSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void asCArrayObject::Destruct()
|
|
{
|
|
// Call destructor and free the memory
|
|
asDELETE(this, asCArrayObject);
|
|
}
|
|
|
|
void asCArrayObject::EnumReferences(asIScriptEngine *engine)
|
|
{
|
|
// If the array is holding handles, then we need to notify the GC of them
|
|
int typeId = objType->GetSubTypeId();
|
|
if( typeId & asTYPEID_MASK_OBJECT )
|
|
{
|
|
void **d = (void**)buffer->data;
|
|
for( asUINT n = 0; n < buffer->numElements; n++ )
|
|
{
|
|
if( d[n] )
|
|
engine->GCEnumCallback(d[n]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void asCArrayObject::ReleaseAllHandles(asIScriptEngine *engine)
|
|
{
|
|
int subTypeId = objType->GetSubTypeId();
|
|
asIObjectType *subType = engine->GetObjectTypeById(subTypeId);
|
|
if( subType && subType->GetFlags() & asOBJ_GC )
|
|
{
|
|
void **d = (void**)buffer->data;
|
|
for( asUINT n = 0; n < buffer->numElements; n++ )
|
|
{
|
|
if( d[n] )
|
|
{
|
|
engine->ReleaseScriptObject(d[n], subTypeId);
|
|
d[n] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int asCArrayObject::AddRef()
|
|
{
|
|
// Clear the GC flag then increase the counter
|
|
gcFlag = false;
|
|
return refCount.atomicInc();
|
|
}
|
|
|
|
int asCArrayObject::Release()
|
|
{
|
|
// Now do the actual releasing (clearing the flag set by GC)
|
|
gcFlag = false;
|
|
int r = refCount.atomicDec();
|
|
if( r == 0 )
|
|
{
|
|
Destruct();
|
|
return 0;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
int asCArrayObject::GetRefCount()
|
|
{
|
|
return refCount.get();
|
|
}
|
|
|
|
void asCArrayObject::SetFlag()
|
|
{
|
|
gcFlag = true;
|
|
}
|
|
|
|
bool asCArrayObject::GetFlag()
|
|
{
|
|
return gcFlag;
|
|
}
|
|
|
|
END_AS_NAMESPACE
|