From 4e5da4ee9eb579d4e28003e76222572ea88947a8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 10 Aug 2024 18:39:39 +0200 Subject: [PATCH] WIP --- src/tl/tl/tl.pro | 2 + src/tl/tl/tlProtocolBufferStruct.cc | 31 + src/tl/tl/tlProtocolBufferStruct.h | 1786 +++++++++++++++++++++++++++ 3 files changed, 1819 insertions(+) create mode 100644 src/tl/tl/tlProtocolBufferStruct.cc create mode 100644 src/tl/tl/tlProtocolBufferStruct.h diff --git a/src/tl/tl/tl.pro b/src/tl/tl/tl.pro index 27b27f14a..0773588d1 100644 --- a/src/tl/tl/tl.pro +++ b/src/tl/tl/tl.pro @@ -30,6 +30,7 @@ SOURCES = \ tlProgress.cc \ tlPixelBuffer.cc \ tlProtocolBuffer.cc \ + tlProtocolBufferStruct.cc \ tlResources.cc \ tlScriptError.cc \ tlSleep.cc \ @@ -87,6 +88,7 @@ HEADERS = \ tlProgress.h \ tlPixelBuffer.h \ tlProtocolBuffer.h \ + tlProtocolBufferStruct.h \ tlResources.h \ tlReuseVector.h \ tlScriptError.h \ diff --git a/src/tl/tl/tlProtocolBufferStruct.cc b/src/tl/tl/tlProtocolBufferStruct.cc new file mode 100644 index 000000000..2749ea44b --- /dev/null +++ b/src/tl/tl/tlProtocolBufferStruct.cc @@ -0,0 +1,31 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "tlProtocolBufferStruct.h" + + +namespace tl +{ + + + +} diff --git a/src/tl/tl/tlProtocolBufferStruct.h b/src/tl/tl/tlProtocolBufferStruct.h new file mode 100644 index 000000000..65ca763ce --- /dev/null +++ b/src/tl/tl/tlProtocolBufferStruct.h @@ -0,0 +1,1786 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 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_tlProtocolBufferStruct +#define HDR_tlProtocolBufferStruct + +#include "tlCommon.h" +#include "tlProtocolBuffer.h" + +namespace tl +{ + +/** + * @brief A basic PB parser error exception class + */ + +class TL_PUBLIC PBException : public tl::Exception +{ +public: + PBException (const char *msg) + : Exception (tl::to_string (tr ("Protocol buffer parser error: %s")).c_str ()), + m_msg (msg) + { + // .. nothing yet .. + } + + PBException (const std::string &msg) + : Exception (fmt (0).c_str (), msg.c_str ()), + m_msg (msg) + { + // .. nothing yet .. + } + + /** + * @brief Raw (unprefixed) message of the PB parser + */ + const std::string & + raw_msg () const + { + return m_msg; + } + +protected: + PBException (const std::string &msg, size_t pos) + : Exception (fmt (pos).c_str (), msg.c_str (), pos), + m_msg (msg) + { + // .. nothing yet .. + } + +private: + std::string m_msg; + + static std::string fmt (size_t pos) + { + if (pos == 0) { + return tl::to_string (tr ("Protocol buffer parser error: %s")).c_str (); + } else { + return tl::to_string (tr ("Protocol buffer parser error: %s at position %ul")).c_str (); + } + } +}; + +/** + * @brief A PB parser error exception class that additionally provides line and column information + */ + +class TL_PUBLIC PBLocatedException : public PBException +{ +public: + PBLocatedException (const std::string &msg, size_t pos) + : PBException (msg, pos), + m_pos (pos) + { + // .. nothing yet .. + } + + /** + * @brief Line number information of the exception + */ + size_t pos () const + { + return m_pos; + } + +private: + size_t m_pos; +}; + +/** + * @brief An object wrapper base class for target object management + * + * Implementations of this class through the PBReaderProxy templates + * manage pointers to certain objects. + */ + +class TL_PUBLIC PBReaderProxyBase +{ +public: + PBReaderProxyBase () { } + virtual ~PBReaderProxyBase () { } + virtual void release () = 0; + virtual void detach () = 0; +}; + +/** + * @brief An object wrapper base class for target object management specialized to a certain class + */ + +template +class TL_PUBLIC_TEMPLATE PBReaderProxy + : public PBReaderProxyBase +{ +public: + PBReaderProxy (Obj *obj, bool owns_obj) + : mp_obj (obj), m_owns_obj (owns_obj) + { } + + virtual ~PBReaderProxy () { } + + virtual void release () + { + if (m_owns_obj && mp_obj) { + delete mp_obj; + } + mp_obj = 0; + } + + virtual void detach () + { + m_owns_obj = false; + } + + Obj *ptr () const + { + return mp_obj; + } + +private: + Obj *mp_obj; + bool m_owns_obj; +}; + +/** + * @brief Helper class: A class tag + */ + +template +struct PBObjTag +{ + PBObjTag() { } + typedef Obj obj; +}; + +/** + * @brief Helper class: The reader state + * + * The reader state mainly consists of a stack of objects being parsed. + */ + +class TL_PUBLIC PBReaderState +{ +public: + /** + * @brief Default constructor + */ + PBReaderState (); + + /** + * @brief Destructor + */ + ~PBReaderState (); + + /** + * @brief Push a new object on the stack + */ + template + void push (PBObjTag /*tag*/) + { + m_objects.push_back (new PBReaderProxy (new Obj (), true)); + } + + /** + * @brief Push an existing object on the stack + */ + template + void push (Obj *obj) + { + m_objects.push_back (new PBReaderProxy (obj, false)); + } + + /** + * @brief Push an existing object on the stack with the ownership flag + */ + template + void push (Obj *obj, bool owner) + { + m_objects.push_back (new PBReaderProxy (obj, owner)); + } + + /** + * @brief Get the top object + */ + template + Obj *back (PBObjTag /*tag*/) + { + tl_assert (! m_objects.empty ()); + return (dynamic_cast &> (*m_objects.back ())).ptr (); + } + + /** + * @brief Get the top object and release + */ + template + Obj *detach_back (PBObjTag /*tag*/) + { + tl_assert (! m_objects.empty ()); + m_objects.back ()->detach (); + return (dynamic_cast &> (*m_objects.back ())).ptr (); + } + + /** + * @brief Pop an object from the stack + */ + template + void pop (PBObjTag /*tag*/) + { + tl_assert (! m_objects.empty ()); + m_objects.back ()->release (); + delete m_objects.back (); + m_objects.pop_back (); + } + + /** + * @brief Empty predicate: true, if no more object is on the stack + */ + bool empty () const + { + return m_objects.empty (); + } + + /** + * @brief Obtain the parent object from the stack + */ + template + Obj *parent (PBObjTag /*tag*/) + { + tl_assert (m_objects.size () > 1); + return (dynamic_cast &> (*m_objects.end () [-2])).ptr (); + } + +private: + std::vector m_objects; +}; + +// ----------------------------------------------------------------- +// The C++ structure definition interface (for use cases see tlProtocolBufferStruct.ut) + +class TL_PUBLIC PBElementBase; + +struct pass_by_value_tag { + pass_by_value_tag () { } +}; + +struct pass_by_ref_tag { + pass_by_ref_tag () { } +}; + +/** + * @brief The PB parser class + * This is the main entry point. It will take a PB reader, the structure (in "root") and + * a reader state initialized with the top level object. + */ +class TL_PUBLIC PBParser +{ +public: + PBParser (); + ~PBParser (); + + void parse (tl::ProtocolBufferReader &reader, const PBElementBase *root, PBReaderState *reader_state); + + template + void parse (tl::ProtocolBufferReader &reader, const PBElementBase *root, Obj &obj) + { + PBReaderState rs; + rs.push (&obj); + parse (reader, root, &rs); + } + +private: + std::vector m_stack; + const PBElementBase *mp_root; + PBReaderState *mp_state; +}; + +/** + * @brief PBElementProxy element of the PB structure definition + * + * The purpose of this class is to provide a wrapper around the + * different derivations of the PBElementBase class, so we can + * pack them into a vector. The proxy objects can be copied + * duplicating the wrapped objects with their "clone" methods. + * The proxy object can be given the pointer to the element + * in two ways: the reference version creates a duplicate, the + * pointer version transfers the ownership of the PBElementBase + * object. + */ + +class TL_PUBLIC PBElementProxy +{ +public: + PBElementProxy (const PBElementProxy &d); + PBElementProxy (const PBElementBase &d); + PBElementProxy (PBElementBase *d); + + ~PBElementProxy (); + + PBElementBase *operator-> () const + { + return mp_ptr; + } + + PBElementBase *get () const + { + return mp_ptr; + } + +private: + PBElementBase *mp_ptr; +}; + +/** + * @brief A list of PB elements + * + * This class provides a list of PB elements. + * A list can be created by using the + operator and + * supplying various objects based on PBElementBase. + */ + +class TL_PUBLIC PBElementList +{ +public: + typedef std::list children_list; + typedef children_list::const_iterator iterator; + + PBElementList () + { + // .. nothing yet .. + } + + PBElementList (const PBElementBase &e) + { + m_elements.push_back (PBElementProxy (e)); + } + + PBElementList (PBElementBase *e) + { + if (e) { + m_elements.push_back (PBElementProxy (e)); + } + } + + PBElementList (const PBElementList &d, const PBElementBase &e) + : m_elements (d.m_elements) + { + m_elements.push_back (PBElementProxy (e)); + } + + PBElementList (const PBElementList &d, PBElementBase *e) + : m_elements (d.m_elements) + { + if (e) { + m_elements.push_back (PBElementProxy (e)); + } + } + + void append (const PBElementBase &e) + { + m_elements.push_back (PBElementProxy (e)); + } + + void append (PBElementBase *e) + { + if (e) { + m_elements.push_back (PBElementProxy (e)); + } + } + + iterator begin () const + { + return m_elements.begin (); + } + + iterator end () const + { + return m_elements.end (); + } + + static PBElementList empty () + { + return PBElementList (); + } + +private: + std::list m_elements; +}; + +/** + * @brief Helper class: A stack of const objects being written + */ + +class TL_PUBLIC PBWriterState +{ +public: + /** + * @brief Default constructor + */ + PBWriterState (); + + /** + * @brief Push a new object on the stack + */ + template + void push (const Obj *obj) + { + m_objects.push_back (obj); + } + + /** + * @brief Pop an object from the stack + */ + template + const Obj *pop (PBObjTag /*tag*/) + { + tl_assert (! m_objects.empty ()); + const Obj *obj = reinterpret_cast (m_objects.back ()); + m_objects.pop_back (); + return obj; + } + + /** + * @brief Obtain the parent object from the stack + */ + template + const Obj *back (PBObjTag /*tag*/) + { + tl_assert (m_objects.size () > 0); + return reinterpret_cast (m_objects.end () [-1]); + } + +private: + std::vector m_objects; +}; + +/** + * @brief The PB element base object + * + * This class is the base class for objects implementing + * the parser handler semantics. The basic methods are + * create (create an actual object), read (read value), + * finish (finalize the actual object). + * + * Writing of objects is also handled through this class. + * The basic method is "write". + */ + +class TL_PUBLIC PBElementBase +{ +public: + typedef PBElementList::iterator iterator; + + PBElementBase (int tag, const PBElementList &children) + : m_tag (tag), mp_children (new PBElementList (children)), m_owns_child_list (true) + { + // .. nothing yet .. + } + + PBElementBase (int tag, const PBElementList *children) + : m_tag (tag), mp_children (children), m_owns_child_list (false) + { + // .. nothing yet .. + } + + PBElementBase (const PBElementBase &d) + : m_tag (d.m_tag), m_owns_child_list (d.m_owns_child_list) + { + if (m_owns_child_list) { + mp_children = new PBElementList (*d.mp_children); + } else { + mp_children = d.mp_children; + } + } + + virtual ~PBElementBase () + { + if (m_owns_child_list) { + delete const_cast (mp_children); + mp_children = 0; + } + } + + virtual PBElementBase *clone () const = 0; + +#if 0 // @@@ + virtual void create (const PBElementBase *parent, PBReaderState &objs, const std::string &uri, const std::string &lname, const std::string &qname) const = 0; + virtual void cdata (const std::string &cdata, PBReaderState &objs) const = 0; + virtual void finish (const PBElementBase *parent, PBReaderState &objs, const std::string &uri, const std::string &lname, const std::string &qname) const = 0; + + virtual void write (const PBElementBase * /*parent*/, tl::ProtocolBufferWriter & /*writer*/, PBWriterState & /*objs*/) const { } + virtual bool has_any (PBWriterState & /*objs*/) const { return false; } +#endif + + int tag () const + { + return m_tag; + } + + iterator begin () const + { + return mp_children->begin (); + } + + iterator end () const + { + return mp_children->end (); + } + +private: + int m_tag; + const PBElementList *mp_children; + bool m_owns_child_list; +}; + +/** + * @brief A PB child element + * + * This class is a PB structure component describing a child + * element in the PB tree. There is no limit about the number of + * child elements. + * This object must be provided a pointer to a factory method (in + * the parent's class), a name and a list of children (which can be + * empty). + * Write is a class providing a Obj &operator(Parent &) operator. + * It is supposed to create a new instance of Obj within Parent. + * Read is a class providing a start(const Parent &) method to start + * iterating over the instances, a const Obj &operator() const for + * access and a bool at_end() method to determine if the iterator + * is at the end and next() to increment the iterator. + */ + +template +class TL_PUBLIC_TEMPLATE PBElement + : public PBElementBase +{ +public: + PBElement (const Read &r, const Write &w, int tag, const PBElementList &children) + : PBElementBase (tag, children), m_r (r), m_w (w) + { + // .. nothing yet .. + } + + PBElement (const Read &r, const Write &w, int tag, const PBElementList *children) + : PBElementBase (tag, children), m_r (r), m_w (w) + { + // .. nothing yet .. + } + + PBElement (const PBElement &d) + : PBElementBase (d), m_r (d.m_r), m_w (d.m_w) + { + // .. nothing yet .. + } + + virtual PBElementBase *clone () const + { + return new PBElement (*this); + } + +#if 0 // @@@ + virtual void create (const PBElementBase *, PBReaderState &objs, const std::string & /*uri*/, const std::string & /*lname*/, const std::string & /*qname*/) const + { + PBObjTag tag; + objs.push (tag); + } + + virtual void cdata (const std::string & /*cdata*/, PBReaderState & /*objs*/) const + { + // .. nothing yet .. + } + + virtual void finish (const PBElementBase * /*parent*/, PBReaderState &objs, const std::string & /*uri*/, const std::string & /*lname*/, const std::string & /*qname*/) const + { + PBObjTag tag; + PBObjTag parent_tag; + m_w (*objs.parent (parent_tag), objs); + objs.pop (tag); + } + + virtual void write (const PBElementBase * /*parent*/, tl::OutputStream &os, int indent, PBWriterState &objs) const + { + PBObjTag parent_tag; + Read r (m_r); + r.start (*objs.back (parent_tag)); + while (! r.at_end ()) { + PBElementBase::write_indent (os, indent); + os << "<" << this->name () << ">\n"; + typedef typename Read::tag read_tag_type; + read_tag_type read_tag; + write_obj (r (), os, indent, read_tag, objs); + PBElementBase::write_indent (os, indent); + os << "name () << ">\n"; + r.next (); + } + } + + virtual bool has_any (PBWriterState &objs) const + { + PBObjTag parent_tag; + Read r (m_r); + r.start (*objs.back (parent_tag)); + return (! r.at_end ()); + } +#endif + +private: + Read m_r; + Write m_w; + +#if 0 // @@@ + // this write helper is used if the reader delivers an object by value + void write_obj (Obj obj, tl::OutputStream &os, int indent, tl::pass_by_value_tag, PBWriterState &objs) const + { + PBObjTag tag; + objs.push (&obj); + for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) { + c->get ()->write (this, os, indent + 1, objs); + } + objs.pop (tag); + } + + void write_obj (const Obj &obj, tl::OutputStream &os, int indent, tl::pass_by_ref_tag, PBWriterState &objs) const + { + PBObjTag tag; + objs.push (&obj); + for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) { + c->get ()->write (this, os, indent + 1, objs); + } + objs.pop (tag); + } +#endif +}; + +/** + * @brief A PB child element with is instantiated with a parent reference + * + * This declares a PB element with a constructor that takes a (object *) arguments + * to the parent. + */ + +template +class TL_PUBLIC_TEMPLATE PBElementWithParentRef + : public PBElementBase +{ +public: + PBElementWithParentRef (const Read &r, const Write &w, int tag, const PBElementList &children) + : PBElementBase (tag, children), m_r (r), m_w (w) + { + // .. nothing yet .. + } + + PBElementWithParentRef (const Read &r, const Write &w, int tag, const PBElementList *children) + : PBElementBase (tag, children), m_r (r), m_w (w) + { + // .. nothing yet .. + } + + PBElementWithParentRef (const PBElementWithParentRef &d) + : PBElementBase (d), m_r (d.m_r), m_w (d.m_w) + { + // .. nothing yet .. + } + + virtual PBElementBase *clone () const + { + return new PBElementWithParentRef (*this); + } + + #if 0 // @@@ + virtual void create (const PBElementBase *, PBReaderState &objs, const std::string & /*uri*/, const std::string & /*lname*/, const std::string & /*qname*/) const + { + PBObjTag tag; + PBObjTag parent_tag; + objs.push (new Obj (objs.back (parent_tag)), true); + } + + virtual void cdata (const std::string & /*cdata*/, PBReaderState & /*objs*/) const + { + // .. nothing yet .. + } + + virtual void finish (const PBElementBase * /*parent*/, PBReaderState &objs, const std::string & /*uri*/, const std::string & /*lname*/, const std::string & /*qname*/) const + { + PBObjTag tag; + PBObjTag parent_tag; + m_w (*objs.parent (parent_tag), objs); + objs.pop (tag); + } + + virtual void write (const PBElementBase * /*parent*/, tl::OutputStream &os, int indent, PBWriterState &objs) const + { + PBObjTag parent_tag; + Read r (m_r); + r.start (*objs.back (parent_tag)); + while (! r.at_end ()) { + PBElementBase::write_indent (os, indent); + os << "<" << this->name () << ">\n"; + typedef typename Read::tag read_tag_type; + read_tag_type read_tag; + write_obj (r (), os, indent, read_tag, objs); + PBElementBase::write_indent (os, indent); + os << "name () << ">\n"; + r.next (); + } + } + + virtual bool has_any (PBWriterState &objs) const + { + PBObjTag parent_tag; + Read r (m_r); + r.start (*objs.back (parent_tag)); + return (! r.at_end ()); + } +#endif + +private: + Read m_r; + Write m_w; + +#if 0 // @@@ + // this write helper is used if the reader delivers an object by value + void write_obj (Obj obj, tl::OutputStream &os, int indent, tl::pass_by_value_tag, PBWriterState &objs) const + { + PBObjTag tag; + objs.push (&obj); + for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) { + c->get ()->write (this, os, indent + 1, objs); + } + objs.pop (tag); + } + + void write_obj (const Obj &obj, tl::OutputStream &os, int indent, tl::pass_by_ref_tag, PBWriterState &objs) const + { + PBObjTag tag; + objs.push (&obj); + for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) { + c->get ()->write (this, os, indent + 1, objs); + } + objs.pop (tag); + } +#endif +}; + +/** + * @brief A PB child element mapped to a member + * + * This class is a PB structure component describing a child + * element in the PB tree. The value of the child element + * is directly mapped to a member of the parent's class. + * This object must be provided two adaptors: + * Write is a writer providing an operator() (Parent &, const Value &) + * that adds a new value or sets the value. + * Read is a class providing a start(const Parent &) method to start + * iterating over the instances, a const Value &operator() const for + * access and a bool at_end() method to determine if the iterator + * is at the end and next() to increment the iterator. + */ + +template +class TL_PUBLIC_TEMPLATE PBMember + : public PBElementBase +{ +public: + PBMember (const Read &r, const Write &w, int tag, Converter c = Converter ()) + : PBElementBase (tag, PBElementList::empty ()), m_r (r), m_w (w), m_c (c) + { + // .. nothing yet .. + } + + PBMember (const PBMember &d) + : PBElementBase (d), m_r (d.m_r), m_w (d.m_w), m_c (d.m_c) + { + // .. nothing yet .. + } + + virtual PBElementBase *clone () const + { + return new PBMember (*this); + } + + #if 0 // @@@ + virtual void create (const PBElementBase *, PBReaderState &objs, const std::string & /*uri*/, const std::string & /*lname*/, const std::string & /*qname*/) const + { + objs.cdata = ""; + } + + virtual void cdata (const std::string &cd, PBReaderState &objs) const + { + objs.cdata += cd; + } + + virtual void finish (const PBElementBase * /*parent*/, PBReaderState &objs, const std::string & /*uri*/, const std::string & /*lname*/, const std::string & /*qname*/) const + { + PBObjTag tag; + PBObjTag parent_tag; + + PBReaderState value_obj; + value_obj.push (tag); + + m_c.from_string (objs.cdata, *value_obj.back (tag)); + m_w (*objs.back (parent_tag), value_obj); + + value_obj.pop (tag); + } + + virtual void write (const PBElementBase * /*parent*/, tl::OutputStream &os, int indent, PBWriterState &objs) const + { + PBObjTag parent_tag; + Read r (m_r); + r.start (* objs.back (parent_tag)); + while (! r.at_end ()) { + + std::string value = m_c.to_string (r ()); + + write_indent (os, indent); + + if (value.empty ()) { + os << "<" << name () << "/>\n"; + } else { + os << "<" << name () << ">"; + write_string (os, value); + os << "\n"; + } + + r.next (); + + } + } + + virtual bool has_any (PBWriterState &objs) const + { + PBObjTag parent_tag; + Read r (m_r); + r.start (*objs.back (parent_tag)); + return (! r.at_end ()); + } +#endif + +private: + Read m_r; + Write m_w; + Converter m_c; +}; + +/** + * @brief The root element of the PB structure + * + * The root element is also the handler implementation. + * It must be supplied a pointer to an actual root object, + * a name and a list of children. + */ + +template +class TL_PUBLIC_TEMPLATE PBStruct + : public PBElementBase +{ +public: + PBStruct (int tag, const PBElementList *children) + : PBElementBase (tag, children) + { + // .. nothing yet .. + } + + PBStruct (int tag, const PBElementList &children) + : PBElementBase (tag, children) + { + // .. nothing yet .. + } + + PBStruct (const PBStruct &d) + : PBElementBase (d) + { + // .. nothing yet .. + } + + virtual PBElementBase *clone () const + { + return new PBStruct (*this); + } + +#if 0 // @@@ + virtual void create (const PBElementBase *, PBReaderState &, const std::string & /*uri*/, const std::string & /*lname*/, const std::string & /*qname*/) const + { + // .. nothing yet .. + } + + virtual void cdata (const std::string &, PBReaderState &) const + { + // .. nothing yet .. + } + + virtual void finish (const PBElementBase *, PBReaderState &, const std::string & /*uri*/, const std::string & /*lname*/, const std::string & /*qname*/) const + { + // .. nothing yet .. + } + + void write (tl::OutputStream &os, const Obj &root) const + { + PBWriterState writer_state; + writer_state.push (& root); + + os << "\n"; + os << "<" << this->name () << ">\n"; + for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) { + c->get ()->write (this, os, 1, writer_state); + } + os << "name () << ">\n"; + + os.flush (); + } + + void parse (PBSource &source, Obj &root) const + { + PBObjTag tag; + PBParser p; + PBReaderState rs; + rs.push (&root); + PBStructureHandler h (this, &rs); + p.parse (source, h); + rs.pop (tag); + tl_assert (rs.empty ()); + } +#endif + +private: +#if 0 // @@@ + virtual void write (const PBElementBase*, tl::OutputStream &, int, PBWriterState &) const + { + // .. see write (os) + } +#endif +}; + +/** + * @brief Utility: add a PB element to a list of some + */ +inline PBElementList +operator+ (const PBElementList &l, const PBElementBase &e) +{ + return PBElementList (l, e); +} + +/** + * @brief Utility: add a PB element to a list of some + * + * This version transfers the ownership of the PBElementBase object. + */ +inline PBElementList +operator+ (const PBElementList &l, PBElementBase *e) +{ + return PBElementList (l, e); +} + + +// Several adaptor classes needed to implement the various make_* utilities + +template +struct PBMemberDummyWriteAdaptor +{ + PBMemberDummyWriteAdaptor () + { + // .. nothing yet .. + } + + void operator () (Parent &, PBReaderState &) const + { + // .. nothing yet .. + } +}; + +template +struct PBMemberWriteAdaptor +{ + PBMemberWriteAdaptor (Value Parent::*member) + : mp_member (member) + { + // .. nothing yet .. + } + + void operator () (Parent &owner, PBReaderState &reader) const + { + PBObjTag tag; + owner.*mp_member = *reader.back (tag); + } + +private: + Value Parent::*mp_member; +}; + +template +struct PBMemberAccRefWriteAdaptor +{ + PBMemberAccRefWriteAdaptor (void (Parent::*member) (const Value &)) + : mp_member (member) + { + // .. nothing yet .. + } + + void operator () (Parent &owner, PBReaderState &reader) const + { + PBObjTag tag; + (owner.*mp_member) (*reader.back (tag)); + } + +private: + void (Parent::*mp_member) (const Value &); +}; + +template +struct PBMemberTransferWriteAdaptor +{ + PBMemberTransferWriteAdaptor (void (Parent::*member) (Value *)) + : mp_member (member) + { + // .. nothing yet .. + } + + void operator () (Parent &owner, PBReaderState &reader) const + { + PBObjTag tag; + (owner.*mp_member) (reader.detach_back (tag)); + } + +private: + void (Parent::*mp_member) (Value *); +}; + +template +struct PBMemberAccWriteAdaptor +{ + PBMemberAccWriteAdaptor (void (Parent::*member) (Value)) + : mp_member (member) + { + // .. nothing yet .. + } + + void operator () (Parent &owner, PBReaderState &reader) const + { + PBObjTag tag; + (owner.*mp_member) (*reader.back (tag)); + } + +private: + void (Parent::*mp_member) (Value); +}; + +template +struct PBMemberDummyReadAdaptor +{ + typedef pass_by_ref_tag tag; + + PBMemberDummyReadAdaptor () + { + // .. nothing yet .. + } + + Value operator () () const + { + return Value (); + } + + bool at_end () const + { + return true; + } + + void start (const Parent &) + { + // .. nothing yet .. + } + + void next () + { + // .. nothing yet .. + } +}; + +template +struct PBMemberReadAdaptor +{ + typedef pass_by_ref_tag tag; + + PBMemberReadAdaptor (Value Parent::*member) + : mp_member (member), mp_owner (0), m_done (false) + { + // .. nothing yet .. + } + + const Value &operator () () const + { + return mp_owner->*mp_member; + } + + bool at_end () const + { + return m_done; + } + + void start (const Parent &owner) + { + mp_owner = &owner; + m_done = false; + } + + void next () + { + m_done = true; + } + +private: + Value Parent::*mp_member; + const Parent *mp_owner; + bool m_done; +}; + +template +struct PBMemberAccRefReadAdaptor +{ + typedef pass_by_ref_tag tag; + + PBMemberAccRefReadAdaptor (const Value &(Parent::*member) () const) + : mp_member (member), mp_owner (0), m_done (false) + { + // .. nothing yet .. + } + + const Value &operator () () const + { + return (mp_owner->*mp_member) (); + } + + bool at_end () const + { + return m_done; + } + + void start (const Parent &owner) + { + mp_owner = &owner; + m_done = false; + } + + void next () + { + m_done = true; + } + +private: + const Value &(Parent::*mp_member) () const; + const Parent *mp_owner; + bool m_done; +}; + +template +struct PBMemberAccReadAdaptor +{ + typedef pass_by_value_tag tag; + + PBMemberAccReadAdaptor (Value (Parent::*member) () const) + : mp_member (member), mp_owner (0), m_done (false) + { + // .. nothing yet .. + } + + Value operator () () const + { + return (mp_owner->*mp_member) (); + } + + bool at_end () const + { + return m_done; + } + + void start (const Parent &owner) + { + mp_owner = &owner; + m_done = false; + } + + void next () + { + m_done = true; + } + +private: + Value (Parent::*mp_member) () const; + const Parent *mp_owner; + bool m_done; +}; + +template +struct PBMemberIterReadAdaptor +{ + typedef pass_by_ref_tag tag; + + PBMemberIterReadAdaptor (Iter (Parent::*begin) () const, Iter (Parent::*end) () const) + : mp_begin (begin), mp_end (end) + { + // .. nothing yet .. + } + + Value operator () () const + { + return *m_iter; + } + + bool at_end () const + { + return m_iter == m_end; + } + + void start (const Parent &parent) + { + m_iter = (parent.*mp_begin) (); + m_end = (parent.*mp_end) (); + } + + void next () + { + ++m_iter; + } + +private: + Iter (Parent::*mp_begin) () const; + Iter (Parent::*mp_end) () const; + Iter m_iter, m_end; +}; + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccRefWriteAdaptor > +pb_make_element (void (Parent::*setter) (const Value &), int tag, const PBElementList *children) +{ + return PBElement, PBMemberAccRefWriteAdaptor > ( + PBMemberDummyReadAdaptor (), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberTransferWriteAdaptor > +pb_make_element (void (Parent::*setter) (Value *), int tag, const PBElementList *children) +{ + return PBElement, PBMemberTransferWriteAdaptor > ( + PBMemberDummyReadAdaptor (), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccRefWriteAdaptor > +pb_make_element (const Value &(Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList *children) +{ + return PBElement, PBMemberAccRefWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberTransferWriteAdaptor > +pb_make_element (const Value &(Parent::*getter) () const, void (Parent::*setter) (Value *), int tag, const PBElementList *children) +{ + return PBElement, PBMemberTransferWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccWriteAdaptor > +pb_make_element (const Value &(Parent::*getter) () const, void (Parent::*setter) (Value), int tag, const PBElementList *children) +{ + return PBElement, PBMemberAccWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccRefWriteAdaptor > +pb_make_element (Value (Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList *children) +{ + return PBElement, PBMemberAccRefWriteAdaptor > ( + PBMemberAccReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberTransferWriteAdaptor > +pb_make_element (Value (Parent::*getter) () const, void (Parent::*setter) (Value *), int tag, const PBElementList *children) +{ + return PBElement, PBMemberTransferWriteAdaptor > ( + PBMemberAccReadAdaptor (getter), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccWriteAdaptor > +pb_make_element (Value (Parent::*getter) () const, void (Parent::*setter) (Value), int tag, const PBElementList *children) +{ + return PBElement, PBMemberAccWriteAdaptor > ( + PBMemberAccReadAdaptor (getter), + PBMemberAccWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberWriteAdaptor > +pb_make_element (Value Parent::*member, int tag, const PBElementList *children) +{ + return PBElement, PBMemberWriteAdaptor > ( + PBMemberReadAdaptor (member), + PBMemberWriteAdaptor (member), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccRefWriteAdaptor > +pb_make_element (Iter (Parent::*begin) () const, Iter (Parent::*end) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList *children) +{ + return PBElement, PBMemberAccRefWriteAdaptor > ( + PBMemberIterReadAdaptor (begin, end), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberTransferWriteAdaptor > +pb_make_element (Iter (Parent::*begin) () const, Iter (Parent::*end) () const, void (Parent::*setter) (Value *), int tag, const PBElementList *children) +{ + return PBElement, PBMemberTransferWriteAdaptor > ( + PBMemberIterReadAdaptor (begin, end), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccRefWriteAdaptor > +pb_make_element (void (Parent::*setter) (const Value &), int tag, const PBElementList &children) +{ + return PBElement, PBMemberAccRefWriteAdaptor > ( + PBMemberDummyReadAdaptor (), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberTransferWriteAdaptor > +pb_make_element (void (Parent::*setter) (Value *), int tag, const PBElementList &children) +{ + return PBElement, PBMemberTransferWriteAdaptor > ( + PBMemberDummyReadAdaptor (), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccRefWriteAdaptor > +pb_make_element (const Value &(Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList &children) +{ + return PBElement, PBMemberAccRefWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberTransferWriteAdaptor > +pb_make_element (const Value &(Parent::*getter) () const, void (Parent::*setter) (Value *), int tag, const PBElementList &children) +{ + return PBElement, PBMemberTransferWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccWriteAdaptor > +pb_make_element (const Value &(Parent::*getter) () const, void (Parent::*setter) (Value), int tag, const PBElementList &children) +{ + return PBElement, PBMemberAccWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccRefWriteAdaptor > +pb_make_element (Value (Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList &children) +{ + return PBElement, PBMemberAccRefWriteAdaptor > ( + PBMemberAccReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberTransferWriteAdaptor > +pb_make_element (Value (Parent::*getter) () const, void (Parent::*setter) (Value *), int tag, const PBElementList &children) +{ + return PBElement, PBMemberTransferWriteAdaptor > ( + PBMemberAccReadAdaptor (getter), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccWriteAdaptor > +pb_make_element (Value (Parent::*getter) () const, void (Parent::*setter) (Value), int tag, const PBElementList &children) +{ + return PBElement, PBMemberAccWriteAdaptor > ( + PBMemberAccReadAdaptor (getter), + PBMemberAccWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberWriteAdaptor > +pb_make_element (Value Parent::*member, int tag, const PBElementList &children) +{ + return PBElement, PBMemberWriteAdaptor > ( + PBMemberReadAdaptor (member), + PBMemberWriteAdaptor (member), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberAccRefWriteAdaptor > +pb_make_element (Iter (Parent::*begin) () const, Iter (Parent::*end) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList &children) +{ + return PBElement, PBMemberAccRefWriteAdaptor > ( + PBMemberIterReadAdaptor (begin, end), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +/** + * @brief Utility: create a PBElement object + */ +template +PBElement, PBMemberTransferWriteAdaptor > +pb_make_element (Iter (Parent::*begin) () const, Iter (Parent::*end) () const, void (Parent::*setter) (Value *), int tag, const PBElementList &children) +{ + return PBElement, PBMemberTransferWriteAdaptor > ( + PBMemberIterReadAdaptor (begin, end), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +template +PBElementWithParentRef, PBMemberAccRefWriteAdaptor > +pb_make_element_with_parent_ref (const Value &(Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList &children) +{ + return PBElementWithParentRef, PBMemberAccRefWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +template +PBElementWithParentRef, PBMemberAccRefWriteAdaptor > +pb_make_element_with_parent_ref (const Value &(Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList *children) +{ + return PBElementWithParentRef, PBMemberAccRefWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +template +PBElementWithParentRef, PBMemberTransferWriteAdaptor > +pb_make_element_with_parent_ref (const Value &(Parent::*getter) () const, void (Parent::*setter) (Value *), int tag, const PBElementList &children) +{ + return PBElementWithParentRef, PBMemberTransferWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +template +PBElementWithParentRef, PBMemberTransferWriteAdaptor > +pb_make_element_with_parent_ref (const Value &(Parent::*getter) () const, void (Parent::*setter) (Value *), int tag, const PBElementList *children) +{ + return PBElementWithParentRef, PBMemberTransferWriteAdaptor > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +template +PBElementWithParentRef, PBMemberAccRefWriteAdaptor > +pb_make_element_with_parent_ref (Iter (Parent::*begin) () const, Iter (Parent::*end) () const, void (Parent::*setter) (const Value &), int tag, const PBElementList &children) +{ + return PBElementWithParentRef, PBMemberAccRefWriteAdaptor > ( + PBMemberIterReadAdaptor (begin, end), + PBMemberAccRefWriteAdaptor (setter), tag, children); +} + +template +PBElementWithParentRef, PBMemberTransferWriteAdaptor > +pb_make_element_with_parent_ref (Iter (Parent::*begin) () const, Iter (Parent::*end) () const, void (Parent::*setter) (Value *), int tag, const PBElementList &children) +{ + return PBElementWithParentRef, PBMemberTransferWriteAdaptor > ( + PBMemberIterReadAdaptor (begin, end), + PBMemberTransferWriteAdaptor (setter), tag, children); +} + +/** + * @brief A helper class providing string to value (and back) conversion + */ + +template +struct PBStdConverter +{ + std::string to_string (const Value &v) const + { + return tl::to_string (v); + } + + void from_string (const std::string &s, Value &v) const + { + tl::from_string (s, v); + } +}; + +/** + * @brief Utility: create a PBMember object without read & write capability + */ +template +PBMember, PBMemberDummyWriteAdaptor , PBStdConverter > +pb_make_member (int tag) +{ + return PBMember, PBMemberDummyWriteAdaptor , PBStdConverter > ( + PBMemberDummyReadAdaptor (), + PBMemberDummyWriteAdaptor (), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberWriteAdaptor , PBStdConverter > +pb_make_member (Value Parent::*member, int tag) +{ + return PBMember, PBMemberWriteAdaptor , PBStdConverter > ( + PBMemberReadAdaptor (member), + PBMemberWriteAdaptor (member), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccRefWriteAdaptor , PBStdConverter > +pb_make_member (void (Parent::*setter) (const Value &), int tag) +{ + return PBMember, PBMemberAccRefWriteAdaptor , PBStdConverter > ( + PBMemberDummyReadAdaptor (), + PBMemberAccRefWriteAdaptor (setter), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccWriteAdaptor , PBStdConverter > +pb_make_member (void (Parent::*setter) (Value), int tag) +{ + return PBMember, PBMemberAccWriteAdaptor , PBStdConverter > ( + PBMemberDummyReadAdaptor (), + PBMemberAccWriteAdaptor (setter), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccRefWriteAdaptor , PBStdConverter > +pb_make_member (const Value &(Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag) +{ + return PBMember, PBMemberAccRefWriteAdaptor , PBStdConverter > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccWriteAdaptor , PBStdConverter > +pb_make_member (Value (Parent::*getter) () const, void (Parent::*setter) (Value), int tag) +{ + return PBMember, PBMemberAccWriteAdaptor , PBStdConverter > ( + PBMemberAccReadAdaptor (getter), + PBMemberAccWriteAdaptor (setter), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccWriteAdaptor , PBStdConverter > +pb_make_member (const Value & (Parent::*getter) () const, void (Parent::*setter) (Value), int tag) +{ + return PBMember, PBMemberAccWriteAdaptor , PBStdConverter > ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccWriteAdaptor (setter), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccRefWriteAdaptor , PBStdConverter > +pb_make_member (Value (Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag) +{ + return PBMember, PBMemberAccRefWriteAdaptor , PBStdConverter > ( + PBMemberAccReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccRefWriteAdaptor , PBStdConverter > +pb_make_member (Iter (Parent::*begin) () const, Iter (Parent::*end) () const, void (Parent::*setter) (const Value &), int tag) +{ + return PBMember, PBMemberAccRefWriteAdaptor , PBStdConverter > ( + PBMemberIterReadAdaptor (begin, end), + PBMemberAccRefWriteAdaptor (setter), tag); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberWriteAdaptor , Converter> +pb_make_member (Value Parent::*member, int tag, Converter conv) +{ + return PBMember, PBMemberWriteAdaptor , Converter> ( + PBMemberReadAdaptor (member), + PBMemberWriteAdaptor (member), tag, conv); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccRefWriteAdaptor , Converter> +pb_make_member (void (Parent::*setter) (const Value &), int tag, Converter conv) +{ + return PBMember, PBMemberAccRefWriteAdaptor , Converter> ( + PBMemberDummyReadAdaptor (), + PBMemberAccRefWriteAdaptor (setter), tag, conv); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberDummyWriteAdaptor , Converter> +pb_make_member (void (Parent::*setter) (Value), int tag, Converter conv) +{ + return PBMember, PBMemberDummyWriteAdaptor , Converter> ( + PBMemberAccReadAdaptor (setter), + PBMemberDummyWriteAdaptor (), tag, conv); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccRefWriteAdaptor , Converter> +pb_make_member (const Value &(Parent::*getter) () const, void (Parent::*setter) (const Value &), int tag, Converter conv) +{ + return PBMember, PBMemberAccRefWriteAdaptor , Converter> ( + PBMemberAccRefReadAdaptor (getter), + PBMemberAccRefWriteAdaptor (setter), tag, conv); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccWriteAdaptor , Converter> +pb_make_member (Value (Parent::*getter) () const, void (Parent::*setter) (Value), int tag, Converter conv) +{ + return PBMember, PBMemberAccWriteAdaptor , Converter> ( + PBMemberAccReadAdaptor (getter), + PBMemberAccWriteAdaptor (setter), tag, conv); +} + +/** + * @brief Utility: create a PBMember object + */ +template +PBMember, PBMemberAccRefWriteAdaptor , Converter> +pb_make_member (Iter (Parent::*begin) () const, Iter (Parent::*end) () const, void (Parent::*setter) (const Value &), int tag, Converter conv) +{ + return PBMember, PBMemberAccRefWriteAdaptor , Converter> ( + PBMemberIterReadAdaptor (begin, end), + PBMemberAccRefWriteAdaptor (setter), tag, conv); +} + +} + +#endif