OpenDDS  Snapshot(2023/04/28-20:55)
dynamic_data_adapter_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 "field_info.h"
9 #include "be_extern.h"
10 
11 #include <utl_identifier.h>
12 
13 #include <string>
14 
15 using namespace AstTypeClassification;
16 
17 namespace {
18  class DynamicDataAdapterGuard : public PreprocessorIfGuard {
19  public:
20  DynamicDataAdapterGuard()
21  : PreprocessorIfGuard(" OPENDDS_HAS_DYNAMIC_DATA_ADAPTER", true, false)
22  {
23  }
24  };
25 
26  class NoSafetyProfileGuard : public PreprocessorIfGuard {
27  public:
28  NoSafetyProfileGuard()
29  : PreprocessorIfGuard("ndef OPENDDS_SAFETY_PROFILE")
30  {
31  }
32  };
33 
34  std::string op(bool set)
35  {
36  return set ? "set" : "get";
37  }
38 
39  bool access_details(bool set, AST_Decl* node, AST_Type* type, std::string& op_type,
40  std::string& extra_access, bool& is_complex)
41  {
42  const bool cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
43  AST_Type* const t = resolveActualType(type);
44  AST_Type* const node_as_type = dynamic_cast<AST_Type*>(node);
45  switch (t->node_type()) {
46  case AST_Decl::NT_pre_defined:
47  if (set && cxx11 && node_as_type &&
48  resolveActualType(node_as_type)->node_type() == AST_Decl::NT_sequence &&
49  dynamic_cast<AST_PredefinedType*>(t)->pt() == AST_PredefinedType::PT_boolean) {
50  // setting a std::vector<bool> requires a special case
51  op_type = "bool_vector_elem";
52  } else {
53  op_type = "simple";
54  }
55  return true;
56  case AST_Decl::NT_enum:
57  op_type = "enum";
58  return true;
59  case AST_Decl::NT_string:
60  if (cxx11) {
61  op_type = "cpp11_s8";
62  } else {
63  if (set) {
64  extra_access = ".inout()";
65  }
66  op_type = "s8";
67  }
68  return true;
69  case AST_Decl::NT_wstring:
70  if (cxx11) {
71  op_type = "cpp11_s16";
72  } else {
73  if (set) {
74  extra_access = ".inout()";
75  }
76  op_type = "s16";
77  }
78  return true;
79  case AST_Decl::NT_struct:
80  case AST_Decl::NT_union:
81  case AST_Decl::NT_sequence:
82  is_complex = true;
83  op_type = set ? "direct_complex" : "complex";
84  return true;
85  case AST_Decl::NT_array:
86  is_complex = true;
87  if (set) {
88  op_type = cxx11 ? "direct_complex" : "indirect_complex";
89  } else {
90  op_type = "complex";
91  }
92  return true;
93  default:
94  return false;
95  }
96  }
97 
98  void generate_op(unsigned indent, bool set, AST_Type* type, const std::string& type_name,
99  const std::string& op_type, bool is_complex, const std::string& value,
100  const char* rc_dest = "return")
101  {
102  RefWrapper type_wrapper(type, type_name, "");
103  type_wrapper.dynamic_data_adapter_ = true;
104  type_wrapper.done();
105  std::string template_params;
106  if (type_wrapper.needs_dda_tag()) {
107  template_params = "<" + type_name + ", " + type_wrapper.get_tag_name() + ">";
108  } else if (is_complex) {
109  template_params = "<" + type_name + ", " + type_name + ">";
110  }
111 
112  be_global->impl_ <<
113  std::string(indent * 2, ' ') << rc_dest << " " <<
114  op(set) << "_" << op_type << "_raw_value" << template_params << "(method, ";
115  if (set) {
116  be_global->impl_ << value << ", id, source, tk";
117  } else {
118  be_global->impl_ << "dest, tk, " << value << ", id";
119  }
120  be_global->impl_ << ");\n";
121  }
122 
123  void generate_dynamic_data_adapter_access_field(
124  AST_Union* union_node, bool set,
125  OpenDDS::XTypes::MemberId field_id, AST_Type* field_type, AST_Field* field = 0)
126  {
127  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
128  const bool disc = union_node && field_id == OpenDDS::XTypes::DISCRIMINATOR_ID;
129  const std::string cpp_field_name = disc ? "_d" : field->local_name()->get_string();
130 
131  be_global->impl_ <<
132  " case ";
133  if (disc) {
134  be_global->impl_ << "OpenDDS::XTypes::DISCRIMINATOR_ID";
135  } else {
136  be_global->impl_ << field_id;
137  }
138  be_global->impl_ << ":\n"
139  " {\n";
140 
141  std::string op_type;
142  std::string extra_access;
143  bool is_complex = false;
144  if ((field && !be_global->dynamic_data_adapter(field->field_type())) ||
145  !access_details(set, field, field_type, op_type, extra_access, is_complex)) {
146  be_global->impl_ <<
147  " ACE_UNUSED_ARG(" << (set ? "source" : "dest") << ");\n"
148  " ACE_UNUSED_ARG(tk);\n"
149  " return missing_dda(method, id);\n";
150 
151  } else {
152  const std::string type_name = field_type_name(field, field_type);
153  std::string value = "value_.";
154  const char* rc_dest = "return";
155  if (union_node) {
156  if (set) {
157  // Setting a union branch or discriminator requires a temporary
158  be_global->impl_ <<
159  " " << type_name << " temp;\n";
160  rc_dest = "rc =";
161  value = "temp";
162  } else {
163  value += cpp_field_name + "()";
164  if (!use_cxx11 && classify(field_type) & CL_ARRAY) {
165  // Unions return pointer to array elements, get reference to array.
166  value = std::string("*reinterpret_cast<") + type_name + "*>(" + value + ")";
167  }
168  }
169  } else {
170  value += (use_cxx11 ? "_" : "") + cpp_field_name;
171  }
172  generate_op(4, set, field_type, type_name, op_type, is_complex,
173  value + extra_access, rc_dest);
174  if (union_node && set) {
175  be_global->impl_ <<
176  " if (rc == DDS::RETCODE_OK) {\n"
177  " value_." << cpp_field_name << "(temp);\n"
178  " }\n"
179  " return rc;\n";
180  }
181  }
182 
183  be_global->impl_ <<
184  " }\n";
185  }
186 
187  bool generate_dynamic_data_adapter_access(AST_Decl* node, RefWrapper& wrapper, bool set)
188  {
189  AST_Structure* struct_node = 0;
190  AST_Union* union_node = 0;
191  AST_Sequence* seq_node = 0;
192  AST_Array* array_node = 0;
193  if (!node) {
194  return false;
195  }
196  switch (node->node_type()) {
197  case AST_Decl::NT_struct:
198  struct_node = dynamic_cast<AST_Structure*>(node);
199  break;
200  case AST_Decl::NT_union:
201  union_node = dynamic_cast<AST_Union*>(node);
202  break;
203  case AST_Decl::NT_sequence:
204  seq_node = dynamic_cast<AST_Sequence*>(node);
205  break;
206  case AST_Decl::NT_array:
207  array_node = dynamic_cast<AST_Array*>(node);
208  break;
209  default:
210  return false;
211  }
212 
213  be_global->impl_ << " DDS::ReturnCode_t " << op(set) << "_raw_value(const char* method, ";
214  if (set) {
215  be_global->impl_ << "DDS::MemberId id, const void* source, DDS::TypeKind tk";
216  } else {
217  be_global->impl_ << "void* dest, DDS::TypeKind tk, DDS::MemberId id";
218  }
219  be_global->impl_ << ")\n"
220  " {\n";
221 
222  if (set) {
223  be_global->impl_ <<
224  " DDS::ReturnCode_t rc = assert_mutable(method);\n"
225  " if (rc != DDS::RETCODE_OK) {\n"
226  " return rc;\n"
227  " }\n";
228  }
229 
230  if (struct_node || union_node) {
231  be_global->impl_ <<
232  " switch (id) {\n";
233 
234  if (union_node) {
235  generate_dynamic_data_adapter_access_field(
236  union_node, set, OpenDDS::XTypes::DISCRIMINATOR_ID, union_node->disc_type());
237  }
238 
239  const Fields fields(union_node ? union_node : struct_node);
240  for (Fields::Iterator i = fields.begin(); i != fields.end(); ++i) {
241  AST_Field* const field = *i;
242  generate_dynamic_data_adapter_access_field(
243  union_node, set, be_global->get_id(field), field->field_type(), field);
244  }
245 
246  be_global->impl_ <<
247  " default:\n"
248  " return invalid_id(method, id);\n"
249  " }\n";
250  } else if (seq_node || array_node) {
251  AST_Type* const base_type = seq_node ? seq_node->base_type() : array_node->base_type();
252  AST_Type* const named_type = deepest_named_type(base_type);
253 
254  std::string op_type;
255  std::string extra_access;
256  bool is_complex = false;
257  if (access_details(set, node, base_type, op_type, extra_access, is_complex)) {
258  be_global->impl_ << " ";
259  if (!set) {
260  be_global->impl_ << "const DDS::ReturnCode_t ";
261  }
262  be_global->impl_ << "rc = check_index(method, id, ";
263  if (seq_node) {
264  be_global->impl_ << wrapper.seq_get_length();
265  } else {
266  be_global->impl_ << array_element_count(array_node);
267  }
268  be_global->impl_ << ");\n"
269  " if (rc != DDS::RETCODE_OK) {\n"
270  " return rc;\n"
271  " }\n";
272  generate_op(2, set, base_type, scoped(named_type->name()), op_type, is_complex,
273  wrapper.flat_collection_access("id") + extra_access);
274  } else {
275  be_global->impl_ <<
276  " ACE_UNUSED_ARG(" << (set ? "source" : "dest") << ");\n"
277  " ACE_UNUSED_ARG(tk);\n"
278  " return missing_dda(method, id);\n";
279  }
280  } else {
281  return false;
282  }
283 
284  be_global->impl_ <<
285  " }\n";
286 
287  return true;
288  }
289 
290  void generate_get_dynamic_data_adapter(
291  const std::string& cpp_name, const std::string& tag, const std::string& export_macro,
292  bool is_const, bool dda_generated)
293  {
294  be_global->header_ <<
295  "template <>\n" <<
296  export_macro << "DDS::DynamicData_ptr get_dynamic_data_adapter<" << cpp_name << tag <<
297  ">(DDS::DynamicType_ptr type, " << (is_const ? "const " : "") << cpp_name << "& value);\n"
298  "\n";
299 
300  be_global->impl_ <<
301  "template <>\n"
302  "DDS::DynamicData_ptr get_dynamic_data_adapter<" << cpp_name << tag <<
303  ">(DDS::DynamicType_ptr type, " << (is_const ? "const " : "") << cpp_name << "& value)\n"
304  "{\n";
305  if (dda_generated) {
306  be_global->impl_ <<
307  "# if OPENDDS_HAS_DYNAMIC_DATA_ADAPTER\n"
308  " if (type) {\n"
309  " return new DynamicDataAdapterImpl<" << cpp_name << tag << ">(type, value);\n"
310  " }\n"
311  "# else\n";
312  }
313  be_global->impl_ <<
314  " ACE_UNUSED_ARG(type);\n"
315  " ACE_UNUSED_ARG(value);\n";
316  if (dda_generated) {
317  be_global->impl_ <<
318  "# endif\n";
319  }
320  be_global->impl_ <<
321  " return 0;\n"
322  "}\n"
323  "\n";
324  }
325 
326  template <typename Type>
327  bool is_collection_of_interface_or_value_type(Type* type)
328  {
329  const AST_Decl::NodeType kind = resolveActualType(type->base_type())->node_type();
330  return kind == AST_Decl::NT_interface || kind == AST_Decl::NT_valuetype;
331  }
332 
333  bool generate_dynamic_data_adapter(
334  AST_Decl* node, const std::string* use_scoped_name = 0, AST_Typedef* typedef_node = 0)
335  {
336  AST_Structure* struct_node = 0;
337  AST_Union* union_node = 0;
338  AST_Sequence* seq_node = 0;
339  AST_Array* array_node = 0;
340  if (!node) {
341  return false;
342  }
343  switch (node->node_type()) {
344  case AST_Decl::NT_struct:
345  struct_node = dynamic_cast<AST_Structure*>(node);
346  break;
347  case AST_Decl::NT_union:
348  union_node = dynamic_cast<AST_Union*>(node);
349  break;
350  case AST_Decl::NT_sequence:
351  seq_node = dynamic_cast<AST_Sequence*>(node);
352  if (is_collection_of_interface_or_value_type(seq_node)) {
353  return true;
354  }
355  break;
356  case AST_Decl::NT_array:
357  array_node = dynamic_cast<AST_Array*>(node);
358  if (is_collection_of_interface_or_value_type(array_node)) {
359  return true;
360  }
361  break;
362  default:
363  return true;
364  }
365  const std::string cpp_name = use_scoped_name ? *use_scoped_name : scoped(node->name());
366  const bool generate = be_global->dynamic_data_adapter(typedef_node ? typedef_node : node);
367  RefWrapper wrapper(dynamic_cast<AST_Type*>(node), cpp_name, "value_", false);
368  wrapper.dynamic_data_adapter_ = true;
369  wrapper.done();
370 
371  be_global->add_include("dds/DCPS/XTypes/DynamicDataAdapter.h", BE_GlobalData::STREAM_H);
372 
373  if (struct_node || union_node) {
374  const Fields fields(union_node ? union_node : struct_node);
375  FieldInfo::EleLenSet anonymous_seq_generated;
376  for (Fields::Iterator i = fields.begin(); i != fields.end(); ++i) {
377  AST_Field* const field = *i;
378  if (field->field_type()->anonymous()) {
379  FieldInfo af(*field);
380  if (af.arr_ || (af.seq_ && af.is_new(anonymous_seq_generated))) {
381  if (!generate_dynamic_data_adapter(af.type_, &af.scoped_type_)) {
383  "Failed to generate adapter for anonymous type of field", field);
384  }
385  }
386  }
387  }
388  }
389 
390  std::vector<std::string> ns;
391  ns.push_back("OpenDDS");
392  ns.push_back("XTypes");
393  NamespaceGuard ng(true, &ns);
394 
395  std::string tag;
396  if (wrapper.needs_dda_tag()) {
397  tag = ", " + wrapper.get_tag_name();
398  } else {
399  tag = ", " + cpp_name;
400  }
401 
402  if (generate) {
403  DynamicDataAdapterGuard ddag;
404 
405  be_global->impl_ <<
406  "template <>\n"
407  "class DynamicDataAdapterImpl<" << cpp_name << tag << " > : public DynamicDataAdapter_T<"
408  << cpp_name << "> {\n"
409  "public:\n"
410  " DynamicDataAdapterImpl(DDS::DynamicType_ptr type, " << cpp_name << "& value)\n"
411  " : DynamicDataAdapter_T<" << cpp_name << ">(type, value)\n"
412  " {\n"
413  " }\n"
414  "\n"
415  " DynamicDataAdapterImpl(DDS::DynamicType_ptr type, const " << cpp_name << "& value)\n"
416  " : DynamicDataAdapter_T<" << cpp_name << ">(type, value)\n"
417  " {\n"
418  " }\n"
419  "\n";
420  if (struct_node || seq_node || array_node) {
421  be_global->impl_ <<
422  " DDS::UInt32 get_item_count()\n"
423  " {\n"
424  " return ";
425  if (struct_node) {
426  be_global->impl_ << struct_node->nfields();
427  } else if (seq_node) {
428  be_global->impl_ << wrapper.seq_get_length();
429  } else if (array_node) {
430  be_global->impl_ << array_element_count(array_node);
431  }
432  be_global->impl_ << ";\n"
433  " }\n"
434  "\n";
435  }
436 
437  if (seq_node) {
438  // TODO: Set new elements to default values?
439  be_global->impl_ <<
440  " DDS::MemberId get_member_id_at_index_impl(DDS::UInt32 index)\n"
441  " {\n"
442  " const DDS::UInt32 count = " << wrapper.seq_get_length() << ";\n"
443  " if (!read_only_ && index >= count) {\n"
444  " " << wrapper.seq_resize("index + 1") <<
445  " return index;\n"
446  " }\n"
447  " return check_index(\"get_member_id_at_index\", index, count)"
448  " == DDS::RETCODE_OK ? index : MEMBER_ID_INVALID;\n"
449  " }\n"
450  "\n";
451  }
452 
453  be_global->impl_ <<
454  "protected:\n";
455 
456  if (!generate_dynamic_data_adapter_access(node, wrapper, false)) {
457  return false;
458  }
459  be_global->impl_ << "\n";
460  if (!generate_dynamic_data_adapter_access(node, wrapper, true)) {
461  return false;
462  }
463 
464  be_global->impl_ <<
465  "};\n"
466  "\n";
467  }
468 
469  {
470  NoSafetyProfileGuard nspg;
471 
472  wrapper.generate_tag();
473 
474  std::string export_macro = be_global->export_macro().c_str();
475  if (export_macro.size()) {
476  export_macro += " ";
477  }
478 
479  generate_get_dynamic_data_adapter(cpp_name, tag, export_macro, true, generate);
480  generate_get_dynamic_data_adapter(cpp_name, tag, export_macro, false, generate);
481 
482  be_global->header_ <<
483  "template <>\n" <<
484  export_macro << "const " << cpp_name << "* get_dynamic_data_adapter_value<" <<
485  cpp_name << tag << ">(DDS::DynamicData_ptr dd);\n"
486  "\n";
487 
488  be_global->impl_ <<
489  "template <>\n"
490  "const " << cpp_name << "* get_dynamic_data_adapter_value<" <<
491  cpp_name << tag << ">(DDS::DynamicData_ptr dd)\n"
492  "{\n"
493  " ACE_UNUSED_ARG(dd);\n";
494  if (generate) {
495  be_global->impl_ <<
496  "# if OPENDDS_HAS_DYNAMIC_DATA_ADAPTER\n"
497  " typedef DynamicDataAdapterImpl<" << cpp_name << tag << "> Dda;\n"
498  " const Dda* const dda = dynamic_cast<Dda*>(dd);\n"
499  " if (dda) {\n"
500  " return &dda->wrapped();\n"
501  " }\n"
502  "# endif\n";
503  }
504  be_global->impl_ <<
505  " return 0;\n"
506  "}\n";
507  }
508 
509  return true;
510  }
511 }
512 
513 bool dynamic_data_adapter_generator::gen_struct(AST_Structure* node, UTL_ScopedName*,
514  const std::vector<AST_Field*>&, AST_Type::SIZE_TYPE, const char*)
515 {
516  return generate_dynamic_data_adapter(node);
517 }
518 
519 bool dynamic_data_adapter_generator::gen_typedef(AST_Typedef* typedef_node, UTL_ScopedName* name,
520  AST_Type* type, const char*)
521 {
522  const AST_Decl::NodeType nt = type->node_type();
523  if (nt != AST_Decl::NT_sequence && nt != AST_Decl::NT_array) {
524  return true;
525  }
526  const std::string cpp_name = scoped(name);
527  return generate_dynamic_data_adapter(type, &cpp_name, typedef_node);
528 }
529 
530 bool dynamic_data_adapter_generator::gen_union(AST_Union* node, UTL_ScopedName*,
531  const std::vector<AST_UnionBranch*>&, AST_Type*, const char*)
532 {
533  return generate_dynamic_data_adapter(node);
534 }
Classification classify(AST_Type *type)
const char * c_str(void) const
bool is_complex(TypeKind tk)
ACE_CDR::ULong MemberId
Definition: TypeObject.h:910
const LogLevel::Value value
Definition: debug.cpp:61
std::string get_tag_name() const
std::string field_type_name(AST_Field *field, AST_Type *field_type)
std::string seq_get_length() const
const ACE_CDR::ULong DISCRIMINATOR_ID
Implementation specific sentinel for a union discriminator used in DynamicData.
Definition: TypeObject.h:913
AST_Type * deepest_named_type(AST_Type *type)
const Classification CL_ARRAY
AST_Type * resolveActualType(AST_Type *element)
const char *const name
Definition: debug.cpp:60
bool gen_struct(AST_Structure *node, UTL_ScopedName *name, const std::vector< AST_Field *> &fields, AST_Type::SIZE_TYPE size, const char *repoid)
std::string flat_collection_access(std::string index) const
std::string scoped(UTL_ScopedName *sn, EscapeContext ec=EscapeContext_Normal)
std::string seq_resize(const std::string &new_size) const
std::set< EleLen > EleLenSet
Definition: field_info.h:31
BE_GlobalData * be_global
Definition: be_global.cpp:44
ACE_CDR::ULong array_element_count(AST_Array *arr)
void generate_tag() const
bool needs_dda_tag() const
RefWrapper & done(Intro *intro=0)
bool dynamic_data_adapter_
void misc_error_and_abort(const std::string &message, AST_Decl *node=0)
Report a miscellaneous error and abort.
bool gen_union(AST_Union *node, UTL_ScopedName *name, const std::vector< AST_UnionBranch *> &branches, AST_Type *type, const char *repoid)
void generate(AST_Structure *node)
called directly by dds_visitor::visit_structure() if -Wb,java
bool gen_typedef(AST_Typedef *node, UTL_ScopedName *name, AST_Type *type, const char *repoid)