OpenDDS  Snapshot(2023/04/28-20:55)
value_writer_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 "global_extern.h"
10 
11 #include <dds/DCPS/Definitions.h>
12 
13 #include <utl_identifier.h>
14 #include <utl_labellist.h>
15 #include <ast_fixed.h>
16 
17 using namespace AstTypeClassification;
18 
19 namespace {
20 
21  void generate_write(const std::string& expression, AST_Type* type, const std::string& idx, int level = 1);
22 
23  std::string primitive_type(AST_PredefinedType::PredefinedType pt)
24  {
25  switch (pt) {
26  case AST_PredefinedType::PT_long:
27  return "int32";
28  case AST_PredefinedType::PT_ulong:
29  return "uint32";
30  case AST_PredefinedType::PT_longlong:
31  return "int64";
32  case AST_PredefinedType::PT_ulonglong:
33  return "uint64";
34  case AST_PredefinedType::PT_short:
35  return "int16";
36  case AST_PredefinedType::PT_ushort:
37  return "uint16";
38 #if OPENDDS_HAS_EXPLICIT_INTS
39  case AST_PredefinedType::PT_int8:
40  return "int8";
41  case AST_PredefinedType::PT_uint8:
42  return "uint8";
43 #endif
44  case AST_PredefinedType::PT_float:
45  return "float32";
46  case AST_PredefinedType::PT_double:
47  return "float64";
48  case AST_PredefinedType::PT_longdouble:
49  return "float128";
50  case AST_PredefinedType::PT_char:
51  return "char8";
52  case AST_PredefinedType::PT_wchar:
53  return "char16";
54  case AST_PredefinedType::PT_boolean:
55  return "boolean";
56  case AST_PredefinedType::PT_octet:
57  return "byte";
58  default:
59  return "";
60  }
61  }
62 
63  void array_helper(const std::string& expression, AST_Array* array,
64  size_t dim_idx, const std::string& idx, int level)
65  {
66  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
67  const std::string indent(level * 2, ' ');
68  const Classification c = classify(array->base_type());
69  const bool primitive = c & CL_PRIMITIVE;
70  // When we have a primitive type the last dimension is written using the write_*_array
71  // operation, when we have a not primitive type the last dimension is written element by element
72  // in a loop in the generated code
73  if ((primitive && (dim_idx < array->n_dims() - 1)) || (!primitive && (dim_idx < array->n_dims()))) {
74  const size_t dim = array->dims()[dim_idx]->ev()->u.ulval;
75  be_global->impl_ <<
76  indent << "value_writer.begin_array();\n";
77  be_global->impl_ <<
78  indent << "for (" << (use_cxx11 ? "size_t " : "::CORBA::ULong ") << idx << " = 0; "
79  << idx << " != " << dim << "; ++" << idx << ") {\n" <<
80  indent << " value_writer.begin_element(" << idx << ");\n";
81  array_helper(expression + "[" + idx + "]", array, dim_idx + 1, idx + "i", level + 1);
82  be_global->impl_ <<
83  indent << " value_writer.end_element();\n" <<
84  indent << "}\n" <<
85  indent << "value_writer.end_array();\n";
86  } else {
87  if (primitive) {
88  const size_t dim = array->dims()[dim_idx]->ev()->u.ulval;
89  AST_Type* const actual = resolveActualType(array->base_type());
90  const AST_PredefinedType::PredefinedType pt =
91  dynamic_cast<AST_PredefinedType*>(actual)->pt();
92  be_global->impl_ <<
93  indent << "value_writer.begin_array();\n";
94  be_global->impl_ << indent <<
95  "value_writer.write_" << primitive_type(pt) << "_array (" << expression << (use_cxx11 ? ".data()" : "") << ", " << dim << ");\n";
96  be_global->impl_ <<
97  indent << "value_writer.end_array();\n";
98 
99  } else {
100  generate_write(expression, array->base_type(), idx + "i", level);
101  }
102  }
103  }
104 
105  void sequence_helper(const std::string& expression, AST_Sequence* sequence,
106  const std::string& idx, int level)
107  {
108  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
109  const char* const length_func = use_cxx11 ? "size" : "length";
110  const std::string indent(level * 2, ' ');
111  be_global->impl_ << indent << "value_writer.begin_sequence();\n";
112 
113  const Classification c = classify(sequence->base_type());
114  AST_Type* const actual = resolveActualType(sequence->base_type());
115  bool use_optimized_write_ = false;
116  if (c & CL_PRIMITIVE) {
117  if (use_cxx11) {
118  const AST_PredefinedType::PredefinedType pt = dynamic_cast<AST_PredefinedType*>(actual)->pt();
119  use_optimized_write_ = !(pt == AST_PredefinedType::PT_boolean);
120  } else {
121  use_optimized_write_ = true;
122  }
123  }
124 
125  if (use_optimized_write_) {
126  const AST_PredefinedType::PredefinedType pt =
127  dynamic_cast<AST_PredefinedType*>(actual)->pt();
128  be_global->impl_ << indent <<
129  "value_writer.write_" << primitive_type(pt) << "_array (" << expression << (use_cxx11 ? ".data()" : ".get_buffer()") << ", " << expression << "." << length_func << "());\n";
130  } else {
131  be_global->impl_ <<
132  indent << "for (" << (use_cxx11 ? "size_t " : "::CORBA::ULong ") << idx << " = 0; "
133  << idx << " != " << expression << "." << length_func << "(); ++" << idx << ") {\n" <<
134  indent << " value_writer.begin_element(" << idx << ");\n";
135  generate_write(expression + "[" + idx + "]", sequence->base_type(), idx + "i", level + 1);
136  be_global->impl_ <<
137  indent << " value_writer.end_element();\n" <<
138  indent << "}\n";
139  }
140 
141  be_global->impl_ <<
142  indent << "value_writer.end_sequence();\n";
143  }
144 
145  void generate_write(const std::string& expression, AST_Type* type, const std::string& idx, int level)
146  {
147  AST_Type* const actual = resolveActualType(type);
148 
149  const Classification c = classify(actual);
150  if (c & CL_SEQUENCE) {
151  AST_Sequence* const sequence = dynamic_cast<AST_Sequence*>(actual);
152  sequence_helper(expression, sequence, idx, level);
153  return;
154 
155  } else if (c & CL_ARRAY) {
156  AST_Array* const array = dynamic_cast<AST_Array*>(actual);
157  array_helper(expression, array, 0, idx, level);
158  return;
159  }
160 
161  be_global->impl_ << std::string(level * 2, ' ');
162 
163  if (c & CL_FIXED) {
164  be_global->impl_ <<
165  "value_writer.write_fixed(" << expression << ");\n";
166 
167  } else if (c & CL_STRING) {
168  be_global->impl_ <<
169  "value_writer.write_" << ((c & CL_WIDE) ? "w" : "") << "string(" << expression << ");\n";
170 
171  } else if (c & CL_PRIMITIVE) {
172  const AST_PredefinedType::PredefinedType pt =
173  dynamic_cast<AST_PredefinedType*>(actual)->pt();
174  be_global->impl_ <<
175  "value_writer.write_" << primitive_type(pt) << '(' << expression << ");\n";
176 
177  } else {
178  be_global->impl_ <<
179  "vwrite(value_writer, " << expression << ");\n";
180  }
181  }
182 
183  std::string branch_helper(const std::string&,
184  AST_Decl* branch,
185  const std::string& field_name,
186  AST_Type* type,
187  const std::string&,
188  bool,
189  Intro&,
190  const std::string&)
191  {
192  be_global->impl_ <<
193  " value_writer.begin_union_member(\"" << canonical_name(branch) << "\");\n";
194  generate_write("value." + field_name + "()", type, "i", 2);
195  be_global->impl_ <<
196  " value_writer.end_union_member();\n";
197  return "";
198  }
199 }
200 
202  UTL_ScopedName* name,
203  const std::vector<AST_EnumVal*>& contents,
204  const char*)
205 {
206  be_global->add_include("dds/DCPS/ValueWriter.h", BE_GlobalData::STREAM_H);
207 
208  const std::string type_name = scoped(name);
209  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
210 
211  {
212  NamespaceGuard guard;
213 
214  Function write("vwrite", "void");
215  write.addArg("value_writer", "OpenDDS::DCPS::ValueWriter&");
216  write.addArg("value", "const " + type_name + "&");
217  write.endArgs();
218 
219  be_global->impl_ <<
220  " switch (value) {\n";
221  for (std::vector<AST_EnumVal*>::const_iterator pos = contents.begin(), limit = contents.end();
222  pos != limit; ++pos) {
223  AST_EnumVal* const val = *pos;
224  const std::string value_name = (use_cxx11 ? (type_name + "::") : module_scope(name))
225  + val->local_name()->get_string();
226  be_global->impl_ <<
227  " case " << value_name << ":\n"
228  " value_writer.write_enum(\"" << canonical_name(val) << "\", " << value_name << ");\n"
229  " break;\n";
230  }
231  be_global->impl_ << " }\n";
232  }
233 
234  return true;
235 }
236 
238  UTL_ScopedName*,
239  AST_Type*,
240  const char*)
241 {
242  return true;
243 }
244 
246  UTL_ScopedName* name,
247  const std::vector<AST_Field*>& fields,
248  AST_Type::SIZE_TYPE,
249  const char*)
250 {
251  be_global->add_include("dds/DCPS/ValueWriter.h", BE_GlobalData::STREAM_H);
252 
253  const std::string type_name = scoped(name);
254  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
255  const std::string accessor_suffix = use_cxx11 ? "()" : "";
256 
257  {
258  NamespaceGuard guard;
259 
260  Function write("vwrite", "void");
261  write.addArg("value_writer", "OpenDDS::DCPS::ValueWriter&");
262  write.addArg("value", "const " + type_name + "&");
263  write.endArgs();
264 
265  be_global->impl_ <<
266  " value_writer.begin_struct();\n";
267  for (std::vector<AST_Field*>::const_iterator pos = fields.begin(), limit = fields.end();
268  pos != limit; ++pos) {
269  AST_Field* const field = *pos;
270  const std::string field_name = field->local_name()->get_string();
271  const std::string idl_name = canonical_name(field);
272  be_global->impl_ <<
273  " value_writer.begin_struct_member(XTypes::MemberDescriptorImpl(\"" << idl_name << "\", "
274  << (be_global->is_key(field) ? "true" : "false") << "));\n";
275  generate_write("value." + field_name + accessor_suffix, field->field_type(), "i");
276  be_global->impl_ <<
277  " value_writer.end_struct_member();\n";
278  }
279  be_global->impl_ <<
280  " value_writer.end_struct();\n";
281  }
282 
283  return true;
284 }
285 
286 
288  UTL_ScopedName* name,
289  const std::vector<AST_UnionBranch*>& branches,
290  AST_Type* discriminator,
291  const char*)
292 {
293  be_global->add_include("dds/DCPS/ValueWriter.h", BE_GlobalData::STREAM_H);
294 
295  const std::string type_name = scoped(name);
296 
297  {
298  NamespaceGuard guard;
299 
300  Function write("vwrite", "void");
301  write.addArg("value_writer", "OpenDDS::DCPS::ValueWriter&");
302  write.addArg("value", "const " + type_name + "&");
303  write.endArgs();
304 
305  be_global->impl_ <<
306  " value_writer.begin_union();\n"
307  " value_writer.begin_discriminator();\n";
308  generate_write("value._d()" , discriminator, "i");
309  be_global->impl_ <<
310  " value_writer.end_discriminator();\n";
311 
312  generateSwitchForUnion(u, "value._d()", branch_helper, branches,
313  discriminator, "", "", type_name.c_str(),
314  false, false);
315  be_global->impl_ <<
316  " value_writer.end_union();\n";
317  }
318 
319  return true;
320 }
Classification classify(AST_Type *type)
const Classification CL_STRING
const Classification CL_WIDE
bool gen_enum(AST_Enum *, UTL_ScopedName *name, const std::vector< AST_EnumVal *> &contents, const char *repoid)
const Classification CL_PRIMITIVE
const Classification CL_ARRAY
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)
bool gen_struct(AST_Structure *node, UTL_ScopedName *name, const std::vector< AST_Field *> &fields, AST_Type::SIZE_TYPE size, const char *repoid)
bool gen_union(AST_Union *, UTL_ScopedName *, const std::vector< AST_UnionBranch *> &, AST_Type *, const char *)
AST_Type * resolveActualType(AST_Type *element)
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
std::string module_scope(UTL_ScopedName *sn)
::DDS::ReturnCode_t write(in<%SCOPED%> instance_data, in ::DDS::InstanceHandle_t handle)
bool gen_typedef(AST_Typedef *, UTL_ScopedName *, AST_Type *, const char *)
const Classification CL_SEQUENCE