/* Convert.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 #include #include #include #include #include using std::tr1::static_pointer_cast; using std::size_t; namespace epics { namespace pvData { static std::vector split(String commaSeparatedList) { String::size_type numValues = 1; String::size_type index=0; while(true) { String::size_type pos = commaSeparatedList.find(',',index); if(pos==String::npos) break; numValues++; index = pos +1; } std::vector valueList(numValues,""); index=0; for(size_t i=0; igetPVFields(); if (fieldsData.size() != 0) { size_t length = pvStructure->getStructure()->getNumberFields(); for(size_t i=0; igetField()->getType(); if(type==structure) { PVStructurePtr pv = static_pointer_cast(fieldField); size_t count = fromString(pv, from, fromStartIndex); processed += count; fromStartIndex += count; } else if(type==scalarArray) { PVScalarArrayPtr pv = static_pointer_cast(fieldField); size_t count = fromString(pv, from[fromStartIndex]); processed += count; fromStartIndex += count; } else if(type==scalar) { PVScalarPtr pv = static_pointer_cast(fieldField); fromString(pv, from[fromStartIndex++]); processed++; } else { // union, structureArray, unionArray not supported String message("Convert::fromString unsupported fieldType "); TypeFunc::toString(&message,type); throw std::logic_error(message); } } } return processed; } size_t Convert::fromString(PVScalarArrayPtr const &pv, String from) { if(from[0]=='[' && from[from.length()]==']') { size_t offset = from.rfind(']'); from = from.substr(1, offset); } std::vector valueList(split(from)); size_t length = valueList.size(); size_t num = fromStringArray(pv,0,length,valueList,0); if(numsetLength(length); return length; } size_t Convert::fromStringArray(PVScalarArrayPtr const &pv, size_t offset, size_t length, StringArray const & from, size_t fromOffset) { size_t alen = pv->getLength(); if(offset==0 && length>=alen) { // replace all existing elements assert(from.size()>=fromOffset+length); PVStringArray::svector data(length); std::copy(from.begin()+fromOffset, from.begin()+fromOffset+length, data.begin()); PVStringArray::const_svector temp(freeze(data)); pv->putFrom(temp); return length; } else { // partial update. throw std::runtime_error("fromStringArray: partial update not implemented"); } } size_t Convert::toStringArray(PVScalarArrayPtr const & pv, size_t offset, size_t length, StringArray &to, size_t toOffset) { PVStringArray::const_svector data; pv->getAs(data); data.slice(offset, length); if(toOffset+data.size() > to.size()) to.resize(toOffset+data.size()); std::copy(data.begin()+toOffset, data.end(), to.begin()); return data.size(); } bool Convert::isCopyCompatible(FieldConstPtr const &from, FieldConstPtr const &to) { if(from->getType()!=to->getType()) return false; switch(from->getType()) { case scalar: { ScalarConstPtr xxx = static_pointer_cast(from); ScalarConstPtr yyy = static_pointer_cast(to); return isCopyScalarCompatible(xxx,yyy); } case scalarArray: { ScalarArrayConstPtr xxx = static_pointer_cast(from); ScalarArrayConstPtr yyy = static_pointer_cast(to); return isCopyScalarArrayCompatible(xxx,yyy); } case structure: { StructureConstPtr xxx = static_pointer_cast(from); StructureConstPtr yyy = static_pointer_cast(to); return isCopyStructureCompatible(xxx,yyy); } case structureArray: { StructureArrayConstPtr xxx = static_pointer_cast(from); StructureArrayConstPtr yyy = static_pointer_cast(to); return isCopyStructureArrayCompatible(xxx,yyy); } case union_: { UnionConstPtr xxx = static_pointer_cast(from); UnionConstPtr yyy = static_pointer_cast(to); return isCopyUnionCompatible(xxx,yyy); } case unionArray: { UnionArrayConstPtr xxx = static_pointer_cast(from); UnionArrayConstPtr yyy = static_pointer_cast(to); return isCopyUnionArrayCompatible(xxx,yyy); } } String message("Convert::isCopyCompatible should never get here"); throw std::logic_error(message); } void Convert::copy(PVFieldPtr const & from, PVFieldPtr const & to) { switch(from->getField()->getType()) { case scalar: { PVScalarPtr xxx = static_pointer_cast(from); PVScalarPtr yyy = static_pointer_cast(to); copyScalar(xxx,yyy); return; } case scalarArray: { PVScalarArrayPtr fromArray = static_pointer_cast(from); PVScalarArrayPtr toArray = static_pointer_cast(to); toArray->assign(*fromArray.get()); return; } case structure: { PVStructurePtr xxx = static_pointer_cast(from); PVStructurePtr yyy = static_pointer_cast(to); copyStructure(xxx,yyy); return; } case structureArray: { PVStructureArrayPtr fromArray = static_pointer_cast(from); PVStructureArrayPtr toArray = static_pointer_cast(to); copyStructureArray(fromArray,toArray); return; } case union_: { PVUnionPtr xxx = static_pointer_cast(from); PVUnionPtr yyy = static_pointer_cast(to); copyUnion(xxx,yyy); return; } case unionArray: { PVUnionArrayPtr fromArray = static_pointer_cast(from); PVUnionArrayPtr toArray = static_pointer_cast(to); copyUnionArray(fromArray,toArray); return; } } } bool Convert::isCopyScalarCompatible( ScalarConstPtr const & fromField, ScalarConstPtr const & toField) { ScalarType fromScalarType = fromField->getScalarType(); ScalarType toScalarType = toField->getScalarType(); if(fromScalarType==toScalarType) return true; if(ScalarTypeFunc::isNumeric(fromScalarType) && ScalarTypeFunc::isNumeric(toScalarType)) return true; if(fromScalarType==pvString) return true; if(toScalarType==pvString) return true; return false; } void Convert::copyScalar(PVScalarPtr const & from, PVScalarPtr const & to) { if(to->isImmutable()) { if(from==to) return; String message("Convert.copyScalar destination is immutable"); throw std::invalid_argument(message); } to->assign(*from.get()); } bool Convert::isCopyScalarArrayCompatible(ScalarArrayConstPtr const &fromArray, ScalarArrayConstPtr const &toArray) { ScalarType fromType = fromArray->getElementType(); ScalarType toType = toArray->getElementType(); if(fromType==toType) return true; if(ScalarTypeFunc::isNumeric(fromType) && ScalarTypeFunc::isNumeric(toType)) return true; if(toType==pvString) return true; if(fromType==pvString) return true; return false; } bool Convert::isCopyStructureCompatible( StructureConstPtr const &fromStruct, StructureConstPtr const &toStruct) { FieldConstPtrArray fromFields = fromStruct->getFields(); FieldConstPtrArray toFields = toStruct->getFields(); size_t length = fromStruct->getNumberFields(); if(length!=toStruct->getNumberFields()) return false; for(size_t i=0; igetType(); Type toType = to->getType(); if(fromType!=toType) return false; switch(fromType) { case scalar: { ScalarConstPtr xxx = static_pointer_cast(from); ScalarConstPtr yyy = static_pointer_cast(to); if(!isCopyScalarCompatible(xxx,yyy)) return false; } break; case scalarArray: { ScalarArrayConstPtr xxx = static_pointer_cast(from); ScalarArrayConstPtr yyy = static_pointer_cast(to); if(!isCopyScalarArrayCompatible(xxx,yyy)) return false; } break; case structure: { StructureConstPtr xxx = static_pointer_cast(from); StructureConstPtr yyy = static_pointer_cast(to); if(!isCopyStructureCompatible(xxx,yyy)) return false; } break; case structureArray: { StructureArrayConstPtr xxx = static_pointer_cast(from); StructureArrayConstPtr yyy = static_pointer_cast(to); if(!isCopyStructureArrayCompatible(xxx,yyy)) return false; } case union_: { UnionConstPtr xxx = static_pointer_cast(from); UnionConstPtr yyy = static_pointer_cast(to); if(!isCopyUnionCompatible(xxx,yyy)) return false; } break; case unionArray: { UnionArrayConstPtr xxx = static_pointer_cast(from); UnionArrayConstPtr yyy = static_pointer_cast(to); if(!isCopyUnionArrayCompatible(xxx,yyy)) return false; } break; } } return true; } void Convert::copyStructure(PVStructurePtr const & from, PVStructurePtr const & to) { if(to->isImmutable()) { if(from==to) return; throw std::invalid_argument("Convert.copyStructure destination is immutable"); } if(from==to) return; PVFieldPtrArray const & fromDatas = from->getPVFields(); PVFieldPtrArray const & toDatas = to->getPVFields(); if(from->getStructure()->getNumberFields() != to->getStructure()->getNumberFields()) { String message("Convert.copyStructure Illegal copyStructure"); throw std::invalid_argument(message); } size_t numberFields = from->getStructure()->getNumberFields(); if(numberFields>=2) { String name0 = fromDatas[0]->getFieldName(); String name1 = fromDatas[1]->getFieldName(); // look for enumerated structure and copy choices first if(name0.compare("index")==0 && name1.compare("choices")==0) { FieldConstPtr fieldIndex = fromDatas[0]->getField(); FieldConstPtr fieldChoices = fromDatas[1]->getField(); if(fieldIndex->getType()==scalar && fieldChoices->getType()==scalarArray) { PVScalarPtr pvScalar = static_pointer_cast(fromDatas[0]); PVScalarArrayPtr pvArray = static_pointer_cast(fromDatas[1]); if((pvScalar->getScalar()->getScalarType()==pvInt) && (pvArray->getScalarArray()->getElementType()==pvString)) { PVScalarArrayPtr toArray = static_pointer_cast(toDatas[1]); toArray->assign(*pvArray.get()); PVScalarPtr toScalar = static_pointer_cast(toDatas[0]); copyScalar(pvScalar,toScalar); return; } } } } for(size_t i=0; i < numberFields; i++) { PVFieldPtr fromData = fromDatas[i]; PVFieldPtr toData = toDatas[i]; Type fromType = fromData->getField()->getType(); Type toType = toData->getField()->getType(); if(fromType!=toType) { String message("Convert.copyStructure Illegal copyStructure"); throw std::invalid_argument(message); } if(toData->isImmutable()) { if(fromData==toData) return; throw std::invalid_argument("Convert.copyStructure destination is immutable"); } switch(fromType) { case scalar: { PVScalarPtr xxx = static_pointer_cast(fromData); PVScalarPtr yyy = static_pointer_cast(toData); copyScalar(xxx,yyy); break; } case scalarArray: { PVScalarArrayPtr fromArray = static_pointer_cast(fromData); PVScalarArrayPtr toArray = static_pointer_cast(toData); toArray->assign(*fromArray.get()); break; } case structure: { PVStructurePtr xxx = static_pointer_cast(fromData); PVStructurePtr yyy = static_pointer_cast(toData); copyStructure(xxx,yyy); break; } case structureArray: { PVStructureArrayPtr fromArray = static_pointer_cast(fromData); PVStructureArrayPtr toArray = static_pointer_cast(toData); copyStructureArray(fromArray,toArray); break; } case union_: { PVUnionPtr xxx = static_pointer_cast(fromData); PVUnionPtr yyy = static_pointer_cast(toData); copyUnion(xxx,yyy); break; } case unionArray: { PVUnionArrayPtr fromArray = static_pointer_cast(fromData); PVUnionArrayPtr toArray = static_pointer_cast(toData); copyUnionArray(fromArray,toArray); break; } } } } bool Convert::isCopyUnionCompatible( UnionConstPtr const &from, UnionConstPtr const &to) { return *(from.get()) == *(to.get()); } void Convert::copyUnion(PVUnionPtr const & from, PVUnionPtr const & to) { if(to->isImmutable()) { if(from==to) return; throw std::invalid_argument("Convert.copyUnion destination is immutable"); } if(from==to) return; if(!isCopyUnionCompatible(from->getUnion(), to->getUnion())) { throw std::invalid_argument("Illegal copyUnion"); } PVFieldPtr fromValue = from->get(); if (from->getUnion()->isVariant()) { if (fromValue.get() == 0) to->set(PVFieldPtr()); else to->set(getPVDataCreate()->createPVField(fromValue)); // clone value // TODO } else { if (fromValue.get() == 0) to->select(PVUnion::UNDEFINED_INDEX); else copy(fromValue, to->select(from->getSelectedIndex())); } } bool Convert::isCopyStructureArrayCompatible( StructureArrayConstPtr const &from, StructureArrayConstPtr const &to) { StructureConstPtr xxx = from->getStructure(); StructureConstPtr yyy = to->getStructure(); return isCopyStructureCompatible(xxx,yyy); } void Convert::copyStructureArray( PVStructureArrayPtr const & from, PVStructureArrayPtr const & to) { if(from==to) { return; } else if(to->isImmutable()) { throw std::invalid_argument("Convert.copyStructureArray destination is immutable"); } to->replace(from->view()); } bool Convert::isCopyUnionArrayCompatible( UnionArrayConstPtr const &from, UnionArrayConstPtr const &to) { UnionConstPtr xxx = from->getUnion(); UnionConstPtr yyy = to->getUnion(); return isCopyUnionCompatible(xxx,yyy); } void Convert::copyUnionArray( PVUnionArrayPtr const & from, PVUnionArrayPtr const & to) { if(from==to) { return; } else if(to->isImmutable()) { throw std::invalid_argument("Convert.copyUnionArray destination is immutable"); } to->replace(from->view()); } void Convert::newLine(StringBuilder buffer, int indentLevel) { *buffer += "\n"; *buffer += String(indentLevel*4, ' '); } ConvertPtr Convert::getConvert() { static ConvertPtr convert; static Mutex mutex; Lock xx(mutex); if(convert.get()==0) { convert = ConvertPtr(new Convert()); } return convert; } }}