This is Unofficial EPICS BASE Doxygen Site
PVStructure.cpp
Go to the documentation of this file.
1 /*PVStructure.cpp*/
2 /*
3  * Copyright information and license terms for this software can be
4  * found in the file LICENSE that is included with the distribution
5  */
9 #include <cstddef>
10 #include <cstdlib>
11 #include <string>
12 #include <cstdio>
13 #include <vector>
14 
15 #define epicsExportSharedSymbols
16 #include <pv/pvData.h>
17 #include <pv/pvIntrospect.h>
18 #include <pv/factory.h>
19 #include <pv/bitSet.h>
20 
22 using std::size_t;
23 using std::string;
24 
25 namespace epics { namespace pvData {
26 
28 : PVField(structurePtr),
29  structurePtr(structurePtr),
30  extendsStructureName("")
31 {
32  size_t numberFields = structurePtr->getNumberFields();
33  FieldConstPtrArray const & fields = structurePtr->getFields();
34  StringArray const & fieldNames = structurePtr->getFieldNames();
35  pvFields.reserve(numberFields);
36  PVDataCreatePtr pvDataCreate = getPVDataCreate();
37  for(size_t i=0; i<numberFields; i++) {
38  pvFields.push_back(pvDataCreate->createPVField(fields[i]));
39  }
40  for(size_t i=0; i<numberFields; i++) {
41  pvFields[i]->setParentAndName(this,fieldNames[i]);
42  }
43 }
44 
46  PVFieldPtrArray const & pvs
47 )
48 : PVField(structurePtr),
49  structurePtr(structurePtr),
50  extendsStructureName("")
51 {
52  size_t numberFields = structurePtr->getNumberFields();
53  StringArray const & fieldNames = structurePtr->getFieldNames();
54  pvFields.reserve(numberFields);
55  for(size_t i=0; i<numberFields; i++) {
56  pvFields.push_back(pvs[i]);
57  }
58  for(size_t i=0; i<numberFields; i++) {
59  pvFields[i]->setParentAndName(this,fieldNames[i]);
60  }
61 }
62 
64 
66 {
67  size_t numFields = pvFields.size();
68  for(size_t i=0; i<numFields; i++) {
69  PVFieldPtr pvField = pvFields[i];
70  pvField->setImmutable();
71  }
73 }
74 
75 PVFieldPtr PVStructure::getSubFieldImpl(size_t fieldOffset, bool throws) const
76 {
77  const PVStructure *current = this;
78 
79 recurse:
80  // we don't permit self lookup
81  if(fieldOffset<=current->getFieldOffset() || fieldOffset>=current->getNextFieldOffset()) {
82  if(throws) {
83  std::stringstream ss;
84  ss << "Failed to get field with offset "
85  << fieldOffset << " (Invalid offset)" ;
86  throw std::runtime_error(ss.str());
87  } else {
88  return PVFieldPtr();
89  }
90  }
91 
92  for(size_t i=0, numFields = current->pvFields.size(); i<numFields; i++) {
93  const PVFieldPtr& pvField = current->pvFields[i];
94 
95  if(pvField->getFieldOffset()==fieldOffset) {
96  return pvField;
97 
98  } else if(pvField->getNextFieldOffset()<=fieldOffset) {
99  continue;
100 
101  } else if(pvField->getField()->getType()==structure) {
102  current = static_cast<PVStructure *>(pvField.get());
103  goto recurse;
104  }
105  }
106  // the first test against current->getNextFieldOffset() would avoid this
107  throw std::logic_error("PVStructure.getSubField: Logic error");
108 }
109 
110 PVFieldPtr PVStructure::getSubFieldImpl(const char *name, bool throws) const
111 {
112  const PVStructure *parent = this;
113  if(!name)
114  {
115  if (throws)
116  throw std::invalid_argument("Failed to get field: (Field name is NULL string)");
117  else
118  return PVFieldPtr();
119  }
120  const char *fullName = name;
121  while(true) {
122  const char *sep=name;
123  while(*sep!='\0' && *sep!='.' && *sep!=' ') sep++;
124  if(*sep==' ')
125  {
126  if (throws)
127  {
128  std::stringstream ss;
129  ss << "Failed to get field: " << fullName
130  << " (No spaces allowed in field name)";
131  throw std::runtime_error(ss.str());
132  }
133  else
134  return PVFieldPtr();
135  }
136  size_t N = sep-name;
137  if(N==0)
138  {
139  if (throws)
140  {
141  std::stringstream ss;
142  ss << "Failed to get field: " << fullName
143  << " (Zero-length field name encountered)";
144  throw std::runtime_error(ss.str());
145  }
146  else
147  return PVFieldPtr();
148  }
149 
150  const PVFieldPtrArray& pvFields = parent->getPVFields();
151 
152  PVField *child = NULL;
153 
154  for(size_t i=0, n=pvFields.size(); i!=n; i++) {
155  const PVFieldPtr& fld = pvFields[i];
156  const std::string& fname = fld->getFieldName();
157 
158  if(fname.size()==N && memcmp(name, fname.c_str(), N)==0) {
159  child = fld.get();
160  break;
161  }
162  }
163 
164  if(!child)
165  {
166  if (throws)
167  {
168  std::stringstream ss;
169  ss << "Failed to get field: " << fullName << " ("
170  << std::string(fullName, sep) << " not found)";
171  throw std::runtime_error(ss.str());
172  }
173  else
174  return PVFieldPtr();
175  }
176 
177  if(*sep) {
178  // this is not the requested leaf
179  parent = dynamic_cast<PVStructure*>(child);
180  if(!parent)
181  {
182  if (throws)
183  {
184  std::stringstream ss;
185  ss << "Failed to get field: " << fullName
186  << " (" << std::string(fullName, sep)
187  << " is not a structure)";
188  throw std::runtime_error(ss.str());
189  }
190  else
191  return PVFieldPtr();
192  }
193  child = NULL;
194  name = sep+1; // skip past '.'
195  // loop around to new parent
196 
197  } else {
198  return child->shared_from_this();
199  }
200  }
201 }
202 
203 void PVStructure::throwBadFieldType(const char *name)
204 {
205  std::ostringstream ss;
206  ss << "Failed to get field: " << name << " (Field has wrong type)";
207  throw std::runtime_error(ss.str());
208 }
209 
210 void PVStructure::throwBadFieldType(std::size_t fieldOffset)
211 {
212  std::stringstream ss;
213  ss << "Failed to get field with offset "
214  << fieldOffset << " (Field has wrong type)";
215  throw std::runtime_error(ss.str());
216 }
217 
219  SerializableControl *pflusher) const {
220  size_t fieldsSize = pvFields.size();
221  for(size_t i = 0; i<fieldsSize; i++)
222  pvFields[i]->serialize(pbuffer, pflusher);
223 }
224 
226  DeserializableControl *pcontrol) {
227  size_t fieldsSize = pvFields.size();
228  for(size_t i = 0; i<fieldsSize; i++)
229  pvFields[i]->deserialize(pbuffer, pcontrol);
230 
231 }
232 
234  SerializableControl *pflusher, BitSet *pbitSet) const {
235  size_t numberFields = this->getNumberFields();
236  size_t offset = this->getFieldOffset();
237  int32 next = pbitSet->nextSetBit(static_cast<uint32>(offset));
238 
239  // no more changes or no changes in this structure
240  if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
241 
242  // entire structure
243  if(static_cast<int32>(offset)==next) {
244  serialize(pbuffer, pflusher);
245  return;
246  }
247 
248  size_t fieldsSize = pvFields.size();
249  for(size_t i = 0; i<fieldsSize; i++) {
250  PVField* pvField = pvFields[i].get();
251  offset = pvField->getFieldOffset();
252  int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
253  next = pbitSet->nextSetBit(static_cast<uint32>(offset));
254 
255  // no more changes
256  if(next<0) return;
257  // no change in this pvField
258  if(next>=static_cast<int32>(offset+inumberFields)) continue;
259 
260  // serialize field or fields
261  if(inumberFields==1) {
262  pvField->serialize(pbuffer, pflusher);
263  } else {
264  static_cast<PVStructure*>(pvField)->serialize(pbuffer, pflusher, pbitSet);
265  }
266  }
267 }
268 
270  DeserializableControl *pcontrol, BitSet *pbitSet) {
271  size_t offset = getFieldOffset();
272  size_t numberFields = getNumberFields();
273  int32 next = pbitSet->nextSetBit(static_cast<uint32>(offset));
274 
275  // no more changes or no changes in this structure
276  if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
277 
278  // entire structure
279  if(static_cast<int32>(offset)==next) {
280  deserialize(pbuffer, pcontrol);
281  return;
282  }
283 
284  size_t fieldsSize = pvFields.size();
285  for(size_t i = 0; i<fieldsSize; i++) {
286  PVFieldPtr pvField = pvFields[i];
287  offset = pvField->getFieldOffset();
288  int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
289  next = pbitSet->nextSetBit(static_cast<uint32>(offset));
290  // no more changes
291  if(next<0) return;
292  // no change in this pvField
293  if(next>=static_cast<int32>(offset+inumberFields)) continue;
294 
295  // deserialize field or fields
296  if(inumberFields==1) {
297  pvField->deserialize(pbuffer, pcontrol);
298  } else {
300  pvStructure->deserialize(pbuffer, pcontrol, pbitSet);
301  }
302  }
303 }
304 
305 std::ostream& PVStructure::dumpValue(std::ostream& o) const
306 {
307  o << format::indent() << getStructure()->getID() << ' ' << getFieldName();
308  o << std::endl;
309  {
311 
312  PVFieldPtrArray const & fieldsData = getPVFields();
313  if (fieldsData.size() != 0) {
314  size_t length = getStructure()->getNumberFields();
315  for(size_t i=0; i<length; i++) {
316  PVFieldPtr fieldField = fieldsData[i];
317  Type type = fieldField->getField()->getType();
318  if (type == scalar || type == scalarArray)
319  o << format::indent() << fieldField->getField()->getID() << ' ' << fieldField->getFieldName() << ' ' << *(fieldField.get()) << std::endl;
320  else
321  o << *(fieldField.get());
322  }
323  }
324  }
325  return o;
326 }
327 
328 
330 {
331  if(isImmutable())
332  throw std::invalid_argument("destination is immutable");
333 
334  if(*getStructure() != *from.getStructure())
335  throw std::invalid_argument("structure definitions do not match");
336 
337  copyUnchecked(from);
338 }
339 
341 {
342  if (this == &from)
343  return;
344 
345  PVFieldPtrArray const & fromPVFields = from.getPVFields();
346  PVFieldPtrArray const & toPVFields = getPVFields();
347 
348  size_t fieldsSize = fromPVFields.size();
349  for(size_t i = 0; i<fieldsSize; i++) {
350  toPVFields[i]->copyUnchecked(*fromPVFields[i]);
351  }
352 }
353 
354 void PVStructure::copyUnchecked(const PVStructure& from, const BitSet& maskBitSet, bool inverse)
355 {
356  if (this == &from)
357  return;
358 
359  size_t numberFields = from.getNumberFields();
360  size_t offset = from.getFieldOffset();
361  int32 next = inverse ?
362  maskBitSet.nextClearBit(static_cast<uint32>(offset)) :
363  maskBitSet.nextSetBit(static_cast<uint32>(offset));
364 
365  // no more changes or no changes in this structure
366  if(next<0||next>=static_cast<int32>(offset+numberFields)) return;
367 
368  // entire structure
369  if(static_cast<int32>(offset)==next) {
370  copyUnchecked(from);
371  return;
372  }
373 
374  PVFieldPtrArray const & fromPVFields = from.getPVFields();
375  PVFieldPtrArray const & toPVFields = getPVFields();
376 
377  size_t fieldsSize = fromPVFields.size();
378  for(size_t i = 0; i<fieldsSize; i++) {
379  PVFieldPtr pvField = fromPVFields[i];
380  offset = pvField->getFieldOffset();
381  int32 inumberFields = static_cast<int32>(pvField->getNumberFields());
382  next = inverse ?
383  maskBitSet.nextClearBit(static_cast<uint32>(offset)) :
384  maskBitSet.nextSetBit(static_cast<uint32>(offset));
385 
386  // no more changes
387  if(next<0) return;
388  // no change in this pvField
389  if(next>=static_cast<int32>(offset+inumberFields)) continue;
390 
391  // serialize field or fields
392  if(inumberFields==1) {
393  toPVFields[i]->copyUnchecked(*pvField);
394  } else {
395  PVStructure::shared_pointer fromPVStructure = std::tr1::static_pointer_cast<PVStructure>(pvField);
396  PVStructure::shared_pointer toPVStructure = std::tr1::static_pointer_cast<PVStructure>(toPVFields[i]);
397  toPVStructure->copyUnchecked(*fromPVStructure, maskBitSet, inverse);
398  }
399  }
400 }
401 
402 
403 }}
virtual void setImmutable() OVERRIDE FINAL
Definition: PVStructure.cpp:65
const std::string & getFieldName() const
Definition: pvData.h:166
const PVFieldPtrArray & getPVFields() const
Definition: pvData.h:736
PVStructure(StructureConstPtr const &structure)
Definition: PVStructure.cpp:27
virtual void serialize(ByteBuffer *buffer, SerializableControl *flusher) const =0
int i
Definition: scan.c:967
virtual void setImmutable()
Definition: PVField.cpp:63
virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const OVERRIDE FINAL
shared_ptr< T > static_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:788
pvd::StructureConstPtr type
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
#define NULL
Definition: catime.c:38
virtual std::ostream & dumpValue(std::ostream &o) const OVERRIDE FINAL
A vector of bits.
Definition: bitSet.h:56
Callback class for deserialization.
Definition: serialize.h:89
PVField is the base class for each PVData field.
Definition: pvData.h:152
std::size_t getFieldOffset() const
Definition: PVField.cpp:44
void copyUnchecked(const PVStructure &from)
void copy(const PVStructure &from)
std::tr1::shared_ptr< PVDataCreate > PVDataCreatePtr
Definition: pvData.h:124
int32 nextClearBit(uint32 fromIndex) const
Definition: bitSet.cpp:181
This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
Definition: byteBuffer.h:233
int32 nextSetBit(uint32 fromIndex) const
Definition: bitSet.cpp:164
std::vector< FieldConstPtr > FieldConstPtrArray
Definition: pvIntrospect.h:146
std::vector< PVFieldPtr > PVFieldPtrArray
Definition: pvData.h:70
Data interface for a structure,.
Definition: pvData.h:712
virtual void deserialize(ByteBuffer *pbuffer, DeserializableControl *pflusher) OVERRIDE FINAL
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
char * pbuffer
Definition: errlog.c:85
bool isImmutable() const
Definition: pvData.h:198
std::vector< std::string > StringArray
Definition: pvType.h:110
std::tr1::shared_ptr< PVField > PVFieldPtr
Definition: pvData.h:66
Callback class for serialization.
Definition: serialize.h:34
const StructureConstPtr & getStructure() const
Definition: pvData.h:731
int32_t int32
Definition: pvType.h:83
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648
std::size_t getNextFieldOffset() const
Definition: PVField.cpp:50
std::size_t getNumberFields() const
Definition: PVField.cpp:56