klayout/src/gsi/gsiSerialisation.h

1919 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_gsiSerialisation
#define _HDR_gsiSerialisation
#include "gsiTypes.h"
#include "tlHeap.h"
#include "tlUtils.h"
#include <list>
#include <memory>
namespace gsi
{
// ------------------------------------------------------------
// SerialArgs definition
class AdaptorBase;
/**
* @brief Copy the contents of adaptor-provided data to the given type X
* X can be a valid target type for the adaptor's container scheme - for
* example a vector for a vector adaptor.
* This generic function will copy the elements of the vector one by one
* to the target.
*/
template <class X> void copy_to (AdaptorBase &a, X &x, tl::Heap &heap);
/**
* @brief Tie the contents of adaptor-provided data to the given type X
* This generic function will first copy the contents of the adaptor-provided
* container to the object x. It will also tie both containers, so when the
* adaptor is deleted, it will pull it's content from the former target x.
* This is used to implement "out" parameter schemes for adapted containers.
* This function will take over the ownership of the a adaptor.
*/
template <class X> void tie_copies (AdaptorBase *a, X &x, tl::Heap &heap);
/**
* @brief An adaptor factory for adaptors of type X
*/
template <class Tag, class X>
struct adaptor_factory
{
/**
* @brief The factory method
* This method will return a new adaptor object providing access to the raw object v.
*/
static AdaptorBase *get (const X &v);
};
/**
* @brief An exception thrown if there are not enough arguments on the serialization buffer
*/
struct GSI_PUBLIC ArglistUnderflowException
: public tl::Exception
{
ArglistUnderflowException ()
: tl::Exception (tl::to_string (QObject::tr ("Too few arguments or no return value supplied")))
{ }
};
/**
* @brief An exception thrown if a reference is null (nil)
*/
struct GSI_PUBLIC NilPointerToReference
: public tl::Exception
{
NilPointerToReference ()
: tl::Exception (tl::to_string (QObject::tr ("nil object passed to a reference")))
{ }
};
/**
* @brief This class provides the basic argument serialization mechanism for the C++/scripting interface
*/
class GSI_PUBLIC SerialArgs
{
public:
/**
* @brief Default constructor
* Creates an empty list.
*/
SerialArgs ()
: mp_buffer (0)
{
mp_write = mp_read = mp_buffer;
}
/**
* @brief Constructor
* Creates a buffer with space for len bytes.
*/
SerialArgs (size_t len)
: mp_buffer (0)
{
// use the internal buffer for small argument lists (which are quite common)
if (len > sizeof (m_buffer)) {
mp_buffer = new char [len];
} else if (len > 0) {
mp_buffer = m_buffer;
}
mp_write = mp_read = mp_buffer;
}
/**
* @brief Destructor
*/
~SerialArgs ()
{
if (mp_buffer && mp_buffer != m_buffer) {
delete [] mp_buffer;
}
mp_buffer = 0;
}
/**
* @brief Resets the write and read pointer
*/
void reset ()
{
mp_read = mp_write = mp_buffer;
}
/**
* @brief gets a pointer to the buffer
*/
char *cptr ()
{
return mp_buffer;
}
/**
* @brief gets a const pointer to the buffer
*/
const char *cptr () const
{
return mp_buffer;
}
/**
* @brief Gets a pointer to the current write position
*/
char *wptr ()
{
return mp_write;
}
/**
* @brief Gets a const pointer to the current write position
*/
const char *wptr () const
{
return mp_write;
}
/**
* @brief Gets a pointer to the current read position
*/
char *rptr ()
{
return mp_read;
}
/**
* @brief Gets a const pointer to the current read position
*/
const char *rptr () const
{
return mp_read;
}
/**
* @brief Writes a value into the buffer
*/
template <class X>
inline void write (const X &x)
{
this->write_impl (typename type_traits<X>::tag (), x);
}
/**
* @brief Reads a value from the buffer
*/
template <class X>
inline X read (tl::Heap &heap)
{
return this->read_impl<X> (typename type_traits<X>::tag (), heap);
}
/**
* @brief returns true, if there is still data available for read
*/
operator bool () const
{
return mp_read && mp_read < mp_write;
}
private:
char *mp_buffer;
char *mp_read, *mp_write;
char m_buffer[200];
inline void check_data () const
{
if (! *this) {
throw ArglistUnderflowException ();
}
}
// -----------------------------------------------------------
// reader implementations
template <class X>
void write_impl (const pod_direct_tag &, const X &x)
{
*((X *)mp_write) = x;
mp_write += item_size<X> ();
}
template <class X>
void write_impl (const x_tag &, const X &x)
{
*((X **)mp_write) = new X (x);
mp_write += item_size<X *> ();
}
template <class X>
void write_impl (const ref_tag &, X &x)
{
*((X **)mp_write) = &x;
mp_write += item_size<X *> ();
}
template <class X>
void write_impl (const ptr_tag &, X *x)
{
*((X **)mp_write) = x;
mp_write += item_size<X *> ();
}
template <class X>
void write_impl (const pod_cref_tag &, const X &x)
{
X *r = (X *)mp_write;
new (r) X(x);
mp_write += item_size<X> ();
}
template <class X>
void write_impl (const npod_cref_tag &, const X &x)
{
*((X const **)mp_write) = &x;
mp_write += item_size<const X *> ();
}
template <class X>
void write_impl (const x_cref_tag &, const X &x)
{
*((X const **)mp_write) = &x;
mp_write += item_size<const X *> ();
}
template <class X>
void write_impl (const pod_cptr_tag &, const X *x)
{
*(bool *)mp_write = (x != 0);
mp_write += item_size<bool> ();
if (x) {
*(X *)mp_write = *x;
}
mp_write += item_size<X> ();
}
// see notes on the serialization for this type:
template <class X>
void write_impl (const npod_cptr_tag &, const X *x)
{
*((X const **)mp_write) = x;
mp_write += item_size<const X *> ();
}
template <class X>
void write_impl (const x_cptr_tag &, const X *x)
{
*((X const **)mp_write) = x;
mp_write += item_size<const X *> ();
}
void write_impl (const vptr_tag &, void *x)
{
*((void **)mp_write) = x;
mp_write += item_size<void *> ();
}
void write_impl (const vptr_tag &, const void *x)
{
*((const void **)mp_write) = x;
mp_write += item_size<const void *> ();
}
template <class X>
void write_impl (const adaptor_direct_tag &, const X &x)
{
*((void **)mp_write) = adaptor_factory<typename gsi::type_traits<X>::tag, X>::get (x);
mp_write += item_size<void *> ();
}
template <class X>
void write_impl (const adaptor_ptr_tag &, X *x)
{
if (x) {
*((void **)mp_write) = adaptor_factory<typename gsi::type_traits<X *>::tag, X *>::get (x);
} else {
*((void **)mp_write) = 0;
}
mp_write += item_size<void *> ();
}
template <class X>
void write_impl (const adaptor_cptr_tag &, const X *x)
{
if (x) {
*((void **)mp_write) = adaptor_factory<typename gsi::type_traits<const X *>::tag, const X *>::get (x);
} else {
*((void **)mp_write) = 0;
}
mp_write += item_size<void *> ();
}
template <class X>
void write_impl (const adaptor_ref_tag &, X &x)
{
*((void **)mp_write) = adaptor_factory<typename gsi::type_traits<X &>::tag, X &>::get (x);
mp_write += item_size<void *> ();
}
template <class X>
void write_impl (const adaptor_cref_tag &, const X &x)
{
*((void **)mp_write) = adaptor_factory<typename gsi::type_traits<const X &>::tag, const X &>::get (x);
mp_write += item_size<void *> ();
}
// -----------------------------------------------------------
// reader implementations
template <class X>
X read_impl (const pod_direct_tag &, tl::Heap &)
{
check_data ();
X r = *((X *)mp_read);
mp_read += item_size<X> ();
return r;
}
template <class X>
X read_impl (const x_tag &, tl::Heap &)
{
check_data ();
X *xp = *(X **)mp_read;
X x = *xp;
delete xp;
mp_read += item_size<void *> ();
return x;
}
template <class X>
X read_impl (const vptr_tag &, tl::Heap &)
{
void *r = *((void **)mp_read);
mp_read += item_size<void *> ();
// Hint: X can be const unsigned char *, const signed char * as well.
return (X)r;
}
template <class X>
X read_impl (const ref_tag &, tl::Heap &)
{
typedef typename type_traits<X>::value_type value_type;
check_data ();
value_type *r = *((value_type **)mp_read);
mp_read += item_size<value_type *> ();
if (! r) {
throw NilPointerToReference ();
}
return *r;
}
template <class X>
X read_impl (const pod_cref_tag &, tl::Heap &)
{
// X is actually an (const X &)
typedef typename type_traits<X>::value_type value_type;
check_data ();
const value_type *r = ((const value_type *)mp_read);
mp_read += item_size<value_type> ();
return *r;
}
template <class X>
X read_impl (const npod_cref_tag &, tl::Heap &)
{
// X is actually an (const X &)
typedef typename type_traits<X>::value_type value_type;
check_data ();
const value_type *r = *((const value_type **)mp_read);
mp_read += item_size<const value_type *> ();
if (! r) {
throw NilPointerToReference ();
}
return *r;
}
template <class X>
X read_impl (const x_cref_tag &, tl::Heap &)
{
// X is actually an (const X &)
typedef typename type_traits<X>::value_type value_type;
check_data ();
const value_type *r = *((const value_type **)mp_read);
mp_read += item_size<const value_type *> ();
if (! r) {
throw NilPointerToReference ();
}
return *r;
}
template <class X>
X read_impl (const ptr_tag &, tl::Heap &)
{
// X is actually an (X *)
typedef typename type_traits<X>::value_type value_type;
check_data ();
value_type * const &r = *((value_type **)mp_read);
mp_read += item_size<value_type *> ();
return r;
}
template <class X>
X read_impl (const pod_cptr_tag &, tl::Heap &)
{
// X is actually an (const X *)
check_data ();
bool h = *(bool *)mp_read;
mp_read += item_size<bool> ();
X r = h ? (X)mp_read : (X)0;
mp_read += item_size<X> ();
return r;
}
// see notes on the serialization for this type:
template <class X>
X read_impl (const npod_cptr_tag &, tl::Heap &)
{
// X is actually an (const X *)
check_data ();
X r = *((X *)mp_read);
mp_read += item_size<X> ();
return r;
}
template <class X>
X read_impl (const x_cptr_tag &, tl::Heap &)
{
// X is actually an (const X *)
check_data ();
X r = *((X *)mp_read);
mp_read += item_size<X> ();
return r;
}
template <class X>
X read_impl (const adaptor_direct_tag &, tl::Heap &heap)
{
check_data ();
std::auto_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
mp_read += item_size<AdaptorBase *> ();
tl_assert (p.get () != 0);
X x = X ();
copy_to<X> (*p, x, heap);
return x;
}
template <class X>
X read_impl (const adaptor_cref_tag &, tl::Heap &heap)
{
typedef typename tl::get_inner_type<X>::result x_type;
check_data ();
std::auto_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
mp_read += item_size<AdaptorBase *> ();
tl_assert (p.get () != 0);
x_type *x = new x_type ();
heap.push (x);
copy_to<x_type> (*p, *x, heap);
return *x;
}
template <class X>
X read_impl (const adaptor_ref_tag &, tl::Heap &heap)
{
typedef typename tl::get_inner_type<X>::result x_type;
check_data ();
AdaptorBase *p = *(AdaptorBase **)mp_read;
mp_read += item_size<AdaptorBase *> ();
tl_assert (p != 0);
x_type *x = new x_type ();
heap.push (x);
tie_copies<x_type> (p, *x, heap);
return *x;
}
template <class X>
X read_impl (const adaptor_cptr_tag &, tl::Heap &heap)
{
typedef typename tl::get_inner_type<X>::result x_type;
check_data ();
std::auto_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
mp_read += item_size<AdaptorBase *> ();
x_type *x = 0;
if (p.get () != 0) {
x = new x_type ();
heap.push (x);
copy_to<x_type> (*p, *x, heap);
}
return x;
}
template <class X>
X read_impl (const adaptor_ptr_tag &, tl::Heap &heap)
{
typedef typename tl::get_inner_type<X>::result x_type;
check_data ();
AdaptorBase *p = *(AdaptorBase **)mp_read;
mp_read += item_size<AdaptorBase *> ();
x_type *x = 0;
if (p != 0) {
x = new x_type ();
heap.push (x);
tie_copies<x_type> (p, *x, heap);
}
return x;
}
};
// ------------------------------------------------------------
// Basic adaptor
class GSI_PUBLIC AdaptorBase
{
public:
AdaptorBase ();
virtual ~AdaptorBase ();
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const = 0;
void tie_copies (AdaptorBase *target, tl::Heap &heap);
};
// ------------------------------------------------------------
// String adaptor framework
/**
* @brief A generic adaptor for strings
* This is the base class for implementing generic access to strings
*/
class GSI_PUBLIC StringAdaptor
: public AdaptorBase
{
public:
/**
* @brief Default constructor
*/
StringAdaptor () { }
/**
* @brief Destructor
*/
virtual ~StringAdaptor () { }
/**
* @brief Returns the size of the string
*/
virtual size_t size () const = 0;
/**
* @brief Returns a pointer to a UTF8 encoded character array with size size()
*/
virtual const char *c_str () const = 0;
/**
* @brief Sets the string to the given UTF8 string with length s
*/
virtual void set (const char *c_str, size_t s, tl::Heap &heap) = 0;
/**
* @brief copy_to implementation
*/
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
StringAdaptor *s = dynamic_cast<StringAdaptor *>(target);
tl_assert (s);
s->set (c_str (), size (), heap);
}
};
/**
* @brief Generic string adaptor implementation
*/
template <class X>
class StringAdaptorImpl
: public StringAdaptor
{
};
/**
* @brief Specialization for QByteArray
*/
template <>
class StringAdaptorImpl<QByteArray>
: public StringAdaptor
{
public:
StringAdaptorImpl (QByteArray *s)
: mp_s (s), m_is_const (false)
{
// .. nothing yet ..
}
StringAdaptorImpl (const QByteArray *s)
: mp_s (const_cast<QByteArray *> (s)), m_is_const (true)
{
// .. nothing yet ..
}
StringAdaptorImpl (const QByteArray &s)
: m_is_const (false), m_s (s)
{
mp_s = &m_s;
}
StringAdaptorImpl ()
: m_is_const (false)
{
mp_s = &m_s;
}
virtual ~StringAdaptorImpl ()
{
// .. nothing yet ..
}
virtual size_t size () const
{
return mp_s->size ();
}
virtual const char *c_str () const
{
return mp_s->constData ();
}
virtual void set (const char *c_str, size_t s, tl::Heap &)
{
if (! m_is_const) {
*mp_s = QByteArray (c_str, s);
}
}
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
StringAdaptorImpl<QByteArray> *s = dynamic_cast<StringAdaptorImpl<QByteArray> *>(target);
if (s) {
*s->mp_s = *mp_s;
} else {
StringAdaptor::copy_to (target, heap);
}
}
private:
QByteArray *mp_s;
bool m_is_const;
QByteArray m_s;
};
/**
* @brief Specialization for QString
*/
template <>
class StringAdaptorImpl<QString>
: public StringAdaptor
{
public:
StringAdaptorImpl (QString *s)
: mp_s (s), m_is_const (false)
{
// .. nothing yet ..
}
StringAdaptorImpl (const QString *s)
: mp_s (const_cast<QString *> (s)), m_is_const (true)
{
// .. nothing yet ..
}
StringAdaptorImpl (const QString &s)
: m_is_const (false), m_s (s)
{
mp_s = &m_s;
}
StringAdaptorImpl ()
: m_is_const (false)
{
mp_s = &m_s;
}
virtual ~StringAdaptorImpl ()
{
// .. nothing yet ..
}
virtual size_t size () const
{
return mp_s->toUtf8 ().size ();
}
virtual const char *c_str () const
{
m_s_utf8 = mp_s->toUtf8 ();
return m_s_utf8.constData ();
}
virtual void set (const char *c_str, size_t s, tl::Heap &)
{
if (! m_is_const) {
*mp_s = QString::fromUtf8 (c_str, s);
}
}
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
StringAdaptorImpl<QString> *s = dynamic_cast<StringAdaptorImpl<QString> *>(target);
if (s) {
*s->mp_s = *mp_s;
} else {
StringAdaptor::copy_to (target, heap);
}
}
private:
QString *mp_s;
bool m_is_const;
QString m_s;
mutable QByteArray m_s_utf8;
};
/**
* @brief Specialization for QStringRef
*/
template <>
class StringAdaptorImpl<QStringRef>
: public StringAdaptor
{
public:
StringAdaptorImpl (QStringRef *s)
: mp_s (s), m_is_const (false)
{
// .. nothing yet ..
}
StringAdaptorImpl (const QStringRef *s)
: mp_s (const_cast<QStringRef *> (s)), m_is_const (true)
{
// .. nothing yet ..
}
StringAdaptorImpl (const QStringRef &s)
: m_is_const (false), m_s (s)
{
mp_s = &m_s;
}
StringAdaptorImpl ()
: m_is_const (false)
{
mp_s = &m_s;
}
virtual ~StringAdaptorImpl ()
{
// .. nothing yet ..
}
virtual size_t size () const
{
return mp_s->toString ().toUtf8 ().size ();
}
virtual const char *c_str () const
{
m_s_utf8 = mp_s->toString ().toUtf8 ();
return m_s_utf8.constData ();
}
virtual void set (const char *c_str, size_t s, tl::Heap &heap)
{
if (! m_is_const) {
QString *qstr = new QString (QString::fromUtf8 (c_str, s));
heap.push (qstr);
*mp_s = QStringRef (qstr);
}
}
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
StringAdaptorImpl<QStringRef> *s = dynamic_cast<StringAdaptorImpl<QStringRef> *>(target);
if (s) {
*s->mp_s = *mp_s;
} else {
StringAdaptor::copy_to (target, heap);
}
}
private:
QStringRef *mp_s;
bool m_is_const;
QStringRef m_s;
mutable QByteArray m_s_utf8;
};
/**
* @brief Specialization for std::string
*/
template <>
class StringAdaptorImpl<std::string>
: public StringAdaptor
{
public:
StringAdaptorImpl (std::string *s)
: mp_s (s), m_is_const (false)
{
// .. nothing yet ..
}
StringAdaptorImpl (const std::string *s)
: mp_s (const_cast<std::string *> (s)), m_is_const (true)
{
// .. nothing yet ..
}
StringAdaptorImpl (const std::string &s)
: m_is_const (false), m_s (s)
{
mp_s = &m_s;
}
StringAdaptorImpl ()
: m_is_const (false)
{
mp_s = &m_s;
}
virtual ~StringAdaptorImpl ()
{
// .. nothing yet ..
}
virtual size_t size () const
{
return mp_s->size ();
}
virtual const char *c_str () const
{
return mp_s->c_str ();
}
virtual void set (const char *c_str, size_t s, tl::Heap &)
{
if (! m_is_const) {
*mp_s = std::string (c_str, s);
}
}
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
StringAdaptorImpl<std::string> *s = dynamic_cast<StringAdaptorImpl<std::string> *>(target);
if (s) {
*s->mp_s = *mp_s;
} else {
StringAdaptor::copy_to (target, heap);
}
}
private:
std::string *mp_s;
bool m_is_const;
std::string m_s;
};
/**
* @brief Specialization for const unsigned char *
*/
template <class CP>
class StringAdaptorImplCCP
: public StringAdaptor
{
public:
StringAdaptorImplCCP (CP *s)
: mp_s (s), m_is_const (false)
{
// .. nothing yet ..
}
StringAdaptorImplCCP (const CP *s)
: mp_s (const_cast<CP *> (s)), m_is_const (true)
{
// .. nothing yet ..
}
StringAdaptorImplCCP (CP s)
: m_is_const (false), m_s ((const char *) s)
{
mp_s = 0;
}
StringAdaptorImplCCP ()
: m_is_const (false)
{
mp_s = 0;
}
virtual ~StringAdaptorImplCCP ()
{
// .. nothing yet ..
}
virtual size_t size () const
{
return mp_s ? strlen ((const char *) *mp_s) : m_s.size ();
}
virtual const char *c_str () const
{
return mp_s ? (const char *) *mp_s : m_s.c_str ();
}
virtual void set (const char *c_str, size_t s, tl::Heap &heap)
{
if (! m_is_const) {
if (! mp_s) {
// This adaptor is not attached to an external "const char *" pointer, so we can
// safely use the internal storage.
m_s = std::string (c_str, s);
} else {
// This means we assign a simple pointer some other pointer without
// knowning how long the other points lives. To account for that we create
// a temporary string on the heap and take the pointer from there.
// Since the target is a pointer outside this adaptor, we cannot use the
// adaptor's internal storage since the adaptor won't survive the outside
// use case.
std::string *tmp_string = new std::string (c_str, s);
heap.push (tmp_string);
*mp_s = (CP) tmp_string->c_str ();
}
}
}
private:
CP *mp_s;
bool m_is_const;
std::string m_s;
};
/**
* @brief Specialization for const char *
*/
template <>
class StringAdaptorImpl<const char *>
: public StringAdaptorImplCCP<const char *>
{
public:
typedef char char_type;
StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP<const char_type *> (s) { }
StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP<const char_type *> (s) { }
StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP<const char_type *> (s) { }
};
/**
* @brief Specialization for const unsigned char *
*/
template <>
class StringAdaptorImpl<const unsigned char *>
: public StringAdaptorImplCCP<const unsigned char *>
{
public:
typedef unsigned char char_type;
StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP<const char_type *> (s) { }
StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP<const char_type *> (s) { }
StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP<const char_type *> (s) { }
};
/**
* @brief Specialization for const signed char *
*/
template <>
class StringAdaptorImpl<const signed char *>
: public StringAdaptorImplCCP<const signed char *>
{
public:
typedef signed char char_type;
StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP<const char_type *> (s) { }
StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP<const char_type *> (s) { }
StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP<const char_type *> (s) { }
};
// ------------------------------------------------------------
// Variant adaptor framework
/**
* @brief A generic adaptor for strings
* This is the base class for implementing generic access to strings
*/
class GSI_PUBLIC VariantAdaptor
: public AdaptorBase
{
public:
/**
* @brief Default constructor
*/
VariantAdaptor () { }
/**
* @brief Destructor
*/
virtual ~VariantAdaptor () { }
/**
* @brief Gets the tl::Variant representing this variant
*/
virtual tl::Variant var () const = 0;
/**
* @brief Sets the variant's value
*/
virtual void set (const tl::Variant &v) = 0;
/**
* @brief Implementation of copy_to
*/
virtual void copy_to (AdaptorBase *target, tl::Heap & /*heap*/) const
{
VariantAdaptor *v = dynamic_cast<VariantAdaptor *>(target);
tl_assert (v);
v->set (var ());
}
};
/**
* @brief Generic string adaptor implementation
*/
template <class X>
class VariantAdaptorImpl
: public VariantAdaptor
{
};
/**
* @brief Specialization for QVariant
*/
template <>
class VariantAdaptorImpl<QVariant>
: public VariantAdaptor
{
public:
VariantAdaptorImpl (QVariant *v)
: mp_v (v), m_is_const (false)
{
// .. nothing yet ..
}
VariantAdaptorImpl (const QVariant *v)
: mp_v (const_cast<QVariant *> (v)), m_is_const (true)
{
// .. nothing yet ..
}
VariantAdaptorImpl (const QVariant &v)
: m_is_const (true), m_v (v)
{
mp_v = &m_v;
}
VariantAdaptorImpl ()
: m_is_const (false)
{
mp_v = &m_v;
}
virtual ~VariantAdaptorImpl ()
{
// .. nothing yet ..
}
virtual tl::Variant var () const
{
return tl::Variant (*mp_v);
}
const QVariant &qvar () const
{
return *mp_v;
}
virtual void set (const tl::Variant &v)
{
if (! m_is_const) {
*mp_v = v.to_qvariant ();
}
}
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
VariantAdaptorImpl<QVariant> *v = dynamic_cast<VariantAdaptorImpl<QVariant> *>(target);
if (v) {
*v->mp_v = qvar ();
} else {
VariantAdaptor::copy_to (target, heap);
}
}
private:
QVariant *mp_v;
bool m_is_const;
QVariant m_v;
};
/**
* @brief Specialization for tl::Variant
*/
template <>
class VariantAdaptorImpl<tl::Variant>
: public VariantAdaptor
{
public:
VariantAdaptorImpl (tl::Variant *v)
: mp_v (v), m_is_const (false)
{
// .. nothing yet ..
}
VariantAdaptorImpl (const tl::Variant *v)
: mp_v (const_cast<tl::Variant *> (v)), m_is_const (true)
{
// .. nothing yet ..
}
VariantAdaptorImpl (const tl::Variant &v)
: m_is_const (true), m_v (v)
{
mp_v = &m_v;
}
VariantAdaptorImpl ()
: m_is_const (false)
{
mp_v = &m_v;
}
virtual ~VariantAdaptorImpl ()
{
// .. nothing yet ..
}
virtual tl::Variant var () const
{
return *mp_v;
}
const tl::Variant &var_ref () const
{
return *mp_v;
}
virtual void set (const tl::Variant &v)
{
if (! m_is_const) {
*mp_v = v;
}
}
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
VariantAdaptorImpl<tl::Variant> *v = dynamic_cast<VariantAdaptorImpl<tl::Variant> *>(target);
if (v) {
*v->mp_v = var_ref ();
} else {
VariantAdaptor::copy_to (target, heap);
}
}
private:
tl::Variant *mp_v;
bool m_is_const;
tl::Variant m_v;
};
// ------------------------------------------------------------
// Vector adaptor framework
/**
* @brief A generalization to the vector (array) iterator
* This is the base class for the actual implementation
*/
class GSI_PUBLIC VectorAdaptorIterator
{
public:
/**
* @brief Default constructor
*/
VectorAdaptorIterator () { }
/**
* @brief Destructor
*/
virtual ~VectorAdaptorIterator () { }
/**
* @brief Gets the currently pointed member
* The member is written to the serial buffer.
* The buffer is not cleared before.
*/
virtual void get (SerialArgs &w, tl::Heap &) const = 0;
/**
* @brief Returns true, if the iterator is at the end of the sequence
*/
virtual bool at_end () const = 0;
/**
* @brief Increments the iterator
*/
virtual void inc () = 0;
};
/**
* @brief A generic adaptor for vectors (arrays in general)
* This is the base class for implementing generic access to vectors or other linear containers.
*/
class GSI_PUBLIC VectorAdaptor
: public AdaptorBase
{
public:
/**
* @brief Default constructor
*/
VectorAdaptor () { }
/**
* @brief Destructor
*/
virtual ~VectorAdaptor () { }
/**
* @brief Returns the size of the array
*/
virtual size_t size () const = 0;
/**
* @brief Creates a generic iterator object
* The object must be destroyed by the caller
*/
virtual VectorAdaptorIterator *create_iterator () const = 0;
/**
* @brief Adds a new member to the container
* The member is expected as a serialized object on the SerialArgs buffer.
* The heap must be provided to account for cases where temporary objects need to be created
* upon reading (for example a vector<vector *>).
*/
virtual void push (SerialArgs &r, tl::Heap &heap) = 0;
/**
* @brief Clears the vector
*/
virtual void clear () = 0;
/**
* @brief Gets the size the serial buffer requires to represent a value
*/
virtual size_t serial_size () const = 0;
/**
* @brief Implementation of copy_to
*/
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
VectorAdaptor *v = dynamic_cast<VectorAdaptor *>(target);
tl_assert (v);
v->clear ();
gsi::SerialArgs rr (serial_size ());
tl_assert (v->serial_size () == serial_size ());
std::auto_ptr<VectorAdaptorIterator> i (create_iterator ());
while (! i->at_end ()) {
rr.reset ();
i->get (rr, heap);
v->push (rr, heap);
i->inc ();
}
}
};
/**
* @brief Implementation of the generic iterator adaptor for a specific container
*/
template <class Cont>
class VectorAdaptorIteratorImpl
: public VectorAdaptorIterator
{
public:
typedef typename Cont::value_type value_type;
VectorAdaptorIteratorImpl (const Cont &v)
: m_b (v.begin ()), m_e (v.end ())
{
}
void get (SerialArgs &ww, tl::Heap &) const
{
ww.write<value_type> (*m_b);
}
bool at_end () const
{
return m_b == m_e;
}
void inc ()
{
++m_b;
}
private:
typename Cont::const_iterator m_b, m_e;
};
template <class X>
void push_vector (std::vector<X> &v, const X &x)
{
v.push_back (x);
}
template <class X>
void push_vector (std::list<X> &v, const X &x)
{
v.push_back (x);
}
template <class X>
void push_vector (std::set<X> &v, const X &x)
{
v.insert (x);
}
template <class X>
void push_vector (QVector<X> &v, const X &x)
{
v.push_back (x);
}
inline void push_vector (QStringList &v, const QString &x)
{
v.push_back (x);
}
template <class X>
void push_vector (QList<X> &v, const X &x)
{
v.push_back (x);
}
template <class X>
void push_vector (QSet<X> &v, const X &x)
{
v.insert (x);
}
/**
* @brief Implementation of the generic adaptor for a specific container
*/
template <class Cont>
class VectorAdaptorImpl
: public VectorAdaptor
{
public:
typedef typename Cont::value_type value_type;
VectorAdaptorImpl (Cont *v)
: mp_v (v), m_is_const (false)
{
// .. nothing yet ..
}
VectorAdaptorImpl (const Cont *v)
: mp_v (const_cast<Cont *> (v)), m_is_const (true)
{
// .. nothing yet ..
}
VectorAdaptorImpl ()
: m_is_const (false)
{
mp_v = &m_v;
}
VectorAdaptorImpl (const Cont &v)
: m_is_const (false), m_v (v)
{
mp_v = &m_v;
}
virtual ~VectorAdaptorImpl ()
{
// .. nothing yet ..
}
virtual size_t size () const
{
return mp_v->size ();
}
virtual VectorAdaptorIterator *create_iterator () const
{
return new VectorAdaptorIteratorImpl<Cont> (*mp_v);
}
virtual void push (SerialArgs &r, tl::Heap &heap)
{
if (! m_is_const) {
push_vector<value_type> (*mp_v, r.read<value_type> (heap));
}
}
virtual void clear ()
{
if (! m_is_const) {
mp_v->clear ();
}
}
virtual size_t serial_size () const
{
return gsi::type_traits<value_type>::serial_size ();
}
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
// simplify copies to identical kinds
VectorAdaptorImpl<Cont> *t = dynamic_cast<VectorAdaptorImpl<Cont> *> (target);
if (t) {
if (! t->m_is_const) {
*t->mp_v = *mp_v;
}
} else {
VectorAdaptor::copy_to (target, heap);
}
}
private:
Cont *mp_v;
bool m_is_const;
Cont m_v;
};
// ------------------------------------------------------------
// Map adaptor framework
/**
* @brief A generalization to the map iterator
* This is the base class for the actual implementation
*/
class GSI_PUBLIC MapAdaptorIterator
{
public:
/**
* @brief Default constructor
*/
MapAdaptorIterator () { }
/**
* @brief Destructor
*/
virtual ~MapAdaptorIterator () { }
/**
* @brief Gets the currently pointed key and value
* The key and value is written to the serial buffer in that order.
* The buffer is not cleared before.
*/
virtual void get (SerialArgs &w, tl::Heap &) const = 0;
/**
* @brief Returns true, if the iterator is at the end of the sequence
*/
virtual bool at_end () const = 0;
/**
* @brief Increments the iterator
*/
virtual void inc () = 0;
};
/**
* @brief A generic adaptor for maps (associative containers in general)
* This is the base class for implementing generic access to map or other associative containers.
*/
class GSI_PUBLIC MapAdaptor
: public AdaptorBase
{
public:
/**
* @brief Default constructor
*/
MapAdaptor () { }
/**
* @brief Destructor
*/
virtual ~MapAdaptor () { }
/**
* @brief Returns the size of the map
*/
virtual size_t size () const = 0;
/**
* @brief Clears the map
*/
virtual void clear () = 0;
/**
* @brief Gets the size of the serial buffer for key and value
*/
virtual size_t serial_size () const = 0;
/**
* @brief Creates a generic iterator object
* The object must be destroyed by the caller
*/
virtual MapAdaptorIterator *create_iterator () const = 0;
/**
* @brief Adds a new member to the map
* The key and value is expected as a serialized object on the SerialArgs buffers.
* The heap must be provided to account for cases where temporary objects need to be created
* upon reading (for example a map<int, vector *>).
*/
virtual void insert (SerialArgs &rr, tl::Heap &heap) = 0;
/**
* @brief Copies the content of this to the target
*/
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
MapAdaptor *v = dynamic_cast<MapAdaptor *>(target);
tl_assert (v);
v->clear ();
gsi::SerialArgs rr (serial_size ());
tl_assert (v->serial_size () == serial_size ());
std::auto_ptr<MapAdaptorIterator> i (create_iterator ());
while (! i->at_end ()) {
rr.reset ();
i->get (rr, heap);
v->insert (rr, heap);
i->inc ();
}
}
};
/**
* @brief Abstract accessor for maps (STL type)
* This template provides abstract insert and getters.
*/
template <class Cont>
struct map_access
{
typedef typename Cont::key_type key_type;
typedef typename Cont::mapped_type value_type;
typedef typename Cont::const_iterator const_iterator;
static void insert (Cont &c, const key_type &k, const value_type &v)
{
c.insert (std::make_pair (k, v));
}
static const key_type &get_key (const_iterator i)
{
return i->first;
}
static const value_type &get_value (const_iterator i)
{
return i->second;
}
};
/**
* @brief Specialization for QMap
*/
template <class X, class Y>
struct map_access<QMap<X, Y> >
{
typedef QMap<X, Y> cont;
typedef typename cont::key_type key_type;
typedef typename cont::mapped_type value_type;
typedef typename cont::const_iterator const_iterator;
static void insert (cont &c, const key_type &k, const value_type &v)
{
c.insert (k, v);
}
static const key_type &get_key (const_iterator i)
{
return i.key ();
}
static const value_type &get_value (const_iterator i)
{
return i.value ();
}
};
/**
* @brief Specialization for QHash
*/
template <class X, class Y>
struct map_access<QHash<X, Y> >
{
typedef QHash<X, Y> cont;
typedef typename cont::key_type key_type;
typedef typename cont::mapped_type value_type;
typedef typename cont::const_iterator const_iterator;
static void insert (cont &c, const key_type &k, const value_type &v)
{
c.insert (k, v);
}
static const key_type &get_key (const_iterator i)
{
return i.key ();
}
static const value_type &get_value (const_iterator i)
{
return i.value ();
}
};
/**
* @brief Implementation of the generic iterator adaptor for a specific container
*/
template <class Cont>
class MapAdaptorIteratorImpl
: public MapAdaptorIterator
{
public:
typedef typename Cont::key_type key_type;
typedef typename Cont::mapped_type value_type;
MapAdaptorIteratorImpl (const Cont &v)
: m_b (v.begin ()), m_e (v.end ())
{
}
void get (SerialArgs &ww, tl::Heap &) const
{
ww.write<key_type> (map_access<Cont>::get_key (m_b));
ww.write<value_type> (map_access<Cont>::get_value (m_b));
}
bool at_end () const
{
return m_b == m_e;
}
void inc ()
{
++m_b;
}
private:
typename Cont::const_iterator m_b, m_e;
};
/**
* @brief Implementation of the generic adaptor for a specific container
*/
template <class Cont>
class MapAdaptorImpl
: public MapAdaptor
{
public:
typedef typename Cont::key_type key_type;
typedef typename Cont::mapped_type value_type;
MapAdaptorImpl (Cont *m)
: mp_m (m), m_is_const (false)
{
// .. nothing yet ..
}
MapAdaptorImpl (const Cont *m)
: mp_m (const_cast<Cont *> (m)), m_is_const (true)
{
// .. nothing yet ..
}
MapAdaptorImpl (const Cont &m)
: m_is_const (false), m_m (m)
{
mp_m = &m_m;
}
MapAdaptorImpl ()
: m_is_const (false)
{
mp_m = &m_m;
}
virtual ~MapAdaptorImpl ()
{
// .. nothing yet ..
}
virtual size_t size () const
{
return mp_m->size ();
}
virtual void clear ()
{
if (! m_is_const) {
mp_m->clear ();
}
}
virtual size_t serial_size () const
{
return (gsi::type_traits<key_type>::serial_size () + gsi::type_traits<value_type>::serial_size ());
}
virtual MapAdaptorIterator *create_iterator () const
{
return new MapAdaptorIteratorImpl<Cont> (*mp_m);
}
virtual void insert (SerialArgs &rr, tl::Heap &heap)
{
if (! m_is_const) {
key_type x = rr.read<key_type> (heap);
value_type y = rr.read<value_type> (heap);
map_access<Cont>::insert (*mp_m, x, y);
}
}
virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
{
// simplify copies to identical kinds
MapAdaptorImpl<Cont> *t = dynamic_cast<MapAdaptorImpl<Cont> *> (target);
if (t) {
if (! t->m_is_const) {
*t->mp_m = *mp_m;
}
} else {
MapAdaptor::copy_to (target, heap);
}
}
private:
Cont *mp_m;
bool m_is_const;
Cont m_m;
};
// ------------------------------------------------------------
// Create adaptors for various categories
template <class X, class V>
inline AdaptorBase *create_adaptor_by_category(const vector_adaptor_tag & /*tag*/, V v)
{
return new VectorAdaptorImpl<X> (v);
}
template <class X, class V>
inline AdaptorBase *create_adaptor_by_category(const map_adaptor_tag & /*tag*/, V v)
{
return new MapAdaptorImpl<X> (v);
}
template <class X, class V>
inline AdaptorBase *create_adaptor_by_category(const string_adaptor_tag & /*tag*/, V v)
{
return new StringAdaptorImpl<X> (v);
}
template <class X, class V>
inline AdaptorBase *create_adaptor_by_category(const variant_adaptor_tag & /*tag*/, const V &v)
{
return new VariantAdaptorImpl<X> (v);
}
template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_direct_tag & /*tag*/, const Tag &tag2, const X &v)
{
return create_adaptor_by_category<X> (tag2, v);
}
template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_cref_tag & /*tag*/, const Tag &tag2, const X &v)
{
return create_adaptor_by_category<X> (tag2, &v);
}
template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_ref_tag & /*tag*/, const Tag &tag2, X &v)
{
return create_adaptor_by_category<X> (tag2, &v);
}
template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_cptr_tag & /*tag*/, const Tag &tag2, const X *v)
{
return create_adaptor_by_category<X> (tag2, v);
}
template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_ptr_tag & /*tag*/, const Tag &tag2, X *v)
{
return create_adaptor_by_category<X> (tag2, v);
}
template <class Tag, class X>
inline AdaptorBase *adaptor_factory<Tag, X>::get (const X &v)
{
Tag tag;
return create_adaptor2 (tag, tag, v);
}
// ------------------------------------------------------------
// A generic function to transfer adaptor-managed information into a C++ object
template <class X>
inline void copy_to (AdaptorBase &a, X &x, tl::Heap &heap)
{
std::auto_ptr<AdaptorBase> t (adaptor_factory<typename gsi::type_traits<X &>::tag, X &>::get (x));
a.copy_to (t.get (), heap);
}
template <class X>
inline void tie_copies (AdaptorBase *a, X &x, tl::Heap &heap)
{
AdaptorBase *t (adaptor_factory<typename gsi::type_traits<X &>::tag, X &>::get (x));
a->tie_copies (t, heap);
}
}
#endif