PVData C++  8.0.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
valueBuilder.cpp
1 /*
2  * Copyright information and license terms for this software can be
3  * found in the file LICENSE that is included with the distribution
4  */
5 
6 #include <memory>
7 
8 #define epicsExportSharedSymbols
9 #include <pv/pvData.h>
10 #include <pv/valueBuilder.h>
11 
12 namespace epics{namespace pvData{
13 
14 struct ValueBuilder::child {
15  virtual ~child() {}
16  Type type;
17  child(Type t) : type(t) {}
18  virtual void build(const std::string& name, FieldBuilderPtr& builder)=0;
19  virtual void store(const PVFieldPtr& val)=0;
20 
21 };
22 
23 struct ValueBuilder::child_struct : public ValueBuilder::child
24 {
25  virtual ~child_struct() {}
26  child_struct(ValueBuilder *par, const std::string& id)
27  :child(structure)
28  ,builder(par, id)
29  {}
30 
31  ValueBuilder builder;
32  virtual void build(const std::string& name, FieldBuilderPtr& builder) OVERRIDE FINAL
33  {
34  FieldBuilderPtr nest(builder->addNestedStructure(name));
35  buildStruct(this->builder, nest);
36  builder = nest->endNested();
37  }
38  virtual void store(const PVFieldPtr& val) OVERRIDE FINAL
39  {
40  if(val->getField()->getType()!=structure)
41  THROW_EXCEPTION2(std::logic_error, "Structure type mis-match");
42  PVStructurePtr str(std::tr1::static_pointer_cast<PVStructure>(val));
43  storeStruct(builder, str);
44  }
45 
46  static
47  void buildStruct(const ValueBuilder& self, FieldBuilderPtr& builder);
48  static
49  void storeStruct(const ValueBuilder& self, const PVStructurePtr& val);
50 
51  static
52  void fillStruct(ValueBuilder& self, const PVStructure& val);
53 };
54 
55 struct ValueBuilder::child_scalar_base : public ValueBuilder::child
56 {
57  virtual ~child_scalar_base() {}
58  ScalarType stype;
59  child_scalar_base(ScalarType s) : child(scalar), stype(s) {}
60 
61  virtual void build(const std::string& name, FieldBuilderPtr& builder) OVERRIDE FINAL
62  {
63  builder->add(name, stype);
64  }
65 };
66 
67 struct ValueBuilder::child_scalar_array : public ValueBuilder::child
68 {
69  virtual ~child_scalar_array() {}
70  shared_vector<const void> array;
71  child_scalar_array(const shared_vector<const void>& v) : child(scalarArray), array(v) {}
72 
73  virtual void build(const std::string& name, FieldBuilderPtr& builder) OVERRIDE FINAL
74  {
75  builder->addArray(name, array.original_type());
76  }
77  virtual void store(const PVFieldPtr& val) OVERRIDE FINAL
78  {
79  if(val->getField()->getType()!=scalarArray)
80  THROW_EXCEPTION2(std::logic_error, "Scalar Array type mis-match");
81 
82  PVScalarArrayPtr arr(std::tr1::static_pointer_cast<PVScalarArray>(val));
83  arr->putFrom(array);
84  }
85 };
86 
87 template <typename T>
88 struct ValueBuilder::child_scalar : public ValueBuilder::child_scalar_base
89 {
90  virtual ~child_scalar() {}
91  T value;
92  child_scalar(const void* v) : child_scalar_base(static_cast<ScalarType>(ScalarTypeID<T>::value)), value(*static_cast<const T*>(v)) {}
93 
94  virtual void store(const PVFieldPtr& val) OVERRIDE FINAL
95  {
96  if(val->getField()->getType()!=scalar)
97  THROW_EXCEPTION2(std::logic_error, "Scalar type mis-match");
98 
99  PVScalarPtr scalar(std::tr1::static_pointer_cast<PVScalar>(val));
100  scalar->putFrom(value);
101  }
102 };
103 
104 ValueBuilder::ValueBuilder(const std::string &id) :parent(0),id(id) {}
105 
106 void ValueBuilder::child_struct::fillStruct(ValueBuilder& self, const PVStructure& val)
107 {
108  StructureConstPtr type(val.getStructure());
109  const StringArray& field = type->getFieldNames();
110  for(StringArray::const_iterator it=field.begin(), end=field.end(); it!=end; ++it)
111  {
112  PVField::const_shared_pointer sub(val.getSubField(*it));
113  assert(sub);
114  FieldConstPtr subtype(sub->getField());
115  switch(subtype->getType()) {
116  case scalar:
117  {
118  const PVScalar* subs(static_cast<const PVScalar*>(sub.get()));
119  ScalarType stype = subs->getScalar()->getScalarType();
120  switch(stype) {
121 #define STYPE(stype) case pv##stype: { const PV ##stype* ptr(static_cast<const PV##stype*>(subs)); PV##stype::value_type temp(ptr->get()); self._add(*it, pv##stype, &temp); } break
122  STYPE(Boolean);
123  STYPE(Byte);
124  STYPE(Short);
125  STYPE(Int);
126  STYPE(Long);
127  STYPE(UByte);
128  STYPE(UShort);
129  STYPE(UInt);
130  STYPE(ULong);
131  STYPE(Float);
132  STYPE(Double);
133  STYPE(String);
134 #undef STYPE
135  }
136  }
137  break;
138  case structure:
139  self._add(*it, *static_cast<const PVStructure*>(sub.get()));
140  break;
141  default:
142  THROW_EXCEPTION2(std::runtime_error, "ValueBuilder can only clone scalar and structure");
143  }
144  }
145 }
146 
147 ValueBuilder::ValueBuilder(const PVStructure& clone) :parent(0)
148 {
149  StructureConstPtr ctype(clone.getStructure());
150  id = ctype->getID();
151  child_struct::fillStruct(*this, clone);
152 }
153 
154 
156  :parent(par)
157  ,id(id)
158 {}
159 
160 ValueBuilder::~ValueBuilder()
161 {
162  for(children_t::const_iterator it=children.begin(), end=children.end(); it!=end; ++it)
163  delete it->second;
164  children.clear();
165 }
166 
167 void ValueBuilder::_add(const std::string& name, const PVStructure& V)
168 {
169  StructureConstPtr T(V.getStructure());
170  ValueBuilder& self = addNested(name, structure, T->getID());
171  child_struct::fillStruct(self, V);
172  self.endNested();
173 }
174 
175 void ValueBuilder::_add(const std::string& name, ScalarType stype, const void *V)
176 {
177  const children_t::iterator it(children.find(name));
178  if(it!=children.end()) {
179  if(it->second->type!=scalar && it->second->type!=scalarArray)
180  THROW_EXCEPTION2(std::logic_error, "Not allowed to replace field. wrong type");
181  }
182 
184  switch(stype) {
185 #define STYPE(stype) case stype: store.reset(new child_scalar<ScalarTypeTraits<stype>::type>(V)); break
186  STYPE(pvBoolean);
187  STYPE(pvByte);
188  STYPE(pvShort);
189  STYPE(pvInt);
190  STYPE(pvLong);
191  STYPE(pvUByte);
192  STYPE(pvUShort);
193  STYPE(pvUInt);
194  STYPE(pvULong);
195  STYPE(pvFloat);
196  STYPE(pvDouble);
197  STYPE(pvString);
198 #undef STYPE
199  }
200  if(!store.get())
201  THROW_EXCEPTION2(std::logic_error, "Unhandled ScalarType");
202 
203  if(it!=children.end()) {
204  delete it->second;
205  children.erase(it);
206  }
207  children[name] = store.get();
208  store.release();
209 }
210 
211 void ValueBuilder::_add(const std::string& name, const shared_vector<const void>& V)
212 {
213  const children_t::iterator it(children.find(name));
214  if(it!=children.end()) {
215  if(it->second->type!=scalar && it->second->type!=scalarArray)
216  THROW_EXCEPTION2(std::logic_error, "Not allowed to replace field. wrong type");
217  }
218 
219  epics::auto_ptr<child> store(new child_scalar_array(V));
220 
221  children[name] = store.get();
222  store.release();
223 }
224 
225 ValueBuilder& ValueBuilder::addNested(const std::string& name, Type type, const std::string &id)
226 {
227  if(type!=structure)
228  THROW_EXCEPTION2(std::invalid_argument, "addNested() only supports structure");
229  child_struct *sub;
230  children_t::const_iterator it(children.find(name));
231  if(it==children.end()) {
232  epics::auto_ptr<child_struct> store(new child_struct(this, id));
233  sub = store.get();
234  children[name] = store.get();
235  store.release();
236  } else if(it->second->type==structure) {
237  sub = static_cast<child_struct*>(it->second);
238  } else {
239  std::ostringstream msg;
240  msg<<"Can't replace non-struct field '"<<name<<"' with struct";
241  THROW_EXCEPTION2(std::invalid_argument, msg.str());
242  }
243  sub->builder.id = id;
244  return sub->builder;
245 }
246 
247 ValueBuilder& ValueBuilder::endNested()
248 {
249  if(!parent) {
250  THROW_EXCEPTION2(std::logic_error, "Can't end top of structure");
251  }
252  return *parent;
253 }
254 
255 void ValueBuilder::child_struct::buildStruct(const ValueBuilder& self, FieldBuilderPtr& builder)
256 {
257  if(!self.id.empty())
258  builder->setId(self.id);
259 
260  for(children_t::const_iterator it=self.children.begin(), end=self.children.end(); it!=end; ++it)
261  {
262  it->second->build(it->first, builder);
263  }
264 }
265 
266 void ValueBuilder::child_struct::storeStruct(const ValueBuilder& self, const PVStructurePtr& val)
267 {
268  for(children_t::const_iterator it=self.children.begin(), end=self.children.end(); it!=end; ++it)
269  {
270  it->second->store(val->getSubFieldT(it->first));
271  }
272 }
273 
274 PVStructure::shared_pointer ValueBuilder::buildPVStructure() const
275 {
276  if(parent)
277  THROW_EXCEPTION2(std::logic_error, "Only top level structure may be built. Missing endNested() ?");
278 
279  StructureConstPtr type;
280  {
281  FieldBuilderPtr tbuild(getFieldCreate()->createFieldBuilder());
282 
283  child_struct::buildStruct(*this, tbuild);
284 
285  type = tbuild->createStructure();
286  }
287 
288  PVStructure::shared_pointer root(type->build());
289 
290  child_struct::storeStruct(*this, root);
291 
292  return root;
293 }
294 
295 }}// namespace epics::pvData
ValueBuilder & endNested()
End a sub-structure.
constexpr auto empty(const _Container &__cont) noexcept(noexcept(__cont.empty())) -> decltype(__cont.empty())
directory_iterator end(directory_iterator) noexcept
const_iterator begin() const noexcept
iterator find(const key_type &__x)
element_type * release()
__string_type str() const
Data interface for a structure,.
Definition: pvData.h:712
std::tr1::shared_ptr< PVScalar > PVScalarPtr
Definition: pvData.h:77
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:154
std::tr1::shared_ptr< PVStructure > buildPVStructure() const
std::tr1::shared_ptr< const Field > FieldConstPtr
Definition: pvIntrospect.h:129
ValueBuilder & addNested(const std::string &name, Type type=structure, const std::string &id=std::string())
Start a sub-structure.
std::tr1::shared_ptr< PVScalarArray > PVScalarArrayPtr
Definition: pvData.h:82
void clear() noexcept
std::tr1::shared_ptr< PVField > PVFieldPtr
Definition: pvData.h:66
PVScalar is the base class for each scalar field.
Definition: pvData.h:272
const_iterator end() const noexcept
const StructureConstPtr & getStructure() const
Definition: pvData.h:731
std::tr1::shared_ptr< PVField > getSubField(A a)
Definition: pvData.h:744
ValueBuilder(const std::string &id=std::string())
empty structure
element_type * get() const
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
const FieldCreatePtr & getFieldCreate()
size_type erase(const key_type &__x)