void t_cpp_generator::generate_struct_declaration()

in compiler/cpp/src/thrift/generate/t_cpp_generator.cc [1210:1425]


void t_cpp_generator::generate_struct_declaration(ostream& out,
                                                  t_struct* tstruct,
                                                  bool is_exception,
                                                  bool pointers,
                                                  bool read,
                                                  bool write,
                                                  bool swap,
                                                  bool is_user_struct) {
  string extends = "";
  if (is_exception) {
    extends = " : public ::apache::thrift::TException";
  } else {
    if (is_user_struct && !gen_templates_) {
      extends = " : public virtual ::apache::thrift::TBase";
    }
  }

  // Get members
  vector<t_field*>::const_iterator m_iter;
  const vector<t_field*>& members = tstruct->get_members();

  // Write the isset structure declaration outside the class. This makes
  // the generated code amenable to processing by SWIG.
  // We only declare the struct if it gets used in the class.

  // Isset struct has boolean fields, but only for non-required fields.
  bool has_nonrequired_fields = false;
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    if ((*m_iter)->get_req() != t_field::T_REQUIRED)
      has_nonrequired_fields = true;
  }

  if (has_nonrequired_fields && (!pointers || read)) {

    out << indent() << "typedef struct _" << tstruct->get_name() << "__isset {" << '\n';
    indent_up();

    indent(out) << "_" << tstruct->get_name() << "__isset() ";
    bool first = true;
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
      if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
        continue;
      }
      string isSet = ((*m_iter)->get_value() != nullptr) ? "true" : "false";
      if (first) {
        first = false;
        out << ": " << (*m_iter)->get_name() << "(" << isSet << ")";
      } else {
        out << ", " << (*m_iter)->get_name() << "(" << isSet << ")";
      }
    }
    out << " {}" << '\n';

    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
        indent(out) << "bool " << (*m_iter)->get_name() << " :1;" << '\n';
      }
    }

    indent_down();
    indent(out) << "} _" << tstruct->get_name() << "__isset;" << '\n';
  }

  out << '\n';

  generate_java_doc(out, tstruct);

  // Open struct def
  out << indent() << "class " << tstruct->get_name() << extends << " {" << '\n' << indent()
      << " public:" << '\n' << '\n';
  indent_up();

  if (!gen_no_constructors_ && !pointers) {
    bool ok_noexcept = is_struct_storage_not_throwing(tstruct);
    // Copy constructor
    indent(out) << tstruct->get_name() << "(const " << tstruct->get_name() << "&)"
                << (ok_noexcept? " noexcept" : "") << ';' << '\n';

    // Move constructor
    if (gen_moveable_) {
      indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&) noexcept;"
                  << '\n';
    }

    // Assignment Operator
    indent(out) << tstruct->get_name() << "& operator=(const " << tstruct->get_name() << "&)"
                << (ok_noexcept? " noexcept" : "") << ';' << '\n';

    // Move assignment operator
    if (gen_moveable_) {
      indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&) noexcept;"
                  << '\n';
    }

    bool has_default_value = has_field_with_default_value(tstruct);

    // Default constructor
    std::string clsname_ctor = tstruct->get_name() + "()";
    indent(out) << clsname_ctor << (has_default_value ? "" : " noexcept") << ";" << '\n';
  }

  if (!gen_no_constructors_ && tstruct->annotations_.find("final") == tstruct->annotations_.end()) {
    out << '\n' << indent();
    if (!gen_templates_) out << "virtual ";
    out << "~" << tstruct->get_name() << "() noexcept;\n";
  }

  // Declare all fields
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    generate_java_doc(out, *m_iter);
    indent(out) << declare_field(*m_iter,
                                 !pointers && gen_no_constructors_,
                                 (pointers && !(*m_iter)->get_type()->is_xception()),
                                 !read) << '\n';
  }

  // Add the __isset data member if we need it, using the definition from above
  if (has_nonrequired_fields && (!pointers || read)) {
    out << '\n' << indent() << "_" << tstruct->get_name() << "__isset __isset;" << '\n';
  }

  // Create a setter function for each field
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    if (pointers) {
      continue;
    }
    if (is_reference((*m_iter))) {
      out << '\n' << indent() << "void __set_" << (*m_iter)->get_name() << "(::std::shared_ptr<"
          << type_name((*m_iter)->get_type(), false, false) << ">";
      out << " val);" << '\n';
    } else {
      out << '\n' << indent() << "void __set_" << (*m_iter)->get_name() << "("
          << type_name((*m_iter)->get_type(), false, true);
      out << " val);" << '\n';
    }
  }
  out << '\n';

  if (!pointers) {
    // Should we generate default operators?
    if (!gen_no_default_operators_) {
      // Generate an equality testing operator.
      out << indent() << "bool operator == (const " << tstruct->get_name() << " & "
          << (members.size() > 0 ? "rhs" : "/* rhs */") << ") const;" << '\n';

      out << indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {"
          << '\n' << indent() << "  return !(*this == rhs);" << '\n' << indent() << "}" << '\n'
          << '\n';

      // Generate the declaration of a less-than operator.  This must be
      // implemented by the application developer if they wish to use it.  (They
      // will get a link error if they try to use it without an implementation.)
      out << indent() << "bool operator < (const " << tstruct->get_name() << " & ) const;" << '\n'
          << '\n';
    }
  }

  if (read) {
    if (gen_templates_) {
      out << indent() << "template <class Protocol_>" << '\n' << indent()
          << "uint32_t read(Protocol_* iprot);" << '\n';
    } else {
      out << indent() << "uint32_t read("
          << "::apache::thrift::protocol::TProtocol* iprot)";
      if(!is_exception && !extends.empty())
        out << " override";
      out << ';' << '\n';
    }
  }
  if (write) {
    if (gen_templates_) {
      out << indent() << "template <class Protocol_>" << '\n' << indent()
          << "uint32_t write(Protocol_* oprot) const;" << '\n';
    } else {
      out << indent() << "uint32_t write("
          << "::apache::thrift::protocol::TProtocol* oprot) const";
      if(!is_exception && !extends.empty())
        out << " override";
      out << ';' << '\n';
    }
  }
  out << '\n';

  if (is_user_struct && !has_custom_ostream(tstruct)) {
    out << indent();
    if (!gen_templates_) out << "virtual ";
    generate_struct_print_method_decl(out, nullptr);
    out << ";" << '\n';
  }

  // std::exception::what()
  if (is_exception) {
    out << indent() << "mutable std::string thriftTExceptionMessageHolder_;" << '\n';
    out << indent();
    generate_exception_what_method_decl(out, tstruct, false);
    out << ";" << '\n';
  }

  indent_down();
  indent(out) << "};" << '\n' << '\n';

  if (swap) {
    // Generate a namespace-scope swap() function
    if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
      out << indent() << "void swap(" << tstruct->get_name() << " &a1, " << tstruct->get_name()
          << " &a2);" << '\n' << '\n';
    } else {
       out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
           << " &b);" << '\n' << '\n';
    }
  }

  if (is_user_struct) {
    generate_struct_ostream_operator_decl(out, tstruct);
  }
}