Merge pull request #7 from dhickin/getSubFieldT

GetSubFieldT
This commit is contained in:
dhickin
2015-07-14 16:19:38 +01:00
6 changed files with 276 additions and 101 deletions

View File

@@ -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
--------------------
<b>PVStructure</b> has a new template member <b>getAs(const char *name)</b>
<b>PVStructure</b> has a new template member <b>getSubFieldT(std::string const &fieldName)</b>
that is like <b>getSubField</b> except that it throws a runtime_error
instead of returning null.

View File

@@ -465,10 +465,10 @@ structure
PVStructurePtr doubleValue = getPVDataCreate()-&gt;createPVStructure(
getStandardField()-&gt;scalar(pvDouble,"alarm,timeStamp"));
PVDoublePtr pvdouble =
doubleValue-&gt;getAs&lt;PVDouble&gt;("value");
doubleValue-&gt;getSubField&lt;PVDouble&gt;("value");
pvdouble-&gt;put(1e5);
cout &lt;&lt; *doubleValue &lt;&lt; endl;
double value = doubleValue-&gt;getAs&lt;PVDouble&gt;("value")-&gt;get();
double value = doubleValue-&gt;getSubField&lt;PVDouble&gt;("value")-&gt;get();
cout &lt;&lt; "from get " &lt;&lt; value &lt;&lt; "\n\n";
</pre>
This produces:
@@ -491,7 +491,7 @@ from get 100000
PVStructurePtr doubleArrayValue = pvDataCreate-&gt;createPVStructure(
standardField-&gt;scalarArray(pvDouble,"alarm,timeStamp"));
PVDoubleArrayPtr pvDoubleArray =
doubleArrayValue-&gt;getAs&lt;PVDoubleArray&gt;("value");
doubleArrayValue-&gt;getSubField&lt;PVDoubleArray&gt;("value");
size_t len = 10;
shared_vector&lt;double&gt; xxx(len);
for(size_t i=0; i&lt; len; ++i) xxx[i] = i;
@@ -605,10 +605,10 @@ structure
createUnion(),
"alarm,timeStamp"));
PVStructurePtr pvTimeStamp =
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;select&lt;PVStructure&gt;(2);
pvTimeStamp-&gt;getAs&lt;PVLong&gt;("secondsPastEpoch")-&gt;put(1000);
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;select&lt;PVStructure&gt;(2);
pvTimeStamp-&gt;getSubField&lt;PVLong&gt;("secondsPastEpoch")-&gt;put(1000);
cout &lt;&lt; *pvStructure) &lt;&lt; "\n";
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;select&lt;PVDouble&gt;(0)-&gt;put(1e5);
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;select&lt;PVDouble&gt;(0)-&gt;put(1e5);
cout &lt;&lt; *pvStructure &lt;&lt; "\n\n";
</pre>
This produces:
@@ -648,13 +648,13 @@ epics:nt/NTUnion:1.0
standardField-&gt;variantUnion("alarm,timeStamp"));
PVStructurePtr pvTimeStamp =
pvDataCreate-&gt;createPVStructure(standardField-&gt;timeStamp());
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;set(pvTimeStamp);
pvTimeStamp-&gt;getAs&lt;PVLong&gt;("secondsPastEpoch")-&gt;put(1000);
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;set(pvTimeStamp);
pvTimeStamp-&gt;getSubField&lt;PVLong&gt;("secondsPastEpoch")-&gt;put(1000);
cout &lt;&lt; *pvStructure &lt;&lt; "\n";
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;set(
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;set(
pvDataCreate-&gt;createPVScalar(pvDouble));
PVDoublePtr pvValue = static_pointer_cast&lt;PVDouble&gt;(
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;get());
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;get());
pvValue-&gt;put(1e5);
cout &lt;&lt; *pvStructure &lt;&lt; "\n\n";
</pre>
@@ -718,7 +718,7 @@ epics:nt/NTUnion:1.0
cout &lt;&lt; *pvStructure-&gt;getStructure() &lt;&lt; endl;
cout &lt;&lt; "data\n";
cout &lt;&lt; *pvStructure &lt;&lt; "\n";
PVUnionPtr pvUnion = pvStructure-&gt;getAs&lt;PVUnion&gt;("value");;
PVUnionPtr pvUnion = pvStructure-&gt;getSubField&lt;PVUnion&gt;("value");;
pvUnion-&gt;select("doubleValue");
PVDoublePtr pvDouble = pvUnion-&gt;get&lt;PVDouble&gt;();
pvDouble-&gt;put(1.55);
@@ -726,7 +726,7 @@ epics:nt/NTUnion:1.0
cout &lt;&lt; *pvStructure &lt;&lt; "\n";
cout &lt;&lt; "value = " &lt;&lt; pvDouble-&gt;get() &lt;&lt; "\n";
pvUnion-&gt;select("structValue");
pvDouble = pvUnion-&gt;get&lt;PVStructure&gt;()-&gt;getAs&lt;PVDouble&gt;("doubleValue");
pvDouble = pvUnion-&gt;get&lt;PVStructure&gt;()-&gt;getSubField&lt;PVDouble&gt;("doubleValue");
pvDouble-&gt;put(1.65);
cout &lt;&lt; "select structValue\n";
cout &lt;&lt; *pvStructure &lt;&lt; "\n";
@@ -2304,14 +2304,21 @@ public:
template&lt;typename PVT&gt;
std::tr1::shared_ptr&lt;PVT&gt; getSubField(std::string const &amp;fieldName) const
template&lt;typename PVT&gt;
PVT&amp; getAs(const char *name) const;
PVFieldPtr getSubField(std::size_t fieldOffset) const;
template&lt;typename PVT&gt;
std::tr1::shared_ptr&lt;PVT&gt; getSubField(std::size_t fieldOffset) const
PVFieldPtr getSubFieldT(std::string const &amp;fieldName) const;
template&lt;typename PVT&gt;
std::tr1::shared_ptr&lt;PVT&gt; getSubFieldT(std::string const &amp;fieldName) const
PVFieldPtr getSubFieldT(std::size_t fieldOffset) const;
template&lt;typename PVT&gt;
std::tr1::shared_ptr&lt;PVT&gt; getSubFieldT(std::size_t fieldOffset) const
virtual void serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
virtual void deserialize(
@@ -2332,10 +2339,7 @@ public:
<dt>getPVFields</dt>
<dd>Returns the array of subfields. The set of subfields must all have
different field names.</dd>
<dt>getAs(const char *name)</dt>
<dd>Like the getSubField except that it throws std::runtime_error if
the field does not exists or has the wrong type.</dd>
<dt>getSubField(std::string fieldName)</dt>
<dt>getSubField(std::string const &amp;fieldName)</dt>
<dd>
Get a subField of a field.d
A non-null result is
@@ -2350,9 +2354,13 @@ public:
<dd>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.
<br />
<b>Note</b> The template version replaces getBooleanField, etc.<br/>
</dd>
<dt>getSubFieldT(std::string const &amp;fieldName)</dt>
<dd>Like getSubField except that it throws std::runtime_error if
the field does not exists or has the wrong type.</dd>
<dt>getSubFieldT(int fieldOffset)</dt>
<dd>Like getSubField except that it throws std::runtime_error if
the field does not exists or has the wrong type.</dd>
<dt>dumpValue</dt>
<dd>Method for streams I/O.</dd>
</dl>
@@ -5414,7 +5422,7 @@ public:
raiseMonitor = true;
if(pvFieldOptions!=NULL) {
PVStringPtr pvString =
pvFieldOptions-&gt;getAs&lt;PVString&gt;("raiseMonitor");
pvFieldOptions-&gt;getSubField&lt;PVString&gt;("raiseMonitor");
if(pvString!=NULL) {
std::string value = pvString-&gt;get();
if(value.compare("false")==0) raiseMonitor = false;

View File

@@ -465,10 +465,10 @@ structure
PVStructurePtr doubleValue = getPVDataCreate()-&gt;createPVStructure(
getStandardField()-&gt;scalar(pvDouble,"alarm,timeStamp"));
PVDoublePtr pvdouble =
doubleValue-&gt;getAs&lt;PVDouble&gt;("value");
doubleValue-&gt;getSubField&lt;PVDouble&gt;("value");
pvdouble-&gt;put(1e5);
cout &lt;&lt; *doubleValue &lt;&lt; endl;
double value = doubleValue-&gt;getAs&lt;PVDouble&gt;("value")-&gt;get();
double value = doubleValue-&gt;getSubField&lt;PVDouble&gt;("value")-&gt;get();
cout &lt;&lt; "from get " &lt;&lt; value &lt;&lt; "\n\n";
</pre>
This produces:
@@ -491,7 +491,7 @@ from get 100000
PVStructurePtr doubleArrayValue = pvDataCreate-&gt;createPVStructure(
standardField-&gt;scalarArray(pvDouble,"alarm,timeStamp"));
PVDoubleArrayPtr pvDoubleArray =
doubleArrayValue-&gt;getAs&lt;PVDoubleArray&gt;("value");
doubleArrayValue-&gt;getSubField&lt;PVDoubleArray&gt;("value");
size_t len = 10;
shared_vector&lt;double&gt; xxx(len);
for(size_t i=0; i&lt; len; ++i) xxx[i] = i;
@@ -605,10 +605,10 @@ structure
createUnion(),
"alarm,timeStamp"));
PVStructurePtr pvTimeStamp =
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;select&lt;PVStructure&gt;(2);
pvTimeStamp-&gt;getAs&lt;PVLong&gt;("secondsPastEpoch")-&gt;put(1000);
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;select&lt;PVStructure&gt;(2);
pvTimeStamp-&gt;getSubField&lt;PVLong&gt;("secondsPastEpoch")-&gt;put(1000);
cout &lt;&lt; *pvStructure) &lt;&lt; "\n";
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;select&lt;PVDouble&gt;(0)-&gt;put(1e5);
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;select&lt;PVDouble&gt;(0)-&gt;put(1e5);
cout &lt;&lt; *pvStructure &lt;&lt; "\n\n";
</pre>
This produces:
@@ -648,13 +648,13 @@ epics:nt/NTUnion:1.0
standardField-&gt;variantUnion("alarm,timeStamp"));
PVStructurePtr pvTimeStamp =
pvDataCreate-&gt;createPVStructure(standardField-&gt;timeStamp());
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;set(pvTimeStamp);
pvTimeStamp-&gt;getAs&lt;PVLong&gt;("secondsPastEpoch")-&gt;put(1000);
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;set(pvTimeStamp);
pvTimeStamp-&gt;getSubField&lt;PVLong&gt;("secondsPastEpoch")-&gt;put(1000);
cout &lt;&lt; *pvStructure &lt;&lt; "\n";
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;set(
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;set(
pvDataCreate-&gt;createPVScalar(pvDouble));
PVDoublePtr pvValue = static_pointer_cast&lt;PVDouble&gt;(
pvStructure-&gt;getAs&lt;PVUnion&gt;("value")-&gt;get());
pvStructure-&gt;getSubField&lt;PVUnion&gt;("value")-&gt;get());
pvValue-&gt;put(1e5);
cout &lt;&lt; *pvStructure &lt;&lt; "\n\n";
</pre>
@@ -718,7 +718,7 @@ epics:nt/NTUnion:1.0
cout &lt;&lt; *pvStructure-&gt;getStructure() &lt;&lt; endl;
cout &lt;&lt; "data\n";
cout &lt;&lt; *pvStructure &lt;&lt; "\n";
PVUnionPtr pvUnion = pvStructure-&gt;getAs&lt;PVUnion&gt;("value");;
PVUnionPtr pvUnion = pvStructure-&gt;getSubField&lt;PVUnion&gt;("value");;
pvUnion-&gt;select("doubleValue");
PVDoublePtr pvDouble = pvUnion-&gt;get&lt;PVDouble&gt;();
pvDouble-&gt;put(1.55);
@@ -726,7 +726,7 @@ epics:nt/NTUnion:1.0
cout &lt;&lt; *pvStructure &lt;&lt; "\n";
cout &lt;&lt; "value = " &lt;&lt; pvDouble-&gt;get() &lt;&lt; "\n";
pvUnion-&gt;select("structValue");
pvDouble = pvUnion-&gt;get&lt;PVStructure&gt;()-&gt;getAs&lt;PVDouble&gt;("doubleValue");
pvDouble = pvUnion-&gt;get&lt;PVStructure&gt;()-&gt;getSubField&lt;PVDouble&gt;("doubleValue");
pvDouble-&gt;put(1.65);
cout &lt;&lt; "select structValue\n";
cout &lt;&lt; *pvStructure &lt;&lt; "\n";
@@ -2304,14 +2304,21 @@ public:
template&lt;typename PVT&gt;
std::tr1::shared_ptr&lt;PVT&gt; getSubField(std::string const &amp;fieldName) const
template&lt;typename PVT&gt;
PVT&amp; getAs(const char *name) const;
PVFieldPtr getSubField(std::size_t fieldOffset) const;
template&lt;typename PVT&gt;
std::tr1::shared_ptr&lt;PVT&gt; getSubField(std::size_t fieldOffset) const
PVFieldPtr getSubFieldT(std::string const &amp;fieldName) const;
template&lt;typename PVT&gt;
std::tr1::shared_ptr&lt;PVT&gt; getSubFieldT(std::string const &amp;fieldName) const
PVFieldPtr getSubFieldT(std::size_t fieldOffset) const;
template&lt;typename PVT&gt;
std::tr1::shared_ptr&lt;PVT&gt; getSubFieldT(std::size_t fieldOffset) const
virtual void serialize(
ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
virtual void deserialize(
@@ -2332,10 +2339,7 @@ public:
<dt>getPVFields</dt>
<dd>Returns the array of subfields. The set of subfields must all have
different field names.</dd>
<dt>getAs(const char *name)</dt>
<dd>Like the getSubField except that it throws std::runtime_error if
the field does not exists or has the wrong type.</dd>
<dt>getSubField(std::string fieldName)</dt>
<dt>getSubField(std::string const &amp;fieldName)</dt>
<dd>
Get a subField of a field.d
A non-null result is
@@ -2350,9 +2354,13 @@ public:
<dd>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.
<br />
<b>Note</b> The template version replaces getBooleanField, etc.<br/>
</dd>
<dt>getSubFieldT(std::string const &amp;fieldName)</dt>
<dd>Like getSubField except that it throws std::runtime_error if
the field does not exists or has the wrong type.</dd>
<dt>getSubFieldT(int fieldOffset)</dt>
<dd>Like getSubField except that it throws std::runtime_error if
the field does not exists or has the wrong type.</dd>
<dt>dumpValue</dt>
<dd>Method for streams I/O.</dd>
</dl>
@@ -5414,7 +5422,7 @@ public:
raiseMonitor = true;
if(pvFieldOptions!=NULL) {
PVStringPtr pvString =
pvFieldOptions-&gt;getAs&lt;PVString&gt;("raiseMonitor");
pvFieldOptions-&gt;getSubField&lt;PVString&gt;("raiseMonitor");
if(pvString!=NULL) {
std::string value = pvString-&gt;get();
if(value.compare("false")==0) raiseMonitor = false;

View File

@@ -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 = getSubFieldImpl(fieldName.c_str(), false);
if (field)
return field->shared_from_this();
else
return PVFieldPtr();
}
@@ -134,21 +134,59 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const
throw std::logic_error("PVStructure.getSubField: Logic error");
}
PVField* PVStructure::GetAsImpl(const char *name) const
PVFieldPtr PVStructure::getSubFieldT(std::size_t fieldOffset) const
{
PVFieldPtr pvField = getSubField(fieldOffset);
if (pvField.get())
return pvField;
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;
if(!name)
throw std::invalid_argument("field name is NULL string");
{
if (throws)
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==' ')
throw std::runtime_error("No spaces allowed in field name");
{
if (throws)
{
std::stringstream ss;
ss << "Failed to get field: " << fullName
<< " (No spaces allowed in field name)";
throw std::runtime_error(ss.str());
}
else
return NULL;
}
size_t N = sep-name;
if(N==0)
throw std::runtime_error("zero-length field name encountered");
{
if (throws)
{
std::stringstream ss;
ss << "Failed to get field: " << fullName
<< " (Zero-length field name encountered)";
throw std::runtime_error(ss.str());
}
else
return NULL;
}
const PVFieldPtrArray& pvFields = parent->getPVFields();
@@ -165,13 +203,34 @@ PVField* PVStructure::GetAsImpl(const char *name) const
}
if(!child)
throw std::runtime_error("field not found"); //TODO: which sub field?
{
if (throws)
{
std::stringstream ss;
ss << "Failed to get field: " << fullName << " ("
<< std::string(fullName, sep) << " not found)";
throw std::runtime_error(ss.str());
}
else
return NULL;
}
if(*sep) {
// this is not the requested leaf
parent = dynamic_cast<PVStructure*>(child);
if(!parent)
throw std::runtime_error("mid-field is not a PVStructure"); //TODO: which sub field?
{
if (throws)
{
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;
}
child = NULL;
name = sep+1; // skip past '.'
// loop around to new parent
@@ -256,22 +315,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<const ScalarArray>(pvField->getField());
if(pscalarArray->getElementType()!=elementType) {
return nullPVScalarArray;
}
return std::tr1::static_pointer_cast<PVScalarArray>(pvField);
}catch(...){
PVScalarArrayPtr arrayField = getSubField<PVScalarArray>(fieldName);
if (arrayField.get() &&
arrayField->getScalarArray()->getElementType()!=elementType)
{
return nullPVScalarArray;
}
}
return arrayField;
}
PVStructureArrayPtr PVStructure::getStructureArrayField(

View File

@@ -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<PVInt>("substruct.leaffield");
* @endcode
*/
template<typename PVT>
std::tr1::shared_ptr<PVT> getSubField(std::string const &fieldName) const
FORCE_INLINE std::tr1::shared_ptr<PVT> getSubField(std::string const &fieldName) const
{
PVFieldPtr pvField = getSubField(fieldName);
if (pvField.get())
return std::tr1::dynamic_pointer_cast<PVT>(pvField);
return this->getSubField<PVT>(fieldName.c_str());
}
template<typename PVT>
std::tr1::shared_ptr<PVT> getSubField(const char *name) const
{
PVField *raw = getSubFieldImpl(name, false);
if (raw)
return std::tr1::dynamic_pointer_cast<PVT>(raw->shared_from_this());
else
return std::tr1::shared_ptr<PVT>();
}
/**
* 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<typename PVT>
std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const
{
@@ -711,32 +730,75 @@ public:
return std::tr1::shared_ptr<PVT>();
}
private:
PVField *GetAsImpl(const char *name) 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 PVFieldPtr getSubFieldT(std::string const &fieldName) const
{
return getSubFieldImpl(fieldName.c_str())->shared_from_this();
}
/**
* 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->getAs<PVInt>("substruct.leaffield");
* PVIntPtr ptr = pvStruct->getSubFieldT<PVInt>("substruct.leaffield");
* @endcode
*/
template<typename PVT>
PVT& getAs(const char *name) const
FORCE_INLINE std::tr1::shared_ptr<PVT> getSubFieldT(std::string const &fieldName) const
{
PVT *raw = dynamic_cast<PVT*>(GetAsImpl(name));
if(!raw)
throw std::runtime_error("Field has wrong type");
return *raw;
return this->getSubFieldT<PVT>(fieldName.c_str());
}
template<typename PVT>
FORCE_INLINE PVT& getAs(std::string const &fieldName) const
std::tr1::shared_ptr<PVT> getSubFieldT(const char *name) const
{
return this->getAs<PVT>(fieldName.c_str());
std::tr1::shared_ptr<PVT> pvField = std::tr1::dynamic_pointer_cast<PVT>(
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());
}
}
/**
* 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
*/
PVFieldPtr 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<typename PVT>
std::tr1::shared_ptr<PVT> getSubFieldT(std::size_t fieldOffset) const
{
std::tr1::shared_ptr<PVT> pvField = std::tr1::dynamic_pointer_cast<PVT>(
getSubFieldT(fieldOffset));
if (pvField.get())
return pvField;
else
{
std::stringstream ss;
ss << "Failed to get field with offset "
<< fieldOffset << " (Field has wrong type)";
throw std::runtime_error(ss.str());
}
}
/**
@@ -911,6 +973,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;

View File

@@ -541,16 +541,16 @@ static void testFieldAccess()
PVIntPtr a = fld->getSubField<PVInt>("test");
testOk1(a!=NULL);
if(a.get()) {
PVInt& b = fld->getAs<PVInt>("test");
testOk(&b==a.get(), "%p == %p", &b, a.get());
PVIntPtr b = fld->getSubFieldT<PVInt>("test");
testOk(b.get()==a.get(), "%p == %p", b.get(), a.get());
} else
testSkip(1, "test doesn't exist?");
a = fld->getSubField<PVInt>("hello.world");
testOk1(a!=NULL);
if(a.get()) {
PVInt& b = fld->getAs<PVInt>("hello.world");
testOk(&b==a.get(), "%p == %p", &b, a.get());
PVIntPtr b = fld->getSubFieldT<PVInt>("hello.world");
testOk(b.get()==a.get(), "%p == %p", b.get(), a.get());
} else
testSkip(1, "hello.world doesn't exist?");
@@ -573,22 +573,67 @@ static void testFieldAccess()
// whitespace
testOk1(fld->getSubField<PVInt>(" test").get()==NULL);
// intermediate field not structure
testOk1(fld->getSubField<PVInt>("hello.world.invalid").get()==NULL);
// null string
try{
fld->getAs<PVInt>("invalid");
char * name = NULL;
fld->getSubFieldT<PVInt>(name);
testFail("missing required exception");
}catch(std::invalid_argument& e){
testPass("caught expected exception: %s", e.what());
}
// non-existent
try{
fld->getSubFieldT<PVInt>("invalid");
testFail("missing required exception");
}catch(std::runtime_error& e){
testPass("caught expected exception: %s", e.what());
}
// wrong type
try{
fld->getAs<PVDouble>("test");
fld->getSubFieldT<PVDouble>("test");
testFail("missing required exception");
}catch(std::runtime_error& e){
testPass("caught expected exception: %s", e.what());
}
// empty leaf field name
try{
fld->getAs<PVDouble>("hello.world.invalid");
fld->getSubFieldT<PVDouble>("hello.");
testFail("missing required exception");
}catch(std::runtime_error& e){
testPass("caught expected exception: %s", e.what());
}
// empty field name
try{
fld->getSubFieldT<PVDouble>("hello..world");
testFail("missing required exception");
}catch(std::runtime_error& e){
testPass("caught expected exception: %s", e.what());
}
try{
fld->getSubFieldT<PVDouble>(".");
testFail("missing required exception");
}catch(std::runtime_error& e){
testPass("caught expected exception: %s", e.what());
}
// whitespace
try{
fld->getSubFieldT<PVDouble>(" test");
testFail("missing required exception");
}catch(std::runtime_error& e){
testPass("caught expected exception: %s", e.what());
}
// intermediate field not structure
try{
fld->getSubFieldT<PVDouble>("hello.world.invalid");
testFail("missing required exception");
}catch(std::runtime_error& e){
testPass("caught expected exception: %s", e.what());
@@ -597,7 +642,7 @@ static void testFieldAccess()
MAIN(testPVData)
{
testPlan(236);
testPlan(242);
fieldCreate = getFieldCreate();
pvDataCreate = getPVDataCreate();
standardField = getStandardField();