From 072113ab4a4b80e4aea97f43388ee4cc4de569bb Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Thu, 21 Aug 2014 10:27:09 -0400 Subject: [PATCH] change to implement builder --- src/nt/ntmultiChannel.cpp | 182 ++++++++++++++++++++++----------- src/nt/ntmultiChannel.h | 160 ++++++++++++++++++++++++++--- test/nt/ntmultiChannelTest.cpp | 53 ++++++++-- 3 files changed, 310 insertions(+), 85 deletions(-) diff --git a/src/nt/ntmultiChannel.cpp b/src/nt/ntmultiChannel.cpp index cf2efc4..3e5a9cb 100644 --- a/src/nt/ntmultiChannel.cpp +++ b/src/nt/ntmultiChannel.cpp @@ -6,121 +6,181 @@ */ #include +#include + +using namespace std; +using namespace epics::pvData; namespace epics { namespace nt { -using namespace epics::pvData; -using std::tr1::static_pointer_cast; -using std::string; -using std::cout; -using std::endl; static FieldCreatePtr fieldCreate = getFieldCreate(); static PVDataCreatePtr pvDataCreate = getPVDataCreate(); -bool NTMultiChannel::isNTMultiChannel(PVStructurePtr const & pvStructure) +namespace detail { + +static NTFieldPtr ntField = NTField::get(); + +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addValue(UnionConstPtr valuePtr) { - PVUnionArrayPtr pvValue = pvStructure->getSubField("value"); - if(!pvValue) return false; - PVStringArrayPtr pvChannelName = - pvStructure->getSubField("channelName"); - return true; + value = true; + valueUnion = valuePtr; + return shared_from_this(); } -NTMultiChannelPtr NTMultiChannel::create( - std::vector const & optionNames) + +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addDescriptor() { - return NTMultiChannel::create(optionNames,fieldCreate->createVariantUnion()); + descriptor = true; + return shared_from_this(); } -NTMultiChannelPtr NTMultiChannel::create( - std::vector const & optionNames, - epics::pvData::UnionConstPtr const & unionPtr) +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addAlarm() { - shared_vector channelNames; - return NTMultiChannel::create(optionNames,unionPtr,channelNames); + alarm = true; + return shared_from_this(); } -NTMultiChannelPtr NTMultiChannel::create( - std::vector const & optionNames, - UnionConstPtr const & unionPtr, - shared_vector channelNames) +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addTimeStamp() +{ + timeStamp = true; + return shared_from_this(); +} + +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addSeverity() +{ + severity = true; + return shared_from_this(); +} + +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addStatus() +{ + status = true; + return shared_from_this(); +} + +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addMessage() +{ + message = true; + return shared_from_this(); +} + +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addSecondsPastEpoch() +{ + secondsPastEpoch = true; + return shared_from_this(); +} + +NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addNanoseconds() +{ + nanoseconds = true; + return shared_from_this(); +} + +StructureConstPtr NTMultiChannelBuilder::createStructure() { StandardFieldPtr standardField = getStandardField(); size_t nfields = 2; - bool hasAlarm = false; - bool hasTimeStamp = false; - bool hasSeverity = false; - bool hasStatus = false; - bool hasMessage = false; - bool hasSecondsPastEpoch = false; - bool hasNanoseconds = false; - bool hasDescriptor = false; - for(size_t i=0; icreateUnionArray(unionPtr); + if(value) { + fields[ind++] = fieldCreate->createUnionArray(valueUnion); + } else { + fields[ind++] = fieldCreate->createVariantUnion(); + } names[ind] = "channelName"; fields[ind++] = fieldCreate->createScalarArray(pvString); - if(hasTimeStamp) { + if(timeStamp) { names[ind] = "timeStamp"; fields[ind++] = standardField->timeStamp(); } - if(hasAlarm) { + if(alarm) { names[ind] = "alarm"; fields[ind++] = standardField->alarm(); } - if(hasDescriptor) { + if(descriptor) { names[ind] = "descriptor"; fields[ind++] = fieldCreate->createScalar(pvString); } - if(hasSeverity) { + if(severity) { names[ind] = "severity"; fields[ind++] = fieldCreate->createScalarArray(pvInt); } - if(hasStatus) { + if(status) { names[ind] = "status"; fields[ind++] = fieldCreate->createScalarArray(pvInt); } - if(hasMessage) { + if(message) { names[ind] = "message"; fields[ind++] = fieldCreate->createScalarArray(pvString); } - if(hasSecondsPastEpoch) { + if(secondsPastEpoch) { names[ind] = "secondsPastEpoch"; fields[ind++] = fieldCreate->createScalarArray(pvLong); } - if(hasNanoseconds) { + if(nanoseconds) { names[ind] = "nanoseconds"; fields[ind++] = fieldCreate->createScalarArray(pvInt); } - StructureConstPtr st = fieldCreate->createStructure(names,fields); - PVStructurePtr pvStructure = pvDataCreate->createPVStructure(st); - if(channelNames.size()>0) { - PVStringArrayPtr pvName = pvStructure->getSubField("channelName"); - pvName->replace(channelNames); - } - return NTMultiChannelPtr(new NTMultiChannel(pvStructure)); + StructureConstPtr st = fieldCreate->createStructure(NTMultiChannel::URI,names,fields); + reset(); + return st; } -NTMultiChannelPtr NTMultiChannel::clone(PVStructurePtr const & pv) +PVStructurePtr NTMultiChannelBuilder::NTMultiChannelBuilder::createPVStructure() { - PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(pv); - return NTMultiChannelPtr(new NTMultiChannel(pvStructure)); + return pvDataCreate->createPVStructure(createStructure()); } +NTMultiChannelPtr NTMultiChannelBuilder::create() +{ + return NTMultiChannelPtr(new NTMultiChannel(createPVStructure())); +} + +NTMultiChannelBuilder::NTMultiChannelBuilder() +{ + reset(); +} + +void NTMultiChannelBuilder::reset() +{ + valueUnion.reset(); + value = false; + descriptor = false; + alarm = false; + timeStamp = false; + severity = false; + status = false; + message = false; + secondsPastEpoch = false; + nanoseconds = false; +} + +} + +const std::string NTMultiChannel::URI("uri:ev4:nt/2012/pwd:NTMultiChannel"); + +bool NTMultiChannel::is_a(StructureConstPtr const &structure) +{ + return structure->getID() == URI; +} + +NTMultiChannelBuilderPtr NTMultiChannel::createBuilder() +{ + return NTMultiChannelBuilderPtr(new detail::NTMultiChannelBuilder()); +} + + NTMultiChannel::NTMultiChannel(PVStructurePtr const & pvStructure) : pvNTMultiChannel(pvStructure), pvTimeStamp(pvStructure->getSubField("timeStamp")), diff --git a/src/nt/ntmultiChannel.h b/src/nt/ntmultiChannel.h index fd61a54..fd274bd 100644 --- a/src/nt/ntmultiChannel.h +++ b/src/nt/ntmultiChannel.h @@ -8,6 +8,9 @@ #define NTMULTICHANNEL_H #include +#include +#include + namespace epics { namespace nt { @@ -20,27 +23,125 @@ namespace epics { namespace nt { class NTMultiChannel; typedef std::tr1::shared_ptr NTMultiChannelPtr; +namespace detail { + + /** + * Interface for in-line creating of NTMultiChannel. + * 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 NTMultiChannelBuilder : + public std::tr1::enable_shared_from_this + { + public: + POINTER_DEFINITIONS(NTMultiChannelBuilder); + /** + * specify the union for the value field. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addValue(epics::pvData::UnionConstPtr valuePtr); + /** + * Add descriptor field to the NTMultiChannel. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addDescriptor(); + /** + * Add alarm structure to the NTMultiChannel. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addAlarm(); + /** + * Add timeStamp structure to the NTMultiChannel. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addTimeStamp(); + /** + * Add severity array to the NTMultiChannel. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addSeverity(); + /** + * Add status array to the NTMultiChannel. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addStatus(); + /** + * Add message array to the NTMultiChannel. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addMessage(); + /** + * Add secondsPastEpoch array to the NTMultiChannel. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addSecondsPastEpoch(); + /** + * Add nanoseconds array to the NTMultiChannel. + * @return this instance of a {@code NTMultiChannelBuilder}. + */ + shared_pointer addNanoseconds(); + /** + * Create a {@code Structure} that represents NTMultiChannel. + * 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 NTMultiChannel. + * 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 NTMultiChannel} instance. + * This resets this instance state and allows new {@code instance to be created. + * @return a new instance of a {@code NTMultiChannel} + */ + NTMultiChannelPtr create(); + private: + NTMultiChannelBuilder(); + + void reset(); + + epics::pvData::UnionConstPtr valueUnion; + bool value; + bool descriptor; + bool alarm; + bool timeStamp; + bool severity; + bool status; + bool message; + bool secondsPastEpoch; + bool nanoseconds; + + friend class ::epics::nt::NTMultiChannel; + }; + +} + +typedef std::tr1::shared_ptr NTMultiChannelBuilderPtr; + + class NTMultiChannel { public: POINTER_DEFINITIONS(NTMultiChannel); + + static const std::string URI; /** * Is the pvStructure an NTMultiChannel. - * @param pvStructure The pvStructure to test. + * @param structure The structure to test. * @return (false,true) if (is not, is) an NTMultiChannel. */ - static bool isNTMultiChannel( - epics::pvData::PVStructurePtr const &pvStructure); - static NTMultiChannelPtr create( - std::vector const & optionNames); - static NTMultiChannelPtr create( - std::vector const & optionNames, - epics::pvData::UnionConstPtr const & unionPtr); - static NTMultiChannelPtr create( - std::vector const & optionNames, - epics::pvData::UnionConstPtr const & unionPtr, - epics::pvData::shared_vector channelNames); - static NTMultiChannelPtr clone(epics::pvData::PVStructurePtr const &); + static bool is_a( + epics::pvData::StructureConstPtr const &structure); + /** + * Create a NTMultiChannelBuilder instance + * @return builder instance. + */ + static NTMultiChannelBuilderPtr createBuilder(); + /** * Destructor */ @@ -72,13 +173,45 @@ public: * @return PVStructurePtr which may be null. */ epics::pvData::PVStructurePtr getAlarm() {return pvAlarm;} + /** + * Get the value of each channel. + * @return PVUnionArrayPtr + */ epics::pvData::PVUnionArrayPtr getValue() {return pvValue;} + /** + * Get the channelName of each channel. + * @return PVStringArrayPtr + */ epics::pvData::PVStringArrayPtr getChannelName() { return pvChannelName;}; + /** + * Get the severity of each channel. + * @return PVIntArrayPtr which may be null. + */ epics::pvData::PVIntArrayPtr getSeverity() {return pvSeverity;} + /** + * Get the status of each channel. + * @return PVIntArrayPtr which may be null. + */ epics::pvData::PVIntArrayPtr getStatus() {return pvStatus;} + /** + * Get the message of each chnnel. + * @return PVStringArrayPtr which may be null. + */ epics::pvData::PVStringArrayPtr getMessage() {return pvMessage;} + /** + * Get the SecondsPastEpoch of each channel. + * @return PVLongArrayPtr which may be null. + */ epics::pvData::PVLongArrayPtr getSecondsPastEpoch() {return pvSecondsPastEpoch;} + /** + * Get the SecondsPastEpoch of each channel. + * @return PVIntArrayPtr which may be null. + */ epics::pvData::PVIntArrayPtr getNanoseconds() {return pvNanoseconds;} + /** + * Get the descriptor. + * @return PVStringPtr which may be null. + */ epics::pvData::PVStringPtr getDescriptor() {return pvDescriptor;} private: NTMultiChannel(epics::pvData::PVStructurePtr const & pvStructure); @@ -93,6 +226,7 @@ private: epics::pvData::PVLongArrayPtr pvSecondsPastEpoch; epics::pvData::PVIntArrayPtr pvNanoseconds; epics::pvData::PVStringPtr pvDescriptor; + friend class detail::NTMultiChannelBuilder; }; }} diff --git a/test/nt/ntmultiChannelTest.cpp b/test/nt/ntmultiChannelTest.cpp index 64f4731..b6e82af 100644 --- a/test/nt/ntmultiChannelTest.cpp +++ b/test/nt/ntmultiChannelTest.cpp @@ -41,14 +41,20 @@ static PVNTFieldPtr pvntField = PVNTField::get(); static void test() { - vector optionNames(10); - optionNames[0] = "alarm"; - optionNames[1] = "timeStamp"; - optionNames[2] = "severity"; - NTMultiChannelPtr multiChannel = NTMultiChannel::create(optionNames); - testOk1(multiChannel.get()!=NULL); + NTMultiChannelBuilderPtr builder = NTMultiChannel::createBuilder(); + testOk(builder.get() != 0, "Got builder"); + + NTMultiChannelPtr multiChannel = builder-> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + addSeverity() -> + create(); + testOk1(multiChannel.get() != 0); + PVStructurePtr pvStructure = multiChannel->getPVStructure(); testOk1(pvStructure.get()!=NULL); + testOk1(NTMultiChannel::is_a(pvStructure->getStructure())); size_t nchan = 3; shared_vector names(nchan); names[0] = "channel 0"; @@ -63,21 +69,32 @@ static void test() add("doubleValue", pvDouble)-> add("intValue", pvInt)-> createUnion(); - multiChannel = NTMultiChannel::create( - optionNames,unionPtr,channelNames); - testOk1(multiChannel.get()!=NULL); + multiChannel = builder-> + addValue(unionPtr) -> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + addSeverity() -> + create(); + testOk1(multiChannel.get() != 0); pvStructure = multiChannel->getPVStructure(); if(debug) {cout << *pvStructure << endl;} + pvChannelName = multiChannel->getChannelName(); + pvChannelName->replace(channelNames); PVUnionArrayPtr pvValue = multiChannel->getValue(); - shared_vector unions(2); + shared_vector unions(nchan); unions[0] = pvDataCreate->createPVUnion(unionPtr); unions[1] = pvDataCreate->createPVUnion(unionPtr); + unions[2] = pvDataCreate->createPVUnion(unionPtr); unions[0]->select("doubleValue"); unions[1]->select("intValue"); + unions[2]->select("intValue"); PVDoublePtr pvDouble = unions[0]->get(); pvDouble->put(1.235); PVIntPtr pvInt = unions[1]->get(); pvInt->put(5); + pvInt = unions[2]->get(); + pvInt->put(7); pvValue->replace(freeze(unions)); shared_vector severities(nchan); severities[0] = 0; @@ -86,12 +103,26 @@ static void test() PVIntArrayPtr pvSeverity = multiChannel->getSeverity(); pvSeverity->replace(freeze(severities)); if(debug) {cout << *pvStructure << endl;} + multiChannel = builder-> + addValue(unionPtr) -> + addDescriptor()-> + addAlarm()-> + addTimeStamp()-> + addSeverity() -> + addStatus() -> + addMessage() -> + addSecondsPastEpoch() -> + addNanoseconds() -> + create(); + testOk1(multiChannel.get() != 0); + pvStructure = multiChannel->getPVStructure(); + if(debug) {cout << *pvStructure << endl;} } MAIN(testCreateRequest) { - testPlan(10); + testPlan(6); test(); return testDone(); }