PVData C++ 8.0.7
Loading...
Searching...
No Matches
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
12namespace epics{namespace pvData{
13
14struct 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
23struct 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
55struct 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
67struct 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
87template <typename T>
88struct 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
104ValueBuilder::ValueBuilder(const std::string &id) :parent(0),id(id) {}
105
106void ValueBuilder::child_struct::fillStruct(ValueBuilder& self, const PVStructure& val)
107{
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
148{
149 StructureConstPtr ctype(clone.getStructure());
150 id = ctype->getID();
151 child_struct::fillStruct(*this, clone);
152}
153
154
155ValueBuilder::ValueBuilder(ValueBuilder* par, const std::string &id)
156 :parent(par)
157 ,id(id)
158{}
159
160ValueBuilder::~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
167void 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
175void 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
211void 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
225ValueBuilder& 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
248{
249 if(!parent) {
250 THROW_EXCEPTION2(std::logic_error, "Can't end top of structure");
251 }
252 return *parent;
253}
254
255void 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
266void 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
274PVStructure::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
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
element_type * release()
element_type * get() const
const_iterator end() const noexcept
void clear() noexcept
size_type erase(const key_type &__x)
iterator find(const key_type &__x)
const_iterator begin() const noexcept
constexpr const_iterator begin() const noexcept
constexpr const_iterator end() const noexcept
PVScalar is the base class for each scalar field.
Definition pvData.h:272
Data interface for a structure,.
Definition pvData.h:713
std::tr1::shared_ptr< PVField > getSubField(A a)
Definition pvData.h:744
const StructureConstPtr & getStructure() const
Definition pvData.h:731
std::tr1::shared_ptr< PVStructure > buildPVStructure() const
ValueBuilder & endNested()
End a sub-structure.
ValueBuilder(const std::string &id=std::string())
empty structure
ValueBuilder & addNested(const std::string &name, Type type=structure, const std::string &id=std::string())
Start a sub-structure.
const char * name(Type type)
std::tr1::shared_ptr< const Structure > StructureConstPtr
const FieldCreatePtr & getFieldCreate()
std::tr1::shared_ptr< PVField > PVFieldPtr
Definition pvData.h:66
std::tr1::shared_ptr< PVScalar > PVScalarPtr
Definition pvData.h:77
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition pvData.h:87
std::tr1::shared_ptr< const Field > FieldConstPtr
std::tr1::shared_ptr< PVScalarArray > PVScalarArrayPtr
Definition pvData.h:82
epics
Definition convert.h:21