From 1e6fb17e92c5c46645bc698ab6bfe0bd0b2b5446 Mon Sep 17 00:00:00 2001 From: Dave Hickin Date: Fri, 21 Aug 2015 06:47:52 +0100 Subject: [PATCH] Add NTURI --- src/Makefile | 2 + src/nt/nt.h | 1 + src/nt/nturi.cpp | 216 +++++++++++++++++++++++++++++++++++ src/nt/nturi.h | 287 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 506 insertions(+) create mode 100644 src/nt/nturi.cpp create mode 100644 src/nt/nturi.h diff --git a/src/Makefile b/src/Makefile index 8b6b64b..4f01a81 100644 --- a/src/Makefile +++ b/src/Makefile @@ -22,6 +22,7 @@ INC += ntaggregate.h INC += ntattribute.h INC += ntcontinuum.h INC += nthistogram.h +INC += nturi.h LIBSRCS += ntutils.cpp LIBSRCS += ntfield.cpp @@ -39,6 +40,7 @@ LIBSRCS += ntaggregate.cpp LIBSRCS += ntattribute.cpp LIBSRCS += ntcontinuum.cpp LIBSRCS += nthistogram.cpp +LIBSRCS += nturi.cpp LIBRARY = nt diff --git a/src/nt/nt.h b/src/nt/nt.h index b70ee27..8bf7ef0 100644 --- a/src/nt/nt.h +++ b/src/nt/nt.h @@ -25,6 +25,7 @@ #include #include #include +#include #endif /* NT_H */ diff --git a/src/nt/nturi.cpp b/src/nt/nturi.cpp new file mode 100644 index 0000000..e99f409 --- /dev/null +++ b/src/nt/nturi.cpp @@ -0,0 +1,216 @@ +/* nturi.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#include + +#define epicsExportSharedSymbols +#include +#include + +using namespace std; +using namespace epics::pvData; + +namespace epics { namespace nt { + +static NTFieldPtr ntField = NTField::get(); + +namespace detail { + + +NTURIBuilder::shared_pointer NTURIBuilder::addQueryString(std::string const & name) +{ + if (std::find(queryFieldNames.begin(), queryFieldNames.end(), name) != queryFieldNames.end()) + throw std::runtime_error("duplicate query field name"); + + queryFieldNames.push_back(name); + queryTypes.push_back(pvString); + + return shared_from_this(); +} + +NTURIBuilder::shared_pointer NTURIBuilder::addQueryDouble(std::string const & name) +{ + if (std::find(queryFieldNames.begin(), queryFieldNames.end(), name) != queryFieldNames.end()) + throw std::runtime_error("duplicate query field name"); + + queryFieldNames.push_back(name); + queryTypes.push_back(pvDouble); + + return shared_from_this(); +} + +NTURIBuilder::shared_pointer NTURIBuilder::addQueryInt(std::string const & name) +{ + if (std::find(queryFieldNames.begin(), queryFieldNames.end(), name) != queryFieldNames.end()) + throw std::runtime_error("duplicate query field name"); + + queryFieldNames.push_back(name); + queryTypes.push_back(pvInt); + + return shared_from_this(); +} + +StructureConstPtr NTURIBuilder::createStructure() +{ + FieldBuilderPtr builder = getFieldCreate()-> + createFieldBuilder()-> + setId(NTURI::URI)-> + add("scheme", pvString); + + if (authority) + builder->add("authority", pvString); + + builder->add("path", pvString); + + if (!queryFieldNames.empty()) + { + FieldBuilderPtr nestedBuilder = builder-> + addNestedStructure("query"); + + vector::size_type len = queryFieldNames.size(); + for (vector::size_type i = 0; i < len; i++) + nestedBuilder->add(queryFieldNames[i], queryTypes[i]); + + builder = nestedBuilder->endNested(); + } + + size_t extraCount = extraFieldNames.size(); + for (size_t i = 0; i< extraCount; i++) + builder->add(extraFieldNames[i], extraFields[i]); + + StructureConstPtr s = builder->createStructure(); + + reset(); + return s; +} + +NTURIBuilder::shared_pointer NTURIBuilder::addAuthority() +{ + authority = true; + return shared_from_this(); +} + +PVStructurePtr NTURIBuilder::createPVStructure() +{ + return getPVDataCreate()->createPVStructure(createStructure()); +} + +NTURIPtr NTURIBuilder::create() +{ + return NTURIPtr(new NTURI(createPVStructure())); +} + +NTURIBuilder::NTURIBuilder() +{ + reset(); +} + +void NTURIBuilder::reset() +{ + queryFieldNames.clear(); + queryTypes.clear(); + authority = false; +} + +NTURIBuilder::shared_pointer NTURIBuilder::add(string const & name, FieldConstPtr const & field) +{ + extraFields.push_back(field); + extraFieldNames.push_back(name); + return shared_from_this(); +} + +} + +const std::string NTURI::URI("epics:nt/NTURI:1.0"); + +NTURI::shared_pointer NTURI::wrap(PVStructurePtr const & structure) +{ + if(!isCompatible(structure)) return shared_pointer(); + return wrapUnsafe(structure); +} + +NTURI::shared_pointer NTURI::wrapUnsafe(PVStructurePtr const & structure) +{ + return shared_pointer(new NTURI(structure)); +} + +bool NTURI::is_a(StructureConstPtr const & structure) +{ + return NTUtils::is_a(structure->getID(), URI); +} + +bool NTURI::isCompatible(PVStructurePtr const & pvStructure) +{ + if(!pvStructure) return false; + + PVStringPtr pvScheme = pvStructure->getSubField("scheme"); + if(!pvScheme) return false; + + PVStringPtr pvPath = pvStructure->getSubField("path"); + if(!pvPath) return false; + + PVFieldPtr pvAuthority = pvStructure->getSubField("authority"); + PVStringPtr pvAuthority2 = pvStructure->getSubField("authority"); + if(!pvAuthority && pvAuthority2) return false; + + PVFieldPtr pvQuery = pvStructure->getSubField("query"); + PVStructurePtr pvQuery2 = pvStructure->getSubField("query"); + if(!pvAuthority && pvAuthority2) return false; + + //TODO check query field types + + return true; +} + +NTURIBuilderPtr NTURI::createBuilder() +{ + return NTURIBuilderPtr(new detail::NTURIBuilder()); +} + + +PVStructurePtr NTURI::getPVStructure() const +{ + return pvNTURI; +} + + +PVStringPtr NTURI::getScheme() const +{ + return pvNTURI->getSubField("scheme"); +} + +PVStringPtr NTURI::getAuthority() const +{ + return pvNTURI->getSubField("authority"); +} + +PVStringPtr NTURI::getPath() const +{ + return pvNTURI->getSubField("path"); +} + +PVStructurePtr NTURI::getQuery() const +{ + return pvNTURI->getSubField("query"); +} + +StringArray const & NTURI::getQueryNames() const +{ + return pvNTURI->getSubField("query")->getStructure()->getFieldNames(); +} + +PVFieldPtr NTURI::getQueryField(std::string const & name) const +{ + return pvNTURI->getSubField("query." + name); +} + +NTURI::NTURI(PVStructurePtr const & pvStructure) : + pvNTURI(pvStructure) +{} + + +}} diff --git a/src/nt/nturi.h b/src/nt/nturi.h new file mode 100644 index 0000000..20f51f5 --- /dev/null +++ b/src/nt/nturi.h @@ -0,0 +1,287 @@ +/* nturi.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +#ifndef NTURI_H +#define NTURI_H + +#include +#include + +#ifdef epicsExportSharedSymbols +# define nturiEpicsExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + +#ifdef nturiEpicsExportSharedSymbols +# define epicsExportSharedSymbols +# undef nturiEpicsExportSharedSymbols +#endif + +#include + +#include + +namespace epics { namespace nt { + +class NTURI; +typedef std::tr1::shared_ptr NTURIPtr; + +namespace detail { + + /** + * @brief Interface for in-line creating of NTURI. + * + * 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 dgh + */ + class epicsShareClass NTURIBuilder : + public std::tr1::enable_shared_from_this + { + public: + POINTER_DEFINITIONS(NTURIBuilder); + + /** + * Add authority field to the NTURI. + * @return this instance of NTURIBuilder. + */ + shared_pointer addAuthority(); + + /** + * Add extra Scalar of ScalarType pvString + * to the query field of the type. + * @param name name of the field. + * @return this instance of NTURIBuilder. + */ + shared_pointer addQueryString(std::string const & name); + + /** + * Add extra Scalar of ScalarType pvDouble + * to the query field of the type. + * @param name name of the field. + * @return this instance of NTURIBuilder. + */ + shared_pointer addQueryDouble(std::string const & name); + + /** + * Add extra Scalar of ScalarType pvInt + * to the query field of the type. + * @param name name of the field. + * @return this instance of NTURIBuilder. + */ + shared_pointer addQueryInt(std::string const & name); + + /** + * Add a column of given Scalar type. + * @param name name of the column. + * @param elementType column type, a scalar array. + * @return this instance of NTURIBuilder. + */ + //shared_pointer addColumn(std::string const & name, epics::pvData::ScalarType elememtType); + + /** + * Create a Structure that represents NTURI. + * This resets this instance state and allows new instance to be created. + * @return a new instance of Structure. + */ + epics::pvData::StructureConstPtr createStructure(); + + /** + * Create a PVStructure that represents NTURI. + * The returned PVStructure will have labels equal to the column names. + * This resets this instance state and allows new instance to be created. + * @return a new instance of PVStructure. + */ + epics::pvData::PVStructurePtr createPVStructure(); + + /** + * Create a NTURI instance. + * The returned NTURI will wrap a PVStructure which will have + * labels equal to the column names. + * This resets this instance state and allows new instance to be created. + * @return a new instance of NTURI. + */ + NTURIPtr create(); + /** + * Add extra Field to the type. + * @param name name of the field. + * @param field a field to add. + * @return this instance of NTURIBuilder. + */ + shared_pointer add(std::string const & name, epics::pvData::FieldConstPtr const & field); + + private: + NTURIBuilder(); + + void reset(); + + std::vector queryFieldNames; + std::vector queryTypes; + + bool authority; + + // NOTE: this preserves order, however it does not handle duplicates + epics::pvData::StringArray extraFieldNames; + epics::pvData::FieldConstPtrArray extraFields; + + friend class ::epics::nt::NTURI; + }; + +} + +typedef std::tr1::shared_ptr NTURIBuilderPtr; + + + +/** + * @brief Convenience Class for NTURI + * + * @author dgh + */ +class epicsShareClass NTURI +{ +public: + POINTER_DEFINITIONS(NTURI); + + static const std::string URI; + + /** + * Wrap (aka dynamic cast, or wrap) the structure to NTURI. + * First isCompatible is called. + * This method will nullptr if the structure is is not compatible. + * This method will nullptr if the structure is nullptr. + * @param structure The structure to wrap-ed (dynamic cast, wrapped) to NTURI. + * @return NTURI instance on success, nullptr otherwise. + */ + static shared_pointer wrap(epics::pvData::PVStructurePtr const & structure); + + /** + * Wrap (aka dynamic cast, or wrap) the structure to NTMultiChannel without checking for isCompatible + * @param structure The structure to wrap-ed (dynamic cast, wrapped) to NTURI. + * @return NTURI instance. + */ + static shared_pointer wrapUnsafe(epics::pvData::PVStructurePtr const & structure); + + /** + * Is the structure an NTURI. + * @param structure The structure to test. + * @return (false,true) if (is not, is) an NTURI. + */ + static bool is_a(epics::pvData::StructureConstPtr const & structure); + + /** + * Is the structure an NTURI. + * @param pvStructure The PVStructure to test. + * @return (false,true) if (is not, is) an NTURI. + */ + static bool is_a(epics::pvData::PVStructurePtr const & pvStructure); + + /** + * Is the Structure compatible with NTURI. + * This method introspects the fields to see if they are compatible. + * @param structure The Structure to test. + * @return (false,true) if (is not, is) an NTURI. + */ + static bool isCompatible( + epics::pvData::StructureConstPtr const &structure); + + /** + * Is the PVStructure compatible with NTURI. + * This method introspects the fields to see if they are compatible. + * @param pvStructure The PVStructure to test. + * @return (false,true) if (is not, is) an NTURI. + */ + static bool isCompatible( + epics::pvData::PVStructurePtr const &pvStructure); + + /** + * Checks if the specified structure is a valid NTURI. + * + * Checks whether the wrapped structure is valid with respect to this + * version of NTURI + * @return (false,true) if (is not, is) a valid NTURI. + */ + bool isValid(); + + /** + * Create a NTURI builder instance. + * @return builder instance. + */ + static NTURIBuilderPtr createBuilder(); + + /** + * Destructor. + */ + ~NTURI() {} + + /** + * Get the pvStructure. + * @return PVStructurePtr. + */ + epics::pvData::PVStructurePtr getPVStructure() const; + + /** + * Get the scheme field. + * @return The PVString for the scheme. + */ + epics::pvData::PVStringPtr getScheme() const; + + /** + * Get the authority field. + * @return The PVString for the authority. + */ + epics::pvData::PVStringPtr getAuthority() const; + + /** + * Get the path field. + * @return The PVString for the path. + */ + epics::pvData::PVStringPtr getPath() const; + + /** + * Get the query field. + * @return The PVStructure for the query. + */ + epics::pvData::PVStructurePtr getQuery() const; + + /** + * Get the names of the query fields for the URI. + * For each name, calling getQueryField should return + * the query field, which should not be null. + * @return The query field names. + */ + epics::pvData::StringArray const & getQueryNames() const; + + /** + * 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. + */ + epics::pvData::PVFieldPtr getQueryField(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 field. + */ + template + std::tr1::shared_ptr getQueryField(std::string const & columnName) const + { + epics::pvData::PVFieldPtr pvField = getQueryField(columnName); + if (pvField.get()) + return std::tr1::dynamic_pointer_cast(pvField); + else + return std::tr1::shared_ptr(); + } + +private: + NTURI(epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVStructurePtr pvNTURI; + friend class detail::NTURIBuilder; +}; + +}} +#endif /* NTURI_H */