// See accompanying file LICENSE or visit the Thrift site at:
// http://developers.facebook.com/thrift/
-#include <stdlib.h>
+#include <cstdlib>
+#include <cassert>
#include <sys/stat.h>
#include <sstream>
#include <boost/lexical_cast.hpp>
"#ifndef " << program_name_ << "_TYPES_H" << endl <<
"#define " << program_name_ << "_TYPES_H" << endl <<
endl;
-
+
// Include base types
f_types_ <<
"#include <Thrift.h>" << endl <<
}
f_types_ <<
endl;
-
+
// Include the types file
f_types_impl_ <<
"#include \"" << program_name_ << "_types.h\"" << endl <<
endl;
+ // If we are generating local reflection metadata, we need to include
+ // the definition of TypeSpec.
+ if (gen_dense_) {
+ f_types_impl_ <<
+ "#include <TReflectionLocal.h>" << endl <<
+ endl;
+ }
+
// Open namespace
ns_open_ = namespace_open(program_->get_cpp_namespace());
ns_close_ = namespace_close(program_->get_cpp_namespace());
// Close ifndef
f_types_ <<
"#endif" << endl;
-
+
// Close output file
f_types_.close();
f_types_impl_.close();
}
indent_down();
f_consts <<
- "};" << endl;
+ "};" << endl;
f_consts_impl <<
"const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) {
generate_struct_definition(f_types_, tstruct, is_exception);
generate_struct_fingerprint(f_types_impl_, tstruct, true);
+ generate_local_reflection(f_types_, tstruct, false);
+ generate_local_reflection(f_types_impl_, tstruct, true);
generate_struct_reader(f_types_impl_, tstruct);
generate_struct_writer(f_types_impl_, tstruct);
}
generate_struct_fingerprint(out, tstruct, false);
// Get members
- vector<t_field*>::const_iterator m_iter;
+ vector<t_field*>::const_iterator m_iter;
const vector<t_field*>& members = tstruct->get_members();
-
+
if (!pointers) {
// Default constructor
indent(out) <<
}
scope_down(out);
}
-
+
out <<
endl <<
indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
indent(out) <<
declare_field(*m_iter, false, pointers && !(*m_iter)->get_type()->is_xception(), !read) << endl;
}
-
+
// 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) {
endl <<
indent() << "struct __isset {" << endl;
indent_up();
-
+
indent(out) <<
"__isset() : ";
bool first = true;
}
}
out << " {}" << endl;
-
+
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::REQUIRED) {
indent(out) <<
indent_down();
indent(out) <<
- "} __isset;" << endl;
+ "} __isset;" << endl;
}
out << endl;
}
out << endl;
- indent_down();
+ indent_down();
indent(out) <<
"};" << endl <<
endl;
}
}
+/**
+ * Writes the local reflection of a type (either declaration or definition).
+ */
+void t_cpp_generator::generate_local_reflection(std::ofstream& out,
+ t_type* ttype,
+ bool is_definition) {
+ if (!gen_dense_) {
+ return;
+ }
+ ttype = get_true_type(ttype);
+ assert(ttype->has_fingerprint());
+ string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl");
+ // Note that we have generated this fingerprint. If we already did, bail out.
+ if (!reflected_fingerprints_.insert(key).second) {
+ return;
+ }
+ // Let each program handle its own structures.
+ if (ttype->get_program() != NULL && ttype->get_program() != program_) {
+ return;
+ }
+
+ // Do dependencies.
+ if (ttype->is_list()) {
+ generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition);
+ } else if (ttype->is_set()) {
+ generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition);
+ } else if (ttype->is_map()) {
+ generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition);
+ generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition);
+ } else if (ttype->is_struct() || ttype->is_xception()) {
+ const vector<t_field*>& members = ((t_struct*)ttype)->get_members();
+ vector<t_field*>::const_iterator m_iter;
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ generate_local_reflection(out, (**m_iter).get_type(), is_definition);
+ }
+
+ // For definitions of structures, do the arrays of tags and field specs also.
+ if (is_definition) {
+ indent(out) << "int16_t " << local_reflection_name("ftags", ttype) <<"[] = {" << endl;
+ indent_up();
+ indent(out);
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ out << (*m_iter)->get_key() << ", ";
+ }
+ indent_down();
+ out << endl << "};" << endl;
+
+ out <<
+ indent() << "facebook::thrift::reflection::local::TypeSpec*" << endl <<
+ indent() << local_reflection_name("specs", ttype) <<"[] = {" << endl;
+ indent_up();
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ indent(out) << "&" <<
+ local_reflection_name("typespec", (*m_iter)->get_type()) << "," << endl;
+ }
+ indent_down();
+ indent(out) << "};" << endl;
+ }
+ }
+
+ out <<
+ indent() << "// " << ttype->get_fingerprint_material() << endl <<
+ indent() << (is_definition ? "" : "extern ") <<
+ "facebook::thrift::reflection::local::TypeSpec" << endl <<
+ local_reflection_name("typespec", ttype) <<
+ (is_definition ? "(" : ";") << endl;
+
+ if (!is_definition) {
+ out << endl;
+ return;
+ }
+
+ indent_up();
+
+ indent(out) << type_to_enum(ttype);
+
+ if (ttype->is_struct()) {
+ out << "," << endl <<
+ indent() << ((t_struct*)ttype)->get_members().size() << "," << endl <<
+ indent() << local_reflection_name("ftags", ttype) << "," << endl <<
+ indent() << local_reflection_name("specs", ttype);
+ } else if (ttype->is_list()) {
+ out << "," << endl <<
+ indent() << "&" << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type()) << "," << endl <<
+ indent() << "NULL";
+ } else if (ttype->is_set()) {
+ out << "," << endl <<
+ indent() << "&" << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type()) << "," << endl <<
+ indent() << "NULL";
+ } else if (ttype->is_map()) {
+ out << "," << endl <<
+ indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type()) << "," << endl <<
+ indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type());
+ }
+
+ out << ");" << endl << endl;
+
+ indent_down();
+}
+
/**
* Makes a helper function to gen a struct reader.
*
// Declare stack tmp variables
out <<
- endl <<
+ endl <<
indent() << "uint32_t xfer = 0;" << endl <<
indent() << "std::string fname;" << endl <<
indent() << "facebook::thrift::protocol::TType ftype;" << endl <<
indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
}
out << endl;
-
-
+
+
// Loop over reading in fields
indent(out) <<
"while (true)" << endl;
scope_up(out);
-
+
// Read beginning field marker
indent(out) <<
"xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
-
+
// Check for field STOP marker
out <<
indent() << "if (ftype == facebook::thrift::protocol::T_STOP) {" << endl <<
indent() << " break;" << endl <<
indent() << "}" << endl;
-
+
// Switch statement on the field we are reading
indent(out) <<
"switch (fid)" << endl;
scope_up(out);
-
+
// Generate deserialization code for known cases
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
indent(out) <<
indent() << "break;" << endl;
indent_down();
}
-
+
// In the default case we skip the field
out <<
indent() << "default:" << endl <<
indent() << " xfer += iprot->skip(ftype);" << endl <<
indent() << " break;" << endl;
-
+
scope_down(out);
// Read field end marker
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
first = false;
- out <<
+ out <<
endl <<
indent() << "if ";
} else {
}
out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
-
+
indent_up();
// Write field header
*/
void t_cpp_generator::generate_service(t_service* tservice) {
string svcname = tservice->get_name();
-
+
// Make output files
string f_header_name = string(T_CPP_DIR)+"/"+svcname+".h";
f_header_.open(f_header_name.c_str());
f_service_ <<
autogen_comment();
f_service_ <<
- "#include \"" << svcname << ".h\"" << endl <<
+ "#include \"" << svcname << ".h\"" << endl <<
endl <<
ns_open_ << endl <<
endl;
*/
void t_cpp_generator::generate_service_helpers(t_service* tservice) {
vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::iterator f_iter;
+ vector<t_function*>::iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
t_struct* ts = (*f_iter)->get_arglist();
string name_orig = ts->get_name();
f_header_ <<
"class " << service_name_ << "If" << extends << " {" << endl <<
" public:" << endl;
- indent_up();
+ indent_up();
f_header_ <<
indent() << "virtual ~" << service_name_ << "If() {}" << endl;
//scope_down(f_header_);
vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::iterator f_iter;
+ vector<t_function*>::iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
f_header_ <<
indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
f_header_ <<
"class " << service_name_ << "Null : virtual public " << service_name_ << "If" << extends << " {" << endl <<
" public:" << endl;
- indent_up();
+ indent_up();
f_header_ <<
indent() << "virtual ~" << service_name_ << "Null() {}" << endl;
vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::iterator f_iter;
+ vector<t_function*>::iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
f_header_ <<
indent() << function_signature(*f_iter) << " {" << endl;
void t_cpp_generator::generate_service_multiface(t_service* tservice) {
// Generate the dispatch methods
vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::iterator f_iter;
+ vector<t_function*>::iterator f_iter;
string extends = "";
string extends_multiface = "";
extends_multiface << " {" << endl <<
" public:" << endl;
indent_up();
- f_header_ <<
+ f_header_ <<
indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
if (!extends.empty()) {
f_header_ <<
f_header_ <<
indent() << "}" << endl;
-
+
indent_down();
f_header_ <<
indent() << "}" << endl <<
"class " << service_name_ << "Client : " <<
"virtual public " << service_name_ << "If" <<
extends_client << " {" << endl <<
- " public:" << endl;
+ " public:" << endl;
indent_up();
f_header_ <<
}
vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::const_iterator f_iter;
+ vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
t_function send_function(g_type_void,
string("send_") + (*f_iter)->get_name(),
}
}
indent_down();
-
+
if (extends.empty()) {
f_header_ <<
" protected:" << endl;
indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot_;" << endl <<
indent() << "facebook::thrift::protocol::TProtocol* iprot_;" << endl <<
indent() << "facebook::thrift::protocol::TProtocol* oprot_;" << endl;
- indent_down();
+ indent_down();
}
f_header_ <<
"};" << endl <<
endl;
-
+
string scope = service_name_ + "Client::";
// Generate client method implementations
// Get the struct of function call params
t_struct* arg_struct = (*f_iter)->get_arglist();
-
+
// Declare the function arguments
const vector<t_field*>& fields = arg_struct->get_members();
vector<t_field*>::const_iterator fld_iter;
indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl <<
endl <<
indent() << argsname << " args;" << endl;
-
+
for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
f_service_ <<
indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl;
}
-
+
f_service_ <<
indent() << "args.write(oprot_);" << endl <<
endl <<
indent() << "oprot_->writeMessageEnd();" << endl <<
indent() << "oprot_->getTransport()->flush();" << endl;
-
+
scope_down(f_service_);
f_service_ << endl;
f_service_ <<
indent() << "throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
}
-
+
// Close function
scope_down(f_service_);
f_service_ << endl;
void t_cpp_generator::generate_service_processor(t_service* tservice) {
// Generate the dispatch methods
vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::iterator f_iter;
+ vector<t_function*>::iterator f_iter;
string extends = "";
string extends_processor = "";
// Generate the header portion
f_header_ <<
"class " << service_name_ << "Processor : " <<
- "virtual public facebook::thrift::TProcessor" <<
+ "virtual public facebook::thrift::TProcessor" <<
extends_processor << " {" << endl;
// Protected data members
}
indent_down();
- f_header_ <<
+ f_header_ <<
" public:" << endl <<
indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface) :" << endl;
if (extends.empty()) {
f_service_ <<
endl <<
indent() << "facebook::thrift::protocol::TProtocol* iprot = piprot.get();" << endl <<
- indent() << "facebook::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
+ indent() << "facebook::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
indent() << "std::string fname;" << endl <<
indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
indent() << "int32_t seqid;" << endl <<
f_service_ <<
"bool " << service_name_ << "Processor::process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid) {" << endl;
indent_up();
-
+
// HOT: member function pointer map
f_service_ <<
indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)>::iterator pfn;" << endl <<
f_service_ <<
indent() << "} else {" << endl <<
indent() << " (this->*(pfn->second))(seqid, iprot, oprot);" << endl <<
- indent() << "}" << endl;
+ indent() << "}" << endl;
// Read end of args field, the T_STOP, and the struct close
f_service_ <<
indent() << "oprot->writeMessageEnd();" << endl <<
indent() << "oprot->getTransport()->flush();" << endl <<
indent() << "oprot->getTransport()->writeEnd();" << endl;
-
+
// Close function
scope_down(f_service_);
f_service_ << endl;
*/
void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
string svcname = tservice->get_name();
-
+
// Service implementation file includes
string f_skeleton_name = string(T_CPP_DIR)+"/"+svcname+"_server.skeleton.cpp";
"// This autogenerated skeleton file illustrates how to build a server." << endl <<
"// You should copy it to another filename to avoid overwriting it." << endl <<
endl <<
- "#include \"" << svcname << ".h\"" << endl <<
+ "#include \"" << svcname << ".h\"" << endl <<
"#include <protocol/TBinaryProtocol.h>" << endl <<
"#include <server/TSimpleServer.h>" << endl <<
"#include <transport/TServerSocket.h>" << endl <<
endl <<
"using boost::shared_ptr;" << endl <<
endl;
-
+
if (!ns.empty()) {
f_skeleton <<
"using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
f_skeleton <<
"}" << endl <<
endl;
-
+
// Close the files
f_skeleton.close();
}
t_type* ttype,
string prefix) {
scope_up(out);
-
+
string size = tmp("_size");
string ktype = tmp("_ktype");
string vtype = tmp("_vtype");
string etype = tmp("_etype");
-
+
indent(out) <<
prefix << ".clear();" << endl <<
indent() << "uint32_t " << size << ";" << endl;
-
+
// Declare variables, read header
if (ttype->is_map()) {
out <<
out <<
indent() << "uint32_t " << i << ";" << endl <<
indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
-
+
scope_up(out);
-
+
if (ttype->is_map()) {
generate_deserialize_map_element(out, (t_map*)ttype, prefix);
} else if (ttype->is_set()) {
} else if (ttype->is_list()) {
generate_deserialize_list_element(out, (t_list*)ttype, prefix);
}
-
+
scope_down(out);
// Read container end
throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
}
-
-
+
+
if (type->is_struct() || type->is_xception()) {
generate_serialize_struct(out,
(t_struct*)type,
indent(out) <<
"xfer += oprot->";
-
+
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
switch (tbase) {
t_type* ttype,
string prefix) {
scope_up(out);
-
+
if (ttype->is_map()) {
indent(out) <<
"xfer += oprot->writeMapBegin(" <<
generate_serialize_list_element(out, (t_list*)ttype, iter);
}
scope_down(out);
-
+
if (ttype->is_map()) {
indent(out) <<
"xfer += oprot->writeMapEnd();" << endl;
"xfer += oprot->writeListEnd();" << endl;
}
- scope_down(out);
+ scope_down(out);
}
/**
if (ns.size() > 0) {
result += ns + "::";
}
- return result;
+ return result;
}
/**
return "const " + bname;
}
}
-
+
// Check for a custom overloaded C++ name
if (ttype->is_container()) {
string cname;
t_list* tlist = (t_list*) ttype;
cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
}
-
+
if (arg) {
return "const " + cname + "&";
} else {
string pname;
t_program* program = ttype->get_program();
if (program != NULL && program != program_) {
- pname =
+ pname =
class_prefix +
namespace_prefix(program->get_cpp_namespace()) +
ttype->get_name();
*/
string t_cpp_generator::type_to_enum(t_type* type) {
type = get_true_type(type);
-
+
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
switch (tbase) {
throw "INVALID TYPE IN type_to_enum: " + type->get_name();
}
+
+/**
+ * Returns the symbol name of the local reflection of a type.
+ */
+string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype) {
+ ttype = get_true_type(ttype);
+
+ // We have to use the program name as part of the identifier because
+ // if two thrift "programs" are compiled into one actual program
+ // you would get a symbol collison if they both defined list<i32>.
+ // trlo = Thrift Reflection LOcal.
+ string prog;
+ string name;
+
+ // TODO(dreiss): Would it be better to pregenerate the base types
+ // and put them in Thrift.{h,cpp} ?
+
+ if (ttype->is_base_type()) {
+ //name = ttype->get_name();
+ prog = program_->get_name();
+ name = ttype->get_ascii_fingerprint();
+ } else if (ttype->is_enum()) {
+ //name = "enum";
+ prog = program_->get_name();
+ name = ttype->get_ascii_fingerprint();
+ } else if (ttype->is_container()) {
+ prog = program_->get_name();
+ name = ttype->get_ascii_fingerprint();
+ } else {
+ assert(ttype->is_struct() || ttype->is_xception());
+ assert(ttype->get_program() != NULL);
+ prog = ttype->get_program()->get_name();
+ name = ttype->get_ascii_fingerprint();
+ }
+
+ return string() + "trlo_" + prefix + "_" + prog + "_" + name;
+}