r1144@dev030 (orig r57821): dreiss | 2007-08-30 18:42:55 -0700
[amiethrift.git] / compiler / cpp / src / generate / t_cpp_generator.cc
blob10127fc39ae5bf0934fb51bb5a78d3dc278af710
1 // Copyright (c) 2006- Facebook
2 // Distributed under the Thrift Software License
3 //
4 // See accompanying file LICENSE or visit the Thrift site at:
5 // http://developers.facebook.com/thrift/
7 #include <cstdlib>
8 #include <cassert>
9 #include <sys/stat.h>
10 #include <sstream>
11 #include <boost/lexical_cast.hpp>
12 #include "t_cpp_generator.h"
13 using namespace std;
15 /**
16 * Prepares for file generation by opening up the necessary file output
17 * streams.
19 * @param tprogram The program to generate
21 void t_cpp_generator::init_generator() {
22 // Make output directory
23 mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
25 // Make output file
26 string f_types_name = string(T_CPP_DIR)+"/"+program_name_+"_types.h";
27 f_types_.open(f_types_name.c_str());
29 string f_types_impl_name = string(T_CPP_DIR)+"/"+program_name_+"_types.cpp";
30 f_types_impl_.open(f_types_impl_name.c_str());
32 // Print header
33 f_types_ <<
34 autogen_comment();
35 f_types_impl_ <<
36 autogen_comment();
38 // Start ifndef
39 f_types_ <<
40 "#ifndef " << program_name_ << "_TYPES_H" << endl <<
41 "#define " << program_name_ << "_TYPES_H" << endl <<
42 endl;
44 // Include base types
45 f_types_ <<
46 "#include <Thrift.h>" << endl <<
47 "#include <reflection_limited_types.h>" << endl <<
48 "#include <protocol/TProtocol.h>" << endl <<
49 "#include <transport/TTransport.h>" << endl <<
50 endl;
52 // Include other Thrift includes
53 const vector<t_program*>& includes = program_->get_includes();
54 for (size_t i = 0; i < includes.size(); ++i) {
55 f_types_ <<
56 "#include \"" << includes[i]->get_name() << "_types.h\"" << endl;
58 f_types_ << endl;
60 // Include custom headers
61 const vector<string>& cpp_includes = program_->get_cpp_includes();
62 for (size_t i = 0; i < cpp_includes.size(); ++i) {
63 f_types_ <<
64 "#include \"" << cpp_includes[i] << "\"" << endl;
66 f_types_ <<
67 endl;
69 // Include the types file
70 f_types_impl_ <<
71 "#include \"" << program_name_ << "_types.h\"" << endl <<
72 endl;
74 // If we are generating local reflection metadata, we need to include
75 // the definition of TypeSpec.
76 if (gen_dense_) {
77 f_types_impl_ <<
78 "#include <TReflectionLocal.h>" << endl <<
79 endl;
82 // Open namespace
83 ns_open_ = namespace_open(program_->get_cpp_namespace());
84 ns_close_ = namespace_close(program_->get_cpp_namespace());
86 f_types_ <<
87 ns_open_ << endl <<
88 endl;
90 f_types_impl_ <<
91 ns_open_ << endl <<
92 endl;
95 /**
96 * Closes the output files.
98 void t_cpp_generator::close_generator() {
99 // Close namespace
100 f_types_ <<
101 ns_close_ << endl <<
102 endl;
103 f_types_impl_ <<
104 ns_close_ << endl;
106 // Close ifndef
107 f_types_ <<
108 "#endif" << endl;
110 // Close output file
111 f_types_.close();
112 f_types_impl_.close();
116 * Generates a typedef. This is just a simple 1-liner in C++
118 * @param ttypedef The type definition
120 void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
121 f_types_ <<
122 indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << ttypedef->get_symbolic() << ";" << endl <<
123 endl;
127 * Generates code for an enumerated type. In C++, this is essentially the same
128 * as the thrift definition itself, using the enum keyword in C++.
130 * @param tenum The enumeration
132 void t_cpp_generator::generate_enum(t_enum* tenum) {
133 f_types_ <<
134 indent() << "enum " << tenum->get_name() << " {" << endl;
135 indent_up();
137 vector<t_enum_value*> constants = tenum->get_constants();
138 vector<t_enum_value*>::iterator c_iter;
139 bool first = true;
140 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
141 if (first) {
142 first = false;
143 } else {
144 f_types_ <<
145 "," << endl;
147 f_types_ <<
148 indent() << (*c_iter)->get_name();
149 if ((*c_iter)->has_value()) {
150 f_types_ <<
151 " = " << (*c_iter)->get_value();
155 indent_down();
156 f_types_ <<
157 endl <<
158 "};" << endl <<
159 endl;
163 * Generates a class that holds all the constants.
165 void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
166 string f_consts_name = string(T_CPP_DIR)+"/"+program_name_+"_constants.h";
167 ofstream f_consts;
168 f_consts.open(f_consts_name.c_str());
170 string f_consts_impl_name = string(T_CPP_DIR)+"/"+program_name_+"_constants.cpp";
171 ofstream f_consts_impl;
172 f_consts_impl.open(f_consts_impl_name.c_str());
174 // Print header
175 f_consts <<
176 autogen_comment();
177 f_consts_impl <<
178 autogen_comment();
180 // Start ifndef
181 f_consts <<
182 "#ifndef " << program_name_ << "_CONSTANTS_H" << endl <<
183 "#define " << program_name_ << "_CONSTANTS_H" << endl <<
184 endl <<
185 "#include \"" << program_name_ << "_types.h\"" << endl <<
186 endl <<
187 ns_open_ << endl <<
188 endl;
190 f_consts_impl <<
191 "#include \"" << program_name_ << "_constants.h\"" << endl <<
192 endl <<
193 ns_open_ << endl <<
194 endl;
196 f_consts <<
197 "class " << program_name_ << "Constants {" << endl <<
198 " public:" << endl <<
199 " " << program_name_ << "Constants();" << endl <<
200 endl;
201 indent_up();
202 vector<t_const*>::iterator c_iter;
203 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
204 string name = (*c_iter)->get_name();
205 t_type* type = (*c_iter)->get_type();
206 f_consts <<
207 indent() << type_name(type) << " " << name << ";" << endl;
209 indent_down();
210 f_consts <<
211 "};" << endl;
213 f_consts_impl <<
214 "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
215 endl <<
216 program_name_ << "Constants::" << program_name_ << "Constants() {" << endl;
217 indent_up();
218 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
219 print_const_value(f_consts_impl,
220 (*c_iter)->get_name(),
221 (*c_iter)->get_type(),
222 (*c_iter)->get_value());
224 indent_down();
225 indent(f_consts_impl) <<
226 "}" << endl;
228 f_consts <<
229 endl <<
230 "extern const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
231 endl <<
232 ns_close_ << endl <<
233 endl <<
234 "#endif" << endl;
235 f_consts.close();
237 f_consts_impl <<
238 endl <<
239 ns_close_ << endl <<
240 endl;
244 * Prints the value of a constant with the given type. Note that type checking
245 * is NOT performed in this function as it is always run beforehand using the
246 * validate_types method in main.cc
248 void t_cpp_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
249 if (type->is_base_type()) {
250 string v2 = render_const_value(out, name, type, value);
251 indent(out) << name << " = " << v2 << ";" << endl <<
252 endl;
253 } else if (type->is_enum()) {
254 indent(out) << name << " = (" << type->get_name() << ")" << value->get_integer() << ";" << endl <<
255 endl;
256 } else if (type->is_struct() || type->is_xception()) {
257 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
258 vector<t_field*>::const_iterator f_iter;
259 const map<t_const_value*, t_const_value*>& val = value->get_map();
260 map<t_const_value*, t_const_value*>::const_iterator v_iter;
261 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
262 t_type* field_type = NULL;
263 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
264 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
265 field_type = (*f_iter)->get_type();
268 if (field_type == NULL) {
269 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
271 string val = render_const_value(out, name, field_type, v_iter->second);
272 indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
273 indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
275 out << endl;
276 } else if (type->is_map()) {
277 t_type* ktype = ((t_map*)type)->get_key_type();
278 t_type* vtype = ((t_map*)type)->get_val_type();
279 const map<t_const_value*, t_const_value*>& val = value->get_map();
280 map<t_const_value*, t_const_value*>::const_iterator v_iter;
281 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
282 string key = render_const_value(out, name, ktype, v_iter->first);
283 string val = render_const_value(out, name, vtype, v_iter->second);
284 indent(out) << name << "[" << key << "] = " << val << ";" << endl;
286 out << endl;
287 } else if (type->is_list()) {
288 t_type* etype = ((t_list*)type)->get_elem_type();
289 const vector<t_const_value*>& val = value->get_list();
290 vector<t_const_value*>::const_iterator v_iter;
291 int i = 0;
292 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
293 string val = render_const_value(out, name, etype, *v_iter);
294 indent(out) << name << "[" << (i++) << "] = " << val << ";" << endl;
296 out << endl;
297 } else if (type->is_set()) {
298 t_type* etype = ((t_set*)type)->get_elem_type();
299 const vector<t_const_value*>& val = value->get_list();
300 vector<t_const_value*>::const_iterator v_iter;
301 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
302 string val = render_const_value(out, name, etype, *v_iter);
303 indent(out) << name << ".insert(" << val << ");" << endl;
305 out << endl;
312 string t_cpp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
313 std::ostringstream render;
315 if (type->is_base_type()) {
316 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
317 switch (tbase) {
318 case t_base_type::TYPE_STRING:
319 render << "\"" + value->get_string() + "\"";
320 break;
321 case t_base_type::TYPE_BOOL:
322 render << ((value->get_integer() > 0) ? "true" : "false");
323 break;
324 case t_base_type::TYPE_BYTE:
325 case t_base_type::TYPE_I16:
326 case t_base_type::TYPE_I32:
327 case t_base_type::TYPE_I64:
328 render << value->get_integer();
329 break;
330 case t_base_type::TYPE_DOUBLE:
331 if (value->get_type() == t_const_value::CV_INTEGER) {
332 render << value->get_integer();
333 } else {
334 render << value->get_double();
336 break;
337 default:
338 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
340 } else if (type->is_enum()) {
341 render << "(" << type_name(type) << ")" << value->get_integer();
342 } else {
343 string t = tmp("tmp");
344 indent(out) << type_name(type) << " " << t << ";" << endl;
345 print_const_value(out, t, type, value);
346 render << t;
349 return render.str();
353 * Generates a struct definition for a thrift data type. This is a class
354 * with data members and a read/write() function, plus a mirroring isset
355 * inner class.
357 * @param tstruct The struct definition
359 void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) {
360 generate_struct_definition(f_types_, tstruct, is_exception);
361 generate_struct_fingerprint(f_types_impl_, tstruct, true);
362 generate_local_reflection(f_types_, tstruct, false);
363 generate_local_reflection(f_types_impl_, tstruct, true);
364 generate_struct_reader(f_types_impl_, tstruct);
365 generate_struct_writer(f_types_impl_, tstruct);
369 * Writes the struct definition into the header file
371 * @param out Output stream
372 * @param tstruct The struct
374 void t_cpp_generator::generate_struct_definition(ofstream& out,
375 t_struct* tstruct,
376 bool is_exception,
377 bool pointers,
378 bool read,
379 bool write) {
380 string extends = "";
381 if (is_exception) {
382 extends = " : public facebook::thrift::TException";
385 // Open struct def
386 out <<
387 indent() << "class " << tstruct->get_name() << extends << " {" << endl <<
388 indent() << " public:" << endl <<
389 endl;
390 indent_up();
392 // Put the fingerprint up top for all to see.
393 generate_struct_fingerprint(out, tstruct, false);
395 // Get members
396 vector<t_field*>::const_iterator m_iter;
397 const vector<t_field*>& members = tstruct->get_members();
399 if (!pointers) {
400 // Default constructor
401 indent(out) <<
402 tstruct->get_name() << "()";
404 bool init_ctor = false;
406 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
407 t_type* t = get_true_type((*m_iter)->get_type());
408 if (t->is_base_type()) {
409 string dval;
410 if (t->is_enum()) {
411 dval += "(" + t->get_name() + ")";
413 dval += t->is_string() ? "\"\"" : "0";
414 t_const_value* cv = (*m_iter)->get_value();
415 if (cv != NULL) {
416 dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
418 if (!init_ctor) {
419 init_ctor = true;
420 out << " : ";
421 out << (*m_iter)->get_name() << "(" << dval << ")";
422 } else {
423 out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
427 out << " {" << endl;
428 indent_up();
429 // TODO(dreiss): When everything else in Thrift is perfect,
430 // do more of these in the initializer list.
431 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
432 t_type* t = get_true_type((*m_iter)->get_type());
434 if (!t->is_base_type()) {
435 t_const_value* cv = (*m_iter)->get_value();
436 if (cv != NULL) {
437 print_const_value(out, (*m_iter)->get_name(), t, cv);
441 scope_down(out);
444 out <<
445 endl <<
446 indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
448 // Declare all fields
449 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
450 indent(out) <<
451 declare_field(*m_iter, false, pointers && !(*m_iter)->get_type()->is_xception(), !read) << endl;
454 // Isset struct has boolean fields, but only for non-required fields.
455 bool has_nonrequired_fields = false;
456 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
457 if ((*m_iter)->get_req() != t_field::REQUIRED)
458 has_nonrequired_fields = true;
461 if (has_nonrequired_fields && (!pointers || read)) {
462 out <<
463 endl <<
464 indent() << "struct __isset {" << endl;
465 indent_up();
467 indent(out) <<
468 "__isset() : ";
469 bool first = true;
470 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
471 if ((*m_iter)->get_req() == t_field::REQUIRED) {
472 continue;
474 if (first) {
475 first = false;
476 out <<
477 (*m_iter)->get_name() << "(false)";
478 } else {
479 out <<
480 ", " << (*m_iter)->get_name() << "(false)";
483 out << " {}" << endl;
485 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
486 if ((*m_iter)->get_req() != t_field::REQUIRED) {
487 indent(out) <<
488 "bool " << (*m_iter)->get_name() << ";" << endl;
492 indent_down();
493 indent(out) <<
494 "} __isset;" << endl;
497 out << endl;
499 if (!pointers) {
500 // Generate an equality testing operator. Make it inline since the compiler
501 // will do a better job than we would when deciding whether to inline it.
502 out <<
503 indent() << "bool operator == (const " << tstruct->get_name() << " & rhs) const" << endl;
504 scope_up(out);
505 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
506 // Most existing Thrift code does not use isset or optional/required,
507 // so we treat "default" fields as required.
508 if ((*m_iter)->get_req() != t_field::OPTIONAL) {
509 out <<
510 indent() << "if (!(" << (*m_iter)->get_name()
511 << " == rhs." << (*m_iter)->get_name() << "))" << endl <<
512 indent() << " return false;" << endl;
513 } else {
514 out <<
515 indent() << "if (__isset." << (*m_iter)->get_name()
516 << " != rhs.__isset." << (*m_iter)->get_name() << ")" << endl <<
517 indent() << " return false;" << endl <<
518 indent() << "else if (__isset." << (*m_iter)->get_name() << " && !("
519 << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name()
520 << "))" << endl <<
521 indent() << " return false;" << endl;
524 indent(out) << "return true;" << endl;
525 scope_down(out);
526 out <<
527 indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" << endl <<
528 indent() << " return !(*this == rhs);" << endl <<
529 indent() << "}" << endl << endl;
531 if (read) {
532 out <<
533 indent() << "uint32_t read(facebook::thrift::protocol::TProtocol* iprot);" << endl;
535 if (write) {
536 out <<
537 indent() << "uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const;" << endl;
539 out << endl;
541 indent_down();
542 indent(out) <<
543 "};" << endl <<
544 endl;
548 * Writes the fingerprint of a struct to either the header or implementation.
550 * @param out Output stream
551 * @param tstruct The struct
553 void t_cpp_generator::generate_struct_fingerprint(ofstream& out,
554 t_struct* tstruct,
555 bool is_definition) {
556 string stat, nspace, comment;
557 if (is_definition) {
558 stat = "";
559 nspace = tstruct->get_name() + "::";
560 comment = " ";
561 } else {
562 stat = "static ";
563 nspace = "";
564 comment = "; // ";
567 if (tstruct->has_fingerprint()) {
568 out <<
569 indent() << stat << "char* " << nspace
570 << "ascii_fingerprint" << comment << "= \"" <<
571 tstruct->get_ascii_fingerprint() << "\";" << endl <<
572 indent() << stat << "char " << nspace <<
573 "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {";
574 char* comma = "";
575 for (int i = 0; i < t_type::fingerprint_len; i++) {
576 out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]);
577 comma = ",";
579 out << "};" << endl << endl;
584 * Writes the local reflection of a type (either declaration or definition).
586 void t_cpp_generator::generate_local_reflection(std::ofstream& out,
587 t_type* ttype,
588 bool is_definition) {
589 if (!gen_dense_) {
590 return;
592 ttype = get_true_type(ttype);
593 assert(ttype->has_fingerprint());
594 string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl");
595 // Note that we have generated this fingerprint. If we already did, bail out.
596 if (!reflected_fingerprints_.insert(key).second) {
597 return;
599 // Let each program handle its own structures.
600 if (ttype->get_program() != NULL && ttype->get_program() != program_) {
601 return;
604 // Do dependencies.
605 if (ttype->is_list()) {
606 generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition);
607 } else if (ttype->is_set()) {
608 generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition);
609 } else if (ttype->is_map()) {
610 generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition);
611 generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition);
612 } else if (ttype->is_struct() || ttype->is_xception()) {
613 const vector<t_field*>& members = ((t_struct*)ttype)->get_members();
614 vector<t_field*>::const_iterator m_iter;
615 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
616 generate_local_reflection(out, (**m_iter).get_type(), is_definition);
619 // For definitions of structures, do the arrays of tags and field specs also.
620 if (is_definition) {
621 indent(out) << "int16_t " << local_reflection_name("ftags", ttype) <<"[] = {" << endl;
622 indent_up();
623 indent(out);
624 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
625 out << (*m_iter)->get_key() << ", ";
627 indent_down();
628 out << endl << "};" << endl;
630 out <<
631 indent() << "facebook::thrift::reflection::local::TypeSpec*" << endl <<
632 indent() << local_reflection_name("specs", ttype) <<"[] = {" << endl;
633 indent_up();
634 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
635 indent(out) << "&" <<
636 local_reflection_name("typespec", (*m_iter)->get_type()) << "," << endl;
638 indent_down();
639 indent(out) << "};" << endl;
643 out <<
644 indent() << "// " << ttype->get_fingerprint_material() << endl <<
645 indent() << (is_definition ? "" : "extern ") <<
646 "facebook::thrift::reflection::local::TypeSpec" << endl <<
647 local_reflection_name("typespec", ttype) <<
648 (is_definition ? "(" : ";") << endl;
650 if (!is_definition) {
651 out << endl;
652 return;
655 indent_up();
657 indent(out) << type_to_enum(ttype);
659 if (ttype->is_struct()) {
660 out << "," << endl <<
661 indent() << ((t_struct*)ttype)->get_members().size() << "," << endl <<
662 indent() << local_reflection_name("ftags", ttype) << "," << endl <<
663 indent() << local_reflection_name("specs", ttype);
664 } else if (ttype->is_list()) {
665 out << "," << endl <<
666 indent() << "&" << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type()) << "," << endl <<
667 indent() << "NULL";
668 } else if (ttype->is_set()) {
669 out << "," << endl <<
670 indent() << "&" << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type()) << "," << endl <<
671 indent() << "NULL";
672 } else if (ttype->is_map()) {
673 out << "," << endl <<
674 indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type()) << "," << endl <<
675 indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type());
678 out << ");" << endl << endl;
680 indent_down();
684 * Makes a helper function to gen a struct reader.
686 * @param out Stream to write to
687 * @param tstruct The struct
689 void t_cpp_generator::generate_struct_reader(ofstream& out,
690 t_struct* tstruct,
691 bool pointers) {
692 indent(out) <<
693 "uint32_t " << tstruct->get_name() << "::read(facebook::thrift::protocol::TProtocol* iprot) {" << endl;
694 indent_up();
696 const vector<t_field*>& fields = tstruct->get_members();
697 vector<t_field*>::const_iterator f_iter;
699 // Declare stack tmp variables
700 out <<
701 endl <<
702 indent() << "uint32_t xfer = 0;" << endl <<
703 indent() << "std::string fname;" << endl <<
704 indent() << "facebook::thrift::protocol::TType ftype;" << endl <<
705 indent() << "int16_t fid;" << endl <<
706 endl <<
707 indent() << "xfer += iprot->readStructBegin(fname);" << endl <<
708 endl <<
709 indent() << "using facebook::thrift::protocol::TProtocolException;" << endl <<
710 endl;
712 // Required variables aren't in __isset, so we need tmp vars to check them.
713 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
714 if ((*f_iter)->get_req() == t_field::REQUIRED)
715 indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
717 out << endl;
720 // Loop over reading in fields
721 indent(out) <<
722 "while (true)" << endl;
723 scope_up(out);
725 // Read beginning field marker
726 indent(out) <<
727 "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
729 // Check for field STOP marker
730 out <<
731 indent() << "if (ftype == facebook::thrift::protocol::T_STOP) {" << endl <<
732 indent() << " break;" << endl <<
733 indent() << "}" << endl;
735 // Switch statement on the field we are reading
736 indent(out) <<
737 "switch (fid)" << endl;
739 scope_up(out);
741 // Generate deserialization code for known cases
742 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
743 indent(out) <<
744 "case " << (*f_iter)->get_key() << ":" << endl;
745 indent_up();
746 indent(out) <<
747 "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
748 indent_up();
750 const char *isset_prefix =
751 ((*f_iter)->get_req() != t_field::REQUIRED) ? "this->__isset." : "isset_";
753 #if 0
754 // This code throws an exception if the same field is encountered twice.
755 // We've decided to leave it out for performance reasons.
756 // TODO(dreiss): Generate this code and "if" it out to make it easier
757 // for people recompiling thrift to include it.
758 out <<
759 indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl <<
760 indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
761 #endif
763 if (pointers && !(*f_iter)->get_type()->is_xception()) {
764 generate_deserialize_field(out, *f_iter, "(*(this->", "))");
765 } else {
766 generate_deserialize_field(out, *f_iter, "this->");
768 out <<
769 indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl;
770 indent_down();
771 out <<
772 indent() << "} else {" << endl <<
773 indent() << " xfer += iprot->skip(ftype);" << endl <<
774 // TODO(dreiss): Make this an option when thrift structs
775 // have a common base class.
776 // indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl <<
777 indent() << "}" << endl <<
778 indent() << "break;" << endl;
779 indent_down();
782 // In the default case we skip the field
783 out <<
784 indent() << "default:" << endl <<
785 indent() << " xfer += iprot->skip(ftype);" << endl <<
786 indent() << " break;" << endl;
788 scope_down(out);
790 // Read field end marker
791 indent(out) <<
792 "xfer += iprot->readFieldEnd();" << endl;
794 scope_down(out);
796 out <<
797 endl <<
798 indent() << "xfer += iprot->readStructEnd();" << endl;
800 // Throw if any required fields are missing.
801 // We do this after reading the struct end so that
802 // there might possibly be a chance of continuing.
803 out << endl;
804 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
805 if ((*f_iter)->get_req() == t_field::REQUIRED)
806 out <<
807 indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
808 indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
811 indent(out) << "return xfer;" << endl;
813 indent_down();
814 indent(out) <<
815 "}" << endl << endl;
819 * Generates the write function.
821 * @param out Stream to write to
822 * @param tstruct The struct
824 void t_cpp_generator::generate_struct_writer(ofstream& out,
825 t_struct* tstruct,
826 bool pointers) {
827 string name = tstruct->get_name();
828 const vector<t_field*>& fields = tstruct->get_members();
829 vector<t_field*>::const_iterator f_iter;
831 indent(out) <<
832 "uint32_t " << tstruct->get_name() << "::write(facebook::thrift::protocol::TProtocol* oprot) const {" << endl;
833 indent_up();
835 out <<
836 indent() << "uint32_t xfer = 0;" << endl;
838 indent(out) <<
839 "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
840 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
841 if ((*f_iter)->get_req() == t_field::OPTIONAL) {
842 indent(out) << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
843 indent_up();
845 // Write field header
846 out <<
847 indent() << "xfer += oprot->writeFieldBegin(" <<
848 "\"" << (*f_iter)->get_name() << "\", " <<
849 type_to_enum((*f_iter)->get_type()) << ", " <<
850 (*f_iter)->get_key() << ");" << endl;
851 // Write field contents
852 if (pointers) {
853 generate_serialize_field(out, *f_iter, "(*(this->", "))");
854 } else {
855 generate_serialize_field(out, *f_iter, "this->");
857 // Write field closer
858 indent(out) <<
859 "xfer += oprot->writeFieldEnd();" << endl;
860 if ((*f_iter)->get_req() == t_field::OPTIONAL) {
861 indent_down();
862 indent(out) << '}' << endl;
866 // Write the struct map
867 out <<
868 indent() << "xfer += oprot->writeFieldStop();" << endl <<
869 indent() << "xfer += oprot->writeStructEnd();" << endl <<
870 indent() << "return xfer;" << endl;
872 indent_down();
873 indent(out) <<
874 "}" << endl <<
875 endl;
879 * Struct writer for result of a function, which can have only one of its
880 * fields set and does a conditional if else look up into the __isset field
881 * of the struct.
883 * @param out Output stream
884 * @param tstruct The result struct
886 void t_cpp_generator::generate_struct_result_writer(ofstream& out,
887 t_struct* tstruct,
888 bool pointers) {
889 string name = tstruct->get_name();
890 const vector<t_field*>& fields = tstruct->get_members();
891 vector<t_field*>::const_iterator f_iter;
893 indent(out) <<
894 "uint32_t " << tstruct->get_name() << "::write(facebook::thrift::protocol::TProtocol* oprot) const {" << endl;
895 indent_up();
897 out <<
898 endl <<
899 indent() << "uint32_t xfer = 0;" << endl <<
900 endl;
902 indent(out) <<
903 "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
905 bool first = true;
906 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
907 if (first) {
908 first = false;
909 out <<
910 endl <<
911 indent() << "if ";
912 } else {
913 out <<
914 " else if ";
917 out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
919 indent_up();
921 // Write field header
922 out <<
923 indent() << "xfer += oprot->writeFieldBegin(" <<
924 "\"" << (*f_iter)->get_name() << "\", " <<
925 type_to_enum((*f_iter)->get_type()) << ", " <<
926 (*f_iter)->get_key() << ");" << endl;
927 // Write field contents
928 if (pointers) {
929 generate_serialize_field(out, *f_iter, "(*(this->", "))");
930 } else {
931 generate_serialize_field(out, *f_iter, "this->");
933 // Write field closer
934 indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
936 indent_down();
937 indent(out) << "}";
940 // Write the struct map
941 out <<
942 endl <<
943 indent() << "xfer += oprot->writeFieldStop();" << endl <<
944 indent() << "xfer += oprot->writeStructEnd();" << endl <<
945 indent() << "return xfer;" << endl;
947 indent_down();
948 indent(out) <<
949 "}" << endl <<
950 endl;
954 * Generates a thrift service. In C++, this comprises an entirely separate
955 * header and source file. The header file defines the methods and includes
956 * the data types defined in the main header file, and the implementation
957 * file contains implementations of the basic printer and default interfaces.
959 * @param tservice The service definition
961 void t_cpp_generator::generate_service(t_service* tservice) {
962 string svcname = tservice->get_name();
964 // Make output files
965 string f_header_name = string(T_CPP_DIR)+"/"+svcname+".h";
966 f_header_.open(f_header_name.c_str());
968 // Print header file includes
969 f_header_ <<
970 autogen_comment();
971 f_header_ <<
972 "#ifndef " << svcname << "_H" << endl <<
973 "#define " << svcname << "_H" << endl <<
974 endl <<
975 "#include <TProcessor.h>" << endl <<
976 "#include \"" << program_name_ << "_types.h\"" << endl;
978 if (tservice->get_extends() != NULL) {
979 f_header_ <<
980 "#include \"" << tservice->get_extends()->get_name() << ".h\"" << endl;
983 f_header_ <<
984 endl <<
985 ns_open_ << endl <<
986 endl;
988 // Service implementation file includes
989 string f_service_name = string(T_CPP_DIR)+"/"+svcname+".cpp";
990 f_service_.open(f_service_name.c_str());
991 f_service_ <<
992 autogen_comment();
993 f_service_ <<
994 "#include \"" << svcname << ".h\"" << endl <<
995 endl <<
996 ns_open_ << endl <<
997 endl;
999 // Generate all the components
1000 generate_service_interface(tservice);
1001 generate_service_null(tservice);
1002 generate_service_helpers(tservice);
1003 generate_service_client(tservice);
1004 generate_service_processor(tservice);
1005 generate_service_multiface(tservice);
1006 generate_service_skeleton(tservice);
1008 // Close the namespace
1009 f_service_ <<
1010 ns_close_ << endl <<
1011 endl;
1012 f_header_ <<
1013 ns_close_ << endl <<
1014 endl;
1015 f_header_ <<
1016 "#endif" << endl;
1018 // Close the files
1019 f_service_.close();
1020 f_header_.close();
1024 * Generates helper functions for a service. Basically, this generates types
1025 * for all the arguments and results to functions.
1027 * @param tservice The service to generate a header definition for
1029 void t_cpp_generator::generate_service_helpers(t_service* tservice) {
1030 vector<t_function*> functions = tservice->get_functions();
1031 vector<t_function*>::iterator f_iter;
1032 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1033 t_struct* ts = (*f_iter)->get_arglist();
1034 string name_orig = ts->get_name();
1036 ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
1037 generate_struct_definition(f_header_, ts, false);
1038 generate_struct_reader(f_service_, ts);
1039 generate_struct_writer(f_service_, ts);
1040 ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
1041 generate_struct_definition(f_header_, ts, false, true, false, true);
1042 generate_struct_writer(f_service_, ts, true);
1043 ts->set_name(name_orig);
1045 generate_function_helpers(tservice, *f_iter);
1048 generate_service_limited_reflector(tservice);
1052 * Generates a service interface definition.
1054 * @param tservice The service to generate a header definition for
1056 void t_cpp_generator::generate_service_interface(t_service* tservice) {
1057 string extends = "";
1058 if (tservice->get_extends() != NULL) {
1059 extends = " : virtual public " + type_name(tservice->get_extends()) + "If";
1061 f_header_ <<
1062 "class " << service_name_ << "If" << extends << " {" << endl <<
1063 " public:" << endl;
1064 indent_up();
1065 f_header_ <<
1066 indent() << "virtual ~" << service_name_ << "If() {}" << endl;
1068 f_header_ <<
1069 indent() << "static void getStaticLimitedReflection" <<
1070 "(facebook::thrift::reflection::limited::Service & _return);" << endl;
1071 // TODO(dreiss): Uncomment and test this if we decide we need
1072 // a virtual function with this effect.
1073 //f_header_ <<
1074 // indent() << "virtual void getVirtualLimitedReflection" <<
1075 // "(facebook::thrift::reflection::limited::Service & _return) ";
1076 //scope_up(f_header_);
1077 //f_header_ <<
1078 // indent() << "getStaticLimitedReflection(_return);" << endl;
1079 //scope_down(f_header_);
1081 vector<t_function*> functions = tservice->get_functions();
1082 vector<t_function*>::iterator f_iter;
1083 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1084 f_header_ <<
1085 indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
1087 indent_down();
1088 f_header_ <<
1089 "};" << endl << endl;
1093 * Generates a null implementation of the service.
1095 * @param tservice The service to generate a header definition for
1097 void t_cpp_generator::generate_service_null(t_service* tservice) {
1098 string extends = "";
1099 if (tservice->get_extends() != NULL) {
1100 extends = " , virtual public " + type_name(tservice->get_extends()) + "Null";
1102 f_header_ <<
1103 "class " << service_name_ << "Null : virtual public " << service_name_ << "If" << extends << " {" << endl <<
1104 " public:" << endl;
1105 indent_up();
1106 f_header_ <<
1107 indent() << "virtual ~" << service_name_ << "Null() {}" << endl;
1108 vector<t_function*> functions = tservice->get_functions();
1109 vector<t_function*>::iterator f_iter;
1110 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1111 f_header_ <<
1112 indent() << function_signature(*f_iter) << " {" << endl;
1113 indent_up();
1114 t_type* returntype = (*f_iter)->get_returntype();
1115 if (returntype->is_void()) {
1116 f_header_ <<
1117 indent() << "return;" << endl;
1118 } else {
1119 if (is_complex_type(returntype)) {
1120 f_header_ <<
1121 indent() << "return;" << endl;
1122 } else {
1123 t_field returnfield(returntype, "_return");
1124 f_header_ <<
1125 indent() << declare_field(&returnfield, true) << endl <<
1126 indent() << "return _return;" << endl;
1129 indent_down();
1130 f_header_ <<
1131 indent() << "}" << endl;
1133 indent_down();
1134 f_header_ <<
1135 "};" << endl << endl;
1140 * Generates a multiface, which is a single server that just takes a set
1141 * of objects implementing the interface and calls them all, returning the
1142 * value of the last one to be called.
1144 * @param tservice The service to generate a multiserver for.
1146 void t_cpp_generator::generate_service_multiface(t_service* tservice) {
1147 // Generate the dispatch methods
1148 vector<t_function*> functions = tservice->get_functions();
1149 vector<t_function*>::iterator f_iter;
1151 string extends = "";
1152 string extends_multiface = "";
1153 if (tservice->get_extends() != NULL) {
1154 extends = type_name(tservice->get_extends());
1155 extends_multiface = ", public " + extends + "Multiface";
1158 string list_type = string("std::vector<boost::shared_ptr<") + service_name_ + "If> >";
1160 // Generate the header portion
1161 f_header_ <<
1162 "class " << service_name_ << "Multiface : " <<
1163 "virtual public " << service_name_ << "If" <<
1164 extends_multiface << " {" << endl <<
1165 " public:" << endl;
1166 indent_up();
1167 f_header_ <<
1168 indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
1169 if (!extends.empty()) {
1170 f_header_ <<
1171 indent() << " std::vector<boost::shared_ptr<" + service_name_ + "If> >::iterator iter;" << endl <<
1172 indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl <<
1173 indent() << " " << extends << "Multiface::add(*iter);" << endl <<
1174 indent() << " }" << endl;
1176 f_header_ <<
1177 indent() << "}" << endl <<
1178 indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl;
1179 indent_down();
1181 // Protected data members
1182 f_header_ <<
1183 " protected:" << endl;
1184 indent_up();
1185 f_header_ <<
1186 indent() << list_type << " ifaces_;" << endl <<
1187 indent() << service_name_ << "Multiface() {}" << endl <<
1188 indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) {" << endl;
1189 if (!extends.empty()) {
1190 f_header_ <<
1191 indent() << " " << extends << "Multiface::add(iface);" << endl;
1193 f_header_ <<
1194 indent() << " ifaces_.push_back(iface);" << endl <<
1195 indent() << "}" << endl;
1196 indent_down();
1198 f_header_ <<
1199 indent() << " public:" << endl;
1200 indent_up();
1202 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1203 t_struct* arglist = (*f_iter)->get_arglist();
1204 const vector<t_field*>& args = arglist->get_members();
1205 vector<t_field*>::const_iterator a_iter;
1207 string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
1208 bool first = true;
1209 if (is_complex_type((*f_iter)->get_returntype())) {
1210 call += "_return";
1211 first = false;
1213 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
1214 if (first) {
1215 first = false;
1216 } else {
1217 call += ", ";
1219 call += (*a_iter)->get_name();
1221 call += ")";
1223 f_header_ <<
1224 indent() << function_signature(*f_iter) << " {" << endl;
1225 indent_up();
1226 f_header_ <<
1227 indent() << "uint32_t sz = ifaces_.size();" << endl <<
1228 indent() << "for (uint32_t i = 0; i < sz; ++i) {" << endl;
1229 if (!(*f_iter)->get_returntype()->is_void()) {
1230 f_header_ <<
1231 indent() << " if (i == sz - 1) {" << endl;
1232 if (is_complex_type((*f_iter)->get_returntype())) {
1233 f_header_ <<
1234 indent() << " " << call << ";" << endl <<
1235 indent() << " return;" << endl;
1236 } else {
1237 f_header_ <<
1238 indent() << " return " << call << ";" << endl;
1240 f_header_ <<
1241 indent() << " } else {" << endl <<
1242 indent() << " " << call << ";" << endl <<
1243 indent() << " }" << endl;
1244 } else {
1245 f_header_ <<
1246 indent() << " " << call << ";" << endl;
1249 f_header_ <<
1250 indent() << "}" << endl;
1252 indent_down();
1253 f_header_ <<
1254 indent() << "}" << endl <<
1255 endl;
1258 indent_down();
1259 f_header_ <<
1260 indent() << "};" << endl <<
1261 endl;
1265 * Generates a service client definition.
1267 * @param tservice The service to generate a server for.
1269 void t_cpp_generator::generate_service_client(t_service* tservice) {
1270 string extends = "";
1271 string extends_client = "";
1272 if (tservice->get_extends() != NULL) {
1273 extends = type_name(tservice->get_extends());
1274 extends_client = ", public " + extends + "Client";
1277 // Generate the header portion
1278 f_header_ <<
1279 "class " << service_name_ << "Client : " <<
1280 "virtual public " << service_name_ << "If" <<
1281 extends_client << " {" << endl <<
1282 " public:" << endl;
1284 indent_up();
1285 f_header_ <<
1286 indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> prot) :" << endl;
1287 if (extends.empty()) {
1288 f_header_ <<
1289 indent() << " piprot_(prot)," << endl <<
1290 indent() << " poprot_(prot) {" << endl <<
1291 indent() << " iprot_ = prot.get();" << endl <<
1292 indent() << " oprot_ = prot.get();" << endl <<
1293 indent() << "}" << endl;
1294 } else {
1295 f_header_ <<
1296 indent() << " " << extends << "Client(prot, prot) {}" << endl;
1299 f_header_ <<
1300 indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) :" << endl;
1301 if (extends.empty()) {
1302 f_header_ <<
1303 indent() << " piprot_(iprot)," << endl <<
1304 indent() << " poprot_(oprot) {" << endl <<
1305 indent() << " iprot_ = iprot.get();" << endl <<
1306 indent() << " oprot_ = oprot.get();" << endl <<
1307 indent() << "}" << endl;
1308 } else {
1309 f_header_ <<
1310 indent() << " " << extends << "Client(iprot, oprot) {}" << endl;
1313 vector<t_function*> functions = tservice->get_functions();
1314 vector<t_function*>::const_iterator f_iter;
1315 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1316 t_function send_function(g_type_void,
1317 string("send_") + (*f_iter)->get_name(),
1318 (*f_iter)->get_arglist());
1319 indent(f_header_) << function_signature(*f_iter) << ";" << endl;
1320 indent(f_header_) << function_signature(&send_function) << ";" << endl;
1321 if (!(*f_iter)->is_async()) {
1322 t_struct noargs(program_);
1323 t_function recv_function((*f_iter)->get_returntype(),
1324 string("recv_") + (*f_iter)->get_name(),
1325 &noargs);
1326 indent(f_header_) << function_signature(&recv_function) << ";" << endl;
1329 indent_down();
1331 if (extends.empty()) {
1332 f_header_ <<
1333 " protected:" << endl;
1334 indent_up();
1335 f_header_ <<
1336 indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot_;" << endl <<
1337 indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot_;" << endl <<
1338 indent() << "facebook::thrift::protocol::TProtocol* iprot_;" << endl <<
1339 indent() << "facebook::thrift::protocol::TProtocol* oprot_;" << endl;
1340 indent_down();
1343 f_header_ <<
1344 "};" << endl <<
1345 endl;
1347 string scope = service_name_ + "Client::";
1349 // Generate client method implementations
1350 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1351 string funname = (*f_iter)->get_name();
1353 // Open function
1354 indent(f_service_) <<
1355 function_signature(*f_iter, scope) << endl;
1356 scope_up(f_service_);
1357 indent(f_service_) <<
1358 "send_" << funname << "(";
1360 // Get the struct of function call params
1361 t_struct* arg_struct = (*f_iter)->get_arglist();
1363 // Declare the function arguments
1364 const vector<t_field*>& fields = arg_struct->get_members();
1365 vector<t_field*>::const_iterator fld_iter;
1366 bool first = true;
1367 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1368 if (first) {
1369 first = false;
1370 } else {
1371 f_service_ << ", ";
1373 f_service_ << (*fld_iter)->get_name();
1375 f_service_ << ");" << endl;
1377 if (!(*f_iter)->is_async()) {
1378 f_service_ << indent();
1379 if (!(*f_iter)->get_returntype()->is_void()) {
1380 if (is_complex_type((*f_iter)->get_returntype())) {
1381 f_service_ << "recv_" << funname << "(_return);" << endl;
1382 } else {
1383 f_service_ << "return recv_" << funname << "();" << endl;
1385 } else {
1386 f_service_ <<
1387 "recv_" << funname << "();" << endl;
1390 scope_down(f_service_);
1391 f_service_ << endl;
1393 // Function for sending
1394 t_function send_function(g_type_void,
1395 string("send_") + (*f_iter)->get_name(),
1396 (*f_iter)->get_arglist());
1398 // Open the send function
1399 indent(f_service_) <<
1400 function_signature(&send_function, scope) << endl;
1401 scope_up(f_service_);
1403 // Function arguments and results
1404 string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs";
1405 string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult";
1407 // Serialize the request
1408 f_service_ <<
1409 indent() << "int32_t cseqid = 0;" << endl <<
1410 indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl <<
1411 endl <<
1412 indent() << argsname << " args;" << endl;
1414 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1415 f_service_ <<
1416 indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl;
1419 f_service_ <<
1420 indent() << "args.write(oprot_);" << endl <<
1421 endl <<
1422 indent() << "oprot_->writeMessageEnd();" << endl <<
1423 indent() << "oprot_->getTransport()->flush();" << endl;
1425 scope_down(f_service_);
1426 f_service_ << endl;
1428 // Generate recv function only if not an async function
1429 if (!(*f_iter)->is_async()) {
1430 t_struct noargs(program_);
1431 t_function recv_function((*f_iter)->get_returntype(),
1432 string("recv_") + (*f_iter)->get_name(),
1433 &noargs);
1434 // Open function
1435 indent(f_service_) <<
1436 function_signature(&recv_function, scope) << endl;
1437 scope_up(f_service_);
1439 f_service_ <<
1440 endl <<
1441 indent() << "int32_t rseqid = 0;" << endl <<
1442 indent() << "std::string fname;" << endl <<
1443 indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
1444 endl <<
1445 indent() << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl <<
1446 indent() << "if (mtype == facebook::thrift::protocol::T_EXCEPTION) {" << endl <<
1447 indent() << " facebook::thrift::TApplicationException x;" << endl <<
1448 indent() << " x.read(iprot_);" << endl <<
1449 indent() << " iprot_->readMessageEnd();" << endl <<
1450 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1451 indent() << " throw x;" << endl <<
1452 indent() << "}" << endl <<
1453 indent() << "if (mtype != facebook::thrift::protocol::T_REPLY) {" << endl <<
1454 indent() << " iprot_->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1455 indent() << " iprot_->readMessageEnd();" << endl <<
1456 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1457 indent() << " throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1458 indent() << "}" << endl <<
1459 indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl <<
1460 indent() << " iprot_->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1461 indent() << " iprot_->readMessageEnd();" << endl <<
1462 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1463 indent() << " throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::WRONG_METHOD_NAME);" << endl <<
1464 indent() << "}" << endl;
1466 if (!(*f_iter)->get_returntype()->is_void() &&
1467 !is_complex_type((*f_iter)->get_returntype())) {
1468 t_field returnfield((*f_iter)->get_returntype(), "_return");
1469 f_service_ <<
1470 indent() << declare_field(&returnfield) << endl;
1473 f_service_ <<
1474 indent() << resultname << " result;" << endl;
1476 if (!(*f_iter)->get_returntype()->is_void()) {
1477 f_service_ <<
1478 indent() << "result.success = &_return;" << endl;
1481 f_service_ <<
1482 indent() << "result.read(iprot_);" << endl <<
1483 indent() << "iprot_->readMessageEnd();" << endl <<
1484 indent() << "iprot_->getTransport()->readEnd();" << endl <<
1485 endl;
1487 // Careful, only look for _result if not a void function
1488 if (!(*f_iter)->get_returntype()->is_void()) {
1489 if (is_complex_type((*f_iter)->get_returntype())) {
1490 f_service_ <<
1491 indent() << "if (result.__isset.success) {" << endl <<
1492 indent() << " // _return pointer has now been filled" << endl <<
1493 indent() << " return;" << endl <<
1494 indent() << "}" << endl;
1495 } else {
1496 f_service_ <<
1497 indent() << "if (result.__isset.success) {" << endl <<
1498 indent() << " return _return;" << endl <<
1499 indent() << "}" << endl;
1503 t_struct* xs = (*f_iter)->get_xceptions();
1504 const std::vector<t_field*>& xceptions = xs->get_members();
1505 vector<t_field*>::const_iterator x_iter;
1506 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1507 f_service_ <<
1508 indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
1509 indent() << " throw result." << (*x_iter)->get_name() << ";" << endl <<
1510 indent() << "}" << endl;
1513 // We only get here if we are a void function
1514 if ((*f_iter)->get_returntype()->is_void()) {
1515 indent(f_service_) <<
1516 "return;" << endl;
1517 } else {
1518 f_service_ <<
1519 indent() << "throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1522 // Close function
1523 scope_down(f_service_);
1524 f_service_ << endl;
1530 * Generates a service server definition.
1532 * @param tservice The service to generate a server for.
1534 void t_cpp_generator::generate_service_processor(t_service* tservice) {
1535 // Generate the dispatch methods
1536 vector<t_function*> functions = tservice->get_functions();
1537 vector<t_function*>::iterator f_iter;
1539 string extends = "";
1540 string extends_processor = "";
1541 if (tservice->get_extends() != NULL) {
1542 extends = type_name(tservice->get_extends());
1543 extends_processor = ", public " + extends + "Processor";
1546 // Generate the header portion
1547 f_header_ <<
1548 "class " << service_name_ << "Processor : " <<
1549 "virtual public facebook::thrift::TProcessor" <<
1550 extends_processor << " {" << endl;
1552 // Protected data members
1553 f_header_ <<
1554 " protected:" << endl;
1555 indent_up();
1556 f_header_ <<
1557 indent() << "boost::shared_ptr<" << service_name_ << "If> iface_;" << endl;
1558 f_header_ <<
1559 indent() << "virtual bool process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid);" << endl;
1560 indent_down();
1562 // Process function declarations
1563 f_header_ <<
1564 " private:" << endl;
1565 indent_up();
1566 f_header_ <<
1567 indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)> processMap_;" << endl;
1568 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1569 indent(f_header_) <<
1570 "void process_" << (*f_iter)->get_name() << "(int32_t seqid, facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot);" << endl;
1572 indent_down();
1574 indent_up();
1575 string declare_map = "";
1576 indent_up();
1578 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1579 declare_map += indent();
1580 declare_map += "processMap_[\"";
1581 declare_map += (*f_iter)->get_name();
1582 declare_map += "\"] = &";
1583 declare_map += service_name_;
1584 declare_map += "Processor::process_";
1585 declare_map += (*f_iter)->get_name();
1586 declare_map += ";\n";
1588 indent_down();
1590 f_header_ <<
1591 " public:" << endl <<
1592 indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface) :" << endl;
1593 if (extends.empty()) {
1594 f_header_ <<
1595 indent() << " iface_(iface) {" << endl;
1596 } else {
1597 f_header_ <<
1598 indent() << " " << extends << "Processor(iface)," << endl <<
1599 indent() << " iface_(iface) {" << endl;
1601 f_header_ <<
1602 declare_map <<
1603 indent() << "}" << endl <<
1604 endl <<
1605 indent() << "virtual bool process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot);" << endl <<
1606 indent() << "virtual ~" << service_name_ << "Processor() {}" << endl;
1607 indent_down();
1608 f_header_ <<
1609 "};" << endl << endl;
1611 // Generate the server implementation
1612 f_service_ <<
1613 "bool " << service_name_ << "Processor::process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot) {" << endl;
1614 indent_up();
1616 f_service_ <<
1617 endl <<
1618 indent() << "facebook::thrift::protocol::TProtocol* iprot = piprot.get();" << endl <<
1619 indent() << "facebook::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
1620 indent() << "std::string fname;" << endl <<
1621 indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
1622 indent() << "int32_t seqid;" << endl <<
1623 endl <<
1624 indent() << "iprot->readMessageBegin(fname, mtype, seqid);" << endl <<
1625 endl <<
1626 indent() << "if (mtype != facebook::thrift::protocol::T_CALL) {" << endl <<
1627 indent() << " iprot->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1628 indent() << " iprot->readMessageEnd();" << endl <<
1629 indent() << " iprot->getTransport()->readEnd();" << endl <<
1630 indent() << " facebook::thrift::TApplicationException x(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1631 indent() << " oprot->writeMessageBegin(fname, facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1632 indent() << " x.write(oprot);" << endl <<
1633 indent() << " oprot->writeMessageEnd();" << endl <<
1634 indent() << " oprot->getTransport()->flush();" << endl <<
1635 indent() << " return true;" << endl <<
1636 indent() << "}" << endl <<
1637 endl <<
1638 indent() << "return process_fn(iprot, oprot, fname, seqid);" <<
1639 endl;
1641 indent_down();
1642 f_service_ <<
1643 indent() << "}" << endl <<
1644 endl;
1646 f_service_ <<
1647 "bool " << service_name_ << "Processor::process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid) {" << endl;
1648 indent_up();
1650 // HOT: member function pointer map
1651 f_service_ <<
1652 indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)>::iterator pfn;" << endl <<
1653 indent() << "pfn = processMap_.find(fname);" << endl <<
1654 indent() << "if (pfn == processMap_.end()) {" << endl;
1655 if (extends.empty()) {
1656 f_service_ <<
1657 indent() << " iprot->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1658 indent() << " iprot->readMessageEnd();" << endl <<
1659 indent() << " iprot->getTransport()->readEnd();" << endl <<
1660 indent() << " facebook::thrift::TApplicationException x(facebook::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: '\"+fname+\"'\");" << endl <<
1661 indent() << " oprot->writeMessageBegin(fname, facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1662 indent() << " x.write(oprot);" << endl <<
1663 indent() << " oprot->writeMessageEnd();" << endl <<
1664 indent() << " oprot->getTransport()->flush();" << endl <<
1665 indent() << " return true;" << endl;
1666 } else {
1667 f_service_ <<
1668 indent() << " return " << extends << "Processor::process_fn(iprot, oprot, fname, seqid);" << endl;
1670 f_service_ <<
1671 indent() << "} else {" << endl <<
1672 indent() << " (this->*(pfn->second))(seqid, iprot, oprot);" << endl <<
1673 indent() << "}" << endl;
1675 // Read end of args field, the T_STOP, and the struct close
1676 f_service_ <<
1677 indent() << "return true;" << endl;
1679 indent_down();
1680 f_service_ <<
1681 "}" << endl <<
1682 endl;
1684 // Generate the process subfunctions
1685 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1686 generate_process_function(tservice, *f_iter);
1691 * Generates a struct and helpers for a function.
1693 * @param tfunction The function
1695 void t_cpp_generator::generate_function_helpers(t_service* tservice,
1696 t_function* tfunction) {
1697 if (tfunction->is_async()) {
1698 return;
1701 t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result");
1702 t_field success(tfunction->get_returntype(), "success", 0);
1703 if (!tfunction->get_returntype()->is_void()) {
1704 result.append(&success);
1707 t_struct* xs = tfunction->get_xceptions();
1708 const vector<t_field*>& fields = xs->get_members();
1709 vector<t_field*>::const_iterator f_iter;
1710 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1711 result.append(*f_iter);
1714 generate_struct_definition(f_header_, &result, false);
1715 generate_struct_reader(f_service_, &result);
1716 generate_struct_result_writer(f_service_, &result);
1718 result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
1719 generate_struct_definition(f_header_, &result, false, true, true, false);
1720 generate_struct_reader(f_service_, &result, true);
1725 * Generates a process function definition.
1727 * @param tfunction The function to write a dispatcher for
1729 void t_cpp_generator::generate_process_function(t_service* tservice,
1730 t_function* tfunction) {
1731 // Open function
1732 f_service_ <<
1733 "void " << tservice->get_name() << "Processor::" <<
1734 "process_" << tfunction->get_name() <<
1735 "(int32_t seqid, facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot)" << endl;
1736 scope_up(f_service_);
1738 string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
1739 string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
1741 f_service_ <<
1742 indent() << argsname << " args;" << endl <<
1743 indent() << "args.read(iprot);" << endl <<
1744 indent() << "iprot->readMessageEnd();" << endl <<
1745 indent() << "iprot->getTransport()->readEnd();" << endl <<
1746 endl;
1748 t_struct* xs = tfunction->get_xceptions();
1749 const std::vector<t_field*>& xceptions = xs->get_members();
1750 vector<t_field*>::const_iterator x_iter;
1752 // Declare result
1753 if (!tfunction->is_async()) {
1754 f_service_ <<
1755 indent() << resultname << " result;" << endl;
1758 // Try block for functions with exceptions
1759 if (xceptions.size() > 0) {
1760 f_service_ <<
1761 indent() << "try {" << endl;
1762 indent_up();
1765 // Generate the function call
1766 t_struct* arg_struct = tfunction->get_arglist();
1767 const std::vector<t_field*>& fields = arg_struct->get_members();
1768 vector<t_field*>::const_iterator f_iter;
1770 bool first = true;
1771 f_service_ << indent();
1772 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1773 if (is_complex_type(tfunction->get_returntype())) {
1774 first = false;
1775 f_service_ << "iface_->" << tfunction->get_name() << "(result.success";
1776 } else {
1777 f_service_ << "result.success = iface_->" << tfunction->get_name() << "(";
1779 } else {
1780 f_service_ <<
1781 "iface_->" << tfunction->get_name() << "(";
1783 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1784 if (first) {
1785 first = false;
1786 } else {
1787 f_service_ << ", ";
1789 f_service_ << "args." << (*f_iter)->get_name();
1791 f_service_ << ");" << endl;
1793 // Set isset on success field
1794 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1795 f_service_ <<
1796 indent() << "result.__isset.success = true;" << endl;
1799 if (!tfunction->is_async() && xceptions.size() > 0) {
1800 indent_down();
1801 f_service_ << indent() << "}";
1802 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1803 f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " &" << (*x_iter)->get_name() << ") {" << endl;
1804 if (!tfunction->is_async()) {
1805 indent_up();
1806 f_service_ <<
1807 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
1808 indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
1809 indent_down();
1810 f_service_ << indent() << "}";
1811 } else {
1812 f_service_ << "}";
1815 f_service_ << endl;
1818 // Shortcut out here for async functions
1819 if (tfunction->is_async()) {
1820 f_service_ <<
1821 indent() << "return;" << endl;
1822 indent_down();
1823 f_service_ << "}" << endl <<
1824 endl;
1825 return;
1828 // Serialize the result into a struct
1829 f_service_ <<
1830 endl <<
1831 indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_REPLY, seqid);" << endl <<
1832 indent() << "result.write(oprot);" << endl <<
1833 indent() << "oprot->writeMessageEnd();" << endl <<
1834 indent() << "oprot->getTransport()->flush();" << endl <<
1835 indent() << "oprot->getTransport()->writeEnd();" << endl;
1837 // Close function
1838 scope_down(f_service_);
1839 f_service_ << endl;
1843 * Helper function for generate_service_limited_reflector.
1844 * Generates a reflection of a single simple type.
1846 * @param ttype The type to reflect
1847 * @param target The name of the lvalue to reflect onto
1848 * @return true iff the type really is simple
1850 * Note: don't let this function output anything unless it is going to return true.
1852 bool t_cpp_generator::generate_simple_type_limited_reflection(ostream & out, t_type* ttype, string target) {
1853 if (ttype->is_base_type()) {
1854 string type;
1855 switch (((t_base_type*)ttype)->get_base()) {
1856 case t_base_type::TYPE_VOID : type = "T_VOID;" ; break;
1857 case t_base_type::TYPE_STRING : type = "T_STRING;" ; break;
1858 case t_base_type::TYPE_BOOL : type = "T_BOOL;" ; break;
1859 case t_base_type::TYPE_BYTE : type = "T_BYTE;" ; break;
1860 case t_base_type::TYPE_I16 : type = "T_I16;" ; break;
1861 case t_base_type::TYPE_I32 : type = "T_I32;" ; break;
1862 case t_base_type::TYPE_I64 : type = "T_I64;" ; break;
1863 case t_base_type::TYPE_DOUBLE : type = "T_DOUBLE;" ; break;
1864 default: return false;
1866 out << indent() << target << ".ttype = " << type << endl;
1867 return true;
1870 if (ttype->is_enum()) {
1871 out <<
1872 indent() << target << ".ttype = T_ENUM;" << endl <<
1873 indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl;
1876 if (ttype->is_struct()) {
1877 out <<
1878 indent() << target << ".ttype = T_STRUCT;" << endl <<
1879 indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl;
1880 return true;
1883 return false;
1887 * Helper function for generate_service_limited_reflector.
1888 * Generates a reflection of a single type.
1890 * @param ttype The type to reflect
1891 * @param target The name of the lvalue to reflect onto
1893 bool t_cpp_generator::generate_type_limited_reflection(t_type* ttype, string target) {
1894 bool is_simple = generate_simple_type_limited_reflection(f_service_, ttype, target + ".simple_type");
1895 if (is_simple) {
1896 f_service_ <<
1897 indent() << target << ".is_container = false;" << endl <<
1898 indent() << target << ".__isset.simple_type = true;" << endl;
1899 return true;
1902 ostringstream out;
1904 out <<
1905 indent() << target << ".is_container = true;" << endl <<
1906 indent() << target << ".__isset.container_type = true;" << endl <<
1907 indent() << target << ".container_type.ttype = ";
1909 if (ttype->is_list()) out << "T_LIST;" << endl;
1910 if (ttype->is_set()) out << "T_SET;" << endl;
1911 if (ttype->is_map()) out << "T_MAP;" << endl;
1913 bool reflected = false;
1915 if (ttype->is_list()) {
1916 reflected = generate_simple_type_limited_reflection(
1917 out, ((t_list*)ttype)->get_elem_type(), target + ".container_type.subtype1");
1919 if (ttype->is_set()) {
1920 reflected = generate_simple_type_limited_reflection(
1921 out, ((t_set*)ttype)->get_elem_type(), target + ".container_type.subtype1");
1923 if (ttype->is_map()) {
1924 reflected =
1925 generate_simple_type_limited_reflection(
1926 out, ((t_map*)ttype)->get_key_type(), target + ".container_type.subtype1")
1928 generate_simple_type_limited_reflection(
1929 out, ((t_map*)ttype)->get_val_type(), target + ".container_type.subtype2");
1930 out << indent() << target << ".container_type.__isset.subtype2 = true;" << endl;
1933 if (reflected) {
1934 f_service_ << out.str();
1935 return true;
1936 } else {
1937 f_service_ <<
1938 indent() << target << ".is_container = false;" << endl <<
1939 indent() << target << ".__isset.simple_type = true;" << endl;
1940 f_service_ << indent() << target << ".simple_type.ttype = T_NOT_REFLECTED;" << endl;
1941 return false;
1946 * Generates a service reflector definition.
1947 * This uses thrift::reflection::limited.
1949 * @param tservice The service to write a reflector for
1951 void t_cpp_generator::generate_service_limited_reflector(t_service* tservice) {
1952 // Open function
1953 f_service_ <<
1954 indent() << "void " << tservice->get_name() << "If::getStaticLimitedReflection" <<
1955 "(facebook::thrift::reflection::limited::Service & _return) ";
1956 scope_up(f_service_);
1958 f_service_ << indent() << "using namespace facebook::thrift::reflection::limited;" << endl;
1960 f_service_ << indent() << "_return.name = \"" << tservice->get_name() << "\";" << endl;
1961 f_service_ << indent() << "_return.fully_reflected = true;" << endl;
1963 bool all_reflectable = true;
1964 bool one_reflectable;
1966 const vector<t_function*> & funcs = tservice->get_functions();
1967 vector<t_function*>::const_iterator f_iter;
1968 for (f_iter = funcs.begin(); f_iter != funcs.end(); ++f_iter) {
1970 f_service_ << indent() << "_return.methods.resize(_return.methods.size() + 1);" << endl;
1971 f_service_ << indent() << "_return.methods.back().name = \"" << (*f_iter)->get_name() << "\";" << endl;
1972 one_reflectable = generate_type_limited_reflection(
1973 (*f_iter)->get_returntype(), "_return.methods.back().return_type");
1974 all_reflectable = all_reflectable && one_reflectable;
1976 t_struct* arglist = (*f_iter)->get_arglist();
1977 const vector<t_field*> & args = arglist->get_members();
1978 vector<t_field*>::const_iterator a_iter;
1979 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
1980 f_service_ <<
1981 indent() << "_return.methods.back().arguments.resize("
1982 "_return.methods.back().arguments.size() + 1);" << endl <<
1983 indent() << "_return.methods.back().arguments.back().name = \"" <<
1984 (*a_iter)->get_name() << "\";" << endl <<
1985 indent() << "_return.methods.back().arguments.back().key = " <<
1986 (*a_iter)->get_key() << ";" << endl;
1987 one_reflectable = generate_type_limited_reflection(
1988 (*a_iter)->get_type(), "_return.methods.back().arguments.back().type");
1989 all_reflectable = all_reflectable && one_reflectable;
1993 if (!all_reflectable) {
1994 f_service_ << indent() << "_return.fully_reflected = false;" << endl;
1997 // Close function
1998 scope_down(f_service_);
1999 f_service_ << endl;
2003 * Generates a skeleton file of a server
2005 * @param tservice The service to generate a server for.
2007 void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
2008 string svcname = tservice->get_name();
2010 // Service implementation file includes
2011 string f_skeleton_name = string(T_CPP_DIR)+"/"+svcname+"_server.skeleton.cpp";
2013 string ns = namespace_prefix(tservice->get_program()->get_cpp_namespace());
2015 ofstream f_skeleton;
2016 f_skeleton.open(f_skeleton_name.c_str());
2017 f_skeleton <<
2018 "// This autogenerated skeleton file illustrates how to build a server." << endl <<
2019 "// You should copy it to another filename to avoid overwriting it." << endl <<
2020 endl <<
2021 "#include \"" << svcname << ".h\"" << endl <<
2022 "#include <protocol/TBinaryProtocol.h>" << endl <<
2023 "#include <server/TSimpleServer.h>" << endl <<
2024 "#include <transport/TServerSocket.h>" << endl <<
2025 "#include <transport/TTransportUtils.h>" << endl <<
2026 endl <<
2027 "using namespace facebook::thrift;" << endl <<
2028 "using namespace facebook::thrift::protocol;" << endl <<
2029 "using namespace facebook::thrift::transport;" << endl <<
2030 "using namespace facebook::thrift::server;" << endl <<
2031 endl <<
2032 "using boost::shared_ptr;" << endl <<
2033 endl;
2035 if (!ns.empty()) {
2036 f_skeleton <<
2037 "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
2038 endl;
2041 f_skeleton <<
2042 "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl <<
2043 " public:" << endl;
2044 indent_up();
2045 f_skeleton <<
2046 indent() << svcname << "Handler() {" << endl <<
2047 indent() << " // Your initialization goes here" << endl <<
2048 indent() << "}" << endl <<
2049 endl;
2051 vector<t_function*> functions = tservice->get_functions();
2052 vector<t_function*>::iterator f_iter;
2053 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2054 f_skeleton <<
2055 indent() << function_signature(*f_iter) << " {" << endl <<
2056 indent() << " // Your implementation goes here" << endl <<
2057 indent() << " printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl <<
2058 indent() << "}" << endl <<
2059 endl;
2062 indent_down();
2063 f_skeleton <<
2064 "};" << endl <<
2065 endl;
2067 f_skeleton <<
2068 indent() << "int main(int argc, char **argv) {" << endl;
2069 indent_up();
2070 f_skeleton <<
2071 indent() << "int port = 9090;" << endl <<
2072 indent() << "shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl <<
2073 indent() << "shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl <<
2074 indent() << "shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));" << endl <<
2075 indent() << "shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl <<
2076 indent() << "shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());" << endl <<
2077 endl <<
2078 indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl <<
2079 indent() << "server.serve();" << endl <<
2080 indent() << "return 0;" << endl;
2081 indent_down();
2082 f_skeleton <<
2083 "}" << endl <<
2084 endl;
2086 // Close the files
2087 f_skeleton.close();
2091 * Deserializes a field of any type.
2093 void t_cpp_generator::generate_deserialize_field(ofstream& out,
2094 t_field* tfield,
2095 string prefix,
2096 string suffix) {
2097 t_type* type = get_true_type(tfield->get_type());
2099 if (type->is_void()) {
2100 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
2101 prefix + tfield->get_name();
2104 string name = prefix + tfield->get_name() + suffix;
2106 if (type->is_struct() || type->is_xception()) {
2107 generate_deserialize_struct(out, (t_struct*)type, name);
2108 } else if (type->is_container()) {
2109 generate_deserialize_container(out, type, name);
2110 } else if (type->is_base_type()) {
2111 indent(out) <<
2112 "xfer += iprot->";
2113 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2114 switch (tbase) {
2115 case t_base_type::TYPE_VOID:
2116 throw "compiler error: cannot serialize void field in a struct: " + name;
2117 break;
2118 case t_base_type::TYPE_STRING:
2119 out << "readString(" << name << ");";
2120 break;
2121 case t_base_type::TYPE_BOOL:
2122 out << "readBool(" << name << ");";
2123 break;
2124 case t_base_type::TYPE_BYTE:
2125 out << "readByte(" << name << ");";
2126 break;
2127 case t_base_type::TYPE_I16:
2128 out << "readI16(" << name << ");";
2129 break;
2130 case t_base_type::TYPE_I32:
2131 out << "readI32(" << name << ");";
2132 break;
2133 case t_base_type::TYPE_I64:
2134 out << "readI64(" << name << ");";
2135 break;
2136 case t_base_type::TYPE_DOUBLE:
2137 out << "readDouble(" << name << ");";
2138 break;
2139 default:
2140 throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
2142 out <<
2143 endl;
2144 } else if (type->is_enum()) {
2145 string t = tmp("ecast");
2146 out <<
2147 indent() << "int32_t " << t << ";" << endl <<
2148 indent() << "xfer += iprot->readI32(" << t << ");" << endl <<
2149 indent() << name << " = (" << type->get_name() << ")" << t << ";" << endl;
2150 } else {
2151 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
2152 tfield->get_name().c_str(), type_name(type).c_str());
2157 * Generates an unserializer for a variable. This makes two key assumptions,
2158 * first that there is a const char* variable named data that points to the
2159 * buffer for deserialization, and that there is a variable protocol which
2160 * is a reference to a TProtocol serialization object.
2162 void t_cpp_generator::generate_deserialize_struct(ofstream& out,
2163 t_struct* tstruct,
2164 string prefix) {
2165 indent(out) <<
2166 "xfer += " << prefix << ".read(iprot);" << endl;
2169 void t_cpp_generator::generate_deserialize_container(ofstream& out,
2170 t_type* ttype,
2171 string prefix) {
2172 scope_up(out);
2174 string size = tmp("_size");
2175 string ktype = tmp("_ktype");
2176 string vtype = tmp("_vtype");
2177 string etype = tmp("_etype");
2179 indent(out) <<
2180 prefix << ".clear();" << endl <<
2181 indent() << "uint32_t " << size << ";" << endl;
2183 // Declare variables, read header
2184 if (ttype->is_map()) {
2185 out <<
2186 indent() << "facebook::thrift::protocol::TType " << ktype << ";" << endl <<
2187 indent() << "facebook::thrift::protocol::TType " << vtype << ";" << endl <<
2188 indent() << "iprot->readMapBegin(" <<
2189 ktype << ", " << vtype << ", " << size << ");" << endl;
2190 } else if (ttype->is_set()) {
2191 out <<
2192 indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
2193 indent() << "iprot->readSetBegin(" <<
2194 etype << ", " << size << ");" << endl;
2195 } else if (ttype->is_list()) {
2196 out <<
2197 indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
2198 indent() << "iprot->readListBegin(" <<
2199 etype << ", " << size << ");" << endl;
2203 // For loop iterates over elements
2204 string i = tmp("_i");
2205 out <<
2206 indent() << "uint32_t " << i << ";" << endl <<
2207 indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
2209 scope_up(out);
2211 if (ttype->is_map()) {
2212 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
2213 } else if (ttype->is_set()) {
2214 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
2215 } else if (ttype->is_list()) {
2216 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
2219 scope_down(out);
2221 // Read container end
2222 if (ttype->is_map()) {
2223 indent(out) << "iprot->readMapEnd();" << endl;
2224 } else if (ttype->is_set()) {
2225 indent(out) << "iprot->readSetEnd();" << endl;
2226 } else if (ttype->is_list()) {
2227 indent(out) << "iprot->readListEnd();" << endl;
2230 scope_down(out);
2235 * Generates code to deserialize a map
2237 void t_cpp_generator::generate_deserialize_map_element(ofstream& out,
2238 t_map* tmap,
2239 string prefix) {
2240 string key = tmp("_key");
2241 string val = tmp("_val");
2242 t_field fkey(tmap->get_key_type(), key);
2243 t_field fval(tmap->get_val_type(), val);
2245 out <<
2246 indent() << declare_field(&fkey) << endl <<
2247 indent() << declare_field(&fval) << endl;
2249 generate_deserialize_field(out, &fkey);
2250 generate_deserialize_field(out, &fval);
2252 indent(out) <<
2253 prefix << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
2256 void t_cpp_generator::generate_deserialize_set_element(ofstream& out,
2257 t_set* tset,
2258 string prefix) {
2259 string elem = tmp("_elem");
2260 t_field felem(tset->get_elem_type(), elem);
2262 indent(out) <<
2263 declare_field(&felem) << endl;
2265 generate_deserialize_field(out, &felem);
2267 indent(out) <<
2268 prefix << ".insert(" << elem << ");" << endl;
2271 void t_cpp_generator::generate_deserialize_list_element(ofstream& out,
2272 t_list* tlist,
2273 string prefix) {
2274 string elem = tmp("_elem");
2275 t_field felem(tlist->get_elem_type(), elem);
2277 indent(out) <<
2278 declare_field(&felem) << endl;
2280 generate_deserialize_field(out, &felem);
2282 indent(out) <<
2283 prefix << ".push_back(" << elem << ");" << endl;
2288 * Serializes a field of any type.
2290 * @param tfield The field to serialize
2291 * @param prefix Name to prepend to field name
2293 void t_cpp_generator::generate_serialize_field(ofstream& out,
2294 t_field* tfield,
2295 string prefix,
2296 string suffix) {
2297 t_type* type = get_true_type(tfield->get_type());
2299 string name = prefix + tfield->get_name() + suffix;
2301 // Do nothing for void types
2302 if (type->is_void()) {
2303 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
2308 if (type->is_struct() || type->is_xception()) {
2309 generate_serialize_struct(out,
2310 (t_struct*)type,
2311 name);
2312 } else if (type->is_container()) {
2313 generate_serialize_container(out, type, name);
2314 } else if (type->is_base_type() || type->is_enum()) {
2316 indent(out) <<
2317 "xfer += oprot->";
2319 if (type->is_base_type()) {
2320 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2321 switch (tbase) {
2322 case t_base_type::TYPE_VOID:
2323 throw
2324 "compiler error: cannot serialize void field in a struct: " + name;
2325 break;
2326 case t_base_type::TYPE_STRING:
2327 out << "writeString(" << name << ");";
2328 break;
2329 case t_base_type::TYPE_BOOL:
2330 out << "writeBool(" << name << ");";
2331 break;
2332 case t_base_type::TYPE_BYTE:
2333 out << "writeByte(" << name << ");";
2334 break;
2335 case t_base_type::TYPE_I16:
2336 out << "writeI16(" << name << ");";
2337 break;
2338 case t_base_type::TYPE_I32:
2339 out << "writeI32(" << name << ");";
2340 break;
2341 case t_base_type::TYPE_I64:
2342 out << "writeI64(" << name << ");";
2343 break;
2344 case t_base_type::TYPE_DOUBLE:
2345 out << "writeDouble(" << name << ");";
2346 break;
2347 default:
2348 throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + name;
2350 } else if (type->is_enum()) {
2351 out << "writeI32((int32_t)" << name << ");";
2353 out << endl;
2354 } else {
2355 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
2356 name.c_str(),
2357 type_name(type).c_str());
2362 * Serializes all the members of a struct.
2364 * @param tstruct The struct to serialize
2365 * @param prefix String prefix to attach to all fields
2367 void t_cpp_generator::generate_serialize_struct(ofstream& out,
2368 t_struct* tstruct,
2369 string prefix) {
2370 indent(out) <<
2371 "xfer += " << prefix << ".write(oprot);" << endl;
2374 void t_cpp_generator::generate_serialize_container(ofstream& out,
2375 t_type* ttype,
2376 string prefix) {
2377 scope_up(out);
2379 if (ttype->is_map()) {
2380 indent(out) <<
2381 "xfer += oprot->writeMapBegin(" <<
2382 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
2383 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
2384 prefix << ".size());" << endl;
2385 } else if (ttype->is_set()) {
2386 indent(out) <<
2387 "xfer += oprot->writeSetBegin(" <<
2388 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
2389 prefix << ".size());" << endl;
2390 } else if (ttype->is_list()) {
2391 indent(out) <<
2392 "xfer += oprot->writeListBegin(" <<
2393 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
2394 prefix << ".size());" << endl;
2397 string iter = tmp("_iter");
2398 out <<
2399 indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl <<
2400 indent() << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl;
2401 scope_up(out);
2402 if (ttype->is_map()) {
2403 generate_serialize_map_element(out, (t_map*)ttype, iter);
2404 } else if (ttype->is_set()) {
2405 generate_serialize_set_element(out, (t_set*)ttype, iter);
2406 } else if (ttype->is_list()) {
2407 generate_serialize_list_element(out, (t_list*)ttype, iter);
2409 scope_down(out);
2411 if (ttype->is_map()) {
2412 indent(out) <<
2413 "xfer += oprot->writeMapEnd();" << endl;
2414 } else if (ttype->is_set()) {
2415 indent(out) <<
2416 "xfer += oprot->writeSetEnd();" << endl;
2417 } else if (ttype->is_list()) {
2418 indent(out) <<
2419 "xfer += oprot->writeListEnd();" << endl;
2422 scope_down(out);
2426 * Serializes the members of a map.
2429 void t_cpp_generator::generate_serialize_map_element(ofstream& out,
2430 t_map* tmap,
2431 string iter) {
2432 t_field kfield(tmap->get_key_type(), iter + "->first");
2433 generate_serialize_field(out, &kfield, "");
2435 t_field vfield(tmap->get_val_type(), iter + "->second");
2436 generate_serialize_field(out, &vfield, "");
2440 * Serializes the members of a set.
2442 void t_cpp_generator::generate_serialize_set_element(ofstream& out,
2443 t_set* tset,
2444 string iter) {
2445 t_field efield(tset->get_elem_type(), "(*" + iter + ")");
2446 generate_serialize_field(out, &efield, "");
2450 * Serializes the members of a list.
2452 void t_cpp_generator::generate_serialize_list_element(ofstream& out,
2453 t_list* tlist,
2454 string iter) {
2455 t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
2456 generate_serialize_field(out, &efield, "");
2460 * Makes a :: prefix for a namespace
2462 * @param ns The namepsace, w/ periods in it
2463 * @return Namespaces
2465 string t_cpp_generator::namespace_prefix(string ns) {
2466 if (ns.size() == 0) {
2467 return "";
2469 string result = "";
2470 string::size_type loc;
2471 while ((loc = ns.find(".")) != string::npos) {
2472 result += ns.substr(0, loc);
2473 result += "::";
2474 ns = ns.substr(loc+1);
2476 if (ns.size() > 0) {
2477 result += ns + "::";
2479 return result;
2483 * Opens namespace.
2485 * @param ns The namepsace, w/ periods in it
2486 * @return Namespaces
2488 string t_cpp_generator::namespace_open(string ns) {
2489 if (ns.size() == 0) {
2490 return "";
2492 string result = "";
2493 string separator = "";
2494 string::size_type loc;
2495 while ((loc = ns.find(".")) != string::npos) {
2496 result += separator;
2497 result += "namespace ";
2498 result += ns.substr(0, loc);
2499 result += " {";
2500 separator = " ";
2501 ns = ns.substr(loc+1);
2503 if (ns.size() > 0) {
2504 result += separator + "namespace " + ns + " {";
2506 return result;
2510 * Closes namespace.
2512 * @param ns The namepsace, w/ periods in it
2513 * @return Namespaces
2515 string t_cpp_generator::namespace_close(string ns) {
2516 if (ns.size() == 0) {
2517 return "";
2519 string result = "}";
2520 string::size_type loc;
2521 while ((loc = ns.find(".")) != string::npos) {
2522 result += "}";
2523 ns = ns.substr(loc+1);
2525 result += " // namespace";
2526 return result;
2530 * Returns a C++ type name
2532 * @param ttype The type
2533 * @return String of the type name, i.e. std::set<type>
2535 string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
2536 if (ttype->is_base_type()) {
2537 string bname = base_type_name(((t_base_type*)ttype)->get_base());
2538 if (!arg) {
2539 return bname;
2542 if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) {
2543 return "const " + bname + "&";
2544 } else {
2545 return "const " + bname;
2549 // Check for a custom overloaded C++ name
2550 if (ttype->is_container()) {
2551 string cname;
2553 t_container* tcontainer = (t_container*) ttype;
2554 if (tcontainer->has_cpp_name()) {
2555 cname = tcontainer->get_cpp_name();
2556 } else if (ttype->is_map()) {
2557 t_map* tmap = (t_map*) ttype;
2558 cname = "std::map<" +
2559 type_name(tmap->get_key_type(), in_typedef) + ", " +
2560 type_name(tmap->get_val_type(), in_typedef) + "> ";
2561 } else if (ttype->is_set()) {
2562 t_set* tset = (t_set*) ttype;
2563 cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> ";
2564 } else if (ttype->is_list()) {
2565 t_list* tlist = (t_list*) ttype;
2566 cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
2569 if (arg) {
2570 return "const " + cname + "&";
2571 } else {
2572 return cname;
2576 string class_prefix;
2577 if (in_typedef && (ttype->is_struct() || ttype->is_xception())) {
2578 class_prefix = "class ";
2581 // Check if it needs to be namespaced
2582 string pname;
2583 t_program* program = ttype->get_program();
2584 if (program != NULL && program != program_) {
2585 pname =
2586 class_prefix +
2587 namespace_prefix(program->get_cpp_namespace()) +
2588 ttype->get_name();
2589 } else {
2590 pname = class_prefix + ttype->get_name();
2593 if (arg) {
2594 if (is_complex_type(ttype)) {
2595 return "const " + pname + "&";
2596 } else {
2597 return "const " + pname;
2599 } else {
2600 return pname;
2605 * Returns the C++ type that corresponds to the thrift type.
2607 * @param tbase The base type
2608 * @return Explicit C++ type, i.e. "int32_t"
2610 string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
2611 switch (tbase) {
2612 case t_base_type::TYPE_VOID:
2613 return "void";
2614 case t_base_type::TYPE_STRING:
2615 return "std::string";
2616 case t_base_type::TYPE_BOOL:
2617 return "bool";
2618 case t_base_type::TYPE_BYTE:
2619 return "int8_t";
2620 case t_base_type::TYPE_I16:
2621 return "int16_t";
2622 case t_base_type::TYPE_I32:
2623 return "int32_t";
2624 case t_base_type::TYPE_I64:
2625 return "int64_t";
2626 case t_base_type::TYPE_DOUBLE:
2627 return "double";
2628 default:
2629 throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
2634 * Declares a field, which may include initialization as necessary.
2636 * @param ttype The type
2637 * @return Field declaration, i.e. int x = 0;
2639 string t_cpp_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant) {
2640 // TODO(mcslee): do we ever need to initialize the field?
2641 string result = "";
2642 if (constant) {
2643 result += "const ";
2645 result += type_name(tfield->get_type());
2646 if (pointer) {
2647 result += "*";
2649 result += " " + tfield->get_name();
2650 if (init) {
2651 t_type* type = get_true_type(tfield->get_type());
2653 if (type->is_base_type()) {
2654 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2655 switch (tbase) {
2656 case t_base_type::TYPE_VOID:
2657 break;
2658 case t_base_type::TYPE_STRING:
2659 result += " = \"\"";
2660 break;
2661 case t_base_type::TYPE_BOOL:
2662 result += " = false";
2663 break;
2664 case t_base_type::TYPE_BYTE:
2665 case t_base_type::TYPE_I16:
2666 case t_base_type::TYPE_I32:
2667 case t_base_type::TYPE_I64:
2668 result += " = 0";
2669 break;
2670 case t_base_type::TYPE_DOUBLE:
2671 result += " = (double)0";
2672 break;
2673 default:
2674 throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase);
2676 } else if (type->is_enum()) {
2677 result += " = (" + type_name(type) + ")0";
2680 return result + ";";
2684 * Renders a function signature of the form 'type name(args)'
2686 * @param tfunction Function definition
2687 * @return String of rendered function definition
2689 string t_cpp_generator::function_signature(t_function* tfunction,
2690 string prefix) {
2691 t_type* ttype = tfunction->get_returntype();
2692 t_struct* arglist = tfunction->get_arglist();
2694 if (is_complex_type(ttype)) {
2695 bool empty = arglist->get_members().size() == 0;
2696 return
2697 "void " + prefix + tfunction->get_name() +
2698 "(" + type_name(ttype) + "& _return" +
2699 (empty ? "" : (", " + argument_list(arglist))) + ")";
2700 } else {
2701 return
2702 type_name(ttype) + " " + prefix + tfunction->get_name() +
2703 "(" + argument_list(arglist) + ")";
2708 * Renders a field list
2710 * @param tstruct The struct definition
2711 * @return Comma sepearated list of all field names in that struct
2713 string t_cpp_generator::argument_list(t_struct* tstruct) {
2714 string result = "";
2716 const vector<t_field*>& fields = tstruct->get_members();
2717 vector<t_field*>::const_iterator f_iter;
2718 bool first = true;
2719 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2720 if (first) {
2721 first = false;
2722 } else {
2723 result += ", ";
2725 result += type_name((*f_iter)->get_type(), false, true) + " " + (*f_iter)->get_name();
2727 return result;
2731 * Converts the parse type to a C++ enum string for the given type.
2733 * @param type Thrift Type
2734 * @return String of C++ code to definition of that type constant
2736 string t_cpp_generator::type_to_enum(t_type* type) {
2737 type = get_true_type(type);
2739 if (type->is_base_type()) {
2740 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2741 switch (tbase) {
2742 case t_base_type::TYPE_VOID:
2743 throw "NO T_VOID CONSTRUCT";
2744 case t_base_type::TYPE_STRING:
2745 return "facebook::thrift::protocol::T_STRING";
2746 case t_base_type::TYPE_BOOL:
2747 return "facebook::thrift::protocol::T_BOOL";
2748 case t_base_type::TYPE_BYTE:
2749 return "facebook::thrift::protocol::T_BYTE";
2750 case t_base_type::TYPE_I16:
2751 return "facebook::thrift::protocol::T_I16";
2752 case t_base_type::TYPE_I32:
2753 return "facebook::thrift::protocol::T_I32";
2754 case t_base_type::TYPE_I64:
2755 return "facebook::thrift::protocol::T_I64";
2756 case t_base_type::TYPE_DOUBLE:
2757 return "facebook::thrift::protocol::T_DOUBLE";
2759 } else if (type->is_enum()) {
2760 return "facebook::thrift::protocol::T_I32";
2761 } else if (type->is_struct()) {
2762 return "facebook::thrift::protocol::T_STRUCT";
2763 } else if (type->is_xception()) {
2764 return "facebook::thrift::protocol::T_STRUCT";
2765 } else if (type->is_map()) {
2766 return "facebook::thrift::protocol::T_MAP";
2767 } else if (type->is_set()) {
2768 return "facebook::thrift::protocol::T_SET";
2769 } else if (type->is_list()) {
2770 return "facebook::thrift::protocol::T_LIST";
2773 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2777 * Returns the symbol name of the local reflection of a type.
2779 string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype) {
2780 ttype = get_true_type(ttype);
2782 // We have to use the program name as part of the identifier because
2783 // if two thrift "programs" are compiled into one actual program
2784 // you would get a symbol collison if they both defined list<i32>.
2785 // trlo = Thrift Reflection LOcal.
2786 string prog;
2787 string name;
2789 // TODO(dreiss): Would it be better to pregenerate the base types
2790 // and put them in Thrift.{h,cpp} ?
2792 if (ttype->is_base_type()) {
2793 //name = ttype->get_name();
2794 prog = program_->get_name();
2795 name = ttype->get_ascii_fingerprint();
2796 } else if (ttype->is_enum()) {
2797 //name = "enum";
2798 prog = program_->get_name();
2799 name = ttype->get_ascii_fingerprint();
2800 } else if (ttype->is_container()) {
2801 prog = program_->get_name();
2802 name = ttype->get_ascii_fingerprint();
2803 } else {
2804 assert(ttype->is_struct() || ttype->is_xception());
2805 assert(ttype->get_program() != NULL);
2806 prog = ttype->get_program()->get_name();
2807 name = ttype->get_ascii_fingerprint();
2810 return string() + "trlo_" + prefix + "_" + prog + "_" + name;