Newer
Older
Import / applications / HighwayDash / ports / Framework / Delegates / Variant.h
#ifndef VARIANT_H
#define VARIANT_H


#include <string.h>
#include <new>
#include <string>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <sstream>
#include <cstdint>
#include "Utils.h"


#include "Namespace.h"
BEGIN_NAMESPACE

typedef bool          boolean_t;
typedef float         float32_t;
typedef double        float64_t;
typedef void*         pointer_t;
typedef const char*   cstring_t;

enum VariantType
{
#define VARIANT_TYPES \
	VARIANT_MACRO(boolean_t) VARIANT_MACRO(char) \
	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)
#define VARIANT_MACRO(type) \
			VT_##type,
VARIANT_TYPES
#undef VARIANT_MACRO
	VT_Unknown
};

template<typename T>
VariantType variantTypeFromType();

template <typename T>
constexpr T n_max(const T a) { return a; }

template <typename T, typename ... Ts>
constexpr T n_max(const T a, const Ts ... args) { return (a>n_max(args...))?a:n_max(args...); }

constexpr size_t maxTypeSize = n_max(
#define VARIANT_MACRO(type) \
            sizeof(type),
VARIANT_TYPES
#undef VARIANT_MACRO
0);


static_assert(maxTypeSize == 8, "Not a big deal if this happens, just comment this line, but a bit unexpected");



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);
		// Next try canConvert and then convert?
		return T();
	}

	Variant()                                         { m_type = VT_Unknown; m_null = true; }
	
	~Variant() { }

	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
	//operator void()                                   { return; }

	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;
};




END_NAMESPACE


#endif // VARIANT_H