/*PVStructure.cpp*/ /** * Copyright - See the COPYRIGHT that is included with this distribution. * EPICS pvData is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ /** * @author mrk */ #include #include #include #include #include #define epicsExportSharedSymbols #include #include #include #include using std::tr1::static_pointer_cast; using std::size_t; using std::string; namespace epics { namespace pvData { PVFieldPtr PVStructure::nullPVField; PVBooleanPtr PVStructure::nullPVBoolean; PVBytePtr PVStructure::nullPVByte; PVShortPtr PVStructure::nullPVShort; PVIntPtr PVStructure::nullPVInt; PVLongPtr PVStructure::nullPVLong; PVUBytePtr PVStructure::nullPVUByte; PVUShortPtr PVStructure::nullPVUShort; PVUIntPtr PVStructure::nullPVUInt; PVULongPtr PVStructure::nullPVULong; PVFloatPtr PVStructure::nullPVFloat; PVDoublePtr PVStructure::nullPVDouble; PVStringPtr PVStructure::nullPVString; PVStructurePtr PVStructure::nullPVStructure; PVStructureArrayPtr PVStructure::nullPVStructureArray; 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), extendsStructureName("") { size_t numberFields = structurePtr->getNumberFields(); FieldConstPtrArray const & fields = structurePtr->getFields(); StringArray const & fieldNames = structurePtr->getFieldNames(); // PVFieldPtrArray * xxx = const_cast(&pvFields); pvFields.reserve(numberFields); PVDataCreatePtr pvDataCreate = getPVDataCreate(); for(size_t i=0; icreatePVField(fields[i])); } for(size_t i=0; isetParentAndName(this,fieldNames[i]); } } PVStructure::PVStructure(StructureConstPtr const & structurePtr, PVFieldPtrArray const & pvs ) : PVField(structurePtr), structurePtr(structurePtr), extendsStructureName("") { size_t numberFields = structurePtr->getNumberFields(); StringArray const & fieldNames = structurePtr->getFieldNames(); pvFields.reserve(numberFields); for(size_t i=0; isetParentAndName(this,fieldNames[i]); } } PVStructure::~PVStructure() { } void PVStructure::setImmutable() { size_t numFields = pvFields.size(); for(size_t i=0; isetImmutable(); } PVField::setImmutable(); } StructureConstPtr PVStructure::getStructure() const { return structurePtr; } const PVFieldPtrArray & PVStructure::getPVFields() const { return pvFields; } PVFieldPtr PVStructure::getSubField(string const &fieldName) const { return findSubField(fieldName,this); } PVFieldPtr PVStructure::getSubField(size_t fieldOffset) const { if(fieldOffset<=getFieldOffset()) { return nullPVField; } if(fieldOffset>getNextFieldOffset()) return nullPVField; size_t numFields = pvFields.size(); for(size_t i=0; igetFieldOffset()==fieldOffset) return pvFields[i]; if(pvField->getNextFieldOffset()<=fieldOffset) continue; if(pvField->getField()->getType()==structure) { PVStructure *pvStructure = static_cast(pvField.get()); return pvStructure->getSubField(fieldOffset); } } 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(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) { return getSubField(fieldName); } PVBytePtr PVStructure::getByteField(string const &fieldName) { return getSubField(fieldName); } PVShortPtr PVStructure::getShortField(string const &fieldName) { return getSubField(fieldName); } PVIntPtr PVStructure::getIntField(string const &fieldName) { return getSubField(fieldName); } PVLongPtr PVStructure::getLongField(string const &fieldName) { return getSubField(fieldName); } PVUBytePtr PVStructure::getUByteField(string const &fieldName) { return getSubField(fieldName); } PVUShortPtr PVStructure::getUShortField(string const &fieldName) { return getSubField(fieldName); } PVUIntPtr PVStructure::getUIntField(string const &fieldName) { return getSubField(fieldName); } PVULongPtr PVStructure::getULongField(string const &fieldName) { return getSubField(fieldName); } PVFloatPtr PVStructure::getFloatField(string const &fieldName) { return getSubField(fieldName); } PVDoublePtr PVStructure::getDoubleField(string const &fieldName) { return getSubField(fieldName); } PVStringPtr PVStructure::getStringField(string const &fieldName) { return getSubField(fieldName); } PVStructurePtr PVStructure::getStructureField(string const &fieldName) { return getSubField(fieldName); } PVUnionPtr PVStructure::getUnionField(string const &fieldName) { return getSubField(fieldName); } PVScalarArrayPtr PVStructure::getScalarArrayField( string const &fieldName,ScalarType elementType) { PVFieldPtr pvField = findSubField(fieldName,this); if(pvField.get()==NULL) { return nullPVScalarArray; } 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); } PVStructureArrayPtr PVStructure::getStructureArrayField( string const &fieldName) { return getSubField(fieldName); } PVUnionArrayPtr PVStructure::getUnionArrayField( string const &fieldName) { return getSubField(fieldName); } void PVStructure::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const { size_t fieldsSize = pvFields.size(); for(size_t i = 0; iserialize(pbuffer, pflusher); } void PVStructure::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t fieldsSize = pvFields.size(); for(size_t i = 0; ideserialize(pbuffer, pcontrol); } void PVStructure::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, BitSet *pbitSet) const { PVStructure* nonConstThis = const_cast(this); size_t numberFields = nonConstThis->getNumberFields(); size_t offset = nonConstThis->getFieldOffset(); int32 next = pbitSet->nextSetBit(static_cast(offset)); // no more changes or no changes in this structure if(next<0||next>=static_cast(offset+numberFields)) return; // entire structure if(static_cast(offset)==next) { serialize(pbuffer, pflusher); return; } size_t fieldsSize = pvFields.size(); for(size_t i = 0; igetFieldOffset(); int32 inumberFields = static_cast(pvField->getNumberFields()); next = pbitSet->nextSetBit(static_cast(offset)); // no more changes if(next<0) return; // no change in this pvField if(next>=static_cast(offset+inumberFields)) continue; // serialize field or fields if(inumberFields==1) { pvField->serialize(pbuffer, pflusher); } else { PVStructurePtr pvStructure = std::tr1::static_pointer_cast(pvField); pvStructure->serialize(pbuffer, pflusher, pbitSet); } } } void PVStructure::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol, BitSet *pbitSet) { size_t offset = getFieldOffset(); size_t numberFields = getNumberFields(); int32 next = pbitSet->nextSetBit(static_cast(offset)); // no more changes or no changes in this structure if(next<0||next>=static_cast(offset+numberFields)) return; // entire structure if(static_cast(offset)==next) { deserialize(pbuffer, pcontrol); return; } size_t fieldsSize = pvFields.size(); for(size_t i = 0; igetFieldOffset(); int32 inumberFields = static_cast(pvField->getNumberFields()); next = pbitSet->nextSetBit(static_cast(offset)); // no more changes if(next<0) return; // no change in this pvField if(next>=static_cast(offset+inumberFields)) continue; // deserialize field or fields if(inumberFields==1) { pvField->deserialize(pbuffer, pcontrol); } else { PVStructurePtr pvStructure = std::tr1::static_pointer_cast(pvField); pvStructure->deserialize(pbuffer, pcontrol, pbitSet); } } } 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; igetFieldName().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(pvField); return findSubField(restOfName,pvStructure.get()); } } return PVFieldPtr(); } std::ostream& PVStructure::dumpValue(std::ostream& o) const { o << format::indent() << getStructure()->getID() << ' ' << getFieldName(); o << std::endl; { format::indent_scope s(o); PVFieldPtrArray const & fieldsData = getPVFields(); if (fieldsData.size() != 0) { size_t length = getStructure()->getNumberFields(); for(size_t i=0; igetField()->getType(); if (type == scalar || type == scalarArray) o << format::indent() << fieldField->getField()->getID() << ' ' << fieldField->getFieldName() << ' ' << *(fieldField.get()) << std::endl; else o << *(fieldField.get()); } } } return o; } void PVStructure::copy(const PVStructure& from) { if(isImmutable()) throw std::invalid_argument("destination is immutable"); if(*getStructure() != *from.getStructure()) throw std::invalid_argument("structure definitions do not match"); copyUnchecked(from); } void PVStructure::copyUnchecked(const PVStructure& from) { if (this == &from) return; PVFieldPtrArray const & fromPVFields = from.getPVFields(); PVFieldPtrArray const & toPVFields = getPVFields(); size_t fieldsSize = fromPVFields.size(); for(size_t i = 0; icopyUnchecked(*fromPVFields[i]); } } void PVStructure::copyUnchecked(const PVStructure& from, const BitSet& maskBitSet, bool inverse) { if (this == &from) return; size_t numberFields = from.getNumberFields(); size_t offset = from.getFieldOffset(); int32 next = inverse ? maskBitSet.nextClearBit(static_cast(offset)) : maskBitSet.nextSetBit(static_cast(offset)); // no more changes or no changes in this structure if(next<0||next>=static_cast(offset+numberFields)) return; // entire structure if(static_cast(offset)==next) { copyUnchecked(from); return; } PVFieldPtrArray const & fromPVFields = from.getPVFields(); PVFieldPtrArray const & toPVFields = getPVFields(); size_t fieldsSize = fromPVFields.size(); for(size_t i = 0; igetFieldOffset(); int32 inumberFields = static_cast(pvField->getNumberFields()); next = inverse ? maskBitSet.nextClearBit(static_cast(offset)) : maskBitSet.nextSetBit(static_cast(offset)); // no more changes if(next<0) return; // no change in this pvField if(next>=static_cast(offset+inumberFields)) continue; // serialize field or fields if(inumberFields==1) { toPVFields[i]->copyUnchecked(*pvField); } else { PVStructure::shared_pointer fromPVStructure = std::tr1::static_pointer_cast(pvField); PVStructure::shared_pointer toPVStructure = std::tr1::static_pointer_cast(toPVFields[i]); toPVStructure->copyUnchecked(*fromPVStructure, maskBitSet, inverse); } } } }}