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();
95 PVStructurePtr PVCopy::getPVMaster()
102 traverseMaster(headNode,callback);
105 StructureConstPtr PVCopy::getStructure()
110 PVStructurePtr PVCopy::createPVStructure()
112 if(cacheInitStructure) {
113 PVStructurePtr save = cacheInitStructure;
114 cacheInitStructure.reset();
117 PVStructurePtr pvStructure =
118 getPVDataCreate()->createPVStructure(structure);
123 size_t PVCopy::getCopyOffset(PVFieldPtr
const &masterPVField)
125 if(!headNode->isStructure) {
126 CopyNodePtr node = static_pointer_cast<CopyNode>(headNode);
127 if((node->masterPVField.get())==masterPVField.get()) {
128 return headNode->structureOffset;
130 PVStructure * parent = masterPVField->getParent();
131 size_t offsetParent = parent->getFieldOffset();
132 size_t off = masterPVField->getFieldOffset();
133 size_t offdiff = off -offsetParent;
134 if(offdiff<node->nfields)
return headNode->structureOffset + offdiff;
138 CopyNodePtr node = getCopyOffset(structNode,masterPVField);
139 if(node)
return node->structureOffset;
143 size_t PVCopy::getCopyOffset(
144 PVStructurePtr
const &masterPVStructure,
145 PVFieldPtr
const &masterPVField)
148 if(!headNode->isStructure) {
149 node = static_pointer_cast<CopyNode>(headNode);
150 if(node->masterPVField.get()!=masterPVStructure.get())
return string::npos;
153 node = getCopyOffset(snode,masterPVField);
155 if(!node)
return string::npos;
156 size_t diff = masterPVField->getFieldOffset()
157 - masterPVStructure->getFieldOffset();
158 return node->structureOffset + diff;
161 PVFieldPtr PVCopy::getMasterPVField(
size_t structureOffset)
164 if(!headNode->isStructure) {
168 node = getMasterNode(snode,structureOffset);
171 throw std::logic_error(
172 "PVCopy::getMasterPVField: structureOffset not valid");
174 size_t diff = structureOffset - node->structureOffset;
175 PVFieldPtr pvMasterField = node->masterPVField;
176 if(diff==0)
return pvMasterField;
177 PVStructurePtr pvStructure
178 = static_pointer_cast<PVStructure>(pvMasterField);
179 return pvStructure->getSubField(
180 pvMasterField->getFieldOffset() + diff);
183 void PVCopy::initCopy(
184 PVStructurePtr
const ©PVStructure,
185 BitSetPtr
const &bitSet)
187 for(
size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
190 updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
194 bool PVCopy::updateCopySetBitSet(
195 PVStructurePtr
const ©PVStructure,
196 BitSetPtr
const &bitSet)
198 updateCopySetBitSet(copyPVStructure,headNode,bitSet);
199 return checkIgnore(copyPVStructure,bitSet);
202 bool PVCopy::updateCopyFromBitSet(
203 PVStructurePtr
const ©PVStructure,
204 BitSetPtr
const &bitSet)
207 for(
size_t i=0; i< copyPVStructure->getNumberFields(); ++i) {
211 updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
212 return checkIgnore(copyPVStructure,bitSet);
215 void PVCopy::updateMasterField(
217 PVFieldPtr
const & pvCopy,
218 PVFieldPtr
const &pvMaster,
219 BitSetPtr
const &bitSet)
222 for(
size_t i=0; i< node->pvFilters.size(); ++i) {
224 if(pvFilter->filter(pvCopy,bitSet,
false)) result =
true;
227 pvMaster->copyUnchecked(*pvCopy);
230 void PVCopy::updateMasterCheckBitSet(
231 PVStructurePtr
const ©PVStructure,
232 BitSetPtr
const &bitSet,
235 if(!bitSet->get(nextSet)) {
236 size_t next = bitSet->nextSetBit(nextSet);
237 if(next==string::npos)
return;
238 updateMasterCheckBitSet(copyPVStructure,bitSet,next);
241 PVFieldPtr pvField = copyPVStructure;
242 if(nextSet!=0) pvField = copyPVStructure->getSubField(nextSet);
243 if(pvField->getField()->getType()==epics::pvData::structure) {
244 bitSet->clear(nextSet);
245 PVStructurePtr pv = static_pointer_cast<PVStructure>(pvField);
246 PVFieldPtrArray pvFieldArray = pv->getPVFields();
247 for(
size_t i=0; i>pvFieldArray.size(); ++i) {
248 PVFieldPtr pvField = pvFieldArray[i];
249 bitSet->set(pvField->getFieldOffset());
252 size_t next = bitSet->nextSetBit(nextSet+1);
253 if(next==string::npos)
return;
254 updateMasterCheckBitSet(copyPVStructure,bitSet,next);
257 CopyNodePtr PVCopy::getCopyNode(std::size_t fieldOffset)
259 if(fieldOffset==0)
return headNode;
262 if(!node->isStructure)
return node;
264 CopyNodePtrArrayPtr nodes = structNode->nodes;
265 bool okToContinue =
false;
266 for(
size_t i=0; i< nodes->size(); i++) {
268 size_t soff = node->structureOffset;
269 if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
274 if(okToContinue)
continue;
276 throw std::logic_error(
"PVCopy::getCopyNode fieldOffset not valid");
280 void PVCopy::updateMaster(
281 PVStructurePtr
const ©PVStructure,
282 BitSetPtr
const &bitSet)
284 updateMasterCheckBitSet(copyPVStructure,bitSet,0);
287 nextSet = bitSet->nextSetBit(nextSet);
288 if(nextSet==string::npos)
return;
289 PVFieldPtr pvCopy = copyPVStructure->getSubField(nextSet);
290 PVFieldPtr pvMaster = headNode->masterPVField;
291 if(pvMaster->getField()->getType()==epics::pvData::structure) {
292 PVStructurePtr pv = static_pointer_cast<PVStructure>(pvMaster);
293 pvMaster = pv->getSubField(pvCopy->getFullName());
295 updateMasterField(getCopyNode(nextSet),pvCopy,pvMaster,bitSet);
296 bitSet->clear(nextSet);
300 PVStructurePtr PVCopy::getOptions(std::size_t fieldOffset)
302 if(fieldOffset==0)
return headNode->options;
305 if(node->structureOffset==fieldOffset)
return node->options;
306 if(!node->isStructure)
return NULLPVStructure;
308 CopyNodePtrArrayPtr nodes = structNode->nodes;
309 bool okToContinue =
false;
310 for(
size_t i=0; i< nodes->size(); i++) {
312 size_t soff = node->structureOffset;
313 if(fieldOffset>=soff && fieldOffset<soff+node->nfields) {
314 if(fieldOffset==soff)
return node->options;
315 if(!node->isStructure) {
316 return NULLPVStructure;
322 if(okToContinue)
continue;
323 throw std::logic_error(
"PVCopy::getOptions logic error: fieldOffset not valid");
327 string PVCopy::dump()
330 dump(&builder,headNode,0);
334 void PVCopy::traverseMaster(
339 if(!node->isStructure) {
340 callback->nextMasterPVField(node->masterPVField);
344 CopyNodePtrArrayPtr nodes = structNode->nodes;
345 for(
size_t i=0; i< nodes->size(); i++) {
347 traverseMaster(node,callback);
351 void PVCopy::updateCopySetBitSet(
352 PVFieldPtr
const & pvCopy,
353 PVFieldPtr
const & pvMaster,
354 BitSetPtr
const & bitSet)
356 if(pvCopy->getField()->getType()!=epics::pvData::structure) {
357 if(*pvCopy==*pvMaster)
return;
358 pvCopy->copy(*pvMaster);
359 bitSet->set(pvCopy->getFieldOffset());
362 PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
363 PVFieldPtrArray
const & pvCopyFields = pvCopyStructure->getPVFields();
364 for(
size_t i=0; i<pvCopyFields.size(); ++i) {
365 PVFieldPtr master = getMasterPVField(pvCopyFields[i]->getFieldOffset());
366 updateCopySetBitSet(pvCopyFields[i],master,bitSet);
370 void PVCopy::updateCopySetBitSet(
371 PVFieldPtr
const & pvCopy,
373 BitSetPtr
const & bitSet)
376 for(
size_t i=0; i< node->pvFilters.size(); ++i) {
378 if(pvFilter->filter(pvCopy,bitSet,
true)) result =
true;
380 if(!node->isStructure) {
382 updateCopySetBitSet(pvCopy,node->masterPVField,bitSet);
386 PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
387 PVFieldPtrArray
const & pvCopyFields = pvCopyStructure->getPVFields();
388 for(
size_t i=0; i<pvCopyFields.size(); ++i) {
389 updateCopySetBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
394 void PVCopy::updateCopyFromBitSet(
395 PVFieldPtr
const & pvCopy,
397 BitSetPtr
const & bitSet)
400 bool update = bitSet->get(pvCopy->getFieldOffset());
402 for(
size_t i=0; i< node->pvFilters.size(); ++i) {
404 if(pvFilter->filter(pvCopy,bitSet,
true)) result =
true;
407 if(!node->isStructure) {
409 PVFieldPtr pvMaster = node->masterPVField;
410 pvCopy->copy(*pvMaster);
414 size_t offset = structureNode->structureOffset;
415 size_t nextSet = bitSet->nextSetBit(offset);
416 if(nextSet==string::npos)
return;
417 if(offset>=pvCopy->getNextFieldOffset())
return;
418 PVStructurePtr pvCopyStructure = static_pointer_cast<PVStructure>(pvCopy);
419 PVFieldPtrArray
const & pvCopyFields = pvCopyStructure->getPVFields();
420 for(
size_t i=0; i<pvCopyFields.size(); ++i) {
421 updateCopyFromBitSet(pvCopyFields[i],(*structureNode->nodes)[i],bitSet);
426 PVStructurePtr
const &pvMaster)
431 void PVCopy::destroy()
436 bool PVCopy::init(epics::pvData::PVStructurePtr
const &pvRequest)
438 PVStructurePtr pvMasterStructure = pvMaster;
439 size_t len = pvRequest->getPVFields().size();
440 bool entireMaster =
false;
441 if(len==0) entireMaster =
true;
442 PVStructurePtr pvOptions;
444 pvOptions = pvRequest->getSubField<PVStructure>(
"_options");
447 structure = pvMasterStructure->getStructure();
450 node->options = pvOptions;
451 node->isStructure =
false;
452 node->structureOffset = 0;
453 node->masterPVField = pvMasterStructure;
454 node->nfields = pvMasterStructure->getNumberFields();
457 structure = createStructure(pvMasterStructure,pvRequest);
458 if(!structure)
return false;
459 cacheInitStructure = createPVStructure();
460 ignorechangeBitSet = BitSetPtr(
new BitSet(cacheInitStructure->getNumberFields()));
461 headNode = createStructureNodes(
469 StructureConstPtr PVCopy::createStructure(
470 PVStructurePtr
const &pvMaster,
471 PVStructurePtr
const &pvFromRequest)
473 if(pvFromRequest->getStructure()->getNumberFields()==0) {
474 return pvMaster->getStructure();
476 PVFieldPtrArray
const &pvFromRequestFields = pvFromRequest->getPVFields();
477 StringArray
const &fromRequestFieldNames = pvFromRequest->getStructure()->getFieldNames();
478 size_t length = pvFromRequestFields.size();
479 if(length==0)
return NULLStructure;
480 FieldConstPtrArray fields; fields.reserve(length);
481 StringArray fieldNames; fieldNames.reserve(length);
482 for(
size_t i=0; i<length; ++i) {
483 string const &fieldName = fromRequestFieldNames[i];
484 PVFieldPtr pvMasterField = pvMaster->getSubField(fieldName);
485 if(!pvMasterField)
continue;
486 FieldConstPtr field = pvMasterField->getField();
487 if(field->getType()==epics::pvData::structure) {
488 PVStructurePtr pvRequestStructure = static_pointer_cast<PVStructure>(
489 pvFromRequestFields[i]);
490 if(pvRequestStructure->getNumberFields()>0) {
491 StringArray
const &names = pvRequestStructure->getStructure()->
493 size_t num = names.size();
494 if(num>0 && names[0].compare(
"_options")==0) --num;
496 if(pvMasterField->getField()->getType()!=epics::pvData::structure)
continue;
497 fieldNames.push_back(fieldName);
498 fields.push_back(createStructure(
499 static_pointer_cast<PVStructure>(pvMasterField),
500 pvRequestStructure));
505 fieldNames.push_back(fieldName);
506 fields.push_back(field);
508 size_t numsubfields = fields.size();
509 if(numsubfields==0) {
510 std::stringstream ss;
511 ss << pvFromRequest <<
"\n";
512 string val(
"no fields from the following request were found\n");
514 throw std::invalid_argument(val);
516 return getFieldCreate()->createStructure(fieldNames, fields);
520 PVStructurePtr
const &pvMasterStructure,
521 PVStructurePtr
const &pvFromRequest,
522 PVStructurePtr
const &pvFromCopy)
524 PVFieldPtrArray
const & copyPVFields = pvFromCopy->getPVFields();
525 PVStructurePtr pvOptions = pvFromRequest->getSubField<PVStructure>(
"_options");
526 size_t number = copyPVFields.size();
528 nodes->reserve(number);
529 for(
size_t i=0; i<number; i++) {
530 PVFieldPtr copyPVField = copyPVFields[i];
531 string fieldName = copyPVField->getFieldName();
532 PVStructurePtr requestPVStructure =
533 pvFromRequest->getSubField<PVStructure>(fieldName);
534 PVStructurePtr pvSubFieldOptions =
535 requestPVStructure->getSubField<PVStructure>(
"_options");
536 PVFieldPtr pvMasterField = pvMasterStructure->getSubField(fieldName);
538 throw std::logic_error(
"PVCopy::createStructureNodes did not find field in master");
540 size_t numberRequest = requestPVStructure->getPVFields().size();
541 bool haveOptions =
false;
542 if(pvSubFieldOptions) {
546 if(numberRequest>0) {
547 Type copyType = copyPVField->getField()->getType();
548 if(copyType==epics::pvData::structure) {
549 nodes->push_back(createStructureNodes(
550 static_pointer_cast<PVStructure>(pvMasterField),
552 static_pointer_cast<PVStructure>(copyPVField)));
555 if(copyType==epics::pvData::union_) {
556 if(numberRequest!=1) {
557 std::stringstream ss;
558 ss << pvFromRequest <<
"\n";
559 string val(
"In the following request a union field has more than one subfield in\n");
561 throw std::invalid_argument(val);
563 PVUnionPtr pvUnion = static_pointer_cast<PVUnion>(pvMasterField);
564 std::string selectedName = pvUnion->getSelectedFieldName();
565 PVFieldPtrArray
const & pvFields = requestPVStructure->getPVFields();
566 size_t len = pvFields.size();
567 if(len>2 || (haveOptions && len!=2)) {
568 std::stringstream ss;
569 ss << pvFromRequest <<
"\n";
570 string val(
"PVCopy logic error: pvRequest is\n");
572 throw std::logic_error(val);
574 size_t indRequestValue = 0;
575 if((pvFields[0]->getFieldName().compare(
"_options"))==0) indRequestValue = 1;
576 PVFieldPtr pvRequestValue = pvFields[indRequestValue];
578 string requestName = pvRequestValue->getFieldName();
579 if(requestName.compare(selectedName)!=0) {
580 std::stringstream ss;
581 ss << pvFromCopy <<
"\n";
582 string requestName = pvRequestValue->getFieldName();
583 string val(
"field ");
584 val += requestName +
" does not match union type in\n";
586 throw std::invalid_argument(val);
590 std::stringstream ss;
591 ss << pvFromCopy <<
"\n";
592 string val(
"requested a subfield of field ");
593 val += fieldName +
" which does not have type structure in\n";
595 throw std::invalid_argument(val);
599 node->options = pvSubFieldOptions;
600 node->isStructure =
false;
601 node->masterPVField = pvMasterField;
602 node->nfields = copyPVField->getNumberFields();
603 node->structureOffset = copyPVField->getFieldOffset();
604 nodes->push_back(node);
607 structureNode->masterPVField = pvMasterStructure;
608 structureNode->isStructure =
true;
609 structureNode->nodes = nodes;
610 structureNode->structureOffset = pvFromCopy->getFieldOffset();
611 structureNode->nfields = pvFromCopy->getNumberFields();
612 structureNode->options = pvOptions;
613 return structureNode;
616 void PVCopy::initPlugin(
618 PVStructurePtr
const & pvOptions,
619 PVFieldPtr
const & pvMasterField)
621 PVFieldPtrArray
const & pvFields = pvOptions->getPVFields();
622 size_t num = pvFields.size();
623 vector<PVFilterPtr> pvFilters(num);
624 size_t numfilter = 0;
625 for(
size_t i=0; i<num; ++i) {
626 PVStringPtr pvOption = static_pointer_cast<PVString>(pvFields[i]);
627 string name = pvOption->getFieldName();
628 string value = pvOption->get();
629 PVPluginPtr pvPlugin = PVPluginRegistry::find(name);
631 if(name.compare(
"ignore")==0) setIgnore(node);
634 pvFilters[numfilter] = pvPlugin->create(value,shared_from_this(),pvMasterField);
635 if(pvFilters[numfilter]) ++numfilter;
637 if(numfilter==0)
return;
638 node->pvFilters.resize(numfilter);
639 for(
size_t i=0; i<numfilter; ++i) node->pvFilters[i] = pvFilters[i];
642 void PVCopy::traverseMasterInitPlugin()
644 traverseMasterInitPlugin(headNode);
647 void PVCopy::traverseMasterInitPlugin(
CopyNodePtr const & node)
649 PVFieldPtr pvField = node->masterPVField;
650 PVStructurePtr pvOptions = node->options;
651 if(pvOptions) initPlugin(node,pvOptions,pvField);
652 if(!node->isStructure)
return;
654 CopyNodePtrArrayPtr nodes = structureNode->nodes;
655 for(
size_t i=0; i< nodes->size(); i++) {
656 traverseMasterInitPlugin((*nodes)[i]);
662 PVFieldPtr
const &masterPVField)
664 size_t offset = masterPVField->getFieldOffset();
665 CopyNodePtrArrayPtr nodes = structureNode->nodes;
666 for(
size_t i=0; i< nodes->size(); i++) {
668 if(!node->isStructure) {
669 size_t off = node->masterPVField->getFieldOffset();
670 size_t nextOffset = node->masterPVField->getNextFieldOffset();
671 if(offset>= off && offset<nextOffset)
return node;
674 static_pointer_cast<CopyStructureNode>(node);
676 getCopyOffset(subNode,masterPVField);
677 if(node)
return node;
685 bool PVCopy::checkIgnore(
686 PVStructurePtr
const & copyPVStructure,
687 BitSetPtr
const & bitSet)
689 if(!ignorechangeBitSet) {
690 return (bitSet->nextSetBit(0)<0) ?
false :
true;
692 int32 numFields = copyPVStructure->getNumberFields();
693 BitSet temp(numFields);
697 ind = ignorechangeBitSet->nextSetBit(ind);
701 if(ind>=numFields)
break;
703 return (temp.nextSetBit(0)<0) ?
false :
true;
707 ignorechangeBitSet->set(node->structureOffset);
708 if(node->isStructure) {
710 CopyNodePtrArrayPtr nodes = structureNode->nodes;
711 for(
size_t i=0; i<nodes->size(); ++i) {
715 size_t num = node->masterPVField->getNumberFields();
717 for(
size_t i=1; i<num; ++i) {
718 ignorechangeBitSet->set(node->structureOffset+i);
727 std::size_t structureOffset)
729 CopyNodePtrArrayPtr nodes = structureNode->nodes;
730 for(
size_t i=0; i<nodes->size(); ++i) {
732 if(structureOffset>=(node->structureOffset + node->nfields))
continue;
733 if(!node->isStructure)
return node;
735 static_pointer_cast<CopyStructureNode>(node);
736 return getMasterNode(subNode,structureOffset);
741 void PVCopy::dump(
string *builder,
CopyNodePtr const &node,
int indentLevel)
743 newLine(builder,indentLevel);
744 std::stringstream ss;
745 ss << (node->isStructure ?
"structureNode" :
"node");
746 ss <<
" structureOffset " << node->structureOffset;
747 ss <<
" nfields " << node->nfields;
748 *builder += ss.str();
749 PVStructurePtr options = node->options;
751 newLine(builder,indentLevel +1);
752 *builder += options->getFieldName();
753 PVFieldPtrArray pvFields = options->getPVFields();
754 for(
size_t i=0; i< pvFields.size() ; ++i) {
755 PVStringPtr pvString = static_pointer_cast<PVString>(pvFields[i]);
756 newLine(builder,indentLevel +2);
757 *builder += pvString->getFieldName() +
" " + pvString->get();
760 string name = node->masterPVField->getFullName();
761 newLine(builder,indentLevel +1);
762 *builder +=
"masterField " + name;
763 if(node->pvFilters.size()>0) {
764 newLine(builder,indentLevel +2);
765 *builder +=
"filters:";
766 for(
size_t i=0; i< node->pvFilters.size(); ++i) {
768 *builder +=
" " + pvFilter->getName();
771 if(!node->isStructure)
return;
773 static_pointer_cast<CopyStructureNode>(node);
774 CopyNodePtrArrayPtr nodes = structureNode->nodes;
775 for(
size_t i=0; i<nodes->size(); ++i) {
778 newLine(builder,indentLevel +1);
780 ss <<
"node[" << i <<
"] is null";
781 *builder += ss.str();
784 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