add PVStructure::getAs<>() for field access w/o NULL

This commit is contained in:
Michael Davidsaver
2015-06-22 17:48:32 -04:00
parent 0d857999bf
commit eadb8ff65b
3 changed files with 141 additions and 1 deletions

View File

@@ -134,6 +134,54 @@ PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const
throw std::logic_error("PVStructure.getSubField: Logic error");
}
PVField* PVStructure::GetAsImpl(const char *name) const
{
const PVStructure *parent = this;
if(!name)
throw std::invalid_argument("field name is NULL string");
while(true) {
const char *sep=name;
while(*sep!='\0' && *sep!='.' && *sep!=' ') sep++;
if(*sep==' ')
throw std::runtime_error("No spaces allowed in field name");
size_t N = sep-name;
if(N==0)
throw std::runtime_error("zero-length field name encountered");
const PVFieldPtrArray& pvFields = parent->getPVFields();
PVField *child = NULL;
for(size_t i=0, n=pvFields.size(); i!=n; i++) {
const PVFieldPtr& fld = pvFields[i];
const std::string& fname = fld->getFieldName();
if(fname.size()==N && memcmp(name, fname.c_str(), N)==0) {
child = fld.get();
break;
}
}
if(!child)
throw std::runtime_error("field not found"); //TODO: which sub field?
if(*sep) {
// this is not the requested leaf
parent = dynamic_cast<PVStructure*>(child);
if(!child)
throw std::runtime_error("mid-field is not a PVStructure"); //TODO: which sub field?
child = NULL;
name = sep+1; // skip past '.'
// loop around to new parent
} else {
return child;
}
}
}
PVBooleanPtr PVStructure::getBooleanField(string const &fieldName)
{

View File

@@ -703,6 +703,34 @@ public:
return std::tr1::shared_ptr<PVT>();
}
private:
PVField *GetAsImpl(const char *name) const;
public:
/**
* Get a subfield with the specified name.
* @param name a '.' seperated 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");
* @endcode
*/
template<typename PVT>
PVT& getAs(const char *name) const
{
PVT *raw = dynamic_cast<PVT*>(GetAsImpl(name));
if(!raw)
throw std::runtime_error("Field has wrong type");
return *raw;
}
template<typename PVT>
FORCE_INLINE PVT& getAs(std::string const &fieldName) const
{
return this->getAs<PVT>(fieldName.c_str());
}
/**
* Get a boolean field with the specified name.
* @deprecated No longer needed. Use templete version of getSubField