#ifndef BU_VARIANT_H #define BU_VARIANT_H #include <bu/fstring.h> #include <typeinfo> #include <bu/membuf.h> #include <bu/formatter.h> namespace Bu { class Formatter; class Variant; template<class t> class VariantType; class VariantTypeRoot { public: VariantTypeRoot(); virtual ~VariantTypeRoot(); virtual Bu::FString toString() const=0; virtual const std::type_info &getType() const=0; virtual VariantTypeRoot *clone() const=0; }; template<class t> class VariantType : public VariantTypeRoot { friend class Variant; private: VariantType() { } VariantType( const t &d ) : data( d ) { } VariantType( const VariantType<t> &vt ) : data( vt.data ) { } virtual ~VariantType() { } public: t &getData() { return data; } const t &getData() const { return data; } virtual Bu::FString toString() const { MemBuf mb; Formatter f( mb ); f << data; return mb.getString(); } virtual const std::type_info &getType() const { return typeid( data ); } VariantType<t> operator=( const t &rhs ) { data = rhs; return *this; } virtual VariantTypeRoot *clone() const { return new VariantType<t>( *this ); } private: t data; }; class Variant { public: Variant(); Variant( const Variant &v ); virtual ~Variant(); bool isSet(); Bu::FString toString() const; const std::type_info &getType() const; Variant &operator=( const Variant &rhs ); template<class t> Variant &operator=( const t &rhs ) { if( pCore && pCore->getType() != typeid(t) ) { delete pCore; pCore = NULL; } pCore = new VariantType<t>(); (*dynamic_cast<VariantType<t> *>(pCore)) = rhs; return *this; } template<class t> t &get() { if( !pCore ) { throw Bu::ExceptionBase("No data!"); } if( pCore->getType() != typeid(t) ) { throw Bu::ExceptionBase("Invalid type conversion."); } return dynamic_cast<VariantType<t> *>(pCore)->getData(); } template<class t> void set( const t &val ) { if( pCore && pCore->getType() != typeid(t) ) { delete pCore; pCore = NULL; } pCore = new VariantType<t>(); (*dynamic_cast<VariantType<t> *>(pCore)) = val; } template<class t> operator t() { if( !pCore ) { throw Bu::ExceptionBase("No data!"); } if( pCore->getType() != typeid(t) ) { throw Bu::ExceptionBase("Invalid type conversion."); } return dynamic_cast<VariantType<t> *>(pCore)->getData(); } template<class t> operator t() const { if( !pCore ) { throw Bu::ExceptionBase("No data!"); } if( pCore->getType() != typeid(t) ) { throw Bu::ExceptionBase("Invalid type conversion."); } return dynamic_cast<VariantType<t> *>(pCore)->getData(); } private: VariantTypeRoot *pCore; }; template<class t> Bu::Formatter &operator<<( Bu::Formatter &f, const VariantType<t> &vt ) { return f << vt.toString(); } Bu::Formatter &operator<<( Bu::Formatter &f, const Variant &v ); template<> Bu::FString VariantType<int>::toString() const; template<> Bu::FString VariantType<bool>::toString() const; }; #endif