Variant Class
This is just something i decided to do one today when I was bored. Do whatever you want with it. I tried my best to put useful comments in the code but English is not my first language. The code is most likely quite messy, so i would recommend you looking it through before using it in a "real life" application, i have not tested it more than in the video. The class basically acts like a union for
the most common types, and it is really simple to add your own types and provide conversion for them to. This "union" provides conversion between all these basic types without to much hassle.
It supports conversion between: bool, char, char *, std::string, int, long, unsigned long, long long, float, double, Vector, List
For example:
Header: Variant.h
Code: Variant.cpp
the most common types, and it is really simple to add your own types and provide conversion for them to. This "union" provides conversion between all these basic types without to much hassle.
It supports conversion between: bool, char, char *, std::string, int, long, unsigned long, long long, float, double, Vector, List
For example:
Code:
Variant var("-18.99");//Here a variant is created and assigned to the char array value "-18.99"
std::cout << var.toStdString()<< std::endl;//Here the char array value will be converted to a std string
std::cout << var.toInt64()<< std::endl;//Here the char array value will be converted to a int64/long long
//since a long long can't hold decimals the .99 will be lost during the conversion
std::cout << var.toDouble() << std::endl;//The char array will here be converted to a double, no data will be
//lost during this conversion since a double can hold decimal values.
std::cout << var.toULong() << std::endl;//When converted to a unsigned long alla data will be lost
//and zero will be returned since unsigned values does not hold negative values
std::cout << var.canFullyConvertTo(Variant::Int64) << std::endl;//Here it checks
//if no data will be lost during a conversion to a Int64(long long) it will return false since the decimals
//in the char array will be lost
Header: Variant.h
Code:
#ifndef VARIANT_H
#define VARIANT_H
#include <sstream>
#include <string.h>
#include <map>
#include <iostream>
#include <string>
#include <vector>
#include <list>
typedef long long int64;//A long long is the same as a int64
class Variant
{
//A class meant to make it easier to convert between basic types
//and classes and various functions that fits in that category
public:
Variant();//The user don't assign the variable in the creation of the class
Variant(const int Val);//The user assigns the class to a integer
Variant(const float Val);//The user assigns the class to a float
Variant(const double Val);//The user assigns the class to a double
Variant(const bool Val);//The user assings the class to a boolean
Variant(const char Val);//The user assigns the class to a char
Variant(const char * Val);//The user assigns the class to a char array/char pointer
Variant(const std::string Val);//The user assigns the class to a std::string
Variant(const unsigned long Val);//The user assigns the class to a unsigned long by default
Variant(const int64);//The user assigns the class to a long long/int64
Variant(const std::vector<Variant> val);//The user assigns the class to a vector
Variant(const std::list<Variant> val);//The user assigns the class to list
Variant(const std::map<const char*,Variant> val);//Assigns the variant to a map
void operator = (const Variant Val);//Set the variant to another variant
bool operator == (const Variant val);//Check if the current variant equals to another
//Variant by the value and the type
bool operator != (const Variant val);//If the Variants don't have the same value and or type return true
//else false
enum Types
{
//A enum to keep track of all the types and classes
//the variant class supports convertion between
Undefined = -1,
Int,
Float,
Double,
Int64,
ULong,
Bool,
Char,
CharArray,
stdString,
Vector,
List,
Map
};
int type();//Return the current type of the current Variant class
//The conversion functions
int toInt();//Try to return the Variant as a integer
float toFloat();//Try to return the Variant as a float
double toDouble();//Try to return the Variant as a double
bool toBool();//Try to return the Variant as a bool
char toChar();//Try to return the Variant as a char
char * toCharArray();//Try to return the Variant as a char array
unsigned long toULong();//Try to return the variant as a unsigned long
std::string toStdString();//Try to return the variant as a std::string
int64 toInt64();//Try to return the variant as a int64
long long toLongLong();//Try to return the variant as a long,long / 64 bit integer
std::vector<Variant> toVector();//Try to return the variant as vector
std::list<Variant> toList();//Try to return the current variant as a list
std::map<const char*, Variant> toMap();//Return the current variant as a map if the current type is map
static int toInt(Variant val);
static float toFloat(Variant val);
static double toDouble(Variant val);
static unsigned long toULong( Variant val);
static int64 toInt64( Variant val);
long long toLongLong(Variant val);
static bool toBool(Variant val);
static char toChar(Variant val);
static char * toCharArray( Variant val);
static std::string toStdString(Variant val);
static std::vector<Variant> toVector(Variant val);
static std::list<Variant> toList(Variant val);
std::map<const char*,Variant> toMap(Variant val);
static bool isTrue(Variant Var);//Check if a variant is true
bool canCastTo(const Types type);//Wheater the variant can be cast/always be converted to a specefied type
bool cast(int & val);//Cast the current variant to the integer the user passed
bool cast(float & val);//Cast the current variant to the float the user passed
bool cast(double &val);//Cast the current variant to the double the user passed
bool cast(bool &val);//Cast the current variant to the bool the user passed
bool cast(char &val);//Cast the current variant to the char the user passed
bool cast(unsigned long & val);//Cast the current variant to the unsigned long the user passed
bool cast(int64 & val);//Cast the current variant to the int64 the user passed
bool canFullyConvertTo(const Types type);//Wheater the Variant can be converted to a type without losing any data
//if it cans it returns true else it returns false
int indexOf(Variant value,const unsigned int begin);//Find the first index of a certain value inside the variant
int lastIndexOf(Variant value,const unsigned int begin);//Find the last reference of a certain value inside the variant
bool contains(const Variant val);//Check if the Variant contains another value or not
bool matchingValues(const Variant val);//If the type matches and
//the value of the both Variants matches return true
//else false
bool matchingTypes(const Variant val);//If the current Variant and the variant passed
//has the same type it will return true
//else it will return false
bool isUndefined();//If the current variant is undefined
//return true else false
bool isContainer();//Wheater the current variant is a container or not
enum Error
{
Error_NoError = 0,
Error_UndefinedType,
Error_UnknownError
};
void clear();//Clear the current variant
void setProperty(const char * keyName,const Variant value);//Set or add a new property to the current variant
Variant property(const char * key);//Return the variant at the key, if it exist
bool setValue(const Variant val, const Types type);//Set the value of the current variant and set type of the current variant
private:
Types currentType;//To keep track of the current type
void setCurrentType(const Types type);//Update the current type
struct Value
{
//A struct/containter to keep track to store
//the current value
int iVal;//To hold integer values
float fVal;//To hold floating point values
double dVal;//To hold double values
unsigned long ulVal;//To hold unsigned long values
int64 i64Val;//To hold the int64 values
bool bVal;//To hold boolean values
char cVal;//To hold char values
char * strVal;//To hold char array values/ cstring values
std::string stdStrVal;//Hold the stdstirng
std::vector<Variant> vecVal;//To hold vectors
std::list<Variant> listVal;//To hold lists
std::map<const char *,Variant> mapVal;//To hold maps
};
Value currentValue;//To keep track of the current value
std::map<const char *,const Variant> properties;//The map that will store all the properties of the current Variant
bool isIntegerData();//Check if the current variant only contains data that can be converted to a integer
bool isDecimalData();//Check if the current variant onlu contains data that can be converted to a decimal type such as float or double
//can fully be converted to a number
bool vecCompare(std::vector<Variant>,std::vector<Variant>);//Check if two vectors are the same
bool listCompare(std::list<Variant>, std::list<Variant>);//Check if two lists are the same
bool mapCompare(std::map<const char*,Variant>,std::map<const char*,Variant>);
std::list<Variant> vecToList(std::vector<Variant> Vec);//Return a vector as list
std::vector<Variant> listToVec(std::list<Variant> list);//Return the list as a vector
};
#endif // VARIANT_H
Code:
#include "variant.h"
Variant::Variant()
{
setCurrentType(Undefined);//The current type is undefined
//since the user did not pass a type as the parameters
}
void Variant::setCurrentType(const Variant::Types type)
{
currentType = type;//Set the current type to keep track of the current type
}
Variant::Variant(const int Val)
{
//The user assigns the class to a integer
setCurrentType(Int);//Set the current type to int
currentValue.iVal = Val;//Set the integer value to the integer the user passed
}
Variant::Variant(const float Val)
{
//The user assigns the class to a float
setCurrentType(Float);//Set the current type to float
currentValue.fVal = Val;//Set the floating point value to the float value the user passed
}
Variant::Variant(const double Val)
{
//The user assigns the class to a double
setCurrentType(Double);//Set the current type to a double
currentValue.dVal = Val;//Set the double to the double the user passed
}
Variant::Variant(const bool Val)
{
//The user assings the class to a boolean
setCurrentType(Bool);//Set the current type to bool
currentValue.bVal = Val;//Set the boolean value to boolean the user passed
}
Variant::Variant(const char Val)
{
//The user assigns the class to a char
setCurrentType(Char);//Set the current type to char
currentValue.cVal = Val;//Set the char value to the value the user passed
}
Variant::Variant(const char * Val)
{
//The user assigns the class to a char array/char pointer
setCurrentType(CharArray);//Set the current type to a char array
currentValue.strVal = (char*)Val;//Set the string value to the string value the user passed
}
Variant::Variant(const std::string Val)
{
//The user assigns the current variant to a std::string
setCurrentType(stdString);//Set the current type to std::string to keep track of the current type
currentValue.stdStrVal = Val;//Set the current value to the value passed by the user
}
Variant::Variant(const unsigned long Val)
{
//The user assigns the current Variant to a unsigned long
setCurrentType(ULong);//To keep track of the current type
currentValue.ulVal = Val;//Set the current value to the value of the ULong passed by the user
}
Variant::Variant(const int64 Val)
{
//The user assigns the Variant to a int64/long long
setCurrentType(Int64);
currentValue.i64Val = Val;//Set the int 64
}
Variant::Variant(const std::vector<Variant> val)
{
setCurrentType(Vector);//Set the current type to vector
currentValue.vecVal = val;//Set the vector
}
Variant::Variant(const std::list<Variant> val)
{
setCurrentType(List);
currentValue.listVal = val;
}
Variant::Variant(const std::map<const char *, Variant> val)
{
setCurrentType(Map);
currentValue.mapVal = val;
}
void Variant::operator =(const Variant Var)
{
this->currentType = Var.currentType;//Set the currentType to the type of the variant the user passed
this->currentValue = Var.currentValue;//Set the currentValue to the value of the variant the user passed
//Since the Variant can handle all the basic types
//there is no need to create a new = operator for each type, when they all can be passed
//via the variant in this function
}
int Variant::type()
{
//Return the current type of the current value
//so the user can check for different types
return (int)currentType;
}
int Variant::toInt()
{
//Try to return the Variant as a integer
if(isIntegerData() || isDecimalData())
{
switch(this->currentType)
{
case Int:
return this->currentValue.iVal;//If the Variant is a integer just return it
break;
case Float:
return (int)this->currentValue.fVal;//If the variant is a float type it to a integer and return it
break;
case Double:
return (int)this->currentValue.dVal;//If the variant is a double type it to a integer and return
break;
case ULong:
return (int)this->currentValue.ulVal;//Return the integer version of the unsigned long
break;
case Int64:
return (int)this->currentValue.i64Val;//Return the integer version of the int64
case Bool:
return (int)this->currentValue.bVal;//Type the boolean to a intger and return
break;
case Char:
{
std::stringstream stream;//Create a stringstream to hold the char value
stream << this->currentValue.cVal;//Set the stringstream to the char value
int Re = 0;//Create the return integer and set it to 0 to avoid undefined behaviour
stream >> Re;//Input the stored char to the integer
return Re;//Return the integer
}
break;
case CharArray:
{
std::stringstream stream;//Create a stringstream to hold the char array
stream << this->currentValue.strVal;//Set the stringstream to the char array
int Re = 0;//Create the return integer and assign it to 0 to avoid undefiend behaviours
stream >> Re;//Input the char array tp the integer
return Re;//Return the integer
}
case stdString:
{
std::stringstream stream;
stream << this->currentValue.stdStrVal;
int Re = 0;//Create the return integer
stream >> Re;//Input the string value to the integer
return Re;//Return the integer
}
case Vector:
return 0;
break;
case List:
return 0;
break;
case Map:
return 0;
break;
break;
case Undefined:
{
return 0;//Return -1 for failed
}
}
}
return 0;//Return -1 for failed
}
float Variant::toFloat()
{
//Try to return the Variant as a float
if(isDecimalData() || isIntegerData())
{
switch(this->currentType)
{
case Int:
return (float)this->currentValue.iVal;//Type the integer to a float and return it
break;
case Float:
return (float)this->currentValue.fVal;//Return the float value
break;
case Double:
return (float)this->currentValue.dVal;//Type the double to a float and return it
break;
case ULong:
return (float)this->currentValue.ulVal;
break;
case Int64:
return (float)this->currentValue.i64Val;
break;
case Bool:
return (float)this->currentValue.bVal;//Type the boolean to a float ad return it
break;
case Char:
{
std::stringstream stream;//Create a stringstream for the char
stream << this->currentValue.cVal;//Set the stringstream to the char
float Re = 0.0;//Create the return float
stream >> Re;//Assign the float to the value of the stream
return Re;//Return the float
}
break;
case CharArray:
{
std::stringstream stream;//Create a stringstream for the char array
stream << this->currentValue.strVal;//Assisgn the stream to the char array
float Re = 0.0;//Create the return float
stream >> Re;//Assign the float the value of the stream
return Re;//Return the float value
}
break;
case stdString:
{
std::stringstream stream;//Create a stringstream for the char array
stream << this->currentValue.stdStrVal;//Assisgn the stream to the std::string
float Re = 0.0;//Create the return float
stream >> Re;//Assign the float the value of the stream
return Re;//Return the float value
}
break;
case Vector:
return 0;
break;
case List:
return 0;
break;
case Map:
return 0;
break;
case Undefined:
{
return (float)0;//Return -1 for error
}
break;
}
}
return (float)0;
}
bool Variant::toBool()
{
return isTrue(this->toCharArray());//If the variant is true it will return true else false
}
double Variant::toDouble()
{
if(isDecimalData() || isIntegerData())
{
switch(this->currentType)
{
case Int:
return (double)this->currentValue.iVal;//Type the integer to a double and return it
break;
case Float:
return (double)this->currentValue.fVal;//Type the float to a double and return it
break;
case Double:
return this->currentValue.dVal;//Return the double vba
break;
case ULong:
return (double)this->currentValue.ulVal;
break;
case Int64:
return (double)this->currentValue.i64Val;
case Bool:
return (double)this->currentValue.bVal;//Type the boolean to a double and return it
break;
case Char:
{
std::stringstream stream;//Create the stream that will store the char
stream << this->currentValue.cVal;//Assign the stream to the char
double Re = 0.0;//Create the return double
stream >> Re;//Assign the double to the value of the stream
return Re;//Return the double value
}
break;
case CharArray:
{
std::stringstream stream;//Create the stream that will store the char array
stream << this->currentValue.strVal;//Assign the stream to the char array
double Re = 0.0;//Create the return double
stream >> Re;//Assign the double to the value of the stream
return Re;//Return the double value
}
break;
case stdString:
{
std::stringstream stream;//Create the stream that will store the char array
stream << this->currentValue.stdStrVal;//Assign the stream to the std::string
double Re = 0.0;//Create the return double
stream >> Re;//Assign the double to the value of the stream
return Re;//Return the double value
}
break;
case Vector:
return 0;
break;
case List:
return 0;
break;
case Map:
return 0;
break;
case Undefined:
{
return 0;//Return 0 failed
}
break;
}
}
return 0;//Return 0 for failed
}
unsigned long Variant::toULong()
{
if(isIntegerData() || isDecimalData())
{
switch(this->currentType)
{
case Int:
return (unsigned long)this->currentValue.iVal;
break;
case Float:
return (unsigned long)this->currentValue.fVal;
break;
case Double:
return (unsigned long)this->currentValue.dVal;
break;
case ULong:
return this->currentValue.ulVal;
break;
case Int64:
return (unsigned long)this->currentValue.i64Val;
case Bool:
return (unsigned long)this->currentValue.bVal;
break;
case Char:
{
std::stringstream stream;//Create the stream that will store the char
stream << this->currentValue.cVal;//Assign the stream to the char
unsigned long Re = 0;//Create the return double
stream >> Re;//Assign the double to the value of the stream
return Re;//Return the ULong value
}
break;
case CharArray:
{
std::stringstream stream;//Create the stream that will store the char array
stream << this->currentValue.strVal;//Assign the stream to the char array
unsigned long Re = 0;//Create the return ulong
stream >> Re;//Assign the double to the value of the stream
return Re;//Return the ulong
}
break;
case stdString:
{
std::stringstream stream;//Create the stream that will store the char array
stream << this->currentValue.stdStrVal;//Assign the stream to the std::string
unsigned long Re = 0;//Create the return ulong
stream >> Re;//Assign the double to the value of the stream
return Re;//Return the ulong
}
break;
case Vector:
return 0;
break;
case List:
return 0;
break;
case Map:
return 0;
break;
case Undefined:
return 0;//Failed
break;
}
}
return 0;//Failed
}
int64 Variant::toInt64()
{
if(isIntegerData() || isDecimalData())
{
switch(this->currentType)
{
case Int:
{
return (int64)this->currentValue.iVal;
}
break;
case Float:
{
return (int64)this->currentValue.fVal;
}
break;
case Double:
{
return (int64)this->currentValue.dVal;
}
break;
case ULong:
{
return (int64)this->currentValue.ulVal;
}
break;
case Int64:
{
return this->currentValue.i64Val;
}
break;
case Bool:
{
return (int64)this->currentValue.bVal;
}
break;
case Char:
{
std::stringstream stream;
stream << this->currentValue.cVal;
int64 re = 0;
stream >> re;
return re;
}
break;
case CharArray:
{
std::stringstream stream;
stream << this->currentValue.strVal;
int64 re = 0;
stream >> re;
return re;
}
break;
case stdString:
{
std::stringstream stream;
stream << this->currentValue.stdStrVal;
int64 re = 0;
stream >> re;
return re;
}
break;
case Vector:
return 0;
break;
case List:
return 0;
break;
case Map:
return 0;
break;
case Undefined:
return 0;
break;
}
}
return 0;
}
long long Variant::toLongLong()
{
return this->toInt64();
}
char * Variant::toCharArray()
{
//Try to return the variant as a char array
switch(this->currentType)
{
case Int:
{
std::stringstream stream;//Create the stream where the ineger will be stored
stream << this->currentValue.iVal;//Assign the stream to the integer value
const char * re;//Create the return char array
re = stream.str().c_str();//Assign the char array with the value of the stream
return (char*) re;//Return the char array
}
break;
case Float:
{
std::stringstream stream;//Create the stream where the ineger will be stored
stream << this->currentValue.fVal;//Assign the stream to the floating point value
const char * re;//Create the return char array
re = stream.str().c_str();//Assign the char array with the value of the stream
return (char*) re;//Return the char array
}
break;
case Double:
{
std::stringstream stream;//Create the stream where the ineger will be stored
stream << this->currentValue.dVal;//Assign the stream to the double value
const char * re;//Create the return char array
re = stream.str().c_str();//Assign the char array with the value of the stream
return (char*) re;//Return the char array
}
break;
case ULong:
{
std::stringstream stream;//Create the stream where the ineger will be stored
stream << this->currentValue.ulVal;//Assign the stream to the unsigned long value
const char * re;//Create the return char array
re = stream.str().c_str();//Assign the char array with the value of the stream
return (char*) re;//Return the char array
}
break;
case Int64:
{
std::stringstream stream;
stream << this->currentValue.i64Val;
const char * re;
re = stream.str().c_str();
return (char*)re;
}
case Bool:
{
if(this->currentValue.bVal == true)
return (char*)"1";//Return one for true
return (char*)"0";//Return zero for false
}
break;
case Char:
{
std::stringstream stream;//Create the stream to hold the char
stream << this->currentValue.cVal;//Set the stream to the char
return (char*)stream.str().c_str();//Return the stream as a char array
}
break;
case CharArray:
return (char*)this->currentValue.strVal;//Just return the char array
break;
case stdString:
return (char*)this->currentValue.stdStrVal.c_str();//Return the char array version of the std::string
break;
case Vector:
return 0;
break;
case List:
return 0;
break;
case Map:
return 0;
break;
case Undefined:
return (char*)"";//Return nothing as for failed
}
return (char*)"";//Return nothing as for failed
}
bool Variant::isTrue(Variant Var)
{
//Check if the passed variant is true or false
const char * str = (const char*)Var.toCharArray();//Convert the variant to a cstring
int strsize = strlen((const char*)str);//Get the lenght of the string
int TCount = 0;//Too keep track of the number of true chars in the string
int FCount = 0;//Too keep track of the number of false chars in the string
for(int i = 0; i < strsize;++i)
{
//Loop through the entire string
//And check each char if it is true or not
if(str[i] == '0')
++FCount;//A new false char was found,increase the number of false chars
else
++TCount;//Else it is a true char increase the number of true chars in the string
}
if(TCount > FCount)
return true;//The string contained more true chars than false chars
else if(FCount > TCount)
return false;//The string contained more false chars than true chars
//If it has gotten to this point TCount and FCount is the same value
//then base boolean of the first char in the string
if(str[0] == '0')
return false;//The first char is false so then return false
return true;//Else the first char is true so return true
}
char Variant::toChar()
{
//Try to convert the current Variant to a char
switch(this->currentType)
{
case Int:
{
std::stringstream stream;//Create the stringstream that will hold tje integer value
stream << this->currentValue.iVal;//Assign the stream to the integer value
char Re = '0';//Create the return char
stream >> Re;//Assign the char to the value of the stream
return Re;//Return the char
}
break;
case Float:
{
std::stringstream stream;//Create the stringstream that will hold the float valie
stream << this->currentValue.fVal;//Assign the stream to the float value
char Re = '0';//Create the return char
stream >> Re;///Assign the char to the value of the stream
return Re;//Return the char
}
break;
case Double:
{
std::stringstream stream;//Create the stringstream that will hold the double
stream << this->currentValue.dVal;//Assign the stream to the double
char Re = '0';//Create the return char
stream >> Re;//Assign the char to the value of the stream
return Re;//Return the char
}
break;
case ULong:
{
std::stringstream stream;//Create the stringstream that will hold the double
stream << this->currentValue.ulVal;//Assign the stream to the unsigned long value
char Re = '0';//Create the return char
stream >> Re;//Assign the char to the value of the stream
return Re;//Return the char
}
break;
case Int64:
{
std::stringstream stream;
stream << this->currentValue.i64Val;
char Re = '0';
stream >> Re;
return Re;
}
break;
case Bool:
{
if(this->currentValue.bVal == true)
return (char)'1';//Return true
return (char)'0';//Return false
}
break;
case Char:
return this->currentValue.cVal;//Just return the char value
break;
case CharArray:
{
if(strlen((const char*)this->currentValue.strVal) > 0)
return (char)this->currentValue.strVal[0];//Return the first char of the string
else
{
return (char)'0';
}
}
break;
case stdString:
{
if(this->currentValue.stdStrVal.size() > 0)
return this->currentValue.stdStrVal.at(0);//Return the first char
else
return (char)'0';
}
break;
case Vector:
return 0;
break;
case List:
return 0;
break;
case Map:
return 0;
break;
case Undefined:
{
return '0';//Return 0 for failed
}
}
return (char)'0';//Return 0 for failed
}
std::string Variant::toStdString()
{
switch(this->currentType)
{
case Int:
{
std::stringstream stream;
stream << this->currentValue.iVal;
return stream.str();
}
break;
case Float:
{
std::stringstream stream;
stream << this->currentValue.fVal;
return stream.str();
}
break;
case Double:
{
std::stringstream stream;
stream << this->currentValue.dVal;
return stream.str();
}
break;
case ULong:
{
std::stringstream stream;
stream << this->currentValue.ulVal;
return stream.str();
}
break;
case Int64:
{
std::stringstream stream;
stream << this->currentValue.i64Val;
return stream.str();
}
break;
case Bool:
{
if(this->currentValue.bVal == true)
return "1";
return "0";
}
break;
case Char:
{
std::stringstream stream;
stream << this->currentValue.cVal;
return stream.str();
}
break;
case CharArray:
{
return (std::string)this->currentValue.strVal;
}
break;
case stdString:
{
return this->currentValue.stdStrVal;
}
break;
case Vector:
return 0;
break;
case List:
return 0;
break;
case Map:
return 0;
break;
case Undefined:
{
return (std::string)"0";
}
break;
default:
return (std::string)"0";
break;
}
return "0";
}
std::vector<Variant> Variant::toVector()
{
if(this->currentType == Vector)
return this->currentValue.vecVal;
else if(this->currentType == List)
{
return listToVec(currentValue.listVal);
}
return std::vector<Variant>();//Return a undefined vector
}
std::list<Variant> Variant::toList()
{
if(currentType == List)
return currentValue.listVal;
else if(currentType == Vector)
{
return vecToList(currentValue.vecVal);//Return the vector as list
}
return std::list<Variant>();//Return a undefined list
}
std::map<const char*,Variant> Variant::toMap()
{
//Maps can only be converted to maps
if(currentType == Map)
return currentValue.mapVal;//Return the map if the current type is map
return std::map<const char*, Variant>();//Return a empty map
}
int Variant::toInt(Variant val)
{
return val.toInt();
}
float Variant::toFloat(Variant val)
{
return val.toFloat();
}
double Variant::toDouble(Variant val)
{
return val.toDouble();
}
unsigned long Variant::toULong(Variant val)
{
return val.toULong();
}
int64 Variant::toInt64(Variant val)
{
return val.toInt64();
}
long long Variant::toLongLong(Variant val)
{
return val.toInt64();
}
bool Variant::toBool(Variant val)
{
return val.toBool();
}
char Variant::toChar(Variant val)
{
return val.toChar();
}
char * Variant::toCharArray(Variant val)
{
return val.toCharArray();
}
std::string Variant::toStdString(Variant val)
{
return val.toStdString();
}
std::vector<Variant> Variant::toVector(Variant val)
{
return val.toVector();
}
std::list<Variant> Variant::toList(Variant val)
{
return val.toList();
}
std::map<const char*, Variant> Variant::toMap(Variant val)
{
return val.toMap();
}
void Variant::clear()
{
//Clear all the Variants values
currentValue.iVal = 0;//Set the integer value to zero
currentValue.fVal = 0;//Set the float value to zero
currentValue.dVal = 0;//Set the double value to zero
currentValue.cVal = (char)(int)0;//Set the char value to null
currentValue.ulVal = 0;
currentValue.i64Val = 0;
currentValue.stdStrVal = "";
currentValue.strVal = (char*)"";//Set the string value to empty
currentValue.bVal = false;//Set the boolean value to false
currentValue.vecVal = std::vector<Variant>();
currentValue.listVal = std::list<Variant>();
currentValue.mapVal = std::map<const char *, Variant>();
setCurrentType(Undefined);//Set the current type to undefined
//no type has been set by the user yet
}
bool Variant::canCastTo(const Variant::Types type)
{
//Check if the current variant can be casted
//to another type
if(this->currentType == Char || this->currentType == Int
|| this->currentType == Float || this->currentType == Double || this->currentType == Bool || this->currentType == ULong || this->currentType == Int64)
{
//If the current Variant is any of these types
return (type == Char || type == Int || type == Float || type == Double || type == Bool || type == ULong || type == Int64);
}
//The remaning type is the char array which can't be casted with anything
return false;//therefore return false for not can be casted with the type the user passed
}
bool Variant::cast(int & val)
{
switch(this->currentType)
{
case Int:
val = (int)this->currentValue.iVal;
return true;
break;
case Float:
val = (int)this->currentValue.fVal;
return true;
break;
case Double:
val = (int)this->currentValue.dVal;
return true;
break;
case ULong:
val = (int)this->currentValue.ulVal;
return true;
break;
case Int64:
val = (int)this->currentValue.i64Val;
return true;
break;
case Bool:
val = (int)this->currentValue.bVal;
return true;
break;
case Char:
val = (int)this->currentValue.cVal;
return true;
break;
case CharArray:
return false;
break;
case stdString:
return false;
break;
case Vector:
return false;
break;
case List:
return false;
break;
case Map:
return false;
break;
case Undefined:
return false;
break;
}
return false;
}
bool Variant::cast(int64 & val)
{
//Cast the current variant to a 64 bit integer
switch(this->currentType)
{
case Int:
val = (int64)this->currentValue.iVal;
return true;
break;
case Float:
val = (int64)this->currentValue.fVal;
return true;
break;
case Double:
val = (int64)this->currentValue.dVal;
return true;
break;
case ULong:
val = (int64)this->currentValue.ulVal;
return true;
break;
case Int64:
val = this->currentValue.i64Val;
return true;
break;
case Char:
val = (int64)this->currentValue.cVal;
return true;
break;
case Bool:
val = (int64)this->currentValue.bVal;
return true;
break;
case CharArray:
return false;
break;
case stdString:
return false;
break;
case Vector:
return false;
break;
case List:
return false;
break;
case Map:
return false;
break;
case Undefined:
return false;
break;
}
return false;
}
bool Variant::cast(unsigned long & val)
{
switch(this->currentType)
{
case Int:
val = (unsigned long)this->currentValue.iVal;
return true;
break;
case Float:
val = (unsigned long)this->currentValue.fVal;
return true;
break;
case Double:
val = (unsigned long)this->currentValue.dVal;
return true;
break;
case ULong:
val = (unsigned long)this->currentValue.ulVal;
return true;
break;
case Int64:
val = (unsigned long)this->currentValue.i64Val;
return true;
break;
case Bool:
val = (unsigned long)this->currentValue.bVal;
return true;
break;
case Char:
val = (unsigned long)this->currentValue.cVal;
return true;
break;
case CharArray:
return false;
break;
case stdString:
return false;
break;
case Vector:
return false;
break;
case List:
return false;
break;
case Map:
return false;
break;
case Undefined:
return false;
break;
}
return false;
}
bool Variant::cast(float & val)
{
switch(this->currentType)
{
case Int:
val = (float)this->currentValue.iVal;
return true;
break;
case Float:
val = (float)this->currentValue.fVal;
return true;
break;
case Double:
val = (float)this->currentValue.dVal;
return true;
break;
case ULong:
val = (float)this->currentValue.ulVal;
return true;
break;
case Int64:
val = (float)this->currentValue.i64Val;
return true;
break;
case Bool:
val = (float)this->currentValue.bVal;
return true;
break;
case Char:
val = (float)this->currentValue.cVal;
return true;
break;
case CharArray:
return false;
break;
case stdString:
return false;
break;
case Vector:
return false;
break;
case List:
return false;
break;
case Map:
return false;
break;
case Undefined:
return false;
break;
}
return false;
}
bool Variant::cast(double & val)
{
switch(this->currentType)
{
case Int:
val = (double)this->currentValue.iVal;
return true;
break;
case Float:
val = (double)this->currentValue.fVal;
return true;
break;
case Double:
val = (double)this->currentValue.dVal;
return true;
break;
case ULong:
val = (double)this->currentValue.ulVal;
return true;
break;
case Int64:
val = (double)this->currentValue.i64Val;
return true;
break;
case Bool:
val = (double)this->currentValue.bVal;
return true;
break;
case Char:
val = (double)this->currentValue.cVal;
return true;
break;
case CharArray:
return false;
break;
case stdString:
return false;
break;
case Vector:
return false;
break;
case List:
return false;
break;
case Map:
return false;
break;
case Undefined:
return false;
break;
}
return false;
}
bool Variant::cast(char & val)
{
switch(this->currentType)
{
case Int:
val = (char)this->currentValue.iVal;
return true;
break;
case Float:
val = (char)(int)this->currentValue.fVal;
return true;
break;
case Double:
val = (char)(int)this->currentValue.dVal;
return true;
break;
case ULong:
val = (char)(int)this->currentValue.ulVal;
return true;
break;
case Int64:
val = (char)(int)this->currentValue.i64Val;
return true;
break;
case Bool:
val = (char)(int)this->currentValue.bVal;
return true;
break;
case Char:
val = (char)this->currentValue.cVal;
return true;
break;
case CharArray:
return false;
break;
case stdString:
return false;
break;
case Vector:
return false;
break;
case List:
return false;
break;
case Map:
return false;
break;
case Undefined:
return false;
break;
}
return false;
}
bool Variant::cast(bool &val)
{
switch(this->currentType)
{
case Int:
val = (bool)this->currentValue.iVal;
return true;
break;
case Float:
val = (bool)(int)this->currentValue.fVal;
return true;
break;
case Double:
val = (bool)(int)this->currentValue.dVal;
return true;
break;
case ULong:
val = (bool)(int)this->currentValue.ulVal;
return true;
break;
case Int64:
val = (bool)(int)this->currentValue.i64Val;
return true;
break;
case Bool:
val = (bool)this->currentValue.bVal;
return true;
break;
case Char:
val = (bool)this->currentValue.cVal;
return true;
break;
case CharArray:
return false;
break;
case stdString:
return false;
break;
case Vector:
return false;
break;
case List:
return false;
break;
case Map:
return false;
break;
case Undefined:
return false;
break;
}
return false;
}
bool Variant::canFullyConvertTo(const Types T)
{
// //A function meant for checking if the Variant can
// //be converted to a type without losing any data
//Since no data should ever be lost during a to std::string conversion
//it can be used to check if the value somehow changed
Variant check;//Create a variant to keep track of the value
if(check.setValue(this->toStdString(),T))
{//Set the value to the current to std::string since no data should be lost
//and convert the string to whatever type the user entered
return (check.toStdString() == this->toStdString());
//If the two strings is the same no data was lost during the conversion and
//true will be returned for can fully convert to
//If the string are not the same data was lost and false will be returned
}
return false;//Return false for the value could not be set
}
int Variant::indexOf(Variant value, const unsigned int begin)
{
//Find the first index of a ceratin value inside
//this current variant from the begin posistion
//if no one is found or it failed is someway return -1
if(!isContainer())
{
const std::string str = toStdString();//The current Variant as a std::string
const std::string refstr = value.toStdString();//The reference value as a std::string
if(begin < str.size() && begin >= 0)//Just a basic overflow and underflow check
{
for(int i = 0; i + begin + refstr.size() <= str.size();++i)
{
//Loop through all the different possible substrings, that matches the lenght of the reference string
if(str.substr(begin + i,refstr.size()) == refstr)
return i;//The start posistion of the reference string was found from the begin point
}
}
}
return -1;//Return -1 for not found
}
int Variant::lastIndexOf(Variant value, const unsigned int begin)
{
//Find the flst index of a certain value inside the Variant
//begining from the begin posistion
//To avoid overflows and underflows
if(!isContainer())
{
const std::string str = toStdString();//The string representatiob of the Variant
const std::string refstr = value.toStdString();//The string representation of the value to find
if(begin < str.size() && begin >= 0)//Just basic overflow and underflow check
{
unsigned int lastIndex = -1;//The integer that will keep track of the last found index
//if non is found the value will stay at -1 and will return false
for(int i = 0; i + begin + refstr.size() <= str.size();++i)
{
//Loop through all the different possible substrings, that matches the lenght of the reference string
if(str.substr(begin + i,refstr.size()) == refstr)
lastIndex = i;//The start posistion of the reference string was found from the begin point
}
return lastIndex;//If the value was found somewhere inside the Variant a value bigger than -1 will be returned
//else -1 will be returned for failed
}
}
return -1;//The user entered a value to either to small or to big, and -1 is returned for failed
}
bool Variant::contains(const Variant val)
{
//If the current variant contains the value
//of val true will be returned, otherwise false
if(this->indexOf(val,0) > -1)
return true;//The value was found inside the variant
return false;//It was not found inside the variant
}
bool Variant::setValue(Variant val, const Types T)
{
//Set the Variant value without changing the T
setCurrentType(T);
if(currentType == T)
{//If the current type actually was set
switch(T)
{
case Int:
this->currentValue.iVal = val.toInt();
return true;
break;
case Float:
this->currentValue.fVal = val.toFloat();
return true;
break;
case Double:
this->currentValue.dVal = val.toDouble();
return true;
break;
case ULong:
this->currentValue.ulVal = val.toULong();
return true;
break;
case Int64:
this->currentValue.i64Val = val.toInt64();
return true;
break;
case Bool:
this->currentValue.bVal = val.toBool();
return true;
break;
case Char:
this->currentValue.cVal = val.toChar();
return true;
break;
case CharArray:
this->currentValue.strVal = val.toCharArray();
return true;
break;
case stdString:
this->currentValue.stdStrVal = val.toStdString();
return true;
break;
case Vector:
this->currentValue.vecVal = val.toVector();
return true;
break;
case List:
this->currentValue.listVal = val.toList();
return true;
break;
case Map:
this->currentValue.mapVal = val.toMap();
return true;
break;
case Undefined:
this->clear();//Clear the current variant/undefine it
return true;
break;
default:
return false;
break;
}
}
return false;//Return false for failed
}
bool Variant::operator ==(const Variant val)
{
return matchingValues(val);//Check if the values and the types are the same
}
bool Variant::matchingTypes(const Variant val)
{
return (this->currentType == val.currentType);
}
bool Variant::matchingValues(Variant val)
{
if(matchingTypes(val))
{
//The types must be the same for the value to match
switch(this->currentType)
{
case Int:
{
return (this->currentValue.iVal == val.currentValue.iVal);
}
break;
case Float:
{
return (this->currentValue.fVal == val.currentValue.fVal);
}
break;
case Double:
{
return (this->currentValue.dVal == val.currentValue.dVal);
}
break;
case ULong:
{
return (this->currentValue.ulVal == val.currentValue.ulVal);
}
break;
case Int64:
{
return (this->currentValue.i64Val == val.currentValue.i64Val);
}
break;
case Bool:
{
return (this->currentValue.bVal == val.currentValue.bVal);
}
break;
case Char:
{
return (this->currentValue.cVal == val.currentValue.cVal);
}
break;
case CharArray:
{
return (this->currentValue.strVal == val.currentValue.strVal);
}
break;
case stdString:
{
return (this->currentValue.stdStrVal == val.currentValue.stdStrVal);
}
break;
case Vector:
{
return vecCompare(this->currentValue.vecVal,val.currentValue.vecVal);
}
break;
case List:
{
return listCompare(this->currentValue.listVal,val.currentValue.listVal);
}
break;
case Map:
{
return mapCompare(this->currentValue.mapVal,val.currentValue.mapVal);
}
break;
case Undefined:
return true;//Both the variants are undefined
break;
}
}
return false;
}
bool Variant::operator !=(const Variant val)
{
//Check if the current variant and the passed variant
//don't have the same value and or type
return (!matchingValues(val));
}
bool Variant::isUndefined()
{
return (currentType == Undefined);
}
void Variant::setProperty(const char * keyName,const Variant value)
{
//Add a new property with the keyName as the key and the Variant as the value
properties.insert(std::pair<const char*,const Variant>(keyName,value));
}
Variant Variant::property(const char *key)
{
//Return the value of the key from key of it
Variant re;//Create a undefined variant
std::map<const char*,const Variant>::const_iterator iter = properties.find(key);
if(iter != properties.end())
{
//If the key was found
//the matching value can be returned
re = iter->second;//Set the variant to the value of the key
}
return re;//If the key and value was not found a undefined variant will be returned
}
bool Variant::isContainer()
{
return (currentType == Vector || currentType == List || currentType == Map);
}
bool Variant::vecCompare(std::vector<Variant> v1, std::vector<Variant> v2)
{
return (v1.size() == v2.size()) && std::equal(v1.begin(),v1.end(),v2.begin());
}
bool Variant::listCompare(std::list<Variant> L1, std::list<Variant> L2)
{
return (L1.size() == L2.size()) && std::equal(L1.begin(),L1.end(),L2.begin());
}
bool Variant::mapCompare(std::map<const char *, Variant> m1, std::map<const char *, Variant> m2)
{
if(m1.size() != m2.size())
return false;
std::map<const char*, Variant>::iterator iter1 = m1.begin(), iter2 = m2.begin();
while(iter1 != m1.end() && iter2 != m2.end())
{
if(iter1->first != iter2->first)return false;
if(iter1->second != iter2->second)return false;
++iter1;
++iter2;
}
return true;//The both maps are the same
}
std::list<Variant> Variant::vecToList(std::vector<Variant> Vec)
{
//Convert a vector to a list
return std::list<Variant>(Vec.begin(),Vec.end());//Fill the list with the data fof the vector
}
std::vector<Variant> Variant::listToVec(std::list<Variant> List)
{
//Convert a List to vector
return std::vector<Variant>(List.begin(),List.end());//Fill the vector with the data of the list
}
bool Variant::isIntegerData()
{
//Check if the current Variant only contains data that can be converted to a integer type
//Only for private usage since it might
if(isContainer())
return false;//If the Variant has the type of a container it can't be converted to any integer type
if(currentType == Int || currentType == ULong || currentType == Int64)
return true;
const std::string check = toStdString();//Convert the current variant to a std::string since
//no data should be lost during that conversion
for(unsigned int i = 0; i < check.size();++i)
if((int)(char)check.at(i) < 48 || (int)(char)check.at(i) > 57)
{
if(i > 0 && (int)(char)check.at(i) != 45)
return false;
}
return true;//The integer only contains data that can be converted to a integer
}
bool Variant::isDecimalData()
{
//Check if the current variant only contains data that can be converted to float or double data
if(isContainer())
return false;
else if(currentType == Float || currentType == Double)
return true;
const std::string check = toStdString();
for(unsigned int i = 0; i < check.size();++i)
if((int)(char)check.at(i) < 48 || (int)(char)check.at(i) > 57)
{
if(i == 0 && (int)(char)check.at(i) == 45);//Check if it is negative mark
else if(i == 0 || i == check.size() - 1 || (int)(char)check.at(i) != 46)//Check if it is not a decimal value
return false;
}
return true;
}

It is a very simple class the code is just very repetitive since i didn't use templates. Look up the boost libraries Variant class if you are confused.