#ifndef VARIANT_H
#define VARIANT_H
#include <iostream>
#include <exception>
#include <map>
#include <sstream>
#include <typeinfo>
#include <string>
using
namespace
std;
enum
VAR_TYPES {
INT
,
CHAR
, DOUBLE, STRING, OBJECT, NONE };
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef
__int64
large;
typedef
unsigned
__int64
ularge;
# define LLCONST(a) (a##i64)
#else
typedef
long
long
large;
typedef
unsigned
long
long
ularge;
# define LLCONST(a) (a##ll)
#endif
template
<
typename
T>
T StrToType(std::string& str)
{
std::istringstream ss(str);
T ret;
ss >> ret;
return
ret;
}
template
<
typename
T>
std::string TypeToStr (
const
T & obj )
{
std::ostringstream ss;
ss << obj;
return
ss.str();
}
template
<
class
T =
void
>
class
variant
{
protected
:
VAR_TYPES _type;
union
{
large i;
char
c;
double
d;
string * s;
T * v;
} _container;
void
releaseObject()
{
if
(
this
->_type == STRING)
delete
this
->_container.s;
if
(
this
->_type == OBJECT &&
typeid
(
this
->_container.v) !=
typeid
(
void
*))
delete
this
->_container.v;
this
->_type = NONE;
}
void
setString(
const
string& s)
{
this
->_container.s =
new
string(s);
this
->_type = STRING;
}
void
setObject(
const
T* o)
{
this
->_container.v = o;
this
->_type = OBJECT;
}
public
:
~variant() { releaseObject(); }
variant() { type = NONE; };
variant(
int
i)
{
this
->_container.i = i;
this
->_type =
INT
;
}
variant(
const
string& s)
{
setString(s);
}
variant(
const
char
* s)
{
setString(s);
}
variant(
char
c)
{
this
->_container.c = c;
this
->_type =
CHAR
;
}
variant(
double
d)
{
this
->_container.d = d;
this
->_type = DOUBLE;
}
variant(T * o)
{
this
->_container.v = o;
this
->_type = OBJECT;
}
variant operator=(
const
string& s)
{
releaseObject();
setString(s);
return
*
this
;
}
variant operator=(
const
char
* s)
{
releaseObject();
setString(s);
return
*
this
;
}
variant operator=(large i)
{
releaseObject();
this
->_type =
INT
;
this
->_container.i = i;
return
*
this
;
}
variant operator=(
char
c)
{
releaseObject();
this
->_type =
CHAR
;
this
->_container.c = c;
return
*
this
;
}
variant operator=(
int
i)
{
releaseObject();
this
->_type =
INT
;
this
->_container.i = i;
return
*
this
;
}
variant operator=(
double
d)
{
releaseObject();
this
->_type = DOUBLE;
this
->_container.d = d;
return
*
this
;
}
variant operator=(T * o)
{
releaseObject();
this
->_type = OBJECT;
this
->_container.v = o;
return
*
this
;
}
variant operator=(variant<> & v)
{
if
(
this
!= &v)
{
switch
(v._type)
{
case
STRING:
this
->_container.s = v._container.s;
v._type = NONE;
return
*
this
;
break
;
case
INT
:
this
->_container.i = v._container.i;
return
*
this
;
break
;
case
DOUBLE:
this
->_container.d = v._container.d;
return
*
this
;
break
;
case
CHAR
:
this
->_container.c = v._container.c;
return
*
this
;
break
;
case
OBJECT:
v._type = NONE;
this
->_container.v = v._container.v;
return
*
this
;
break
;
}
}
return
*
this
;
}
bool
operator>(
const
variant& v)
{
if
(
this
->type == NONE || v.type == NONE)
return
true
;
if
(
this
->type == STRING && v.type == STRING)
{
return
*
this
->_container.s > *v._container.s;
}
else
if
(
this
->_type ==
INT
&& v._type ==
INT
)
{
return
this
->_container.i >
this
->_container.i;
}
else
{
return
true
;
}
}
bool
operator<(
const
variant & v)
{
return
!(*
this
> v);
}
operator large()
const
{
switch
(
this
->_type)
{
case
INT
:
return
this
->_container.i;
break
;
case
STRING:
return
StrToType<
int
>(
this
->_container.s);
break
;
case
DOUBLE:
return
(large)
this
->_container.d;
break
;
case
CHAR
:
return
(large)
this
->_container.c;
case
OBJECT:
return
(large)
this
->_container.v;
}
return
NULL;
}
operator
double
()
const
{
switch
(
this
->_type)
{
case
INT
:
return
(
double
)
this
->_container.i;
break
;
case
STRING:
return
StrToType<
double
>(
this
->_container.s);
break
;
case
DOUBLE:
return
(
double
)
this
->_container.d;
break
;
case
CHAR
:
return
(
double
)
this
->_container.c;
case
OBJECT:
return
(
double
)
this
->_container.v;
}
return
NULL;
}
operator
int
()
const
{
switch
(
this
->_type)
{
case
INT
:
return
(
int
)
this
->_container.i;
break
;
case
STRING:
return
StrToType<
int
>(*
this
->_container.s);
break
;
case
DOUBLE:
return
(
int
)
this
->_container.d;
break
;
case
CHAR
:
return
(
int
)
this
->_container.c;
case
OBJECT:
return
(
int
)
this
->_container.v;
}
return
NULL;
}
operator
char
()
const
{
switch
(
this
->_type)
{
case
INT
:
return
(
char
)
this
->_container.i;
break
;
case
STRING:
return
StrToType<
char
>(*
this
->_container.s);
break
;
case
DOUBLE:
return
(
char
)
this
->_container.d;
break
;
case
CHAR
:
return
this
->_container.c;
case
OBJECT:
return
(
char
)
this
->_container.v;
}
return
NULL;
}
operator string()
const
{
switch
(
this
->_type)
{
case
INT
:
return
TypeToStr<large>(
this
->_container.i);
break
;
case
STRING:
return
*
this
->_container.s;
break
;
case
DOUBLE:
return
TypeToStr<
double
>(
this
->_container.d);
break
;
case
CHAR
:
return
TypeToStr<
char
>(
this
->_container.c);
break
;
case
OBJECT:
return
TypeToStr<T*>(
this
->_container.v);
break
;
}
return
""
;
}
variant & operator+(
const
variant & v)
{
*
this
+= v;
return
*
this
;
}
variant & operator+(large i)
{
if
(
this
->_type ==
INT
)
{
this
->_container.i += i;
}
else
if
(
this
->_type == STRING)
{
large i = StrToType(*
this
->_container.s) + i;
releaseObject();
this
->_container.s =
new
string(TypeToStr<large>(i));
}
return
*
this
;
}
variant & operator+(
int
i)
{
if
(
this
->_type ==
INT
)
{
this
->_container.i += i;
}
else
if
(
this
->_type == STRING)
{
large i2 = StrToType<large>(*
this
->_container.s) + i;
releaseObject();
this
->_type = STRING;
this
->_container.s =
new
string(TypeToStr<large>(i2));
}
return
*
this
;
}
variant & operator+(
const
string & s)
{
if
(
this
->_type == STRING)
(*
this
->_container.s) += s;
return
*
this
;
}
variant & operator+(
char
c)
{
if
(
this
->_type ==
CHAR
)
{
this
->_container.c += c;
}
else
if
(
this
->_type == STRING)
{
(*
this
->_container.s) += c;
}
return
*
this
;
}
variant & operator+(
double
d)
{
if
(
this
->_type == DOUBLE)
this
->_container.d += d;
return
*
this
;
}
variant & operator+(T * obj)
{
if
(
this
->_type == OBJECT)
(*
this
->_container.o) += *obj;
return
*
this
;
}
variant & operator+=(
const
variant & v)
{
switch
(
this
->_type)
{
case
INT
:
switch
(v._type)
{
case
INT
:
this
->_container.i += v._container.i;
break
;
case
CHAR
:
this
->_container.i += (large)v._container.c;
break
;
case
DOUBLE:
this
->_container.i += (large)v._container.d;
break
;
case
STRING:
this
->_container.i += StrToType<large>(*v._container.s);
break
;
case
OBJECT:
break
;
}
break
;
case
DOUBLE:
switch
(v._type)
{
case
INT
:
this
->_container.d += (
double
)v._container.i;
break
;
case
CHAR
:
this
->_container.d += (
double
)v._container.c;
break
;
case
DOUBLE:
this
->_container.d += v._container.d;
break
;
case
STRING:
this
->_container.d += StrToType<
double
>(*v._container.s);
break
;
case
OBJECT:
break
;
}
break
;
case
STRING:
switch
(v._type)
{
case
INT
:
*
this
->_container.s += TypeToStr<large>(v._container.i);
break
;
case
CHAR
:
*
this
->_container.s += v._container.c;
break
;
case
DOUBLE:
*
this
->_container.s += TypeToStr<
double
>(v._container.d);
break
;
case
STRING:
*
this
->_container.s += *v._container.s;
break
;
case
OBJECT:
break
;
}
break
;
case
CHAR
:
switch
(v._type)
{
case
INT
:
this
->_container.c += TypeToStr<large>(v._container.i)[0];
break
;
case
CHAR
:
this
->_container.c += v._container.c;
break
;
case
DOUBLE:
this
->_container.c += TypeToStr<
double
>(v._container.d)[0];
break
;
case
STRING:
this
->_container.c += (*v._container.s)[0];
break
;
case
OBJECT:
break
;
}
break
;
case
OBJECT:
break
;
}
return
*
this
;
}
variant & operator+=(large i)
{
if
(
this
->_type ==
INT
)
{
this
->_container.i += i;
}
else
if
(
this
->_type == STRING)
{
large i = StrToType(*
this
->_container.s) + i;
releaseObject();
this
->_container.s =
new
string(TypeToStr<large>(i));
}
return
*
this
;
}
variant & operator+=(
int
i)
{
if
(
this
->_type ==
INT
)
{
this
->_container.i += i;
}
else
if
(
this
->_type == STRING)
{
large i2 = StrToType<large>(*
this
->_container.s) + i;
releaseObject();
this
->_type = STRING;
this
->_container.s =
new
string(TypeToStr<large>(i2));
}
return
*
this
;
}
variant & operator+=(
const
string & s)
{
if
(
this
->_type == STRING)
{
(*
this
->_container.s) += s;
}
else
if
(
this
->_type ==
INT
) {
large i = StrToType<large>(
const_cast
<string>(s));
this
->_container.i += i;
}
return
*
this
;
}
variant & operator+=(
const
char
* s)
{
if
(
this
->_type == STRING)
{
(*
this
->_container.s) += s;
}
else
if
(
this
->_type ==
INT
)
{
string tmp = string(s);
large i = StrToType<large>(tmp);
this
->_container.i += i;
}
return
*
this
;
}
variant & operator+=(
char
c)
{
if
(
this
->_type ==
CHAR
)
{
this
->_container.c += c;
}
else
if
(
this
->_type == STRING)
{
(*
this
->_container.s) += c;
}
return
*
this
;
}
variant & operator+=(
double
d)
{
if
(
this
->_type == DOUBLE)
this
->_container.d += d;
return
*
this
;
}
variant & operator+=(T * obj)
{
if
(
this
->_type == OBJECT)
(*
this
->_container.o) += *obj;
return
*
this
;
}
friend
ostream & operator<<(
const
ostream & o, variant<T> & v);
friend
istream & operator>>(istream & i, variant<T> & v);
friend
ostream & operator<<(
const
ostream & o, variant<> & v);
friend
istream & operator>>(istream & i, variant<> & v);
operator T*()
const
{
return
this
->_container.v;
}
operator T()
const
{
return
*
this
->_container.v;
}
VAR_TYPES type() {
return
this
->_type; }
};
ostream & operator<<(ostream& o, variant<> & v)
{
o << (string)v;
return
o;
}
istream & operator>>(istream & i, variant<> & v)
{
string * x =
new
string();
i >> *x;
v._type = STRING;
v._container.s = x;
return
i;
}
template
<
class
T>
ostream & operator<<(ostream& o, variant<T> & v)
{
o << (string)v;
return
o;
}
template
<
class
T>
istream & operator>>(istream & i, variant<T> & v)
{
string * x =
new
string();
i >> *x;
v._type = STRING;
v._container.s = x;
return
i;
}
#endif