2021-04-12 18:25:02 +00:00
# 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 )
{
2022-04-10 10:08:18 +00:00
[[maybe_unused]] int r ;
2021-04-12 18:25:02 +00:00
// 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