OpenDDS  Snapshot(2023/04/28-20:55)
value_reader_generator.cpp
Go to the documentation of this file.
1 /*
2  * Distributed under the OpenDDS License.
3  * See: http://www.opendds.org/license.html
4  */
5 
7 
8 #include "be_extern.h"
9 #include "be_util.h"
10 
11 #include <dds/DCPS/Definitions.h>
12 
13 #include <global_extern.h>
14 #include <utl_identifier.h>
15 #include <utl_labellist.h>
16 #include <ast_fixed.h>
17 
18 using namespace AstTypeClassification;
19 
20 namespace {
21 
22  void generate_read(const std::string& expression, const std::string& accessor,
23  AST_Type* type, const std::string& idx, int level = 1);
24 
25  std::string primitive_type(AST_PredefinedType::PredefinedType pt)
26  {
27  switch (pt) {
28  case AST_PredefinedType::PT_long:
29  return "int32";
30  case AST_PredefinedType::PT_ulong:
31  return "uint32";
32  case AST_PredefinedType::PT_longlong:
33  return "int64";
34  case AST_PredefinedType::PT_ulonglong:
35  return "uint64";
36  case AST_PredefinedType::PT_short:
37  return "int16";
38  case AST_PredefinedType::PT_ushort:
39  return "uint16";
40 #if OPENDDS_HAS_EXPLICIT_INTS
41  case AST_PredefinedType::PT_int8:
42  return "int8";
43  case AST_PredefinedType::PT_uint8:
44  return "uint8";
45 #endif
46  case AST_PredefinedType::PT_float:
47  return "float32";
48  case AST_PredefinedType::PT_double:
49  return "float64";
50  case AST_PredefinedType::PT_longdouble:
51  return "float128";
52  case AST_PredefinedType::PT_char:
53  return "char8";
54  case AST_PredefinedType::PT_wchar:
55  return "char16";
56  case AST_PredefinedType::PT_boolean:
57  return "boolean";
58  case AST_PredefinedType::PT_octet:
59  return "byte";
60  default:
61  return "";
62  }
63  }
64 
65  void array_helper(const std::string& expression, AST_Array* array,
66  size_t dim_idx, const std::string& idx, int level)
67  {
68  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
69  const std::string indent(level * 2, ' ');
70  const Classification c = classify(array->base_type());
71  const bool primitive = c & CL_PRIMITIVE;
72  // When we have a primitive type the last dimension is read using the read_*_array
73  // operation, when we have a not primitive type the last dimension is read element by element
74  // in a loop in the generated code
75  if ((primitive && (dim_idx < array->n_dims() - 1)) || (!primitive && (dim_idx < array->n_dims()))) {
76  const size_t dim = array->dims()[dim_idx]->ev()->u.ulval;
77  be_global->impl_ <<
78  indent << "if (!value_reader.begin_array()) return false;\n" <<
79  indent << "for (" << (use_cxx11 ? "size_t " : "unsigned int ") << idx << " = 0; "
80  << idx << " != " << dim << "; ++" << idx << ") {\n" <<
81  indent << " if (!value_reader.begin_element()) return false;\n";
82  array_helper(expression + "[" + idx + "]", array, dim_idx + 1, idx + "i", level + 1);
83  be_global->impl_ <<
84  indent << " if (!value_reader.end_element()) return false;\n" <<
85  indent << "}\n" <<
86  indent << "if (!value_reader.end_array()) return false;\n";
87  } else {
88  if (primitive) {
89  const size_t dim = array->dims()[dim_idx]->ev()->u.ulval;
90  AST_Type* const actual = resolveActualType(array->base_type());
91  const AST_PredefinedType::PredefinedType pt =
92  dynamic_cast<AST_PredefinedType*>(actual)->pt();
93  be_global->impl_ <<
94  indent << "if (!value_reader.begin_array()) return false;\n";
95  be_global->impl_ << indent <<
96  "if (!value_reader.read_" << primitive_type(pt) << "_array (" << expression << (use_cxx11 ? ".data()" : "") << ", " << dim << ")) return false;\n";
97  be_global->impl_ <<
98  indent << "if (!value_reader.end_array()) return false;\n";
99 
100  } else {
101  generate_read(expression, "", array->base_type(), idx + "i", level);
102  }
103  }
104  }
105 
106  void sequence_helper(const std::string& expression, AST_Sequence* sequence,
107  const std::string& idx, int level)
108  {
109  // TODO: Take advantage of the size.
110  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
111  const std::string indent(level * 2, ' ');
112  be_global->impl_ <<
113  indent << "if (!value_reader.begin_sequence()) return false;\n" <<
114  indent << "for (" << (use_cxx11 ? "size_t " : "unsigned int ") << idx << " = 0; "
115  "value_reader.elements_remaining(); ++" << idx << ") {\n";
116  if (use_cxx11) {
117  be_global->impl_ << indent << " " << expression << ".resize(" << expression << ".size() + 1);\n";
118  } else {
119  be_global->impl_ << indent << " OpenDDS::DCPS::grow(" << expression << ");\n";
120  }
121  be_global->impl_ <<
122  indent << " if (!value_reader.begin_element()) return false;\n";
123  generate_read(expression + "[" + idx + "]", "", sequence->base_type(), idx + "i", level + 1);
124  be_global->impl_ <<
125  indent << " if (!value_reader.end_element()) return false;\n" <<
126  indent << "}\n" <<
127  indent << "if (!value_reader.end_sequence()) return false;\n";
128  }
129 
130  void generate_read(const std::string& expression, const std::string& accessor,
131  AST_Type* type, const std::string& idx, int level)
132  {
133  AST_Type* const actual = resolveActualType(type);
134 
135  const Classification c = classify(actual);
136  if (c & CL_SEQUENCE) {
137  AST_Sequence* const sequence = dynamic_cast<AST_Sequence*>(actual);
138  sequence_helper(expression + accessor, sequence, idx, level);
139  return;
140 
141  } else if (c & CL_ARRAY) {
142  AST_Array* const array = dynamic_cast<AST_Array*>(actual);
143  array_helper(expression + accessor, array, 0, idx, level);
144  return;
145  }
146 
147  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
148  const std::string indent(level * 2, ' ');
149  if (c & CL_FIXED) {
150  be_global->impl_ <<
151  indent << "if (!value_reader.read_fixed(" << expression << ")) return false;\n";
152 
153  } else if (c & CL_STRING) {
154  be_global->impl_ <<
155  indent << "{\n" <<
156  indent << " " << ((c & CL_WIDE) ? "WString" : "String") << " x;\n" <<
157  indent << " if (!value_reader.read_" << ((c & CL_WIDE) ? "w" : "")
158  << "string(x)) return false;\n" <<
159  indent << " " << expression << accessor << " = x" << (use_cxx11 ? "" : ".c_str()")
160  << ";\n" <<
161  indent << "}\n";
162 
163  } else if (c & CL_PRIMITIVE) {
164  const AST_PredefinedType::PredefinedType pt =
165  dynamic_cast<AST_PredefinedType*>(actual)->pt();
166  if (pt == AST_PredefinedType::PT_boolean) {
167  be_global->impl_ <<
168  indent << "{\n" <<
169  indent << " " << scoped(type->name()) << " bx;\n" <<
170  indent << " if (!value_reader.read_" << primitive_type(pt)
171  << "(bx)) return false;\n" <<
172  indent << " " << expression << accessor << " = bx;\n" <<
173  indent << "}\n";
174  } else {
175  be_global->impl_ <<
176  indent << "if (!value_reader.read_" << primitive_type(pt) << '(' << expression << accessor << ")) return false;\n";
177  }
178  } else {
179  be_global->impl_ <<
180  indent << "if (!vread(value_reader, " << expression << accessor <<
181  ")) return false;\n";
182  }
183  }
184 
185  std::string branch_helper(const std::string&, AST_Decl* branch,
186  const std::string& field_name,
187  AST_Type* type,
188  const std::string&,
189  bool,
190  Intro&,
191  const std::string&)
192  {
193  AST_Type* const actual = resolveActualType(type);
194  std::string decl = field_type_name(dynamic_cast<AST_Field*>(branch), type);
195 
196  const Classification c = classify(actual);
197  if (c & CL_STRING) {
198  decl = (c & CL_WIDE) ? "std::wstring" : "std::string";
199  }
200 
201  be_global->impl_ <<
202  " if (!value_reader.begin_union_member()) return false;\n"
203  " " << decl << " bv;\n";
204  generate_read("bv", "", type, "i", 2);
205  be_global->impl_ <<
206  " value." << field_name << "(bv" << ((c & CL_STRING) ? ".c_str()" : "") << ");\n" <<
207  " if (!value_reader.end_union_member()) return false;\n";
208  return "";
209  }
210 }
211 
213  UTL_ScopedName* name,
214  const std::vector<AST_EnumVal*>& contents,
215  const char*)
216 {
217  be_global->add_include("dds/DCPS/Util.h", BE_GlobalData::STREAM_H);
218  be_global->add_include("dds/DCPS/ValueReader.h", BE_GlobalData::STREAM_H);
219 
220  const std::string type_name = scoped(name);
221 
222  {
223  NamespaceGuard guard;
224 
225  Function read("vread", "bool");
226  read.addArg("value_reader", "OpenDDS::DCPS::ValueReader&");
227  read.addArg("value", type_name + "&");
228  read.endArgs();
229 
230  be_global->impl_ <<
231  " static const ListEnumHelper::Pair pairs[] = {";
232 
233  for (size_t i = 0; i != contents.size(); ++i) {
234  if (i) {
235  be_global->impl_ << ',';
236  }
237  const std::string idl_name = canonical_name(contents[i]);
238  be_global->impl_ <<
239  '{' << '"' << idl_name << '"' << ',' << contents[i]->constant_value()->ev()->u.eval << '}';
240  }
241 
242  be_global->impl_ <<
243  ",{0,0}};\n"
244  " ListEnumHelper helper(pairs);\n"
245  " return value_reader.read_enum(value, helper);\n";
246  }
247 
248  return true;
249 }
250 
252  UTL_ScopedName*,
253  AST_Type*,
254  const char*)
255 {
256  return true;
257 }
258 
260  UTL_ScopedName* name,
261  const std::vector<AST_Field*>& fields,
262  AST_Type::SIZE_TYPE,
263  const char*)
264 {
265  be_global->add_include("dds/DCPS/Util.h", BE_GlobalData::STREAM_H);
266  be_global->add_include("dds/DCPS/ValueReader.h", BE_GlobalData::STREAM_H);
267 
268  const std::string type_name = scoped(name);
269  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
270  const std::string accessor = use_cxx11 ? "()" : "";
271 
272  {
273  NamespaceGuard guard;
274 
275  Function read("vread", "bool");
276  read.addArg("value_reader", "OpenDDS::DCPS::ValueReader&");
277  read.addArg("value", type_name + "&");
278  read.endArgs();
279 
280  be_global->impl_ <<
281  " static const ListMemberHelper::Pair pairs[] = {";
282 
283  for (size_t i = 0; i != fields.size(); ++i) {
284  if (i) {
285  be_global->impl_ << ',';
286  }
287  const std::string idl_name = canonical_name(fields[i]);
288  be_global->impl_ <<
289  '{' << '"' << idl_name << '"' << ',' << be_global->get_id(fields[i]) << '}';
290  }
291 
292  be_global->impl_ <<
293  ",{0,0}};\n"
294  " ListMemberHelper helper(pairs);\n";
295 
296  be_global->impl_ <<
297  " if (!value_reader.begin_struct()) return false;\n"
298  " XTypes::MemberId member_id;\n"
299  " while (value_reader.begin_struct_member(member_id, helper)) {\n"
300  " switch (member_id) {\n";
301 
302  for (std::vector<AST_Field*>::const_iterator pos = fields.begin(), limit = fields.end();
303  pos != limit; ++pos) {
304  AST_Field* const field = *pos;
305  const std::string field_name = field->local_name()->get_string();
306  be_global->impl_ <<
307  " case " << be_global->get_id(field) << ": {\n";
308  generate_read("value." + field_name, accessor, field->field_type(), "i", 3);
309  be_global->impl_ <<
310  " break;\n"
311  " }\n";
312  }
313 
314  be_global->impl_ <<
315  " }\n"
316  " if (!value_reader.end_struct_member()) return false;\n"
317  " }\n"
318  " if (!value_reader.end_struct()) return false;\n"
319  " return true;\n";
320  }
321 
322  return true;
323 }
324 
325 
327  UTL_ScopedName* name,
328  const std::vector<AST_UnionBranch*>& branches,
329  AST_Type* discriminator,
330  const char*)
331 {
332  be_global->add_include("dds/DCPS/Util.h", BE_GlobalData::STREAM_H);
333  be_global->add_include("dds/DCPS/ValueReader.h", BE_GlobalData::STREAM_H);
334 
335  const std::string type_name = scoped(name);
336 
337  {
338  NamespaceGuard guard;
339 
340  Function read("vread", "bool");
341  read.addArg("value_reader", "OpenDDS::DCPS::ValueReader&");
342  read.addArg("value", type_name + "&");
343  read.endArgs();
344 
345  be_global->impl_ <<
346  " if (!value_reader.begin_union()) return false;\n"
347  " if (!value_reader.begin_discriminator()) return false;\n"
348  " {\n"
349  " " << scoped(discriminator->name()) << " d;\n";
350  generate_read("d", "", discriminator, "i", 2);
351  be_global->impl_ <<
352  " value._d(d);\n"
353  " }\n"
354  " if (!value_reader.end_discriminator()) return false;\n";
355 
356  generateSwitchForUnion(u, "value._d()", branch_helper, branches,
357  discriminator, "", "", type_name.c_str(),
358  false, false);
359  be_global->impl_ <<
360  " if (!value_reader.end_union()) return false;\n"
361  " return true;\n";
362  }
363 
364  return true;
365 }
Classification classify(AST_Type *type)
const Classification CL_STRING
const Classification CL_WIDE
std::string field_type_name(AST_Field *field, AST_Type *field_type)
const Classification CL_PRIMITIVE
bool gen_typedef(AST_Typedef *, UTL_ScopedName *, AST_Type *, const char *)
const Classification CL_ARRAY
bool gen_union(AST_Union *, UTL_ScopedName *, const std::vector< AST_UnionBranch *> &, AST_Type *, const char *)
bool generateSwitchForUnion(AST_Union *u, const char *switchExpr, CommonFn commonFn, const std::vector< AST_UnionBranch *> &branches, AST_Type *discriminator, const char *statementPrefix, const char *namePrefix="", const char *uni="", bool forceDisableDefault=false, bool parens=true, bool breaks=true, CommonFn commonFn2=0)
returns true if a default: branch was generated (no default: label in IDL)
std::string canonical_name(UTL_ScopedName *sn)
AST_Type * resolveActualType(AST_Type *element)
bool gen_enum(AST_Enum *, UTL_ScopedName *name, const std::vector< AST_EnumVal *> &contents, const char *repoid)
ssize_t read(ACE_HANDLE handle, void *buf, size_t len)
bool gen_struct(AST_Structure *node, UTL_ScopedName *name, const std::vector< AST_Field *> &fields, AST_Type::SIZE_TYPE size, const char *repoid)
void endArgs()
const char *const name
Definition: debug.cpp:60
const Classification CL_FIXED
std::string scoped(UTL_ScopedName *sn, EscapeContext ec=EscapeContext_Normal)
void addArg(const char *name, const std::string &type)
BE_GlobalData * be_global
Definition: be_global.cpp:44
const Classification CL_SEQUENCE