14 #include <epicsThread.h> 15 #include <pv/pvData.h> 16 #include <pv/bitSet.h> 17 #include <pv/thread.h> 19 #define epicsExportSharedSymbols 23 using std::tr1::static_pointer_cast;
24 using std::tr1::dynamic_pointer_cast;
32 namespace epics {
namespace pvCopy {
40 static void newLine(
string *buffer,
int indentLevel)
43 *buffer += string(indentLevel*4,
' ');
47 static StructureConstPtr NULLStructure;
48 static PVStructurePtr NULLPVStructure;
56 PVFieldPtr masterPVField;
58 size_t structureOffset;
60 PVStructurePtr options;
61 vector<PVFilterPtr> pvFilters;
69 struct CopyStructureNode :
public CopyNode {
70 CopyNodePtrArrayPtr nodes;
74 PVStructurePtr
const &pvMaster,
75 PVStructurePtr
const &pvRequest,
76 string const & structureName)
78 PVStructurePtr pvStructure(pvRequest);
79 if(structureName.size()>0) {
80 if(pvStructure->getStructure()->getNumberFields()>0) {
81 pvStructure = pvRequest->getSubField<PVStructure>(structureName);
82 if(!pvStructure)
return NULLPVCopy;
84 }
else if(pvRequest->getSubField<PVStructure>(
"field")) {
85 pvStructure = pvRequest->getSubField<PVStructure>(
"field");
88 bool result = pvCopy->init(pvStructure);
90 pvCopy->traverseMasterInitPlugin();
94 PVStructurePtr PVCopy::getPVMaster()
101 traverseMaster(headNode,callback);
104 StructureConstPtr PVCopy::getStructure()
109 PVStructurePtr PVCopy::createPVStructure()
111 if(cacheInitStructure) {
112 PVStructurePtr save = cacheInitStructure;
113 cacheInitStructure.reset();
116 PVStructurePtr pvStructure =
117 getPVDataCreate()->createPVStructure(structure);
122 size_t PVCopy::getCopyOffset(PVFieldPtr
const &masterPVField)
124 if(!headNode->isStructure) {
125 CopyNodePtr node = static_pointer_cast<CopyNode>(headNode);
126 if((node->masterPVField.get())==masterPVField.get()) {
127 return headNode->structureOffset;
129 PVStructure * parent = masterPVField->getParent();
130 size_t offsetParent = parent->getFieldOffset();
131 size_t off = masterPVField->getFieldOffset();
132 size_t offdiff = off -offsetParent;
133 if(offdiff<node->nfields)
return headNode->structureOffset + offdiff;
137 CopyNodePtr node = getCopyOffset(structNode,masterPVField);
138 if(node)
return node->structureOffset;
142 size_t PVCopy::getCopyOffset(
143 PVStructurePtr
const &masterPVStructure,
144 PVFieldPtr
const &masterPVField)
147 if(!headNode->isStructure) {
148 node = static_pointer_cast<CopyNode>(headNode);
149 if(node->masterPVField.get()!=masterPVStructure.get())
return string::npos;
152 node = getCopyOffset(snode,masterPVField);
154 if(!node)
return string::npos;
155 size_t diff = masterPVField->getFieldOffset()
156 - masterPVStructure->getFieldOffset();
157 return node->structureOffset + diff;
160 PVFieldPtr PVCopy::getMasterPVField(
size_t structureOffset)
163 if(!headNode->isStructure) {
167 node = getMasterNode(snode,structureOffset);
170 throw std::logic_error(
171 "PVCopy::getMasterPVField: structureOffset not valid");
173 size_t diff = structureOffset - node->structureOffset;
174 PVFieldPtr pvMasterField = node->masterPVField;
175 if(diff==0)
return pvMasterField;
176 PVStructurePtr pvStructure
177 = static_pointer_cast<PVStructure>(pvMasterField);
178 return pvStructure->getSubField(
179 pvMasterField->getFieldOffset() + diff);
182 void PVCopy::initCopy(
183 PVStructurePtr
const ©PVStructure,
184 BitSetPtr
const &bitSet)
186 for(
size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
189 updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
193 bool PVCopy::updateCopySetBitSet(
194 PVStructurePtr
const ©PVStructure,
195 BitSetPtr
const &bitSet)
197 updateCopySetBitSet(copyPVStructure,headNode,bitSet);
198 return checkIgnore(copyPVStructure,bitSet);
201 bool PVCopy::updateCopyFromBitSet(
202 PVStructurePtr
const ©PVStructure,
203 BitSetPtr
const &bitSet)
206 for(
size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
210 updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
211 return checkIgnore(copyPVStructure,bitSet);
214 void PVCopy::updateMasterField(
216 PVFieldPtr
const & pvCopy,
217 PVFieldPtr
const &pvMaster,
218 BitSetPtr
const &bitSet)
221 for(
size_t i=0; i< node->pvFilters.size(); ++i) {
223 if(pvFilter->filter(pvCopy,bitSet,
false)) result =
true;
226 pvMaster->copyUnchecked(*pvCopy);
229 void PVCopy::updateMasterCheckBitSet(
230 PVStructurePtr
const ©PVStructure,
231 BitSetPtr
const &bitSet,
234 if(!bitSet->get(nextSet)) {
235 size_t next = bitSet->nextSetBit(nextSet);
236 if(next==string::npos)
return;
237 updateMasterCheckBitSet(copyPVStructure,bitSet,next);
240 PVFieldPtr pvField = copyPVStructure;
241 if(nextSet!=0) pvField = copyPVStructure->getSubField(nextSet);
242 if(pvField->getField()->getType()==epics::pvData::structure) {
243 bitSet->clear(nextSet);
244 PVStructurePtr pv = static_pointer_cast<PVStructure>(pvField);
245 PVFieldPtrArray pvFieldArray = pv->getPVFields();
246 for(
size_t i=0; i<pvFieldArray.size(); ++i) {
247 PVFieldPtr pvField = pvFieldArray[i];
248 bitSet->set(pvField->getFieldOffset());
251 size_t next = bitSet->nextSetBit(nextSet+1);
252 if(next==string::npos)
return;
253 updateMasterCheckBitSet(copyPVStructure,bitSet,next);
256 CopyNodePtr PVCopy::getCopyNode(std::size_t fieldOffset)
258 if(fieldOffset==0)
return headNode;
261 if(!node->isStructure)
return node;
263 CopyNodePtrArrayPtr nodes = structNode->nodes;
264 bool okToContinue =
false;
265 for(
size_t i=0; i< nodes->size(); i++) {
267 size_t soff = node->structureOffset;
268 if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
273 if(okToContinue)
continue;
275 throw std::logic_error(
"PVCopy::getCopyNode fieldOffset not valid");
279 void PVCopy::updateMaster(
280 PVStructurePtr
const ©PVStructure,
281 BitSetPtr
const &bitSet)
283 updateMasterCheckBitSet(copyPVStructure,bitSet,0);
286 nextSet = bitSet->nextSetBit(nextSet);
287 if(nextSet==string::npos)
return;
288 PVFieldPtr pvCopy = copyPVStructure->getSubField(nextSet);
289 PVFieldPtr pvMaster = headNode->masterPVField;
290 if(pvMaster->getField()->getType()==epics::pvData::structure) {
291 PVStructurePtr pv = static_pointer_cast<PVStructure>(pvMaster);
292 pvMaster = pv->getSubField(pvCopy->getFullName());
294 updateMasterField(getCopyNode(nextSet),pvCopy,pvMaster,bitSet);
295 bitSet->clear(nextSet);
299 PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
301 if(fieldOffset==0)
return headNode->options;
304 if(node->structureOffset==fieldOffset)
return node->options;
305 if(!node->isStructure)
return NULLPVStructure;
307 CopyNodePtrArrayPtr nodes = structNode->nodes;
308 bool okToContinue =
false;
309 for(
size_t i=0; i< nodes->size(); i++) {
311 size_t soff = node->structureOffset;
312 if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
313 if(fieldOffset==soff)
return node->options;
314 if(!node->isStructure) {
315 return NULLPVStructure;
321 if(okToContinue)
continue;
322 throw std::logic_error(
"PVCopy::getOptions logic error: fieldOffset not valid");
326 string PVCopy::dump()
329 dump(&builder,headNode,0);
333 void PVCopy::traverseMaster(
338 if(!node->isStructure) {
339 callback->nextMasterPVField(node->masterPVField);
343 CopyNodePtrArrayPtr nodes = structNode->nodes;
344 for(
size_t i=0; i< nodes->size(); i++) {
346 traverseMaster(node,callback);
350 void PVCopy::updateCopySetBitSet(
351 PVFieldPtr
const & pvCopy,
352 PVFieldPtr
const & pvMaster,
353 BitSetPtr
const & bitSet)
355 if(pvCopy->getField()->getType()!=epics::pvData::structure) {
356 if(*pvCopy==*pvMaster)
return;
357 pvCopy->copy(*pvMaster);
358 bitSet->set(pvCopy->getFieldOffset());
361 PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
362 PVFieldPtrArray
const & pvCopyFields = pvCopyStructure->getPVFields();
363 for(
size_t i=0; i<pvCopyFields.size(); ++i) {
364 PVFieldPtr master = getMasterPVField(pvCopyFields[i]->getFieldOffset());
365 updateCopySetBitSet(pvCopyFields[i],master,bitSet);
369 void PVCopy::updateCopySetBitSet(
370 PVFieldPtr
const & pvCopy,
372 BitSetPtr
const & bitSet)
375 for(
size_t i=0; i< node->pvFilters.size(); ++i) {
377 if(pvFilter->filter(pvCopy,bitSet,
true)) result =
true;
379 if(!node->isStructure) {
381 updateCopySetBitSet(pvCopy,node->masterPVField,bitSet);
385 PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
386 PVFieldPtrArray
const & pvCopyFields = pvCopyStructure->getPVFields();
387 for(
size_t i=0; i<pvCopyFields.size(); ++i) {
388 updateCopySetBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
393 void PVCopy::updateCopyFromBitSet(
394 PVFieldPtr
const & pvCopy,
396 BitSetPtr
const & bitSet)
399 bool update = bitSet->get(pvCopy->getFieldOffset());
401 for(
size_t i=0; i< node->pvFilters.size(); ++i) {
403 if(pvFilter->filter(pvCopy,bitSet,
true)) result =
true;
406 if(!node->isStructure) {
408 PVFieldPtr pvMaster = node->masterPVField;
409 pvCopy->copy(*pvMaster);
413 size_t offset = structureNode->structureOffset;
414 size_t nextSet = bitSet->nextSetBit(offset);
415 if(nextSet==string::npos)
return;
416 if(offset>=pvCopy->getNextFieldOffset())
return;
417 PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
418 PVFieldPtrArray
const & pvCopyFields = pvCopyStructure->getPVFields();
419 for(
size_t i=0; i<pvCopyFields.size(); ++i) {
420 updateCopyFromBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
425 PVStructurePtr
const &pvMaster)
430 bool PVCopy::init(epics::pvData::PVStructurePtr
const &pvRequest)
432 PVStructurePtr pvMasterStructure = pvMaster;
433 size_t len = pvRequest->getPVFields().size();
434 bool entireMaster =
false;
435 PVStructurePtr pvOptions;
442 PVStructurePtr masterFieldPtr = pvMaster->getSubField<PVStructure>(
"_");
443 PVStructurePtr requestFieldPtr = pvRequest->getSubField<PVStructure>(
"_");
444 if (!masterFieldPtr && requestFieldPtr) {
446 pvOptions = requestFieldPtr->getSubField<PVStructure>(
"_options");
450 structure = pvMasterStructure->getStructure();
453 node->options = pvOptions;
454 node->isStructure =
false;
455 node->structureOffset = 0;
456 node->masterPVField = pvMasterStructure;
457 node->nfields = pvMasterStructure->getNumberFields();
460 structure = createStructure(pvMasterStructure,pvRequest);
461 if(!structure)
return false;
462 cacheInitStructure = createPVStructure();
463 ignorechangeBitSet = BitSetPtr(
new BitSet(cacheInitStructure->getNumberFields()));
464 headNode = createStructureNodes(
472 StructureConstPtr PVCopy::createStructure(
473 PVStructurePtr
const &pvMaster,
474 PVStructurePtr
const &pvFromRequest)
476 if(pvFromRequest->getStructure()->getNumberFields()==0) {
477 return pvMaster->getStructure();
479 PVFieldPtrArray
const &pvFromRequestFields = pvFromRequest->getPVFields();
480 StringArray
const &fromRequestFieldNames = pvFromRequest->getStructure()->getFieldNames();
481 size_t length = pvFromRequestFields.size();
482 if(length==0)
return NULLStructure;
483 FieldConstPtrArray fields; fields.reserve(length);
484 StringArray fieldNames; fieldNames.reserve(length);
485 for(
size_t i=0; i<length; ++i) {
486 string const &fieldName = fromRequestFieldNames[i];
487 PVFieldPtr pvMasterField = pvMaster->getSubField(fieldName);
488 if(!pvMasterField)
continue;
489 FieldConstPtr field = pvMasterField->getField();
490 if(field->getType()==epics::pvData::structure) {
491 PVStructurePtr pvRequestStructure = static_pointer_cast<PVStructure>(
492 pvFromRequestFields[i]);
493 if(pvRequestStructure->getNumberFields()>0) {
494 StringArray
const &names = pvRequestStructure->getStructure()->
496 size_t num = names.size();
497 if(num>0 && names[0].compare(
"_options")==0) --num;
499 if(pvMasterField->getField()->getType()!=epics::pvData::structure)
continue;
500 fieldNames.push_back(fieldName);
501 fields.push_back(createStructure(
502 static_pointer_cast<PVStructure>(pvMasterField),
503 pvRequestStructure));
508 fieldNames.push_back(fieldName);
509 fields.push_back(field);
511 size_t numsubfields = fields.size();
512 if(numsubfields==0) {
513 std::stringstream ss;
514 ss << pvFromRequest <<
"\n";
515 string val(
"no fields from the following request were found\n");
517 throw std::invalid_argument(val);
519 return getFieldCreate()->createStructure(fieldNames, fields);
523 PVStructurePtr
const &pvMasterStructure,
524 PVStructurePtr
const &pvFromRequest,
525 PVStructurePtr
const &pvFromCopy)
527 PVFieldPtrArray
const & copyPVFields = pvFromCopy->getPVFields();
528 PVStructurePtr pvOptions = pvFromRequest->getSubField<PVStructure>(
"_options");
529 size_t number = copyPVFields.size();
531 nodes->reserve(number);
532 for(
size_t i=0; i<number; i++) {
533 PVFieldPtr copyPVField = copyPVFields[i];
534 string fieldName = copyPVField->getFieldName();
535 PVStructurePtr requestPVStructure =
536 pvFromRequest->getSubField<PVStructure>(fieldName);
537 PVStructurePtr pvSubFieldOptions =
538 requestPVStructure->getSubField<PVStructure>(
"_options");
539 PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
541 throw std::logic_error(
"PVCopy::createStructureNodes did not find field in master");
543 size_t numberRequest = requestPVStructure->getPVFields().size();
544 bool haveOptions =
false;
545 if(pvSubFieldOptions) {
549 if(numberRequest>0) {
550 Type copyType = copyPVField->getField()->getType();
551 if(copyType==epics::pvData::structure) {
552 nodes->push_back(createStructureNodes(
553 static_pointer_cast<PVStructure>(pvMasterField),
555 static_pointer_cast<PVStructure>(copyPVField)));
558 if(copyType==epics::pvData::union_) {
559 if(numberRequest!=1) {
560 std::stringstream ss;
561 ss << pvFromRequest <<
"\n";
562 string val(
"In the following request a union field has more than one subfield in\n");
564 throw std::invalid_argument(val);
566 PVUnionPtr pvUnion = static_pointer_cast<PVUnion>(pvMasterField);
567 std::string selectedName = pvUnion->getSelectedFieldName();
568 PVFieldPtrArray
const & pvFields = requestPVStructure->getPVFields();
569 size_t len = pvFields.size();
570 if(len>2 || (haveOptions && len!=2)) {
571 std::stringstream ss;
572 ss << pvFromRequest <<
"\n";
573 string val(
"PVCopy logic error: pvRequest is\n");
575 throw std::logic_error(val);
577 size_t indRequestValue = 0;
578 if((pvFields[0]->getFieldName().compare(
"_options"))==0) indRequestValue = 1;
579 PVFieldPtr pvRequestValue = pvFields[indRequestValue];
581 string requestName = pvRequestValue->getFieldName();
582 if(requestName.compare(selectedName)!=0) {
583 std::stringstream ss;
584 ss << pvFromCopy <<
"\n";
585 string requestName = pvRequestValue->getFieldName();
586 string val(
"field ");
587 val += requestName +
" does not match union type in\n";
589 throw std::invalid_argument(val);
593 std::stringstream ss;
594 ss << pvFromCopy <<
"\n";
595 string val(
"requested a subfield of field ");
596 val += fieldName +
" which does not have type structure in\n";
598 throw std::invalid_argument(val);
602 node->options = pvSubFieldOptions;
603 node->isStructure =
false;
604 node->masterPVField = pvMasterField;
605 node->nfields = copyPVField->getNumberFields();
606 node->structureOffset = copyPVField->getFieldOffset();
607 nodes->push_back(node);
610 structureNode->masterPVField = pvMasterStructure;
611 structureNode->isStructure =
true;
612 structureNode->nodes = nodes;
613 structureNode->structureOffset = pvFromCopy->getFieldOffset();
614 structureNode->nfields = pvFromCopy->getNumberFields();
615 structureNode->options = pvOptions;
616 return structureNode;
619 void PVCopy::initPlugin(
621 PVStructurePtr
const & pvOptions,
622 PVFieldPtr
const & pvMasterField)
624 PVFieldPtrArray
const & pvFields = pvOptions->getPVFields();
625 size_t num = pvFields.size();
626 vector<PVFilterPtr> pvFilters(num);
627 size_t numfilter = 0;
628 for(
size_t i=0; i<num; ++i) {
629 PVStringPtr pvOption = static_pointer_cast<PVString>(pvFields[i]);
630 string name = pvOption->getFieldName();
631 string value = pvOption->get();
632 PVPluginPtr pvPlugin = PVPluginRegistry::find(name);
634 if(name.compare(
"ignore")==0) setIgnore(node);
637 pvFilters[numfilter] = pvPlugin->create(value,shared_from_this(),pvMasterField);
638 if(pvFilters[numfilter]) ++numfilter;
640 if(numfilter==0)
return;
641 node->pvFilters.resize(numfilter);
642 for(
size_t i=0; i<numfilter; ++i) node->pvFilters[i] = pvFilters[i];
645 void PVCopy::traverseMasterInitPlugin()
647 traverseMasterInitPlugin(headNode);
650 void PVCopy::traverseMasterInitPlugin(
CopyNodePtr const & node)
652 PVFieldPtr pvField = node->masterPVField;
653 PVStructurePtr pvOptions = node->options;
654 if(pvOptions) initPlugin(node,pvOptions,pvField);
655 if(!node->isStructure)
return;
657 CopyNodePtrArrayPtr nodes = structureNode->nodes;
658 for(
size_t i=0; i< nodes->size(); i++) {
659 traverseMasterInitPlugin((*nodes)[i]);
665 PVFieldPtr
const &masterPVField)
667 size_t offset = masterPVField->getFieldOffset();
668 CopyNodePtrArrayPtr nodes = structureNode->nodes;
669 for(
size_t i=0; i< nodes->size(); i++) {
671 if(!node->isStructure) {
672 size_t off = node->masterPVField->getFieldOffset();
673 size_t nextOffset = node->masterPVField->getNextFieldOffset();
674 if(offset>= off && offset<nextOffset)
return node;
677 static_pointer_cast<CopyStructureNode>(node);
679 getCopyOffset(subNode,masterPVField);
680 if(node)
return node;
688 bool PVCopy::checkIgnore(
689 PVStructurePtr
const & copyPVStructure,
690 BitSetPtr
const & bitSet)
692 if(!ignorechangeBitSet) {
693 return (bitSet->nextSetBit(0)<0) ?
false :
true;
695 int32 numFields = copyPVStructure->getNumberFields();
696 BitSet temp(numFields);
700 ind = ignorechangeBitSet->nextSetBit(ind);
704 if(ind>=numFields)
break;
706 return (temp.nextSetBit(0)<0) ?
false :
true;
710 ignorechangeBitSet->set(node->structureOffset);
711 if(node->isStructure) {
713 CopyNodePtrArrayPtr nodes = structureNode->nodes;
714 for(
size_t i=0; i<nodes->size(); ++i) {
718 size_t num = node->masterPVField->getNumberFields();
720 for(
size_t i=1; i<num; ++i) {
721 ignorechangeBitSet->set(node->structureOffset+i);
730 std::size_t structureOffset)
732 CopyNodePtrArrayPtr nodes = structureNode->nodes;
733 for(
size_t i=0; i<nodes->size(); ++i) {
735 if(structureOffset>=(node->structureOffset + node->nfields))
continue;
736 if(!node->isStructure)
return node;
738 static_pointer_cast<CopyStructureNode>(node);
739 return getMasterNode(subNode,structureOffset);
744 void PVCopy::dump(
string *builder,
CopyNodePtr const &node,
int indentLevel)
746 newLine(builder,indentLevel);
747 std::stringstream ss;
748 ss << (node->isStructure ?
"structureNode" :
"node");
749 ss <<
" structureOffset " << node->structureOffset;
750 ss <<
" nfields " << node->nfields;
751 *builder += ss.str();
752 PVStructurePtr options = node->options;
754 newLine(builder,indentLevel +1);
755 *builder += options->getFieldName();
756 PVFieldPtrArray pvFields = options->getPVFields();
757 for(
size_t i=0; i< pvFields.size() ; ++i) {
758 PVStringPtr pvString = static_pointer_cast<PVString>(pvFields[i]);
759 newLine(builder,indentLevel +2);
760 *builder += pvString->getFieldName() +
" " + pvString->get();
763 string name = node->masterPVField->getFullName();
764 newLine(builder,indentLevel +1);
765 *builder +=
"masterField " + name;
766 if(node->pvFilters.size()>0) {
767 newLine(builder,indentLevel +2);
768 *builder +=
"filters:";
769 for(
size_t i=0; i< node->pvFilters.size(); ++i) {
771 *builder +=
" " + pvFilter->getName();
774 if(!node->isStructure)
return;
776 static_pointer_cast<CopyStructureNode>(node);
777 CopyNodePtrArrayPtr nodes = structureNode->nodes;
778 for(
size_t i=0; i<nodes->size(); ++i) {
781 newLine(builder,indentLevel +1);
783 ss <<
"node[" << i <<
"] is null";
784 *builder += ss.str();
787 dump(builder,node,indentLevel+1);
std::tr1::shared_ptr< CopyStructureNode > CopyStructureNodePtr
std::tr1::shared_ptr< CopyNode > CopyNodePtr
std::tr1::shared_ptr< PVPlugin > PVPluginPtr
std::tr1::shared_ptr< PVFilter > PVFilterPtr
std::tr1::shared_ptr< PVCopy > PVCopyPtr
Support for subset of fields in a pvStructure.
std::vector< CopyNodePtr > CopyNodePtrArray
std::tr1::shared_ptr< PVCopyTraverseMasterCallback > PVCopyTraverseMasterCallbackPtr
std::tr1::shared_ptr< CopyNodePtrArray > CopyNodePtrArrayPtr