Files
pvData/pvDataApp/factory/PVStructure.cpp
2012-05-09 14:06:17 -04:00

642 lines
21 KiB
C++

/*PVStructure.cpp*/
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <vector>
#include <pv/pvData.h>
#include <pv/pvIntrospect.h>
#include <pv/convert.h>
#include <pv/factory.h>
#include <pv/bitSet.h>
using std::tr1::static_pointer_cast;
using std::tr1::const_pointer_cast;
using std::size_t;
namespace epics { namespace pvData {
static PVFieldPtr nullPVField;
static PVBooleanPtr nullPVBoolean;
static PVBytePtr nullPVByte;
static PVShortPtr nullPVShort;
static PVIntPtr nullPVInt;
static PVLongPtr nullPVLong;
static PVUBytePtr nullPVUByte;
static PVUShortPtr nullPVUShort;
static PVUIntPtr nullPVUInt;
static PVULongPtr nullPVULong;
static PVFloatPtr nullPVFloat;
static PVDoublePtr nullPVDouble;
static PVStringPtr nullPVString;
static PVStructurePtr nullPVStructure;
static PVStructureArrayPtr nullPVStructureArray;
static PVScalarArrayPtr nullPVScalarArray;
static PVFieldPtr &findSubField(String fieldName,PVStructure *pvStructure);
PVStructure::PVStructure(StructureConstPtr& structurePtr)
: PVField(structurePtr),
structurePtr(structurePtr),
extendsStructureName("")
{
size_t numberFields = structurePtr->getNumberFields();
FieldConstPtrArray fields = structurePtr->getFields();
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]->setParent(this);
}
}
PVStructure::PVStructure(StructureConstPtr structurePtr,
PVFieldPtrArray & pvs
)
: PVField(structurePtr),
structurePtr(structurePtr),
extendsStructureName("")
{
size_t numberFields = structurePtr->getNumberFields();
pvFields = pvs;
for(size_t i=0; i<numberFields; i++) {
pvFields[i]->setParent(this);
}
}
PVStructure::~PVStructure()
{
}
StructureConstPtr &PVStructure::getStructure()
{
return structurePtr;
}
PVFieldPtrArray & PVStructure::getPVFields()
{
return pvFields;
}
PVFieldPtr &PVStructure::getSubField(String fieldName)
{
return findSubField(fieldName,this);
}
PVFieldPtr &PVStructure::getSubField(size_t fieldOffset)
{
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");
}
void PVStructure::appendPVField(String fieldName,PVFieldPtr & pvField )
{
size_t origLength = pvFields.size();
size_t newLength = origLength+1;
PVFieldPtrArray newPVFields;
newPVFields.reserve(newLength);
for(size_t i=0; i<origLength; i++) {
newPVFields.push_back(pvFields[i]);
}
newPVFields.push_back(pvField);
pvFields.swap(newPVFields);
FieldConstPtr field = getFieldCreate()->appendField(structurePtr,fieldName,pvField->getField());
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
for(size_t i=0; i<newLength; i++) pvFields[i]->setParent(this);
}
void PVStructure::appendPVFields(StringArray &fieldNames,PVFieldPtrArray &pvFields)
{
size_t origLength = this->pvFields.size();
size_t extra = fieldNames.size();
if(extra==0) return;
size_t newLength = origLength + extra;
PVFieldPtrArray newPVFields;
newPVFields.reserve(newLength);
for(size_t i=0; i<origLength; i++) {
newPVFields.push_back(this->pvFields[i]);
}
for(size_t i=0; i<extra; i++) {
newPVFields.push_back(pvFields[i]);
}
this->pvFields.swap(newPVFields);
FieldConstPtrArray fields;
fields.reserve(extra);
for(size_t i=0; i<extra; i++) fields.push_back(pvFields[i]->getField());
FieldConstPtr field = getFieldCreate()->appendFields(structurePtr,fieldNames,fields);
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
for(size_t i=0; i<newLength; i++) pvFields[i]->setParent(this);
}
void PVStructure::removePVField(String fieldName)
{
PVFieldPtr pvField = getSubField(fieldName);
if(pvField.get()==NULL) {
String message("removePVField ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return;
}
size_t origLength = pvFields.size();
size_t newLength = origLength - 1;
PVFieldPtrArray const & origPVFields = pvFields;
FieldConstPtrArray origFields = structurePtr->getFields();
PVFieldPtrArray newPVFields;
newPVFields.reserve(newLength);
StringArray newFieldNames;
newFieldNames.reserve(newLength);
FieldConstPtrArray fields;
fields.reserve(newLength);
for(size_t i=0; i<origLength; i++) {
if(origPVFields[i]!=pvField) {
newFieldNames.push_back(origPVFields[i]->getFieldName());
newPVFields.push_back(origPVFields[i]);
fields.push_back(origFields[i]);
}
}
pvFields.swap(newPVFields);
FieldConstPtr field = getFieldCreate()->createStructure(newFieldNames,fields);
replaceField(field);
structurePtr = static_pointer_cast<const Structure>(field);
for(size_t i=0; i<newLength; i++) pvFields[i]->setParent(this);
}
PVBooleanPtr PVStructure::getBooleanField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVBoolean;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvBoolean) {
return std::tr1::static_pointer_cast<PVBoolean>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type boolean ";
this->message(message, errorMessage);
return nullPVBoolean;
}
PVBytePtr PVStructure::getByteField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVByte;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvByte) {
return std::tr1::static_pointer_cast<PVByte>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type byte ";
this->message(message, errorMessage);
return nullPVByte;
}
PVShortPtr PVStructure::getShortField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVShort;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvShort) {
return std::tr1::static_pointer_cast<PVShort>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type short ";
this->message(message, errorMessage);
return nullPVShort;
}
PVIntPtr PVStructure::getIntField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVInt;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvInt) {
return std::tr1::static_pointer_cast<PVInt>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type int ";
this->message(message, errorMessage);
return nullPVInt;
}
PVLongPtr PVStructure::getLongField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVLong;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvLong) {
return std::tr1::static_pointer_cast<PVLong>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type long ";
this->message(message, errorMessage);
return nullPVLong;
}
PVUBytePtr PVStructure::getUByteField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVUByte;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvUByte) {
return std::tr1::static_pointer_cast<PVUByte>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type byte ";
this->message(message, errorMessage);
return nullPVUByte;
}
PVUShortPtr PVStructure::getUShortField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVUShort;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvUShort) {
return std::tr1::static_pointer_cast<PVUShort>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type short ";
this->message(message, errorMessage);
return nullPVUShort;
}
PVUIntPtr PVStructure::getUIntField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVUInt;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvUInt) {
return std::tr1::static_pointer_cast<PVUInt>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type int ";
this->message(message, errorMessage);
return nullPVUInt;
}
PVULongPtr PVStructure::getULongField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVULong;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvULong) {
return std::tr1::static_pointer_cast<PVULong>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type long ";
this->message(message, errorMessage);
return nullPVULong;
}
PVFloatPtr PVStructure::getFloatField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVFloat;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvFloat) {
return std::tr1::static_pointer_cast<PVFloat>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type float ";
this->message(message, errorMessage);
return nullPVFloat;
}
PVDoublePtr PVStructure::getDoubleField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVDouble;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvDouble) {
return std::tr1::static_pointer_cast<PVDouble>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type double ";
this->message(message, errorMessage);
return nullPVDouble;
}
PVStringPtr PVStructure::getStringField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVString;
}
if(pvField->getField()->getType()==scalar) {
ScalarConstPtr pscalar = static_pointer_cast<const Scalar>(
pvField->getField());
if(pscalar->getScalarType()==pvString) {
return std::tr1::static_pointer_cast<PVString>(pvField);
}
}
String message("fieldName ");
message += fieldName + " does not have type string ";
this->message(message, errorMessage);
return nullPVString;
}
PVStructurePtr PVStructure::getStructureField(String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVStructure;
}
if(pvField->getField()->getType()==structure) {
return std::tr1::static_pointer_cast<PVStructure>(pvField);
}
String message("fieldName ");
message += fieldName + " does not have type structure ";
this->message(message, errorMessage);
return nullPVStructure;
}
PVScalarArrayPtr PVStructure::getScalarArrayField(
String fieldName,ScalarType elementType)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVScalarArray;
}
FieldConstPtr field = pvField->getField();
Type type = field->getType();
if(type!=scalarArray) {
String message("fieldName ");
message += fieldName + " does not have type array ";
this->message(message, errorMessage);
return nullPVScalarArray;
}
ScalarArrayConstPtr pscalarArray
= static_pointer_cast<const ScalarArray>(pvField->getField());
if(pscalarArray->getElementType()!=elementType) {
String message("fieldName ");
message += fieldName + " is array but does not have elementType ";
ScalarTypeFunc::toString(&message,elementType);
this->message(message, errorMessage);
return nullPVScalarArray;
}
return std::tr1::static_pointer_cast<PVScalarArray>(pvField);
}
PVStructureArrayPtr PVStructure::getStructureArrayField(
String fieldName)
{
PVFieldPtr pvField = findSubField(fieldName,this);
if(pvField.get()==NULL) {
String message("fieldName ");
message += fieldName + " does not exist";
this->message(message, errorMessage);
return nullPVStructureArray;
}
if(pvField->getField()->getType()==structureArray) {
return std::tr1::static_pointer_cast<PVStructureArray>(pvField);
}
String message("fieldName ");
message += fieldName + " does not have type structureArray ";
this->message(message, errorMessage);
return nullPVStructureArray;
}
String PVStructure::getExtendsStructureName()
{
return extendsStructureName;
}
bool PVStructure::putExtendsStructureName(
String extendsStructureName)
{
if(extendsStructureName.length()!=0) return false;
extendsStructureName = extendsStructureName;
return true;
}
void PVStructure::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher) const {
for(size_t i = 0; i<pvFields.size(); i++)
pvFields[i]->serialize(pbuffer, pflusher);
}
void PVStructure::deserialize(ByteBuffer *pbuffer,
DeserializableControl *pcontrol) {
for(size_t i = 0; i<pvFields.size(); i++)
pvFields[i]->deserialize(pbuffer, pcontrol);
}
void PVStructure::serialize(ByteBuffer *pbuffer,
SerializableControl *pflusher, BitSet *pbitSet) const {
size_t offset = const_cast<PVStructure*>(this)->getFieldOffset();
size_t numberFields = const_cast<PVStructure*>(this)->getNumberFields();
size_t next = pbitSet->nextSetBit(offset);
// no more changes or no changes in this structure
if(next<0||next>=offset+numberFields) return;
// entire structure
if(offset==next) {
serialize(pbuffer, pflusher);
return;
}
for(size_t i = 0; i<numberFields; i++) {
PVFieldPtr pvField = pvFields[i];
offset = pvField->getFieldOffset();
numberFields = pvField->getNumberFields();
next = pbitSet->nextSetBit(offset);
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=offset+numberFields) continue;
// serialize field or fields
if(numberFields==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();
size_t next = pbitSet->nextSetBit(offset);
// no more changes or no changes in this structure
if(next<0||next>=offset+numberFields) return;
// entire structure
if(offset==next) {
deserialize(pbuffer, pcontrol);
return;
}
for(size_t i = 0; i<numberFields; i++) {
PVFieldPtr pvField = pvFields[i];
offset = pvField->getFieldOffset();
numberFields = pvField->getNumberFields();
next = pbitSet->nextSetBit(offset);
// no more changes
if(next<0) return;
// no change in this pvField
if(next>=offset+numberFields) continue;
// deserialize field or fields
if(numberFields==1) {
pvField->deserialize(pbuffer, pcontrol);
} else {
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
pvStructure->deserialize(pbuffer, pcontrol, pbitSet);
}
}
}
static PVFieldPtr &findSubField(String fieldName,PVStructure *pvStructure) {
if( fieldName.length()<1) return nullPVField;
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 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 nullPVField;
PVStructurePtr pvStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
return findSubField(restOfName,pvStructure.get());
}
}
return nullPVField;
}
}}