klayout/src/tl/tlVariant.cc

2512 lines
65 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlVariant.h"
#include "tlInternational.h"
#include "tlString.h"
#include <string.h>
#include <limits>
#include <QVariant>
#include <QStringList>
// the Qt classes supported by QVariant:
#include <QBitArray>
#include <QBitmap>
#include <QBrush>
#include <QByteArray>
#include <QChar>
#include <QColor>
#include <QCursor>
#include <QDate>
#include <QDateTime>
#if QT_VERSION >= 0x040600
# include <QEasingCurve>
#endif
#include <QFont>
#include <QVariantHash>
#include <QIcon>
#include <QImage>
#include <QKeySequence>
#include <QLine>
#include <QLineF>
#include <QVariantList>
#include <QLocale>
#include <QTransform>
#include <QMatrix4x4>
#include <QPalette>
#include <QPen>
#include <QPixmap>
#include <QPoint>
#include <QPointF>
#include <QPolygon>
#include <QQuaternion>
#include <QRect>
#include <QRectF>
#include <QRegExp>
#include <QRegion>
#include <QSize>
#include <QSizeF>
#include <QSizePolicy>
#include <QString>
#include <QStringList>
#include <QTextFormat>
#include <QTextLength>
#include <QTime>
#include <QUrl>
#include <QVector2D>
#include <QVector3D>
#include <QVector4D>
namespace tl
{
// --------------------------------------------------------------------
// Helper for converting int128 from and to string
#if defined(HAVE_64BIT_COORD)
template <>
TL_PUBLIC bool test_extractor_impl (tl::Extractor &ex, __int128 &v)
{
__int128 x = 0;
bool neg = ex.test("-");
while (*ex <= '9' && *ex >= '0') {
x = x * 10 + __int128 (*ex - '0');
++ex;
}
v = neg ? -x : x;
return true;
}
template <>
TL_PUBLIC void extractor_impl (tl::Extractor &ex, __int128 &v)
{
if (! test_extractor_impl (ex, v)) {
ex.error (tl::to_string (QObject::tr ("Expected a value specification")));
}
}
TL_PUBLIC std::string to_string (__int128 v)
{
if (v < 0) {
return std::string ("-") + to_string (-v);
}
std::string res;
do {
res += '0' + char (v % __int128 (10));
v /= __int128 (10);
} while (v > 0);
std::reverse (res.begin (), res.end ());
return res;
}
#endif
// --------------------------------------------------------------------
// Implementation of tl::VariantUserClassBase
struct VariantUserClassTableKey
{
VariantUserClassTableKey (const std::type_info &t, bool c)
: type (&t), is_const (c)
{
}
bool operator< (const VariantUserClassTableKey &k) const
{
if (is_const != k.is_const) {
return is_const < k.is_const;
}
if (*type != *k.type) {
return type->before (*k.type);
}
return false;
}
bool operator== (const VariantUserClassTableKey &k) const
{
return is_const == k.is_const && *type == *k.type;
}
const std::type_info *type;
bool is_const;
};
static std::map<VariantUserClassTableKey, const tl::VariantUserClassBase *> *sp_class_table = 0;
static std::map <std::string, const VariantUserClassBase *> s_user_type_by_name;
void
VariantUserClassBase::clear_class_table ()
{
s_user_type_by_name.clear ();
}
std::string
VariantUserClassBase::translate_class_name (const std::string &lc_clsname)
{
// Note: for pre-0.23 versions to be able to read PCell's generated by 0.23 and further
// (see #601), we need to use the old "complex type" names, specifically "layer" instead of "layerinfo".
if (lc_clsname == "layerinfo") {
return "layer";
} else {
return lc_clsname;
}
}
void
VariantUserClassBase::register_user_class (const std::string &name, const VariantUserClassBase *cls)
{
s_user_type_by_name.insert (std::make_pair (name, cls));
}
const VariantUserClassBase *
VariantUserClassBase::find_cls_by_name (const std::string &name)
{
tl_assert (! s_user_type_by_name.empty ());
std::map <std::string, const VariantUserClassBase *>::const_iterator s = s_user_type_by_name.find (tl::to_lower_case (name));
if (s == s_user_type_by_name.end ()) {
return 0;
}
return s->second;
}
const tl::VariantUserClassBase *VariantUserClassBase::instance (const std::type_info &type, bool is_const)
{
tl_assert (sp_class_table != 0);
std::map<VariantUserClassTableKey, const tl::VariantUserClassBase *>::const_iterator c = sp_class_table->find (VariantUserClassTableKey (type, is_const));
tl_assert (c != sp_class_table->end ());
return c->second;
}
void VariantUserClassBase::register_instance (const tl::VariantUserClassBase *inst, const std::type_info &type, bool is_const)
{
if (! sp_class_table) {
sp_class_table = new std::map<VariantUserClassTableKey, const tl::VariantUserClassBase *> ();
}
(*sp_class_table)[VariantUserClassTableKey (type, is_const)] = inst;
}
void VariantUserClassBase::unregister_instance (const tl::VariantUserClassBase *inst, const std::type_info &type, bool is_const)
{
if (sp_class_table) {
std::map<VariantUserClassTableKey, const tl::VariantUserClassBase *>::iterator c = sp_class_table->find (VariantUserClassTableKey (type, is_const));
if (c != sp_class_table->end () && c->second == inst) {
sp_class_table->erase (c);
}
if (sp_class_table->empty ()) {
delete sp_class_table;
sp_class_table = 0;
}
}
}
// --------------------------------------------------------------------
// Implementation of tl::Variant
Variant::Variant ()
: m_type (t_nil), m_string (0)
{
// .. nothing yet ..
}
Variant::Variant (const QByteArray &qba)
: m_type (t_qbytearray), m_string (0)
{
m_var.m_qbytearray = new QByteArray (qba);
}
Variant::Variant (const QString &qs)
: m_type (t_qstring), m_string (0)
{
m_var.m_qstring = new QString (qs);
}
Variant::Variant (const std::string &s)
: m_type (t_stdstring), m_string (0)
{
m_var.m_stdstring = new std::string (s);
}
Variant::Variant (const char *s)
: m_type (t_string)
{
m_string = new char [strlen (s) + 1];
strcpy (m_string, s);
}
Variant::Variant (double d)
: m_type (t_double), m_string (0)
{
m_var.m_double = d;
}
Variant::Variant (float d)
: m_type (t_float), m_string (0)
{
m_var.m_float = d;
}
Variant::Variant (bool b)
: m_type (t_bool), m_string (0)
{
m_var.m_bool = b;
}
Variant::Variant (char c)
: m_type (t_char), m_string (0)
{
m_var.m_char = c;
}
Variant::Variant (signed char c)
: m_type (t_schar), m_string (0)
{
m_var.m_schar = c;
}
Variant::Variant (unsigned char c)
: m_type (t_uchar), m_string (0)
{
m_var.m_uchar = c;
}
Variant::Variant (short s)
: m_type (t_short), m_string (0)
{
m_var.m_short = s;
}
Variant::Variant (unsigned short s)
: m_type (t_ushort), m_string (0)
{
m_var.m_ushort = s;
}
Variant::Variant (int l)
: m_type (t_int), m_string (0)
{
m_var.m_int = l;
}
Variant::Variant (unsigned int l)
: m_type (t_uint), m_string (0)
{
m_var.m_uint = l;
}
Variant::Variant (long long l)
: m_type (t_longlong), m_string (0)
{
m_var.m_longlong = l;
}
Variant::Variant (unsigned long long l)
: m_type (t_ulonglong), m_string (0)
{
m_var.m_ulonglong = l;
}
#if defined(HAVE_64BIT_COORD)
Variant::Variant (__int128 l)
: m_type (t_int128), m_string (0)
{
m_var.m_int128 = l;
}
#endif
Variant::Variant (long l)
: m_type (t_long), m_string (0)
{
m_var.m_long = l;
}
Variant::Variant (unsigned long l)
: m_type (t_ulong), m_string (0)
{
m_var.m_ulong = l;
}
Variant::Variant (size_t l, bool /*dummy*/)
: m_type (t_id), m_string (0)
{
m_var.m_id = l;
}
Variant::Variant (const Variant &v)
: m_type (t_nil), m_string (0)
{
operator= (v);
}
Variant::Variant (const QVariant &v)
: m_type (t_nil), m_string (0)
{
switch (v.type ()) {
case QVariant::Invalid:
break;
case QVariant::Bool:
operator= (v.toBool ());
break;
case QVariant::ByteArray:
operator= (v.toByteArray ());
break;
case QVariant::Double:
operator= (v.toDouble ());
break;
case QVariant::Hash:
{
QHash<QString, QVariant> m = v.toHash ();
set_array ();
for (QHash<QString, QVariant>::const_iterator i = m.begin (); i != m.end (); ++i) {
insert (tl::Variant (i.key ()), tl::Variant (i.value ()));
}
}
break;
case QVariant::Int:
operator= (v.toInt ());
break;
case QVariant::List:
{
QList<QVariant> vl = v.toList ();
set_list ();
for (QList<QVariant>::const_iterator i = vl.begin (); i != vl.end (); ++i) {
push (tl::Variant (*i));
}
}
break;
case QVariant::LongLong:
operator= (v.toLongLong ());
break;
case QVariant::Map:
{
QMap<QString, QVariant> m = v.toMap ();
set_array ();
for (QMap<QString, QVariant>::const_iterator i = m.begin (); i != m.end (); ++i) {
insert (tl::Variant (i.key ()), tl::Variant (i.value ()));
}
}
break;
case QVariant::StringList:
{
QStringList sl = v.toStringList ();
set_list ();
for (QStringList::const_iterator s = sl.begin (); s != sl.end (); ++s) {
push (tl::Variant (*s));
}
}
break;
case QVariant::UInt:
operator= (v.toUInt ());
break;
case QVariant::ULongLong:
operator= (v.toULongLong ());
break;
// special types supported by QVariant too:
case QVariant::BitArray:
operator= (tl::Variant (v.value<QBitArray> ()));
break;
case QVariant::Bitmap:
operator= (tl::Variant (v.value<QBitmap> ()));
break;
case QVariant::Brush:
operator= (tl::Variant (v.value<QBrush> ()));
break;
case QVariant::Color:
operator= (tl::Variant (v.value<QColor> ()));
break;
case QVariant::Cursor:
operator= (tl::Variant (v.value<QCursor> ()));
break;
case QVariant::Date:
operator= (tl::Variant (v.value<QDate> ()));
break;
case QVariant::DateTime:
operator= (tl::Variant (v.value<QDateTime> ()));
break;
#if QT_VERSION >= 0x040700
case QVariant::EasingCurve:
operator= (tl::Variant (v.value<QEasingCurve> ()));
break;
#endif
case QVariant::Font:
operator= (tl::Variant (v.value<QFont> ()));
break;
case QVariant::Icon:
operator= (tl::Variant (v.value<QIcon> ()));
break;
case QVariant::Image:
operator= (tl::Variant (v.value<QImage> ()));
break;
case QVariant::KeySequence:
operator= (tl::Variant (v.value<QKeySequence> ()));
break;
case QVariant::Line:
operator= (tl::Variant (v.value<QLine> ()));
break;
case QVariant::LineF:
operator= (tl::Variant (v.value<QLineF> ()));
break;
case QVariant::Locale:
operator= (tl::Variant (v.value<QLocale> ()));
break;
case QVariant::Transform:
operator= (tl::Variant (v.value<QTransform> ()));
break;
case QVariant::Matrix4x4:
operator= (tl::Variant (v.value<QMatrix4x4> ()));
break;
case QVariant::Palette:
operator= (tl::Variant (v.value<QPalette> ()));
break;
case QVariant::Pen:
operator= (tl::Variant (v.value<QPen> ()));
break;
case QVariant::Pixmap:
operator= (tl::Variant (v.value<QPixmap> ()));
break;
case QVariant::Point:
operator= (tl::Variant (v.value<QPoint> ()));
break;
case QVariant::PointF:
operator= (tl::Variant (v.value<QPointF> ()));
break;
case QVariant::Polygon:
operator= (tl::Variant (v.value<QPolygon> ()));
break;
case QVariant::Quaternion:
operator= (tl::Variant (v.value<QQuaternion> ()));
break;
case QVariant::Rect:
operator= (tl::Variant (v.value<QRect> ()));
break;
case QVariant::RectF:
operator= (tl::Variant (v.value<QRectF> ()));
break;
case QVariant::RegExp:
operator= (tl::Variant (v.value<QRegExp> ()));
break;
case QVariant::Region:
operator= (tl::Variant (v.value<QRegion> ()));
break;
case QVariant::Size:
operator= (tl::Variant (v.value<QSize> ()));
break;
case QVariant::SizeF:
operator= (tl::Variant (v.value<QSizeF> ()));
break;
case QVariant::SizePolicy:
operator= (tl::Variant (v.value<QSizePolicy> ()));
break;
case QVariant::TextFormat:
operator= (tl::Variant (v.value<QTextFormat> ()));
break;
case QVariant::TextLength:
operator= (tl::Variant (v.value<QTextLength> ()));
break;
case QVariant::Time:
operator= (tl::Variant (v.value<QTime> ()));
break;
case QVariant::Url:
operator= (tl::Variant (v.value<QUrl> ()));
break;
case QVariant::Vector2D:
operator= (tl::Variant (v.value<QVector2D> ()));
break;
case QVariant::Vector3D:
operator= (tl::Variant (v.value<QVector3D> ()));
break;
case QVariant::Vector4D:
operator= (tl::Variant (v.value<QVector4D> ()));
break;
default:
case QVariant::String:
operator= (v.toString ());
break;
}
}
Variant::~Variant ()
{
reset ();
}
void
Variant::reset ()
{
if (m_string) {
delete [] m_string;
}
m_string = 0;
if (m_type == t_list) {
delete m_var.m_list;
} else if (m_type == t_array) {
delete m_var.m_array;
} else if (m_type == t_qstring) {
delete m_var.m_qstring;
} else if (m_type == t_qbytearray) {
delete m_var.m_qbytearray;
} else if (m_type == t_stdstring) {
delete m_var.m_stdstring;
} else if (m_type == t_user_ref) {
WeakOrSharedPtr *ptr = reinterpret_cast<WeakOrSharedPtr *> (m_var.mp_user_ref.ptr);
ptr->~WeakOrSharedPtr();
} else if (m_type == t_user) {
if (m_var.mp_user.object && m_var.mp_user.shared) {
m_var.mp_user.cls->destroy (m_var.mp_user.object);
}
}
m_type = t_nil;
}
Variant &
Variant::operator= (const char *s)
{
if (m_type == t_string && s == m_string) {
// we are assigning to ourselves
} else {
char *snew = new char [strlen (s) + 1];
strcpy (snew, s);
reset ();
m_type = t_string;
m_string = snew;
}
return *this;
}
Variant &
Variant::operator= (const std::string &s)
{
if (m_type == t_stdstring && &s == m_var.m_stdstring) {
// we are assigning to ourselves
} else {
std::string *snew = new std::string (s);
reset ();
m_type = t_stdstring;
m_var.m_stdstring = snew;
}
return *this;
}
Variant &
Variant::operator= (const QByteArray &qs)
{
if (m_type == t_qbytearray && &qs == m_var.m_qbytearray) {
// we are assigning to ourselves
} else {
QByteArray *snew = new QByteArray (qs);
reset ();
m_type = t_qbytearray;
m_var.m_qbytearray = snew;
}
return *this;
}
Variant &
Variant::operator= (const QString &qs)
{
if (m_type == t_qstring && &qs == m_var.m_qstring) {
// we are assigning to ourselves
} else {
QString *snew = new QString (qs);
reset ();
m_type = t_qstring;
m_var.m_qstring = snew;
}
return *this;
}
Variant &
Variant::operator= (double d)
{
reset ();
m_type = t_double;
m_var.m_double = d;
return *this;
}
Variant &
Variant::operator= (float d)
{
reset ();
m_type = t_float;
m_var.m_float = d;
return *this;
}
Variant &
Variant::operator= (bool b)
{
reset ();
m_type = t_bool;
m_var.m_bool = b;
return *this;
}
Variant &
Variant::operator= (signed char c)
{
reset ();
m_type = t_schar;
m_var.m_schar = c;
return *this;
}
Variant &
Variant::operator= (unsigned char c)
{
reset ();
m_type = t_uchar;
m_var.m_uchar = c;
return *this;
}
Variant &
Variant::operator= (char c)
{
reset ();
m_type = t_char;
m_var.m_char = c;
return *this;
}
Variant &
Variant::operator= (unsigned short s)
{
reset ();
m_type = t_ushort;
m_var.m_ushort = s;
return *this;
}
Variant &
Variant::operator= (short s)
{
reset ();
m_type = t_short;
m_var.m_short = s;
return *this;
}
Variant &
Variant::operator= (unsigned int l)
{
reset ();
m_type = t_uint;
m_var.m_uint = l;
return *this;
}
Variant &
Variant::operator= (int l)
{
reset ();
m_type = t_int;
m_var.m_int = l;
return *this;
}
Variant &
Variant::operator= (unsigned long l)
{
reset ();
m_type = t_ulong;
m_var.m_ulong = l;
return *this;
}
Variant &
Variant::operator= (long l)
{
reset ();
m_type = t_long;
m_var.m_long = l;
return *this;
}
Variant &
Variant::operator= (unsigned long long l)
{
reset ();
m_type = t_ulonglong;
m_var.m_ulonglong = l;
return *this;
}
Variant &
Variant::operator= (long long l)
{
reset ();
m_type = t_longlong;
m_var.m_longlong = l;
return *this;
}
#if defined(HAVE_64BIT_COORD)
Variant &
Variant::operator= (__int128 l)
{
reset ();
m_type = t_int128;
m_var.m_int128 = l;
return *this;
}
#endif
Variant &
Variant::operator= (const Variant &v)
{
if (this != &v) {
// Clearing *this through swap delays the destruction of
// this's content. This is important if we assign a list member
// of this to this itself (this happens in tl::Expression).
tl::Variant vv;
vv.swap (*this);
m_type = v.m_type;
if (m_type == t_double) {
m_var.m_double = v.m_var.m_double;
} else if (m_type == t_float) {
m_var.m_float = v.m_var.m_float;
} else if (m_type == t_bool) {
m_var.m_bool = v.m_var.m_bool;
} else if (m_type == t_uchar) {
m_var.m_uchar = v.m_var.m_uchar;
} else if (m_type == t_schar) {
m_var.m_schar = v.m_var.m_schar;
} else if (m_type == t_char) {
m_var.m_char = v.m_var.m_char;
} else if (m_type == t_ushort) {
m_var.m_ushort = v.m_var.m_ushort;
} else if (m_type == t_short) {
m_var.m_short = v.m_var.m_short;
} else if (m_type == t_uint) {
m_var.m_uint = v.m_var.m_uint;
} else if (m_type == t_int) {
m_var.m_int = v.m_var.m_int;
} else if (m_type == t_ulong) {
m_var.m_ulong = v.m_var.m_ulong;
} else if (m_type == t_long) {
m_var.m_long = v.m_var.m_long;
} else if (m_type == t_longlong) {
m_var.m_longlong = v.m_var.m_longlong;
} else if (m_type == t_ulonglong) {
m_var.m_ulonglong = v.m_var.m_ulonglong;
#if defined(HAVE_64BIT_COORD)
} else if (m_type == t_int128) {
m_var.m_int128 = v.m_var.m_int128;
#endif
} else if (m_type == t_id) {
m_var.m_id = v.m_var.m_id;
} else if (m_type == t_qstring) {
m_var.m_qstring = new QString (*v.m_var.m_qstring);
} else if (m_type == t_qbytearray) {
m_var.m_qbytearray = new QByteArray (*v.m_var.m_qbytearray);
} else if (m_type == t_stdstring) {
m_var.m_stdstring = new std::string (*v.m_var.m_stdstring);
} else if (m_type == t_string) {
m_string = new char [strlen (v.m_string) + 1];
strcpy (m_string, v.m_string);
} else if (m_type == t_list) {
m_var.m_list = new std::vector<tl::Variant> (*v.m_var.m_list);
} else if (m_type == t_array) {
m_var.m_array = new std::map<tl::Variant, tl::Variant> (*v.m_var.m_array);
} else if (m_type == t_user) {
m_var.mp_user.cls = v.m_var.mp_user.cls;
if (v.m_var.mp_user.object) {
if (v.m_var.mp_user.shared) {
m_var.mp_user.object = v.m_var.mp_user.cls->clone (v.m_var.mp_user.object);
m_var.mp_user.shared = true;
} else {
m_var.mp_user.object = v.m_var.mp_user.object;
m_var.mp_user.shared = false;
}
} else {
m_var.mp_user.object = 0;
}
} else if (m_type == t_user_ref) {
m_var.mp_user_ref.cls = v.m_var.mp_user_ref.cls;
const WeakOrSharedPtr *ptr = reinterpret_cast<const WeakOrSharedPtr *> (v.m_var.mp_user_ref.ptr);
new (m_var.mp_user_ref.ptr) WeakOrSharedPtr (*ptr);
}
}
return *this;
}
inline bool
is_integer_type (Variant::type type)
{
switch (type) {
case Variant::t_char:
case Variant::t_schar:
case Variant::t_short:
case Variant::t_int:
case Variant::t_long:
case Variant::t_uchar:
case Variant::t_ushort:
case Variant::t_uint:
case Variant::t_ulong:
case Variant::t_longlong:
case Variant::t_ulonglong:
#if defined(HAVE_64BIT_COORD)
case Variant::t_int128:
#endif
return true;
default:
return false;
}
}
inline Variant::type
normalized_type (Variant::type type)
{
switch (type) {
case Variant::t_float:
case Variant::t_double:
return Variant::t_double;
case Variant::t_char:
case Variant::t_schar:
case Variant::t_short:
case Variant::t_int:
case Variant::t_long:
return Variant::t_long;
case Variant::t_uchar:
case Variant::t_ushort:
case Variant::t_uint:
case Variant::t_ulong:
return Variant::t_ulong;
case Variant::t_stdstring:
case Variant::t_string:
return Variant::t_string;
default:
case Variant::t_longlong:
case Variant::t_ulonglong:
#if defined(HAVE_64BIT_COORD)
case Variant::t_int128:
#endif
case Variant::t_bool:
case Variant::t_nil:
case Variant::t_qstring:
case Variant::t_qbytearray:
return type;
}
}
inline std::pair<bool, Variant::type>
normalized_type (Variant::type type1, Variant::type type2)
{
type1 = normalized_type (type1);
type2 = normalized_type (type2);
if (type1 == type2) {
return std::make_pair (true, type1);
}
if (type1 == Variant::t_double && is_integer_type (type2)) {
// use double as common representation
return std::make_pair (true, Variant::t_double);
} else if (type2 == Variant::t_double && is_integer_type (type1)) {
// use double as common representation
return std::make_pair (true, Variant::t_double);
} else {
return std::make_pair (type1 == type2, type1);
}
}
bool
Variant::operator== (const tl::Variant &d) const
{
std::pair<bool, type> tt = normalized_type (m_type, d.m_type);
if (! tt.first) {
return false;
}
type t = tt.second;
if (t == t_nil) {
return true;
} else if (t == t_bool) {
return m_var.m_bool == d.m_var.m_bool;
} else if (t == t_ulong) {
return to_ulong () == d.to_ulong ();
} else if (t == t_long) {
return to_long () == d.to_long ();
} else if (t == t_ulonglong) {
return to_ulonglong () == d.to_ulonglong ();
} else if (t == t_longlong) {
return to_longlong () == d.to_longlong ();
#if defined(HAVE_64BIT_COORD)
} else if (t == t_int128) {
return to_int128 () == d.to_int128 ();
#endif
} else if (t == t_id) {
return m_var.m_id == d.m_var.m_id;
} else if (t == t_double) {
return to_double () == d.to_double ();
} else if (t == t_string) {
return strcmp (to_string (), d.to_string ()) == 0;
} else if (t == t_qstring) {
return *m_var.m_qstring == *d.m_var.m_qstring;
} else if (t == t_qbytearray) {
return *m_var.m_qbytearray == *d.m_var.m_qbytearray;
} else if (t == t_list) {
return *m_var.m_list == *d.m_var.m_list;
} else if (t == t_array) {
return *m_var.m_array == *d.m_var.m_array;
} else if (t == t_user) {
return m_var.mp_user.cls == d.m_var.mp_user.cls && m_var.mp_user.cls->equal (m_var.mp_user.object, d.m_var.mp_user.object);
} else if (t == t_user_ref) {
const tl::Object *self = reinterpret_cast<const WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ();
const tl::Object *other = reinterpret_cast<const WeakOrSharedPtr *> (d.m_var.mp_user_ref.ptr)->get ();
return m_var.mp_user_ref.cls == d.m_var.mp_user_ref.cls && m_var.mp_user_ref.cls->equal (m_var.mp_user_ref.cls->deref_proxy_const (self), m_var.mp_user_ref.cls->deref_proxy_const (other));
} else {
return false;
}
}
bool
Variant::operator< (const tl::Variant &d) const
{
std::pair<bool, type> tt = normalized_type (m_type, d.m_type);
if (! tt.first) {
return normalized_type (m_type) < normalized_type (d.m_type);
}
type t = tt.second;
if (t == t_nil) {
return false;
} else if (t == t_bool) {
return m_var.m_bool < d.m_var.m_bool;
} else if (t == t_ulong) {
return to_ulong () < d.to_ulong ();
} else if (t == t_long) {
return to_long () < d.to_long ();
} else if (t == t_ulonglong) {
return to_ulonglong () < d.to_ulonglong ();
} else if (t == t_longlong) {
return to_longlong () < d.to_longlong ();
#if defined(HAVE_64BIT_COORD)
} else if (t == t_int128) {
return to_int128 () < d.to_int128 ();
#endif
} else if (t == t_id) {
return m_var.m_id < d.m_var.m_id;
} else if (t == t_double) {
return to_double () < d.to_double ();
} else if (t == t_string) {
return strcmp (to_string (), d.to_string ()) < 0;
} else if (t == t_qstring) {
return *m_var.m_qstring < *d.m_var.m_qstring;
} else if (t == t_qbytearray) {
return *m_var.m_qbytearray < *d.m_var.m_qbytearray;
} else if (t == t_list) {
return *m_var.m_list < *d.m_var.m_list;
} else if (t == t_array) {
return *m_var.m_array < *d.m_var.m_array;
} else if (t == t_user) {
if (m_var.mp_user.cls != d.m_var.mp_user.cls) {
// TODO: there should be some class Id that can be used for comparison (that is more predictable)
return m_var.mp_user.cls < d.m_var.mp_user.cls;
}
return m_var.mp_user.cls->less (m_var.mp_user.object, d.m_var.mp_user.object);
} else if (t == t_user_ref) {
if (m_var.mp_user_ref.cls != d.m_var.mp_user_ref.cls) {
// TODO: there should be some class Id that can be used for comparison (that is more predictable)
return m_var.mp_user_ref.cls < d.m_var.mp_user_ref.cls;
}
const tl::Object *self = reinterpret_cast<const WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ();
const tl::Object *other = reinterpret_cast<const WeakOrSharedPtr *> (d.m_var.mp_user_ref.ptr)->get ();
return m_var.mp_user_ref.cls->less (m_var.mp_user_ref.cls->deref_proxy_const (self), m_var.mp_user_ref.cls->deref_proxy_const (other));
} else {
return false;
}
}
bool
Variant::can_convert_to_float () const
{
switch (m_type) {
case t_float:
case t_char:
case t_uchar:
case t_schar:
case t_short:
case t_ushort:
case t_int:
case t_uint:
case t_long:
case t_ulong:
case t_longlong:
case t_ulonglong:
#if defined(HAVE_64BIT_COORD)
case t_int128:
#endif
case t_bool:
case t_nil:
return true;
case t_double:
return m_var.m_double < std::numeric_limits<float>::max () && m_var.m_double > std::numeric_limits<float>::min ();
case t_qstring:
case t_qbytearray:
case t_stdstring:
case t_string:
{
tl::Extractor ex (to_string ());
double d;
return ex.try_read (d) && ex.at_end ();
}
default:
return false;
}
}
bool
Variant::can_convert_to_double () const
{
switch (m_type) {
case t_double:
case t_float:
case t_char:
case t_uchar:
case t_schar:
case t_short:
case t_ushort:
case t_int:
case t_uint:
case t_long:
case t_ulong:
case t_longlong:
case t_ulonglong:
#if defined(HAVE_64BIT_COORD)
case t_int128:
#endif
case t_bool:
case t_nil:
return true;
case t_qstring:
case t_qbytearray:
case t_stdstring:
case t_string:
{
tl::Extractor ex (to_string ());
double d;
return ex.try_read (d) && ex.at_end ();
}
default:
return false;
}
}
#if defined(HAVE_64BIT_COORD)
bool
Variant::can_convert_to_int128 () const
{
switch (m_type) {
case t_double:
return m_var.m_double <= std::numeric_limits<__int128>::max () && m_var.m_double >= std::numeric_limits<__int128>::min ();
case t_float:
return m_var.m_float <= float (std::numeric_limits<__int128>::max ()) && m_var.m_float >= float (std::numeric_limits<__int128>::min ());
case t_longlong:
case t_long:
case t_int128:
case t_char:
case t_schar:
case t_short:
case t_int:
case t_bool:
case t_uchar:
case t_ushort:
case t_uint:
case t_nil:
return true;
case t_string:
case t_qstring:
case t_qbytearray:
case t_stdstring:
// TODO: there is no range checking currently
return true;
default:
return false;
}
}
#endif
bool
Variant::can_convert_to_ulonglong () const
{
switch (m_type) {
case t_double:
return m_var.m_double <= std::numeric_limits<unsigned long long>::max () && m_var.m_double >= std::numeric_limits<unsigned long long>::min ();
case t_float:
return m_var.m_float <= float (std::numeric_limits<unsigned long long>::max ()) && m_var.m_float >= float (std::numeric_limits<unsigned long long>::min ());
case t_longlong:
return m_var.m_longlong >= 0;
#if defined(HAVE_64BIT_COORD)
case t_int128:
return m_var.m_int128 <= __int128 (std::numeric_limits<unsigned long long>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<unsigned long long>::min ());
#endif
case t_ulonglong:
case t_ulong:
case t_bool:
case t_uchar:
case t_ushort:
case t_uint:
case t_nil:
return true;
case t_long:
return m_var.m_long >= 0;
case t_char:
return m_var.m_char >= 0;
case t_schar:
return m_var.m_schar >= 0;
case t_short:
return m_var.m_short >= 0;
case t_int:
return m_var.m_int >= 0;
case t_string:
case t_qstring:
case t_qbytearray:
case t_stdstring:
{
tl::Extractor ex (to_string ());
unsigned long long ll;
return ex.try_read (ll) && ex.at_end ();
}
default:
return false;
}
}
bool
Variant::can_convert_to_longlong () const
{
switch (m_type) {
case t_double:
return m_var.m_double <= std::numeric_limits<long long>::max () && m_var.m_double >= std::numeric_limits<long long>::min ();
case t_float:
return m_var.m_float <= float (std::numeric_limits<long long>::max ()) && m_var.m_float >= float (std::numeric_limits<long long>::min ());
#if defined(HAVE_64BIT_COORD)
case t_int128:
return m_var.m_int128 <= __int128 (std::numeric_limits<long long>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<long long>::min ());
#endif
case t_ulonglong:
return m_var.m_ulonglong <= (unsigned long long) std::numeric_limits<long long>::max ();
case t_longlong:
case t_ulong:
case t_long:
case t_bool:
case t_char:
case t_uchar:
case t_schar:
case t_short:
case t_ushort:
case t_int:
case t_uint:
case t_nil:
return true;
case t_string:
case t_qstring:
case t_qbytearray:
case t_stdstring:
{
tl::Extractor ex (to_string ());
long long ll;
return ex.try_read (ll) && ex.at_end ();
}
default:
return false;
}
}
bool
Variant::can_convert_to_ulong () const
{
switch (m_type) {
case t_double:
return m_var.m_double <= std::numeric_limits<unsigned long>::max () && m_var.m_double >= std::numeric_limits<unsigned long>::min ();
case t_float:
return m_var.m_float <= std::numeric_limits<unsigned long>::max () && m_var.m_float >= std::numeric_limits<unsigned long>::min ();
#if defined(HAVE_64BIT_COORD)
case t_int128:
return m_var.m_int128 <= __int128 (std::numeric_limits<unsigned long long>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<unsigned long long>::min ());
#endif
case t_longlong:
return m_var.m_longlong >= 0 && m_var.m_longlong < (long long) std::numeric_limits<unsigned long>::max ();
case t_ulonglong:
return m_var.m_ulonglong < (unsigned long long) std::numeric_limits<unsigned long>::max ();
case t_ulong:
case t_bool:
case t_uchar:
case t_ushort:
case t_uint:
case t_nil:
return true;
case t_long:
return m_var.m_long >= 0;
case t_char:
return m_var.m_char >= 0;
case t_schar:
return m_var.m_schar >= 0;
case t_short:
return m_var.m_short >= 0;
case t_int:
return m_var.m_int >= 0;
case t_string:
case t_qstring:
case t_qbytearray:
case t_stdstring:
{
tl::Extractor ex (to_string ());
unsigned long l;
return ex.try_read (l) && ex.at_end ();
}
default:
return false;
}
}
bool
Variant::can_convert_to_long () const
{
switch (m_type) {
case t_double:
return m_var.m_double <= std::numeric_limits<long>::max () && m_var.m_double >= std::numeric_limits<long>::min ();
case t_float:
return m_var.m_float <= std::numeric_limits<long>::max () && m_var.m_float >= std::numeric_limits<long>::min ();
#if defined(HAVE_64BIT_COORD)
case t_int128:
return m_var.m_int128 <= __int128 (std::numeric_limits<long>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<long>::min ());
#endif
case t_ulonglong:
return m_var.m_ulonglong <= (unsigned long long) std::numeric_limits<long>::max ();
case t_longlong:
return m_var.m_longlong >= (long long) std::numeric_limits<long>::min () && m_var.m_longlong <= (long long) std::numeric_limits<long>::max ();
case t_ulong:
return m_var.m_ulong <= (unsigned long) std::numeric_limits<long>::max ();
case t_long:
case t_bool:
case t_char:
case t_uchar:
case t_schar:
case t_short:
case t_ushort:
case t_int:
case t_uint:
case t_nil:
return true;
case t_string:
case t_qstring:
case t_qbytearray:
case t_stdstring:
{
tl::Extractor ex (to_string ());
long l;
return ex.try_read (l) && ex.at_end ();
}
default:
return false;
}
}
bool
Variant::can_convert_to_int () const
{
switch (m_type) {
case t_double:
return m_var.m_double <= std::numeric_limits<int>::max () && m_var.m_double >= std::numeric_limits<int>::min ();
case t_float:
return m_var.m_float <= std::numeric_limits<int>::max () && m_var.m_float >= std::numeric_limits<int>::min ();
#if defined(HAVE_64BIT_COORD)
case t_int128:
return m_var.m_int128 <= __int128 (std::numeric_limits<int>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<int>::min ());
#endif
case t_ulonglong:
return m_var.m_ulonglong <= (unsigned long long) std::numeric_limits<int>::max ();
case t_longlong:
return m_var.m_longlong >= (long long) std::numeric_limits<int>::min () && m_var.m_longlong <= (long long) std::numeric_limits<int>::max ();
case t_ulong:
return m_var.m_ulong <= (unsigned long) std::numeric_limits<int>::max ();
case t_uint:
return m_var.m_uint <= (unsigned int) std::numeric_limits<int>::max ();
case t_long:
return m_var.m_long >= (long) std::numeric_limits<int>::min () && m_var.m_long <= (long) std::numeric_limits<int>::max ();
case t_bool:
case t_char:
case t_uchar:
case t_schar:
case t_short:
case t_ushort:
case t_int:
case t_nil:
return true;
case t_string:
case t_qstring:
case t_qbytearray:
case t_stdstring:
{
tl::Extractor ex (to_string ());
long l;
return ex.try_read (l) && ex.at_end () && l >= (long) std::numeric_limits<int>::min () && l <= (long) std::numeric_limits<int>::max ();
}
default:
return false;
}
}
bool
Variant::can_convert_to_uint () const
{
switch (m_type) {
case t_double:
return m_var.m_double <= std::numeric_limits<unsigned int>::max () && m_var.m_double >= std::numeric_limits<unsigned int>::min ();
case t_float:
return m_var.m_float <= std::numeric_limits<unsigned int>::max () && m_var.m_float >= std::numeric_limits<unsigned int>::min ();
#if defined(HAVE_64BIT_COORD)
case t_int128:
return m_var.m_int128 <= __int128 (std::numeric_limits<unsigned int>::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits<unsigned int>::min ());
#endif
case t_ulonglong:
return m_var.m_ulonglong <= (unsigned long long) std::numeric_limits<unsigned int>::max ();
case t_longlong:
return m_var.m_longlong >= (long long) std::numeric_limits<unsigned int>::min () && m_var.m_longlong <= (long long) std::numeric_limits<unsigned int>::max ();
case t_ulong:
return m_var.m_ulong <= (unsigned long) std::numeric_limits<unsigned int>::max ();
case t_int:
return m_var.m_int >= (long) std::numeric_limits<unsigned int>::min ();
case t_long:
return m_var.m_long >= (long) std::numeric_limits<unsigned int>::min () && (sizeof (long) == sizeof (unsigned int) || m_var.m_long <= (long) std::numeric_limits<unsigned int>::max ());
case t_bool:
case t_char:
case t_uchar:
case t_schar:
case t_short:
case t_ushort:
case t_uint:
case t_nil:
return true;
case t_string:
case t_qstring:
case t_qbytearray:
case t_stdstring:
{
tl::Extractor ex (to_string ());
long l;
return ex.try_read (l) && ex.at_end () && l >= (long) std::numeric_limits<int>::min () && l <= (long) std::numeric_limits<int>::max ();
}
default:
return false;
}
}
bool
Variant::can_convert_to_short () const
{
return can_convert_to_long () && (to_long () <= (long) std::numeric_limits<short>::max () && to_long () >= (long) std::numeric_limits<short>::min ());
}
bool
Variant::can_convert_to_ushort () const
{
return can_convert_to_long () && (to_long () <= (long) std::numeric_limits<unsigned short>::max () && to_long () >= (long) std::numeric_limits<unsigned short>::min ());
}
bool
Variant::can_convert_to_char () const
{
return can_convert_to_long () && (to_long () <= (long) std::numeric_limits<char>::max () && to_long () >= (long) std::numeric_limits<char>::min ());
}
bool
Variant::can_convert_to_schar () const
{
return can_convert_to_long () && (to_short () <= (long) std::numeric_limits<signed char>::max () && to_short () >= (long) std::numeric_limits<signed char>::min ());
}
bool
Variant::can_convert_to_uchar () const
{
return can_convert_to_long () && (to_short () <= (long) std::numeric_limits<unsigned char>::max () && to_short () >= (long) std::numeric_limits<unsigned char>::min ());
}
QByteArray
Variant::to_qbytearray () const
{
if (m_type == t_qbytearray) {
return *m_var.m_qbytearray;
} else if (m_type == t_qstring) {
return m_var.m_qstring->toUtf8 ();
} else if (m_type == t_stdstring) {
return QByteArray (m_var.m_stdstring->c_str (), int (m_var.m_stdstring->size ()));
} else {
// TODO: maybe some other conversion makes sense? I.e. byte representation of int?
std::string s = to_string ();
return QByteArray (s.c_str (), int (s.size ()));
}
}
QString
Variant::to_qstring () const
{
if (m_type == t_qstring) {
return *m_var.m_qstring;
} else if (m_type == t_qbytearray) {
return QString::fromUtf8 (*m_var.m_qbytearray);
} else {
return tl::to_qstring (to_string ());
}
}
std::string
Variant::to_stdstring () const
{
if (m_type == t_stdstring) {
return *m_var.m_stdstring;
} else if (m_type == t_qstring) {
return tl::to_string (*m_var.m_qstring);
} else if (m_type == t_qbytearray) {
return std::string (m_var.m_qbytearray->constData (), m_var.m_qbytearray->size ());
} else {
return std::string (to_string ());
}
}
const char *
Variant::to_string () const
{
if (m_type == t_stdstring) {
return m_var.m_stdstring->c_str ();
} else if (m_type == t_qbytearray) {
// TODO: content may be longer - const char * terminates at first 0 character
return m_var.m_qbytearray->constData ();
// conversion needed
} else if (! m_string) {
std::string r;
if (m_type == t_nil) {
r = "nil";
} else if (m_type == t_double) {
r = tl::to_string (m_var.m_double);
} else if (m_type == t_float) {
r = tl::to_string (m_var.m_float);
} else if (m_type == t_char) {
r = tl::to_string ((int) m_var.m_char);
} else if (m_type == t_schar) {
r = tl::to_string ((int) m_var.m_schar);
} else if (m_type == t_uchar) {
r = tl::to_string ((int) m_var.m_uchar);
} else if (m_type == t_short) {
r = tl::to_string ((int) m_var.m_short);
} else if (m_type == t_ushort) {
r = tl::to_string ((int) m_var.m_ushort);
} else if (m_type == t_int) {
r = tl::to_string (m_var.m_int);
} else if (m_type == t_uint) {
r = tl::to_string (m_var.m_uint);
} else if (m_type == t_long) {
r = tl::to_string (m_var.m_long);
} else if (m_type == t_ulong) {
r = tl::to_string (m_var.m_ulong);
} else if (m_type == t_longlong) {
r = tl::to_string (m_var.m_longlong);
} else if (m_type == t_ulonglong) {
r = tl::to_string (m_var.m_ulonglong);
#if defined(HAVE_64BIT_COORD)
} else if (m_type == t_int128) {
r = tl::to_string (m_var.m_int128);
#endif
} else if (m_type == t_bool) {
r = tl::to_string (m_var.m_bool);
} else if (m_type == t_qstring) {
r = tl::to_string (*m_var.m_qstring);
} else if (m_type == t_qbytearray) {
r = std::string (m_var.m_qbytearray->constData (), m_var.m_qbytearray->size ());
} else if (m_type == t_list) {
for (std::vector<tl::Variant>::const_iterator v = m_var.m_list->begin (); v != m_var.m_list->end (); ++v) {
if (v != m_var.m_list->begin ()) {
r += ",";
}
r += v->to_string ();
}
} else if (m_type == t_array) {
for (const_array_iterator v = m_var.m_array->begin (); v != m_var.m_array->end (); ++v) {
if (v != m_var.m_array->begin ()) {
r += ",";
}
r += v->first.to_string ();
r += "=>";
r += v->second.to_string ();
}
} else if (m_type == t_id) {
r = "[id" + tl::to_string (m_var.m_id) + "]";
} else if (m_type == t_user) {
r = m_var.mp_user.cls->to_string (m_var.mp_user.object);
} else if (m_type == t_user_ref) {
r = m_var.mp_user_ref.cls->to_string (m_var.mp_user_ref.cls->deref_proxy_const (reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ()));
} else {
r = "[unknown]";
}
m_string = new char [r.size () + 1];
strcpy (m_string, r.c_str ());
}
return m_string;
}
bool
Variant::to_bool () const
{
if (m_type == t_nil) {
return false;
} else if (m_type == t_bool) {
return m_var.m_bool;
} else {
return true;
}
}
#if defined(HAVE_64BIT_COORD)
__int128
Variant::to_int128 () const
{
if (m_type == t_nil) {
return 0;
} else if (m_type == t_int128) {
return m_var.m_int128;
} else if (m_type == t_double) {
return (__int128) (m_var.m_double);
} else if (m_type == t_float) {
return (__int128) (m_var.m_float);
} else if (m_type == t_uchar) {
return m_var.m_uchar;
} else if (m_type == t_schar) {
return m_var.m_schar;
} else if (m_type == t_char) {
return m_var.m_char;
} else if (m_type == t_ushort) {
return m_var.m_ushort;
} else if (m_type == t_short) {
return m_var.m_short;
} else if (m_type == t_uint) {
return m_var.m_uint;
} else if (m_type == t_int) {
return m_var.m_int;
} else if (m_type == t_ulong) {
return m_var.m_ulong;
} else if (m_type == t_long) {
return m_var.m_long;
} else if (m_type == t_ulonglong) {
return m_var.m_ulonglong;
} else if (m_type == t_longlong) {
return m_var.m_longlong;
} else if (m_type == t_bool) {
return m_var.m_bool;
} else if (m_type == t_stdstring) {
tl::Extractor ex (m_var.m_stdstring->c_str ());
__int128 l = 0;
ex.read (l);
return l;
} else if (m_type == t_qbytearray) {
tl::Extractor ex (m_var.m_qbytearray->constData ());
__int128 l = 0;
ex.read (l);
return l;
} else if (m_type == t_string || m_type == t_qstring) {
std::string s (to_string ());
tl::Extractor ex (s.c_str ());
__int128 l = 0;
ex.read (l);
return l;
} else {
return 0;
}
}
#endif
unsigned long long
Variant::to_ulonglong () const
{
if (m_type == t_nil) {
return 0;
} else if (m_type == t_double) {
return (unsigned long long) (m_var.m_double);
} else if (m_type == t_float) {
return (unsigned long long) (m_var.m_float);
} else if (m_type == t_uchar) {
return m_var.m_uchar;
} else if (m_type == t_schar) {
return m_var.m_schar;
} else if (m_type == t_char) {
return m_var.m_char;
} else if (m_type == t_ushort) {
return m_var.m_ushort;
} else if (m_type == t_short) {
return m_var.m_short;
} else if (m_type == t_uint) {
return m_var.m_uint;
} else if (m_type == t_int) {
return m_var.m_int;
} else if (m_type == t_ulong) {
return m_var.m_ulong;
} else if (m_type == t_long) {
return m_var.m_long;
#if defined(HAVE_64BIT_COORD)
} else if (m_type == t_int128) {
return m_var.m_int128;
#endif
} else if (m_type == t_ulonglong) {
return m_var.m_ulonglong;
} else if (m_type == t_longlong) {
return m_var.m_longlong;
} else if (m_type == t_bool) {
return m_var.m_bool;
} else if (m_type == t_stdstring) {
unsigned long long l = 0;
tl::from_string (*m_var.m_stdstring, l);
return l;
} else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) {
unsigned long long l = 0;
tl::from_string (to_string (), l);
return l;
} else {
return 0;
}
}
long long
Variant::to_longlong () const
{
if (m_type == t_nil) {
return 0;
} else if (m_type == t_double) {
return (long long) (m_var.m_double);
} else if (m_type == t_float) {
return (long long) (m_var.m_float);
} else if (m_type == t_uchar) {
return m_var.m_uchar;
} else if (m_type == t_schar) {
return m_var.m_schar;
} else if (m_type == t_char) {
return m_var.m_char;
} else if (m_type == t_ushort) {
return m_var.m_ushort;
} else if (m_type == t_short) {
return m_var.m_short;
} else if (m_type == t_uint) {
return m_var.m_uint;
} else if (m_type == t_int) {
return m_var.m_int;
} else if (m_type == t_ulong) {
return m_var.m_ulong;
} else if (m_type == t_long) {
return m_var.m_long;
} else if (m_type == t_ulonglong) {
return m_var.m_ulonglong;
} else if (m_type == t_longlong) {
return m_var.m_longlong;
#if defined(HAVE_64BIT_COORD)
} else if (m_type == t_int128) {
return m_var.m_int128;
#endif
} else if (m_type == t_bool) {
return m_var.m_bool;
} else if (m_type == t_stdstring) {
long long l = 0;
tl::from_string (*m_var.m_stdstring, l);
return l;
} else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) {
long long l = 0;
tl::from_string (to_string (), l);
return l;
} else {
return 0;
}
}
unsigned long
Variant::to_ulong () const
{
if (m_type == t_nil) {
return 0;
} else if (m_type == t_double) {
return (unsigned long) (m_var.m_double);
} else if (m_type == t_float) {
return (unsigned long) (m_var.m_float);
} else if (m_type == t_uchar) {
return m_var.m_uchar;
} else if (m_type == t_schar) {
return m_var.m_schar;
} else if (m_type == t_char) {
return m_var.m_char;
} else if (m_type == t_ushort) {
return m_var.m_ushort;
} else if (m_type == t_short) {
return m_var.m_short;
} else if (m_type == t_uint) {
return m_var.m_uint;
} else if (m_type == t_int) {
return m_var.m_int;
} else if (m_type == t_ulong) {
return m_var.m_ulong;
} else if (m_type == t_long) {
return m_var.m_long;
} else if (m_type == t_ulonglong) {
return m_var.m_ulonglong;
} else if (m_type == t_longlong) {
return m_var.m_longlong;
#if defined(HAVE_64BIT_COORD)
} else if (m_type == t_int128) {
return m_var.m_int128;
#endif
} else if (m_type == t_bool) {
return m_var.m_bool;
} else if (m_type == t_stdstring) {
unsigned long l = 0;
tl::from_string (*m_var.m_stdstring, l);
return l;
} else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) {
unsigned long l = 0;
tl::from_string (to_string (), l);
return l;
} else {
return 0;
}
}
long
Variant::to_long () const
{
if (m_type == t_nil) {
return 0;
} else if (m_type == t_double) {
return (long) (m_var.m_double);
} else if (m_type == t_float) {
return (long) (m_var.m_float);
} else if (m_type == t_uchar) {
return m_var.m_uchar;
} else if (m_type == t_schar) {
return m_var.m_schar;
} else if (m_type == t_char) {
return m_var.m_char;
} else if (m_type == t_ushort) {
return m_var.m_ushort;
} else if (m_type == t_short) {
return m_var.m_short;
} else if (m_type == t_uint) {
return m_var.m_uint;
} else if (m_type == t_int) {
return m_var.m_int;
} else if (m_type == t_ulong) {
return m_var.m_ulong;
} else if (m_type == t_long) {
return m_var.m_long;
} else if (m_type == t_ulonglong) {
return m_var.m_ulonglong;
} else if (m_type == t_longlong) {
return m_var.m_longlong;
#if defined(HAVE_64BIT_COORD)
} else if (m_type == t_int128) {
return m_var.m_int128;
#endif
} else if (m_type == t_bool) {
return m_var.m_bool;
} else if (m_type == t_stdstring) {
long l = 0;
tl::from_string (*m_var.m_stdstring, l);
return l;
} else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) {
long l = 0;
tl::from_string (to_string (), l);
return l;
} else {
return 0;
}
}
int
Variant::to_int () const
{
return (int) to_long ();
}
unsigned int
Variant::to_uint () const
{
return (unsigned int) to_ulong ();
}
short
Variant::to_short () const
{
return (short) to_long ();
}
unsigned short
Variant::to_ushort () const
{
return (unsigned short) to_ulong ();
}
char
Variant::to_char () const
{
return (char) to_long ();
}
signed char
Variant::to_schar () const
{
return (signed char) to_long ();
}
unsigned char
Variant::to_uchar () const
{
return (unsigned char) to_ulong ();
}
size_t
Variant::to_id () const
{
if (m_type == t_id) {
return m_var.m_id;
} else {
return 0;
}
}
double
Variant::to_double () const
{
if (m_type == t_nil) {
return 0;
} else if (m_type == t_double) {
return m_var.m_double;
} else if (m_type == t_float) {
return m_var.m_float;
} else if (m_type == t_uchar) {
return m_var.m_uchar;
} else if (m_type == t_schar) {
return m_var.m_schar;
} else if (m_type == t_char) {
return m_var.m_char;
} else if (m_type == t_ushort) {
return m_var.m_ushort;
} else if (m_type == t_short) {
return m_var.m_short;
} else if (m_type == t_uint) {
return m_var.m_uint;
} else if (m_type == t_int) {
return m_var.m_int;
} else if (m_type == t_ulong) {
return m_var.m_ulong;
} else if (m_type == t_long) {
return m_var.m_long;
} else if (m_type == t_ulonglong) {
return m_var.m_ulonglong;
} else if (m_type == t_longlong) {
return m_var.m_longlong;
#if defined(HAVE_64BIT_COORD)
} else if (m_type == t_int128) {
return m_var.m_int128;
#endif
} else if (m_type == t_bool) {
return m_var.m_bool;
} else if (m_type == t_stdstring) {
double d = 0;
tl::from_string (*m_var.m_stdstring, d);
return d;
} else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) {
double d = 0;
tl::from_string (to_string (), d);
return d;
} else {
return 0;
}
}
float
Variant::to_float () const
{
return to_double ();
}
const void *
Variant::native_ptr () const
{
switch (m_type) {
case t_user:
return m_var.mp_user.object;
case t_user_ref:
return reinterpret_cast<const WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ();
case t_double:
return &m_var.m_double;
case t_float:
return &m_var.m_float;
case t_ulonglong:
return &m_var.m_ulonglong;
case t_longlong:
return &m_var.m_longlong;
#if defined(HAVE_64BIT_COORD)
case t_int128:
return &m_var.m_int128;
#endif
case t_ulong:
return &m_var.m_ulong;
case t_long:
return &m_var.m_long;
case t_bool:
return &m_var.m_bool;
case t_char:
return &m_var.m_char;
case t_uchar:
return &m_var.m_uchar;
case t_schar:
return &m_var.m_schar;
case t_short:
return &m_var.m_short;
case t_ushort:
return &m_var.m_ushort;
case t_int:
return &m_var.m_int;
case t_uint:
return &m_var.m_uint;
case t_string:
return m_string;
case t_qstring:
return m_var.m_qstring;
case t_qbytearray:
return m_var.m_qbytearray;
case t_stdstring:
return m_var.m_stdstring;
case t_array:
return m_var.m_array;
case t_list:
return m_var.m_list;
case t_nil:
default:
return 0;
}
}
tl::Variant
Variant::empty_list ()
{
static std::vector<tl::Variant> empty_list;
return tl::Variant (empty_list.begin (), empty_list.end ());
}
tl::Variant
Variant::empty_array ()
{
tl::Variant e;
e.set_array ();
return e;
}
tl::Variant *
tl::Variant::find (const tl::Variant &k)
{
if (m_type != t_array) {
return 0;
} else {
array_iterator a = m_var.m_array->find (k);
if (a != m_var.m_array->end ()) {
return &a->second;
} else {
return 0;
}
}
}
/**
* @brief Returns the value for the given key or 0 if the variant is not an array or does not contain the key
*/
const tl::Variant *
tl::Variant::find (const tl::Variant &k) const
{
if (m_type != t_array) {
return 0;
} else {
const_array_iterator a = m_var.m_array->find (k);
if (a != m_var.m_array->end ()) {
return &a->second;
} else {
return 0;
}
}
}
std::string
Variant::to_parsable_string () const
{
if (is_long ()) {
return "#" + tl::to_string (to_long ());
#if defined(HAVE_64BIT_COORD)
} else if (is_int128 ()) {
return "#ll" + tl::to_string (to_int128 ());
#endif
} else if (is_longlong ()) {
return "#l" + tl::to_string (to_longlong ());
} else if (is_ulong ()) {
return "#u" + tl::to_string (to_ulong ());
} else if (is_ulonglong ()) {
return "#lu" + tl::to_string (to_ulonglong ());
} else if (is_double ()) {
return "##" + tl::to_string (to_double ());
} else if (is_bool ()) {
return m_var.m_bool ? "true" : "false";
} else if (is_nil ()) {
return "nil";
} else if (is_stdstring ()) {
return tl::to_quoted_string (*m_var.m_stdstring);
} else if (is_cstring () || is_qstring () || is_qbytearray ()) {
return tl::to_quoted_string (to_string ());
} else if (is_list ()) {
std::string r = "(";
for (tl::Variant::const_iterator l = begin (); l != end (); ++l) {
if (l != begin ()) {
r += ",";
}
r += l->to_parsable_string ();
}
r += ")";
return r;
} else if (is_array ()) {
std::string r = "{";
for (tl::Variant::const_array_iterator l = begin_array (); l != end_array (); ++l) {
if (l != begin_array ()) {
r += ",";
}
r += l->first.to_parsable_string ();
r += "=>";
r += l->second.to_parsable_string ();
}
r += "}";
return r;
} else if (is_id ()) {
return "[id" + tl::to_string (m_var.m_id) + "]";
} else if (is_user ()) {
if (user_cls ()) {
// for downward compatibility we use lower case name + do a translation
return "[" + tl::VariantUserClassBase::translate_class_name (tl::to_lower_case (user_cls ()->name ())) + ":" + user_cls ()->to_string (to_user ()) + "]";
} else {
return "[unknown_user_type]";
}
} else {
return "";
}
}
void
tl::Variant::swap (tl::Variant &other)
{
ValueHolder a = m_var;
if (m_type == t_user_ref) {
new (a.mp_user_ref.ptr) tl::WeakOrSharedPtr (*reinterpret_cast <tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr));
reinterpret_cast <tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->~WeakOrSharedPtr ();
}
m_var = other.m_var;
if (other.m_type == t_user_ref) {
new (m_var.mp_user_ref.ptr) tl::WeakOrSharedPtr (*reinterpret_cast <tl::WeakOrSharedPtr *> (other.m_var.mp_user_ref.ptr));
reinterpret_cast <tl::WeakOrSharedPtr *> (other.m_var.mp_user_ref.ptr)->~WeakOrSharedPtr ();
}
other.m_var = a;
if (m_type == t_user_ref) {
new (other.m_var.mp_user_ref.ptr) tl::WeakOrSharedPtr (*reinterpret_cast <tl::WeakOrSharedPtr *> (a.mp_user_ref.ptr));
reinterpret_cast <tl::WeakOrSharedPtr *> (a.mp_user_ref.ptr)->~WeakOrSharedPtr ();
}
std::swap (m_type, other.m_type);
std::swap (m_string, other.m_string);
}
QVariant Variant::to_qvariant () const
{
switch (m_type) {
case t_nil:
return QVariant ();
case t_double:
return QVariant (m_var.m_double);
case t_float:
return QVariant ((double) m_var.m_float);
case t_char:
return QVariant ((unsigned int) m_var.m_char);
case t_schar:
return QVariant ((int) m_var.m_schar);
case t_uchar:
return QVariant ((unsigned int) m_var.m_uchar);
case t_short:
return QVariant ((int) m_var.m_short);
case t_ushort:
return QVariant ((unsigned int) m_var.m_ushort);
case t_int:
return QVariant (m_var.m_int);
case t_uint:
return QVariant (m_var.m_uint);
case t_long:
// TODO: will int == long always?
return QVariant ((int) m_var.m_long);
case t_ulong:
// TODO: will unsigned int == long always?
return QVariant ((unsigned int) m_var.m_ulong);
case t_longlong:
return QVariant (m_var.m_longlong);
case t_ulonglong:
return QVariant (m_var.m_ulonglong);
#if defined(HAVE_64BIT_COORD)
case t_int128:
// TODO: support for int128 in QVariant?
return QVariant ((double) m_var.m_m128);
#endif
case t_bool:
return QVariant (m_var.m_bool);
case t_qstring:
return QVariant (*m_var.m_qstring);
case t_stdstring:
return QVariant (tl::to_qstring (*m_var.m_stdstring));
case t_string:
return QVariant (tl::to_qstring (m_string));
case t_qbytearray:
return QVariant (*m_var.m_qbytearray);
case t_list:
{
QList<QVariant> l;
for (std::vector<tl::Variant>::const_iterator v = m_var.m_list->begin (); v != m_var.m_list->end (); ++v) {
l.append (v->to_qvariant ());
}
return QVariant (l);
}
case t_array:
{
QMap<QString, QVariant> a;
for (const_array_iterator v = m_var.m_array->begin (); v != m_var.m_array->end (); ++v) {
a.insert (v->first.to_qstring (), v->second.to_qvariant ());
}
return QVariant (a);
}
case t_id:
return QVariant ((unsigned int) m_var.m_id);
case t_user:
{
const tl::VariantUserClassBase *cls = user_cls ();
// try any of the other supported classes of QVariant:
if (dynamic_cast<const tl::VariantUserClass<QBitArray> *> (cls)) {
return QVariant (to_user<QBitArray> ());
} else if (dynamic_cast<const tl::VariantUserClass<QBitArray> *> (cls)) {
return QVariant (to_user<QBitArray> ());
} else if (dynamic_cast<const tl::VariantUserClass<QBitmap> *> (cls)) {
return QVariant (to_user<QBitmap> ());
} else if (dynamic_cast<const tl::VariantUserClass<QBrush> *> (cls)) {
return QVariant (to_user<QBrush> ());
} else if (dynamic_cast<const tl::VariantUserClass<QChar> *> (cls)) {
return QVariant (to_user<QChar> ());
} else if (dynamic_cast<const tl::VariantUserClass<QColor> *> (cls)) {
return QVariant (to_user<QColor> ());
} else if (dynamic_cast<const tl::VariantUserClass<QCursor> *> (cls)) {
return QVariant (to_user<QCursor> ());
} else if (dynamic_cast<const tl::VariantUserClass<QDate> *> (cls)) {
return QVariant (to_user<QDate> ());
} else if (dynamic_cast<const tl::VariantUserClass<QDateTime> *> (cls)) {
return QVariant (to_user<QDateTime> ());
#if QT_VERSION >= 0x040700
} else if (dynamic_cast<const tl::VariantUserClass<QEasingCurve> *> (cls)) {
return QVariant (to_user<QEasingCurve> ());
#endif
} else if (dynamic_cast<const tl::VariantUserClass<QFont> *> (cls)) {
return QVariant (to_user<QFont> ());
} else if (dynamic_cast<const tl::VariantUserClass<QIcon> *> (cls)) {
return QVariant (to_user<QIcon> ());
} else if (dynamic_cast<const tl::VariantUserClass<QImage> *> (cls)) {
return QVariant (to_user<QImage> ());
#if QT_VERSION >= 0x050000
} else if (dynamic_cast<const tl::VariantUserClass<QKeySequence> *> (cls)) {
return QVariant (to_user<QKeySequence> ());
#endif
} else if (dynamic_cast<const tl::VariantUserClass<QLine> *> (cls)) {
return QVariant (to_user<QLine> ());
} else if (dynamic_cast<const tl::VariantUserClass<QLineF> *> (cls)) {
return QVariant (to_user<QLineF> ());
} else if (dynamic_cast<const tl::VariantUserClass<QLocale> *> (cls)) {
return QVariant (to_user<QLocale> ());
} else if (dynamic_cast<const tl::VariantUserClass<QTransform> *> (cls)) {
return QVariant (to_user<QTransform> ());
} else if (dynamic_cast<const tl::VariantUserClass<QMatrix4x4> *> (cls)) {
return QVariant (to_user<QMatrix4x4> ());
} else if (dynamic_cast<const tl::VariantUserClass<QPalette> *> (cls)) {
return QVariant (to_user<QPalette> ());
} else if (dynamic_cast<const tl::VariantUserClass<QPen> *> (cls)) {
return QVariant (to_user<QPen> ());
} else if (dynamic_cast<const tl::VariantUserClass<QPixmap> *> (cls)) {
return QVariant (to_user<QPixmap> ());
} else if (dynamic_cast<const tl::VariantUserClass<QPoint> *> (cls)) {
return QVariant (to_user<QPoint> ());
} else if (dynamic_cast<const tl::VariantUserClass<QPointF> *> (cls)) {
return QVariant (to_user<QPointF> ());
} else if (dynamic_cast<const tl::VariantUserClass<QPolygon> *> (cls)) {
return QVariant (to_user<QPolygon> ());
} else if (dynamic_cast<const tl::VariantUserClass<QQuaternion> *> (cls)) {
return QVariant (to_user<QQuaternion> ());
} else if (dynamic_cast<const tl::VariantUserClass<QRect> *> (cls)) {
return QVariant (to_user<QRect> ());
} else if (dynamic_cast<const tl::VariantUserClass<QRectF> *> (cls)) {
return QVariant (to_user<QRectF> ());
} else if (dynamic_cast<const tl::VariantUserClass<QRegExp> *> (cls)) {
return QVariant (to_user<QRegExp> ());
} else if (dynamic_cast<const tl::VariantUserClass<QRegion> *> (cls)) {
return QVariant (to_user<QRegion> ());
} else if (dynamic_cast<const tl::VariantUserClass<QSize> *> (cls)) {
return QVariant (to_user<QSize> ());
} else if (dynamic_cast<const tl::VariantUserClass<QSizeF> *> (cls)) {
return QVariant (to_user<QSizeF> ());
} else if (dynamic_cast<const tl::VariantUserClass<QSizePolicy> *> (cls)) {
return QVariant (to_user<QSizePolicy> ());
} else if (dynamic_cast<const tl::VariantUserClass<QTextFormat> *> (cls)) {
return QVariant (to_user<QTextFormat> ());
} else if (dynamic_cast<const tl::VariantUserClass<QTextLength> *> (cls)) {
return QVariant (to_user<QTextLength> ());
} else if (dynamic_cast<const tl::VariantUserClass<QTime> *> (cls)) {
return QVariant (to_user<QTime> ());
} else if (dynamic_cast<const tl::VariantUserClass<QUrl> *> (cls)) {
return QVariant (to_user<QUrl> ());
} else if (dynamic_cast<const tl::VariantUserClass<QVector2D> *> (cls)) {
return QVariant (to_user<QVector2D> ());
} else if (dynamic_cast<const tl::VariantUserClass<QVector3D> *> (cls)) {
return QVariant (to_user<QVector3D> ());
} else if (dynamic_cast<const tl::VariantUserClass<QVector4D> *> (cls)) {
return QVariant (to_user<QVector4D> ());
} else {
return QVariant ();
}
}
default:
return QVariant ();
}
}
void Variant::set_user_object (void *obj, bool shared)
{
m_var.mp_user.object = obj;
m_var.mp_user.shared = shared;
}
bool Variant::user_is_const () const
{
tl_assert (is_user ());
return user_cls ()->is_const ();
}
bool Variant::user_is_ref () const
{
if (m_type == t_user) {
return !m_var.mp_user.shared;
} else if (m_type == t_user_ref) {
return !reinterpret_cast <const tl::WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->is_shared ();
} else {
return false;
}
}
void Variant::user_destroy ()
{
tl_assert (is_user ());
void *obj = to_user ();
if (obj) {
user_cls ()->destroy (obj);
}
reset ();
}
void Variant::user_assign (const tl::Variant &other)
{
tl_assert (is_user ());
tl_assert (other.is_user ());
if (user_cls () == other.user_cls ()) {
user_cls ()->assign (to_user (), other.to_user ());
}
}
tl::Variant Variant::user_dup () const
{
tl_assert (is_user ());
return tl::Variant (user_cls ()->clone (to_user ()), user_cls (), true);
}
// ----------------------------------------------------------------------------------
// Extractor implementation
template <>
TL_PUBLIC bool test_extractor_impl (tl::Extractor &ex, tl::Variant &v)
{
std::string s;
if (ex.test ("##")) {
double x = 0;
ex.read (x);
v = x;
return true;
#if defined(HAVE_64BIT_COORD)
} else if (ex.test ("#ll")) {
__int128 x = 0;
ex.read (x);
v = x;
return true;
#endif
} else if (ex.test ("#lu")) {
unsigned long long x = 0;
ex.read (x);
v = x;
return true;
} else if (ex.test ("#l")) {
long long x = 0;
ex.read (x);
v = x;
return true;
} else if (ex.test ("#u")) {
unsigned long x = 0;
ex.read (x);
v = x;
return true;
} else if (ex.test ("#")) {
long x = 0;
ex.read (x);
v = x;
return true;
} else if (ex.test ("nil")) {
v = tl::Variant ();
return true;
} else if (ex.test ("false")) {
v = false;
return true;
} else if (ex.test ("true")) {
v = true;
return true;
} else if (ex.test ("[")) {
std::string cls;
ex.read_word_or_quoted (cls);
const VariantUserClassBase *ccls = tl::VariantUserClassBase::find_cls_by_name (cls);
if (ccls) {
void *obj = ccls->create ();
v.set_user (obj, ccls, true);
ex.test (":");
ccls->read (obj, ex);
}
ex.test ("]");
return true;
} else if (ex.test ("(")) {
std::vector<tl::Variant> values;
if (! ex.test (")")) {
while (true) {
values.push_back (tl::Variant ());
ex.read (values.back ());
if (ex.test (",")) {
// .. continue
} else {
ex.expect (")");
break;
}
}
}
v = tl::Variant (values.begin (), values.end ());
return true;
} else if (ex.test ("{")) {
v = tl::Variant::empty_array ();
if (! ex.test ("}")) {
while (true) {
tl::Variant k, x;
ex.read (k);
if (ex.test ("=>")) {
ex.read (x);
}
v.insert (k, x);
if (ex.test (",")) {
// .. continue
} else {
ex.expect ("}");
break;
}
}
}
return true;
} else if (ex.try_read_word_or_quoted (s)) {
v = tl::Variant (s);
return true;
} else {
return false;
}
}
template <>
TL_PUBLIC void extractor_impl (tl::Extractor &ex, tl::Variant &v)
{
if (! test_extractor_impl (ex, v)) {
ex.error (tl::to_string (QObject::tr ("Expected a value specification")));
}
}
} // namespace tl