19 #define epicsExportSharedSymbols 32 namespace epics {
namespace pvCopy {
40 static void newLine(
string *buffer,
int indentLevel)
43 *buffer += string(indentLevel*4,
' ');
76 string const & structureName)
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")) {
88 bool result = pvCopy->init(pvStructure);
90 pvCopy->traverseMasterInitPlugin();
102 traverseMaster(headNode,callback);
112 if(cacheInitStructure) {
114 cacheInitStructure.reset();
123 size_t PVCopy::getCopyOffset(
PVFieldPtr const &masterPVField)
125 if(!headNode->isStructure) {
127 if((node->masterPVField.get())==masterPVField.get()) {
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(
148 if(!headNode->isStructure) {
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;
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;
180 pvMasterField->getFieldOffset() + diff);
183 void PVCopy::initCopy(
187 for(
size_t i=0;
i< copyPVStructure->getNumberFields(); ++
i) {
190 updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
194 bool PVCopy::updateCopySetBitSet(
198 updateCopySetBitSet(copyPVStructure,headNode,bitSet);
199 return checkIgnore(copyPVStructure,bitSet);
202 bool PVCopy::updateCopyFromBitSet(
207 for(
size_t i=0;
i< copyPVStructure->getNumberFields(); ++
i) {
211 updateCopyFromBitSet(copyPVStructure,headNode,bitSet);
212 return checkIgnore(copyPVStructure,bitSet);
215 void PVCopy::updateMasterField(
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(
235 if(!bitSet->get(nextSet)) {
236 size_t next = bitSet->nextSetBit(nextSet);
237 if(next==string::npos)
return;
238 updateMasterCheckBitSet(copyPVStructure,bitSet,next);
242 if(nextSet!=0) pvField = copyPVStructure->getSubField(nextSet);
244 bitSet->clear(nextSet);
247 for(
size_t i=0;
i<pvFieldArray.size(); ++
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(
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;
295 updateMasterField(getCopyNode(nextSet),pvCopy,pvMaster,bitSet);
296 bitSet->clear(nextSet);
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(
357 if(*pvCopy==*pvMaster)
return;
358 pvCopy->copy(*pvMaster);
359 bitSet->set(pvCopy->getFieldOffset());
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(
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);
388 for(
size_t i=0;
i<pvCopyFields.size(); ++
i) {
389 updateCopySetBitSet(pvCopyFields[
i],(*structureNode->nodes)[i],bitSet);
394 void PVCopy::updateCopyFromBitSet(
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) {
410 pvCopy->copy(*pvMaster);
415 size_t nextSet = bitSet->nextSetBit(offset);
416 if(nextSet==string::npos)
return;
417 if(offset>=pvCopy->getNextFieldOffset())
return;
420 for(
size_t i=0;
i<pvCopyFields.size(); ++
i) {
421 updateCopyFromBitSet(pvCopyFields[
i],(*structureNode->nodes)[i],bitSet);
431 void PVCopy::destroy()
439 size_t len = pvRequest->getPVFields().size();
440 bool entireMaster =
false;
441 if(len==0) entireMaster =
true;
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);
459 cacheInitStructure = createPVStructure();
460 ignorechangeBitSet =
BitSetPtr(
new BitSet(cacheInitStructure->getNumberFields()));
461 headNode = createStructureNodes(
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;
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;
489 pvFromRequestFields[
i]);
490 if(pvRequestStructure->getNumberFields()>0) {
493 size_t num = names.size();
494 if(num>0 && names[0].
compare(
"_options")==0) --num;
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);
526 size_t number = copyPVFields.size();
528 nodes->reserve(number);
529 for(
size_t i=0;
i<number;
i++) {
531 string fieldName = copyPVField->getFieldName();
533 pvFromRequest->getSubField<
PVStructure>(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();
549 nodes->push_back(createStructureNodes(
550 static_pointer_cast<PVStructure>(pvMasterField),
552 static_pointer_cast<PVStructure>(copyPVField)));
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);
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(
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) {
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)
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]);
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;
676 getCopyOffset(subNode,masterPVField);
677 if(node)
return node;
685 bool PVCopy::checkIgnore(
689 if(!ignorechangeBitSet) {
690 return (bitSet->nextSetBit(0)<0) ?
false :
true;
692 int32 numFields = copyPVStructure->getNumberFields();
701 if(ind>=numFields)
break;
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;
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();
751 newLine(builder,indentLevel +1);
752 *builder += options->getFieldName();
754 for(
size_t i=0;
i< pvFields.size() ; ++
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;
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);
FORCE_INLINE std::tr1::shared_ptr< PVField > getSubField(A a)
const PVFieldPtrArray & getPVFields() const
std::tr1::shared_ptr< CopyStructureNode > CopyStructureNodePtr
BitSet & clear(uint32 bitIndex)
std::tr1::shared_ptr< CopyNode > CopyNodePtr
std::tr1::shared_ptr< PVPlugin > PVPluginPtr
std::tr1::shared_ptr< PVFilter > PVFilterPtr
std::tr1::shared_ptr< PVCopy > PVCopyPtr
shared_ptr< T > static_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
TODO only here because of the Lockable.
std::tr1::shared_ptr< const Structure > StructureConstPtr
Support for subset of fields in a pvStructure.
std::vector< CopyNodePtr > CopyNodePtrArray
std::tr1::shared_ptr< PVCopyTraverseMasterCallback > PVCopyTraverseMasterCallbackPtr
CopyNodePtrArrayPtr nodes
std::string getSelectedFieldName() const
std::size_t getFieldOffset() const
PVString is special case, since it implements SerializableArray.
std::tr1::shared_ptr< PVUnion > PVUnionPtr
std::tr1::shared_ptr< CopyNodePtrArray > CopyNodePtrArrayPtr
bool compare(const Field &a, const Field &b)
int32 nextSetBit(uint32 fromIndex) const
PVUnion has a single subfield.
std::vector< FieldConstPtr > FieldConstPtrArray
std::vector< PVFieldPtr > PVFieldPtrArray
Data interface for a structure,.
std::tr1::shared_ptr< const Field > FieldConstPtr
FORCE_INLINE const FieldCreatePtr & getFieldCreate()
std::tr1::shared_ptr< PVStructure > PVStructurePtr
std::tr1::shared_ptr< PVString > PVStringPtr
vector< PVFilterPtr > pvFilters
std::vector< std::string > StringArray
std::tr1::shared_ptr< PVField > PVFieldPtr
std::tr1::shared_ptr< BitSet > BitSetPtr
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
const StructureConstPtr & getStructure() const
BitSet & set(uint32 bitIndex)
C++ and C descriptions for a thread.
PVStructure * getParent()
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()