Newer
Older
Import / research / ui / toolkit / include / Variant.h
#pragma once
#include <cstring>
#include "Common.h"
BEGIN_NAMESPACE


typedef bool          boolean_t;
typedef float         float32_t;
typedef double        float64_t;
typedef void*         pointer_t;
typedef const char*   cstring_t;
typedef std::string   string_t;


class Variant;


// TODO: User types
// TODO: other types, datetime, color, 3d points, matrixes, ???

enum VariantType
{
#define VARIANT_TYPES \
	/* VARIANT_MACRO(ArgList_t) */ VARIANT_MACRO(boolean_t) VARIANT_MACRO(char)  /*    VARIANT_MACRO(wchar_t) */ \
	VARIANT_MACRO(int8_t)    VARIANT_MACRO(int16_t)   VARIANT_MACRO(int32_t)   VARIANT_MACRO(int64_t)  \
	VARIANT_MACRO(uint8_t)   VARIANT_MACRO(uint16_t)  VARIANT_MACRO(uint32_t)  VARIANT_MACRO(uint64_t) \
	VARIANT_MACRO(float32_t) VARIANT_MACRO(float64_t) VARIANT_MACRO(pointer_t) VARIANT_MACRO(cstring_t) \
	VARIANT_MACRO(String)    VARIANT_MACRO(WidgetFlags)
	//VARIANT_MACRO(enum_t) VARIANT_MACRO(string_t) 
#define VARIANT_MACRO(type) \
			VT_##type,
VARIANT_TYPES
#undef VARIANT_MACRO
	VT_Unknown
};


template<typename T>
VariantType variantTypeFromType();


const size_t maxTypeSize = 80;


class Variant
{
public:
  template<typename T>
  void setValue(const T &a_val)
	{
		m_type = variantTypeFromType<T>();
		m_null = false;
		STATIC_ASSERT(sizeof(T) <= maxTypeSize, typeTooBig);
		memset(m_data, 0, maxTypeSize);
		new (m_data)T(a_val);
	}

	template<typename T>
	const T variant_cast() const {
		STATIC_ASSERT(sizeof(T) <= maxTypeSize, typeTooBig);
		if (VariantType(m_type) == variantTypeFromType<T>())
    {
      // return reinterpret_cast<const T&>(m_data);
      union Temp { T* t; const char* d; };// m_data[maxTypeSize]; };
      Temp tmp;
      tmp.d = m_data;
      T t = *tmp.t;
      //memcpy(tmp.m_data, m_data, maxTypeSize);
			return t;//tmp.t;
		}
    // Next try canConvert and then convert?
		return T();
	}

	Variant()                                         { m_type = VT_Unknown; m_null = true; }
	
	~Variant()
	{
		if (m_type == VT_String) {
			String* v = reinterpret_cast<String*>(m_data);
			v->~String(); // Properly tidy up,  TODO: need to do this for all non-basic types
		}
	}

	template<typename T>
	Variant(const T& a_val)                           { setValue(a_val); }

	template<typename T>
	operator const T() const                          { return variant_cast<T>(); }

  template<typename T>
  const T value() const                             { return variant_cast<T>(); }

	operator const char*() const					            { m_str = toString(); return m_str.c_str(); } // TODO

	bool isNull() const                               { return m_null; }
	bool isValid() const                              { return !m_null && (m_type != VT_Unknown); }

	VariantType type() const                          { return (VariantType)m_type; }
	const char* typeName() const;

  bool operator==(const Variant &v) const           { return compareEquality(v); }
  bool operator!=(const Variant &v) const           { return !compareEquality(v); }
    
	// TODO: probably just comparing memory is not correct, what if it is a pointer to a string for example
	bool compareEquality(const Variant &v) const      { return (m_type == v.m_type) && (memcmp(m_data, v.m_data, maxTypeSize) == 0); }

  static VariantType nameToType(const char* a_name);
  static const char* typeToName(VariantType a_type);

  template<typename T>
  static Variant fromValue(const T &value)          { return Variant(value); }

	String toString() const;
	
private:
	mutable std::string m_str;  // TODO: should see if there is a way to avoid needing this member variable needed for const char* cast
	char                m_data[maxTypeSize];
	uint32_t            m_type : 31;
	uint32_t            m_null : 1;
};

/*

// Experimentation with idea of smart enums
class EnumBaseBase
{
public:
	struct EnumMaps;
	EnumBaseBase() : value(0) {}
	static const String& toStringHelper(const EnumMaps& a_maps, int a_val);
	static int fromStringHelper(const EnumMaps& a_maps, const String& a_str);
	static EnumMaps& initMapsHelper(const char* enumName, const char* enumValues);
  int value;
};


template <class Derived>
class EnumBase : public EnumBaseBase
{
public:
	operator const char* () const				         { return toStringHelper(initMaps(), value).data(); }
	String toString() const				         	     { return toStringHelper(initMaps(), value); }
	static const String& toString(Derived a_val) { return toStringHelper(initMaps(), a_val.value); }
	static int fromString(const String& a_str)   { return fromStringHelper(initMaps(), a_str); }
	static Vector<int> allValues()					     { return initMaps().valueList; }
	static EnumMaps& initMaps()	                 { return initMapsHelper(Derived::enumName(), Derived::enumValues()); }
};


#define DECLARE_ENUM(EnumName, ...) \
	class EnumName : public EnumBase<EnumName> \
	{ \
	public: \
		enum						                { __VA_ARGS__ }; \
		EnumName(int a_val)			        { value = a_val; } \
		static const char* enumName()   { return #EnumName; } \
		static const char* enumValues() { return #__VA_ARGS__; } \
	};

*/

END_NAMESPACE