bbvariant.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #ifndef BB_VARIANT_H
  2. #define BB_VARIANT_H
  3. #include "bbtypeinfo.h"
  4. struct bbVariant{
  5. template<class T> static bbObject *_getObject( T const& ){ bbRuntimeError( "Variant cast failed" );return 0; }
  6. template<class T,class R=typename T::bb_object_type> static bbObject *_getObject( T *p ){ return dynamic_cast<bbObject*>( p ); }
  7. template<class T> static int _getArrayLength( T const& ){ bbRuntimeError( "Variant is not an array" );return 0; }
  8. template<class T> static bbVariant _getArrayElement( T const&,int index ){ bbRuntimeError( "Variant is not an array" );return {}; }
  9. template<class T> static void _setArrayElement( T const&,int index,bbVariant value ){ bbRuntimeError( "Variant is not an array" ); }
  10. template<class T,int D> static int _getArrayLength( bbArray<T,D> v ){ return v.length(); }
  11. template<class T,int D> static bbVariant _getArrayElement( bbArray<T,D> v,int index );
  12. template<class T,int D> static void _setArrayElement( bbArray<T,D> v,int index,bbVariant value );
  13. template<class T,int D> static void _setArrayElement( bbArray<bbGCVar<T>,D> v,int index,bbVariant value );
  14. struct RepBase{
  15. int _refs=1;
  16. virtual ~RepBase(){
  17. }
  18. virtual void gcMark(){
  19. }
  20. virtual bbTypeInfo *getType(){
  21. return 0;
  22. }
  23. virtual bbObject *getObject(){
  24. return 0;
  25. }
  26. virtual int getArrayLength(){
  27. return 0;
  28. }
  29. virtual bbVariant getArrayElement( int index ){
  30. return {};
  31. }
  32. virtual void setArrayElement( int index,bbVariant value ){
  33. }
  34. virtual bbVariant invoke( bbArray<bbVariant> params ){
  35. bbRuntimeError( "Variant is not invokable" );
  36. return {};
  37. }
  38. };
  39. template<class T> struct Rep : public RepBase{
  40. T value;
  41. Rep( const T &value ):value( value ){
  42. }
  43. virtual void gcMark(){
  44. bbGCMark( value );
  45. }
  46. virtual bbTypeInfo *getType(){
  47. return bbGetType<T>();
  48. }
  49. virtual bbObject *getObject(){
  50. return _getObject( value );
  51. }
  52. virtual int getArrayLength(){
  53. return _getArrayLength( value );
  54. }
  55. virtual bbVariant getArrayElement( int index ){
  56. return _getArrayElement( value,index );
  57. }
  58. virtual void setArrayElement( int index,bbVariant evalue ){
  59. _setArrayElement( value,index,evalue );
  60. }
  61. };
  62. static RepBase _null;
  63. RepBase *_rep;
  64. void retain()const{
  65. ++_rep->_refs;
  66. }
  67. void release(){
  68. if( !--_rep->_refs && _rep!=&_null ) delete _rep;
  69. }
  70. // ***** public *****
  71. bbVariant():_rep( &_null ){
  72. }
  73. bbVariant( const bbVariant &v ):_rep( v._rep ){
  74. retain();
  75. }
  76. template<class T> explicit bbVariant( const T &t ):_rep( new Rep<T>( t ) ){
  77. }
  78. template<class T> explicit bbVariant( const bbGCVar<T> &t ):_rep( new Rep<T*>( t.get() ) ){
  79. }
  80. ~bbVariant(){
  81. release();
  82. }
  83. bbVariant &operator=( const bbVariant &v ){
  84. v.retain();
  85. release();
  86. _rep=v._rep;
  87. return *this;
  88. }
  89. template<class T,class R=typename T::bb_object_type> T *_get( T* const& )const{
  90. bbObject *obj=_rep->getObject();
  91. return dynamic_cast<T*>( obj );
  92. }
  93. template<class T> T _get( T const& )const{
  94. bbRuntimeError( "Variant cast failed" );
  95. return {};
  96. }
  97. template<class T> T get()const{
  98. Rep<T> *r=dynamic_cast<Rep<T>*>( _rep );
  99. if( !r ) return _get( *(T*)0 );
  100. return r->value;
  101. }
  102. template<class T,class R=typename T::bb_object_type> T *_ref( T** )const{
  103. return get<T*>();
  104. }
  105. template<class T> T *_ref( T* )const{
  106. Rep<T> *r=dynamic_cast<Rep<T>*>( _rep );
  107. if( !r ) bbRuntimeError( "Variant cast failed" );
  108. return &r->value;
  109. }
  110. template<class T> T *ref()const{
  111. return _ref<T>( 0 );
  112. }
  113. bbTypeInfo *getType()const{
  114. return _rep->getType();
  115. }
  116. bbTypeInfo *getDynamicType()const{
  117. if( bbObject *obj=_rep->getObject() ) return obj->typeof();
  118. return _rep->getType();
  119. }
  120. operator bool()const{
  121. return _rep!=&_null;
  122. }
  123. int enumValue()const{
  124. return getType()->getEnum( *this );
  125. }
  126. int getArrayLength(){
  127. return _rep->getArrayLength();
  128. }
  129. bbVariant getArrayElement( int index ){
  130. return _rep->getArrayElement( index );
  131. }
  132. void setArrayElement( int index,bbVariant value ){
  133. _rep->setArrayElement( index,value );
  134. }
  135. };
  136. inline void bbGCMark( const bbVariant &v ){
  137. v._rep->gcMark();
  138. }
  139. inline int bbCompare( const bbVariant &x,const bbVariant &y ){
  140. return y._rep>x._rep ? -1 : x._rep>y._rep;
  141. }
  142. template<class T,int D> bbVariant bbVariant::_getArrayElement( bbArray<T,D> v,int index ){
  143. return bbVariant( v[index] );
  144. }
  145. template<class T,int D> void bbVariant::_setArrayElement( bbArray<T,D> v,int index,bbVariant value ){
  146. v[index]=value.get<T>();
  147. }
  148. template<class T,int D> void bbVariant::_setArrayElement( bbArray<bbGCVar<T>,D> v,int index,bbVariant value ){
  149. v[index]=value.get<T*>();
  150. }
  151. #endif