Newer
Older
Import / research / ui / toolkit / src / backup / Variant.cpp
#include <sstream>
#include "Widget.h"
#include "Variant.h"


BEGIN_NAMESPACE


class VariantTypeMapper
{
public:
	VariantTypeMapper();
	VariantType lookup(const char* a_name)  { VariantType def = VT_Unknown; return m_variantTypeMap.forwardFind(a_name, def); }
	const char* lookup(VariantType a_type) 	{ const char* def = "Unknown"; return m_variantTypeMap.reverseFind(a_type, def); }
private:
	BidirectionalMap<const char*,VariantType> m_variantTypeMap;
};


VariantTypeMapper::VariantTypeMapper()
{
#define VARIANT_MACRO(type) \
		m_variantTypeMap.insert(#type, VT_##type);
VARIANT_TYPES
#undef VARIANT_MACRO
	m_variantTypeMap.insert("Unknown", VT_Unknown);
}


VariantTypeMapper g_variantTypeMapper;


template<typename T>
VariantType variantTypeFromType()  { return VT_Unknown; }


#define VARIANT_MACRO(type) \
			template<> \
			VariantType variantTypeFromType<type>()  { return VT_##type; }
VARIANT_TYPES
#undef VARIANT_MACRO


/*
template<>
VariantType variantTypeFromType<WidgetFlags>()  { return VT_enum_t; }

template<>
VariantType variantTypeFromType<enum_t>()  { return VT_enum_t; }


template<>
const enum_t Variant::variant_cast<enum_t>() const
{
	STATIC_ASSERT(sizeof(enum_t) <= maxTypeSize, typeTooBig);
	if (VariantType(m_type) == variantTypeFromType<enum_t>())
		return reinterpret_cast<const enum_t&>(m_data);
	// Next try canConvert and then convert?
	return enum_t();
}


*/


/*
void operator<<(std::ostringstream& s, const ArgList_t& args)
{
	s << "ArgList_t streaming not implemented";
}
*/


void operator<<(std::ostringstream& s, String& str)
{
	s << str.data();
}


String Variant::toString() const
{
	if (VariantType(m_type) == VT_boolean_t)
	{
		return (variant_cast<boolean_t>()) ? "true" : "false";
	}
  /*
	else if (VariantType(m_type) == VT_wchar_t)
	{
		wchar_t str[2] = { variant_cast<wchar_t>(), 0 };
		return String(str);
	}
  */

	std::ostringstream s;
	switch (VariantType(m_type))
	{
#define VARIANT_MACRO(type) \
		case VT_##type:			s << variant_cast<type>(); break;
VARIANT_TYPES
#undef VARIANT_MACRO
		case VT_Unknown:		break;
	}
	return String(s.str().c_str());
}


const char* Variant::typeName() const
{
	return g_variantTypeMapper.lookup((VariantType)m_type);
}


VariantType Variant::nameToType(const char* a_name)
{
	return g_variantTypeMapper.lookup(a_name);
}


const char* Variant::typeToName(VariantType a_type)
{
	return g_variantTypeMapper.lookup((VariantType)a_type);
}


END_NAMESPACE


#include "Test.h"
#include <climits>

	
BEGIN_NAMESPACE


UNIT_TEST(VariantTests, 0)
{
	Variant v0(true);
	Variant v1('a');
	//Variant v2(L'a');
	Variant v3(-12345);
	Variant v4(UINT_MAX);
	Variant v5(9223372036854775808ULL);
	Variant v6(0.0001f);
	Variant v7(0.0001);
	
	CHECK(String(v0.typeName()) == "boolean_t");
	CHECK(String(v1.typeName()) == "char");
	//CHECK(String(v2.typeName()) == "wchar_t");
	CHECK(String(v3.typeName()) == "int32_t");
	CHECK(String(v4.typeName()) == "uint32_t");
	CHECK(String(v5.typeName()) == "uint64_t");
	CHECK(String(v6.typeName()) == "float32_t");
	CHECK(String(v7.typeName()) == "float64_t");

	CHECK(v0.toString() == "true");
	CHECK(v1.toString() == "a");
	//CHECK(v2.toString() == "a");
	CHECK(v3.toString() == "-12345");
	CHECK(v4.toString() == "4294967295");
	CHECK(v5.toString() == "9223372036854775808");
	CHECK(v6.toString() == "0.0001");
	CHECK(v7.toString() == "0.0001");
}


END_NAMESPACE


#if 0

#include <iostream>
#include <utility>
BEGIN_NAMESPACE


// Experimentation with idea of a smart enum
struct EnumBaseBase::EnumMaps 
{
	BidirectionalMap<int,String> valueNameMap;
	Vector<int> valueList;
};


static void baseInitMaps(const char* a_str, EnumBaseBase::EnumMaps& maps)
{
	if (maps.valueNameMap.size() == 0)
	{
		// TODO: there might be some much more efficient string parsing and marking the sub-strings
		// of a_str of where the names begin/end that doesn't involve a lot of string copying
		int val = 0;
		Vector<String> strings = String(a_str).replace(" ", "").replace("\t", "").replace("\n", "").split(",");
		for (unsigned i = 0; i < strings.size(); i++)
		{
			Vector<String> nameValue = strings[i].split("=");
			if (nameValue.size() == 2)
				val = atoi(nameValue[1].toUtf8().c_str());
			maps.valueNameMap.insert(val, nameValue[0]);
			maps.valueList.push_back(val);
			val++; // This is copying how enums auto increment if not assigned a value
		}
	}
}


const String& EnumBaseBase::toStringHelper(const EnumBaseBase::EnumMaps& a_maps, int a_val)
{
	static const String errorMsg = "Invalid enum value"; // TODO: crash? exception? exit?
	return a_maps.valueNameMap.forwardFind(a_val, errorMsg);
}


int EnumBaseBase::fromStringHelper(const EnumBaseBase::EnumMaps& a_maps, const String& a_str)
{
	int def = -1;
	return a_maps.valueNameMap.reverseFind(a_str, def);
}


EnumBaseBase::EnumMaps& EnumBaseBase::initMapsHelper(const char* enumName, const char* enumValues)
{
	static std::map<const char*,EnumMaps> allMaps;
	std::map<const char*,EnumMaps>::iterator it = allMaps.find(enumName);
	if (it == allMaps.end()) {
		EnumBaseBase::EnumMaps maps;
		baseInitMaps(enumValues, maps);
		allMaps.insert(std::pair<const char*,EnumMaps>(enumName,maps));
	}
	return allMaps[enumName];
}


DECLARE_ENUM(
MyEnum,
	ONE=1,
	TWO,
	THREE,
	TEN=10,
	ELEVEN
);


UNIT_TEST(SmartEnumTests, 0)
{
	MyEnum foo = MyEnum::TWO;
	
	std::cout << foo << "\n";

	CHECK(MyEnum::toString(foo) == "TWO"); // static method 
	CHECK(foo.toString() == "TWO"); // member method
	CHECK(MyEnum::toString(MyEnum::TWO) == "TWO");
	CHECK(MyEnum::toString(10) == "TEN");
	CHECK(MyEnum::toString(100) == "Invalid enum value");
	CHECK(MyEnum::fromString("COW") == -1);
	CHECK(MyEnum::fromString("TWO") == 2);

	/*
	// C++11 iteration over all values
	for( auto x : MyEnum::allValues() )
	{
	  std::cout << MyEnum(x).toString() << std::endl;
	}
	*/
}


END_NAMESPACE

#endif