#ifndef BB_VARIANT_H #define BB_VARIANT_H #include "bbtypeinfo.h" struct bbVariant{ template static bbObject *_getObject( T const& ){ bbRuntimeError( "Variant cast failed" );return 0; } template static bbObject *_getObject( T *p ){ return dynamic_cast( p ); } template static int _getArrayLength( T const& ){ bbRuntimeError( "Variant is not an array" );return 0; } template static bbVariant _getArrayElement( T const&,int index ){ bbRuntimeError( "Variant is not an array" );return {}; } template static void _setArrayElement( T const&,int index,bbVariant value ){ bbRuntimeError( "Variant is not an array" ); } template static int _getArrayLength( bbArray v ){ return v.length(); } template static bbVariant _getArrayElement( bbArray v,int index ); template static void _setArrayElement( bbArray v,int index,bbVariant value ); template static void _setArrayElement( bbArray,D> v,int index,bbVariant value ); struct RepBase{ int _refs=1; virtual ~RepBase(){ } virtual void gcMark(){ } virtual bbTypeInfo *getType(){ return 0; } virtual bbObject *getObject(){ return 0; } virtual int getArrayLength(){ return 0; } virtual bbVariant getArrayElement( int index ){ return {}; } virtual void setArrayElement( int index,bbVariant value ){ } virtual bbVariant invoke( bbArray params ){ bbRuntimeError( "Variant is not invokable" ); return {}; } }; template struct Rep : public RepBase{ T value; Rep( const T &value ):value( value ){ } virtual void gcMark(){ bbGCMark( value ); } virtual bbTypeInfo *getType(){ return bbGetType(); } virtual bbObject *getObject(){ return _getObject( value ); } virtual int getArrayLength(){ return _getArrayLength( value ); } virtual bbVariant getArrayElement( int index ){ return _getArrayElement( value,index ); } virtual void setArrayElement( int index,bbVariant evalue ){ _setArrayElement( value,index,evalue ); } }; static RepBase _null; RepBase *_rep; void retain()const{ ++_rep->_refs; } void release(){ if( !--_rep->_refs && _rep!=&_null ) delete _rep; } // ***** public ***** bbVariant():_rep( &_null ){ } bbVariant( const bbVariant &v ):_rep( v._rep ){ retain(); } template explicit bbVariant( const T &t ):_rep( new Rep( t ) ){ } template explicit bbVariant( const bbGCVar &t ):_rep( new Rep( t.get() ) ){ } ~bbVariant(){ release(); } bbVariant &operator=( const bbVariant &v ){ v.retain(); release(); _rep=v._rep; return *this; } template T *_get( T* const& )const{ bbObject *obj=_rep->getObject(); return dynamic_cast( obj ); } template T _get( T const& )const{ bbRuntimeError( "Variant cast failed" ); return {}; } template T get()const{ Rep *r=dynamic_cast*>( _rep ); if( !r ) return _get( *(T*)0 ); return r->value; } template T *_ref( T** )const{ return get(); } template T *_ref( T* )const{ Rep *r=dynamic_cast*>( _rep ); if( !r ) bbRuntimeError( "Variant cast failed" ); return &r->value; } template T *ref()const{ return _ref( 0 ); } bbTypeInfo *getType()const{ return _rep->getType(); } bbTypeInfo *getDynamicType()const{ if( bbObject *obj=_rep->getObject() ) return obj->typeof(); return _rep->getType(); } operator bool()const{ return _rep!=&_null; } int enumValue()const{ return getType()->getEnum( *this ); } int getArrayLength(){ return _rep->getArrayLength(); } bbVariant getArrayElement( int index ){ return _rep->getArrayElement( index ); } void setArrayElement( int index,bbVariant value ){ _rep->setArrayElement( index,value ); } }; inline void bbGCMark( const bbVariant &v ){ v._rep->gcMark(); } inline int bbCompare( const bbVariant &x,const bbVariant &y ){ return y._rep>x._rep ? -1 : x._rep>y._rep; } template bbVariant bbVariant::_getArrayElement( bbArray v,int index ){ return bbVariant( v[index] ); } template void bbVariant::_setArrayElement( bbArray v,int index,bbVariant value ){ v[index]=value.get(); } template void bbVariant::_setArrayElement( bbArray,D> v,int index,bbVariant value ){ v[index]=value.get(); } #endif