This is Unofficial EPICS BASE Doxygen Site
PVUnion.cpp
Go to the documentation of this file.
1 /*PVUnion.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/serializeHelper.h>
20 
22 using std::size_t;
23 using std::string;
24 
25 namespace epics { namespace pvData {
26 
27 #define PVUNION_UNDEFINED_INDEX -1
29 
30 PVDataCreatePtr PVUnion::pvDataCreate(getPVDataCreate());
31 
33 : PVField(unionPtr),
34  unionPtr(unionPtr),
35  selector(PVUNION_UNDEFINED_INDEX), // to allow out-of-order static initialization
36  value(),
37  variant(unionPtr->isVariant())
38 {
39 }
40 
41 #undef PVUNION_UNDEFINED_INDEX
42 
44 
46 {
47  // no name for undefined and for variant unions
48  if (selector == UNDEFINED_INDEX)
49  return string();
50  else
51  return unionPtr->getFieldName(selector);
52 }
53 
55 {
56  if (variant && index != UNDEFINED_INDEX)
57  throw std::invalid_argument("index out of bounds");
58 
59  // no change
60  if (selector == index && !variant)
61  return value;
62 
63  if (index == UNDEFINED_INDEX)
64  {
65  selector = UNDEFINED_INDEX;
66  value.reset();
67  return value;
68  }
69  else if (index < 0 || size_t(index) >= unionPtr->getFields().size())
70  throw std::invalid_argument("index out of bounds");
71 
72  FieldConstPtr field = unionPtr->getField(index);
73  selector = index;
74  value = pvDataCreate->createPVField(field);
75 
76  return value;
77 }
78 
79 PVFieldPtr PVUnion::select(string const & fieldName)
80 {
81  int32 index = variant ? -1 : static_cast<int32>(unionPtr->getFieldIndex(fieldName));
82  if (index == -1)
83  throw std::invalid_argument("no such fieldName");
84  return select(index);
85 }
86 
87 void PVUnion::set(int32 index, PVFieldPtr const & value)
88 {
89  if (variant && index != UNDEFINED_INDEX)
90  throw std::invalid_argument("index out of bounds");
91  else if (!variant)
92  {
93  if (index == UNDEFINED_INDEX)
94  {
95  // for undefined index we accept only null values
96  if (value)
97  throw std::invalid_argument("non-null value for index == UNDEFINED_INDEX");
98  }
99  else if (index < 0 || size_t(index) >= unionPtr->getFields().size())
100  throw std::invalid_argument("index out of bounds");
101  else if (!value)
102  throw std::invalid_argument("Can't set defined index w/ NULL");
103  else if (value->getField() != unionPtr->getField(index))
104  throw std::invalid_argument("selected field and its introspection data do not match");
105  }
106 
107  selector = index;
108  this->value = value;
109  postPut();
110 }
111 
112 void PVUnion::set(string const & fieldName, PVFieldPtr const & value)
113 {
114  int32 index = variant ? -1 : static_cast<int32>(unionPtr->getFieldIndex(fieldName));
115  if (index == -1)
116  throw std::invalid_argument("no such fieldName");
117 
118  set(index, value);
119 }
120 
122 {
123  if (variant)
124  {
125  // write introspection data
126  if (value.get() == 0) {
127  pflusher->ensureBuffer(1);
128  pbuffer->put((int8)-1);
129  }else {
130  pflusher->cachedSerialize(value->getField(), pbuffer);
131  value->serialize(pbuffer, pflusher);
132  }
133  }
134  else
135  {
136  // write selector value
137  SerializeHelper::writeSize(selector, pbuffer, pflusher);
138  // write value, no value for UNDEFINED_INDEX
139  if (selector != UNDEFINED_INDEX)
140  value->serialize(pbuffer, pflusher);
141  }
142 }
143 
145 {
146  if (variant)
147  {
148  FieldConstPtr field = pcontrol->cachedDeserialize(pbuffer);
149  if (field.get())
150  {
151  // try to reuse existing field instance
152  if (!value.get() || *value->getField() != *field)
153  value = pvDataCreate->createPVField(field);
154  value->deserialize(pbuffer, pcontrol);
155  }
156  else
157  value.reset();
158  }
159  else
160  {
161  int32 previousSelector = selector;
162  selector = static_cast<int32>(SerializeHelper::readSize(pbuffer, pcontrol));
163  if (selector != UNDEFINED_INDEX)
164  {
165  if (selector != previousSelector)
166  {
167  FieldConstPtr field = unionPtr->getField(selector);
168  // try to reuse existing field instance
169  if (!value.get() || *value->getField() != *field)
170  value = pvDataCreate->createPVField(field);
171  }
172  value->deserialize(pbuffer, pcontrol);
173  }
174  else
175  value.reset();
176  }
177 }
178 
179 std::ostream& PVUnion::dumpValue(std::ostream& o) const
180 {
181  o << format::indent() << getUnion()->getID() << ' ' << getFieldName() << std::endl;
182  {
184  const PVField::const_shared_pointer& fieldField = get();
185  if (fieldField.get() == NULL)
186  o << format::indent() << "(none)" << std::endl;
187  else
188  {
189  Type type = fieldField->getField()->getType();
190  if (type == scalar || type == scalarArray)
191  o << format::indent() << fieldField->getField()->getID() << ' ' << fieldField->getFieldName() << ' ' << *(fieldField.get()) << std::endl;
192  else
193  o << *(fieldField.get());
194  }
195  }
196  return o;
197 }
198 
199 void PVUnion::copy(const PVUnion& from)
200 {
201  if(isImmutable())
202  throw std::invalid_argument("destination is immutable");
203 
204  if(*getUnion() != *from.getUnion())
205  throw std::invalid_argument("union definitions do not match");
206 
207  copyUnchecked(from);
208 }
209 
211 {
212 
213  const PVField::const_shared_pointer& fromValue = from.get();
214  if (from.getUnion()->isVariant())
215  {
216  if (fromValue.get() == 0)
217  {
218  set(PVField::shared_pointer());
219  }
220  else
221  {
222  PVFieldPtr toValue = get();
223  if (toValue.get() == 0 || *toValue->getField() != *fromValue->getField())
224  {
225  toValue = pvDataCreate->createPVField(fromValue->getField());
226  toValue->copyUnchecked(*fromValue);
227  set(toValue);
228  }
229  else
230  {
231  toValue->copyUnchecked(*fromValue);
232  postPut();
233  }
234  }
235  }
236  else
237  {
238  if (fromValue.get() == 0)
239  {
240  select(PVUnion::UNDEFINED_INDEX);
241  }
242  else
243  {
244  select(from.getSelectedIndex())->copyUnchecked(*fromValue);
245  }
246  postPut();
247  }
248 
249 }
250 
251 
252 }}
int8_t int8
Definition: pvType.h:75
const std::string & getFieldName() const
Definition: pvData.h:166
Definition: link.h:174
const PVFieldPtr & get()
Definition: pvData.h:968
#define PVUNION_UNDEFINED_INDEX
Definition: PVUnion.cpp:27
virtual std::ostream & dumpValue(std::ostream &o) const OVERRIDE FINAL
Definition: PVUnion.cpp:179
int32 getSelectedIndex() const
Definition: pvData.h:1014
const UnionConstPtr & getUnion() const
Definition: pvData.h:962
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
#define NULL
Definition: catime.c:38
static void writeSize(std::size_t s, ByteBuffer *buffer, SerializableControl *flusher)
static std::size_t readSize(ByteBuffer *buffer, DeserializableControl *control)
Callback class for deserialization.
Definition: serialize.h:89
PVField is the base class for each PVData field.
Definition: pvData.h:152
PVUnion(UnionConstPtr const &punion)
Definition: PVUnion.cpp:32
std::string getSelectedFieldName() const
Definition: PVUnion.cpp:45
std::tr1::shared_ptr< PVDataCreate > PVDataCreatePtr
Definition: pvData.h:124
virtual std::tr1::shared_ptr< const Field > cachedDeserialize(ByteBuffer *buffer)=0
std::tr1::shared_ptr< const Union > UnionConstPtr
Definition: pvIntrospect.h:170
virtual void deserialize(ByteBuffer *pbuffer, DeserializableControl *pflusher) OVERRIDE FINAL
Definition: PVUnion.cpp:144
This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
Definition: byteBuffer.h:233
PVUnion has a single subfield.
Definition: pvData.h:940
void copy(const PVUnion &from)
Definition: PVUnion.cpp:199
std::tr1::shared_ptr< const Field > FieldConstPtr
Definition: pvIntrospect.h:137
void set(PVFieldPtr const &value)
Definition: pvData.h:1028
virtual void cachedSerialize(std::tr1::shared_ptr< const Field > const &field, ByteBuffer *buffer)=0
char * pbuffer
Definition: errlog.c:85
PVFieldPtr select(int32 index)
Definition: PVUnion.cpp:54
virtual void serialize(ByteBuffer *pbuffer, SerializableControl *pflusher) const OVERRIDE FINAL
Definition: PVUnion.cpp:121
bool isImmutable() const
Definition: pvData.h:198
std::tr1::shared_ptr< PVField > PVFieldPtr
Definition: pvData.h:66
virtual void ensureBuffer(std::size_t size)=0
Callback class for serialization.
Definition: serialize.h:34
void copyUnchecked(const PVUnion &from)
Definition: PVUnion.cpp:210
int32_t int32
Definition: pvType.h:83
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648
static const int32 UNDEFINED_INDEX
Definition: pvData.h:956