diff --git a/src/tl/tl/tlProtocolBufferStruct.cc b/src/tl/tl/tlProtocolBufferStruct.cc index 6a675031f..25ecbd43a 100644 --- a/src/tl/tl/tlProtocolBufferStruct.cc +++ b/src/tl/tl/tlProtocolBufferStruct.cc @@ -21,12 +21,234 @@ */ #include "tlProtocolBufferStruct.h" - +#include namespace tl { - // -------------------------------------------------------------------- +static size_t s_oid = 0; + +// -------------------------------------------------------------------- +// PBElementList implementation + +PBElementList::PBElementList () + : m_oid (++s_oid) +{ + // .. nothing yet .. +} + +PBElementList::PBElementList (const PBElementBase &e) + : m_oid (++s_oid) +{ + m_elements.push_back (PBElementProxy (e)); +} + +PBElementList::PBElementList (PBElementBase *e) + : m_oid (++s_oid) +{ + if (e) { + m_elements.push_back (PBElementProxy (e)); + } +} + +PBElementList::PBElementList (const std::string &name, const PBElementList &d) + : m_elements (d.m_elements), m_oid (d.m_oid), m_name (name) +{ + // .. nothing yet .. +} + +PBElementList::PBElementList (const PBElementList &d) + : m_elements (d.m_elements), m_oid (d.m_oid), m_name (d.m_name) +{ + // .. nothing yet .. +} + +PBElementList::PBElementList (const PBElementList &d, const PBElementBase &e) + : m_elements (d.m_elements), m_oid (++s_oid), m_name (d.m_name) +{ + m_elements.push_back (PBElementProxy (e)); +} + +PBElementList::PBElementList (const PBElementList &d, PBElementBase *e) + : m_elements (d.m_elements), m_oid (++s_oid), m_name (d.m_name) +{ + if (e) { + m_elements.push_back (PBElementProxy (e)); + } +} + +void PBElementList::append (const PBElementBase &e) +{ + m_elements.push_back (PBElementProxy (e)); +} + +void PBElementList::append (PBElementBase *e) +{ + if (e) { + m_elements.push_back (PBElementProxy (e)); + } +} + +PBElementList::iterator PBElementList::begin () const +{ + return m_elements.begin (); +} + +PBElementList::iterator PBElementList::end () const +{ + return m_elements.end (); +} + +PBElementList PBElementList::empty () +{ + return PBElementList (); +} + +// -------------------------------------------------------------------- +// PBElementBase implementation + +PBElementBase::PBElementBase (const std::string &name, int tag, const PBElementList &children) + : m_name (name), m_tag (tag), mp_children (new PBElementList (children)), m_owns_child_list (true) +{ + // .. nothing yet .. +} + +PBElementBase::PBElementBase (const std::string &name, int tag, const PBElementList *children) + : m_name (name), m_tag (tag), mp_children (children), m_owns_child_list (false) +{ + // .. nothing yet .. +} + +PBElementBase::PBElementBase (const PBElementBase &d) + : m_name (d.m_name), 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; + } +} + +PBElementBase::~PBElementBase () +{ + if (m_owns_child_list) { + delete const_cast (mp_children); + mp_children = 0; + } +} + +PBElementBase::Cardinality +PBElementBase::cardinality () const +{ + return Zero; +} + +PBElementBase::iterator +PBElementBase::begin () const +{ + return mp_children->begin (); +} + +PBElementBase::iterator +PBElementBase::end () const +{ + return mp_children->end (); +} + +std::string +PBElementBase::name4code () const +{ + std::string res; + const char *n = name ().c_str (); + + if (! isalpha (*n) && *n != '_') { + res += '_'; + } + + while (*n) { + if (*n == '-') { + res += '_'; + } else if (isalnum (*n) || *n == '_') { + res += *n; + } + ++n; + } + + return res; +} + +std::string +PBElementBase::create_def (std::map > &messages) const +{ + std::string res; + + auto m = messages.find (oid ()); + if (m != messages.end ()) { + + res += "message " + m->second.second + " {\n"; + + for (auto i = begin (); i != end (); ++i) { + const PBElementBase *e = i->get (); + Cardinality c = e->cardinality (); + std::string entry = e->create_def_entry (messages); + if (! entry.empty ()) { + res += " "; + if (c != Zero) { + if (c == Many) { + res += "repeated "; + } else { + res += "optional "; + } + res += entry + "\n"; + } + } + } + + res += "}"; + + } + + return res; +} + +void +PBElementBase::collect_messages (std::map > &messages) const +{ + for (auto i = begin (); i != end (); ++i) { + i->get ()->collect_messages (messages); + } +} + +std::string +PBElementBase::make_message_name () const +{ + std::string res = mp_children->name (); + if (! res.empty ()) { + return res; + } + + // Capitalize names + std::string n4c = name4code (); + + bool upcase = true; + + const char *n = n4c.c_str (); + while (*n) { + if (*n == '_') { + upcase = true; + } else if (upcase) { + res += toupper (*n); + upcase = false; + } else { + res += *n; + } + ++n; + } + + return res; +} + +// -------------------------------------------------------------------- // PBParser implementation PBParser::PBParser () diff --git a/src/tl/tl/tlProtocolBufferStruct.h b/src/tl/tl/tlProtocolBufferStruct.h index c22635594..c4bacf3de 100644 --- a/src/tl/tl/tlProtocolBufferStruct.h +++ b/src/tl/tl/tlProtocolBufferStruct.h @@ -26,6 +26,8 @@ #include "tlCommon.h" #include "tlProtocolBuffer.h" +#include + namespace tl { @@ -277,12 +279,24 @@ private: class TL_PUBLIC PBElementBase; -struct pass_by_value_tag { - pass_by_value_tag () { } +struct pb_pass_by_value_tag { + pb_pass_by_value_tag () { } }; -struct pass_by_ref_tag { - pass_by_ref_tag () { } +struct pb_pass_by_ref_tag { + pb_pass_by_ref_tag () { } +}; + +struct pb_zero_cardinality_tag { + pb_zero_cardinality_tag () { } +}; + +struct pb_single_cardinality_tag { + pb_single_cardinality_tag () { } +}; + +struct pb_many_cardinality_tag { + pb_many_cardinality_tag () { } }; /** @@ -360,66 +374,36 @@ public: typedef std::list children_list; typedef children_list::const_iterator iterator; - PBElementList () + PBElementList (); + PBElementList (const PBElementBase &e); + PBElementList (PBElementBase *e); + PBElementList (const std::string &name, const PBElementList &d); + PBElementList (const PBElementList &d); + PBElementList (const PBElementList &d, const PBElementBase &e); + PBElementList (const PBElementList &d, PBElementBase *e); + + void append (const PBElementBase &e); + void append (PBElementBase *e); + + iterator begin () const; + iterator end () const; + + static PBElementList empty (); + + size_t oid () const { - // .. nothing yet .. + return m_oid; } - PBElementList (const PBElementBase &e) + const std::string &name () const { - 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 (); + return m_name; } private: std::list m_elements; + size_t m_oid; + std::string m_name; }; /** @@ -486,35 +470,14 @@ class TL_PUBLIC PBElementBase public: typedef PBElementList::iterator iterator; - PBElementBase (const std::string &name, int tag, const PBElementList &children) - : m_name (name), m_tag (tag), mp_children (new PBElementList (children)), m_owns_child_list (true) - { - // .. nothing yet .. - } + enum Cardinality { + Zero, Single, Many + }; - PBElementBase (const std::string &name, int tag, const PBElementList *children) - : m_name (name), m_tag (tag), mp_children (children), m_owns_child_list (false) - { - // .. nothing yet .. - } - - PBElementBase (const PBElementBase &d) - : m_name (d.m_name), 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; - } - } + PBElementBase (const std::string &name, int tag, const PBElementList &children); + PBElementBase (const std::string &name, int tag, const PBElementList *children); + PBElementBase (const PBElementBase &d); + virtual ~PBElementBase (); virtual PBElementBase *clone () const = 0; @@ -524,6 +487,13 @@ public: virtual void write (const PBElementBase *, tl::ProtocolBufferWriterBase &, PBWriterState &) const { } + virtual Cardinality cardinality () const; + + size_t oid () const + { + return mp_children->oid (); + } + int tag () const { return m_tag; @@ -534,14 +504,36 @@ public: return m_name; } - iterator begin () const + /** + * @brief Returns a name suitable for code + * Specifically, hyphens are replaced by underscores. + */ + std::string name4code () const; + + iterator begin () const; + iterator end () const; + + std::string create_def (std::map > &messages) const; + +protected: + virtual void collect_messages (std::map > &messages) const; + virtual std::string create_def_entry (std::map > &messages) const = 0; + + std::string make_message_name () const; + + static Cardinality get_cardinality (tl::pb_zero_cardinality_tag) { - return mp_children->begin (); + return Zero; } - iterator end () const + static Cardinality get_cardinality (tl::pb_single_cardinality_tag) { - return mp_children->end (); + return Single; + } + + static Cardinality get_cardinality (tl::pb_many_cardinality_tag) + { + return Many; } private: @@ -625,12 +617,35 @@ public: r.start (*objs.back (parent_tag)); while (! r.at_end ()) { typedef typename Read::tag read_tag_type; - read_tag_type read_tag; - write_obj (r (), tag (), writer, read_tag, objs); + write_obj (r (), tag (), writer, read_tag_type (), objs); r.next (); } } + virtual Cardinality cardinality () const + { + typedef typename Read::cardinality cardinality_type; + return get_cardinality (cardinality_type ()); + } + + virtual void collect_messages (std::map > &messages) const + { + if (messages.find (oid ()) == messages.end ()) { + messages [oid ()] = std::make_pair (this, make_message_name ()); + PBElementBase::collect_messages (messages); + } + } + + virtual std::string create_def_entry (std::map > &messages) const + { + auto m = messages.find (oid ()); + if (m != messages.end ()) { + return m->second.second + " " + name4code () + " = " + tl::to_string (tag ()) + ";"; + } else { + return std::string (); + } + } + protected: Read &rear () { return m_r; } Write &write () { return m_w; } @@ -640,7 +655,7 @@ private: Write m_w; // this write helper is used if the reader delivers an object by value - void write_obj (Obj obj, int tag, tl::ProtocolBufferWriterBase &writer, tl::pass_by_value_tag, PBWriterState &objs) const + void write_obj (Obj obj, int tag, tl::ProtocolBufferWriterBase &writer, tl::pb_pass_by_value_tag, PBWriterState &objs) const { PBObjTag self_tag; @@ -658,7 +673,7 @@ private: } } - void write_obj (const Obj &obj, int tag, tl::ProtocolBufferWriterBase &writer, tl::pass_by_ref_tag, PBWriterState &objs) const + void write_obj (const Obj &obj, int tag, tl::ProtocolBufferWriterBase &writer, tl::pb_pass_by_ref_tag, PBWriterState &objs) const { PBObjTag self_tag; @@ -800,6 +815,23 @@ public: } } + virtual Cardinality cardinality () const + { + typedef typename Read::cardinality cardinality_type; + return get_cardinality (cardinality_type ()); + } + + virtual void collect_messages (std::map > & /*messages*/) const + { + // no messages here. + } + + virtual std::string create_def_entry (std::map > & /*messages*/) const + { + const Value *v = 0; + return typestring (v) + " " + name4code () + " = " + tl::to_string (tag ()) + ";"; + } + private: Read m_r; Write m_w; @@ -952,6 +984,74 @@ private: reader.read (vv); m_c.pb_decode (vv, v); } + + // type strings + std::string typestring (const float *) const + { + return "float"; + } + + std::string typestring (const double *) const + { + return "double"; + } + + std::string typestring (const uint8_t *) const + { + return "uint32"; + } + + std::string typestring (const uint16_t *) const + { + return "uint32"; + } + + std::string typestring (const uint32_t *) const + { + return "uint32"; + } + + std::string typestring (const uint64_t *) const + { + return "uint64"; + } + + std::string typestring (const int8_t *) const + { + return "sint32"; + } + + std::string typestring (const int16_t *) const + { + return "sint32"; + } + + std::string typestring (const int32_t *) const + { + return "sint32"; + } + + std::string typestring (const int64_t *) const + { + return "sint64"; + } + + std::string typestring (const bool *) const + { + return "uint32"; + } + + std::string typestring (const std::string *) const + { + return "string"; + } + + template + std::string typestring (const T *) const + { + const typename Converter::pb_type *v = 0; + return typestring (v); + } }; /** @@ -1035,7 +1135,23 @@ public: */ std::string create_def () const { - return std::string (); // @@@ + std::map > msgs; + collect_messages (msgs); + msgs[oid ()] = std::make_pair (this, make_message_name ()); + + std::string res = "// created from KLayout proto definition '" + name () + "'\n\n"; + res += "syntax = \"proto2\";"; + + for (auto i = msgs.begin (); i != msgs.end (); ++i) { + std::string entry = i->second.first->create_def (msgs); + if (! entry.empty ()) { + res += "\n"; + res += "\n"; + res += entry; + } + } + + return res; } private: @@ -1054,10 +1170,15 @@ private: // disable base class implementation } - virtual void finish (const PBElementBase * /*parent*/, PBReaderState &) const + virtual void finish (const PBElementBase *, PBReaderState &) const { // disable base class implementation } + + virtual std::string create_def_entry (std::map > &) const + { + return std::string (); + } }; /** @@ -1176,7 +1297,8 @@ private: template struct PBMemberDummyReadAdaptor { - typedef pass_by_ref_tag tag; + typedef pb_pass_by_ref_tag tag; + typedef pb_zero_cardinality_tag cardinality; PBMemberDummyReadAdaptor () { @@ -1207,7 +1329,8 @@ struct PBMemberDummyReadAdaptor template struct PBMemberReadAdaptor { - typedef pass_by_ref_tag tag; + typedef pb_pass_by_ref_tag tag; + typedef pb_single_cardinality_tag cardinality; PBMemberReadAdaptor (Value Parent::*member) : mp_member (member), mp_owner (0), m_done (false) @@ -1245,7 +1368,8 @@ private: template struct PBMemberAccRefReadAdaptor { - typedef pass_by_ref_tag tag; + typedef pb_pass_by_ref_tag tag; + typedef pb_single_cardinality_tag cardinality; PBMemberAccRefReadAdaptor (const Value &(Parent::*member) () const) : mp_member (member), mp_owner (0), m_done (false) @@ -1283,7 +1407,8 @@ private: template struct PBMemberAccReadAdaptor { - typedef pass_by_value_tag tag; + typedef pb_pass_by_value_tag tag; + typedef pb_single_cardinality_tag cardinality; PBMemberAccReadAdaptor (Value (Parent::*member) () const) : mp_member (member), mp_owner (0), m_done (false) @@ -1321,7 +1446,8 @@ private: template struct PBMemberIterReadAdaptor { - typedef pass_by_ref_tag tag; + typedef pb_pass_by_ref_tag tag; + typedef pb_many_cardinality_tag cardinality; PBMemberIterReadAdaptor (Iter (Parent::*begin) () const, Iter (Parent::*end) () const) : mp_begin (begin), mp_end (end) diff --git a/src/tl/unit_tests/tlProtocolBufferTests.cc b/src/tl/unit_tests/tlProtocolBufferTests.cc index e50b33a45..75289aed1 100644 --- a/src/tl/unit_tests/tlProtocolBufferTests.cc +++ b/src/tl/unit_tests/tlProtocolBufferTests.cc @@ -205,15 +205,16 @@ struct Root { const Child &get_child () const { return m_child; } }; -static tl::PBElementList child_struct = - tl::pb_make_member (&Child::txt, "txt", 1) + - tl::pb_make_member (&Child::d, "d", 2) + - tl::pb_make_element (&Child::begin_children, &Child::end_children, &Child::add_child, "children", 3, &child_struct); +static tl::PBElementList child_struct ("Child", + tl::pb_make_member (&Child::txt, "txt", 1) + + tl::pb_make_member (&Child::d, "d", 2) + + tl::pb_make_element (&Child::begin_children, &Child::end_children, &Child::add_child, "children", 3, &child_struct) +); static tl::PBStruct structure ("pbtest-struct", 88888888, tl::pb_make_member (&Root::begin_subs, &Root::end_subs, &Root::add_sub, "sub", 1) + tl::pb_make_member (&Root::begin_isubs, &Root::end_isubs, &Root::add_isub, "isub", 2) + - tl::pb_make_element (&Root::begin_children, &Root::end_children, &Root::add_child, "childredn", 3, &child_struct) + + tl::pb_make_element (&Root::begin_children, &Root::end_children, &Root::add_child, "children", 3, &child_struct) + tl::pb_make_element (&Root::get_child, &Root::set_child, "child", 4, &child_struct) + tl::pb_make_member (&Root::m, "m", 5) + tl::pb_make_member (&Root::get_mi, &Root::set_mi, "mi", 6) + @@ -608,3 +609,27 @@ TEST (108_InvalidType) EXPECT_EQ (std::string (error, 0, 34), "Expected a VARINT or I32 wire type"); } +TEST (109_DumpSpec) +{ + EXPECT_EQ (structure.create_def (), + "// created from KLayout proto definition 'pbtest-struct'\n" + "\n" + "syntax = \"proto2\";\n" + "\n" + "message Child {\n" + " optional string txt = 1;\n" + " optional double d = 2;\n" + " repeated Child children = 3;\n" + "}\n" + "\n" + "message PbtestStruct {\n" + " repeated double sub = 1;\n" + " repeated sint32 isub = 2;\n" + " repeated Child children = 3;\n" + " optional Child child = 4;\n" + " optional sint64 m = 5;\n" + " optional sint32 mi = 6;\n" + " optional uint32 b = 7;\n" + "}" + ); +}