marshal_generator.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  * Distributed under the OpenDDS License.
00005  * See: http://www.opendds.org/license.html
00006  */
00007 
00008 #include "marshal_generator.h"
00009 #include "be_extern.h"
00010 
00011 #include "utl_identifier.h"
00012 
00013 #include <string>
00014 #include <map>
00015 #include <sstream>
00016 #include <iostream>
00017 #include <cctype>
00018 using std::string;
00019 
00020 using namespace AstTypeClassification;
00021 
00022 bool marshal_generator::gen_enum(AST_Enum*, UTL_ScopedName* name,
00023   const std::vector<AST_EnumVal*>&, const char*)
00024 {
00025   NamespaceGuard ng;
00026   be_global->add_include("dds/DCPS/Serializer.h");
00027   string cxx = scoped(name); // name as a C++ class
00028   {
00029     Function insertion("operator<<", "bool");
00030     insertion.addArg("strm", "Serializer&");
00031     insertion.addArg("enumval", "const " + cxx + "&");
00032     insertion.endArgs();
00033     be_global->impl_ <<
00034       "  return strm << static_cast<CORBA::ULong>(enumval);\n";
00035   }
00036   {
00037     Function extraction("operator>>", "bool");
00038     extraction.addArg("strm", "Serializer&");
00039     extraction.addArg("enumval", cxx + "&");
00040     extraction.endArgs();
00041     be_global->impl_ <<
00042       "  CORBA::ULong temp = 0;\n"
00043       "  if (strm >> temp) {\n"
00044       "    enumval = static_cast<" << cxx << ">(temp);\n"
00045       "    return true;\n"
00046       "  }\n"
00047       "  return false;\n";
00048   }
00049   return true;
00050 }
00051 
00052 namespace {
00053 
00054   string getMaxSizeExprPrimitive(AST_Type* type)
00055   {
00056     if (type->node_type() != AST_Decl::NT_pre_defined) {
00057       return "";
00058     }
00059     AST_PredefinedType* pt = AST_PredefinedType::narrow_from_decl(type);
00060     switch (pt->pt()) {
00061     case AST_PredefinedType::PT_octet:
00062       return "max_marshaled_size_octet()";
00063     case AST_PredefinedType::PT_char:
00064       return "max_marshaled_size_char()";
00065     case AST_PredefinedType::PT_wchar:
00066       return "max_marshaled_size_wchar()";
00067     case AST_PredefinedType::PT_boolean:
00068       return "max_marshaled_size_boolean()";
00069     default:
00070       return "gen_max_marshaled_size(" + scoped(type->name()) + "())";
00071     }
00072   }
00073 
00074   string getSerializerName(AST_Type* type)
00075   {
00076     switch (AST_PredefinedType::narrow_from_decl(type)->pt()) {
00077     case AST_PredefinedType::PT_long:
00078       return "long";
00079     case AST_PredefinedType::PT_ulong:
00080       return "ulong";
00081     case AST_PredefinedType::PT_short:
00082       return "short";
00083     case AST_PredefinedType::PT_ushort:
00084       return "ushort";
00085     case AST_PredefinedType::PT_octet:
00086       return "octet";
00087     case AST_PredefinedType::PT_char:
00088       return "char";
00089     case AST_PredefinedType::PT_wchar:
00090       return "wchar";
00091     case AST_PredefinedType::PT_float:
00092       return "float";
00093     case AST_PredefinedType::PT_double:
00094       return "double";
00095     case AST_PredefinedType::PT_longlong:
00096       return "longlong";
00097     case AST_PredefinedType::PT_ulonglong:
00098       return "ulonglong";
00099     case AST_PredefinedType::PT_longdouble:
00100       return "longdouble";
00101     case AST_PredefinedType::PT_boolean:
00102       return "boolean";
00103     default:
00104       return "";
00105     }
00106   }
00107 
00108   string nameOfSeqHeader(AST_Type* elem)
00109   {
00110     string ser = getSerializerName(elem);
00111     if (ser.size()) {
00112       ser[0] = static_cast<char>(std::toupper(ser[0]));
00113     }
00114     if (ser[0] == 'U' || ser[0] == 'W') {
00115       ser[1] = static_cast<char>(std::toupper(ser[1]));
00116     }
00117     const size_t fourthLast = ser.size() - 4;
00118     if (ser.size() > 7 && ser.substr(fourthLast) == "long") {
00119       ser[fourthLast] = static_cast<char>(std::toupper(ser[fourthLast]));
00120     }
00121     if (ser == "Longdouble") return "LongDouble";
00122     return ser;
00123   }
00124 
00125   string streamAndCheck(const string& expr, size_t indent = 2)
00126   {
00127     string idt(indent, ' ');
00128     return idt + "if (!(strm " + expr + ")) {\n" +
00129       idt + "  return false;\n" +
00130       idt + "}\n";
00131   }
00132 
00133   string checkAlignment(AST_Type* elem)
00134   {
00135     // At this point the stream must be 4-byte aligned (from the sequence
00136     // length), but it might need to be 8-byte aligned for primitives > 4.
00137     switch (AST_PredefinedType::narrow_from_decl(elem)->pt()) {
00138     case AST_PredefinedType::PT_longlong:
00139     case AST_PredefinedType::PT_ulonglong:
00140     case AST_PredefinedType::PT_double:
00141     case AST_PredefinedType::PT_longdouble:
00142       return
00143         "  if ((size + padding) % 8) {\n"
00144         "    padding += 4;\n"
00145         "  }\n";
00146     default:
00147       return "";
00148     }
00149   }
00150 
00151   bool isRtpsSpecialSequence(const string& cxx)
00152   {
00153     return cxx == "OpenDDS::RTPS::ParameterList";
00154   }
00155 
00156   bool genRtpsSpecialSequence(const string& cxx)
00157   {
00158     {
00159       Function find_size("gen_find_size", "void");
00160       find_size.addArg("seq", "const " + cxx + "&");
00161       find_size.addArg("size", "size_t&");
00162       find_size.addArg("padding", "size_t&");
00163       find_size.endArgs();
00164       be_global->impl_ <<
00165         "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
00166         "    if (seq[i]._d() == OpenDDS::RTPS::PID_SENTINEL) continue;\n"
00167         "    size_t param_size = 0, param_padding = 0;\n"
00168         "    gen_find_size(seq[i], param_size, param_padding);\n"
00169         "    size += param_size + param_padding;\n"
00170         "    if (size % 4) {\n"
00171         "      size += 4 - (size % 4);\n"
00172         "    }\n"
00173         "  }\n"
00174         "  size += 4; /* PID_SENTINEL */\n";
00175     }
00176     {
00177       Function insertion("operator<<", "bool");
00178       insertion.addArg("strm", "Serializer&");
00179       insertion.addArg("seq", "const " + cxx + "&");
00180       insertion.endArgs();
00181       be_global->impl_ <<
00182         "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
00183         "    if (seq[i]._d() == OpenDDS::RTPS::PID_SENTINEL) continue;\n"
00184         "    if (!(strm << seq[i])) {\n"
00185         "      return false;\n"
00186         "    }\n"
00187         "  }\n"
00188         "  return (strm << OpenDDS::RTPS::PID_SENTINEL)\n"
00189         "    && (strm << OpenDDS::RTPS::PID_PAD);\n";
00190     }
00191     {
00192       Function extraction("operator>>", "bool");
00193       extraction.addArg("strm", "Serializer&");
00194       extraction.addArg("seq", cxx + "&");
00195       extraction.endArgs();
00196       be_global->impl_ <<
00197         "  while (true) {\n"
00198         "    const CORBA::ULong len = seq.length();\n"
00199         "    seq.length(len + 1);\n"
00200         "    if (!(strm >> seq[len])) {\n"
00201         "      return false;\n"
00202         "    }\n"
00203         "    if (seq[len]._d() == OpenDDS::RTPS::PID_SENTINEL) {\n"
00204         "      seq.length(len);\n"
00205         "      return true;\n"
00206         "    }\n"
00207         "  }\n";
00208     }
00209     return true;
00210   }
00211 
00212   void gen_sequence(UTL_ScopedName* tdname, AST_Sequence* seq)
00213   {
00214     be_global->add_include("dds/DCPS/Serializer.h");
00215     NamespaceGuard ng;
00216     string cxx = scoped(tdname);
00217     if (isRtpsSpecialSequence(cxx)) {
00218       genRtpsSpecialSequence(cxx);
00219       return;
00220     }
00221     AST_Type* elem = resolveActualType(seq->base_type());
00222     Classification elem_cls = classify(elem);
00223     if (!elem->in_main_file()) {
00224       if (elem->node_type() == AST_Decl::NT_pre_defined) {
00225         if (be_global->language_mapping() != BE_GlobalData::LANGMAP_FACE_CXX &&
00226             be_global->language_mapping() != BE_GlobalData::LANGMAP_SP_CXX) {
00227           be_global->add_include(("dds/CorbaSeq/" + nameOfSeqHeader(elem)
00228                                   + "SeqTypeSupportImpl.h").c_str(), BE_GlobalData::STREAM_CPP);
00229         }
00230       } else {
00231         be_global->add_referenced(elem->file_name().c_str());
00232       }
00233     }
00234     string cxx_elem = scoped(elem->name());
00235     {
00236       Function find_size("gen_find_size", "void");
00237       find_size.addArg("seq", "const " + cxx + "&");
00238       find_size.addArg("size", "size_t&");
00239       find_size.addArg("padding", "size_t&");
00240       find_size.endArgs();
00241       be_global->impl_ <<
00242         "  find_size_ulong(size, padding);\n"
00243         "  if (seq.length() == 0) {\n"
00244         "    return;\n"
00245         "  }\n";
00246       if (elem_cls & CL_ENUM) {
00247         be_global->impl_ <<
00248           "  size += seq.length() * max_marshaled_size_ulong();\n";
00249       } else if (elem_cls & CL_PRIMITIVE) {
00250         be_global->impl_ << checkAlignment(elem) <<
00251           "  size += seq.length() * " << getMaxSizeExprPrimitive(elem) << ";\n";
00252       } else if (elem_cls & CL_INTERFACE) {
00253         be_global->impl_ <<
00254           "  // sequence of objrefs is not marshaled\n";
00255       } else if (elem_cls == CL_UNKNOWN) {
00256         be_global->impl_ <<
00257           "  // sequence of unknown/unsupported type\n";
00258       } else { // String, Struct, Array, Sequence, Union
00259         be_global->impl_ <<
00260           "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n";
00261         if (elem_cls & CL_STRING) {
00262           be_global->impl_ <<
00263             "    find_size_ulong(size, padding);\n"
00264             "    if (seq[i]) {\n"
00265             "      size += ACE_OS::strlen(seq[i])"
00266             << ((elem_cls & CL_WIDE)
00267                 ? " * OpenDDS::DCPS::Serializer::WCHAR_SIZE;\n"
00268                 : " + 1;\n") <<
00269             "    }\n";
00270         } else if (elem_cls & CL_ARRAY) {
00271           be_global->impl_ <<
00272             "    " << cxx_elem << "_var tmp_var = " << cxx_elem
00273             << "_dup(seq[i]);\n"
00274             "    " << cxx_elem << "_forany tmp = tmp_var.inout();\n"
00275             "    gen_find_size(tmp, size, padding);\n";
00276         } else { // Struct, Sequence, Union
00277           be_global->impl_ <<
00278             "    gen_find_size(seq[i], size, padding);\n";
00279         }
00280         be_global->impl_ <<
00281           "  }\n";
00282       }
00283     }
00284     {
00285       Function insertion("operator<<", "bool");
00286       insertion.addArg("strm", "Serializer&");
00287       insertion.addArg("seq", "const " + cxx + "&");
00288       insertion.endArgs();
00289       be_global->impl_ <<
00290         "  const CORBA::ULong length = seq.length();\n"
00291         << streamAndCheck("<< length") <<
00292         "  if (length == 0) {\n"
00293         "    return true;\n"
00294         "  }\n";
00295       if (elem_cls & CL_PRIMITIVE) {
00296         be_global->impl_ <<
00297           "  return strm.write_" << getSerializerName(elem)
00298           << "_array(seq.get_buffer(), length);\n";
00299       } else if (elem_cls & CL_INTERFACE) {
00300         be_global->impl_ <<
00301           "  return false; // sequence of objrefs is not marshaled\n";
00302       } else if (elem_cls == CL_UNKNOWN) {
00303         be_global->impl_ <<
00304           "  return false; // sequence of unknown/unsupported type\n";
00305       } else { // Enum, String, Struct, Array, Sequence, Union
00306         be_global->impl_ <<
00307           "  for (CORBA::ULong i = 0; i < length; ++i) {\n";
00308         if (elem_cls & CL_ARRAY) {
00309           const string typedefname = scoped(seq->base_type()->name());
00310           be_global->impl_ <<
00311             "    " << typedefname << "_var tmp_var = " << typedefname
00312             << "_dup(seq[i]);\n"
00313             "    " << typedefname << "_forany tmp = tmp_var.inout();\n"
00314             << streamAndCheck("<< tmp", 4);
00315         } else {
00316           be_global->impl_ << streamAndCheck("<< seq[i]", 4);
00317         }
00318         be_global->impl_ <<
00319           "  }\n"
00320           "  return true;\n";
00321       }
00322     }
00323     {
00324       Function extraction("operator>>", "bool");
00325       extraction.addArg("strm", "Serializer&");
00326       extraction.addArg("seq", cxx + "&");
00327       extraction.endArgs();
00328       be_global->impl_ <<
00329         "  CORBA::ULong length;\n"
00330         << streamAndCheck(">> length");
00331       if (!seq->unbounded()) {
00332         be_global->impl_ <<
00333           "  if (length > seq.maximum()) {\n"
00334           "    return false;\n"
00335           "  }\n";
00336       }
00337       be_global->impl_ <<
00338         "  seq.length(length);\n";
00339       if (elem_cls & CL_PRIMITIVE) {
00340         be_global->impl_ <<
00341           "  if (length == 0) {\n"
00342           "    return true;\n"
00343           "  }\n"
00344           "  return strm.read_" << getSerializerName(elem)
00345           << "_array(seq.get_buffer(), length);\n";
00346       } else if (elem_cls & CL_INTERFACE) {
00347         be_global->impl_ <<
00348           "  return false; // sequence of objrefs is not marshaled\n";
00349       } else if (elem_cls == CL_UNKNOWN) {
00350         be_global->impl_ <<
00351           "  return false; // sequence of unknown/unsupported type\n";
00352       } else { // Enum, String, Struct, Array, Sequence, Union
00353         be_global->impl_ <<
00354           "  for (CORBA::ULong i = 0; i < length; ++i) {\n";
00355         if (elem_cls & CL_ARRAY) {
00356           const string typedefname = scoped(seq->base_type()->name());
00357           be_global->impl_ <<
00358             "    " << typedefname << "_var tmp = " << typedefname
00359             << "_alloc();\n"
00360             "    " << typedefname << "_forany fa = tmp.inout();\n"
00361             << streamAndCheck(">> fa", 4) <<
00362             "    " << typedefname << "_copy(seq[i], tmp.in());\n";
00363         } else if (elem_cls & CL_STRING) {
00364           if (elem_cls & CL_BOUNDED) {
00365             AST_String* str = AST_String::narrow_from_decl(elem);
00366             std::ostringstream args;
00367             args << "seq[i].out(), " << str->max_size()->ev()->u.ulval;
00368             be_global->impl_ <<
00369               streamAndCheck(">> " + getWrapper(args.str(), elem, WD_INPUT), 4);
00370           } else { // unbounded string
00371             const string getbuffer =
00372               (be_global->language_mapping() == BE_GlobalData::LANGMAP_NONE)
00373               ? ".get_buffer()" : "";
00374             be_global->impl_ << streamAndCheck(">> seq" + getbuffer + "[i]", 4);
00375           }
00376         } else { // Enum, Struct, Sequence, Union
00377           be_global->impl_ << streamAndCheck(">> seq[i]", 4);
00378         }
00379         be_global->impl_ <<
00380           "  }\n"
00381           "  return true;\n";
00382       }
00383     }
00384   }
00385 
00386   string getAlignment(AST_Type* elem)
00387   {
00388     if (elem->node_type() == AST_Decl::NT_enum) {
00389       return "4";
00390     }
00391     switch (AST_PredefinedType::narrow_from_decl(elem)->pt()) {
00392     case AST_PredefinedType::PT_short:
00393     case AST_PredefinedType::PT_ushort:
00394       return "2";
00395     case AST_PredefinedType::PT_long:
00396     case AST_PredefinedType::PT_ulong:
00397     case AST_PredefinedType::PT_float:
00398       return "4";
00399     case AST_PredefinedType::PT_longlong:
00400     case AST_PredefinedType::PT_ulonglong:
00401     case AST_PredefinedType::PT_double:
00402     case AST_PredefinedType::PT_longdouble:
00403       return "8";
00404     default:
00405       return "";
00406     }
00407   }
00408 
00409   void gen_array(UTL_ScopedName* name, AST_Array* arr)
00410   {
00411     be_global->add_include("dds/DCPS/Serializer.h");
00412     NamespaceGuard ng;
00413     string cxx = scoped(name);
00414     AST_Type* elem = resolveActualType(arr->base_type());
00415     Classification elem_cls = classify(elem);
00416     if (!elem->in_main_file()
00417         && elem->node_type() != AST_Decl::NT_pre_defined) {
00418       be_global->add_referenced(elem->file_name().c_str());
00419     }
00420     string cxx_elem = scoped(elem->name());
00421     size_t n_elems = 1;
00422     for (size_t i = 0; i < arr->n_dims(); ++i) {
00423       n_elems *= arr->dims()[i]->ev()->u.ulval;
00424     }
00425     {
00426       Function find_size("gen_find_size", "void");
00427       find_size.addArg("arr", "const " + cxx + "_forany&");
00428       find_size.addArg("size", "size_t&");
00429       find_size.addArg("padding", "size_t&");
00430       find_size.endArgs();
00431       if (elem_cls & CL_ENUM) {
00432         be_global->impl_ <<
00433           "  find_size_ulong(size, padding);\n";
00434           if (n_elems > 1) {
00435             be_global->impl_ <<
00436               "  size += " << n_elems - 1 << " * max_marshaled_size_ulong();\n";
00437           }
00438       } else if (elem_cls & CL_PRIMITIVE) {
00439         const string align = getAlignment(elem);
00440         if (!align.empty()) {
00441           be_global->impl_ <<
00442             "  if ((size + padding) % " << align << ") {\n"
00443             "    padding += " << align << " - ((size + padding) % " << align
00444             << ");\n"
00445             "  }\n";
00446         }
00447         be_global->impl_ <<
00448           "  size += " << n_elems << " * " << getMaxSizeExprPrimitive(elem)
00449           << ";\n";
00450       } else { // String, Struct, Array, Sequence, Union
00451         string indent = "  ";
00452         NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
00453         if (elem_cls & CL_STRING) {
00454           be_global->impl_ <<
00455             indent << "find_size_ulong(size, padding);\n" <<
00456             indent << "size += ACE_OS::strlen(arr" << nfl.index_ << ".in())"
00457             << ((elem_cls & CL_WIDE)
00458                 ? " * OpenDDS::DCPS::Serializer::WCHAR_SIZE;\n"
00459                 : " + 1;\n");
00460         } else if (elem_cls & CL_ARRAY) {
00461           be_global->impl_ <<
00462             indent << cxx_elem << "_var tmp_var = " << cxx_elem
00463             << "_dup(arr" << nfl.index_ << ");\n" <<
00464             indent << cxx_elem << "_forany tmp = tmp_var.inout();\n" <<
00465             indent << "gen_find_size(tmp, size, padding);\n";
00466         } else { // Struct, Sequence, Union
00467           be_global->impl_ <<
00468             indent << "gen_find_size(arr" << nfl.index_
00469             << ", size, padding);\n";
00470         }
00471       }
00472     }
00473     {
00474       Function insertion("operator<<", "bool");
00475       insertion.addArg("strm", "Serializer&");
00476       insertion.addArg("arr", "const " + cxx + "_forany&");
00477       insertion.endArgs();
00478       if (elem_cls & CL_PRIMITIVE) {
00479         be_global->impl_ <<
00480           "  return strm.write_" << getSerializerName(elem)
00481           << "_array(arr.in(), " << n_elems << ");\n";
00482       } else { // Enum, String, Struct, Array, Sequence, Union
00483         {
00484           string indent = "  ";
00485           NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
00486           if (elem_cls & CL_ARRAY) {
00487             be_global->impl_ <<
00488               indent << cxx_elem << "_var tmp_var = " << cxx_elem
00489               << "_dup(arr" << nfl.index_ << ");\n" <<
00490               indent << cxx_elem << "_forany tmp = tmp_var.inout();\n" <<
00491               streamAndCheck("<< tmp", indent.size());
00492           } else {
00493             string suffix = (elem_cls & CL_STRING) ? ".in()" : "";
00494             be_global->impl_ <<
00495               streamAndCheck("<< arr" + nfl.index_ + suffix , indent.size());
00496           }
00497         }
00498         be_global->impl_ << "  return true;\n";
00499       }
00500     }
00501     {
00502       Function extraction("operator>>", "bool");
00503       extraction.addArg("strm", "Serializer&");
00504       extraction.addArg("arr", cxx + "_forany&");
00505       extraction.endArgs();
00506       if (elem_cls & CL_PRIMITIVE) {
00507         be_global->impl_ <<
00508           "  return strm.read_" << getSerializerName(elem)
00509           << "_array(arr.out(), " << n_elems << ");\n";
00510       } else { // Enum, String, Struct, Array, Sequence, Union
00511         {
00512           string indent = "  ";
00513           NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
00514           if (elem_cls & CL_ARRAY) {
00515             const string typedefname = scoped(arr->base_type()->name());
00516             be_global->impl_ <<
00517               indent << typedefname << "_var tmp = " << typedefname
00518               << "_alloc();\n" <<
00519               indent << typedefname << "_forany fa = tmp.inout();\n"
00520               << streamAndCheck(">> fa", indent.size()) <<
00521               indent << typedefname << "_copy(arr" << nfl.index_ <<
00522               ", tmp.in());\n";
00523           } else {
00524             string suffix = (elem_cls & CL_STRING) ? ".out()" : "";
00525             be_global->impl_ <<
00526               streamAndCheck(">> arr" + nfl.index_ + suffix, indent.size());
00527           }
00528         }
00529         be_global->impl_ << "  return true;\n";
00530       }
00531     }
00532   }
00533 
00534   string getArrayForany(const char* prefix, const char* fname,
00535                         const string& cxx_fld)
00536   {
00537     string local = fname;
00538     if (local.size() > 2 && local.substr(local.size() - 2, 2) == "()") {
00539       local.erase(local.size() - 2);
00540     }
00541     return cxx_fld + "_forany " + prefix + '_' + local + "(const_cast<"
00542       + cxx_fld + "_slice*>(" + prefix + "." + fname + "));";
00543   }
00544 
00545   // This function looks through the fields of a struct for the key
00546   // specified and returns the AST_Type associated with that key.
00547   // Because the key name can contain indexed arrays and nested
00548   // structures, things can get interesting.
00549   AST_Type* find_type(const std::vector<AST_Field*>& fields, const string& key)
00550   {
00551     string key_base = key;   // the field we are looking for here
00552     string key_rem;          // the sub-field we will look for recursively
00553     bool is_array = false;
00554     size_t pos = key.find_first_of(".[");
00555     if (pos != std::string::npos) {
00556       key_base = key.substr(0, pos);
00557       if (key[pos] == '[') {
00558         is_array = true;
00559         size_t l_brack = key.find("]");
00560         if (l_brack == std::string::npos) {
00561           throw std::string("Missing right bracket");
00562         } else if (l_brack != key.length()) {
00563           key_rem = key.substr(l_brack+1);
00564         }
00565       } else {
00566         key_rem = key.substr(pos+1);
00567       }
00568     }
00569     for (size_t i = 0; i < fields.size(); ++i) {
00570       string field_name = fields[i]->local_name()->get_string();
00571       if (field_name == key_base) {
00572         AST_Type* field_type = fields[i]->field_type();
00573         if (!is_array && key_rem.empty()) {
00574           // The requested key field matches this one.  We do not allow
00575           // arrays (must be indexed specifically) or structs (must
00576           // identify specific sub-fields).
00577           AST_Structure* sub_struct = dynamic_cast<AST_Structure*>(field_type);
00578           if (sub_struct != 0) {
00579             throw std::string("Structs not allowed as keys");
00580           }
00581           AST_Typedef* typedef_node = dynamic_cast<AST_Typedef*>(field_type);
00582           if (typedef_node != 0) {
00583             AST_Array* array_node =
00584               dynamic_cast<AST_Array*>(typedef_node->base_type());
00585             if (array_node != 0) {
00586               throw std::string("Arrays not allowed as keys");
00587             }
00588           }
00589           return field_type;
00590         } else if (is_array) {
00591           // must be a typedef of an array
00592           AST_Typedef* typedef_node = dynamic_cast<AST_Typedef*>(field_type);
00593           if (typedef_node == 0) {
00594             throw std::string("Indexing for non-array type");
00595           }
00596           AST_Array* array_node =
00597             dynamic_cast<AST_Array*>(typedef_node->base_type());
00598           if (array_node == 0) {
00599             throw std::string("Indexing for non-array type");
00600           }
00601           if (array_node->n_dims() > 1) {
00602             throw std::string("Only single dimension arrays allowed in keys");
00603           }
00604           if (key_rem == "") {
00605             return array_node->base_type();
00606           } else {
00607             // This must be a struct...
00608             if ((key_rem[0] != '.') || (key_rem.length() == 1)) {
00609               throw std::string("Unexpected characters after array index");
00610             } else {
00611               // Set up key_rem and field_type and let things fall into
00612               // the struct code below
00613               key_rem = key_rem.substr(1);
00614               field_type = array_node->base_type();
00615             }
00616           }
00617         }
00618 
00619         // nested structures
00620         AST_Structure* sub_struct = dynamic_cast<AST_Structure*>(field_type);
00621         if (sub_struct == 0) {
00622           throw std::string("Expected structure field for ") + key_base;
00623         }
00624         size_t nfields = sub_struct->nfields();
00625         std::vector<AST_Field*> sub_fields;
00626         sub_fields.reserve(nfields);
00627 
00628         for (unsigned long i = 0; i < nfields; ++i) {
00629           AST_Field** f;
00630           sub_struct->field(f, i);
00631           sub_fields.push_back(*f);
00632         }
00633         // find type of nested struct field
00634         return find_type(sub_fields, key_rem);
00635       }
00636     }
00637     throw std::string("Field not found.");
00638   }
00639 
00640   bool is_bounded_type(AST_Type* type)
00641   {
00642     bool bounded = true;
00643     static std::vector<AST_Type*> type_stack;
00644     type = resolveActualType(type);
00645     for (unsigned int i = 0; i < type_stack.size(); i++) {
00646       // If we encounter the same type recursively, then we are unbounded
00647       if (type == type_stack[i]) return false;
00648     }
00649     type_stack.push_back(type);
00650     Classification fld_cls = classify(type);
00651     if ((fld_cls & CL_STRING) && !(fld_cls & CL_BOUNDED)) {
00652       bounded = false;
00653     } else if (fld_cls & CL_STRUCTURE) {
00654       AST_Structure* struct_node = dynamic_cast<AST_Structure*>(type);
00655       for (unsigned long i = 0; i < struct_node->nfields(); ++i) {
00656         AST_Field** f;
00657         struct_node->field(f, i);
00658         if (!is_bounded_type((*f)->field_type())) {
00659           bounded = false;
00660           break;
00661         }
00662       }
00663     } else if (fld_cls & CL_SEQUENCE) {
00664       if (fld_cls & CL_BOUNDED) {
00665         AST_Sequence* seq_node = dynamic_cast<AST_Sequence*>(type);
00666         if (!is_bounded_type(seq_node->base_type())) bounded = false;
00667       } else {
00668         bounded = false;
00669       }
00670     } else if (fld_cls & CL_ARRAY) {
00671       AST_Array* array_node = dynamic_cast<AST_Array*>(type);
00672       if (!is_bounded_type(array_node->base_type())) bounded = false;
00673     } else if (fld_cls & CL_UNION) {
00674       AST_Union* union_node = dynamic_cast<AST_Union*>(type);
00675       for (unsigned long i = 0; i < union_node->nfields(); ++i) {
00676         AST_Field** f;
00677         union_node->field(f, i);
00678         if (!is_bounded_type((*f)->field_type())) {
00679           bounded = false;
00680           break;
00681         }
00682       }
00683     }
00684     type_stack.pop_back();
00685     return bounded;
00686   }
00687 
00688   void align(size_t alignment, size_t& size, size_t& padding)
00689   {
00690     if ((size + padding) % alignment) {
00691       padding += alignment - ((size + padding) % alignment);
00692     }
00693   }
00694 
00695   void max_marshaled_size(AST_Type* type, size_t& size, size_t& padding);
00696 
00697   // Max marshaled size of repeating 'type' 'n' times in the stream
00698   // (for an array or sequence)
00699   void mms_repeating(AST_Type* type, size_t n, size_t& size, size_t& padding)
00700   {
00701     if (n > 0) {
00702       // 1st element may need padding relative to whatever came before
00703       max_marshaled_size(type, size, padding);
00704     }
00705     if (n > 1) {
00706       // subsequent elements may need padding relative to prior element
00707       size_t prev_size = size, prev_pad = padding;
00708       max_marshaled_size(type, size, padding);
00709       size += (n - 2) * (size - prev_size);
00710       padding += (n - 2) * (padding - prev_pad);
00711     }
00712   }
00713 
00714   // Should only be called on bounded types (see above function)
00715   void max_marshaled_size(AST_Type* type, size_t& size, size_t& padding)
00716   {
00717     type = resolveActualType(type);
00718     switch (type->node_type()) {
00719     case AST_Decl::NT_pre_defined: {
00720         AST_PredefinedType* p = AST_PredefinedType::narrow_from_decl(type);
00721         switch (p->pt()) {
00722         case AST_PredefinedType::PT_char:
00723         case AST_PredefinedType::PT_boolean:
00724         case AST_PredefinedType::PT_octet:
00725           size += 1;
00726           break;
00727         case AST_PredefinedType::PT_short:
00728         case AST_PredefinedType::PT_ushort:
00729           align(2, size, padding);
00730           size += 2;
00731           break;
00732         case AST_PredefinedType::PT_wchar:
00733           size += 3; // see Serializer::max_marshaled_size_wchar()
00734           break;
00735         case AST_PredefinedType::PT_long:
00736         case AST_PredefinedType::PT_ulong:
00737         case AST_PredefinedType::PT_float:
00738           align(4, size, padding);
00739           size += 4;
00740           break;
00741         case AST_PredefinedType::PT_longlong:
00742         case AST_PredefinedType::PT_ulonglong:
00743         case AST_PredefinedType::PT_double:
00744           align(8, size, padding);
00745           size += 8;
00746           break;
00747         case AST_PredefinedType::PT_longdouble:
00748           align(8, size, padding);
00749           size += 16;
00750           break;
00751         default:
00752           // Anything else shouldn't be in a DDS type or is unbounded.
00753           break;
00754         }
00755         break;
00756       }
00757     case AST_Decl::NT_enum:
00758       align(4, size, padding);
00759       size += 4;
00760       break;
00761     case AST_Decl::NT_string:
00762     case AST_Decl::NT_wstring: {
00763         AST_String* string_node = dynamic_cast<AST_String*>(type);
00764         align(4, size, padding);
00765         size += 4;
00766         const int width = (string_node->width() == 1) ? 1 : 2 /*UTF-16*/;
00767         size += width * string_node->max_size()->ev()->u.ulval;
00768         if (type->node_type() == AST_Decl::NT_string) {
00769           size += 1; // narrow string includes the null terminator
00770         }
00771         break;
00772       }
00773     case AST_Decl::NT_struct: {
00774         AST_Structure* struct_node = dynamic_cast<AST_Structure*>(type);
00775         for (unsigned long i = 0; i < struct_node->nfields(); ++i) {
00776           AST_Field** f;
00777           struct_node->field(f, i);
00778           AST_Type* field_type = (*f)->field_type();
00779           max_marshaled_size(field_type, size, padding);
00780         }
00781         break;
00782       }
00783     case AST_Decl::NT_sequence: {
00784         AST_Sequence* seq_node = dynamic_cast<AST_Sequence*>(type);
00785         AST_Type* base_node = seq_node->base_type();
00786         size_t bound = seq_node->max_size()->ev()->u.ulval;
00787         align(4, size, padding);
00788         size += 4;
00789         mms_repeating(base_node, bound, size, padding);
00790         break;
00791       }
00792     case AST_Decl::NT_array: {
00793         AST_Array* array_node = dynamic_cast<AST_Array*>(type);
00794         AST_Type* base_node = array_node->base_type();
00795         size_t array_size = 1;
00796         AST_Expression** dims = array_node->dims();
00797         for (unsigned long i = 0; i < array_node->n_dims(); i++) {
00798           array_size *= dims[i]->ev()->u.ulval;
00799         }
00800         mms_repeating(base_node, array_size, size, padding);
00801         break;
00802       }
00803     case AST_Decl::NT_union: {
00804         AST_Union* union_node = dynamic_cast<AST_Union*>(type);
00805         max_marshaled_size(union_node->disc_type(), size, padding);
00806         size_t largest_field_size = 0, largest_field_pad = 0;
00807         const size_t starting_size = size, starting_pad = padding;
00808         for (unsigned long i = 0; i < union_node->nfields(); ++i) {
00809           AST_Field** f;
00810           union_node->field(f, i);
00811           AST_Type* field_type = (*f)->field_type();
00812           max_marshaled_size(field_type, size, padding);
00813           size_t field_size = size - starting_size,
00814             field_pad = padding - starting_pad;
00815           if (field_size > largest_field_size) {
00816             largest_field_size = field_size;
00817             largest_field_pad = field_pad;
00818           }
00819           // rewind:
00820           size = starting_size;
00821           padding = starting_pad;
00822         }
00823         size += largest_field_size;
00824         padding += largest_field_pad;
00825         break;
00826       }
00827     default:
00828       // Anything else should be not here or is unbounded
00829       break;
00830     }
00831   }
00832 }
00833 
00834 bool marshal_generator::gen_typedef(AST_Typedef*, UTL_ScopedName* name, AST_Type* base,
00835   const char*)
00836 {
00837   switch (base->node_type()) {
00838   case AST_Decl::NT_sequence:
00839     gen_sequence(name, AST_Sequence::narrow_from_decl(base));
00840     break;
00841   case AST_Decl::NT_array:
00842     gen_array(name, AST_Array::narrow_from_decl(base));
00843     break;
00844   default:
00845     return true;
00846   }
00847   return true;
00848 }
00849 
00850 namespace {
00851   // common to both fields (in structs) and branches (in unions)
00852   string findSizeCommon(const string& name, AST_Type* type,
00853                         const string& prefix, string& intro,
00854                         const string& = "") // same sig as streamCommon
00855   {
00856     AST_Type* typedeff = type;
00857     type = resolveActualType(type);
00858     Classification fld_cls = classify(type);
00859     const string qual = prefix + '.' + name;
00860     const string indent = (prefix == "uni") ? "      " : "  ";
00861     if (fld_cls & CL_ENUM) {
00862       return indent + "find_size_ulong(size, padding);\n";
00863     } else if (fld_cls & CL_STRING) {
00864       const string suffix = (prefix == "uni") ? "" : ".in()";
00865       return indent + "find_size_ulong(size, padding);\n" +
00866         indent + "size += ACE_OS::strlen(" + qual + suffix + ")"
00867         + ((fld_cls & CL_WIDE) ? " * OpenDDS::DCPS::Serializer::WCHAR_SIZE;\n"
00868                                : " + 1;\n");
00869     } else if (fld_cls & CL_PRIMITIVE) {
00870       string align = getAlignment(type);
00871       if (!align.empty()) {
00872         align =
00873           indent + "if ((size + padding) % " + align + ") {\n" +
00874           indent + "  padding += " + align + " - ((size + padding) % "
00875           + align + ");\n" +
00876           indent + "}\n";
00877       }
00878       return align +
00879         indent + "size += gen_max_marshaled_size(" +
00880         getWrapper(qual, type, WD_OUTPUT) + ");\n";
00881     } else if (fld_cls == CL_UNKNOWN) {
00882       return ""; // warning will be issued for the serialize functions
00883     } else { // sequence, struct, union, array
00884       string fieldref = prefix, local = name;
00885       if (fld_cls & CL_ARRAY) {
00886         intro += indent + getArrayForany(prefix.c_str(), name.c_str(),
00887                                          scoped(typedeff->name())) + '\n';
00888         fieldref += '_';
00889         if (local.size() > 2 && local.substr(local.size() - 2) == "()") {
00890           local.erase(local.size() - 2);
00891         }
00892       } else {
00893         fieldref += '.';
00894       }
00895       return indent +
00896         "gen_find_size(" + fieldref + local + ", size, padding);\n";
00897     }
00898   }
00899 
00900   // common to both fields (in structs) and branches (in unions)
00901   string streamCommon(const string& name, AST_Type* type,
00902                       const string& prefix, string& intro,
00903                       const string& stru = "")
00904   {
00905     AST_Type* typedeff = type;
00906     type = resolveActualType(type);
00907     Classification fld_cls = classify(type);
00908     const string qual = prefix + '.' + name, shift = prefix.substr(0, 2);
00909     WrapDirection dir = (shift == ">>") ? WD_INPUT : WD_OUTPUT;
00910     if ((fld_cls & CL_STRING) && (dir == WD_INPUT)) {
00911       return "(strm " + qual + ".out())";
00912     } else if (fld_cls & CL_PRIMITIVE) {
00913       return "(strm " + shift + ' '
00914         + getWrapper(qual.substr(3), type, dir) + ')';
00915     } else if (fld_cls == CL_UNKNOWN) {
00916       if (dir == WD_INPUT) { // no need to warn twice
00917         std::cerr << "WARNING: field " << name << " can not be serialized.  "
00918           "The struct or union it belongs to (" << stru <<
00919           ") can not be used in an OpenDDS topic type." << std::endl;
00920       }
00921       return "false";
00922     } else { // sequence, struct, union, array, enum, string(insertion)
00923       string fieldref = prefix, local = name;
00924       const bool accessor =
00925         local.size() > 2 && local.substr(local.size() - 2) == "()";
00926       if (fld_cls & CL_ARRAY) {
00927         string pre = prefix;
00928         if (shift == ">>" || shift == "<<") {
00929           pre.erase(0, 3);
00930         }
00931         if (accessor) {
00932           local.erase(local.size() - 2);
00933         }
00934         intro += "  " + getArrayForany(pre.c_str(), name.c_str(),
00935           scoped(typedeff->name())) + '\n';
00936         fieldref += '_';
00937       } else {
00938         fieldref += '.';
00939       }
00940       if ((fld_cls & CL_STRING) && !accessor) local += ".in()";
00941       return "(strm " + fieldref + local + ')';
00942     }
00943   }
00944 
00945   bool isRtpsSpecialStruct(const string& cxx)
00946   {
00947     return cxx == "OpenDDS::RTPS::SequenceNumberSet"
00948       || cxx == "OpenDDS::RTPS::FragmentNumberSet";
00949   }
00950 
00951   bool genRtpsSpecialStruct(const string& cxx)
00952   {
00953     {
00954       Function find_size("gen_find_size", "void");
00955       find_size.addArg("stru", "const " + cxx + "&");
00956       find_size.addArg("size", "size_t&");
00957       find_size.addArg("padding", "size_t&");
00958       find_size.endArgs();
00959       be_global->impl_ <<
00960         "  size += "
00961         << ((cxx == "OpenDDS::RTPS::SequenceNumberSet") ? "12" : "8")
00962         << " + 4 * ((stru.numBits + 31) / 32); // RTPS Custom\n";
00963     }
00964     {
00965       Function insertion("operator<<", "bool");
00966       insertion.addArg("strm", "Serializer&");
00967       insertion.addArg("stru", "const " + cxx + "&");
00968       insertion.endArgs();
00969       be_global->impl_ <<
00970         "  if ((strm << stru.bitmapBase) && (strm << stru.numBits)) {\n"
00971         "    const CORBA::ULong M = (stru.numBits + 31) / 32;\n"
00972         "    if (stru.bitmap.length() < M) {\n"
00973         "      return false;\n"
00974         "    }\n"
00975         "    for (CORBA::ULong i = 0; i < M; ++i) {\n"
00976         "      if (!(strm << stru.bitmap[i])) {\n"
00977         "        return false;\n"
00978         "      }\n"
00979         "    }\n"
00980         "    return true;\n"
00981         "  }\n"
00982         "  return false;\n";
00983     }
00984     {
00985       Function extraction("operator>>", "bool");
00986       extraction.addArg("strm", "Serializer&");
00987       extraction.addArg("stru", cxx + "&");
00988       extraction.endArgs();
00989       be_global->impl_ <<
00990         "  if ((strm >> stru.bitmapBase) && (strm >> stru.numBits)) {\n"
00991         "    const CORBA::ULong M = (stru.numBits + 31) / 32;\n"
00992         "    if (M > 8) {\n"
00993         "      return false;\n"
00994         "    }\n"
00995         "    stru.bitmap.length(M);\n"
00996         "    for (CORBA::ULong i = 0; i < M; ++i) {\n"
00997         "      if (!(strm >> stru.bitmap[i])) {\n"
00998         "        return false;\n"
00999         "      }\n"
01000         "    }\n"
01001         "    return true;\n"
01002         "  }\n"
01003         "  return false;\n";
01004     }
01005     return true;
01006   }
01007 
01008   struct RtpsFieldCustomizer {
01009 
01010     explicit RtpsFieldCustomizer(const string& cxx)
01011     {
01012       if (cxx == "OpenDDS::RTPS::DataSubmessage") {
01013         cst_["inlineQos"] = "stru.smHeader.flags & 2";
01014         iQosOffset_ = "16";
01015 
01016       } else if (cxx == "OpenDDS::RTPS::DataFragSubmessage") {
01017         cst_["inlineQos"] = "stru.smHeader.flags & 2";
01018         iQosOffset_ = "28";
01019 
01020       } else if (cxx == "OpenDDS::RTPS::InfoReplySubmessage") {
01021         cst_["multicastLocatorList"] = "stru.smHeader.flags & 2";
01022 
01023       } else if (cxx == "OpenDDS::RTPS::InfoTimestampSubmessage") {
01024         cst_["timestamp"] = "!(stru.smHeader.flags & 2)";
01025 
01026       } else if (cxx == "OpenDDS::RTPS::InfoReplyIp4Submessage") {
01027         cst_["multicastLocator"] = "stru.smHeader.flags & 2";
01028 
01029       } else if (cxx == "OpenDDS::RTPS::SubmessageHeader") {
01030         preamble_ =
01031           "  strm.swap_bytes(ACE_CDR_BYTE_ORDER != (stru.flags & 1));\n";
01032       }
01033     }
01034 
01035     string getConditional(const string& field_name) const
01036     {
01037       if (cst_.empty()) {
01038         return "";
01039       }
01040       std::map<string, string>::const_iterator it = cst_.find(field_name);
01041       if (it != cst_.end()) {
01042         return it->second;
01043       }
01044       return "";
01045     }
01046 
01047     string preFieldRead(const string& field_name) const
01048     {
01049       if (cst_.empty() || field_name != "inlineQos" || iQosOffset_.empty()) {
01050         return "";
01051       }
01052       return "strm.skip(stru.octetsToInlineQos - " + iQosOffset_ + ")\n"
01053         "    && ";
01054     }
01055 
01056     std::map<string, string> cst_;
01057     string iQosOffset_, preamble_;
01058   };
01059 }
01060 
01061 bool marshal_generator::gen_struct(AST_Structure*, UTL_ScopedName* name,
01062   const std::vector<AST_Field*>& fields, AST_Type::SIZE_TYPE, const char*)
01063 {
01064   NamespaceGuard ng;
01065   be_global->add_include("dds/DCPS/Serializer.h");
01066   string cxx = scoped(name); // name as a C++ class
01067   if (isRtpsSpecialStruct(cxx)) {
01068     return genRtpsSpecialStruct(cxx);
01069   }
01070   RtpsFieldCustomizer rtpsCustom(cxx);
01071   {
01072     Function find_size("gen_find_size", "void");
01073     find_size.addArg("stru", "const " + cxx + "&");
01074     find_size.addArg("size", "size_t&");
01075     find_size.addArg("padding", "size_t&");
01076     find_size.endArgs();
01077     string expr, intro;
01078     for (size_t i = 0; i < fields.size(); ++i) {
01079       AST_Type* field_type = resolveActualType(fields[i]->field_type());
01080       if (!field_type->in_main_file()
01081           && field_type->node_type() != AST_Decl::NT_pre_defined) {
01082         be_global->add_referenced(field_type->file_name().c_str());
01083       }
01084       const string field_name = fields[i]->local_name()->get_string(),
01085         cond = rtpsCustom.getConditional(field_name);
01086       if (!cond.empty()) {
01087         expr += "  if (" + cond + ") {\n  ";
01088       }
01089       expr += findSizeCommon(field_name, field_type, "stru", intro);
01090       if (!cond.empty()) {
01091         expr += "  }\n";
01092       }
01093     }
01094     be_global->impl_ << intro << expr;
01095   }
01096   {
01097     Function insertion("operator<<", "bool");
01098     insertion.addArg("strm", "Serializer&");
01099     insertion.addArg("stru", "const " + cxx + "&");
01100     insertion.endArgs();
01101     string expr, intro = rtpsCustom.preamble_;
01102     for (size_t i = 0; i < fields.size(); ++i) {
01103       if (i) expr += "\n    && ";
01104       const string field_name = fields[i]->local_name()->get_string(),
01105         cond = rtpsCustom.getConditional(field_name);
01106       if (!cond.empty()) {
01107         expr += "(!(" + cond + ") || ";
01108       }
01109       expr += streamCommon(field_name, fields[i]->field_type(),
01110                            "<< stru", intro, cxx);
01111       if (!cond.empty()) {
01112         expr += ")";
01113       }
01114     }
01115     be_global->impl_ << intro << "  return " << expr << ";\n";
01116   }
01117   {
01118     Function extraction("operator>>", "bool");
01119     extraction.addArg("strm", "Serializer&");
01120     extraction.addArg("stru", cxx + "&");
01121     extraction.endArgs();
01122     string expr, intro;
01123     for (size_t i = 0; i < fields.size(); ++i) {
01124       if (i) expr += "\n    && ";
01125       const string field_name = fields[i]->local_name()->get_string(),
01126         cond = rtpsCustom.getConditional(field_name);
01127       if (!cond.empty()) {
01128         expr += rtpsCustom.preFieldRead(field_name);
01129         expr += "(!(" + cond + ") || ";
01130       }
01131       expr += streamCommon(field_name, fields[i]->field_type(),
01132                            ">> stru", intro, cxx);
01133       if (!cond.empty()) {
01134         expr += ")";
01135       }
01136     }
01137     be_global->impl_ << intro << "  return " << expr << ";\n";
01138   }
01139 
01140   IDL_GlobalData::DCPS_Data_Type_Info* info = idl_global->is_dcps_type(name);
01141   // Only generate these methods if this is a DCPS type
01142   if (info != 0) {
01143     bool is_bounded_struct = true;
01144     {
01145       Function is_bounded("gen_is_bounded_size", "bool");
01146       is_bounded.addArg("", "const " + cxx + "&");
01147       is_bounded.endArgs();
01148       for (size_t i = 0; i < fields.size(); ++i) {
01149         if (!is_bounded_type(fields[i]->field_type())) {
01150           is_bounded_struct = false;
01151           break;
01152         }
01153       }
01154       be_global->impl_ << "  return "
01155                        << (is_bounded_struct ? "true" : "false") << ";\n";
01156     }
01157     {
01158       Function max_marsh("gen_max_marshaled_size", "size_t");
01159       max_marsh.addArg("stru", "const " + cxx + "&");
01160       max_marsh.addArg("align", "bool");
01161       max_marsh.endArgs();
01162       if (is_bounded_struct) {
01163         size_t size = 0, padding = 0;
01164         for (size_t i = 0; i < fields.size(); ++i) {
01165           max_marshaled_size(fields[i]->field_type(), size, padding);
01166         }
01167         if (padding) {
01168           be_global->impl_
01169             << "  return align ? " << size + padding << " : " << size << ";\n";
01170         } else {
01171           be_global->impl_
01172             << "  return " << size << ";\n";
01173         }
01174       } else { // unbounded
01175         be_global->impl_
01176           << "  return 0;\n";
01177       }
01178     }
01179 
01180     // Generate key-related marshaling code
01181     bool bounded_key = true;
01182     {
01183       Function is_bounded("gen_is_bounded_size", "bool");
01184       is_bounded.addArg("", "KeyOnly<const " + cxx + ">");
01185       is_bounded.endArgs();
01186 
01187       IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01188       for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01189         string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01190         AST_Type* field_type = 0;
01191         try {
01192           field_type = find_type(fields, key_name);
01193         } catch (const std::string& error) {
01194           std::cerr << "ERROR: Invalid key specification for " << cxx
01195                     << " (" << key_name << "). " << error << std::endl;
01196           return false;
01197         }
01198         if (!is_bounded_type(field_type)) {
01199           bounded_key = false;
01200           break;
01201         }
01202       }
01203 
01204       be_global->impl_ << "  return "
01205                        << (bounded_key ? "true" : "false") << ";\n";
01206     }
01207 
01208     {
01209       Function max_marsh("gen_max_marshaled_size", "size_t");
01210       max_marsh.addArg("stru", "KeyOnly<const " + cxx + ">");
01211       max_marsh.addArg("align", "bool");
01212       max_marsh.endArgs();
01213 
01214       if (bounded_key) {  // Only generate a size if the key is bounded
01215         IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01216         size_t size = 0, padding = 0;
01217         for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01218           string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01219           AST_Type* field_type = 0;
01220           try {
01221             field_type = find_type(fields, key_name);
01222           } catch (const std::string& error) {
01223             std::cerr << "ERROR: Invalid key specification for " << cxx
01224                       << " (" << key_name << "). " << error << std::endl;
01225             return false;
01226           }
01227           max_marshaled_size(field_type, size, padding);
01228         }
01229         if (padding) {
01230           be_global->impl_
01231             << "  return align ? " << size + padding << " : " << size << ";\n";
01232         } else {
01233           be_global->impl_
01234             << "  return " << size << ";\n";
01235         }
01236       } else { // unbounded
01237         be_global->impl_
01238           << "  return 0;\n";
01239       }
01240     }
01241 
01242     {
01243       Function find_size("gen_find_size", "void");
01244       find_size.addArg("stru", "KeyOnly<const " + cxx + ">");
01245       find_size.addArg("size", "size_t&");
01246       find_size.addArg("padding", "size_t&");
01247       find_size.endArgs();
01248       string expr, intro;
01249       IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01250       for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01251         string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01252         AST_Type* field_type = 0;
01253         try {
01254           field_type = find_type(fields, key_name);
01255         } catch (const std::string& error) {
01256           std::cerr << "ERROR: Invalid key specification for " << cxx
01257                     << " (" << key_name << "). " << error << std::endl;
01258           return false;
01259         }
01260         expr += findSizeCommon(key_name, field_type, "stru.t", intro);
01261       }
01262       be_global->impl_ << intro << expr;
01263     }
01264 
01265     {
01266       Function insertion("operator<<", "bool");
01267       insertion.addArg("strm", "Serializer&");
01268       insertion.addArg("stru", "KeyOnly<const " + cxx + ">");
01269       insertion.endArgs();
01270 
01271       bool first = true;
01272       string expr, intro;
01273       IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01274       for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01275         string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01276         AST_Type* field_type = 0;
01277         try {
01278           field_type = find_type(fields, key_name);
01279         } catch (const std::string& error) {
01280           std::cerr << "ERROR: Invalid key specification for " << cxx
01281                     << " (" << key_name << "). " << error << std::endl;
01282           return false;
01283         }
01284         if (first) first = false;
01285         else       expr += "\n    && ";
01286         expr += streamCommon(key_name, field_type, "<< stru.t", intro);
01287       }
01288       if (first) be_global->impl_ << intro << "  return true;\n";
01289       else be_global->impl_ << intro << "  return " << expr << ";\n";
01290     }
01291 
01292     {
01293       Function extraction("operator>>", "bool");
01294       extraction.addArg("strm", "Serializer&");
01295       extraction.addArg("stru", "KeyOnly<" + cxx + ">");
01296       extraction.endArgs();
01297 
01298       bool first = true;
01299       string expr, intro;
01300       IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01301       for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01302         string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01303         AST_Type* field_type = 0;
01304         try {
01305           field_type = find_type(fields, key_name);
01306         } catch (const std::string& error) {
01307           std::cerr << "ERROR: Invalid key specification for " << cxx
01308                     << " (" << key_name << "). " << error << std::endl;
01309           return false;
01310         }
01311         if (first) first = false;
01312         else       expr += "\n    && ";
01313         expr += streamCommon(key_name, field_type, ">> stru.t", intro);
01314       }
01315       if (first) be_global->impl_ << intro << "  return true;\n";
01316       else be_global->impl_ << intro << "  return " << expr << ";\n";
01317     }
01318   }
01319 
01320   return true;
01321 }
01322 
01323 namespace {
01324 
01325   bool isRtpsSpecialUnion(const string& cxx)
01326   {
01327     return cxx == "OpenDDS::RTPS::Parameter"
01328       || cxx == "OpenDDS::RTPS::Submessage";
01329   }
01330 
01331   bool genRtpsParameter(AST_Type* discriminator,
01332                         const std::vector<AST_UnionBranch*>& branches)
01333   {
01334     const string cxx = "OpenDDS::RTPS::Parameter";
01335     {
01336       Function find_size("gen_find_size", "void");
01337       find_size.addArg("uni", "const " + cxx + "&");
01338       find_size.addArg("size", "size_t&");
01339       find_size.addArg("padding", "size_t&");
01340       find_size.endArgs();
01341       generateSwitchForUnion("uni._d()", findSizeCommon, branches, discriminator,
01342                                  "", "", cxx);
01343       be_global->impl_ <<
01344         "  size += 4; // parameterId & length\n";
01345     }
01346     {
01347       Function insertion("operator<<", "bool");
01348       insertion.addArg("outer_strm", "Serializer&");
01349       insertion.addArg("uni", "const " + cxx + "&");
01350       insertion.endArgs();
01351       be_global->impl_ <<
01352         "  if (!(outer_strm << uni._d())) {\n"
01353         "    return false;\n"
01354         "  }\n"
01355         "  size_t size = 0, pad = 0;\n"
01356         "  gen_find_size(uni, size, pad);\n"
01357         "  size -= 4; // parameterId & length\n"
01358         "  const size_t post_pad = 4 - ((size + pad) % 4);\n"
01359         "  const size_t total = size + pad + ((post_pad < 4) ? post_pad : 0);\n"
01360         "  if (size + pad > ACE_UINT16_MAX || "
01361         "!(outer_strm << ACE_CDR::UShort(total))) {\n"
01362         "    return false;\n"
01363         "  }\n"
01364         "  ACE_Message_Block param(size + pad);\n"
01365         "  Serializer strm(&param, outer_strm.swap_bytes(), "
01366         "outer_strm.alignment());\n"
01367         "  if (!insertParamData(strm, uni)) {\n"
01368         "    return false;\n"
01369         "  }\n"
01370         "  const ACE_CDR::Octet* data = reinterpret_cast<ACE_CDR::Octet*>("
01371         "param.rd_ptr());\n"
01372         "  if (!outer_strm.write_octet_array(data, ACE_CDR::ULong(param.length()))) {\n"
01373         "    return false;\n"
01374         "  }\n"
01375         "  if (post_pad < 4 && outer_strm.alignment() != "
01376         "Serializer::ALIGN_NONE) {\n"
01377         "    static const ACE_CDR::Octet padding[3] = {0};\n"
01378         "    return outer_strm.write_octet_array(padding, "
01379         "ACE_CDR::ULong(post_pad));\n"
01380         "  }\n"
01381         "  return true;\n";
01382     }
01383     {
01384       Function insertData("insertParamData", "bool");
01385       insertData.addArg("strm", "Serializer&");
01386       insertData.addArg("uni", "const " + cxx + "&");
01387       insertData.endArgs();
01388       generateSwitchForUnion("uni._d()", streamCommon, branches, discriminator,
01389                                  "return", "<< ", cxx);
01390     }
01391     {
01392       Function extraction("operator>>", "bool");
01393       extraction.addArg("outer_strm", "Serializer&");
01394       extraction.addArg("uni", cxx + "&");
01395       extraction.endArgs();
01396       be_global->impl_ <<
01397         "  ACE_CDR::UShort disc, size;\n"
01398         "  if (!(outer_strm >> disc) || !(outer_strm >> size)) {\n"
01399         "    return false;\n"
01400         "  }\n"
01401         "  if (disc == OpenDDS::RTPS::PID_SENTINEL) {\n"
01402         "    uni._d(OpenDDS::RTPS::PID_SENTINEL);\n"
01403         "    return true;\n"
01404         "  }\n"
01405         "  ACE_Message_Block param(size);\n"
01406         "  ACE_CDR::Octet* data = reinterpret_cast<ACE_CDR::Octet*>("
01407         "param.wr_ptr());\n"
01408         "  if (!outer_strm.read_octet_array(data, size)) {\n"
01409         "    return false;\n"
01410         "  }\n"
01411         "  param.wr_ptr(size);\n"
01412         "  Serializer strm(&param, outer_strm.swap_bytes(), "
01413         "Serializer::ALIGN_CDR);\n"
01414         "  switch (disc) {\n";
01415       generateSwitchBodyForUnion(streamCommon, branches, discriminator,
01416                                  "return", ">> ", cxx, true);
01417       be_global->impl_ <<
01418         "  default:\n"
01419         "    {\n"
01420         "      uni.unknown_data(DDS::OctetSeq(size));\n"
01421         "      uni.unknown_data().length(size);\n"
01422         "      std::memcpy(uni.unknown_data().get_buffer(), data, size);\n"
01423         "      uni._d(disc);\n"
01424         "    }\n"
01425         "  }\n"
01426         "  return true;\n";
01427     }
01428     return true;
01429   }
01430 
01431   bool genRtpsSubmessage(AST_Type* discriminator,
01432                          const std::vector<AST_UnionBranch*>& branches)
01433   {
01434     const string cxx = "OpenDDS::RTPS::Submessage";
01435     {
01436       Function find_size("gen_find_size", "void");
01437       find_size.addArg("uni", "const " + cxx + "&");
01438       find_size.addArg("size", "size_t&");
01439       find_size.addArg("padding", "size_t&");
01440       find_size.endArgs();
01441       generateSwitchForUnion("uni._d()", findSizeCommon, branches, discriminator,
01442                                  "", "", cxx);
01443     }
01444     {
01445       Function insertion("operator<<", "bool");
01446       insertion.addArg("strm", "Serializer&");
01447       insertion.addArg("uni", "const " + cxx + "&");
01448       insertion.endArgs();
01449       generateSwitchForUnion("uni._d()", streamCommon, branches, discriminator,
01450                                  "return", "<< ", cxx);
01451     }
01452     {
01453       Function insertion("operator>>", "bool");
01454       insertion.addArg("strm", "Serializer&");
01455       insertion.addArg("uni", cxx + "&");
01456       insertion.endArgs();
01457       be_global->impl_ << "  // unused\n  return false;\n";
01458     }
01459     return true;
01460   }
01461 
01462   bool genRtpsSpecialUnion(const string& cxx, AST_Type* discriminator,
01463                            const std::vector<AST_UnionBranch*>& branches)
01464   {
01465     if (cxx == "OpenDDS::RTPS::Parameter") {
01466       return genRtpsParameter(discriminator, branches);
01467     } else if (cxx == "OpenDDS::RTPS::Submessage") {
01468       return genRtpsSubmessage(discriminator, branches);
01469     } else {
01470       return false;
01471     }
01472   }
01473 }
01474 
01475 bool marshal_generator::gen_union(AST_Union*, UTL_ScopedName* name,
01476    const std::vector<AST_UnionBranch*>& branches, AST_Type* discriminator,
01477    const char*)
01478 {
01479   NamespaceGuard ng;
01480   be_global->add_include("dds/DCPS/Serializer.h");
01481   string cxx = scoped(name); // name as a C++ class
01482   if (isRtpsSpecialUnion(cxx)) {
01483     return genRtpsSpecialUnion(cxx, discriminator, branches);
01484   }
01485   const string wrap_out = getWrapper("uni._d()", discriminator, WD_OUTPUT);
01486   {
01487     Function find_size("gen_find_size", "void");
01488     find_size.addArg("uni", "const " + cxx + "&");
01489     find_size.addArg("size", "size_t&");
01490     find_size.addArg("padding", "size_t&");
01491     find_size.endArgs();
01492     const string align = getAlignment(discriminator);
01493     if (!align.empty()) {
01494       be_global->impl_ <<
01495         "  if ((size + padding) % " << align << ") {\n"
01496         "    padding += " << align << " - ((size + padding) % " << align
01497         << ");\n"
01498         "  }\n";
01499     }
01500     be_global->impl_ <<
01501       "  size += gen_max_marshaled_size(" << wrap_out << ");\n";
01502       generateSwitchForUnion("uni._d()", findSizeCommon, branches, discriminator,
01503                                "", "", cxx);
01504   }
01505   {
01506     Function insertion("operator<<", "bool");
01507     insertion.addArg("strm", "Serializer&");
01508     insertion.addArg("uni", "const " + cxx + "&");
01509     insertion.endArgs();
01510     be_global->impl_ <<
01511       streamAndCheck("<< " + wrap_out);
01512     generateSwitchForUnion("uni._d()", streamCommon, branches, discriminator,
01513                                "return", "<< ", cxx);
01514     be_global->impl_ <<
01515       "  return true;\n";
01516   }
01517   {
01518     Function extraction("operator>>", "bool");
01519     extraction.addArg("strm", "Serializer&");
01520     extraction.addArg("uni", cxx + "&");
01521     extraction.endArgs();
01522     be_global->impl_ <<
01523       "  " << scoped(discriminator->name()) << " disc;\n" <<
01524       streamAndCheck(">> " + getWrapper("disc", discriminator, WD_INPUT));
01525     generateSwitchForUnion("disc", streamCommon, branches, discriminator,
01526                            "if", ">> ", cxx);
01527     be_global->impl_ <<
01528       "  return true;\n";
01529   }
01530   return true;
01531 }

Generated on Fri Feb 12 20:05:23 2016 for OpenDDS by  doxygen 1.4.7