NTTable refactored

This commit is contained in:
Matej Sekoranja
2014-08-21 13:28:52 +02:00
parent 327371151a
commit fdeda9dc97
4 changed files with 487 additions and 253 deletions

View File

@@ -5,148 +5,177 @@
* in file LICENSE that is included with this distribution.
*/
#include <algorithm>
#include <pv/nttable.h>
namespace epics { namespace pvData {
using namespace std;
using namespace epics::pvData;
using std::tr1::static_pointer_cast;
namespace epics { namespace nt {
bool NTTable::isNTTable(PVStructurePtr const & pvStructure)
namespace detail {
static NTFieldPtr ntField = NTField::get();
NTTableBuilder::shared_pointer NTTableBuilder::add(
std::string const & name, epics::pvData::ScalarType scalarType
)
{
NTFieldPtr ntfield = NTField::get();
PVStringArrayPtr pvLabel = static_pointer_cast<PVStringArray>
(pvStructure->getScalarArrayField("label",pvString));
if(pvLabel.get()==NULL) return false;
size_t nfields = pvLabel->getLength();
size_t nextra = 1; // label is 1 field
PVFieldPtr pvField = pvStructure->getSubField("function");
if(pvField.get()!=NULL
&& pvStructure->getStringField("function").get()!=NULL) nextra++;
pvField = pvStructure->getSubField("timeStamp");
if(pvField!=0 && ntfield->isTimeStamp(pvField->getField())) {
nextra++;
}
pvField = pvStructure->getSubField("alarm");
if(pvField.get()!=NULL && ntfield->isAlarm(pvField->getField())) {
nextra++;
}
if(nfields!=(pvStructure->getStructure()->getNumberFields()-nextra)) {
if (std::find(labels.begin(), labels.end(), name) != labels.end())
throw std::runtime_error("duplicate column name");
labels.push_back(name);
types.push_back(scalarType);
return shared_from_this();
}
StructureConstPtr NTTableBuilder::createStructure()
{
FieldBuilderPtr builder = getFieldCreate()->createFieldBuilder();
FieldBuilderPtr nestedBuilder =
builder->
setId(NTTable::URI)->
addArray("labels", pvString)->
addNestedStructure("value");
vector<string>::size_type len = labels.size();
for (vector<string>::size_type i = 0; i < len; i++)
nestedBuilder->addArray(labels[i], types[i]);
builder = nestedBuilder->endNested();
if (descriptor)
builder->add("descriptor", pvString);
if (alarm)
builder->add("alarm", ntField->createAlarm());
if (timeStamp)
builder->add("timeStamp", ntField->createTimeStamp());
StructureConstPtr s = builder->createStructure();
reset();
return s;
}
NTTableBuilder::shared_pointer NTTableBuilder::addDescriptor()
{
descriptor = true;
return shared_from_this();
}
NTTableBuilder::shared_pointer NTTableBuilder::addAlarm()
{
alarm = true;
return shared_from_this();
}
NTTableBuilder::shared_pointer NTTableBuilder::addTimeStamp()
{
timeStamp = true;
return shared_from_this();
}
PVStructurePtr NTTableBuilder::createPVStructure()
{
PVStringArray::svector l;
l.resize(labels.size());
std::copy(labels.begin(), labels.end(), l.begin());
PVStructurePtr s = getPVDataCreate()->createPVStructure(createStructure());
s->getSubField<PVStringArray>("labels")->replace(freeze(l));
return s;
}
NTTablePtr NTTableBuilder::create()
{
return NTTablePtr(new NTTable(createPVStructure()));
}
NTTableBuilder::NTTableBuilder()
{
reset();
}
void NTTableBuilder::reset()
{
labels.clear();
types.clear();
descriptor = false;
alarm = false;
timeStamp = false;
}
}
const std::string NTTable::URI("uri:ev4:nt/2012/pwd:NTTable");
bool NTTable::is_a(StructureConstPtr const & structure)
{
return structure->getID() == URI;
}
NTTableBuilderPtr NTTable::createBuilder()
{
return NTTableBuilderPtr(new detail::NTTableBuilder());
}
bool NTTable::attachTimeStamp(PVTimeStamp &pvTimeStamp) const
{
PVStructurePtr ts = getTimeStamp();
if (ts)
return pvTimeStamp.attach(ts);
else
return false;
}
FieldConstPtrArray fields = pvStructure->getStructure()->getFields();
for(size_t i=0; i<nfields; i++) {
FieldConstPtr field = fields[i+nextra];
Type type = field->getType();
if(type!=scalarArray && type!=structureArray) return false;
}
return true;
}
NTTablePtr NTTable::create(
bool hasFunction,bool hasTimeStamp, bool hasAlarm,
shared_vector<std::string> const & valueNames,
FieldConstPtrArray const &valueFields)
bool NTTable::attachAlarm(PVAlarm &pvAlarm) const
{
StandardFieldPtr standardField = getStandardField();
size_t nfields = 1;
if(hasFunction) nfields++;
if(hasTimeStamp) nfields++;
if(hasAlarm) nfields++;
nfields += valueFields.size();
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
FieldConstPtrArray fields(nfields);
StringArray names(nfields);
size_t ind = 0;
if(hasFunction) {
names[ind] = "function";
fields[ind++] = fieldCreate->createScalar(pvString);
}
if(hasTimeStamp) {
names[ind] = "timeStamp";
fields[ind++] = standardField->timeStamp();
}
if(hasAlarm) {
names[ind] = "alarm";
fields[ind++] = standardField->alarm();
}
names[ind] = "label";
fields[ind++] = fieldCreate->createScalarArray(pvString);
size_t numberValues = valueNames.size();
for(size_t i=0; i<numberValues ; i++) {
names[ind] = valueNames[i];
fields[ind++] = valueFields[i];
}
StructureConstPtr st = fieldCreate->createStructure(names,fields);
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(st);
PVStringArrayPtr pvLabel = static_pointer_cast<PVStringArray>
(pvStructure->getScalarArrayField("label",pvString));
shared_vector<std::string> xxx(numberValues);
for(size_t i=0; i<numberValues; ++i) xxx[i] = valueNames[i];
shared_vector<const std::string> data(freeze(xxx));
pvLabel->replace(data);
return NTTablePtr(new NTTable(pvStructure));
PVStructurePtr al = getAlarm();
if (al)
return pvAlarm.attach(al);
else
return false;
}
NTTablePtr NTTable::clone(PVStructurePtr const & pv)
PVStructurePtr NTTable::getPVStructure() const
{
PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(pv);
return NTTablePtr(new NTTable(pvStructure));
return pvNTTable;
}
NTTable::NTTable(PVStructurePtr const & pvStructure)
: pvNTTable(pvStructure),
offsetFields(1)
PVStringPtr NTTable::getDescriptor() const
{
NTFieldPtr ntfield = NTField::get();
PVScalarArrayPtr pvScalarArray
= pvStructure->getScalarArrayField("label",pvString);
pvLabel = static_pointer_cast<PVStringArray>(pvScalarArray);
PVFieldPtr pvField = pvStructure->getSubField("function");
if(pvField.get()!=NULL) {
offsetFields++;
pvFunction = pvStructure->getStringField("function");
}
pvField = pvStructure->getSubField("timeStamp");
if(pvField.get()!=NULL && ntfield->isTimeStamp(pvField->getField())) {
offsetFields++;
pvTimeStamp = static_pointer_cast<PVStructure>(pvField);
}
pvField = pvStructure->getSubField("alarm");
if(pvField.get()!=NULL && ntfield->isAlarm(pvField->getField())) {
offsetFields++;
pvAlarm = static_pointer_cast<PVStructure>(pvField);
}
return pvNTTable->getSubField<PVString>("descriptor");
}
void NTTable::attachTimeStamp(PVTimeStamp &pv)
PVStructurePtr NTTable::getTimeStamp() const
{
if(pvTimeStamp.get()==NULL) return;
pv.attach(pvTimeStamp);
return pvNTTable->getSubField<PVStructure>("timeStamp");
}
void NTTable::attachAlarm(PVAlarm &pv)
PVStructurePtr NTTable::getAlarm() const
{
if(pvAlarm.get()==NULL) return;
pv.attach(pvAlarm);
return pvNTTable->getSubField<PVStructure>("alarm");
}
size_t NTTable::getNumberValues()
PVStringArrayPtr NTTable::getLabels() const
{
return pvLabel->getLength();
return pvNTTable->getSubField<PVStringArray>("labels");
}
FieldConstPtr NTTable::getField(size_t index)
PVFieldPtr NTTable::getColumn(std::string const & columnName) const
{
FieldConstPtrArray fields = pvNTTable->getStructure()->getFields();
return fields[index + offsetFields];
return pvNTTable->getSubField("value." + columnName);
}
PVFieldPtr NTTable::getPVField(size_t index)
{
PVFieldPtrArray pvFields = pvNTTable->getPVFields();
return pvFields[index+offsetFields];
}
NTTable::NTTable(PVStructurePtr const & pvStructure) :
pvNTTable(pvStructure)
{}
}}

View File

@@ -9,107 +9,197 @@
#include <pv/ntfield.h>
namespace epics { namespace pvData {
#include <vector>
#include <string>
/**
* Convenience Class for NTTable
* @author mrk
*
*/
namespace epics { namespace nt {
class NTTable;
typedef std::tr1::shared_ptr<NTTable> NTTablePtr;
namespace detail {
/**
* Interface for in-line creating of NTTable.
* One instance can be used to create multiple instances.
* An instance of this object must not be used concurrently (an object has a state).
* @author mse
*/
class epicsShareClass NTTableBuilder :
public std::tr1::enable_shared_from_this<NTTableBuilder>
{
public:
POINTER_DEFINITIONS(NTTableBuilder);
/**
* Add a column of given {@code Scalar} type.
* @param name name of the column.
* @param scalarType column type, a scalar array.
* @return this instance of a {@code NTTableBuilder}.
*/
shared_pointer add(std::string const & name, epics::pvData::ScalarType scalarType);
/**
* Add descriptor field to the NTTable.
* @return this instance of a {@code NTTableBuilder}.
*/
shared_pointer addDescriptor();
/**
* Add alarm structure to the NTTable.
* @return this instance of a {@code NTTableBuilder}.
*/
shared_pointer addAlarm();
/**
* Add timeStamp structure to the NTTable.
* @return this instance of a {@code NTTableBuilder}.
*/
shared_pointer addTimeStamp();
/**
* Create a {@code Structure} that represents NTTable.
* This resets this instance state and allows new instance to be created.
* @return a new instance of a {@code Structure}.
*/
epics::pvData::StructureConstPtr createStructure();
/**
* Create a {@code PVStructure} that represents NTTable.
* This resets this instance state and allows new {@code instance to be created.
* @return a new instance of a {@code PVStructure}
*/
epics::pvData::PVStructurePtr createPVStructure();
/**
* Create a {@code NTTable} instance.
* This resets this instance state and allows new {@code instance to be created.
* @return a new instance of a {@code NTTable}
*/
NTTablePtr create();
private:
NTTableBuilder();
void reset();
std::vector<std::string> labels;
std::vector<epics::pvData::ScalarType> types;
bool descriptor;
bool alarm;
bool timeStamp;
friend class ::epics::nt::NTTable;
};
}
typedef std::tr1::shared_ptr<detail::NTTableBuilder> NTTableBuilderPtr;
/**
* Convenience Class for NTTable
* @author mrk
*/
class NTTable
{
public:
POINTER_DEFINITIONS(NTTable);
static const std::string URI;
/**
* Is the pvStructure an NTTable.
* @param pvStructure The pvStructure to test.
* @return (false,true) if (is not, is) an NTNameValuePair.
* Is the structure an NTTable.
* @param structure The structure to test.
* @return (false,true) if (is not, is) an NTTable.
*/
static bool isNTTable(PVStructurePtr const &pvStructure);
static bool is_a(epics::pvData::StructureConstPtr const & structure);
/**
* Create an NTTable pvStructure.
* @param hasFunction Create a PVString field named function.
* @param hasTimeStamp Create a timeStamp structure field.
* @param hasAlarm Create an alarm structure field.
* @param numberValues The number of fields that follow the label field.
* @param valueFields The fields that follow the label field.
* @return an NTTablePtr
* Create a NTTable builder instance.
* @return builder instance.
*/
static NTTablePtr create(
bool hasFunction,bool hasTimeStamp, bool hasAlarm,
shared_vector<std::string> const & valueNames,
FieldConstPtrArray const &valueFields);
static NTTablePtr clone(PVStructurePtr const &);
static NTTableBuilderPtr createBuilder();
/**
* Destructor
* Destructor.
*/
~NTTable() {}
/**
* Get the function field.
* @return The pvString or null if no function field.
*/
PVStringPtr getFunction() {return pvFunction;}
/**
* Attach a pvTimeStamp.
* @param pvTimeStamp The pvTimeStamp that will be attached.
* Does nothing if no timeStamp
* Does nothing if no timeStamp.
* @return true if the operation was successfull (i.e. this instance has a timeStamp field), otherwise false.
*/
void attachTimeStamp(PVTimeStamp &pvTimeStamp);
bool attachTimeStamp(epics::pvData::PVTimeStamp &pvTimeStamp) const;
/**
* Attach an pvAlarm.
* @param pvAlarm The pvAlarm that will be attached.
* Does nothing if no alarm
* Does nothing if no alarm.
* @return true if the operation was successfull (i.e. this instance has a timeStamp field), otherwise false.
*/
void attachAlarm(PVAlarm &pvAlarm);
bool attachAlarm(epics::pvData::PVAlarm &pvAlarm) const;
/**
* Get the pvStructure.
* @return PVStructurePtr.
*/
PVStructurePtr getPVStructure(){return pvNTTable;}
epics::pvData::PVStructurePtr getPVStructure() const;
/**
* Get the descriptor field.
* @return The pvString or null if no function field.
*/
epics::pvData::PVStringPtr getDescriptor() const;
/**
* Get the timeStamp.
* @return PVStructurePtr which may be null.
*/
PVStructurePtr getTimeStamp(){return pvTimeStamp;}
epics::pvData::PVStructurePtr getTimeStamp() const;
/**
* Get the alarm.
* @return PVStructurePtr which may be null.
*/
PVStructurePtr getAlarm() {return pvAlarm;}
epics::pvData::PVStructurePtr getAlarm() const;
/**
* Get the label field.
* @return The pvStringArray for the label.
* Get the labels field.
* @return The pvStringArray for the labels.
*/
PVStringArrayPtr getLabel() {return pvLabel;}
epics::pvData::PVStringArrayPtr getLabels() const;
/**
* Get the the number of fields that follow the label field.
* @return The number of fields.
*/
size_t getNumberValues();
/**
* Get the Field for a field that follows the label field.
* @param index The index of the field desired.
* @return The FieldConstPtr for the field.
*/
FieldConstPtr getField(size_t index);
/**
* Get the PVField for a field that follows the label field.
* @param index The index of the field desired.
* Get the PVField (column) for a field that follows the label field.
* @param columnName The name of the column.
* @return The PVFieldPtr for the field.
*/
PVFieldPtr getPVField(size_t index);
epics::pvData::PVFieldPtr getColumn(std::string const & columnName) const;
/**
* Get the PVField (column) for a field that follows the label field of a specified type (e.g. PVDoubleArray).
* @param columnName The name of the column.
* @return The <PVT> field.
*/
template<typename PVT>
std::tr1::shared_ptr<PVT> getColumn(std::string const & columnName) const
{
epics::pvData::PVFieldPtr pvField = getColumn(columnName);
if (pvField.get())
return std::tr1::dynamic_pointer_cast<PVT>(pvField);
else
return std::tr1::shared_ptr<PVT>();
}
private:
NTTable(PVStructurePtr const & pvStructure);
PVStructurePtr pvNTTable;
PVStringPtr pvFunction;
PVStructurePtr pvTimeStamp;
PVStructurePtr pvAlarm;
PVStringArrayPtr pvLabel;
size_t offsetFields;
NTTable(epics::pvData::PVStructurePtr const & pvStructure);
epics::pvData::PVStructurePtr pvNTTable;
friend class detail::NTTableBuilder;
};
}}