klayout/src/tl/tlVariant.h

1584 lines
40 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
*/
#ifndef _HDR_tlVariant
#define _HDR_tlVariant
#include "tlCommon.h"
#include <string>
#include <vector>
#include <map>
#include <stdexcept>
#include <typeinfo>
#include "tlInternational.h"
#include "tlAssert.h"
#include "tlObject.h"
#include <QString>
#include <QByteArray>
#include <QVariant>
namespace gsi
{
class ClassBase;
class NoAdaptorTag;
template <class T, class A> class Class;
template <class X> 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<tl::Object *> (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 T>
class VariantUserClass
: public VariantUserClassBase
{
public:
VariantUserClass () { }
T *get (void *ptr) const { return reinterpret_cast<T *> (ptr); }
const T *get (const void *ptr) const { return reinterpret_cast<const T *> (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<tl::Variant>::const_iterator const_iterator;
typedef std::vector<tl::Variant>::iterator iterator;
typedef std::map<tl::Variant, tl::Variant> 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 <class T>
Variant (const T &obj)
: m_type (t_user), m_string (0)
{
const tl::VariantUserClassBase *c = tl::VariantUserClass<T>::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 <class Iter>
Variant (Iter from, Iter to)
: m_type (t_list), m_string (0)
{
m_var.m_list = new std::vector<tl::Variant> (from, to);
}
/**
* @brief Destructor
*/
~Variant ();
/**
* @brief Utility: initialize a variant from GSI type reference
*/
template <class T>
static tl::Variant make_variant_ref (T *t)
{
const tl::VariantUserClassBase *c = gsi::cls_decl<T> ()->var_cls (false);
tl_assert (c != 0);
return tl::Variant ((void *) t, c, false);
}
/**
* @brief Utility: initialize a variant from GSI type reference
*/
template <class T>
static tl::Variant make_variant_ref (const T *t)
{
const tl::VariantUserClassBase *c = gsi::cls_decl<T> ()->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 <class T>
static tl::Variant make_variant (T *t)
{
const tl::VariantUserClassBase *c = gsi::cls_decl<T> ()->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 <class T>
static tl::Variant make_variant (const T &t, bool is_const = false)
{
const tl::VariantUserClassBase *c = gsi::cls_decl <T> ()->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<tl::Variant> ();
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<tl::Variant, tl::Variant> ();
}
/**
* @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 <class T>
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<const WeakOrSharedPtr *> (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<WeakOrSharedPtr *> (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<const WeakOrSharedPtr *> (m_var.mp_user_ref.ptr)->get ();
} else {
return 0;
}
}
/**
* @brief Converts to the user object
*/
tl::Object *to_object ()
{
return const_cast<tl::Object *> (((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 <class T>
const T &to_user () const
{
if (is_user()) {
const VariantUserClass<T> *tcls = dynamic_cast<const VariantUserClass<T> *> (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 <class T>
T &to_user ()
{
return const_cast<T &> (((const Variant *) this)->to_user<T> ());
}
/**
* @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<class T>
tl::Variant &morph ()
{
if (! is_nil ()) {
*this = to<T> ();
}
return *this;
}
/**
* @brief Cast to the given type
*
* This creates a new variant which uses the given type internally
*/
template <class T>
Variant cast () const
{
return Variant (to<T> ());
}
/**
* @brief Access the native (internal) object
*
* For nil, 0 is returned.
*/
void *native_ptr ()
{
// saves one implementation ...
return const_cast<void *> (((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<tl::Variant> &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<tl::Variant> &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 <class T>
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 <class T>
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 <class T>
bool is_user () const
{
if (m_type == t_user) {
const VariantUserClass<T> *tcls = dynamic_cast<const VariantUserClass<T> *> (m_var.mp_user.cls);
return tcls != 0;
} else if (m_type == t_user_ref) {
const VariantUserClass<T> *tcls = dynamic_cast<const VariantUserClass<T> *> (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 <class T>
bool is_object () const
{
if (m_type == t_user_ref) {
const VariantUserClass<T> *tcls = dynamic_cast<const VariantUserClass<T> *> (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<tl::Variant> *m_list;
std::map<tl::Variant, tl::Variant> *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<bool> () const { return to_bool (); }
template<> inline char Variant::to<char> () const { return to_char (); }
template<> inline unsigned char Variant::to<unsigned char> () const { return to_uchar (); }
template<> inline signed char Variant::to<signed char> () const { return to_schar (); }
template<> inline short Variant::to<short> () const { return to_short (); }
template<> inline unsigned short Variant::to<unsigned short> () const { return to_ushort (); }
template<> inline int Variant::to<int> () const { return to_int (); }
template<> inline unsigned int Variant::to<unsigned int> () const { return to_uint (); }
template<> inline long Variant::to<long> () const { return to_long (); }
template<> inline unsigned long Variant::to<unsigned long> () const { return to_ulong (); }
template<> inline long long Variant::to<long long> () const { return to_longlong (); }
template<> inline unsigned long long Variant::to<unsigned long long> () 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<double> () const { return to_double (); }
template<> inline float Variant::to<float> () const { return to_float (); }
template<> inline std::string Variant::to<std::string> () const { return to_stdstring (); }
template<> inline QString Variant::to<QString> () const { return to_qstring (); }
template<> inline QByteArray Variant::to<QByteArray> () const { return to_qbytearray (); }
template<> inline const char *Variant::to<const char *> () const { return to_string (); }
// specializations if the is.. methods
template<> inline bool Variant::is<bool> () const { return m_type == t_bool; }
template<> inline bool Variant::is<char> () const { return m_type == t_char; }
template<> inline bool Variant::is<unsigned char> () const { return m_type == t_uchar; }
template<> inline bool Variant::is<signed char> () const { return m_type == t_schar; }
template<> inline bool Variant::is<short> () const { return m_type == t_short; }
template<> inline bool Variant::is<unsigned short> () const { return m_type == t_ushort; }
template<> inline bool Variant::is<int> () const { return m_type == t_int; }
template<> inline bool Variant::is<unsigned int> () const { return m_type == t_uint; }
template<> inline bool Variant::is<long> () const { return m_type == t_long; }
template<> inline bool Variant::is<unsigned long> () const { return m_type == t_ulong; }
template<> inline bool Variant::is<long long> () const { return m_type == t_longlong; }
template<> inline bool Variant::is<unsigned long long> () 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<double> () const { return m_type == t_double; }
template<> inline bool Variant::is<float> () const { return m_type == t_float; }
template<> inline bool Variant::is<std::string> () const { return m_type == t_stdstring; }
template<> inline bool Variant::is<QString> () const { return m_type == t_qstring; }
template<> inline bool Variant::is<QByteArray> () const { return m_type == t_qbytearray; }
template<> inline bool Variant::is<const char *> () const { return m_type == t_string; }
// specializations of the can_convert.. methods
template<> inline bool Variant::can_convert_to<bool> () const { return true; }
template<> inline bool Variant::can_convert_to<char> () const { return can_convert_to_char (); }
template<> inline bool Variant::can_convert_to<unsigned char> () const { return can_convert_to_uchar (); }
template<> inline bool Variant::can_convert_to<signed char> () const { return can_convert_to_schar (); }
template<> inline bool Variant::can_convert_to<short> () const { return can_convert_to_short (); }
template<> inline bool Variant::can_convert_to<unsigned short> () const { return can_convert_to_ushort (); }
template<> inline bool Variant::can_convert_to<int> () const { return can_convert_to_int (); }
template<> inline bool Variant::can_convert_to<unsigned int> () const { return can_convert_to_uint (); }
template<> inline bool Variant::can_convert_to<long> () const { return can_convert_to_long (); }
template<> inline bool Variant::can_convert_to<unsigned long> () const { return can_convert_to_ulong (); }
template<> inline bool Variant::can_convert_to<long long> () const { return can_convert_to_longlong (); }
template<> inline bool Variant::can_convert_to<unsigned long long> () 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<double> () const { return can_convert_to_double (); }
template<> inline bool Variant::can_convert_to<float> () const { return can_convert_to_float (); }
template<> inline bool Variant::can_convert_to<std::string> () const { return true; }
template<> inline bool Variant::can_convert_to<QString> () const { return true; }
template<> inline bool Variant::can_convert_to<QByteArray> () const { return true; }
template<> inline bool Variant::can_convert_to<const char *> () const { return true; }
/**
* @brief Initialize the class table (must be called once)
*/
void initialize_variant_class_table ();
} // namespace tl
#endif