From e99509abde688315ac7a82d764b352e2e3312e61 Mon Sep 17 00:00:00 2001
From: Mike Buland <eichlan@xagasoft.com>
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 <bu/sio.h>
+#include <bu/variant.h>
+#include <bu/list.h>
+
+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<int>(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<int>::toString() const
+{
+	Bu::FString s;
+	s.format("%d", data );
+	return s;
+}
+
+template<> Bu::FString Bu::VariantType<bool>::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 <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;
+		}
+		
+		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();
+		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
-- 
cgit v1.2.3