medit/moo/mooscript/mooscript-variant.h

292 lines
6.6 KiB
C++

#ifndef MOM_SCRIPT_VARIANT_H
#define MOM_SCRIPT_VARIANT_H
#include "mooscript-types.h"
namespace mom {
enum VariantType
{
VtVoid,
VtBool,
VtIndex,
VtBase1,
VtInt,
VtDouble,
VtString,
VtArray,
VtDict,
VtObject,
};
class Variant;
class VariantArray : public moo::Vector<Variant>
{
public:
VariantArray() : moo::Vector<Variant>() {}
};
class VariantDict : public moo::Dict<String, Variant>
{
public:
VariantDict() : moo::Dict<String, Variant>() {}
};
union VariantData
{
char p[1];
gint64 dummy1__;
double dummy2__;
long double dummy3__;
void *dummy4__[2];
};
MOO_STATIC_ASSERT(sizeof(String) <= sizeof(VariantData), "must fit into Variant");
MOO_STATIC_ASSERT(sizeof(VariantArray) <= sizeof(VariantData), "must fit into Variant");
MOO_STATIC_ASSERT(sizeof(VariantDict) <= sizeof(VariantDict), "must fit into Variant");
MOO_STATIC_ASSERT(sizeof(HObject) <= sizeof(VariantData), "must fit into Variant");
namespace impl {
template<VariantType vt>
class VtHelper;
template<typename T>
class VtRHelper;
}
class Variant {
public:
Variant() NOTHROW;
~Variant() NOTHROW;
Variant(const Variant &v);
Variant &operator=(const Variant &v);
NOTHROW VariantType vt() const { return m_vt; }
NOTHROW bool isVoid() const { return m_vt == VtVoid; }
void reset() NOTHROW;
template<typename T>
Variant(const T &val);
template<typename T>
void setValue(const T &val);
template<VariantType _vt_> NOTHROW
typename impl::VtHelper<_vt_>::ImplType value() const;
private:
VariantData m_data;
VariantType m_vt;
};
namespace impl {
template<typename Data>
struct DataPtr
{
private:
moo::util::CowPtr<Data> m_impl;
public:
DataPtr() {}
~DataPtr() {}
DataPtr(const Data &data)
: m_impl(data)
{
}
DataPtr &operator=(const Data &data)
{
if (&m_impl.getConst()->data != &data)
m_impl->data = data;
return *this;
}
operator const Data& () const { return m_impl->data; }
};
MOO_STATIC_ASSERT(sizeof(DataPtr<Variant>) <= sizeof(VariantData), "must fit into Variant");
#define MOM_DEFINE_VT_HELPER(_vt_, _ImplType_) \
template<> class VtHelper<_vt_> \
{ \
public: \
static const VariantType vt = _vt_; \
typedef _ImplType_ ImplType; \
}; \
\
template<> class VtRHelper<_ImplType_> \
{ \
public: \
static const VariantType vt = _vt_; \
typedef _ImplType_ ImplType; \
};
MOM_DEFINE_VT_HELPER(VtBool, bool)
MOM_DEFINE_VT_HELPER(VtIndex, Index)
MOM_DEFINE_VT_HELPER(VtBase1, Base1Int)
MOM_DEFINE_VT_HELPER(VtInt, int)
MOM_DEFINE_VT_HELPER(VtDouble, double)
MOM_DEFINE_VT_HELPER(VtObject, HObject)
MOM_DEFINE_VT_HELPER(VtString, String)
MOM_DEFINE_VT_HELPER(VtArray, VariantArray)
MOM_DEFINE_VT_HELPER(VtDict, VariantDict)
#undef MOM_DEFINE_VT_HELPER
template<typename T> NOTHROW
inline void destroyTyped(VariantData &data)
{
reinterpret_cast<T*>(data.p)->~T();
}
#define MOM_VT_CASE(vt,what) \
case vt: what(vt); break
#define MOM_VT_CASES(what) \
MOM_VT_CASE(VtBool, what); \
MOM_VT_CASE(VtIndex, what); \
MOM_VT_CASE(VtBase1, what); \
MOM_VT_CASE(VtInt, what); \
MOM_VT_CASE(VtDouble, what); \
MOM_VT_CASE(VtObject, what); \
MOM_VT_CASE(VtString, what); \
MOM_VT_CASE(VtArray, what); \
MOM_VT_CASE(VtDict, what);
NOTHROW inline void destroy(VariantType vt, VariantData &data)
{
switch (vt)
{
case VtVoid: break;
#define MOM_VT_DESTROY_CASE(VT) destroyTyped<VtHelper<VT>::ImplType>(data)
MOM_VT_CASES(MOM_VT_DESTROY_CASE)
#undef MOM_VT_DESTROY_CASE
}
}
template<VariantType vt> NOTHROW
inline typename VtHelper<vt>::ImplType &cast(VariantData &data)
{
typedef typename VtHelper<vt>::ImplType ImplType;
return *reinterpret_cast<ImplType*>(data.p);
}
template<VariantType vt> NOTHROW
inline const typename VtHelper<vt>::ImplType &cast(const VariantData &data)
{
typedef typename VtHelper<vt>::ImplType ImplType;
return *reinterpret_cast<const ImplType*>(data.p);
}
template<typename T> NOTHROW
inline T &cast(VariantData &data)
{
return *reinterpret_cast<T*>(data.p);
}
template<typename T> NOTHROW
inline const T &cast(const VariantData &data)
{
return *reinterpret_cast<const T*>(data.p);
}
NOTHROW inline void copy(VariantType vt, const VariantData &src, VariantData &dest)
{
switch (vt)
{
case VtVoid: break;
#define MOM_VT_COPY_CASE(VT) cast<VT>(dest) = cast<VT>(src)
MOM_VT_CASES(MOM_VT_COPY_CASE)
#undef MOM_VT_COPY_CASE
}
}
NOTHROW inline void copyRaw(VariantType vt, const VariantData &src, VariantData &dest)
{
switch (vt)
{
case VtVoid: break;
#define MOM_VT_COPY_RAW_CASE(VT) new (&dest) VtHelper<VT>::ImplType(cast<VT>(src))
MOM_VT_CASES(MOM_VT_COPY_RAW_CASE)
#undef MOM_VT_COPY_RAW_CASE
}
}
}
NOTHROW inline Variant::Variant()
: m_vt(VtVoid)
{
}
template<typename T>
inline Variant::Variant(const T &val)
: m_vt(VtVoid)
{
setValue(val);
}
NOTHROW inline Variant::~Variant()
{
impl::destroy(m_vt, m_data);
}
inline Variant::Variant(const Variant &v)
: m_vt(v.m_vt)
{
impl::copyRaw(v.m_vt, v.m_data, m_data);
}
NOTHROW inline Variant &Variant::operator=(const Variant &v)
{
if (m_vt == v.m_vt)
{
impl::copy(m_vt, v.m_data, m_data);
}
else
{
impl::destroy(m_vt, m_data);
m_vt = v.m_vt;
impl::copyRaw(m_vt, v.m_data, m_data);
}
return *this;
}
NOTHROW inline void Variant::reset()
{
impl::destroy(m_vt, m_data);
m_vt = VtVoid;
}
template<typename T>
inline void Variant::setValue(const T &value)
{
const VariantType vt = impl::VtRHelper<T>::vt;
if (m_vt == vt)
{
*reinterpret_cast<T*>(m_data.p) = value;
}
else
{
impl::destroy(m_vt, m_data);
m_vt = vt;
new (&m_data) T(value);
}
}
template<VariantType _vt_> NOTHROW
inline typename impl::VtHelper<_vt_>::ImplType Variant::value() const
{
typedef typename impl::VtHelper<_vt_>::ImplType ImplType;
moo_return_val_if_fail(m_vt == _vt_, ImplType());
return *reinterpret_cast<const ImplType*>(m_data.p);
}
} // namespace mom
#endif // MOM_SCRIPT_VARIANT_H