/* 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 #include #include #include // the Qt classes supported by QVariant: #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x040600 # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 *sp_class_table = 0; static std::map 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 ::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::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 (); } (*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::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 m = v.toHash (); set_array (); for (QHash::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 vl = v.toList (); set_list (); for (QList::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 m = v.toMap (); set_array (); for (QMap::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 ())); break; case QVariant::Bitmap: operator= (tl::Variant (v.value ())); break; case QVariant::Brush: operator= (tl::Variant (v.value ())); break; case QVariant::Color: operator= (tl::Variant (v.value ())); break; case QVariant::Cursor: operator= (tl::Variant (v.value ())); break; case QVariant::Date: operator= (tl::Variant (v.value ())); break; case QVariant::DateTime: operator= (tl::Variant (v.value ())); break; #if QT_VERSION >= 0x040700 case QVariant::EasingCurve: operator= (tl::Variant (v.value ())); break; #endif case QVariant::Font: operator= (tl::Variant (v.value ())); break; case QVariant::Icon: operator= (tl::Variant (v.value ())); break; case QVariant::Image: operator= (tl::Variant (v.value ())); break; case QVariant::KeySequence: operator= (tl::Variant (v.value ())); break; case QVariant::Line: operator= (tl::Variant (v.value ())); break; case QVariant::LineF: operator= (tl::Variant (v.value ())); break; case QVariant::Locale: operator= (tl::Variant (v.value ())); break; case QVariant::Transform: operator= (tl::Variant (v.value ())); break; case QVariant::Matrix4x4: operator= (tl::Variant (v.value ())); break; case QVariant::Palette: operator= (tl::Variant (v.value ())); break; case QVariant::Pen: operator= (tl::Variant (v.value ())); break; case QVariant::Pixmap: operator= (tl::Variant (v.value ())); break; case QVariant::Point: operator= (tl::Variant (v.value ())); break; case QVariant::PointF: operator= (tl::Variant (v.value ())); break; case QVariant::Polygon: operator= (tl::Variant (v.value ())); break; case QVariant::Quaternion: operator= (tl::Variant (v.value ())); break; case QVariant::Rect: operator= (tl::Variant (v.value ())); break; case QVariant::RectF: operator= (tl::Variant (v.value ())); break; case QVariant::RegExp: operator= (tl::Variant (v.value ())); break; case QVariant::Region: operator= (tl::Variant (v.value ())); break; case QVariant::Size: operator= (tl::Variant (v.value ())); break; case QVariant::SizeF: operator= (tl::Variant (v.value ())); break; case QVariant::SizePolicy: operator= (tl::Variant (v.value ())); break; case QVariant::TextFormat: operator= (tl::Variant (v.value ())); break; case QVariant::TextLength: operator= (tl::Variant (v.value ())); break; case QVariant::Time: operator= (tl::Variant (v.value ())); break; case QVariant::Url: operator= (tl::Variant (v.value ())); break; case QVariant::Vector2D: operator= (tl::Variant (v.value ())); break; case QVariant::Vector3D: operator= (tl::Variant (v.value ())); break; case QVariant::Vector4D: operator= (tl::Variant (v.value ())); 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 (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 (*v.m_var.m_list); } else if (m_type == t_array) { m_var.m_array = new std::map (*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 (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 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 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 (m_var.mp_user_ref.ptr)->get (); const tl::Object *other = reinterpret_cast (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 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 (m_var.mp_user_ref.ptr)->get (); const tl::Object *other = reinterpret_cast (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::max () && m_var.m_double > std::numeric_limits::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::max () && m_var.m_double >= std::numeric_limits::min (); case t_float: return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::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::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::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::max () && m_var.m_double >= std::numeric_limits::min (); case t_float: return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::min ()); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); #endif case t_ulonglong: return m_var.m_ulonglong <= (unsigned long long) std::numeric_limits::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::max () && m_var.m_double >= std::numeric_limits::min (); case t_float: return m_var.m_float <= std::numeric_limits::max () && m_var.m_float >= std::numeric_limits::min (); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); #endif case t_longlong: return m_var.m_longlong >= 0 && m_var.m_longlong < (long long) std::numeric_limits::max (); case t_ulonglong: return m_var.m_ulonglong < (unsigned long long) std::numeric_limits::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::max () && m_var.m_double >= std::numeric_limits::min (); case t_float: return m_var.m_float <= std::numeric_limits::max () && m_var.m_float >= std::numeric_limits::min (); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); #endif case t_ulonglong: return m_var.m_ulonglong <= (unsigned long long) std::numeric_limits::max (); case t_longlong: return m_var.m_longlong >= (long long) std::numeric_limits::min () && m_var.m_longlong <= (long long) std::numeric_limits::max (); case t_ulong: return m_var.m_ulong <= (unsigned long) std::numeric_limits::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::max () && m_var.m_double >= std::numeric_limits::min (); case t_float: return m_var.m_float <= std::numeric_limits::max () && m_var.m_float >= std::numeric_limits::min (); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); #endif case t_ulonglong: return m_var.m_ulonglong <= (unsigned long long) std::numeric_limits::max (); case t_longlong: return m_var.m_longlong >= (long long) std::numeric_limits::min () && m_var.m_longlong <= (long long) std::numeric_limits::max (); case t_ulong: return m_var.m_ulong <= (unsigned long) std::numeric_limits::max (); case t_uint: return m_var.m_uint <= (unsigned int) std::numeric_limits::max (); case t_long: return m_var.m_long >= (long) std::numeric_limits::min () && m_var.m_long <= (long) std::numeric_limits::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::min () && l <= (long) std::numeric_limits::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::max () && m_var.m_double >= std::numeric_limits::min (); case t_float: return m_var.m_float <= std::numeric_limits::max () && m_var.m_float >= std::numeric_limits::min (); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); #endif case t_ulonglong: return m_var.m_ulonglong <= (unsigned long long) std::numeric_limits::max (); case t_longlong: return m_var.m_longlong >= (long long) std::numeric_limits::min () && m_var.m_longlong <= (long long) std::numeric_limits::max (); case t_ulong: return m_var.m_ulong <= (unsigned long) std::numeric_limits::max (); case t_int: return m_var.m_int >= (long) std::numeric_limits::min (); case t_long: return m_var.m_long >= (long) std::numeric_limits::min () && (sizeof (long) == sizeof (unsigned int) || m_var.m_long <= (long) std::numeric_limits::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::min () && l <= (long) std::numeric_limits::max (); } default: return false; } } bool Variant::can_convert_to_short () const { return can_convert_to_long () && (to_long () <= (long) std::numeric_limits::max () && to_long () >= (long) std::numeric_limits::min ()); } bool Variant::can_convert_to_ushort () const { return can_convert_to_long () && (to_long () <= (long) std::numeric_limits::max () && to_long () >= (long) std::numeric_limits::min ()); } bool Variant::can_convert_to_char () const { return can_convert_to_long () && (to_long () <= (long) std::numeric_limits::max () && to_long () >= (long) std::numeric_limits::min ()); } bool Variant::can_convert_to_schar () const { return can_convert_to_long () && (to_short () <= (long) std::numeric_limits::max () && to_short () >= (long) std::numeric_limits::min ()); } bool Variant::can_convert_to_uchar () const { return can_convert_to_long () && (to_short () <= (long) std::numeric_limits::max () && to_short () >= (long) std::numeric_limits::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::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 (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 (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 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 (m_var.mp_user_ref.ptr)); reinterpret_cast (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 (other.m_var.mp_user_ref.ptr)); reinterpret_cast (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 (a.mp_user_ref.ptr)); reinterpret_cast (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 l; for (std::vector::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 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 *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); #if QT_VERSION >= 0x040700 } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); #endif } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); #if QT_VERSION >= 0x050000 } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); #endif } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } else if (dynamic_cast *> (cls)) { return QVariant (to_user ()); } 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 (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 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