add PVIFBuilder abstraction

This commit is contained in:
Michael Davidsaver
2017-09-12 15:31:46 -05:00
parent 0a9d03baf0
commit 850d79dc62
10 changed files with 123 additions and 42 deletions

View File

@ -1,6 +1,8 @@
#ifndef HELPER_H
#define HELPER_H
#include <memory>
#if __cplusplus>=201103L
# define AUTO_VAL(NAME,VAL) auto NAME = VAL
# define AUTO_REF(NAME,VAL) auto& NAME = VAL
@ -13,4 +15,15 @@
# error Require C++11 or G++
#endif
namespace p2p {
#if __cplusplus>=201103L
template<typename T>
using auto_ptr = std::unique_ptr<T>;
#define PTRMOVE(AUTO) std::move(AUTO)
#else
using std::auto_ptr;
#define PTRMOVE(AUTO) (AUTO)
#endif
}
#endif // HELPER_H

View File

@ -362,7 +362,9 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &)
DBCH chan(mem.pvname);
builder->add(mem.pvfldname, PVIF::dtype(chan));
info.builder.reset(new ScalarBuilder);
builder->add(mem.pvfldname, info.builder->dtype(chan));
info.attachment = mem.pvfldname;
info.chan.swap(chan);
@ -437,7 +439,7 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &)
info.evt_VALUE.index = info.evt_PROPERTY.index = i++;
info.evt_VALUE.self = info.evt_PROPERTY.self = pv;
info.pvif.reset(PVIF::attach(info.chan,
info.pvif.reset(info.builder->attach(info.chan,
pv->complete->getSubFieldT<pvd::PVStructure>(info.attachment)));
info.evt_PROPERTY.create(event_context, info.chan, &pdb_group_event, DBE_PROPERTY);

View File

@ -173,7 +173,7 @@ PDBGroupPut::PDBGroupPut(const PDBGroupChannel::shared_pointer& channel,
{
PDBGroupPV::Info& info = channel->pv->members[i];
pvif[i].reset(PVIF::attach(info.chan,
pvif[i].reset(info.builder->attach(info.chan,
pvf->getSubFieldT<pvd::PVStructure>(info.attachment)
));
}
@ -195,7 +195,7 @@ void PDBGroupPut::put(pvd::PVStructure::shared_pointer const & value,
{
PDBGroupPV::Info& info = channel->pv->members[i];
putpvif[i].reset(PVIF::attach(info.chan,
putpvif[i].reset(info.builder->attach(info.chan,
value->getSubFieldT<pvd::PVStructure>(info.attachment)
));
}

View File

@ -8,6 +8,7 @@
#include <pv/pvAccess.h>
#include "helper.h"
#include "pvahelper.h"
#include "pvif.h"
#include "pdb.h"
@ -34,10 +35,11 @@ struct epicsShareClass PDBGroupPV : public PDBPV
struct Info {
DBCH chan;
p2p::auto_ptr<PVIFBuilder> builder;
std::string attachment;
std::vector<size_t> triggers;
DBManyLock locker; // lock only those channels being triggered
std::auto_ptr<PVIF> pvif;
p2p::auto_ptr<PVIF> pvif;
DBEvent evt_VALUE, evt_PROPERTY;
bool had_initial_VALUE, had_initial_PROPERTY;

View File

@ -69,16 +69,17 @@ void pdb_single_event(void *user_arg, struct dbChannel *chan,
PDBSinglePV::PDBSinglePV(DBCH& chan,
const PDBProvider::shared_pointer& prov)
:provider(prov)
,builder(new ScalarBuilder)
,evt_VALUE(this)
,evt_PROPERTY(this)
,hadevent_VALUE(false)
,hadevent_PROPERTY(false)
{
this->chan.swap(chan);
fielddesc = PVIF::dtype(this->chan);
fielddesc = builder->dtype(this->chan);
complete = pvd::getPVDataCreate()->createPVStructure(fielddesc);
pvif.reset(PVIF::attach(this->chan, complete));
pvif.reset(builder->attach(this->chan, complete));
epics::atomic::increment(num_instances);
}
@ -206,7 +207,7 @@ PDBSinglePut::PDBSinglePut(const PDBSingleChannel::shared_pointer &channel,
,requester(requester)
,changed(new pvd::BitSet(channel->fielddesc->getNumberFields()))
,pvf(pvd::getPVDataCreate()->createPVStructure(channel->fielddesc))
,pvif(PVIF::attach(channel->pv->chan, pvf))
,pvif(channel->pv->builder->attach(channel->pv->chan, pvf))
,notifyBusy(0)
,doProc(true)
,doProcForce(false)
@ -280,7 +281,7 @@ void PDBSinglePut::put(pvd::PVStructure::shared_pointer const & value,
// TODO: dbNotify doesn't allow us for force processing
// assume value may be a different struct each time
std::auto_ptr<PVIF> putpvif(PVIF::attach(channel->pv->chan, value));
p2p::auto_ptr<PVIF> putpvif(channel->pv->builder->attach(channel->pv->chan, value));
unsigned mask = putpvif->dbe(*changed);
if(mask&~DBE_VALUE) {
@ -294,7 +295,7 @@ void PDBSinglePut::put(pvd::PVStructure::shared_pointer const & value,
notify.requestType = (mask&DBE_VALUE) ? putProcessRequest : processRequest;
wait_pvif = putpvif;
wait_pvif = PTRMOVE(putpvif);
wait_changed = changed;
dbProcessNotify(&notify);
@ -302,7 +303,7 @@ void PDBSinglePut::put(pvd::PVStructure::shared_pointer const & value,
return; // skip notification
} else {
// assume value may be a different struct each time
std::auto_ptr<PVIF> putpvif(PVIF::attach(channel->pv->chan, value));
p2p::auto_ptr<PVIF> putpvif(channel->pv->builder->attach(channel->pv->chan, value));
try{
DBScanLocker L(chan);
putpvif->get(*changed);

View File

@ -10,6 +10,7 @@
#include <pv/pvAccess.h>
#include "helper.h"
#include "pvahelper.h"
#include "pvif.h"
#include "pdb.h"
@ -35,7 +36,8 @@ struct epicsShareClass PDBSinglePV : public PDBPV
epicsMutex lock;
epics::pvData::BitSet scratch;
std::auto_ptr<PVIF> pvif;
p2p::auto_ptr<PVIFBuilder> builder;
p2p::auto_ptr<PVIF> pvif;
epics::pvData::PVStructurePtr complete; // complete copy from subscription
@ -90,7 +92,7 @@ struct PDBSinglePut : public epics::pvAccess::ChannelPut,
epics::pvData::BitSetPtr changed, wait_changed;
epics::pvData::PVStructurePtr pvf;
std::auto_ptr<PVIF> pvif, wait_pvif;
p2p::auto_ptr<PVIF> pvif, wait_pvif;
processNotify notify;
int notifyBusy; // atomic: 0 - idle, 1 - active, 2 - being cancelled

View File

@ -285,7 +285,7 @@ void pvaOpenLink(DBLINK *plink)
void pvaRemoveLink(struct dbLocker *locker, DBLINK *plink)
{
try {
std::auto_ptr<pvaLink> self((pvaLink*)plink->value.json.jlink);
p2p::auto_ptr<pvaLink> self((pvaLink*)plink->value.json.jlink);
assert(self->alive);
Guard G(self->lchan->lock);

View File

@ -491,10 +491,11 @@ short PVD2DBR(pvd::ScalarType pvt)
}
}
pvd::StructureConstPtr PVIF::dtype(dbChannel* chan)
epics::pvData::StructureConstPtr
ScalarBuilder::dtype(dbChannel *channel)
{
const short dbr = dbChannelFinalFieldType(chan);
const long maxelem = dbChannelFinalElements(chan);
const short dbr = dbChannelFinalFieldType(channel);
const long maxelem = dbChannelFinalElements(channel);
const pvd::ScalarType pvt = DBR2PVD(dbr);
if(INVALID_DB_REQ(dbr))
@ -516,10 +517,11 @@ pvd::StructureConstPtr PVIF::dtype(dbChannel* chan)
return pvd::getStandardField()->scalarArray(pvt, options);
}
PVIF* PVIF::attach(dbChannel* chan, const epics::pvData::PVStructurePtr& root)
PVIF*
ScalarBuilder::attach(dbChannel *channel, const epics::pvData::PVStructurePtr& root)
{
const short dbr = dbChannelFinalFieldType(chan);
const long maxelem = dbChannelFinalElements(chan);
const short dbr = dbChannelFinalFieldType(channel);
const long maxelem = dbChannelFinalElements(channel);
//const pvd::ScalarType pvt = DBR2PVD(dbr);
if(maxelem==1) {
@ -530,14 +532,14 @@ PVIF* PVIF::attach(dbChannel* chan, const epics::pvData::PVStructurePtr& root)
case DBR_USHORT:
case DBR_LONG:
case DBR_ULONG:
return new PVIFScalarNumeric<pvScalar, metaLONG>(chan, dbr, root);
return new PVIFScalarNumeric<pvScalar, metaLONG>(channel, dbr, root);
case DBR_FLOAT:
case DBR_DOUBLE:
return new PVIFScalarNumeric<pvScalar, metaDOUBLE>(chan, dbr, root);
return new PVIFScalarNumeric<pvScalar, metaDOUBLE>(channel, dbr, root);
case DBR_ENUM:
return new PVIFScalarNumeric<pvScalar, metaENUM>(chan, dbr, root);
return new PVIFScalarNumeric<pvScalar, metaENUM>(channel, dbr, root);
case DBR_STRING:
return new PVIFScalarNumeric<pvScalar, metaSTRING>(chan, dbr, root);
return new PVIFScalarNumeric<pvScalar, metaSTRING>(channel, dbr, root);
}
} else {
switch(dbr) {
@ -547,12 +549,32 @@ PVIF* PVIF::attach(dbChannel* chan, const epics::pvData::PVStructurePtr& root)
case DBR_USHORT:
case DBR_LONG:
case DBR_ULONG:
return new PVIFScalarNumeric<pvArray, metaLONG>(chan, dbr, root);
return new PVIFScalarNumeric<pvArray, metaLONG>(channel, dbr, root);
case DBR_FLOAT:
case DBR_DOUBLE:
return new PVIFScalarNumeric<pvArray, metaDOUBLE>(chan, dbr, root);
return new PVIFScalarNumeric<pvArray, metaDOUBLE>(channel, dbr, root);
}
}
throw std::invalid_argument("Channel has invalid/unsupported DBR type");
}
PVIFBuilder::PVIFBuilder()
{}
PVIFBuilder::~PVIFBuilder() {}
PVIFBuilder* PVIFBuilder::create(const options_t& options)
{
options_t::const_iterator it;
if((it = options.find("@type"))==options.end())
throw std::runtime_error("Field mapping missing required key \"@type\"");
const std::string& type(it->second.ref<std::string>());
if(type=="scalar")
return new ScalarBuilder(options);
else
throw std::runtime_error("Unknown mapping @type");
}

View File

@ -13,6 +13,8 @@
#include <pv/bitSet.h>
#include <pv/pvData.h>
#include <anyscalar.h>
#include <shareLib.h>
#ifndef VERSION_INT
@ -257,7 +259,7 @@ struct epicsShareClass PVIF {
PVIF(dbChannel *ch, const epics::pvData::PVStructurePtr& p);
virtual ~PVIF() {}
dbChannel * const chan;
dbChannel * const chan; // borrowed reference from PVIFBuilder
const epics::pvData::PVStructurePtr pvalue;
//! Copy from PDB record to pvalue (call dbChannelGet())
@ -269,11 +271,45 @@ struct epicsShareClass PVIF {
//! Calculate DBE mask from changed bitset
virtual unsigned dbe(const epics::pvData::BitSet& mask) =0;
// fetch the structure description for a DBR type
static epics::pvData::StructureConstPtr dtype(dbChannel *chan);
// Create a PVIF associating the given channel to the given PVStructure node (may not be actual root)
static PVIF* attach(dbChannel* ch, const epics::pvData::PVStructurePtr& root);
private:
PVIF(const PVIF&);
PVIF& operator=(const PVIF&);
};
struct epicsShareClass PVIFBuilder {
virtual ~PVIFBuilder();
// fetch the structure description
virtual epics::pvData::StructureConstPtr dtype(dbChannel *channel) =0;
// Attach to a structure instance.
// must be of the type returned by dtype().
// need not be the root structure
virtual PVIF* attach(dbChannel *channel, const epics::pvData::PVStructurePtr& root) =0;
typedef std::map<std::string, AnyScalar> options_t;
static PVIFBuilder* create(const options_t& options);
protected:
PVIFBuilder();
private:
PVIFBuilder(const PVIFBuilder&);
PVIFBuilder& operator=(const PVIFBuilder&);
};
struct epicsShareClass ScalarBuilder : public PVIFBuilder
{
ScalarBuilder() {}
ScalarBuilder(const options_t& options)
{}
virtual ~ScalarBuilder() {}
virtual epics::pvData::StructureConstPtr dtype(dbChannel *channel) OVERRIDE FINAL;
virtual PVIF* attach(dbChannel *channel, const epics::pvData::PVStructurePtr& root) OVERRIDE FINAL;
};
#endif // PVIF_H

View File

@ -8,6 +8,7 @@
#include <mbbiRecord.h>
#include <stringinRecord.h>
#include "helper.h"
#include "pvif.h"
#include "utilities.h"
@ -53,11 +54,13 @@ void testScalar()
testEqual(dbChannelFinalFieldType(chan_ai_rval), DBR_LONG);
testEqual(dbChannelFinalFieldType(chan_mbbi), DBR_ENUM);
pvd::StructureConstPtr dtype_li(PVIF::dtype(chan_li));
pvd::StructureConstPtr dtype_si(PVIF::dtype(chan_si));
pvd::StructureConstPtr dtype_ai(PVIF::dtype(chan_ai));
pvd::StructureConstPtr dtype_ai_rval(PVIF::dtype(chan_ai_rval));
pvd::StructureConstPtr dtype_mbbi(PVIF::dtype(chan_mbbi));
ScalarBuilder builder;
pvd::StructureConstPtr dtype_li(builder.dtype(chan_li));
pvd::StructureConstPtr dtype_si(builder.dtype(chan_si));
pvd::StructureConstPtr dtype_ai(builder.dtype(chan_ai));
pvd::StructureConstPtr dtype_ai_rval(builder.dtype(chan_ai_rval));
pvd::StructureConstPtr dtype_mbbi(builder.dtype(chan_mbbi));
pvd::StructureConstPtr dtype_root(pvd::getFieldCreate()->createFieldBuilder()
->add("li", dtype_li)
@ -69,11 +72,11 @@ void testScalar()
pvd::PVStructurePtr root(pvd::getPVDataCreate()->createPVStructure(dtype_root));
std::auto_ptr<PVIF> pvif_li(PVIF::attach(chan_li, root->getSubField<pvd::PVStructure>("li")));
std::auto_ptr<PVIF> pvif_si(PVIF::attach(chan_si, root->getSubField<pvd::PVStructure>("si")));
std::auto_ptr<PVIF> pvif_ai(PVIF::attach(chan_ai, root->getSubField<pvd::PVStructure>("ai")));
std::auto_ptr<PVIF> pvif_ai_rval(PVIF::attach(chan_ai_rval, root->getSubField<pvd::PVStructure>("ai_rval")));
std::auto_ptr<PVIF> pvif_mbbi(PVIF::attach(chan_mbbi, root->getSubField<pvd::PVStructure>("mbbi")));
p2p::auto_ptr<PVIF> pvif_li(builder.attach(chan_li, root->getSubField<pvd::PVStructure>("li")));
p2p::auto_ptr<PVIF> pvif_si(builder.attach(chan_si, root->getSubField<pvd::PVStructure>("si")));
p2p::auto_ptr<PVIF> pvif_ai(builder.attach(chan_ai, root->getSubField<pvd::PVStructure>("ai")));
p2p::auto_ptr<PVIF> pvif_ai_rval(builder.attach(chan_ai_rval, root->getSubField<pvd::PVStructure>("ai_rval")));
p2p::auto_ptr<PVIF> pvif_mbbi(builder.attach(chan_mbbi, root->getSubField<pvd::PVStructure>("mbbi")));
pvd::BitSet mask;