Okay, I edited this thinking I got it working but I was wrong. What I am doing is trying to get a multi-dimensional array class with template args working. It's only meant to be used right now by basic types handled with template specialization so it's not very robust, but I need a class that can handle up to three-dimensional arrays of different types.
What happens right now is I get a crash on
Array<int> arr;arr.resize( 64, 64, 64 ); //worksint temp = arr.at( 2 ); <--here
I looked at the array add_on and I think I do the reference counting the same, though I'd wager dollars to donuts that I am making some very simple mistake. Hopefully someone can spot it quickly. Here is the code:
namespace scriptarraytemplate{template<class T>class ScriptArray{public: ScriptArray() : self(), ref_count(1), type(0) {} ScriptArray( uint x ) : self(x), ref_count(1), type(0) {} ScriptArray( uint y, uint x ) : self(y,x), ref_count(1), type(0) {} ScriptArray( uint z, uint y, uint x ) : self(z,y,x), ref_count(1), type(0) {} ScriptArray( const ScriptArray<T>& other ) : self(other.self), ref_count(1), type(0) {} ~ScriptArray() { if( type ) type->Release(); } void AddTypeRef( asIObjectType *objType ) { type = objType; type->AddRef(); } static ScriptArray<T>* ScriptArrayFactory() { ScriptArray<T> *a = new ScriptArray<T>(); return CheckScriptException( a ); } static ScriptArray<T>* ScriptArrayFactory1( uint x ) { ScriptArray<T> *a = new ScriptArray<T>( x ); return CheckScriptException( a ); } static ScriptArray<T>* ScriptArrayFactory2( uint y, uint x ) { ScriptArray<T> *a = new ScriptArray<T>( y, x ); return CheckScriptException( a ); } static ScriptArray<T>* ScriptArrayFactory3( uint z, uint y, uint x ) { ScriptArray<T> *a = new ScriptArray<T>( z, y, x ); return CheckScriptException( a ); } static ScriptArray<T>* ScriptArrayFactoryCopy( const ScriptArray<T>& _Array ) { ScriptArray<T> *a = new ScriptArray<T>( _Array ); return CheckScriptException( a ); }///////////////////////////////////////////////////////////// static ScriptArray<T>* _ScriptArrayFactory( asIObjectType *objType ) { ScriptArray<T> *a = new ScriptArray<T>(); a->AddTypeRef( objType ); return CheckScriptException( a ); } static ScriptArray<T>* _ScriptArrayFactory1( asIObjectType *objType, uint x ) { ScriptArray<T> *a = new ScriptArray<T>( x ); a->AddTypeRef( objType ); return CheckScriptException( a ); } static ScriptArray<T>* _ScriptArrayFactory2( asIObjectType *objType, uint y, uint x ) { ScriptArray<T> *a = new ScriptArray<T>( y, x ); a->AddTypeRef( objType ); return CheckScriptException( a ); } static ScriptArray<T>* _ScriptArrayFactory3( asIObjectType *objType, uint z, uint y, uint x ) { ScriptArray<T> *a = new ScriptArray<T>( z, y, x ); a->AddTypeRef( objType ); return CheckScriptException( a ); } static ScriptArray<T>* _ScriptArrayFactoryCopy( asIObjectType *objType, const ScriptArray<T>& _Array ) { ScriptArray<T> *a = new ScriptArray<T>( _Array ); a->AddTypeRef( objType ); return CheckScriptException( a ); }////////////////////////////////////////////////////////////// static ScriptArray<T> *CheckScriptException( ScriptArray<T>* _Array ) { // 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 ) { delete _Array; return 0; } return _Array; } ScriptArray<T>& AssignmentOperator( const ScriptArray<T>& rhs ) { self = rhs.self; return *this; } T* At1( uint x ) { if( x >= self.Size() ) { asIScriptContext* activeContext = asGetActiveContext(); if( activeContext ) activeContext->SetException("Array Index Out of Bounds."); return 0; } return &self( x ); } T* At2( uint y, uint x ) { if( self.Offset(y, x) >= self.Size() ) { asIScriptContext* activeContext = asGetActiveContext(); if( activeContext ) activeContext->SetException("Array Index Out of Bounds."); return 0; } return &self( y, x ); } T* At3( uint z, uint y, uint x ) { if( self.Offset(z, y, x) >= self.Size() ) { asIScriptContext* activeContext = asGetActiveContext(); if( activeContext ) activeContext->SetException("Array Index Out of Bounds."); return 0; } return &self( z, y, x ); } uint Size() { return self.Size(); } void Resize1( uint x ) { self.Resize(x); } void Resize2( uint y, uint x ) { self.Resize(y, x); } void Resize3( uint z, uint y, uint x ) { self.Resize(z, y, x); } bool Empty() { return self.Empty(); } uint Offset1( uint x, Array<T>* self ) { return x; } uint Offset2( uint y, uint x ) { return self.Offset(y, x); } uint Offset3( uint z, uint y, uint x ) { return self.Offset(z, y, x); } void Assign( uint begin, uint end, const T& value ) { self.Assign( begin, end, value ); } void AddRef() { ++ref_count; } void Release() { if( --ref_count <= 0 ) { delete this; } }protected: Array<T> self; int ref_count; asIObjectType *type;};} //namespace scriptarraytemplatevoid ScriptingEngine::RegisterScriptArrayTemplateSpecializations(){ RegisterArrayTemplate<int>( "Array<T>", "T" ); RegisterArrayTemplateSpecialization<int> ( "Array<int>", "int" ); //RegisterArrayTemplateSpecialization<float> ( "Array<float>", "float" ); //RegisterArrayTemplateSpecialization<ubColor> ( "Array<Color>", "Color" ); //RegisterArrayTemplateSpecialization<Vector2> ( "Array<Vector2>", "Vector2" );}template <class T>void ScriptingEngine::RegisterArrayTemplateSpecialization( const std::string decl, const std::string type ){ int r(0); using namespace scriptarraytemplate; const std::string const_ref( (std::string("const ") + type) + " &in" ); // register the array type r = engine->RegisterObjectType( decl.c_str(), 0, asOBJ_REF ); assert( r >= 0 ); // constructors r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, ( decl + " @f()" ).c_str(), asFUNCTION(ScriptArray<T>::ScriptArrayFactory), asCALL_CDECL ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, (((decl + " @f(") + const_ref) + ")" ).c_str(), asFUNCTION(ScriptArray<T>::ScriptArrayFactory1), asCALL_CDECL ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, (((((decl + " @f(") + const_ref) + "," ) + const_ref ) + ")" ).c_str(), asFUNCTION(ScriptArray<T>::ScriptArrayFactory2), asCALL_CDECL ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, (((((((decl + " @f(") + const_ref) + "," ) + const_ref ) + "," ) + const_ref ) + ")" ).c_str(), asFUNCTION(ScriptArray<T>::ScriptArrayFactory3), asCALL_CDECL ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, (((decl + " @f(const ") + decl) + " &in)" ).c_str(), asFUNCTION(ScriptArray<T>::ScriptArrayFactoryCopy), asCALL_CDECL ); assert( r >= 0 ); // index methods r = engine->RegisterObjectMethod( decl.c_str(), ( type + "& at(uint)" ).c_str(), asMETHOD(ScriptArray<T>, At1), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), ( type + "& at(uint, uint)" ).c_str(), asMETHOD(ScriptArray<T>, At2), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), ( type + "& at(uint, uint, uint)" ).c_str(), asMETHOD(ScriptArray<T>, At3), asCALL_THISCALL ); assert( r >= 0 ); // resize methods r = engine->RegisterObjectMethod( decl.c_str(), "void resize(uint)", asMETHOD(ScriptArray<T>, Resize1), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "void resize(uint, uint)", asMETHOD(ScriptArray<T>, Resize2), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "void resize(uint, uint, uint)", asMETHOD(ScriptArray<T>, Resize3), asCALL_THISCALL ); assert( r >= 0 ); // operators r = engine->RegisterObjectMethod( decl.c_str(), ( decl + "& opAssign(const " + type + " &in)" ).c_str(), asMETHOD(ScriptArray<T>, AssignmentOperator), asCALL_THISCALL ); assert( r >= 0 ); // methods r = engine->RegisterObjectMethod( decl.c_str(), "bool empty() const", asMETHOD(ScriptArray<T>, Empty), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "uint size() const", asMETHOD(ScriptArray<T>, Size), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "uint offset(uint)", asMETHOD(ScriptArray<T>, Offset1), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "uint offset(uint, uint)", asMETHOD(ScriptArray<T>, Offset2), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "uint offset(uint, uint, uint)", asMETHOD(ScriptArray<T>, Offset3), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), (( std::string( "void assign(uint, uint, " ) + const_ref ) + ")" ).c_str(), asMETHOD(ScriptArray<T>, Assign), asCALL_THISCALL ); assert( r >= 0 ); // memory management r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_ADDREF, "void f()", asMETHOD(ScriptArray<T>, AddRef), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_RELEASE, "void f()", asMETHOD(ScriptArray<T>, Release), asCALL_THISCALL); assert( r >= 0 ); }template <class T>void ScriptingEngine::RegisterArrayTemplate( const std::string decl, const std::string type ){ int r(0); using namespace scriptarraytemplate; const std::string const_ref( (std::string("const ") + type) + " &in" ); // register the array type r = engine->RegisterObjectType( "Array<class T>", 0, asOBJ_REF | asOBJ_TEMPLATE ); assert( r >= 0 ); // constructors r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, ( decl + " @f(int &in)" ).c_str(), asFUNCTION(ScriptArray<T>::_ScriptArrayFactory), asCALL_CDECL ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, (((decl + " @f(int &in, ") + const_ref) + ")" ).c_str(), asFUNCTION(ScriptArray<T>::_ScriptArrayFactory1), asCALL_CDECL ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, (((((decl + " @f(int &in, ") + const_ref) + "," ) + const_ref ) + ")" ).c_str(), asFUNCTION(ScriptArray<T>::_ScriptArrayFactory2), asCALL_CDECL ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, (((((((decl + " @f(int &in, ") + const_ref) + "," ) + const_ref ) + "," ) + const_ref ) + ")" ).c_str(), asFUNCTION(ScriptArray<T>::_ScriptArrayFactory3), asCALL_CDECL ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_FACTORY, (((decl + " @f(int &in, const ") + decl) + " &in)" ).c_str(), asFUNCTION(ScriptArray<T>::_ScriptArrayFactoryCopy), asCALL_CDECL ); assert( r >= 0 ); // index methods r = engine->RegisterObjectMethod( decl.c_str(), ( type + "& at(uint)" ).c_str(), asMETHOD(ScriptArray<T>, At1), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), ( type + "& at(uint, uint)" ).c_str(), asMETHOD(ScriptArray<T>, At2), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), ( type + "& at(uint, uint, uint)" ).c_str(), asMETHOD(ScriptArray<T>, At3), asCALL_THISCALL ); assert( r >= 0 ); // resize methods r = engine->RegisterObjectMethod( decl.c_str(), "void resize(uint)", asMETHOD(ScriptArray<T>, Resize1), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "void resize(uint, uint)", asMETHOD(ScriptArray<T>, Resize2), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "void resize(uint, uint, uint)", asMETHOD(ScriptArray<T>, Resize3), asCALL_THISCALL ); assert( r >= 0 ); // operators r = engine->RegisterObjectMethod( decl.c_str(), ( decl + "& opAssign(const " + type + " &in)" ).c_str(), asMETHOD(ScriptArray<T>, AssignmentOperator), asCALL_THISCALL ); assert( r >= 0 ); // methods r = engine->RegisterObjectMethod( decl.c_str(), "bool empty() const", asMETHOD(ScriptArray<T>, Empty), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "uint size() const", asMETHOD(ScriptArray<T>, Size), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "uint offset(uint)", asMETHOD(ScriptArray<T>, Offset1), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "uint offset(uint, uint)", asMETHOD(ScriptArray<T>, Offset2), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), "uint offset(uint, uint, uint)", asMETHOD(ScriptArray<T>, Offset3), asCALL_THISCALL ); assert( r >= 0 ); r = engine->RegisterObjectMethod( decl.c_str(), (( std::string( "void assign(uint, uint, " ) + const_ref ) + ")" ).c_str(), asMETHOD(ScriptArray<T>, Assign), asCALL_THISCALL ); assert( r >= 0 ); // memory management r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_ADDREF, "void f()", asMETHOD(ScriptArray<T>, AddRef), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( decl.c_str(), asBEHAVE_RELEASE, "void f()", asMETHOD(ScriptArray<T>, Release), asCALL_THISCALL); assert( r >= 0 ); }
Just curious; Any plans to allow a class to register their own index operator? Like: "T& uint[][][] f()" or something which might translate to "T& f(uint,uint,uint)"? It's a quick mock-up but that's the idea. Right now index ops can take only a single value.
[Edited by - arpeggiodragon on September 22, 2010 6:49:35 PM]