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.
This commit is contained in:
Michael Davidsaver
2018-09-18 06:45:50 -07:00
parent 5a59b1da75
commit aa87a2a23d
3 changed files with 127 additions and 27 deletions

View File

@@ -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

View File

@@ -10,6 +10,7 @@
#include <pv/pvdVersion.h>
#include <pv/pvData.h>
#include <pv/valueBuilder.h>
#include <pv/bitSet.h>
#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(); i<N; i++)
{
if(i!=0)
if(mask && !mask->get(children[i]->getFieldOffset())) continue;
if(first)
first = false;
else
A.strm.put(',');
A.doIntent();
A.strm<<'\"'<<names[i]<<"\": ";
show_field(A, children[i].get());
show_field(A, children[i].get(), mask);
}
A.indent--;
@@ -66,7 +72,7 @@ void show_struct(args& A, const pvd::PVStructure* fld)
A.strm.put('}');
}
void show_field(args& A, const pvd::PVField* fld)
void show_field(args& A, const pvd::PVField* fld, const pvd::BitSet *mask)
{
switch(fld->getField()->getType())
{
@@ -79,7 +85,7 @@ void show_field(args& A, const pvd::PVField* fld)
A.strm<<scalar->getAs<std::string>();
}
}
break;
return;
case pvd::scalarArray:
{
const pvd::PVScalarArray *scalar=static_cast<const pvd::PVScalarArray*>(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<const pvd::PVStructure*>(fld));
break;
show_struct(A, static_cast<const pvd::PVStructure*>(fld), mask);
return;
case pvd::structureArray:
{
pvd::PVStructureArray::const_svector arr(static_cast<const pvd::PVStructureArray*>(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<const pvd::PVUnion*>(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<const pvd::PVUnionArray*>(fld);
pvd::PVUnionArray::const_svector arr(U->view());
A.strm.put('[');
A.indent++;
for(size_t i=0, N=arr.size(); i<N; i++) {
if(i!=0)
A.strm.put(',');
A.doIntent();
if(arr[i])
show_field(A, arr[i].get(), 0);
else
A.strm<<"NULL";
}
A.indent--;
A.doIntent();
A.strm.put(']');
}
return;
}
// should not be reached
if(A.opts.ignoreUnprintable)
A.strm<<"// unprintable field type";
else
throw std::runtime_error("Encountered unprintable field type");
}
void expandBS(const pvd::PVStructure& top, pvd::BitSet& mask, bool parents) {
if(mask.get(0)) { // special handling because getSubField(0) not allowed
// wildcard
for(size_t idx=1, N=top.getNumberFields(); idx<N; idx++) {
mask.set(idx);
}
} else {
for(pvd::int32 idx = mask.nextSetBit(0), N=top.getNumberFields(); idx>=0 && idx<N; idx=mask.nextSetBit(idx+1)) {
pvd::PVField::const_shared_pointer fld = top.getSubFieldT(idx);
// look forward and mark all children
for(size_t i=idx+1, N=fld->getNextFieldOffset(); i<N; i++)
mask.set(i);
if(parents) {
// look back and mark all parents
// we've already stepped past all parents so siblings will not be automatically marked
for(const pvd::PVStructure *parent = fld->getParent(); 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

View File

@@ -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()
*