Merge pull request #4 from mdavidsaver/getasfield
Add PVStructure::getAs<>()
This commit is contained in:
@@ -44,10 +44,6 @@ PVUnionPtr PVStructure::nullPVUnion;
|
||||
PVUnionArrayPtr PVStructure::nullPVUnionArray;
|
||||
PVScalarArrayPtr PVStructure::nullPVScalarArray;
|
||||
|
||||
static PVFieldPtr findSubField(
|
||||
string const &fieldName,
|
||||
const PVStructure *pvStructure);
|
||||
|
||||
PVStructure::PVStructure(StructureConstPtr const & structurePtr)
|
||||
: PVField(structurePtr),
|
||||
structurePtr(structurePtr),
|
||||
@@ -111,7 +107,11 @@ const PVFieldPtrArray & PVStructure::getPVFields() const
|
||||
|
||||
PVFieldPtr PVStructure::getSubField(string const &fieldName) const
|
||||
{
|
||||
return findSubField(fieldName,this);
|
||||
try{
|
||||
return GetAsImpl(fieldName.c_str())->shared_from_this();
|
||||
}catch(...){
|
||||
return PVFieldPtr();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -208,21 +256,22 @@ PVUnionPtr PVStructure::getUnionField(string const &fieldName)
|
||||
PVScalarArrayPtr PVStructure::getScalarArrayField(
|
||||
string const &fieldName,ScalarType elementType)
|
||||
{
|
||||
PVFieldPtr pvField = findSubField(fieldName,this);
|
||||
if(pvField.get()==NULL) {
|
||||
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(...){
|
||||
return nullPVScalarArray;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
PVStructureArrayPtr PVStructure::getStructureArrayField(
|
||||
@@ -327,37 +376,6 @@ void PVStructure::deserialize(ByteBuffer *pbuffer,
|
||||
}
|
||||
}
|
||||
|
||||
static PVFieldPtr findSubField(
|
||||
string const & fieldName,
|
||||
PVStructure const *pvStructure)
|
||||
{
|
||||
if( fieldName.length()<1) return PVFieldPtr();
|
||||
string::size_type index = fieldName.find('.');
|
||||
string name = fieldName;
|
||||
string restOfName = string();
|
||||
if(index>0) {
|
||||
name = fieldName.substr(0, index);
|
||||
if(fieldName.length()>index) {
|
||||
restOfName = fieldName.substr(index+1);
|
||||
}
|
||||
}
|
||||
PVFieldPtrArray const & pvFields = pvStructure->getPVFields();
|
||||
PVFieldPtr pvField;
|
||||
size_t numFields = pvStructure->getStructure()->getNumberFields();
|
||||
for(size_t i=0; i<numFields; i++) {
|
||||
pvField = pvFields[i];
|
||||
size_t result = pvField->getFieldName().compare(name);
|
||||
if(result==0) {
|
||||
if(restOfName.length()==0) return pvFields[i];
|
||||
if(pvField->getField()->getType()!=structure) return PVFieldPtr();
|
||||
PVStructurePtr pvStructure =
|
||||
std::tr1::static_pointer_cast<PVStructure>(pvField);
|
||||
return findSubField(restOfName,pvStructure.get());
|
||||
}
|
||||
}
|
||||
return PVFieldPtr();
|
||||
}
|
||||
|
||||
std::ostream& PVStructure::dumpValue(std::ostream& o) const
|
||||
{
|
||||
o << format::indent() << getStructure()->getID() << ' ' << getFieldName();
|
||||
|
||||
@@ -711,6 +711,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
|
||||
|
||||
@@ -525,9 +525,72 @@ static void testCopy()
|
||||
testOk(*pvUnion == *pvUnion2, "PVUnion PVStructure copy, to different type PVUnion");
|
||||
}
|
||||
|
||||
static void testFieldAccess()
|
||||
{
|
||||
testDiag("Check methods for accessing structure fields");
|
||||
|
||||
StructureConstPtr tdef = fieldCreate->createFieldBuilder()->
|
||||
add("test", pvInt)->
|
||||
addNestedStructure("hello")->
|
||||
add("world", pvInt)->
|
||||
endNested()->
|
||||
createStructure();
|
||||
|
||||
PVStructurePtr fld = pvDataCreate->createPVStructure(tdef);
|
||||
|
||||
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());
|
||||
} 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());
|
||||
} else
|
||||
testSkip(1, "hello.world doesn't exist?");
|
||||
|
||||
// non-existant
|
||||
testOk1(fld->getSubField<PVInt>("invalid").get()==NULL);
|
||||
|
||||
// wrong type
|
||||
testOk1(fld->getSubField<PVDouble>("test").get()==NULL);
|
||||
|
||||
// intermediate struct non existant
|
||||
testOk1(fld->getSubField<PVDouble>("helo.world").get()==NULL);
|
||||
|
||||
// empty leaf field name
|
||||
testOk1(fld->getSubField<PVDouble>("hello.").get()==NULL);
|
||||
|
||||
// empty field name
|
||||
testOk1(fld->getSubField<PVDouble>("hello..world").get()==NULL);
|
||||
testOk1(fld->getSubField<PVDouble>(".").get()==NULL);
|
||||
|
||||
// whitespace
|
||||
testOk1(fld->getSubField<PVInt>(" test").get()==NULL);
|
||||
|
||||
try{
|
||||
fld->getAs<PVInt>("invalid");
|
||||
testFail("missing requried exception");
|
||||
}catch(std::runtime_error& e){
|
||||
testPass("caught expected exception: %s", e.what());
|
||||
}
|
||||
|
||||
try{
|
||||
fld->getAs<PVDouble>("test");
|
||||
testFail("missing requried exception");
|
||||
}catch(std::runtime_error& e){
|
||||
testPass("caught expected exception: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
MAIN(testPVData)
|
||||
{
|
||||
testPlan(222);
|
||||
testPlan(235);
|
||||
fieldCreate = getFieldCreate();
|
||||
pvDataCreate = getPVDataCreate();
|
||||
standardField = getStandardField();
|
||||
@@ -538,6 +601,7 @@ MAIN(testPVData)
|
||||
testScalarArray();
|
||||
testRequest();
|
||||
testCopy();
|
||||
testFieldAccess();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user