From 97cbea6f4d2f1f2292a39442d28a52d04b29a8e8 Mon Sep 17 00:00:00 2001 From: Dave Hickin Date: Mon, 13 Jul 2015 02:16:08 +0100 Subject: [PATCH 1/6] Implement getSubField functions without using exceptions Implementation of getSubField (and getScalarArrayField) introduced in the getAs pull request throws an exception then catches it to return a null pointer. Implement without throwing. Signed-off-by: Dave Hickin --- src/factory/PVStructure.cpp | 70 ++++++++++++++++++++++--------------- src/pv/pvData.h | 2 +- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/factory/PVStructure.cpp b/src/factory/PVStructure.cpp index 5d61056..12afbb8 100644 --- a/src/factory/PVStructure.cpp +++ b/src/factory/PVStructure.cpp @@ -107,11 +107,11 @@ const PVFieldPtrArray & PVStructure::getPVFields() const PVFieldPtr PVStructure::getSubField(string const &fieldName) const { - try{ - return GetAsImpl(fieldName.c_str())->shared_from_this(); - }catch(...){ - return PVFieldPtr(); - } + PVField * field = GetAsImpl(fieldName.c_str(), false); + if (field) + return field->shared_from_this(); + else + return PVFieldPtr(); } @@ -134,21 +134,34 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const throw std::logic_error("PVStructure.getSubField: Logic error"); } -PVField* PVStructure::GetAsImpl(const char *name) const +PVField* PVStructure::GetAsImpl(const char *name, bool throws) const { const PVStructure *parent = this; if(!name) - throw std::invalid_argument("field name is NULL string"); - + { + if (throws) + throw std::invalid_argument("field name is NULL string"); + else + return NULL; + } while(true) { const char *sep=name; while(*sep!='\0' && *sep!='.' && *sep!=' ') sep++; if(*sep==' ') - throw std::runtime_error("No spaces allowed in field name"); - + { + if (throws) + throw std::runtime_error("No spaces allowed in field name "); + else + return NULL; + } size_t N = sep-name; if(N==0) - throw std::runtime_error("zero-length field name encountered"); + { + if (throws) + throw std::runtime_error("zero-length field name encountered"); + else + return NULL; + } const PVFieldPtrArray& pvFields = parent->getPVFields(); @@ -165,13 +178,23 @@ PVField* PVStructure::GetAsImpl(const char *name) const } if(!child) - throw std::runtime_error("field not found"); //TODO: which sub field? + { + if (throws) + throw std::runtime_error("field not found"); //TODO: which sub field? + else + return NULL; + } if(*sep) { // this is not the requested leaf parent = dynamic_cast(child); if(!parent) - throw std::runtime_error("mid-field is not a PVStructure"); //TODO: which sub field? + { + if (throws) + throw std::runtime_error("mid-field is not a PVStructure"); //TODO: which sub field? + else + return NULL; + } child = NULL; name = sep+1; // skip past '.' // loop around to new parent @@ -256,22 +279,13 @@ PVUnionPtr PVStructure::getUnionField(string const &fieldName) PVScalarArrayPtr PVStructure::getScalarArrayField( string const &fieldName,ScalarType elementType) { - try{ - PVFieldPtr pvField = GetAsImpl(fieldName.c_str())->shared_from_this(); - FieldConstPtr field = pvField->getField(); - Type type = field->getType(); - if(type!=scalarArray) { - return nullPVScalarArray; - } - ScalarArrayConstPtr pscalarArray - = static_pointer_cast(pvField->getField()); - if(pscalarArray->getElementType()!=elementType) { - return nullPVScalarArray; - } - return std::tr1::static_pointer_cast(pvField); - }catch(...){ + PVScalarArrayPtr arrayField = getSubField(fieldName); + if (arrayField.get() && + arrayField->getScalarArray()->getElementType()!=elementType) + { return nullPVScalarArray; - } + } + return arrayField; } PVStructureArrayPtr PVStructure::getStructureArrayField( diff --git a/src/pv/pvData.h b/src/pv/pvData.h index 7384cac..6dc27dc 100644 --- a/src/pv/pvData.h +++ b/src/pv/pvData.h @@ -712,7 +712,7 @@ public: } private: - PVField *GetAsImpl(const char *name) const; + PVField *GetAsImpl(const char *name, bool throws = true) const; public: /** From 1dba611b8e09af8e8e57702814fa06e90bf89616 Mon Sep 17 00:00:00 2001 From: Dave Hickin Date: Mon, 13 Jul 2015 11:47:21 +0100 Subject: [PATCH 2/6] Improve exception messages when getting PVStructure subfield Signed-off-by: Dave Hickin --- src/factory/PVStructure.cpp | 32 +++++++++++++++++++++++++++----- src/pv/pvData.h | 6 +++++- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/factory/PVStructure.cpp b/src/factory/PVStructure.cpp index 12afbb8..0b8fb02 100644 --- a/src/factory/PVStructure.cpp +++ b/src/factory/PVStructure.cpp @@ -140,17 +140,23 @@ PVField* PVStructure::GetAsImpl(const char *name, bool throws) const if(!name) { if (throws) - throw std::invalid_argument("field name is NULL string"); + throw std::invalid_argument("Failed to get field: (Field name is NULL string)"); else return NULL; } + const char *fullName = name; while(true) { const char *sep=name; while(*sep!='\0' && *sep!='.' && *sep!=' ') sep++; if(*sep==' ') { if (throws) - throw std::runtime_error("No spaces allowed in field name "); + { + std::stringstream ss; + ss << "Failed to get field: " << fullName + << " (No spaces allowed in field name)"; + throw std::runtime_error(ss.str()); + } else return NULL; } @@ -158,7 +164,12 @@ PVField* PVStructure::GetAsImpl(const char *name, bool throws) const if(N==0) { if (throws) - throw std::runtime_error("zero-length field name encountered"); + { + std::stringstream ss; + ss << "Failed to get field: " << fullName + << " (Zero-length field name encountered)"; + throw std::runtime_error(ss.str()); + } else return NULL; } @@ -180,7 +191,12 @@ PVField* PVStructure::GetAsImpl(const char *name, bool throws) const if(!child) { if (throws) - throw std::runtime_error("field not found"); //TODO: which sub field? + { + std::stringstream ss; + ss << "Failed to get field: " << fullName << " (" + << std::string(fullName, sep) << " not found)"; + throw std::runtime_error(ss.str()); + } else return NULL; } @@ -191,7 +207,13 @@ PVField* PVStructure::GetAsImpl(const char *name, bool throws) const if(!parent) { if (throws) - throw std::runtime_error("mid-field is not a PVStructure"); //TODO: which sub field? + { + std::stringstream ss; + ss << "Failed to get field: " << fullName + << " (" << std::string(fullName, sep) + << " is not a structure)"; + throw std::runtime_error(ss.str()); + } else return NULL; } diff --git a/src/pv/pvData.h b/src/pv/pvData.h index 6dc27dc..797cb04 100644 --- a/src/pv/pvData.h +++ b/src/pv/pvData.h @@ -729,7 +729,11 @@ public: { PVT *raw = dynamic_cast(GetAsImpl(name)); if(!raw) - throw std::runtime_error("Field has wrong type"); + { + std::stringstream ss; + ss << "Failed to get field: " << name << " (Field has wrong type)"; + throw std::runtime_error(ss.str()); + } return *raw; } From e4689dd3f89255c29f4ab18d7aa1f962ff2b715b Mon Sep 17 00:00:00 2001 From: Dave Hickin Date: Mon, 13 Jul 2015 12:07:54 +0100 Subject: [PATCH 3/6] Added unit tests for functions for getting subfields Signed-off-by: Dave Hickin --- testApp/pv/testPVData.cpp | 47 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/testApp/pv/testPVData.cpp b/testApp/pv/testPVData.cpp index 327a9c2..12b4092 100644 --- a/testApp/pv/testPVData.cpp +++ b/testApp/pv/testPVData.cpp @@ -573,6 +573,19 @@ static void testFieldAccess() // whitespace testOk1(fld->getSubField(" test").get()==NULL); + // intermediate field not structure + testOk1(fld->getSubField("hello.world.invalid").get()==NULL); + + // null string + try{ + char * name = NULL; + fld->getAs(name); + testFail("missing required exception"); + }catch(std::invalid_argument& e){ + testPass("caught expected exception: %s", e.what()); + } + + // non-existent try{ fld->getAs("invalid"); testFail("missing required exception"); @@ -580,6 +593,7 @@ static void testFieldAccess() testPass("caught expected exception: %s", e.what()); } + // wrong type try{ fld->getAs("test"); testFail("missing required exception"); @@ -587,6 +601,37 @@ static void testFieldAccess() testPass("caught expected exception: %s", e.what()); } + // empty leaf field name + try{ + fld->getAs("hello."); + testFail("missing required exception"); + }catch(std::runtime_error& e){ + testPass("caught expected exception: %s", e.what()); + } + + // empty field name + try{ + fld->getAs("hello..world"); + testFail("missing required exception"); + }catch(std::runtime_error& e){ + testPass("caught expected exception: %s", e.what()); + } + try{ + fld->getAs("."); + testFail("missing required exception"); + }catch(std::runtime_error& e){ + testPass("caught expected exception: %s", e.what()); + } + + // whitespace + try{ + fld->getAs(" test"); + testFail("missing required exception"); + }catch(std::runtime_error& e){ + testPass("caught expected exception: %s", e.what()); + } + + // intermediate field not structure try{ fld->getAs("hello.world.invalid"); testFail("missing required exception"); @@ -597,7 +642,7 @@ static void testFieldAccess() MAIN(testPVData) { - testPlan(236); + testPlan(242); fieldCreate = getFieldCreate(); pvDataCreate = getPVDataCreate(); standardField = getStandardField(); From ebe2d6196cdadc2e2fb41640e8ff29698e05adb4 Mon Sep 17 00:00:00 2001 From: Dave Hickin Date: Mon, 13 Jul 2015 12:34:15 +0100 Subject: [PATCH 4/6] Rename getAs getSubFieldT Signed-off-by: Dave Hickin --- documentation/RELEASE_NOTES.md | 6 ++--- documentation/pvDataCPP.html | 38 +++++++++++++-------------- documentation/pvDataCPP_20150623.html | 38 +++++++++++++-------------- src/factory/PVStructure.cpp | 4 +-- src/pv/pvData.h | 12 ++++----- testApp/pv/testPVData.cpp | 20 +++++++------- 6 files changed, 59 insertions(+), 59 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 61ca2d7..2076f68 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -7,7 +7,7 @@ The main changes since release 4.0 are: * Convert::copyUnion now always copies between subfields. * CreateRequest prevents a possible SEGFAULT. * New stream operators for Field and PVField are provided. -* New method getAs that is like getSubField except that it throws exception +* New method getSubFieldT that is like getSubField except that it throws exception Convert copy methods and equals operators ----------------------------------------- @@ -73,10 +73,10 @@ Now it can be done as follows: cout << pv << endl; } -New method getAs that is like getSubField except that it throws exception +New method getSubFieldT that is like getSubField except that it throws exception -------------------- -PVStructure has a new template member getAs(const char *name) +PVStructure has a new template member getSubFieldT(std::string const &fieldName) that is like getSubField except that it throws a runtime_error instead of returning null. diff --git a/documentation/pvDataCPP.html b/documentation/pvDataCPP.html index 6ea31bd..8618d59 100644 --- a/documentation/pvDataCPP.html +++ b/documentation/pvDataCPP.html @@ -465,10 +465,10 @@ structure PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure( getStandardField()->scalar(pvDouble,"alarm,timeStamp")); PVDoublePtr pvdouble = - doubleValue->getAs<PVDouble>("value"); + doubleValue->getSubField<PVDouble>("value"); pvdouble->put(1e5); cout << *doubleValue << endl; - double value = doubleValue->getAs<PVDouble>("value")->get(); + double value = doubleValue->getSubField<PVDouble>("value")->get(); cout << "from get " << value << "\n\n"; This produces: @@ -491,7 +491,7 @@ from get 100000 PVStructurePtr doubleArrayValue = pvDataCreate->createPVStructure( standardField->scalarArray(pvDouble,"alarm,timeStamp")); PVDoubleArrayPtr pvDoubleArray = - doubleArrayValue->getAs<PVDoubleArray>("value"); + doubleArrayValue->getSubField<PVDoubleArray>("value"); size_t len = 10; shared_vector<double> xxx(len); for(size_t i=0; i< len; ++i) xxx[i] = i; @@ -605,10 +605,10 @@ structure createUnion(), "alarm,timeStamp")); PVStructurePtr pvTimeStamp = - pvStructure->getAs<PVUnion>("value")->select<PVStructure>(2); - pvTimeStamp->getAs<PVLong>("secondsPastEpoch")->put(1000); + pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2); + pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000); cout << *pvStructure) << "\n"; - pvStructure->getAs<PVUnion>("value")->select<PVDouble>(0)->put(1e5); + pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5); cout << *pvStructure << "\n\n"; This produces: @@ -648,13 +648,13 @@ epics:nt/NTUnion:1.0 standardField->variantUnion("alarm,timeStamp")); PVStructurePtr pvTimeStamp = pvDataCreate->createPVStructure(standardField->timeStamp()); - pvStructure->getAs<PVUnion>("value")->set(pvTimeStamp); - pvTimeStamp->getAs<PVLong>("secondsPastEpoch")->put(1000); + pvStructure->getSubField<PVUnion>("value")->set(pvTimeStamp); + pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000); cout << *pvStructure << "\n"; - pvStructure->getAs<PVUnion>("value")->set( + pvStructure->getSubField<PVUnion>("value")->set( pvDataCreate->createPVScalar(pvDouble)); PVDoublePtr pvValue = static_pointer_cast<PVDouble>( - pvStructure->getAs<PVUnion>("value")->get()); + pvStructure->getSubField<PVUnion>("value")->get()); pvValue->put(1e5); cout << *pvStructure << "\n\n"; @@ -718,7 +718,7 @@ epics:nt/NTUnion:1.0 cout << *pvStructure->getStructure() << endl; cout << "data\n"; cout << *pvStructure << "\n"; - PVUnionPtr pvUnion = pvStructure->getAs<PVUnion>("value");; + PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");; pvUnion->select("doubleValue"); PVDoublePtr pvDouble = pvUnion->get<PVDouble>(); pvDouble->put(1.55); @@ -726,7 +726,7 @@ epics:nt/NTUnion:1.0 cout << *pvStructure << "\n"; cout << "value = " << pvDouble->get() << "\n"; pvUnion->select("structValue"); - pvDouble = pvUnion->get<PVStructure>()->getAs<PVDouble>("doubleValue"); + pvDouble = pvUnion->get<PVStructure>()->getSubField<PVDouble>("doubleValue"); pvDouble->put(1.65); cout << "select structValue\n"; cout << *pvStructure << "\n"; @@ -2304,14 +2304,14 @@ public: template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::string const &fieldName) const - template<typename PVT> - PVT& getAs(const char *name) const; - PVFieldPtr getSubField(std::size_t fieldOffset) const; template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const + template<typename PVT> + PVT& getSubFieldT(std::string const &fieldName) const; + virtual void serialize( ByteBuffer *pbuffer,SerializableControl *pflusher) const ; virtual void deserialize( @@ -2332,9 +2332,6 @@ public:
getPVFields
Returns the array of subfields. The set of subfields must all have different field names.
-
getAs(const char *name)
-
Like the getSubField except that it throws std::runtime_error if - the field does not exists or has the wrong type.
getSubField(std::string fieldName)
Get a subField of a field.d @@ -2353,6 +2350,9 @@ public:
Note The template version replaces getBooleanField, etc.
+
getSubFieldT(std::string const &fieldName)
+
Like getSubField except that it throws std::runtime_error if + the field does not exists or has the wrong type.
dumpValue
Method for streams I/O.
@@ -5414,7 +5414,7 @@ public: raiseMonitor = true; if(pvFieldOptions!=NULL) { PVStringPtr pvString = - pvFieldOptions->getAs<PVString>("raiseMonitor"); + pvFieldOptions->getSubField<PVString>("raiseMonitor"); if(pvString!=NULL) { std::string value = pvString->get(); if(value.compare("false")==0) raiseMonitor = false; diff --git a/documentation/pvDataCPP_20150623.html b/documentation/pvDataCPP_20150623.html index 6ea31bd..8618d59 100644 --- a/documentation/pvDataCPP_20150623.html +++ b/documentation/pvDataCPP_20150623.html @@ -465,10 +465,10 @@ structure PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure( getStandardField()->scalar(pvDouble,"alarm,timeStamp")); PVDoublePtr pvdouble = - doubleValue->getAs<PVDouble>("value"); + doubleValue->getSubField<PVDouble>("value"); pvdouble->put(1e5); cout << *doubleValue << endl; - double value = doubleValue->getAs<PVDouble>("value")->get(); + double value = doubleValue->getSubField<PVDouble>("value")->get(); cout << "from get " << value << "\n\n"; This produces: @@ -491,7 +491,7 @@ from get 100000 PVStructurePtr doubleArrayValue = pvDataCreate->createPVStructure( standardField->scalarArray(pvDouble,"alarm,timeStamp")); PVDoubleArrayPtr pvDoubleArray = - doubleArrayValue->getAs<PVDoubleArray>("value"); + doubleArrayValue->getSubField<PVDoubleArray>("value"); size_t len = 10; shared_vector<double> xxx(len); for(size_t i=0; i< len; ++i) xxx[i] = i; @@ -605,10 +605,10 @@ structure createUnion(), "alarm,timeStamp")); PVStructurePtr pvTimeStamp = - pvStructure->getAs<PVUnion>("value")->select<PVStructure>(2); - pvTimeStamp->getAs<PVLong>("secondsPastEpoch")->put(1000); + pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2); + pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000); cout << *pvStructure) << "\n"; - pvStructure->getAs<PVUnion>("value")->select<PVDouble>(0)->put(1e5); + pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5); cout << *pvStructure << "\n\n"; This produces: @@ -648,13 +648,13 @@ epics:nt/NTUnion:1.0 standardField->variantUnion("alarm,timeStamp")); PVStructurePtr pvTimeStamp = pvDataCreate->createPVStructure(standardField->timeStamp()); - pvStructure->getAs<PVUnion>("value")->set(pvTimeStamp); - pvTimeStamp->getAs<PVLong>("secondsPastEpoch")->put(1000); + pvStructure->getSubField<PVUnion>("value")->set(pvTimeStamp); + pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000); cout << *pvStructure << "\n"; - pvStructure->getAs<PVUnion>("value")->set( + pvStructure->getSubField<PVUnion>("value")->set( pvDataCreate->createPVScalar(pvDouble)); PVDoublePtr pvValue = static_pointer_cast<PVDouble>( - pvStructure->getAs<PVUnion>("value")->get()); + pvStructure->getSubField<PVUnion>("value")->get()); pvValue->put(1e5); cout << *pvStructure << "\n\n"; @@ -718,7 +718,7 @@ epics:nt/NTUnion:1.0 cout << *pvStructure->getStructure() << endl; cout << "data\n"; cout << *pvStructure << "\n"; - PVUnionPtr pvUnion = pvStructure->getAs<PVUnion>("value");; + PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");; pvUnion->select("doubleValue"); PVDoublePtr pvDouble = pvUnion->get<PVDouble>(); pvDouble->put(1.55); @@ -726,7 +726,7 @@ epics:nt/NTUnion:1.0 cout << *pvStructure << "\n"; cout << "value = " << pvDouble->get() << "\n"; pvUnion->select("structValue"); - pvDouble = pvUnion->get<PVStructure>()->getAs<PVDouble>("doubleValue"); + pvDouble = pvUnion->get<PVStructure>()->getSubField<PVDouble>("doubleValue"); pvDouble->put(1.65); cout << "select structValue\n"; cout << *pvStructure << "\n"; @@ -2304,14 +2304,14 @@ public: template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::string const &fieldName) const - template<typename PVT> - PVT& getAs(const char *name) const; - PVFieldPtr getSubField(std::size_t fieldOffset) const; template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const + template<typename PVT> + PVT& getSubFieldT(std::string const &fieldName) const; + virtual void serialize( ByteBuffer *pbuffer,SerializableControl *pflusher) const ; virtual void deserialize( @@ -2332,9 +2332,6 @@ public:
getPVFields
Returns the array of subfields. The set of subfields must all have different field names.
-
getAs(const char *name)
-
Like the getSubField except that it throws std::runtime_error if - the field does not exists or has the wrong type.
getSubField(std::string fieldName)
Get a subField of a field.d @@ -2353,6 +2350,9 @@ public:
Note The template version replaces getBooleanField, etc.
+
getSubFieldT(std::string const &fieldName)
+
Like getSubField except that it throws std::runtime_error if + the field does not exists or has the wrong type.
dumpValue
Method for streams I/O.
@@ -5414,7 +5414,7 @@ public: raiseMonitor = true; if(pvFieldOptions!=NULL) { PVStringPtr pvString = - pvFieldOptions->getAs<PVString>("raiseMonitor"); + pvFieldOptions->getSubField<PVString>("raiseMonitor"); if(pvString!=NULL) { std::string value = pvString->get(); if(value.compare("false")==0) raiseMonitor = false; diff --git a/src/factory/PVStructure.cpp b/src/factory/PVStructure.cpp index 0b8fb02..5319369 100644 --- a/src/factory/PVStructure.cpp +++ b/src/factory/PVStructure.cpp @@ -107,7 +107,7 @@ const PVFieldPtrArray & PVStructure::getPVFields() const PVFieldPtr PVStructure::getSubField(string const &fieldName) const { - PVField * field = GetAsImpl(fieldName.c_str(), false); + PVField * field = getSubFieldImpl(fieldName.c_str(), false); if (field) return field->shared_from_this(); else @@ -134,7 +134,7 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const throw std::logic_error("PVStructure.getSubField: Logic error"); } -PVField* PVStructure::GetAsImpl(const char *name, bool throws) const +PVField* PVStructure::getSubFieldImpl(const char *name, bool throws) const { const PVStructure *parent = this; if(!name) diff --git a/src/pv/pvData.h b/src/pv/pvData.h index 797cb04..0e0e6b2 100644 --- a/src/pv/pvData.h +++ b/src/pv/pvData.h @@ -712,7 +712,7 @@ public: } private: - PVField *GetAsImpl(const char *name, bool throws = true) const; + PVField *getSubFieldImpl(const char *name, bool throws = true) const; public: /** @@ -721,13 +721,13 @@ public: * @returns A reference to the sub-field (never NULL) * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type * @code - * PVInt& ref = pvStruct->getAs("substruct.leaffield"); + * PVInt& ref = pvStruct->getSubFieldT("substruct.leaffield"); * @endcode */ template - PVT& getAs(const char *name) const + PVT& getSubFieldT(const char *name) const { - PVT *raw = dynamic_cast(GetAsImpl(name)); + PVT *raw = dynamic_cast(getSubFieldImpl(name)); if(!raw) { std::stringstream ss; @@ -738,9 +738,9 @@ public: } template - FORCE_INLINE PVT& getAs(std::string const &fieldName) const + FORCE_INLINE PVT& getSubFieldT(std::string const &fieldName) const { - return this->getAs(fieldName.c_str()); + return this->getSubFieldT(fieldName.c_str()); } /** diff --git a/testApp/pv/testPVData.cpp b/testApp/pv/testPVData.cpp index 12b4092..747d8c6 100644 --- a/testApp/pv/testPVData.cpp +++ b/testApp/pv/testPVData.cpp @@ -541,7 +541,7 @@ static void testFieldAccess() PVIntPtr a = fld->getSubField("test"); testOk1(a!=NULL); if(a.get()) { - PVInt& b = fld->getAs("test"); + PVInt& b = fld->getSubFieldT("test"); testOk(&b==a.get(), "%p == %p", &b, a.get()); } else testSkip(1, "test doesn't exist?"); @@ -549,7 +549,7 @@ static void testFieldAccess() a = fld->getSubField("hello.world"); testOk1(a!=NULL); if(a.get()) { - PVInt& b = fld->getAs("hello.world"); + PVInt& b = fld->getSubFieldT("hello.world"); testOk(&b==a.get(), "%p == %p", &b, a.get()); } else testSkip(1, "hello.world doesn't exist?"); @@ -579,7 +579,7 @@ static void testFieldAccess() // null string try{ char * name = NULL; - fld->getAs(name); + fld->getSubFieldT(name); testFail("missing required exception"); }catch(std::invalid_argument& e){ testPass("caught expected exception: %s", e.what()); @@ -587,7 +587,7 @@ static void testFieldAccess() // non-existent try{ - fld->getAs("invalid"); + fld->getSubFieldT("invalid"); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); @@ -595,7 +595,7 @@ static void testFieldAccess() // wrong type try{ - fld->getAs("test"); + fld->getSubFieldT("test"); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); @@ -603,7 +603,7 @@ static void testFieldAccess() // empty leaf field name try{ - fld->getAs("hello."); + fld->getSubFieldT("hello."); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); @@ -611,13 +611,13 @@ static void testFieldAccess() // empty field name try{ - fld->getAs("hello..world"); + fld->getSubFieldT("hello..world"); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); } try{ - fld->getAs("."); + fld->getSubFieldT("."); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); @@ -625,7 +625,7 @@ static void testFieldAccess() // whitespace try{ - fld->getAs(" test"); + fld->getSubFieldT(" test"); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); @@ -633,7 +633,7 @@ static void testFieldAccess() // intermediate field not structure try{ - fld->getAs("hello.world.invalid"); + fld->getSubFieldT("hello.world.invalid"); testFail("missing required exception"); }catch(std::runtime_error& e){ testPass("caught expected exception: %s", e.what()); From 9827caa3e3e9b3d7eadbe637628cf04a834c51fe Mon Sep 17 00:00:00 2001 From: Dave Hickin Date: Mon, 13 Jul 2015 12:41:47 +0100 Subject: [PATCH 5/6] Make overloads of getSubField and getSubFieldT match For each getSubField overload a throwing getSubFieldT has been added and vice versa. These have been documented in doxygen and in the module documentation. Signed-off-by: Dave Hickin --- documentation/pvDataCPP.html | 16 ++++-- documentation/pvDataCPP_20150623.html | 16 ++++-- src/factory/PVStructure.cpp | 14 +++++ src/pv/pvData.h | 81 +++++++++++++++++++++++---- 4 files changed, 107 insertions(+), 20 deletions(-) diff --git a/documentation/pvDataCPP.html b/documentation/pvDataCPP.html index 8618d59..89541be 100644 --- a/documentation/pvDataCPP.html +++ b/documentation/pvDataCPP.html @@ -2309,8 +2309,15 @@ public: template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const + PVField& getSubFieldT(std::string const &fieldName) const; + template<typename PVT> - PVT& getSubFieldT(std::string const &fieldName) const; + PVT& getSubFieldT(std::string const &fieldName) const + + PVField& getSubFieldT(std::size_t fieldOffset) const; + + template<typename PVT> + PVT& getSubFieldT(std::size_t fieldOffset) const virtual void serialize( ByteBuffer *pbuffer,SerializableControl *pflusher) const ; @@ -2332,7 +2339,7 @@ public:
getPVFields
Returns the array of subfields. The set of subfields must all have different field names.
-
getSubField(std::string fieldName)
+
getSubField(std::string const &fieldName)
Get a subField of a field.d A non-null result is @@ -2347,12 +2354,13 @@ public:
Get the field located a fieldOffset, where fieldOffset is relative to the top level structure. This returns null if the specified field is not located within this PVStructure. -
- Note The template version replaces getBooleanField, etc.
getSubFieldT(std::string const &fieldName)
Like getSubField except that it throws std::runtime_error if the field does not exists or has the wrong type.
+
getSubFieldT(int fieldOffset)
+
Like getSubField except that it throws std::runtime_error if + the field does not exists or has the wrong type.
dumpValue
Method for streams I/O.
diff --git a/documentation/pvDataCPP_20150623.html b/documentation/pvDataCPP_20150623.html index 8618d59..89541be 100644 --- a/documentation/pvDataCPP_20150623.html +++ b/documentation/pvDataCPP_20150623.html @@ -2309,8 +2309,15 @@ public: template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const + PVField& getSubFieldT(std::string const &fieldName) const; + template<typename PVT> - PVT& getSubFieldT(std::string const &fieldName) const; + PVT& getSubFieldT(std::string const &fieldName) const + + PVField& getSubFieldT(std::size_t fieldOffset) const; + + template<typename PVT> + PVT& getSubFieldT(std::size_t fieldOffset) const virtual void serialize( ByteBuffer *pbuffer,SerializableControl *pflusher) const ; @@ -2332,7 +2339,7 @@ public:
getPVFields
Returns the array of subfields. The set of subfields must all have different field names.
-
getSubField(std::string fieldName)
+
getSubField(std::string const &fieldName)
Get a subField of a field.d A non-null result is @@ -2347,12 +2354,13 @@ public:
Get the field located a fieldOffset, where fieldOffset is relative to the top level structure. This returns null if the specified field is not located within this PVStructure. -
- Note The template version replaces getBooleanField, etc.
getSubFieldT(std::string const &fieldName)
Like getSubField except that it throws std::runtime_error if the field does not exists or has the wrong type.
+
getSubFieldT(int fieldOffset)
+
Like getSubField except that it throws std::runtime_error if + the field does not exists or has the wrong type.
dumpValue
Method for streams I/O.
diff --git a/src/factory/PVStructure.cpp b/src/factory/PVStructure.cpp index 5319369..b4ecf6b 100644 --- a/src/factory/PVStructure.cpp +++ b/src/factory/PVStructure.cpp @@ -134,6 +134,20 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const throw std::logic_error("PVStructure.getSubField: Logic error"); } +PVField& PVStructure::getSubFieldT(std::size_t fieldOffset) const +{ + PVField * raw = getSubField(fieldOffset).get(); + if (raw) + return *raw; + else + { + std::stringstream ss; + ss << "Failed to get field with offset " + << fieldOffset << "(Invalid offset)" ; + throw std::runtime_error(ss.str()); + } +} + PVField* PVStructure::getSubFieldImpl(const char *name, bool throws) const { const PVStructure *parent = this; diff --git a/src/pv/pvData.h b/src/pv/pvData.h index 0e0e6b2..1e305b9 100644 --- a/src/pv/pvData.h +++ b/src/pv/pvData.h @@ -684,23 +684,42 @@ public: */ PVFieldPtr getSubField(std::string const &fieldName) const; + /** + * Get a subfield with the specified name. + * @param fieldName a '.' separated list of child field names (no whitespace allowed) + * @returns A pointer to the sub-field or null if field does not exist or has a different type + * @code + * PVIntPtr ptr = pvStruct->getSubField("substruct.leaffield"); + * @endcode + */ template - std::tr1::shared_ptr getSubField(std::string const &fieldName) const + FORCE_INLINE std::tr1::shared_ptr getSubField(std::string const &fieldName) const { - PVFieldPtr pvField = getSubField(fieldName); - if (pvField.get()) - return std::tr1::dynamic_pointer_cast(pvField); + return this->getSubField(fieldName.c_str()); + } + + template + std::tr1::shared_ptr getSubField(const char *name) const + { + PVField *raw = getSubFieldImpl(name, false); + if (raw) + return std::tr1::dynamic_pointer_cast(raw->shared_from_this()); else return std::tr1::shared_ptr(); } - + /** * Get the subfield with the specified offset. * @param fieldOffset The offset. * @return Pointer to the field or null if field does not exist. */ PVFieldPtr getSubField(std::size_t fieldOffset) const; - + + /** + * Get the subfield with the specified offset. + * @param fieldOffset The offset. + * @return Pointer to the field or null if field does not exist. + */ template std::tr1::shared_ptr getSubField(std::size_t fieldOffset) const { @@ -711,19 +730,32 @@ public: return std::tr1::shared_ptr(); } -private: - PVField *getSubFieldImpl(const char *name, bool throws = true) const; -public: + /** + * Get a subfield with the specified name. + * @param fieldName a '.' separated list of child field names (no whitespace allowed) + * @returns A reference to the sub-field (never NULL) + * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type + */ + FORCE_INLINE PVField& getSubFieldT(std::string const &fieldName) const + { + return *getSubFieldImpl(fieldName.c_str()); + } /** * Get a subfield with the specified name. - * @param name a '.' separated list of child field names (no whitespace allowed) + * @param fieldName a '.' separated list of child field names (no whitespace allowed) * @returns A reference to the sub-field (never NULL) * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type * @code * PVInt& ref = pvStruct->getSubFieldT("substruct.leaffield"); * @endcode */ + template + FORCE_INLINE PVT& getSubFieldT(std::string const &fieldName) const + { + return this->getSubFieldT(fieldName.c_str()); + } + template PVT& getSubFieldT(const char *name) const { @@ -737,10 +769,33 @@ public: return *raw; } + /** + * Get the subfield with the specified offset. + * @param fieldOffset The offset. + * @returns A reference to the sub-field (never NULL) + * @throws std::runtime_error if the requested sub-field doesn't exist + */ + PVField& getSubFieldT(std::size_t fieldOffset) const; + + /** + * Get the subfield with the specified offset. + * @param fieldOffset The offset. + * @returns A reference to the sub-field (never NULL) + * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type + */ template - FORCE_INLINE PVT& getSubFieldT(std::string const &fieldName) const + PVT& getSubFieldT(std::size_t fieldOffset) const { - return this->getSubFieldT(fieldName.c_str()); + PVT* raw = dynamic_cast(&getSubFieldT(fieldOffset)); + if (raw) + return *raw; + else + { + std::stringstream ss; + ss << "Failed to get field with offset " + << fieldOffset << " (Field has wrong type)"; + throw std::runtime_error(ss.str()); + } } /** @@ -915,6 +970,8 @@ public: void copyUnchecked(const PVStructure& from, const BitSet& maskBitSet, bool inverse = false); private: + PVField *getSubFieldImpl(const char *name, bool throws = true) const; + static PVFieldPtr nullPVField; static PVBooleanPtr nullPVBoolean; static PVBytePtr nullPVByte; From ac2b6ea8dbdf1f74cf2392534b919710eb21bdbc Mon Sep 17 00:00:00 2001 From: Dave Hickin Date: Mon, 13 Jul 2015 12:48:05 +0100 Subject: [PATCH 6/6] Make getSubFieldT return shared pointer Signed-off-by: Dave Hickin --- documentation/pvDataCPP.html | 8 +++---- documentation/pvDataCPP_20150623.html | 8 +++---- src/factory/PVStructure.cpp | 8 +++---- src/pv/pvData.h | 31 +++++++++++++++------------ testApp/pv/testPVData.cpp | 8 +++---- 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/documentation/pvDataCPP.html b/documentation/pvDataCPP.html index 89541be..53902c0 100644 --- a/documentation/pvDataCPP.html +++ b/documentation/pvDataCPP.html @@ -2309,15 +2309,15 @@ public: template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const - PVField& getSubFieldT(std::string const &fieldName) const; + PVFieldPtr getSubFieldT(std::string const &fieldName) const; template<typename PVT> - PVT& getSubFieldT(std::string const &fieldName) const + std::tr1::shared_ptr<PVT> getSubFieldT(std::string const &fieldName) const - PVField& getSubFieldT(std::size_t fieldOffset) const; + PVFieldPtr getSubFieldT(std::size_t fieldOffset) const; template<typename PVT> - PVT& getSubFieldT(std::size_t fieldOffset) const + std::tr1::shared_ptr<PVT> getSubFieldT(std::size_t fieldOffset) const virtual void serialize( ByteBuffer *pbuffer,SerializableControl *pflusher) const ; diff --git a/documentation/pvDataCPP_20150623.html b/documentation/pvDataCPP_20150623.html index 89541be..53902c0 100644 --- a/documentation/pvDataCPP_20150623.html +++ b/documentation/pvDataCPP_20150623.html @@ -2309,15 +2309,15 @@ public: template<typename PVT> std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const - PVField& getSubFieldT(std::string const &fieldName) const; + PVFieldPtr getSubFieldT(std::string const &fieldName) const; template<typename PVT> - PVT& getSubFieldT(std::string const &fieldName) const + std::tr1::shared_ptr<PVT> getSubFieldT(std::string const &fieldName) const - PVField& getSubFieldT(std::size_t fieldOffset) const; + PVFieldPtr getSubFieldT(std::size_t fieldOffset) const; template<typename PVT> - PVT& getSubFieldT(std::size_t fieldOffset) const + std::tr1::shared_ptr<PVT> getSubFieldT(std::size_t fieldOffset) const virtual void serialize( ByteBuffer *pbuffer,SerializableControl *pflusher) const ; diff --git a/src/factory/PVStructure.cpp b/src/factory/PVStructure.cpp index b4ecf6b..a7996b7 100644 --- a/src/factory/PVStructure.cpp +++ b/src/factory/PVStructure.cpp @@ -134,11 +134,11 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const throw std::logic_error("PVStructure.getSubField: Logic error"); } -PVField& PVStructure::getSubFieldT(std::size_t fieldOffset) const +PVFieldPtr PVStructure::getSubFieldT(std::size_t fieldOffset) const { - PVField * raw = getSubField(fieldOffset).get(); - if (raw) - return *raw; + PVFieldPtr pvField = getSubField(fieldOffset); + if (pvField.get()) + return pvField; else { std::stringstream ss; diff --git a/src/pv/pvData.h b/src/pv/pvData.h index 1e305b9..e54d636 100644 --- a/src/pv/pvData.h +++ b/src/pv/pvData.h @@ -736,9 +736,9 @@ public: * @returns A reference to the sub-field (never NULL) * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type */ - FORCE_INLINE PVField& getSubFieldT(std::string const &fieldName) const + FORCE_INLINE PVFieldPtr getSubFieldT(std::string const &fieldName) const { - return *getSubFieldImpl(fieldName.c_str()); + return getSubFieldImpl(fieldName.c_str())->shared_from_this(); } /** @@ -747,35 +747,37 @@ public: * @returns A reference to the sub-field (never NULL) * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type * @code - * PVInt& ref = pvStruct->getSubFieldT("substruct.leaffield"); + * PVIntPtr ptr = pvStruct->getSubFieldT("substruct.leaffield"); * @endcode */ template - FORCE_INLINE PVT& getSubFieldT(std::string const &fieldName) const + FORCE_INLINE std::tr1::shared_ptr getSubFieldT(std::string const &fieldName) const { return this->getSubFieldT(fieldName.c_str()); } template - PVT& getSubFieldT(const char *name) const + std::tr1::shared_ptr getSubFieldT(const char *name) const { - PVT *raw = dynamic_cast(getSubFieldImpl(name)); - if(!raw) + std::tr1::shared_ptr pvField = std::tr1::dynamic_pointer_cast( + getSubFieldImpl(name)->shared_from_this()); + + if (pvField.get()) + return pvField; + else { std::stringstream ss; ss << "Failed to get field: " << name << " (Field has wrong type)"; throw std::runtime_error(ss.str()); } - return *raw; } - /** * Get the subfield with the specified offset. * @param fieldOffset The offset. * @returns A reference to the sub-field (never NULL) * @throws std::runtime_error if the requested sub-field doesn't exist */ - PVField& getSubFieldT(std::size_t fieldOffset) const; + PVFieldPtr getSubFieldT(std::size_t fieldOffset) const; /** * Get the subfield with the specified offset. @@ -784,11 +786,12 @@ public: * @throws std::runtime_error if the requested sub-field doesn't exist, or has a different type */ template - PVT& getSubFieldT(std::size_t fieldOffset) const + std::tr1::shared_ptr getSubFieldT(std::size_t fieldOffset) const { - PVT* raw = dynamic_cast(&getSubFieldT(fieldOffset)); - if (raw) - return *raw; + std::tr1::shared_ptr pvField = std::tr1::dynamic_pointer_cast( + getSubFieldT(fieldOffset)); + if (pvField.get()) + return pvField; else { std::stringstream ss; diff --git a/testApp/pv/testPVData.cpp b/testApp/pv/testPVData.cpp index 747d8c6..ec387f7 100644 --- a/testApp/pv/testPVData.cpp +++ b/testApp/pv/testPVData.cpp @@ -541,16 +541,16 @@ static void testFieldAccess() PVIntPtr a = fld->getSubField("test"); testOk1(a!=NULL); if(a.get()) { - PVInt& b = fld->getSubFieldT("test"); - testOk(&b==a.get(), "%p == %p", &b, a.get()); + PVIntPtr b = fld->getSubFieldT("test"); + testOk(b.get()==a.get(), "%p == %p", b.get(), a.get()); } else testSkip(1, "test doesn't exist?"); a = fld->getSubField("hello.world"); testOk1(a!=NULL); if(a.get()) { - PVInt& b = fld->getSubFieldT("hello.world"); - testOk(&b==a.get(), "%p == %p", &b, a.get()); + PVIntPtr b = fld->getSubFieldT("hello.world"); + testOk(b.get()==a.get(), "%p == %p", b.get(), a.get()); } else testSkip(1, "hello.world doesn't exist?");