From aa87a2a23dc825e090bae9271703e3d51717eca8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 18 Sep 2018 06:45:50 -0700 Subject: [PATCH] json print/parse updates These functions don't create new refs, so they don't really need to work with shared_ptr. Fully support printing. Add option for maskable PVStructure printing. --- src/json/parseinto.cpp | 14 +++++- src/json/print.cpp | 106 +++++++++++++++++++++++++++++++++-------- src/json/pv/json.h | 34 +++++++++++-- 3 files changed, 127 insertions(+), 27 deletions(-) diff --git a/src/json/parseinto.cpp b/src/json/parseinto.cpp index 940f6c3..587f095 100644 --- a/src/json/parseinto.cpp +++ b/src/json/parseinto.cpp @@ -302,13 +302,17 @@ struct handler { operator yajl_handle() { return handle; } }; +struct noop { + void operator()(pvd::PVField*) {} +}; + } // namespace namespace epics{namespace pvData{ epicsShareFunc void parseJSON(std::istream& strm, - const PVField::shared_pointer& dest, + PVField& dest, BitSet *assigned) { #ifndef EPICS_YAJL_VERSION @@ -318,7 +322,12 @@ void parseJSON(std::istream& strm, conf.checkUTF8 = 1; #endif - context ctxt(dest, assigned); + // we won't create refs to 'dest' which presist beyond this call. + // however, it is convienent to treat 'dest' in the same manner as + // any union/structureArray memebers it may contain. + PVFieldPtr fakedest(&dest, noop()); + + context ctxt(fakedest, assigned); #ifndef EPICS_YAJL_VERSION handler handle(yajl_alloc(&jtree_cbs, &conf, NULL, &ctxt)); @@ -334,6 +343,7 @@ void parseJSON(std::istream& strm, if(!ctxt.stack.empty()) throw std::logic_error("field stack not empty"); + assert(fakedest.use_count()==1); } }} // namespace epics::pvData diff --git a/src/json/print.cpp b/src/json/print.cpp index e834473..60707d2 100644 --- a/src/json/print.cpp +++ b/src/json/print.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1) @@ -40,9 +41,9 @@ struct args { } }; -void show_field(args& A, const pvd::PVField* fld); +void show_field(args& A, const pvd::PVField* fld, const pvd::BitSet *mask); -void show_struct(args& A, const pvd::PVStructure* fld) +void show_struct(args& A, const pvd::PVStructure* fld, const pvd::BitSet *mask) { const pvd::StructureConstPtr& type = fld->getStructure(); const pvd::PVFieldPtrArray& children = fld->getPVFields(); @@ -52,13 +53,18 @@ void show_struct(args& A, const pvd::PVStructure* fld) A.strm.put('{'); A.indent++; + bool first = true; for(size_t i=0, N=names.size(); iget(children[i]->getFieldOffset())) continue; + + if(first) + first = false; + else A.strm.put(','); A.doIntent(); A.strm<<'\"'<getField()->getType()) { @@ -79,7 +85,7 @@ void show_field(args& A, const pvd::PVField* fld) A.strm<getAs(); } } - break; + return; case pvd::scalarArray: { const pvd::PVScalarArray *scalar=static_cast(fld); @@ -102,10 +108,10 @@ void show_field(args& A, const pvd::PVField* fld) } A.strm.put(']'); } - break; + return; case pvd::structure: - show_struct(A, static_cast(fld)); - break; + show_struct(A, static_cast(fld), mask); + return; case pvd::structureArray: { pvd::PVStructureArray::const_svector arr(static_cast(fld)->view()); @@ -117,7 +123,7 @@ void show_field(args& A, const pvd::PVField* fld) A.strm.put(','); A.doIntent(); if(arr[i]) - show_struct(A, arr[i].get()); + show_struct(A, arr[i].get(), 0); else A.strm<<"NULL"; } @@ -126,7 +132,7 @@ void show_field(args& A, const pvd::PVField* fld) A.doIntent(); A.strm.put(']'); } - break; + return; case pvd::union_: { const pvd::PVUnion *U=static_cast(fld); @@ -135,15 +141,63 @@ void show_field(args& A, const pvd::PVField* fld) if(!C) { A.strm<<"null"; } else { - show_field(A, C.get()); + show_field(A, C.get(), 0); } } - break; - default: - if(A.opts.ignoreUnprintable) - A.strm<<"// unprintable field type"; - else - throw std::runtime_error("Encountered unprintable field type"); + return; + case pvd::unionArray: { + const pvd::PVUnionArray *U=static_cast(fld); + pvd::PVUnionArray::const_svector arr(U->view()); + A.strm.put('['); + A.indent++; + + for(size_t i=0, N=arr.size(); i=0 && idxgetNextFieldOffset(); igetParent(); parent; parent = parent->getParent()) { + mask.set(parent->getFieldOffset()); + } + } + } } } @@ -158,11 +212,23 @@ JSONPrintOptions::JSONPrintOptions() {} void printJSON(std::ostream& strm, - const PVField::const_shared_pointer& val, + const PVStructure& val, + const BitSet& mask, const JSONPrintOptions& opts) { args A(strm, opts); - show_field(A, val.get()); + pvd::BitSet emask(mask); + expandBS(val, emask, true); + if(!emask.get(0)) return; + show_struct(A, &val, &emask); +} + +void printJSON(std::ostream& strm, + const PVField& val, + const JSONPrintOptions& opts) +{ + args A(strm, opts); + show_field(A, &val, 0); } }} // namespace epics::pvData diff --git a/src/json/pv/json.h b/src/json/pv/json.h index 5a7bc19..eb500ca 100644 --- a/src/json/pv/json.h +++ b/src/json/pv/json.h @@ -51,15 +51,30 @@ struct epicsShareClass JSONPrintOptions /** Print PVStructure as JSON * - * Restrictions: - * - * - No support for union or array of union + * 'mask' selects those fields which will be printed. */ epicsShareFunc void printJSON(std::ostream& strm, - const PVField::const_shared_pointer& val, + const PVStructure& val, + const BitSet& mask, const JSONPrintOptions& opts = JSONPrintOptions()); +/** Print PVField as JSON + */ +epicsShareFunc +void printJSON(std::ostream& strm, + const PVField& val, + const JSONPrintOptions& opts = JSONPrintOptions()); + +// To be deprecated in favor of previous form +FORCE_INLINE +void printJSON(std::ostream& strm, + const PVField::const_shared_pointer& val, + const JSONPrintOptions& opts = JSONPrintOptions()) +{ + printJSON(strm, *val, opts); +} + /** Parse JSON text into a PVStructure * * Restrictions: @@ -85,9 +100,18 @@ PVStructure::shared_pointer parseJSON(std::istream& strm); */ epicsShareFunc void parseJSON(std::istream& strm, - const PVField::shared_pointer& dest, + PVField& dest, BitSet *assigned=0); +// To be deprecated in favor of previous form +FORCE_INLINE +void parseJSON(std::istream& strm, + const PVField::shared_pointer& dest, + BitSet *assigned=0) +{ + parseJSON(strm, *dest, assigned); +} + /** Wrapper around yajl_parse() *