From e99509abde688315ac7a82d764b352e2e3312e61 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 25 Sep 2009 22:14:26 +0000 Subject: New Bu::Variant class. Store anything in it, get it out again, find out it's type. It's really just that easy. More info, docs, and tweaks to come. --- src/tests/variant.cpp | 45 ++++++++++++ src/variant.cpp | 77 +++++++++++++++++++++ src/variant.h | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+) create mode 100644 src/tests/variant.cpp create mode 100644 src/variant.cpp create mode 100644 src/variant.h diff --git a/src/tests/variant.cpp b/src/tests/variant.cpp new file mode 100644 index 0000000..a0ac1f2 --- /dev/null +++ b/src/tests/variant.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +using namespace Bu; + +Variant getThing( int i ) +{ + Variant v; + switch( i ) + { + case 0: + v = 45; + break; + + case 1: + v = true; + break; + + case 2: + v = List(5).append(10).append(15); + break; + } + + return v; +} + +int main() +{ + Variant a; + Variant b; + Variant c; + + a = getThing( 0 ); + b = getThing( 1 ); + c = getThing( 2 ); + + sio << "a = " << a << " or " << (int)a << sio.nl + << "b = " << b << " or " << b.toString() << sio.nl + << "c = " << c << " or " << c.toString() << sio.nl + << sio.nl; + + return 0; +} + diff --git a/src/variant.cpp b/src/variant.cpp new file mode 100644 index 0000000..95eea88 --- /dev/null +++ b/src/variant.cpp @@ -0,0 +1,77 @@ +#include "bu/variant.h" + +namespace Bu +{ + Formatter &operator<<( Formatter &f, const FString &s ); +}; + +Bu::VariantTypeRoot::VariantTypeRoot() +{ +} + +Bu::VariantTypeRoot::~VariantTypeRoot() +{ +} + +Bu::Variant::Variant() : + pCore( NULL ) +{ +} + +Bu::Variant::~Variant() +{ +} + +bool Bu::Variant::isSet() +{ + return pCore != NULL; +} + +Bu::FString Bu::Variant::toString() const +{ + if( !pCore ) + return "***NO DATA***"; + return pCore->toString(); +} + +const std::type_info &Bu::Variant::getType() const +{ + if( !pCore ) + { + throw Bu::ExceptionBase("No data!"); + } + return pCore->getType(); +} + +Bu::Variant &Bu::Variant::operator=( const Bu::Variant &rhs ) +{ + if( pCore ) + { + delete pCore; + pCore = NULL; + } + if( rhs.pCore ) + { + pCore = rhs.pCore->clone(); + } + + return *this; +} + +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Variant &v ) +{ + return f << v.toString(); +} + +template<> Bu::FString Bu::VariantType::toString() const +{ + Bu::FString s; + s.format("%d", data ); + return s; +} + +template<> Bu::FString Bu::VariantType::toString() const +{ + return data?"true":"false"; +} + diff --git a/src/variant.h b/src/variant.h new file mode 100644 index 0000000..889df88 --- /dev/null +++ b/src/variant.h @@ -0,0 +1,184 @@ +#ifndef BU_VARIANT_H +#define BU_VARIANT_H + +#include +#include +#include +#include + +namespace Bu +{ + class Formatter; + class Variant; + template 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 VariantType : public VariantTypeRoot + { + friend class Variant; + private: + VariantType() + { + } + + VariantType( const t &d ) : + data( d ) + { + } + + VariantType( const VariantType &vt ) : + data( vt.data ) + { + } + + virtual ~VariantType() + { + } + + public: + t &getData() + { + return data; + } + + 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 operator=( const t &rhs ) + { + data = rhs; + + return *this; + } + + virtual VariantTypeRoot *clone() const + { + return new VariantType( *this ); + } + + private: + t data; + }; + + class Variant + { + public: + Variant(); + virtual ~Variant(); + + bool isSet(); + Bu::FString toString() const; + const std::type_info &getType() const; + + Variant &operator=( const Variant &rhs ); + + template + Variant &operator=( const t &rhs ) + { + if( pCore && pCore->getType() != typeid(t) ) + { + delete pCore; + pCore = NULL; + } + pCore = new VariantType(); + (*dynamic_cast *>(pCore)) = rhs; + return *this; + } + + template + t &get() + { + if( !pCore ) + { + throw Bu::ExceptionBase("No data!"); + } + if( pCore->getType() != typeid(t) ) + { + throw Bu::ExceptionBase("Invalid type conversion."); + } + return dynamic_cast *>(pCore)->getData(); + } + + template + void set( const t &val ) + { + if( pCore && pCore->getType() != typeid(t) ) + { + delete pCore; + pCore = NULL; + } + pCore = new VariantType(); + (*dynamic_cast *>(pCore)) = val; + } + + template + operator t() + { + if( !pCore ) + { + throw Bu::ExceptionBase("No data!"); + } + if( pCore->getType() != typeid(t) ) + { + throw Bu::ExceptionBase("Invalid type conversion."); + } + return dynamic_cast *>(pCore)->getData(); + } + + template + operator t() const + { + if( !pCore ) + { + throw Bu::ExceptionBase("No data!"); + } + if( pCore->getType() != typeid(t) ) + { + throw Bu::ExceptionBase("Invalid type conversion."); + } + return dynamic_cast *>(pCore)->getData(); + } + + private: + VariantTypeRoot *pCore; + }; + + template + Bu::Formatter &operator<<( Bu::Formatter &f, const VariantType &vt ) + { + return f << vt.toString(); + } + + Bu::Formatter &operator<<( Bu::Formatter &f, const Variant &v ); + + template<> Bu::FString VariantType::toString() const; + template<> Bu::FString VariantType::toString() const; +}; + +#endif -- cgit v1.2.3