/* 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 #include 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 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 void tie_copies (AdaptorBase *a, X &x, tl::Heap &heap); /** * @brief An adaptor factory for adaptors of type X */ template 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 inline void write (const X &x) { this->write_impl (typename type_traits::tag (), x); } /** * @brief Reads a value from the buffer */ template inline X read (tl::Heap &heap) { return this->read_impl (typename type_traits::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 void write_impl (const pod_direct_tag &, const X &x) { *((X *)mp_write) = x; mp_write += item_size (); } template void write_impl (const x_tag &, const X &x) { *((X **)mp_write) = new X (x); mp_write += item_size (); } template void write_impl (const ref_tag &, X &x) { *((X **)mp_write) = &x; mp_write += item_size (); } template void write_impl (const ptr_tag &, X *x) { *((X **)mp_write) = x; mp_write += item_size (); } template void write_impl (const pod_cref_tag &, const X &x) { X *r = (X *)mp_write; new (r) X(x); mp_write += item_size (); } template void write_impl (const npod_cref_tag &, const X &x) { *((X const **)mp_write) = &x; mp_write += item_size (); } template void write_impl (const x_cref_tag &, const X &x) { *((X const **)mp_write) = &x; mp_write += item_size (); } template void write_impl (const pod_cptr_tag &, const X *x) { *(bool *)mp_write = (x != 0); mp_write += item_size (); if (x) { *(X *)mp_write = *x; } mp_write += item_size (); } // see notes on the serialization for this type: template void write_impl (const npod_cptr_tag &, const X *x) { *((X const **)mp_write) = x; mp_write += item_size (); } template void write_impl (const x_cptr_tag &, const X *x) { *((X const **)mp_write) = x; mp_write += item_size (); } void write_impl (const vptr_tag &, void *x) { *((void **)mp_write) = x; mp_write += item_size (); } void write_impl (const vptr_tag &, const void *x) { *((const void **)mp_write) = x; mp_write += item_size (); } template void write_impl (const adaptor_direct_tag &, const X &x) { *((void **)mp_write) = adaptor_factory::tag, X>::get (x); mp_write += item_size (); } template void write_impl (const adaptor_ptr_tag &, X *x) { if (x) { *((void **)mp_write) = adaptor_factory::tag, X *>::get (x); } else { *((void **)mp_write) = 0; } mp_write += item_size (); } template void write_impl (const adaptor_cptr_tag &, const X *x) { if (x) { *((void **)mp_write) = adaptor_factory::tag, const X *>::get (x); } else { *((void **)mp_write) = 0; } mp_write += item_size (); } template void write_impl (const adaptor_ref_tag &, X &x) { *((void **)mp_write) = adaptor_factory::tag, X &>::get (x); mp_write += item_size (); } template void write_impl (const adaptor_cref_tag &, const X &x) { *((void **)mp_write) = adaptor_factory::tag, const X &>::get (x); mp_write += item_size (); } // ----------------------------------------------------------- // reader implementations template X read_impl (const pod_direct_tag &, tl::Heap &) { check_data (); X r = *((X *)mp_read); mp_read += item_size (); return r; } template X read_impl (const x_tag &, tl::Heap &) { check_data (); X *xp = *(X **)mp_read; X x = *xp; delete xp; mp_read += item_size (); return x; } template X read_impl (const vptr_tag &, tl::Heap &) { void *r = *((void **)mp_read); mp_read += item_size (); // Hint: X can be const unsigned char *, const signed char * as well. return (X)r; } template X read_impl (const ref_tag &, tl::Heap &) { typedef typename type_traits::value_type value_type; check_data (); value_type *r = *((value_type **)mp_read); mp_read += item_size (); if (! r) { throw NilPointerToReference (); } return *r; } template X read_impl (const pod_cref_tag &, tl::Heap &) { // X is actually an (const X &) typedef typename type_traits::value_type value_type; check_data (); const value_type *r = ((const value_type *)mp_read); mp_read += item_size (); return *r; } template X read_impl (const npod_cref_tag &, tl::Heap &) { // X is actually an (const X &) typedef typename type_traits::value_type value_type; check_data (); const value_type *r = *((const value_type **)mp_read); mp_read += item_size (); if (! r) { throw NilPointerToReference (); } return *r; } template X read_impl (const x_cref_tag &, tl::Heap &) { // X is actually an (const X &) typedef typename type_traits::value_type value_type; check_data (); const value_type *r = *((const value_type **)mp_read); mp_read += item_size (); if (! r) { throw NilPointerToReference (); } return *r; } template X read_impl (const ptr_tag &, tl::Heap &) { // X is actually an (X *) typedef typename type_traits::value_type value_type; check_data (); value_type * const &r = *((value_type **)mp_read); mp_read += item_size (); return r; } template 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 (); X r = h ? (X)mp_read : (X)0; mp_read += item_size (); return r; } // see notes on the serialization for this type: template 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 (); return r; } template 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 (); return r; } template X read_impl (const adaptor_direct_tag &, tl::Heap &heap) { check_data (); std::auto_ptr p (*(AdaptorBase **)mp_read); mp_read += item_size (); tl_assert (p.get () != 0); X x = X (); copy_to (*p, x, heap); return x; } template X read_impl (const adaptor_cref_tag &, tl::Heap &heap) { typedef typename tl::get_inner_type::result x_type; check_data (); std::auto_ptr p (*(AdaptorBase **)mp_read); mp_read += item_size (); tl_assert (p.get () != 0); x_type *x = new x_type (); heap.push (x); copy_to (*p, *x, heap); return *x; } template X read_impl (const adaptor_ref_tag &, tl::Heap &heap) { typedef typename tl::get_inner_type::result x_type; check_data (); AdaptorBase *p = *(AdaptorBase **)mp_read; mp_read += item_size (); tl_assert (p != 0); x_type *x = new x_type (); heap.push (x); tie_copies (p, *x, heap); return *x; } template X read_impl (const adaptor_cptr_tag &, tl::Heap &heap) { typedef typename tl::get_inner_type::result x_type; check_data (); std::auto_ptr p (*(AdaptorBase **)mp_read); mp_read += item_size (); x_type *x = 0; if (p.get () != 0) { x = new x_type (); heap.push (x); copy_to (*p, *x, heap); } return x; } template X read_impl (const adaptor_ptr_tag &, tl::Heap &heap) { typedef typename tl::get_inner_type::result x_type; check_data (); AdaptorBase *p = *(AdaptorBase **)mp_read; mp_read += item_size (); x_type *x = 0; if (p != 0) { x = new x_type (); heap.push (x); tie_copies (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(target); tl_assert (s); s->set (c_str (), size (), heap); } }; /** * @brief Generic string adaptor implementation */ template class StringAdaptorImpl : public StringAdaptor { }; /** * @brief Specialization for QByteArray */ template <> class StringAdaptorImpl : public StringAdaptor { public: StringAdaptorImpl (QByteArray *s) : mp_s (s), m_is_const (false) { // .. nothing yet .. } StringAdaptorImpl (const QByteArray *s) : mp_s (const_cast (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 *s = dynamic_cast *>(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 : public StringAdaptor { public: StringAdaptorImpl (QString *s) : mp_s (s), m_is_const (false) { // .. nothing yet .. } StringAdaptorImpl (const QString *s) : mp_s (const_cast (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 *s = dynamic_cast *>(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 : public StringAdaptor { public: StringAdaptorImpl (QStringRef *s) : mp_s (s), m_is_const (false) { // .. nothing yet .. } StringAdaptorImpl (const QStringRef *s) : mp_s (const_cast (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 *s = dynamic_cast *>(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 : 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 (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 *s = dynamic_cast *>(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 StringAdaptorImplCCP : public StringAdaptor { public: StringAdaptorImplCCP (CP *s) : mp_s (s), m_is_const (false) { // .. nothing yet .. } StringAdaptorImplCCP (const CP *s) : mp_s (const_cast (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 : public StringAdaptorImplCCP { public: typedef char char_type; StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP (s) { } StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP (s) { } StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP (s) { } }; /** * @brief Specialization for const unsigned char * */ template <> class StringAdaptorImpl : public StringAdaptorImplCCP { public: typedef unsigned char char_type; StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP (s) { } StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP (s) { } StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP (s) { } }; /** * @brief Specialization for const signed char * */ template <> class StringAdaptorImpl : public StringAdaptorImplCCP { public: typedef signed char char_type; StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP (s) { } StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP (s) { } StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP (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(target); tl_assert (v); v->set (var ()); } }; /** * @brief Generic string adaptor implementation */ template class VariantAdaptorImpl : public VariantAdaptor { }; /** * @brief Specialization for QVariant */ template <> class VariantAdaptorImpl : public VariantAdaptor { public: VariantAdaptorImpl (QVariant *v) : mp_v (v), m_is_const (false) { // .. nothing yet .. } VariantAdaptorImpl (const QVariant *v) : mp_v (const_cast (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 *v = dynamic_cast *>(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 : 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 (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 *v = dynamic_cast *>(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). */ 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(target); tl_assert (v); v->clear (); gsi::SerialArgs rr (serial_size ()); tl_assert (v->serial_size () == serial_size ()); std::auto_ptr 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 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 (*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 void push_vector (std::vector &v, const X &x) { v.push_back (x); } template void push_vector (std::list &v, const X &x) { v.push_back (x); } template void push_vector (std::set &v, const X &x) { v.insert (x); } template void push_vector (QVector &v, const X &x) { v.push_back (x); } inline void push_vector (QStringList &v, const QString &x) { v.push_back (x); } template void push_vector (QList &v, const X &x) { v.push_back (x); } template void push_vector (QSet &v, const X &x) { v.insert (x); } /** * @brief Implementation of the generic adaptor for a specific container */ template 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 (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 (*mp_v); } virtual void push (SerialArgs &r, tl::Heap &heap) { if (! m_is_const) { push_vector (*mp_v, r.read (heap)); } } virtual void clear () { if (! m_is_const) { mp_v->clear (); } } virtual size_t serial_size () const { return gsi::type_traits::serial_size (); } virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const { // simplify copies to identical kinds VectorAdaptorImpl *t = dynamic_cast *> (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). */ 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(target); tl_assert (v); v->clear (); gsi::SerialArgs rr (serial_size ()); tl_assert (v->serial_size () == serial_size ()); std::auto_ptr 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 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 struct map_access > { typedef QMap 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 struct map_access > { typedef QHash 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 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 (map_access::get_key (m_b)); ww.write (map_access::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 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 (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::serial_size () + gsi::type_traits::serial_size ()); } virtual MapAdaptorIterator *create_iterator () const { return new MapAdaptorIteratorImpl (*mp_m); } virtual void insert (SerialArgs &rr, tl::Heap &heap) { if (! m_is_const) { key_type x = rr.read (heap); value_type y = rr.read (heap); map_access::insert (*mp_m, x, y); } } virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const { // simplify copies to identical kinds MapAdaptorImpl *t = dynamic_cast *> (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 inline AdaptorBase *create_adaptor_by_category(const vector_adaptor_tag & /*tag*/, V v) { return new VectorAdaptorImpl (v); } template inline AdaptorBase *create_adaptor_by_category(const map_adaptor_tag & /*tag*/, V v) { return new MapAdaptorImpl (v); } template inline AdaptorBase *create_adaptor_by_category(const string_adaptor_tag & /*tag*/, V v) { return new StringAdaptorImpl (v); } template inline AdaptorBase *create_adaptor_by_category(const variant_adaptor_tag & /*tag*/, const V &v) { return new VariantAdaptorImpl (v); } template inline AdaptorBase *create_adaptor2 (const adaptor_direct_tag & /*tag*/, const Tag &tag2, const X &v) { return create_adaptor_by_category (tag2, v); } template inline AdaptorBase *create_adaptor2 (const adaptor_cref_tag & /*tag*/, const Tag &tag2, const X &v) { return create_adaptor_by_category (tag2, &v); } template inline AdaptorBase *create_adaptor2 (const adaptor_ref_tag & /*tag*/, const Tag &tag2, X &v) { return create_adaptor_by_category (tag2, &v); } template inline AdaptorBase *create_adaptor2 (const adaptor_cptr_tag & /*tag*/, const Tag &tag2, const X *v) { return create_adaptor_by_category (tag2, v); } template inline AdaptorBase *create_adaptor2 (const adaptor_ptr_tag & /*tag*/, const Tag &tag2, X *v) { return create_adaptor_by_category (tag2, v); } template inline AdaptorBase *adaptor_factory::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 inline void copy_to (AdaptorBase &a, X &x, tl::Heap &heap) { std::auto_ptr t (adaptor_factory::tag, X &>::get (x)); a.copy_to (t.get (), heap); } template inline void tie_copies (AdaptorBase *a, X &x, tl::Heap &heap) { AdaptorBase *t (adaptor_factory::tag, X &>::get (x)); a->tie_copies (t, heap); } } #endif