Files
pvData/src/factory/PVStructure.cpp
2015-06-22 18:14:23 -04:00

508 lines
15 KiB
C++

/*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 <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <vector>
#define epicsExportSharedSymbols
#include <pv/pvData.h>
#include <pv/pvIntrospect.h>
#include <pv/factory.h>
#include <pv/bitSet.h>
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<PVFieldPtrArray *>(&pvFields);
pvFields.reserve(numberFields);
PVDataCreatePtr pvDataCreate = getPVDataCreate();
for(size_t i=0; i<numberFields; i++) {
pvFields.push_back(pvDataCreate->createPVField(fields[i]));
}
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParentAndName(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; i<numberFields; i++) {
pvFields.push_back(pvs[i]);
}
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParentAndName(this,fieldNames[i]);
}
}
PVStructure::~PVStructure()
{
}
void PVStructure::setImmutable()
{
size_t numFields = pvFields.size();
for(size_t i=0; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i];
pvField->setImmutable();
}
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; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i];
if(pvField->getFieldOffset()==fieldOffset) return pvFields[i];
if(pvField->getNextFieldOffset()<=fieldOffset) continue;
if(pvField->getField()->getType()==structure) {
PVStructure *pvStructure = static_cast<PVStructure *>(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<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)
{
return getSubField<PVBoolean>(fieldName);
}
PVBytePtr PVStructure::getByteField(string const &fieldName)
{
return getSubField<PVByte>(fieldName);
}
PVShortPtr PVStructure::getShortField(string const &fieldName)
{
return getSubField<PVShort>(fieldName);
}
PVIntPtr PVStructure::getIntField(string const &fieldName)
{
return getSubField<PVInt>(fieldName);
}
PVLongPtr PVStructure::getLongField(string const &fieldName)
{
return getSubField<PVLong>(fieldName);
}
PVUBytePtr PVStructure::getUByteField(string const &fieldName)
{
return getSubField<PVUByte>(fieldName);
}
PVUShortPtr PVStructure::getUShortField(string const &fieldName)
{
return getSubField<PVUShort>(fieldName);
}
PVUIntPtr PVStructure::getUIntField(string const &fieldName)
{
return getSubField<PVUInt>(fieldName);
}
PVULongPtr PVStructure::getULongField(string const &fieldName)
{
return getSubField<PVULong>(fieldName);
}
PVFloatPtr PVStructure::getFloatField(string const &fieldName)
{
return getSubField<PVFloat>(fieldName);
}
PVDoublePtr PVStructure::getDoubleField(string const &fieldName)
{
return getSubField<PVDouble>(fieldName);
}
PVStringPtr PVStructure::getStringField(string const &fieldName)
{
return getSubField<PVString>(fieldName);
}
PVStructurePtr PVStructure::getStructureField(string const &fieldName)
{
return getSubField<PVStructure>(fieldName);
}
PVUnionPtr PVStructure::getUnionField(string const &fieldName)
{
return getSubField<PVUnion>(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<const ScalarArray>(pvField->getField());
if(pscalarArray->getElementType()!=elementType) {
return nullPVScalarArray;
}
return std::tr1::static_pointer_cast<PVScalarArray>(pvField);
}
PVStructureArrayPtr PVStructure::getStructureArrayField(
string const &fieldName)
{
return getSubField<PVStructureArray>(fieldName);
}
PVUnionArrayPtr PVStructure::getUnionArrayField(
string const &fieldName)
{
return getSubField<PVUnionArray>(fieldName);
}
void PVStructure::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++)
pvFields[i]->serialize(pbuffer, pflusher);
}
void PVStructure::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++)
pvFields[i]->deserialize(pbuffer, pcontrol);
}
void PVStructure::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, BitSet *pbitSet) const {
PVStructure* nonConstThis = const_cast<PVStructure*>(this);
size_t numberFields = nonConstThis->getNumberFields();
size_t offset = nonConstThis->getFieldOffset();
int32 next = pbitSet->nextSetBit(static_cast<uint32>(offset));
// no more changes or no changes in this structure
if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
// entire structure
if(static_cast<int32>(offset)==next) {
serialize(pbuffer, pflusher);
return;
}
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = pvFields[i];
offset = pvField->getFieldOffset();
int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
next = pbitSet->nextSetBit(static_cast<uint32>(offset));
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=static_cast<int32>(offset+inumberFields)) continue;
// serialize field or fields
if(inumberFields==1) {
pvField->serialize(pbuffer, pflusher);
} else {
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(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<uint32>(offset));
// no more changes or no changes in this structure
if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
// entire structure
if(static_cast<int32>(offset)==next) {
deserialize(pbuffer, pcontrol);
return;
}
size_t fieldsSize = pvFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = pvFields[i];
offset = pvField->getFieldOffset();
int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
next = pbitSet->nextSetBit(static_cast<uint32>(offset));
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=static_cast<int32>(offset+inumberFields)) continue;
// deserialize field or fields
if(inumberFields==1) {
pvField->deserialize(pbuffer, pcontrol);
} else {
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(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; 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();
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; i<length; i++) {
PVFieldPtr fieldField = fieldsData[i];
Type type = fieldField->getField()->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; i<fieldsSize; i++) {
toPVFields[i]->copyUnchecked(*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<uint32>(offset)) :
maskBitSet.nextSetBit(static_cast<uint32>(offset));
// no more changes or no changes in this structure
if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
// entire structure
if(static_cast<int32>(offset)==next) {
copyUnchecked(from);
return;
}
PVFieldPtrArray const & fromPVFields = from.getPVFields();
PVFieldPtrArray const & toPVFields = getPVFields();
size_t fieldsSize = fromPVFields.size();
for(size_t i = 0; i<fieldsSize; i++) {
PVFieldPtr pvField = fromPVFields[i];
offset = pvField->getFieldOffset();
int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
next = inverse ?
maskBitSet.nextClearBit(static_cast<uint32>(offset)) :
maskBitSet.nextSetBit(static_cast<uint32>(offset));
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=static_cast<int32>(offset+inumberFields)) continue;
// serialize field or fields
if(inumberFields==1) {
toPVFields[i]->copyUnchecked(*pvField);
} else {
PVStructure::shared_pointer fromPVStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
PVStructure::shared_pointer toPVStructure = std::tr1::static_pointer_cast<PVStructure>(toPVFields[i]);
toPVStructure->copyUnchecked(*fromPVStructure, maskBitSet, inverse);
}
}
}
}}