This commit is contained in:
Matthias Koefferlein 2024-08-10 20:06:20 +02:00
parent 4e5da4ee9e
commit b6e38b8fdf
3 changed files with 350 additions and 74 deletions

View File

@ -298,14 +298,6 @@ public:
void parse (tl::ProtocolBufferReader &reader, const PBElementBase *root, PBReaderState *reader_state);
template <class Obj>
void parse (tl::ProtocolBufferReader &reader, const PBElementBase *root, Obj &obj)
{
PBReaderState rs;
rs.push (&obj);
parse (reader, root, &rs);
}
private:
std::vector <const PBElementBase *> m_stack;
const PBElementBase *mp_root;
@ -525,10 +517,11 @@ public:
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
virtual void write (const PBElementBase*, tl::ProtocolBufferWriter &, PBWriterState &) const { }
int tag () const
{
return m_tag;
@ -641,32 +634,64 @@ public:
}
#endif
virtual void write (const PBElementBase * /*parent*/, tl::ProtocolBufferWriter &writer, PBWriterState &objs) const
{
PBObjTag<Parent> parent_tag;
Read r (m_r);
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);
r.next ();
}
}
protected:
Read &rear () { return m_r; }
Write &write () { return m_w; }
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
void write_obj (Obj obj, int tag, tl::ProtocolBufferWriter &writer, tl::pass_by_value_tag, PBWriterState &objs) const
{
PBObjTag<Obj> tag;
objs.push (&obj);
for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) {
c->get ()->write (this, os, indent + 1, objs);
PBObjTag<Obj> self_tag;
for (unsigned int pass = 0; pass < 2; ++pass) {
writer.begin_seq (tag, pass == 0);
objs.push (&obj);
for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) {
c->get ()->write (this, writer, objs);
}
objs.pop (self_tag);
writer.end_seq ();
if (! writer.is_counting ()) {
break;
}
}
objs.pop (tag);
}
void write_obj (const Obj &obj, tl::OutputStream &os, int indent, tl::pass_by_ref_tag, PBWriterState &objs) const
void write_obj (const Obj &obj, int tag, tl::ProtocolBufferWriter &writer, tl::pass_by_ref_tag, PBWriterState &objs) const
{
PBObjTag<Obj> tag;
objs.push (&obj);
for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) {
c->get ()->write (this, os, indent + 1, objs);
PBObjTag<Obj> self_tag;
for (unsigned int pass = 0; pass < 2; ++pass) {
writer.begin_seq (tag, pass == 0);
objs.push (&obj);
for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) {
c->get ()->write (this, writer, objs);
}
objs.pop (self_tag);
writer.end_seq ();
if (! writer.is_counting ()) {
break;
}
}
objs.pop (tag);
}
#endif
};
/**
@ -678,23 +703,23 @@ private:
template <class Obj, class Parent, class Read, class Write>
class TL_PUBLIC_TEMPLATE PBElementWithParentRef
: public PBElementBase
: public PBElement<Obj, Parent, Read, Write>
{
public:
PBElementWithParentRef (const Read &r, const Write &w, int tag, const PBElementList &children)
: PBElementBase (tag, children), m_r (r), m_w (w)
: PBElement<Obj, Parent, Read, Write> (r, w, tag, children)
{
// .. nothing yet ..
}
PBElementWithParentRef (const Read &r, const Write &w, int tag, const PBElementList *children)
: PBElementBase (tag, children), m_r (r), m_w (w)
: PBElement<Obj, Parent, Read, Write> (r, w, tag, children)
{
// .. nothing yet ..
}
PBElementWithParentRef (const PBElementWithParentRef<Obj, Parent, Read, Write> &d)
: PBElementBase (d), m_r (d.m_r), m_w (d.m_w)
: PBElement<Obj, Parent, Read, Write> (d)
{
// .. nothing yet ..
}
@ -750,33 +775,6 @@ public:
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<Obj> 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<Obj> 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
};
/**
@ -874,10 +872,87 @@ public:
}
#endif
virtual void write (const PBElementBase * /*parent*/, tl::ProtocolBufferWriter &writer, PBWriterState &objs) const
{
PBObjTag<Parent> parent_tag;
Read r (m_r);
r.start (* objs.back (parent_tag));
while (! r.at_end ()) {
write (writer, tag (), r ());
r.next ();
}
}
private:
Read m_r;
Write m_w;
Converter m_c;
void write (tl::ProtocolBufferWriter &writer, int tag, float v) const
{
writer.write (tag, v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, double v) const
{
writer.write (tag, v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, uint8_t v) const
{
writer.write (tag, (uint32_t) v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, int8_t v) const
{
writer.write (tag, (int32_t) v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, uint16_t v) const
{
writer.write (tag, (uint32_t) v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, int16_t v) const
{
writer.write (tag, (int32_t) v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, uint32_t v) const
{
writer.write (tag, v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, int32_t v) const
{
writer.write (tag, v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, uint64_t v) const
{
writer.write (tag, v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, int64_t v) const
{
writer.write (tag, v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, bool v) const
{
writer.write (tag, v);
}
void write (tl::ProtocolBufferWriter &writer, int tag, const std::string &v) const
{
writer.write (tag, v);
}
template <class T>
void write (tl::ProtocolBufferWriter &writer, int tag, const T &v) const
{
writer.write (tag, m_c.to_string (v));
}
};
/**
@ -893,14 +968,14 @@ class TL_PUBLIC_TEMPLATE PBStruct
: public PBElementBase
{
public:
PBStruct (int tag, const PBElementList *children)
: PBElementBase (tag, children)
PBStruct (const PBElementList *children)
: PBElementBase (0, children)
{
// .. nothing yet ..
}
PBStruct (int tag, const PBElementList &children)
: PBElementBase (tag, children)
PBStruct (const PBElementList &children)
: PBElementBase (0, children)
{
// .. nothing yet ..
}
@ -931,42 +1006,36 @@ public:
{
// .. nothing yet ..
}
#endif
void write (tl::OutputStream &os, const Obj &root) const
void write (tl::ProtocolBufferWriter &writer, const Obj &root) const
{
PBWriterState writer_state;
writer_state.push (& root);
os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
os << "<" << this->name () << ">\n";
for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) {
c->get ()->write (this, os, 1, writer_state);
}
os << "</" << this->name () << ">\n";
// @@@ writer.write (0, name ());
os.flush ();
for (PBElementBase::iterator c = this->begin (); c != this->end (); ++c) {
c->get ()->write (this, writer, writer_state);
}
}
void parse (PBSource &source, Obj &root) const
void parse (tl::ProtocolBufferReader &reader, Obj &root) const
{
PBObjTag<Obj> tag;
PBParser p;
PBReaderState rs;
rs.push (&root);
PBStructureHandler h (this, &rs);
p.parse (source, h);
PBParser h;
h.parse (reader, this, &rs);
rs.pop (tag);
tl_assert (rs.empty ());
}
#endif
private:
#if 0 // @@@
virtual void write (const PBElementBase*, tl::OutputStream &, int, PBWriterState &) const
virtual void write (const PBElementBase*, tl::ProtocolBufferWriter &, PBWriterState &) const
{
// .. see write (os)
}
#endif
};
/**

View File

@ -0,0 +1,206 @@
/*
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"
#include "tlUnitTest.h"
#include "tlFileUtils.h"
#include <sstream>
#include <cmath>
struct Child {
Child () : txt (""), d(-1), live(true) { }
~Child () { tl_assert (live); live = false; }
std::string txt;
double d;
bool live;
bool operator== (const Child &x) const { return txt == x.txt && fabs (d - x.d) < 1e-9 && children == x.children; }
std::vector<Child> children;
std::vector<Child>::const_iterator begin_children() const { return children.begin (); }
std::vector<Child>::const_iterator end_children() const { return children.end (); }
void add_child (const Child &c) { children.push_back (c); }
void add_child_ptr (Child *c) { children.push_back (*c); delete c; }
};
struct Root {
long m;
unsigned int mi;
std::vector<double> m_subs;
std::vector<int> m_isubs;
std::vector<Child> m_children;
Child m_child;
Root () : m(0), mi(0) { }
bool operator== (const Root &x) const { return m == x.m &&
mi == x.mi && m_subs == x.m_subs &&
m_isubs == x.m_isubs && m_children == x.m_children
&& m_child == x.m_child; }
int get_mi () const { return mi; }
void set_mi (int i) { mi = i; }
void add_sub (const double &s) {
m_subs.push_back (s);
}
void add_isub (const int &s) {
m_isubs.push_back (s);
}
std::vector<double>::const_iterator begin_subs () const {
return m_subs.begin ();
}
std::vector<double>::const_iterator end_subs () const {
return m_subs.end ();
}
std::vector<int>::const_iterator begin_isubs () const {
return m_isubs.begin ();
}
std::vector<int>::const_iterator end_isubs () const {
return m_isubs.end ();
}
void add_child_ptr (Child *c) {
m_children.push_back (*c);
delete c;
}
void add_child (const Child &c) {
m_children.push_back (c);
}
std::vector<Child>::const_iterator begin_children () const {
return m_children.begin ();
}
std::vector<Child>::const_iterator end_children () const {
return m_children.end ();
}
void set_child (const Child &child) { m_child = child; }
const Child &get_child () const { return m_child; }
};
TEST (1)
{
Root root;
tl::PBStruct<Root> structure (
tl::pb_make_member (&Root::begin_subs, &Root::end_subs, &Root::add_sub, 1) +
tl::pb_make_member (&Root::begin_isubs, &Root::end_isubs, &Root::add_isub, 2) +
tl::pb_make_element (&Root::begin_children, &Root::end_children, &Root::add_child, 3,
tl::pb_make_member (&Child::txt, 1) +
tl::pb_make_member (&Child::d, 2)
) +
tl::pb_make_element (&Root::get_child, &Root::set_child, 4,
tl::pb_make_member (&Child::txt, 1) +
tl::pb_make_member (&Child::d, 2)
) +
tl::pb_make_member (&Root::m, 5) +
tl::pb_make_member (&Root::get_mi, &Root::set_mi, 6)
);
root.add_sub (0.5);
root.add_sub (7.5);
root.add_isub (42);
root.add_isub (1700000000);
Child c1;
c1.txt = "c1";
c1.d = 1.0;
root.add_child (c1);
Child c2;
c2.txt = "c2";
c2.d = 2.0;
Child c21;
c21.txt = "c21";
c21.d = 2.1;
c2.add_child (c21);
Child c22;
c22.txt = "c22";
c22.d = 2.2;
c2.add_child (c22);
Child c23;
c23.txt = "c23";
c23.d = 2.3;
c2.add_child (c23);
root.add_child (c2);
std::string fn = tl::combine_path (tl::testtmp (), "pb_test.pb");
{
tl::OutputStream os (fn);
tl::ProtocolBufferWriter writer (os);
structure.write (writer, root);
}
std::string error;
try {
tl::InputStream is (fn);
tl::ProtocolBufferReader reader (is);
structure.parse (reader, root);
} catch (tl::Exception &ex) {
error = ex.msg ();
}
// TODO: adjust
EXPECT_EQ (error, "");
EXPECT_EQ (root.m_subs.size (), size_t (2));
EXPECT_EQ (root.m_subs [0], 1.0);
EXPECT_EQ (root.m_subs [1], -2.5);
EXPECT_EQ (root.m_isubs.size (), size_t (1));
EXPECT_EQ (root.m_isubs [0], -100);
EXPECT_EQ (root.m, 10);
EXPECT_EQ (root.mi, (unsigned int) 21);
EXPECT_EQ (root.m_children.size (), size_t (2));
EXPECT_EQ (root.m_children [0].txt, " Text ");
EXPECT_EQ (fabs (root.m_children [0].d - 0.001) < 1e-12, true);
EXPECT_EQ (root.m_children [1].txt, "T2");
EXPECT_EQ (root.m_children [1].d, -1.0);
EXPECT_EQ (root.m_child.txt, "Single child");
EXPECT_EQ (root.m_child.d, -1.0);
// write ..
tl::OutputMemoryStream out;
{
tl::OutputStream os (out);
tl::ProtocolBufferWriter writer (os);
structure.write (writer, root);
}
// and read again.
Root rsave (root);
try {
error.clear ();
tl::InputMemoryStream s2 (out.data (), out.size ());
tl::InputStream is (s2);
root = Root ();
tl::ProtocolBufferReader reader (is);
structure.parse (reader, root);
} catch (tl::Exception &ex) {
error = ex.msg ();
}
EXPECT_EQ (error, "");
EXPECT_EQ (root == rsave, true);
}

View File

@ -33,6 +33,7 @@ SOURCES = \
tlObjectTests.cc \
tlOptionalTests.cc \
tlPixelBufferTests.cc \
tlProtocolBufferTests.cc \
tlResourcesTests.cc \
tlReuseVectorTests.cc \
tlStableVectorTests.cc \