/* 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 */ #ifndef _HDR_tlVariant #define _HDR_tlVariant #include "tlCommon.h" #include #include #include #include #include #include "tlInternational.h" #include "tlAssert.h" #include "tlObject.h" #include #include #include namespace gsi { class ClassBase; class NoAdaptorTag; template class Class; template const ClassBase *cls_decl (); } namespace tl { class Extractor; class EvalClass; /** * @brief A base class which describes a class, i.e. an object capable of converting and handling void * * * There must be one particular class object per class. In particular the equality of the * class object pointer's must indicate that two object's share the same class. */ class TL_PUBLIC VariantUserClassBase { public: VariantUserClassBase () { } virtual ~VariantUserClassBase () { } virtual void *create () const = 0; virtual void destroy (void *) const = 0; virtual bool equal (const void *, const void *) const = 0; virtual bool less (const void *, const void *) const = 0; virtual void *clone (const void *) const = 0; virtual std::string to_string (const void *) const = 0; virtual void read (void *, tl::Extractor &ex) const = 0; virtual const char *name () const = 0; virtual bool is_const () const = 0; virtual void assign (void *self, const void *other) const = 0; virtual const gsi::ClassBase *gsi_cls () const = 0; virtual const tl::EvalClass *eval_cls () const = 0; virtual void *deref_proxy (tl::Object *proxy) const = 0; const void *deref_proxy_const (const tl::Object *proxy) const { return deref_proxy (const_cast (proxy)); } static std::string translate_class_name (const std::string &lc_clsname); static void clear_class_table (); static void register_user_class (const std::string &name, const VariantUserClassBase *cls); static const VariantUserClassBase *find_cls_by_name (const std::string &name); protected: static const tl::VariantUserClassBase *instance (const std::type_info &type, bool is_const); static void register_instance (const tl::VariantUserClassBase *inst, const std::type_info &type, bool is_const); static void unregister_instance (const tl::VariantUserClassBase *inst, const std::type_info &type, bool is_const); }; /** * @brief A derived class encapsulating a certain user type * * We will employ RTTI to identify a type through that base class. */ template class VariantUserClass : public VariantUserClassBase { public: VariantUserClass () { } T *get (void *ptr) const { return reinterpret_cast (ptr); } const T *get (const void *ptr) const { return reinterpret_cast (ptr); } static const tl::VariantUserClassBase *instance (bool is_const) { return VariantUserClassBase::instance (typeid (T), is_const); } private: static const tl::VariantUserClassBase *ms_instances[4]; protected: void register_instance (const tl::VariantUserClassBase *inst, bool is_const) { VariantUserClassBase::register_instance (inst, typeid (T), is_const); } void unregister_instance (const tl::VariantUserClassBase *inst, bool is_const) { VariantUserClassBase::unregister_instance (inst, typeid (T), is_const); } }; /** * @brief A basic variant type * * This variant is capable of storing long, double, std::string, void (nil) and lists * of other variants. */ class TL_PUBLIC Variant { public: enum type { t_nil, t_bool, t_char, t_schar, t_uchar, t_short, t_ushort, t_int, t_uint, t_long, t_ulong, t_longlong, t_ulonglong, #if defined(HAVE_64BIT_COORD) t_int128, #endif t_id, t_float, t_double, t_string, t_stdstring, t_qstring, t_qbytearray, t_list, t_array, t_user, t_user_ref }; typedef std::vector::const_iterator const_iterator; typedef std::vector::iterator iterator; typedef std::map array_type; typedef array_type::const_iterator const_array_iterator; typedef array_type::iterator array_iterator; /** * @brief Initialize the Variant with "nil" */ Variant (); /** * @brief Copy ctor */ Variant (const tl::Variant &d); /** * @brief Initialize the Variant with a QByteArray */ Variant (const QByteArray &s); /** * @brief Initialize the Variant with a QString */ Variant (const QString &s); /** * @brief Initialize the Variant with "string" */ Variant (const std::string &s); /** * @brief Initialize the Variant with "string" */ Variant (const char *s); /** * @brief Initialize the Variant with "double" */ Variant (double d); /** * @brief Initialize the Variant with "float" */ Variant (float d); /** * @brief Initialize the Variant with "char" */ Variant (char c); /** * @brief Initialize the Variant with "signed char" */ Variant (signed char c); /** * @brief Initialize the Variant with "unsigned char" */ Variant (unsigned char c); /** * @brief Initialize the Variant with "short" */ Variant (short s); /** * @brief Initialize the Variant with "unsigned short" */ Variant (unsigned short s); /** * @brief Initialize the Variant with "bool" */ Variant (bool l); /** * @brief Initialize the Variant with "int" (actually "long") */ Variant (int l); /** * @brief Initialize the Variant with "unsigned int" (actually "unsigned long") */ Variant (unsigned int l); /** * @brief Initialize the Variant with "long" */ Variant (long l); /** * @brief Initialize the Variant with "unsigned long" */ Variant (unsigned long l); /** * @brief Initialize the Variant with "long long" */ Variant (long long l); /** * @brief Initialize the Variant with "unsigned long long" */ Variant (unsigned long long l); #if defined(HAVE_64BIT_COORD) /** * @brief Initialize the Variant with "__int128" */ Variant (__int128 l); #endif /** * @brief Initialize the Variant with an "id" * * The "id" type is basically a size_t, but is supposed to be used as a representative for another value. * One application for that type is a placeholder for an OASIS name until it is associated with a real value. */ Variant (size_t l, bool /*dummy*/); /** * @brief Create from a QVariant * * This constructor will convert a QVariant into a tl::Variant as far as possible. */ explicit Variant (const QVariant &v); /** * @brief Initialize with a user type based on void * * * The Variant will take over the ownership over the user object. */ Variant (void *object, const VariantUserClassBase *cls, bool shared) : m_type (t_user), m_string (0) { m_var.mp_user.object = object; m_var.mp_user.shared = shared; m_var.mp_user.cls = cls; } /** * @brief Initialize with a user type based on tl::Object * * If shared is true, the variant will use a shared pointer to manage the ownership * of the object (i.e. if the object is new'd it will be deleted by the variant). If * shared is false, a weak pointer will be employed that watches the object. */ Variant (tl::Object *object, const VariantUserClassBase *cls, bool shared) : m_type (t_user_ref), m_string (0) { new (m_var.mp_user_ref.ptr) WeakOrSharedPtr (object, shared); m_var.mp_user_ref.cls = cls; } /** * @brief Initialize with a user type (will always create a deep copy) */ template Variant (const T &obj) : m_type (t_user), m_string (0) { const tl::VariantUserClassBase *c = tl::VariantUserClass::instance (false); tl_assert (c != 0); m_var.mp_user.object = new T (obj); m_var.mp_user.shared = true; m_var.mp_user.cls = c; } /** * @brief Initialize the Variant with a list */ template Variant (Iter from, Iter to) : m_type (t_list), m_string (0) { m_var.m_list = new std::vector (from, to); } /** * @brief Destructor */ ~Variant (); /** * @brief Utility: initialize a variant from GSI type reference */ template static tl::Variant make_variant_ref (T *t) { const tl::VariantUserClassBase *c = gsi::cls_decl ()->var_cls (false); tl_assert (c != 0); return tl::Variant ((void *) t, c, false); } /** * @brief Utility: initialize a variant from GSI type reference */ template static tl::Variant make_variant_ref (const T *t) { const tl::VariantUserClassBase *c = gsi::cls_decl ()->var_cls (true); tl_assert (c != 0); return tl::Variant ((void *) t, c, false); } /** * @brief Utility: initialize a variant from GSI type (take over ownership) */ template static tl::Variant make_variant (T *t) { const tl::VariantUserClassBase *c = gsi::cls_decl ()->var_cls (false); tl_assert (c != 0); return tl::Variant ((void *) t, c, true); } /** * @brief Utility: initialize a variant from GSI type (deep copy) */ template static tl::Variant make_variant (const T &t, bool is_const = false) { const tl::VariantUserClassBase *c = gsi::cls_decl ()->var_cls (is_const); tl_assert (c != 0); return tl::Variant ((void *) new T(t), c, true); } /** * @brief Convert to a QVariant */ QVariant to_qvariant () const; /** * @brief Assignment */ Variant &operator= (const Variant &v); /** * @brief Assignment of a string */ Variant &operator= (const char *v); /** * @brief Assignment of a QByteArray */ Variant &operator= (const QByteArray &v); /** * @brief Assignment of a QString */ Variant &operator= (const QString &v); /** * @brief Assignment of a string */ Variant &operator= (const std::string &v); /** * @brief Assignment of a double */ Variant &operator= (double d); /** * @brief Assignment of a float */ Variant &operator= (float d); /** * @brief Assignment of a bool */ Variant &operator= (bool l); /** * @brief Assignment of a char */ Variant &operator= (char l); /** * @brief Assignment of an unsigned char */ Variant &operator= (unsigned char c); /** * @brief Assignment of a signed char */ Variant &operator= (signed char c); /** * @brief Assignment of a short */ Variant &operator= (short s); /** * @brief Assignment of an unsigned char */ Variant &operator= (unsigned short s); /** * @brief Assignment of a int */ Variant &operator= (int l); /** * @brief Assignment of a unsigned int */ Variant &operator= (unsigned int l); /** * @brief Assignment of a long */ Variant &operator= (long l); /** * @brief Assignment of a unsigned long */ Variant &operator= (unsigned long l); /** * @brief Assignment of a long long */ Variant &operator= (long long l); /** * @brief Assignment of a unsigned long long */ Variant &operator= (unsigned long long l); #if defined(HAVE_64BIT_COORD) /** * @brief Assignment of a int128 */ Variant &operator= (__int128 l); #endif /** * @brief Reset to nil */ void reset (); /** * @brief Initialize with a user type */ void set_user (void *object, const VariantUserClassBase *cls, bool shared) { reset (); m_type = t_user; m_var.mp_user.object = object; m_var.mp_user.shared = shared; m_var.mp_user.cls = cls; } /** * @brief Initialize with a user type */ void set_user_ref (tl::Object *obj, const VariantUserClassBase *cls, bool shared) { reset (); m_type = t_user_ref; new (m_var.mp_user_ref.ptr) tl::WeakOrSharedPtr (obj, shared); m_var.mp_user_ref.cls = cls; } /** * @brief Initialize with an empty list with the given reserve */ void set_list (size_t reserve = 0) { reset (); m_type = t_list; m_var.m_list = new std::vector (); if (reserve > 0) { m_var.m_list->reserve (reserve); } } /** * @brief Initialize with an empty array */ void set_array () { reset (); m_type = t_array; m_var.m_array = new std::map (); } /** * @brief Equality * * For user types, this is not implemented yet. */ bool operator== (const Variant &d) const; /** * @brief Inequality * * For user types, this is not implemented yet. */ bool operator!= (const Variant &d) const { return !operator== (d); } /** * @brief Comparison * * For user types, this is not implemented yet. */ bool operator< (const Variant &d) const; /** * @brief Conversion to a string * * This performs the conversion to a string as far as possible. * No conversion is provided to user types currently. */ const char *to_string () const; /** * @brief Conversion to a QByteArray * * This performs the conversion to a QByteArray as far as possible. * No conversion is provided to user types currently. */ QByteArray to_qbytearray () const; /** * @brief Conversion to a QString * * This performs the conversion to a QString as far as possible. * No conversion is provided to user types currently. */ QString to_qstring () const; /** * @brief Conversion to a std::string * * This performs the conversion to a QString as far as possible. * No conversion is provided to user types currently. */ std::string to_stdstring () const; /** * @brief Conversion to a unsigned long long * * This performs the conversion to a unsigned long long as far as possible. * No conversion is provided to user types currently. */ unsigned long long to_ulonglong () const; /** * @brief Conversion to a long long * * This performs the conversion to a long long as far as possible. * No conversion is provided to user types currently. */ long long to_longlong () const; #if defined(HAVE_64BIT_COORD) /** * @brief Conversion to an int128 */ __int128 to_int128 () const; #endif /** * @brief Conversion to a unsigned int * * This performs the conversion to a unsigned int as far as possible. * No conversion is provided to user types currently. */ unsigned int to_uint () const; /** * @brief Conversion to a int * * This performs the conversion to a int as far as possible. * No conversion is provided to user types currently. */ int to_int () const; /** * @brief Conversion to a unsigned long * * This performs the conversion to a unsigned long as far as possible. * No conversion is provided to user types currently. */ unsigned long to_ulong () const; /** * @brief Conversion to a long * * This performs the conversion to a long as far as possible. * No conversion is provided to user types currently. */ long to_long () const; /** * @brief Conversion to a unsigned long * * This performs the conversion to a unsigned short as far as possible. * No conversion is provided to user types currently. */ unsigned short to_ushort () const; /** * @brief Conversion to a short * * This performs the conversion to a short as far as possible. * No conversion is provided to user types currently. */ short to_short () const; /** * @brief Conversion to a signed char * * This performs the conversion to a signed char as far as possible. * No conversion is provided to user types currently. */ signed char to_schar () const; /** * @brief Conversion to a unsigned char * * This performs the conversion to an unsigned char as far as possible. * No conversion is provided to user types currently. */ unsigned char to_uchar () const; /** * @brief Conversion to a char * * This performs the conversion to a char as far as possible. * No conversion is provided to user types currently. */ char to_char () const; /** * @brief Conversion to an id * * This gets the id value if the variant is an id. * No conversion is provided to user types currently. */ size_t to_id () const; /** * @brief Conversion to a bool * * This performs the conversion to a bool as far as possible. * No conversion is provided to user types currently. */ bool to_bool () const; /** * @brief Conversion to a double * * This performs the conversion to a double value as far as possible. * No conversion is provided to user types currently. */ double to_double () const; /** * @brief Conversion to a float * * This performs the conversion to a float value as far as possible. * No conversion is provided to user types currently. */ float to_float () const; /** * @brief conversion to a standard type * * This is a templatized version of the various to_... methods. This * does also not include conversion to a user type. * This is the generic version. Specializations follow. */ template T to () const { tl_assert (false); } /** * @brief Converts to the user object (const) */ const void *to_user () const { if (m_type == t_user) { return m_var.mp_user.object; } else if (m_type == t_user_ref) { return m_var.mp_user_ref.cls->deref_proxy_const (reinterpret_cast (m_var.mp_user_ref.ptr)->get ()); } else { return 0; } } /** * @brief Converts to the user object */ void *to_user () { if (m_type == t_user) { return m_var.mp_user.object; } else if (m_type == t_user_ref) { return m_var.mp_user_ref.cls->deref_proxy (reinterpret_cast (m_var.mp_user_ref.ptr)->get ()); } else { return 0; } } /** * @brief Converts to a tl::Object (const) */ const tl::Object *to_object () const { if (m_type == t_user_ref) { return reinterpret_cast (m_var.mp_user_ref.ptr)->get (); } else { return 0; } } /** * @brief Converts to the user object */ tl::Object *to_object () { return const_cast (((const tl::Variant *) this)->to_object ()); } /** * @brief Gets the user object's class */ const VariantUserClassBase *user_cls () const { if (m_type == t_user) { return m_var.mp_user.cls; } else if (m_type == t_user_ref) { return m_var.mp_user_ref.cls; } else { return 0; } } /** * @brief Gets the GSI class if the variant is a user object */ const gsi::ClassBase *gsi_cls () const { return user_cls () ? user_cls ()->gsi_cls () : 0; } /** * @brief Returns a value indicating whether the user object is a const reference or object */ bool user_is_const () const; /** * @brief Returns a value indicating whether the user object is a reference * References do not own the object and upon destruction of the tl::Variant the object * is not deleted. */ bool user_is_ref () const; /** * @brief Deletes the user object * An object can only be deleted if it is owned by the variant, i.e. user_is_ref is false. */ void user_destroy (); /** * @brief Assigns the object stored in other to self * * "other" needs to be a user object and the class of "other" needs to be same as self. */ void user_assign (const tl::Variant &other); /** * @brief Creates a clone of the current object */ tl::Variant user_dup () const; /** * @brief Convert to the given user type (const version) */ template const T &to_user () const { if (is_user()) { const VariantUserClass *tcls = dynamic_cast *> (user_cls ()); tl_assert (tcls != 0); const T *t = tcls->get (to_user ()); tl_assert (t); return *t; } else { tl_assert (false); } } /** * @brief Convert to the given user type */ template T &to_user () { return const_cast (((const Variant *) this)->to_user ()); } /** * @brief Morph to the given type * * After morphing the variant, the variant will use the given type internally. * The native pointer can be used to access the value then. * A nil value is not morphed and remains nil. In that case, the native pointer will be 0. */ template tl::Variant &morph () { if (! is_nil ()) { *this = to (); } return *this; } /** * @brief Cast to the given type * * This creates a new variant which uses the given type internally */ template Variant cast () const { return Variant (to ()); } /** * @brief Access the native (internal) object * * For nil, 0 is returned. */ void *native_ptr () { // saves one implementation ... return const_cast (((const tl::Variant *) this)->native_ptr ()); } /** * @brief Access the native (internal) object * * For nil, 0 is returned. */ const void *native_ptr () const; /** * @brief Get the list iterators, if it is one */ const_iterator begin () const { tl_assert (m_type == t_list); return m_var.m_list->begin (); } /** * @brief Get the list iterators, if it is one */ const_iterator end () const { tl_assert (m_type == t_list); return m_var.m_list->end (); } /** * @brief Get the list iterators, if it is one */ iterator begin () { tl_assert (m_type == t_list); return m_var.m_list->begin (); } /** * @brief Get the list iterators, if it is one */ iterator end () { tl_assert (m_type == t_list); return m_var.m_list->end (); } /** * @brief Reserve some length for a list */ void reserve (size_t n) { tl_assert (m_type == t_list); m_var.m_list->reserve (n); } /** * @brief Get the length of the list if there is one, otherwise 0 */ size_t size () const { return m_type == t_list ? m_var.m_list->size () : 0; } /** * @brief Add a element to the list */ void push (const tl::Variant &v) { tl_assert (m_type == t_list); m_var.m_list->push_back (v); } /** * @brief Get the back element of the list */ tl::Variant &back () { tl_assert (m_type == t_list); return m_var.m_list->back (); } /** * @brief Get the back element of the list (const) */ const tl::Variant &back () const { tl_assert (m_type == t_list); return m_var.m_list->back (); } /** * @brief Get the front element of the list */ tl::Variant &front () { tl_assert (m_type == t_list); return m_var.m_list->front (); } /** * @brief Get the front element of the list (const) */ const tl::Variant &front () const { tl_assert (m_type == t_list); return m_var.m_list->front (); } /** * @brief Get the list, if it is one */ std::vector &get_list () { tl_assert (m_type == t_list); return *m_var.m_list; } /** * @brief Get the list, if it is one (const) */ const std::vector &get_list () const { tl_assert (m_type == t_list); return *m_var.m_list; } /** * @brief Get the array iterators, if it is one */ const_array_iterator begin_array () const { tl_assert (m_type == t_array); return m_var.m_array->begin (); } /** * @brief Get the array iterators, if it is one */ const_array_iterator end_array () const { tl_assert (m_type == t_array); return m_var.m_array->end (); } /** * @brief Get the array iterators, if it is one */ array_iterator begin_array () { tl_assert (m_type == t_array); return m_var.m_array->begin (); } /** * @brief Get the array iterators, if it is one */ array_iterator end_array () { tl_assert (m_type == t_array); return m_var.m_array->end (); } /** * @brief Get the length of the array if there is one, otherwise 0 */ size_t array_size () const { return m_type == t_array ? m_var.m_array->size () : 0; } /** * @brief Insert an element into the array */ void insert (const tl::Variant &k, const tl::Variant &v) { tl_assert (m_type == t_array); m_var.m_array->insert (std::make_pair (k, v)); } /** * @brief Returns the value for the given key or 0 if the variant is not an array or does not contain the key */ tl::Variant *find (const tl::Variant &k); /** * @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 *find (const tl::Variant &k) const; /** * @brief Get the list, if it is one */ array_type &get_array () { tl_assert (m_type == t_array); return *m_var.m_array; } /** * @brief Get the list, if it is one (const) */ const array_type &get_array () const { tl_assert (m_type == t_array); return *m_var.m_array; } /** * @brief Test, if it can convert to a double * * All numeric types can convert to double. That is double and the integer types. */ bool can_convert_to_double () const; /** * @brief Test, if it can convert to a float * * All numeric types can convert to float. That is double and the integer types unless the double value is outside the float range. */ bool can_convert_to_float () const; /** * @brief Test, if it can convert to a char * * All numeric types can convert to char unless the value is outside the allowed range. */ bool can_convert_to_char () const; /** * @brief Test, if it can convert to an signed char * * All numeric types can convert to signed char unless the value is outside the allowed range. */ bool can_convert_to_schar () const; /** * @brief Test, if it can convert to an unsigned char * * All numeric types can convert to unsigned char unless the value is outside the allowed range. */ bool can_convert_to_uchar () const; /** * @brief Test, if it can convert to a short * * All numeric types can convert to short unless the value is outside the allowed range. */ bool can_convert_to_short () const; /** * @brief Test, if it can convert to an unsigned short * * All numeric types can convert to unsigned short unless the value is outside the allowed range. */ bool can_convert_to_ushort () const; /** * @brief Test, if it can convert to an int * * All numeric types can convert to int unless the value is outside the allowed range. */ bool can_convert_to_int () const; /** * @brief Test, if it can convert to an unsigned int * * All numeric types can convert to unsigned int unless the value is outside the allowed range. */ bool can_convert_to_uint () const; /** * @brief Test, if it can convert to a long * * All numeric types can convert to long unless the value is outside the allowed range. */ bool can_convert_to_long () const; /** * @brief Test, if it can convert to an unsigned long * * All numeric types can convert to unsigned long unless the value is outside the allowed range. */ bool can_convert_to_ulong () const; /** * @brief Test, if it can convert to a long long * * All numeric types can convert to long unless the value is outside the allowed range. */ bool can_convert_to_longlong () const; /** * @brief Test, if it can convert to an unsigned long long * * All numeric types can convert to unsigned long unless the value is outside the allowed range. */ bool can_convert_to_ulonglong () const; #if defined(HAVE_64BIT_COORD) /** * @brief Test, if it can convert to an int128 */ bool can_convert_to_int128 () const; #endif /** * @brief Returns true if the conversion to the given type is possible * * This is a templatized version of the various can_convert_to_... methods. This * does not include conversion to a user type, arrays or lists. * This is the generic version. Specializations follow. */ template bool can_convert_to () const { return false; } /** * @brief Test, if it is a double or can be converted to a double */ bool is_double () const { return m_type == t_double || m_type == t_float; } /** * @brief Test, if it is a char */ bool is_char () const { return m_type == t_char; } /** * @brief Test, if it is a long or can be converted to a long */ bool is_long () const { return m_type == t_long || m_type == t_int || m_type == t_short || m_type == t_schar; } /** * @brief Test, if it is an unsigned long or can be converted into one */ bool is_ulong () const { return m_type == t_ulong || m_type == t_uint || m_type == t_ushort || m_type == t_uchar; } /** * @brief Test, if it is a long long */ bool is_longlong () const { return m_type == t_longlong; } /** * @brief Test, if it is a unsigned long long */ bool is_ulonglong () const { return m_type == t_ulonglong; } #if defined(HAVE_64BIT_COORD) /** * @brief Test, if it is an int128 */ bool is_int128 () const { return m_type == t_int128; } #endif /** * @brief Test, if it is a bool */ bool is_bool () const { return m_type == t_bool; } /** * @brief Test, if it is a id */ bool is_id () const { return m_type == t_id; } /** * @brief Test, if it is a QByteArray */ bool is_qbytearray () const { return m_type == t_qbytearray; } /** * @brief Test, if it is a QString */ bool is_qstring () const { return m_type == t_qstring; } /** * @brief Test, if it is a std::string */ bool is_stdstring () const { return m_type == t_stdstring; } /** * @brief Test, if it is a "C" string */ bool is_cstring () const { return m_type == t_string; } /** * @brief Test, if it is any string */ bool is_a_string () const { return m_type == t_string || m_type == t_stdstring || m_type == t_qstring || m_type == t_qbytearray; } /** * @brief Returns true if the variant is of the given type internally * * This is a templatized version of the various can_convert_to_... methods. This * does not include conversion to a user type, arrays or lists. * This is the generic version. Specializations follow. */ template bool is () const { return false; } /** * @brief Test, if it is nil */ bool is_nil () const { return m_type == t_nil; } /** * @brief Test, if it is an array */ bool is_array () const { return m_type == t_array; } /** * @brief Test, if it is a list */ bool is_list () const { return m_type == t_list; } /** * @brief Get the type code */ type type_code () const { return m_type; } /** * @brief Test, if this is a user type */ bool is_user () const { return m_type == t_user || m_type == t_user_ref; } /** * @brief Test, if this is a user type and can convert to the given type */ template bool is_user () const { if (m_type == t_user) { const VariantUserClass *tcls = dynamic_cast *> (m_var.mp_user.cls); return tcls != 0; } else if (m_type == t_user_ref) { const VariantUserClass *tcls = dynamic_cast *> (m_var.mp_user_ref.cls); return tcls != 0; } else { return false; } } /** * @brief Test, if this is a user type of tl::Object class */ bool is_object () const { return m_type == t_user_ref; } /** * @brief Test, if this is a user type and can convert to the given type */ template bool is_object () const { if (m_type == t_user_ref) { const VariantUserClass *tcls = dynamic_cast *> (m_var.mp_user_ref.cls); return tcls != 0; } else { return false; } } /** * @brief Swap contents with another instance */ void swap (tl::Variant &other); /** * @brief A method to deliver an empty-list variant */ static tl::Variant empty_list (); /** * @brief A method to deliver an empty-array variant */ static tl::Variant empty_array (); /** * @brief Convert the Variant to a string that can be parsed with the Extractor * * No conversion is provided for user types and "nil" currently. */ std::string to_parsable_string () const; private: type m_type; union ValueHolder { std::vector *m_list; std::map *m_array; double m_double; float m_float; char m_char; unsigned char m_uchar; signed char m_schar; short m_short; unsigned short m_ushort; int m_int; unsigned int m_uint; long m_long; unsigned long m_ulong; long long m_longlong; unsigned long long m_ulonglong; #if defined(HAVE_64BIT_COORD) __int128 m_int128; #endif bool m_bool; size_t m_id; struct { void *object; bool shared; const VariantUserClassBase *cls; } mp_user; struct { char ptr [sizeof (WeakOrSharedPtr)]; const VariantUserClassBase *cls; } mp_user_ref; QString *m_qstring; QByteArray *m_qbytearray; std::string *m_stdstring; } m_var; // this will hold the string if it is valid mutable char *m_string; void set_user_object (void *obj, bool shared); }; // specializations of the to ... methods template<> inline bool Variant::to () const { return to_bool (); } template<> inline char Variant::to () const { return to_char (); } template<> inline unsigned char Variant::to () const { return to_uchar (); } template<> inline signed char Variant::to () const { return to_schar (); } template<> inline short Variant::to () const { return to_short (); } template<> inline unsigned short Variant::to () const { return to_ushort (); } template<> inline int Variant::to () const { return to_int (); } template<> inline unsigned int Variant::to () const { return to_uint (); } template<> inline long Variant::to () const { return to_long (); } template<> inline unsigned long Variant::to () const { return to_ulong (); } template<> inline long long Variant::to () const { return to_longlong (); } template<> inline unsigned long long Variant::to () const { return to_ulonglong (); } #if defined(HAVE_64BIT_COORD) template<> inline __int128 Variant::to<__int128> () const { return to_int128 (); } #endif template<> inline double Variant::to () const { return to_double (); } template<> inline float Variant::to () const { return to_float (); } template<> inline std::string Variant::to () const { return to_stdstring (); } template<> inline QString Variant::to () const { return to_qstring (); } template<> inline QByteArray Variant::to () const { return to_qbytearray (); } template<> inline const char *Variant::to () const { return to_string (); } // specializations if the is.. methods template<> inline bool Variant::is () const { return m_type == t_bool; } template<> inline bool Variant::is () const { return m_type == t_char; } template<> inline bool Variant::is () const { return m_type == t_uchar; } template<> inline bool Variant::is () const { return m_type == t_schar; } template<> inline bool Variant::is () const { return m_type == t_short; } template<> inline bool Variant::is () const { return m_type == t_ushort; } template<> inline bool Variant::is () const { return m_type == t_int; } template<> inline bool Variant::is () const { return m_type == t_uint; } template<> inline bool Variant::is () const { return m_type == t_long; } template<> inline bool Variant::is () const { return m_type == t_ulong; } template<> inline bool Variant::is () const { return m_type == t_longlong; } template<> inline bool Variant::is () const { return m_type == t_ulonglong; } #if defined(HAVE_64BIT_COORD) template<> inline bool Variant::is<__int128> () const { return m_type == t_int128; } #endif template<> inline bool Variant::is () const { return m_type == t_double; } template<> inline bool Variant::is () const { return m_type == t_float; } template<> inline bool Variant::is () const { return m_type == t_stdstring; } template<> inline bool Variant::is () const { return m_type == t_qstring; } template<> inline bool Variant::is () const { return m_type == t_qbytearray; } template<> inline bool Variant::is () const { return m_type == t_string; } // specializations of the can_convert.. methods template<> inline bool Variant::can_convert_to () const { return true; } template<> inline bool Variant::can_convert_to () const { return can_convert_to_char (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_uchar (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_schar (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_short (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_ushort (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_int (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_uint (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_long (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_ulong (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_longlong (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_ulonglong (); } #if defined(HAVE_64BIT_COORD) template<> inline bool Variant::can_convert_to<__int128> () const { return can_convert_to_int128 (); } #endif template<> inline bool Variant::can_convert_to () const { return can_convert_to_double (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_float (); } template<> inline bool Variant::can_convert_to () const { return true; } template<> inline bool Variant::can_convert_to () const { return true; } template<> inline bool Variant::can_convert_to () const { return true; } template<> inline bool Variant::can_convert_to () const { return true; } /** * @brief Initialize the class table (must be called once) */ void initialize_variant_class_table (); } // namespace tl #endif