/*PVDataCreateFactory.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 */ #ifdef _WIN32 #define NOMINMAX #endif #include #include #include #include #define epicsExportSharedSymbols #include #include #include #include #include #include using std::tr1::static_pointer_cast; using std::size_t; using std::min; namespace epics { namespace pvData { template<> const ScalarType PVBoolean::typeCode = pvBoolean; template<> const ScalarType PVByte::typeCode = pvByte; template<> const ScalarType PVShort::typeCode = pvShort; template<> const ScalarType PVInt::typeCode = pvInt; template<> const ScalarType PVLong::typeCode = pvLong; template<> const ScalarType PVUByte::typeCode = pvUByte; template<> const ScalarType PVUShort::typeCode = pvUShort; template<> const ScalarType PVUInt::typeCode = pvUInt; template<> const ScalarType PVULong::typeCode = pvULong; template<> const ScalarType PVFloat::typeCode = pvFloat; template<> const ScalarType PVDouble::typeCode = pvDouble; template<> const ScalarType PVScalarValue::typeCode = pvString; template<> const ScalarType PVBooleanArray::typeCode = pvBoolean; template<> const ScalarType PVByteArray::typeCode = pvByte; template<> const ScalarType PVShortArray::typeCode = pvShort; template<> const ScalarType PVIntArray::typeCode = pvInt; template<> const ScalarType PVLongArray::typeCode = pvLong; template<> const ScalarType PVUByteArray::typeCode = pvUByte; template<> const ScalarType PVUShortArray::typeCode = pvUShort; template<> const ScalarType PVUIntArray::typeCode = pvUInt; template<> const ScalarType PVULongArray::typeCode = pvULong; template<> const ScalarType PVFloatArray::typeCode = pvFloat; template<> const ScalarType PVDoubleArray::typeCode = pvDouble; template<> const ScalarType PVStringArray::typeCode = pvString; /** Default storage for scalar values */ template class BasePVScalar : public PVScalarValue { public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; BasePVScalar(ScalarConstPtr const & scalar); virtual ~BasePVScalar(); virtual T get() const ; virtual void put(T val); virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const; virtual void deserialize(ByteBuffer *pbuffer, DeserializableControl *pflusher); private: T value; }; template BasePVScalar::BasePVScalar(ScalarConstPtr const & scalar) : PVScalarValue(scalar),value(0) {} //Note: '0' is a suitable default for all POD types (not String) template BasePVScalar::~BasePVScalar() {} template T BasePVScalar::get() const { return value;} template void BasePVScalar::put(T val) { value = val; PVField::postPut(); } template void BasePVScalar::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const { pflusher->ensureBuffer(sizeof(T)); pbuffer->put(value); } template void BasePVScalar::deserialize(ByteBuffer *pbuffer, DeserializableControl *pflusher) { pflusher->ensureData(sizeof(T)); value = pbuffer->GET(T); } typedef BasePVScalar BasePVBoolean; typedef BasePVScalar BasePVByte; typedef BasePVScalar BasePVShort; typedef BasePVScalar BasePVInt; typedef BasePVScalar BasePVLong; typedef BasePVScalar BasePVUByte; typedef BasePVScalar BasePVUShort; typedef BasePVScalar BasePVUInt; typedef BasePVScalar BasePVULong; typedef BasePVScalar BasePVFloat; typedef BasePVScalar BasePVDouble; // BasePVString is special case, since it implements SerializableArray class BasePVString : public PVString { public: typedef String value_type; typedef String* pointer; typedef const String* const_pointer; BasePVString(ScalarConstPtr const & scalar); virtual ~BasePVString(); virtual String get() const ; virtual void put(String val); virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const; virtual void deserialize(ByteBuffer *pbuffer, DeserializableControl *pflusher); virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const; private: String value; }; BasePVString::BasePVString(ScalarConstPtr const & scalar) : PVString(scalar),value() {} BasePVString::~BasePVString() {} String BasePVString::get() const { return value;} void BasePVString::put(String val) { value = val; postPut(); } void BasePVString::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const { SerializeHelper::serializeString(value, pbuffer, pflusher); } void BasePVString::deserialize(ByteBuffer *pbuffer, DeserializableControl *pflusher) { value = SerializeHelper::deserializeString(pbuffer, pflusher); } void BasePVString::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { // check bounds const size_t length = /*(value == null) ? 0 :*/ value.length(); /*if (offset < 0) offset = 0; else*/ if (offset > length) offset = length; //if (count < 0) count = length; const size_t maxCount = length - offset; if (count > maxCount) count = maxCount; // write SerializeHelper::serializeSubstring(value, offset, count, pbuffer, pflusher); } /** Default storage for arrays */ template class DefaultPVArray : public PVValueArray { public: typedef T* pointer; typedef const T* const_pointer; typedef std::vector vector; typedef const std::vector const_vector; typedef std::tr1::shared_ptr shared_vector; typedef ::epics::pvData::shared_vector svector; typedef ::epics::pvData::shared_vector const_svector; DefaultPVArray(ScalarArrayConstPtr const & scalarArray); virtual ~DefaultPVArray(); virtual size_t getLength() const {return value.size();} virtual size_t getCapacity() const {return value.capacity();} virtual void setCapacity(size_t capacity); virtual void setLength(size_t length); virtual const_svector view() const {return value;} virtual void swap(const_svector &other); virtual void replace(const const_svector& next); // from Serializable virtual void serialize(ByteBuffer *pbuffer,SerializableControl *pflusher) const; virtual void deserialize(ByteBuffer *pbuffer,DeserializableControl *pflusher); virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const; private: const_svector value; }; template DefaultPVArray::DefaultPVArray(ScalarArrayConstPtr const & scalarArray) : PVValueArray(scalarArray), value() { } template DefaultPVArray::~DefaultPVArray() { } template void DefaultPVArray::setCapacity(size_t capacity) { if(this->isCapacityMutable()) { value.reserve(capacity); } } template void DefaultPVArray::setLength(size_t length) { if(this->isImmutable()) THROW_EXCEPTION2(std::logic_error,"Immutable"); if(length == value.size()) return; else if(length < value.size()) value.slice(0, length); else value.resize(length); } template void DefaultPVArray::replace(const const_svector& next) { value = next; this->postPut(); } template void DefaultPVArray::swap(const_svector &other) { if(this->isImmutable()) THROW_EXCEPTION2(std::logic_error,"Immutable"); value.swap(other); } template void DefaultPVArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const { serialize(pbuffer, pflusher, 0, this->getLength()); } template void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t size = SerializeHelper::readSize(pbuffer, pcontrol); svector nextvalue(thaw(value)); nextvalue.resize(size); // TODO: avoid copy of stuff we will then overwrite T* cur = nextvalue.data(); // try to avoid deserializing from the buffer // this is only possible if we do not need to do endian-swapping if (!pbuffer->reverse()) if (pcontrol->directDeserialize(pbuffer, (char*)cur, size, sizeof(T))) { // inform about the change? PVField::postPut(); return; } // retrieve value from the buffer size_t remaining = size; while(remaining) { const size_t have_bytes = pbuffer->getRemaining(); // correctly rounds down in an element is partially received const size_t available = have_bytes/sizeof(T); if(available == 0) { // get at least one element pcontrol->ensureData(sizeof(T)); continue; } const size_t n2read = std::min(remaining, available); pbuffer->getArray(cur, n2read); cur += n2read; remaining -= n2read; } value = freeze(nextvalue); // inform about the change? PVField::postPut(); } template void DefaultPVArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { //TODO: avoid incrementing the ref counter... const_svector temp(value); temp.slice(offset, count); count = temp.size(); SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); const T* cur = temp.data(); // try to avoid copying into the buffer // this is only possible if we do not need to do endian-swapping if (!pbuffer->reverse()) if (pflusher->directSerialize(pbuffer, (const char*)cur, count, sizeof(T))) return; while(count) { const size_t empty = pbuffer->getRemaining(); const size_t space_for = empty/sizeof(T); if(space_for==0) { pflusher->flushSerializeBuffer(); // Can we be certain that more space is now free??? // If not then we spinnnnnnnnn continue; } const size_t n2send = std::min(count, space_for); pbuffer->putArray(cur, n2send); cur += n2send; count -= n2send; } } // specializations for String template<> void DefaultPVArray::deserialize(ByteBuffer *pbuffer, DeserializableControl *pcontrol) { size_t size = SerializeHelper::readSize(pbuffer, pcontrol); svector nextvalue(thaw(value)); // Decide if we must re-allocate if(size > nextvalue.size() || !nextvalue.unique()) nextvalue.resize(size); else if(size < nextvalue.size()) nextvalue.slice(0, size); String * pvalue = nextvalue.data(); for(size_t i = 0; i void DefaultPVArray::serialize(ByteBuffer *pbuffer, SerializableControl *pflusher, size_t offset, size_t count) const { const_svector temp(value); temp.slice(offset, count); SerializeHelper::writeSize(temp.size(), pbuffer, pflusher); const String * pvalue = temp.data(); for(size_t i = 0; i DefaultPVBooleanArray; typedef DefaultPVArray BasePVByteArray; typedef DefaultPVArray BasePVShortArray; typedef DefaultPVArray BasePVIntArray; typedef DefaultPVArray BasePVLongArray; typedef DefaultPVArray BasePVUByteArray; typedef DefaultPVArray BasePVUShortArray; typedef DefaultPVArray BasePVUIntArray; typedef DefaultPVArray BasePVULongArray; typedef DefaultPVArray BasePVFloatArray; typedef DefaultPVArray BasePVDoubleArray; typedef DefaultPVArray BasePVStringArray; // Factory PVDataCreate::PVDataCreate() : fieldCreate(getFieldCreate()) { } PVFieldPtr PVDataCreate::createPVField(FieldConstPtr const & field) { switch(field->getType()) { case scalar: { ScalarConstPtr xx = static_pointer_cast(field); return createPVScalar(xx); } case scalarArray: { ScalarArrayConstPtr xx = static_pointer_cast(field); return createPVScalarArray(xx); } case structure: { StructureConstPtr xx = static_pointer_cast(field); return createPVStructure(xx); } case structureArray: { StructureArrayConstPtr xx = static_pointer_cast(field); return createPVStructureArray(xx); } case union_: { UnionConstPtr xx = static_pointer_cast(field); return createPVUnion(xx); } case unionArray: { UnionArrayConstPtr xx = static_pointer_cast(field); return createPVUnionArray(xx); } } throw std::logic_error("PVDataCreate::createPVField should never get here"); } PVFieldPtr PVDataCreate::createPVField(PVFieldPtr const & fieldToClone) { switch(fieldToClone->getField()->getType()) { case scalar: { PVScalarPtr pvScalar = static_pointer_cast(fieldToClone); return createPVScalar(pvScalar); } case scalarArray: { PVScalarArrayPtr pvScalarArray = static_pointer_cast(fieldToClone); return createPVScalarArray(pvScalarArray); } case structure: { PVStructurePtr pvStructure = static_pointer_cast(fieldToClone); StringArray const & fieldNames = pvStructure->getStructure()->getFieldNames(); PVFieldPtrArray pvFieldPtrArray = pvStructure->getPVFields(); return createPVStructure(fieldNames,pvFieldPtrArray); } case structureArray: { PVStructureArrayPtr from = static_pointer_cast(fieldToClone); StructureArrayConstPtr structureArray = from->getStructureArray(); PVStructureArrayPtr to = createPVStructureArray( structureArray); getConvert()->copyStructureArray(from, to); return to; } case union_: { PVUnionPtr pvUnion = static_pointer_cast(fieldToClone); return createPVUnion(pvUnion); } case unionArray: { PVUnionArrayPtr from = static_pointer_cast(fieldToClone); UnionArrayConstPtr unionArray = from->getUnionArray(); PVUnionArrayPtr to = createPVUnionArray(unionArray); getConvert()->copyUnionArray(from, to); return to; } } throw std::logic_error("PVDataCreate::createPVField should never get here"); } PVScalarPtr PVDataCreate::createPVScalar(ScalarConstPtr const & scalar) { ScalarType scalarType = scalar->getScalarType(); switch(scalarType) { case pvBoolean: return PVScalarPtr(new BasePVBoolean(scalar)); case pvByte: return PVScalarPtr(new BasePVByte(scalar)); case pvShort: return PVScalarPtr(new BasePVShort(scalar)); case pvInt: return PVScalarPtr(new BasePVInt(scalar)); case pvLong: return PVScalarPtr(new BasePVLong(scalar)); case pvUByte: return PVScalarPtr(new BasePVUByte(scalar)); case pvUShort: return PVScalarPtr(new BasePVUShort(scalar)); case pvUInt: return PVScalarPtr(new BasePVUInt(scalar)); case pvULong: return PVScalarPtr(new BasePVULong(scalar)); case pvFloat: return PVScalarPtr(new BasePVFloat(scalar)); case pvDouble: return PVScalarPtr(new BasePVDouble(scalar)); case pvString: return PVScalarPtr(new BasePVString(scalar)); } throw std::logic_error("PVDataCreate::createPVScalar should never get here"); } PVScalarPtr PVDataCreate::createPVScalar(ScalarType scalarType) { ScalarConstPtr scalar = fieldCreate->createScalar(scalarType); return createPVScalar(scalar); } PVScalarPtr PVDataCreate::createPVScalar(PVScalarPtr const & scalarToClone) { ScalarType scalarType = scalarToClone->getScalar()->getScalarType(); PVScalarPtr pvScalar = createPVScalar(scalarType); getConvert()->copyScalar(scalarToClone, pvScalar); PVAuxInfoPtr from = scalarToClone->getPVAuxInfo(); PVAuxInfoPtr to = pvScalar->getPVAuxInfo(); PVAuxInfo::PVInfoMap & map = from->getInfoMap(); for(PVAuxInfo::PVInfoIter iter = map.begin(); iter!= map.end(); ++iter) { String key = iter->first; PVScalarPtr pvFrom = iter->second; ScalarConstPtr scalar = pvFrom->getScalar(); PVScalarPtr pvTo = to->createInfo(key,scalar->getScalarType()); getConvert()->copyScalar(pvFrom,pvTo); } return pvScalar; } PVScalarArrayPtr PVDataCreate::createPVScalarArray( ScalarArrayConstPtr const & scalarArray) { switch(scalarArray->getElementType()) { case pvBoolean: return PVScalarArrayPtr(new DefaultPVBooleanArray(scalarArray)); case pvByte: return PVScalarArrayPtr(new BasePVByteArray(scalarArray)); case pvShort: return PVScalarArrayPtr(new BasePVShortArray(scalarArray)); case pvInt: return PVScalarArrayPtr(new BasePVIntArray(scalarArray)); case pvLong: return PVScalarArrayPtr(new BasePVLongArray(scalarArray)); case pvUByte: return PVScalarArrayPtr(new BasePVUByteArray(scalarArray)); case pvUShort: return PVScalarArrayPtr(new BasePVUShortArray(scalarArray)); case pvUInt: return PVScalarArrayPtr(new BasePVUIntArray(scalarArray)); case pvULong: return PVScalarArrayPtr(new BasePVULongArray(scalarArray)); case pvFloat: return PVScalarArrayPtr(new BasePVFloatArray(scalarArray)); case pvDouble: return PVScalarArrayPtr(new BasePVDoubleArray(scalarArray)); case pvString: return PVScalarArrayPtr(new BasePVStringArray(scalarArray)); } throw std::logic_error("PVDataCreate::createPVScalarArray should never get here"); } PVScalarArrayPtr PVDataCreate::createPVScalarArray( ScalarType elementType) { ScalarArrayConstPtr scalarArray = fieldCreate->createScalarArray(elementType); return createPVScalarArray(scalarArray); } PVScalarArrayPtr PVDataCreate::createPVScalarArray( PVScalarArrayPtr const & arrayToClone) { PVScalarArrayPtr pvArray = createPVScalarArray( arrayToClone->getScalarArray()->getElementType()); pvArray->assign(*arrayToClone.get()); PVAuxInfoPtr from = arrayToClone->getPVAuxInfo(); PVAuxInfoPtr to = pvArray->getPVAuxInfo(); PVAuxInfo::PVInfoMap & map = from->getInfoMap(); for(PVAuxInfo::PVInfoIter iter = map.begin(); iter!= map.end(); ++iter) { String key = iter->first; PVScalarPtr pvFrom = iter->second; ScalarConstPtr scalar = pvFrom->getScalar(); PVScalarPtr pvTo = to->createInfo(key,scalar->getScalarType()); getConvert()->copyScalar(pvFrom,pvTo); } return pvArray; } PVStructureArrayPtr PVDataCreate::createPVStructureArray( StructureArrayConstPtr const & structureArray) { return PVStructureArrayPtr(new PVStructureArray(structureArray)); } PVStructurePtr PVDataCreate::createPVStructure( StructureConstPtr const & structure) { return PVStructurePtr(new PVStructure(structure)); } PVUnionArrayPtr PVDataCreate::createPVUnionArray( UnionArrayConstPtr const & unionArray) { return PVUnionArrayPtr(new PVUnionArray(unionArray)); } PVUnionPtr PVDataCreate::createPVUnion( UnionConstPtr const & punion) { return PVUnionPtr(new PVUnion(punion)); } PVUnionPtr PVDataCreate::createPVVariantUnion() { return PVUnionPtr(new PVUnion(fieldCreate->createVariantUnion())); } PVUnionArrayPtr PVDataCreate::createPVVariantUnionArray() { return PVUnionArrayPtr(new PVUnionArray(fieldCreate->createVariantUnionArray())); } PVStructurePtr PVDataCreate::createPVStructure( StringArray const & fieldNames,PVFieldPtrArray const & pvFields) { size_t num = fieldNames.size(); FieldConstPtrArray fields(num); for (size_t i=0;igetField(); StructureConstPtr structure = fieldCreate->createStructure(fieldNames,fields); PVStructurePtr pvStructure(new PVStructure(structure,pvFields)); return pvStructure; } PVStructurePtr PVDataCreate::createPVStructure(PVStructurePtr const & structToClone) { FieldConstPtrArray field; if(structToClone==0) { // is this correct?! FieldConstPtrArray fields(0); StringArray fieldNames(0); StructureConstPtr structure = fieldCreate->createStructure(fieldNames,fields); return PVStructurePtr(new PVStructure(structure)); } StructureConstPtr structure = structToClone->getStructure(); PVStructurePtr pvStructure(new PVStructure(structure)); getConvert()->copyStructure(structToClone,pvStructure); return pvStructure; } PVUnionPtr PVDataCreate::createPVUnion(PVUnionPtr const & unionToClone) { PVUnionPtr punion(new PVUnion(unionToClone->getUnion())); // set cloned value punion->set(unionToClone->getSelectedIndex(), createPVField(unionToClone->get())); return punion; } // TODO not thread-safe (local static initializers) // TODO replace with non-locking singleton pattern PVDataCreatePtr PVDataCreate::getPVDataCreate() { static PVDataCreatePtr pvDataCreate; static Mutex mutex; Lock xx(mutex); if(pvDataCreate.get()==0) pvDataCreate = PVDataCreatePtr(new PVDataCreate()); return pvDataCreate; } PVDataCreatePtr getPVDataCreate() { return PVDataCreate::getPVDataCreate(); } }}