r1192@dev030 (orig r59869): dweatherford | 2007-09-15 01:49:48 -0700
[amiethrift.git] / compiler / cpp / src / generate / t_cpp_generator.cc
bloba92be52f9db66c2d5b4cddf5398c7a43bad6da48
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_local_reflection_pointer(f_types_impl_, tstruct);
365 generate_struct_reader(f_types_impl_, tstruct);
366 generate_struct_writer(f_types_impl_, tstruct);
370 * Writes the struct definition into the header file
372 * @param out Output stream
373 * @param tstruct The struct
375 void t_cpp_generator::generate_struct_definition(ofstream& out,
376 t_struct* tstruct,
377 bool is_exception,
378 bool pointers,
379 bool read,
380 bool write) {
381 string extends = "";
382 if (is_exception) {
383 extends = " : public facebook::thrift::TException";
386 // Open struct def
387 out <<
388 indent() << "class " << tstruct->get_name() << extends << " {" << endl <<
389 indent() << " public:" << endl <<
390 endl;
391 indent_up();
393 // Put the fingerprint up top for all to see.
394 generate_struct_fingerprint(out, tstruct, false);
396 // Get members
397 vector<t_field*>::const_iterator m_iter;
398 const vector<t_field*>& members = tstruct->get_members();
400 if (!pointers) {
401 // Default constructor
402 indent(out) <<
403 tstruct->get_name() << "()";
405 bool init_ctor = false;
407 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
408 t_type* t = get_true_type((*m_iter)->get_type());
409 if (t->is_base_type()) {
410 string dval;
411 if (t->is_enum()) {
412 dval += "(" + t->get_name() + ")";
414 dval += t->is_string() ? "\"\"" : "0";
415 t_const_value* cv = (*m_iter)->get_value();
416 if (cv != NULL) {
417 dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
419 if (!init_ctor) {
420 init_ctor = true;
421 out << " : ";
422 out << (*m_iter)->get_name() << "(" << dval << ")";
423 } else {
424 out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
428 out << " {" << endl;
429 indent_up();
430 // TODO(dreiss): When everything else in Thrift is perfect,
431 // do more of these in the initializer list.
432 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
433 t_type* t = get_true_type((*m_iter)->get_type());
435 if (!t->is_base_type()) {
436 t_const_value* cv = (*m_iter)->get_value();
437 if (cv != NULL) {
438 print_const_value(out, (*m_iter)->get_name(), t, cv);
442 scope_down(out);
445 out <<
446 endl <<
447 indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
449 // Pointer to this structure's reflection local typespec.
450 if (gen_dense_) {
451 indent(out) <<
452 "static facebook::thrift::reflection::local::TypeSpec* local_reflection;" <<
453 endl << endl;
456 // Declare all fields
457 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
458 indent(out) <<
459 declare_field(*m_iter, false, pointers && !(*m_iter)->get_type()->is_xception(), !read) << endl;
462 // Isset struct has boolean fields, but only for non-required fields.
463 bool has_nonrequired_fields = false;
464 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
465 if ((*m_iter)->get_req() != t_field::REQUIRED)
466 has_nonrequired_fields = true;
469 if (has_nonrequired_fields && (!pointers || read)) {
470 out <<
471 endl <<
472 indent() << "struct __isset {" << endl;
473 indent_up();
475 indent(out) <<
476 "__isset() : ";
477 bool first = true;
478 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
479 if ((*m_iter)->get_req() == t_field::REQUIRED) {
480 continue;
482 if (first) {
483 first = false;
484 out <<
485 (*m_iter)->get_name() << "(false)";
486 } else {
487 out <<
488 ", " << (*m_iter)->get_name() << "(false)";
491 out << " {}" << endl;
493 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
494 if ((*m_iter)->get_req() != t_field::REQUIRED) {
495 indent(out) <<
496 "bool " << (*m_iter)->get_name() << ";" << endl;
500 indent_down();
501 indent(out) <<
502 "} __isset;" << endl;
505 out << endl;
507 if (!pointers) {
508 // Generate an equality testing operator. Make it inline since the compiler
509 // will do a better job than we would when deciding whether to inline it.
510 out <<
511 indent() << "bool operator == (const " << tstruct->get_name() << " & rhs) const" << endl;
512 scope_up(out);
513 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
514 // Most existing Thrift code does not use isset or optional/required,
515 // so we treat "default" fields as required.
516 if ((*m_iter)->get_req() != t_field::OPTIONAL) {
517 out <<
518 indent() << "if (!(" << (*m_iter)->get_name()
519 << " == rhs." << (*m_iter)->get_name() << "))" << endl <<
520 indent() << " return false;" << endl;
521 } else {
522 out <<
523 indent() << "if (__isset." << (*m_iter)->get_name()
524 << " != rhs.__isset." << (*m_iter)->get_name() << ")" << endl <<
525 indent() << " return false;" << endl <<
526 indent() << "else if (__isset." << (*m_iter)->get_name() << " && !("
527 << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name()
528 << "))" << endl <<
529 indent() << " return false;" << endl;
532 indent(out) << "return true;" << endl;
533 scope_down(out);
534 out <<
535 indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" << endl <<
536 indent() << " return !(*this == rhs);" << endl <<
537 indent() << "}" << endl << endl;
539 if (read) {
540 out <<
541 indent() << "uint32_t read(facebook::thrift::protocol::TProtocol* iprot);" << endl;
543 if (write) {
544 out <<
545 indent() << "uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const;" << endl;
547 out << endl;
549 indent_down();
550 indent(out) <<
551 "};" << endl <<
552 endl;
556 * Writes the fingerprint of a struct to either the header or implementation.
558 * @param out Output stream
559 * @param tstruct The struct
561 void t_cpp_generator::generate_struct_fingerprint(ofstream& out,
562 t_struct* tstruct,
563 bool is_definition) {
564 string stat, nspace, comment;
565 if (is_definition) {
566 stat = "";
567 nspace = tstruct->get_name() + "::";
568 comment = " ";
569 } else {
570 stat = "static ";
571 nspace = "";
572 comment = "; // ";
575 if (tstruct->has_fingerprint()) {
576 out <<
577 indent() << stat << "char* " << nspace
578 << "ascii_fingerprint" << comment << "= \"" <<
579 tstruct->get_ascii_fingerprint() << "\";" << endl <<
580 indent() << stat << "uint8_t " << nspace <<
581 "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {";
582 char* comma = "";
583 for (int i = 0; i < t_type::fingerprint_len; i++) {
584 out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]);
585 comma = ",";
587 out << "};" << endl << endl;
592 * Writes the local reflection of a type (either declaration or definition).
594 void t_cpp_generator::generate_local_reflection(std::ofstream& out,
595 t_type* ttype,
596 bool is_definition) {
597 if (!gen_dense_) {
598 return;
600 ttype = get_true_type(ttype);
601 assert(ttype->has_fingerprint());
602 string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl");
603 // Note that we have generated this fingerprint. If we already did, bail out.
604 if (!reflected_fingerprints_.insert(key).second) {
605 return;
607 // Let each program handle its own structures.
608 if (ttype->get_program() != NULL && ttype->get_program() != program_) {
609 return;
612 // Do dependencies.
613 if (ttype->is_list()) {
614 generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition);
615 } else if (ttype->is_set()) {
616 generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition);
617 } else if (ttype->is_map()) {
618 generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition);
619 generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition);
620 } else if (ttype->is_struct() || ttype->is_xception()) {
621 // Hacky hacky. For efficiency and convenience, we need a dummy "T_STOP"
622 // type at the end of our typespec array. Unfortunately, there is no
623 // T_STOP type, so we use the global void type, and special case it when
624 // generating its typespec.
626 const vector<t_field*>& members = ((t_struct*)ttype)->get_members();
627 vector<t_field*>::const_iterator m_iter;
628 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
629 generate_local_reflection(out, (**m_iter).get_type(), is_definition);
631 generate_local_reflection(out, g_type_void, is_definition);
633 // For definitions of structures, do the arrays of metas and field specs also.
634 if (is_definition) {
635 out <<
636 indent() << "facebook::thrift::reflection::local::FieldMeta" << endl <<
637 indent() << local_reflection_name("metas", ttype) <<"[] = {" << endl;
638 indent_up();
639 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
640 indent(out) << "{ " << (*m_iter)->get_key() << ", " <<
641 (((*m_iter)->get_req() == t_field::OPTIONAL) ? "true" : "false") <<
642 " }," << endl;
644 // Zero for the T_STOP marker.
645 indent(out) << "{ 0, false }" << endl << "};" << endl;
646 indent_down();
648 out <<
649 indent() << "facebook::thrift::reflection::local::TypeSpec*" << endl <<
650 indent() << local_reflection_name("specs", ttype) <<"[] = {" << endl;
651 indent_up();
652 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
653 indent(out) << "&" <<
654 local_reflection_name("typespec", (*m_iter)->get_type()) << "," << endl;
656 indent(out) << "&" <<
657 local_reflection_name("typespec", g_type_void) << "," << endl;
658 indent_down();
659 indent(out) << "};" << endl;
663 out <<
664 indent() << "// " << ttype->get_fingerprint_material() << endl <<
665 indent() << (is_definition ? "" : "extern ") <<
666 "facebook::thrift::reflection::local::TypeSpec" << endl <<
667 local_reflection_name("typespec", ttype) <<
668 (is_definition ? "(" : ";") << endl;
670 if (!is_definition) {
671 out << endl;
672 return;
675 indent_up();
677 if (ttype->is_void()) {
678 indent(out) << "facebook::thrift::protocol::T_STOP";
679 } else {
680 indent(out) << type_to_enum(ttype);
683 if (ttype->is_struct()) {
684 out << "," << endl <<
685 indent() << type_name(ttype) << "::binary_fingerprint," << endl <<
686 indent() << local_reflection_name("metas", ttype) << "," << endl <<
687 indent() << local_reflection_name("specs", ttype);
688 } else if (ttype->is_list()) {
689 out << "," << endl <<
690 indent() << "&" << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type()) << "," << endl <<
691 indent() << "NULL";
692 } else if (ttype->is_set()) {
693 out << "," << endl <<
694 indent() << "&" << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type()) << "," << endl <<
695 indent() << "NULL";
696 } else if (ttype->is_map()) {
697 out << "," << endl <<
698 indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type()) << "," << endl <<
699 indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type());
702 out << ");" << endl << endl;
704 indent_down();
708 * Writes the structure's static pointer to its local reflection typespec
709 * into the implementation file.
711 void t_cpp_generator::generate_local_reflection_pointer(std::ofstream& out,
712 t_type* ttype) {
713 if (!gen_dense_) {
714 return;
716 indent(out) <<
717 "facebook::thrift::reflection::local::TypeSpec* " <<
718 ttype->get_name() << "::local_reflection = " << endl <<
719 indent() << " &" << local_reflection_name("typespec", ttype) << ";" <<
720 endl << endl;
724 * Makes a helper function to gen a struct reader.
726 * @param out Stream to write to
727 * @param tstruct The struct
729 void t_cpp_generator::generate_struct_reader(ofstream& out,
730 t_struct* tstruct,
731 bool pointers) {
732 indent(out) <<
733 "uint32_t " << tstruct->get_name() << "::read(facebook::thrift::protocol::TProtocol* iprot) {" << endl;
734 indent_up();
736 const vector<t_field*>& fields = tstruct->get_members();
737 vector<t_field*>::const_iterator f_iter;
739 // Declare stack tmp variables
740 out <<
741 endl <<
742 indent() << "uint32_t xfer = 0;" << endl <<
743 indent() << "std::string fname;" << endl <<
744 indent() << "facebook::thrift::protocol::TType ftype;" << endl <<
745 indent() << "int16_t fid;" << endl <<
746 endl <<
747 indent() << "xfer += iprot->readStructBegin(fname);" << endl <<
748 endl <<
749 indent() << "using facebook::thrift::protocol::TProtocolException;" << endl <<
750 endl;
752 // Required variables aren't in __isset, so we need tmp vars to check them.
753 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
754 if ((*f_iter)->get_req() == t_field::REQUIRED)
755 indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
757 out << endl;
760 // Loop over reading in fields
761 indent(out) <<
762 "while (true)" << endl;
763 scope_up(out);
765 // Read beginning field marker
766 indent(out) <<
767 "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
769 // Check for field STOP marker
770 out <<
771 indent() << "if (ftype == facebook::thrift::protocol::T_STOP) {" << endl <<
772 indent() << " break;" << endl <<
773 indent() << "}" << endl;
775 // Switch statement on the field we are reading
776 indent(out) <<
777 "switch (fid)" << endl;
779 scope_up(out);
781 // Generate deserialization code for known cases
782 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
783 indent(out) <<
784 "case " << (*f_iter)->get_key() << ":" << endl;
785 indent_up();
786 indent(out) <<
787 "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
788 indent_up();
790 const char *isset_prefix =
791 ((*f_iter)->get_req() != t_field::REQUIRED) ? "this->__isset." : "isset_";
793 #if 0
794 // This code throws an exception if the same field is encountered twice.
795 // We've decided to leave it out for performance reasons.
796 // TODO(dreiss): Generate this code and "if" it out to make it easier
797 // for people recompiling thrift to include it.
798 out <<
799 indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl <<
800 indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
801 #endif
803 if (pointers && !(*f_iter)->get_type()->is_xception()) {
804 generate_deserialize_field(out, *f_iter, "(*(this->", "))");
805 } else {
806 generate_deserialize_field(out, *f_iter, "this->");
808 out <<
809 indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl;
810 indent_down();
811 out <<
812 indent() << "} else {" << endl <<
813 indent() << " xfer += iprot->skip(ftype);" << endl <<
814 // TODO(dreiss): Make this an option when thrift structs
815 // have a common base class.
816 // indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl <<
817 indent() << "}" << endl <<
818 indent() << "break;" << endl;
819 indent_down();
822 // In the default case we skip the field
823 out <<
824 indent() << "default:" << endl <<
825 indent() << " xfer += iprot->skip(ftype);" << endl <<
826 indent() << " break;" << endl;
828 scope_down(out);
830 // Read field end marker
831 indent(out) <<
832 "xfer += iprot->readFieldEnd();" << endl;
834 scope_down(out);
836 out <<
837 endl <<
838 indent() << "xfer += iprot->readStructEnd();" << endl;
840 // Throw if any required fields are missing.
841 // We do this after reading the struct end so that
842 // there might possibly be a chance of continuing.
843 out << endl;
844 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
845 if ((*f_iter)->get_req() == t_field::REQUIRED)
846 out <<
847 indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
848 indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
851 indent(out) << "return xfer;" << endl;
853 indent_down();
854 indent(out) <<
855 "}" << endl << endl;
859 * Generates the write function.
861 * @param out Stream to write to
862 * @param tstruct The struct
864 void t_cpp_generator::generate_struct_writer(ofstream& out,
865 t_struct* tstruct,
866 bool pointers) {
867 string name = tstruct->get_name();
868 const vector<t_field*>& fields = tstruct->get_members();
869 vector<t_field*>::const_iterator f_iter;
871 indent(out) <<
872 "uint32_t " << tstruct->get_name() << "::write(facebook::thrift::protocol::TProtocol* oprot) const {" << endl;
873 indent_up();
875 out <<
876 indent() << "uint32_t xfer = 0;" << endl;
878 indent(out) <<
879 "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
880 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
881 if ((*f_iter)->get_req() == t_field::OPTIONAL) {
882 indent(out) << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
883 indent_up();
885 // Write field header
886 out <<
887 indent() << "xfer += oprot->writeFieldBegin(" <<
888 "\"" << (*f_iter)->get_name() << "\", " <<
889 type_to_enum((*f_iter)->get_type()) << ", " <<
890 (*f_iter)->get_key() << ");" << endl;
891 // Write field contents
892 if (pointers) {
893 generate_serialize_field(out, *f_iter, "(*(this->", "))");
894 } else {
895 generate_serialize_field(out, *f_iter, "this->");
897 // Write field closer
898 indent(out) <<
899 "xfer += oprot->writeFieldEnd();" << endl;
900 if ((*f_iter)->get_req() == t_field::OPTIONAL) {
901 indent_down();
902 indent(out) << '}' << endl;
906 // Write the struct map
907 out <<
908 indent() << "xfer += oprot->writeFieldStop();" << endl <<
909 indent() << "xfer += oprot->writeStructEnd();" << endl <<
910 indent() << "return xfer;" << endl;
912 indent_down();
913 indent(out) <<
914 "}" << endl <<
915 endl;
919 * Struct writer for result of a function, which can have only one of its
920 * fields set and does a conditional if else look up into the __isset field
921 * of the struct.
923 * @param out Output stream
924 * @param tstruct The result struct
926 void t_cpp_generator::generate_struct_result_writer(ofstream& out,
927 t_struct* tstruct,
928 bool pointers) {
929 string name = tstruct->get_name();
930 const vector<t_field*>& fields = tstruct->get_members();
931 vector<t_field*>::const_iterator f_iter;
933 indent(out) <<
934 "uint32_t " << tstruct->get_name() << "::write(facebook::thrift::protocol::TProtocol* oprot) const {" << endl;
935 indent_up();
937 out <<
938 endl <<
939 indent() << "uint32_t xfer = 0;" << endl <<
940 endl;
942 indent(out) <<
943 "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
945 bool first = true;
946 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
947 if (first) {
948 first = false;
949 out <<
950 endl <<
951 indent() << "if ";
952 } else {
953 out <<
954 " else if ";
957 out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
959 indent_up();
961 // Write field header
962 out <<
963 indent() << "xfer += oprot->writeFieldBegin(" <<
964 "\"" << (*f_iter)->get_name() << "\", " <<
965 type_to_enum((*f_iter)->get_type()) << ", " <<
966 (*f_iter)->get_key() << ");" << endl;
967 // Write field contents
968 if (pointers) {
969 generate_serialize_field(out, *f_iter, "(*(this->", "))");
970 } else {
971 generate_serialize_field(out, *f_iter, "this->");
973 // Write field closer
974 indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
976 indent_down();
977 indent(out) << "}";
980 // Write the struct map
981 out <<
982 endl <<
983 indent() << "xfer += oprot->writeFieldStop();" << endl <<
984 indent() << "xfer += oprot->writeStructEnd();" << endl <<
985 indent() << "return xfer;" << endl;
987 indent_down();
988 indent(out) <<
989 "}" << endl <<
990 endl;
994 * Generates a thrift service. In C++, this comprises an entirely separate
995 * header and source file. The header file defines the methods and includes
996 * the data types defined in the main header file, and the implementation
997 * file contains implementations of the basic printer and default interfaces.
999 * @param tservice The service definition
1001 void t_cpp_generator::generate_service(t_service* tservice) {
1002 string svcname = tservice->get_name();
1004 // Make output files
1005 string f_header_name = string(T_CPP_DIR)+"/"+svcname+".h";
1006 f_header_.open(f_header_name.c_str());
1008 // Print header file includes
1009 f_header_ <<
1010 autogen_comment();
1011 f_header_ <<
1012 "#ifndef " << svcname << "_H" << endl <<
1013 "#define " << svcname << "_H" << endl <<
1014 endl <<
1015 "#include <TProcessor.h>" << endl <<
1016 "#include \"" << program_name_ << "_types.h\"" << endl;
1018 if (tservice->get_extends() != NULL) {
1019 f_header_ <<
1020 "#include \"" << tservice->get_extends()->get_name() << ".h\"" << endl;
1023 f_header_ <<
1024 endl <<
1025 ns_open_ << endl <<
1026 endl;
1028 // Service implementation file includes
1029 string f_service_name = string(T_CPP_DIR)+"/"+svcname+".cpp";
1030 f_service_.open(f_service_name.c_str());
1031 f_service_ <<
1032 autogen_comment();
1033 f_service_ <<
1034 "#include \"" << svcname << ".h\"" << endl <<
1035 endl <<
1036 ns_open_ << endl <<
1037 endl;
1039 // Generate all the components
1040 generate_service_interface(tservice);
1041 generate_service_null(tservice);
1042 generate_service_helpers(tservice);
1043 generate_service_client(tservice);
1044 generate_service_processor(tservice);
1045 generate_service_multiface(tservice);
1046 generate_service_skeleton(tservice);
1048 // Close the namespace
1049 f_service_ <<
1050 ns_close_ << endl <<
1051 endl;
1052 f_header_ <<
1053 ns_close_ << endl <<
1054 endl;
1055 f_header_ <<
1056 "#endif" << endl;
1058 // Close the files
1059 f_service_.close();
1060 f_header_.close();
1064 * Generates helper functions for a service. Basically, this generates types
1065 * for all the arguments and results to functions.
1067 * @param tservice The service to generate a header definition for
1069 void t_cpp_generator::generate_service_helpers(t_service* tservice) {
1070 vector<t_function*> functions = tservice->get_functions();
1071 vector<t_function*>::iterator f_iter;
1072 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1073 t_struct* ts = (*f_iter)->get_arglist();
1074 string name_orig = ts->get_name();
1076 ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
1077 generate_struct_definition(f_header_, ts, false);
1078 generate_struct_reader(f_service_, ts);
1079 generate_struct_writer(f_service_, ts);
1080 ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
1081 generate_struct_definition(f_header_, ts, false, true, false, true);
1082 generate_struct_writer(f_service_, ts, true);
1083 ts->set_name(name_orig);
1085 generate_function_helpers(tservice, *f_iter);
1088 generate_service_limited_reflector(tservice);
1092 * Generates a service interface definition.
1094 * @param tservice The service to generate a header definition for
1096 void t_cpp_generator::generate_service_interface(t_service* tservice) {
1097 string extends = "";
1098 if (tservice->get_extends() != NULL) {
1099 extends = " : virtual public " + type_name(tservice->get_extends()) + "If";
1101 f_header_ <<
1102 "class " << service_name_ << "If" << extends << " {" << endl <<
1103 " public:" << endl;
1104 indent_up();
1105 f_header_ <<
1106 indent() << "virtual ~" << service_name_ << "If() {}" << endl;
1108 f_header_ <<
1109 indent() << "static void getStaticLimitedReflection" <<
1110 "(facebook::thrift::reflection::limited::Service & _return);" << endl;
1111 // TODO(dreiss): Uncomment and test this if we decide we need
1112 // a virtual function with this effect.
1113 //f_header_ <<
1114 // indent() << "virtual void getVirtualLimitedReflection" <<
1115 // "(facebook::thrift::reflection::limited::Service & _return) ";
1116 //scope_up(f_header_);
1117 //f_header_ <<
1118 // indent() << "getStaticLimitedReflection(_return);" << endl;
1119 //scope_down(f_header_);
1121 vector<t_function*> functions = tservice->get_functions();
1122 vector<t_function*>::iterator f_iter;
1123 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1124 f_header_ <<
1125 indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
1127 indent_down();
1128 f_header_ <<
1129 "};" << endl << endl;
1133 * Generates a null implementation of the service.
1135 * @param tservice The service to generate a header definition for
1137 void t_cpp_generator::generate_service_null(t_service* tservice) {
1138 string extends = "";
1139 if (tservice->get_extends() != NULL) {
1140 extends = " , virtual public " + type_name(tservice->get_extends()) + "Null";
1142 f_header_ <<
1143 "class " << service_name_ << "Null : virtual public " << service_name_ << "If" << extends << " {" << endl <<
1144 " public:" << endl;
1145 indent_up();
1146 f_header_ <<
1147 indent() << "virtual ~" << service_name_ << "Null() {}" << endl;
1148 vector<t_function*> functions = tservice->get_functions();
1149 vector<t_function*>::iterator f_iter;
1150 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1151 f_header_ <<
1152 indent() << function_signature(*f_iter) << " {" << endl;
1153 indent_up();
1154 t_type* returntype = (*f_iter)->get_returntype();
1155 if (returntype->is_void()) {
1156 f_header_ <<
1157 indent() << "return;" << endl;
1158 } else {
1159 if (is_complex_type(returntype)) {
1160 f_header_ <<
1161 indent() << "return;" << endl;
1162 } else {
1163 t_field returnfield(returntype, "_return");
1164 f_header_ <<
1165 indent() << declare_field(&returnfield, true) << endl <<
1166 indent() << "return _return;" << endl;
1169 indent_down();
1170 f_header_ <<
1171 indent() << "}" << endl;
1173 indent_down();
1174 f_header_ <<
1175 "};" << endl << endl;
1180 * Generates a multiface, which is a single server that just takes a set
1181 * of objects implementing the interface and calls them all, returning the
1182 * value of the last one to be called.
1184 * @param tservice The service to generate a multiserver for.
1186 void t_cpp_generator::generate_service_multiface(t_service* tservice) {
1187 // Generate the dispatch methods
1188 vector<t_function*> functions = tservice->get_functions();
1189 vector<t_function*>::iterator f_iter;
1191 string extends = "";
1192 string extends_multiface = "";
1193 if (tservice->get_extends() != NULL) {
1194 extends = type_name(tservice->get_extends());
1195 extends_multiface = ", public " + extends + "Multiface";
1198 string list_type = string("std::vector<boost::shared_ptr<") + service_name_ + "If> >";
1200 // Generate the header portion
1201 f_header_ <<
1202 "class " << service_name_ << "Multiface : " <<
1203 "virtual public " << service_name_ << "If" <<
1204 extends_multiface << " {" << endl <<
1205 " public:" << endl;
1206 indent_up();
1207 f_header_ <<
1208 indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
1209 if (!extends.empty()) {
1210 f_header_ <<
1211 indent() << " std::vector<boost::shared_ptr<" + service_name_ + "If> >::iterator iter;" << endl <<
1212 indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl <<
1213 indent() << " " << extends << "Multiface::add(*iter);" << endl <<
1214 indent() << " }" << endl;
1216 f_header_ <<
1217 indent() << "}" << endl <<
1218 indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl;
1219 indent_down();
1221 // Protected data members
1222 f_header_ <<
1223 " protected:" << endl;
1224 indent_up();
1225 f_header_ <<
1226 indent() << list_type << " ifaces_;" << endl <<
1227 indent() << service_name_ << "Multiface() {}" << endl <<
1228 indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) {" << endl;
1229 if (!extends.empty()) {
1230 f_header_ <<
1231 indent() << " " << extends << "Multiface::add(iface);" << endl;
1233 f_header_ <<
1234 indent() << " ifaces_.push_back(iface);" << endl <<
1235 indent() << "}" << endl;
1236 indent_down();
1238 f_header_ <<
1239 indent() << " public:" << endl;
1240 indent_up();
1242 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1243 t_struct* arglist = (*f_iter)->get_arglist();
1244 const vector<t_field*>& args = arglist->get_members();
1245 vector<t_field*>::const_iterator a_iter;
1247 string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
1248 bool first = true;
1249 if (is_complex_type((*f_iter)->get_returntype())) {
1250 call += "_return";
1251 first = false;
1253 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
1254 if (first) {
1255 first = false;
1256 } else {
1257 call += ", ";
1259 call += (*a_iter)->get_name();
1261 call += ")";
1263 f_header_ <<
1264 indent() << function_signature(*f_iter) << " {" << endl;
1265 indent_up();
1266 f_header_ <<
1267 indent() << "uint32_t sz = ifaces_.size();" << endl <<
1268 indent() << "for (uint32_t i = 0; i < sz; ++i) {" << endl;
1269 if (!(*f_iter)->get_returntype()->is_void()) {
1270 f_header_ <<
1271 indent() << " if (i == sz - 1) {" << endl;
1272 if (is_complex_type((*f_iter)->get_returntype())) {
1273 f_header_ <<
1274 indent() << " " << call << ";" << endl <<
1275 indent() << " return;" << endl;
1276 } else {
1277 f_header_ <<
1278 indent() << " return " << call << ";" << endl;
1280 f_header_ <<
1281 indent() << " } else {" << endl <<
1282 indent() << " " << call << ";" << endl <<
1283 indent() << " }" << endl;
1284 } else {
1285 f_header_ <<
1286 indent() << " " << call << ";" << endl;
1289 f_header_ <<
1290 indent() << "}" << endl;
1292 indent_down();
1293 f_header_ <<
1294 indent() << "}" << endl <<
1295 endl;
1298 indent_down();
1299 f_header_ <<
1300 indent() << "};" << endl <<
1301 endl;
1305 * Generates a service client definition.
1307 * @param tservice The service to generate a server for.
1309 void t_cpp_generator::generate_service_client(t_service* tservice) {
1310 string extends = "";
1311 string extends_client = "";
1312 if (tservice->get_extends() != NULL) {
1313 extends = type_name(tservice->get_extends());
1314 extends_client = ", public " + extends + "Client";
1317 // Generate the header portion
1318 f_header_ <<
1319 "class " << service_name_ << "Client : " <<
1320 "virtual public " << service_name_ << "If" <<
1321 extends_client << " {" << endl <<
1322 " public:" << endl;
1324 indent_up();
1325 f_header_ <<
1326 indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> prot) :" << endl;
1327 if (extends.empty()) {
1328 f_header_ <<
1329 indent() << " piprot_(prot)," << endl <<
1330 indent() << " poprot_(prot) {" << endl <<
1331 indent() << " iprot_ = prot.get();" << endl <<
1332 indent() << " oprot_ = prot.get();" << endl <<
1333 indent() << "}" << endl;
1334 } else {
1335 f_header_ <<
1336 indent() << " " << extends << "Client(prot, prot) {}" << endl;
1339 f_header_ <<
1340 indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) :" << endl;
1341 if (extends.empty()) {
1342 f_header_ <<
1343 indent() << " piprot_(iprot)," << endl <<
1344 indent() << " poprot_(oprot) {" << endl <<
1345 indent() << " iprot_ = iprot.get();" << endl <<
1346 indent() << " oprot_ = oprot.get();" << endl <<
1347 indent() << "}" << endl;
1348 } else {
1349 f_header_ <<
1350 indent() << " " << extends << "Client(iprot, oprot) {}" << endl;
1353 vector<t_function*> functions = tservice->get_functions();
1354 vector<t_function*>::const_iterator f_iter;
1355 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1356 t_function send_function(g_type_void,
1357 string("send_") + (*f_iter)->get_name(),
1358 (*f_iter)->get_arglist());
1359 indent(f_header_) << function_signature(*f_iter) << ";" << endl;
1360 indent(f_header_) << function_signature(&send_function) << ";" << endl;
1361 if (!(*f_iter)->is_async()) {
1362 t_struct noargs(program_);
1363 t_function recv_function((*f_iter)->get_returntype(),
1364 string("recv_") + (*f_iter)->get_name(),
1365 &noargs);
1366 indent(f_header_) << function_signature(&recv_function) << ";" << endl;
1369 indent_down();
1371 if (extends.empty()) {
1372 f_header_ <<
1373 " protected:" << endl;
1374 indent_up();
1375 f_header_ <<
1376 indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot_;" << endl <<
1377 indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot_;" << endl <<
1378 indent() << "facebook::thrift::protocol::TProtocol* iprot_;" << endl <<
1379 indent() << "facebook::thrift::protocol::TProtocol* oprot_;" << endl;
1380 indent_down();
1383 f_header_ <<
1384 "};" << endl <<
1385 endl;
1387 string scope = service_name_ + "Client::";
1389 // Generate client method implementations
1390 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1391 string funname = (*f_iter)->get_name();
1393 // Open function
1394 indent(f_service_) <<
1395 function_signature(*f_iter, scope) << endl;
1396 scope_up(f_service_);
1397 indent(f_service_) <<
1398 "send_" << funname << "(";
1400 // Get the struct of function call params
1401 t_struct* arg_struct = (*f_iter)->get_arglist();
1403 // Declare the function arguments
1404 const vector<t_field*>& fields = arg_struct->get_members();
1405 vector<t_field*>::const_iterator fld_iter;
1406 bool first = true;
1407 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1408 if (first) {
1409 first = false;
1410 } else {
1411 f_service_ << ", ";
1413 f_service_ << (*fld_iter)->get_name();
1415 f_service_ << ");" << endl;
1417 if (!(*f_iter)->is_async()) {
1418 f_service_ << indent();
1419 if (!(*f_iter)->get_returntype()->is_void()) {
1420 if (is_complex_type((*f_iter)->get_returntype())) {
1421 f_service_ << "recv_" << funname << "(_return);" << endl;
1422 } else {
1423 f_service_ << "return recv_" << funname << "();" << endl;
1425 } else {
1426 f_service_ <<
1427 "recv_" << funname << "();" << endl;
1430 scope_down(f_service_);
1431 f_service_ << endl;
1433 // Function for sending
1434 t_function send_function(g_type_void,
1435 string("send_") + (*f_iter)->get_name(),
1436 (*f_iter)->get_arglist());
1438 // Open the send function
1439 indent(f_service_) <<
1440 function_signature(&send_function, scope) << endl;
1441 scope_up(f_service_);
1443 // Function arguments and results
1444 string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs";
1445 string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult";
1447 // Serialize the request
1448 f_service_ <<
1449 indent() << "int32_t cseqid = 0;" << endl <<
1450 indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl <<
1451 endl <<
1452 indent() << argsname << " args;" << endl;
1454 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1455 f_service_ <<
1456 indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl;
1459 f_service_ <<
1460 indent() << "args.write(oprot_);" << endl <<
1461 endl <<
1462 indent() << "oprot_->writeMessageEnd();" << endl <<
1463 indent() << "oprot_->getTransport()->flush();" << endl <<
1464 indent() << "oprot_->getTransport()->writeEnd();" << endl;
1466 scope_down(f_service_);
1467 f_service_ << endl;
1469 // Generate recv function only if not an async function
1470 if (!(*f_iter)->is_async()) {
1471 t_struct noargs(program_);
1472 t_function recv_function((*f_iter)->get_returntype(),
1473 string("recv_") + (*f_iter)->get_name(),
1474 &noargs);
1475 // Open function
1476 indent(f_service_) <<
1477 function_signature(&recv_function, scope) << endl;
1478 scope_up(f_service_);
1480 f_service_ <<
1481 endl <<
1482 indent() << "int32_t rseqid = 0;" << endl <<
1483 indent() << "std::string fname;" << endl <<
1484 indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
1485 endl <<
1486 indent() << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl <<
1487 indent() << "if (mtype == facebook::thrift::protocol::T_EXCEPTION) {" << endl <<
1488 indent() << " facebook::thrift::TApplicationException x;" << endl <<
1489 indent() << " x.read(iprot_);" << endl <<
1490 indent() << " iprot_->readMessageEnd();" << endl <<
1491 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1492 indent() << " throw x;" << endl <<
1493 indent() << "}" << endl <<
1494 indent() << "if (mtype != facebook::thrift::protocol::T_REPLY) {" << endl <<
1495 indent() << " iprot_->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1496 indent() << " iprot_->readMessageEnd();" << endl <<
1497 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1498 indent() << " throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1499 indent() << "}" << endl <<
1500 indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl <<
1501 indent() << " iprot_->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1502 indent() << " iprot_->readMessageEnd();" << endl <<
1503 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1504 indent() << " throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::WRONG_METHOD_NAME);" << endl <<
1505 indent() << "}" << endl;
1507 if (!(*f_iter)->get_returntype()->is_void() &&
1508 !is_complex_type((*f_iter)->get_returntype())) {
1509 t_field returnfield((*f_iter)->get_returntype(), "_return");
1510 f_service_ <<
1511 indent() << declare_field(&returnfield) << endl;
1514 f_service_ <<
1515 indent() << resultname << " result;" << endl;
1517 if (!(*f_iter)->get_returntype()->is_void()) {
1518 f_service_ <<
1519 indent() << "result.success = &_return;" << endl;
1522 f_service_ <<
1523 indent() << "result.read(iprot_);" << endl <<
1524 indent() << "iprot_->readMessageEnd();" << endl <<
1525 indent() << "iprot_->getTransport()->readEnd();" << endl <<
1526 endl;
1528 // Careful, only look for _result if not a void function
1529 if (!(*f_iter)->get_returntype()->is_void()) {
1530 if (is_complex_type((*f_iter)->get_returntype())) {
1531 f_service_ <<
1532 indent() << "if (result.__isset.success) {" << endl <<
1533 indent() << " // _return pointer has now been filled" << endl <<
1534 indent() << " return;" << endl <<
1535 indent() << "}" << endl;
1536 } else {
1537 f_service_ <<
1538 indent() << "if (result.__isset.success) {" << endl <<
1539 indent() << " return _return;" << endl <<
1540 indent() << "}" << endl;
1544 t_struct* xs = (*f_iter)->get_xceptions();
1545 const std::vector<t_field*>& xceptions = xs->get_members();
1546 vector<t_field*>::const_iterator x_iter;
1547 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1548 f_service_ <<
1549 indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
1550 indent() << " throw result." << (*x_iter)->get_name() << ";" << endl <<
1551 indent() << "}" << endl;
1554 // We only get here if we are a void function
1555 if ((*f_iter)->get_returntype()->is_void()) {
1556 indent(f_service_) <<
1557 "return;" << endl;
1558 } else {
1559 f_service_ <<
1560 indent() << "throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1563 // Close function
1564 scope_down(f_service_);
1565 f_service_ << endl;
1571 * Generates a service server definition.
1573 * @param tservice The service to generate a server for.
1575 void t_cpp_generator::generate_service_processor(t_service* tservice) {
1576 // Generate the dispatch methods
1577 vector<t_function*> functions = tservice->get_functions();
1578 vector<t_function*>::iterator f_iter;
1580 string extends = "";
1581 string extends_processor = "";
1582 if (tservice->get_extends() != NULL) {
1583 extends = type_name(tservice->get_extends());
1584 extends_processor = ", public " + extends + "Processor";
1587 // Generate the header portion
1588 f_header_ <<
1589 "class " << service_name_ << "Processor : " <<
1590 "virtual public facebook::thrift::TProcessor" <<
1591 extends_processor << " {" << endl;
1593 // Protected data members
1594 f_header_ <<
1595 " protected:" << endl;
1596 indent_up();
1597 f_header_ <<
1598 indent() << "boost::shared_ptr<" << service_name_ << "If> iface_;" << endl;
1599 f_header_ <<
1600 indent() << "virtual bool process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid);" << endl;
1601 indent_down();
1603 // Process function declarations
1604 f_header_ <<
1605 " private:" << endl;
1606 indent_up();
1607 f_header_ <<
1608 indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)> processMap_;" << endl;
1609 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1610 indent(f_header_) <<
1611 "void process_" << (*f_iter)->get_name() << "(int32_t seqid, facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot);" << endl;
1613 indent_down();
1615 indent_up();
1616 string declare_map = "";
1617 indent_up();
1619 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1620 declare_map += indent();
1621 declare_map += "processMap_[\"";
1622 declare_map += (*f_iter)->get_name();
1623 declare_map += "\"] = &";
1624 declare_map += service_name_;
1625 declare_map += "Processor::process_";
1626 declare_map += (*f_iter)->get_name();
1627 declare_map += ";\n";
1629 indent_down();
1631 f_header_ <<
1632 " public:" << endl <<
1633 indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface) :" << endl;
1634 if (extends.empty()) {
1635 f_header_ <<
1636 indent() << " iface_(iface) {" << endl;
1637 } else {
1638 f_header_ <<
1639 indent() << " " << extends << "Processor(iface)," << endl <<
1640 indent() << " iface_(iface) {" << endl;
1642 f_header_ <<
1643 declare_map <<
1644 indent() << "}" << endl <<
1645 endl <<
1646 indent() << "virtual bool process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot);" << endl <<
1647 indent() << "virtual ~" << service_name_ << "Processor() {}" << endl;
1648 indent_down();
1649 f_header_ <<
1650 "};" << endl << endl;
1652 // Generate the server implementation
1653 f_service_ <<
1654 "bool " << service_name_ << "Processor::process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot) {" << endl;
1655 indent_up();
1657 f_service_ <<
1658 endl <<
1659 indent() << "facebook::thrift::protocol::TProtocol* iprot = piprot.get();" << endl <<
1660 indent() << "facebook::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
1661 indent() << "std::string fname;" << endl <<
1662 indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
1663 indent() << "int32_t seqid;" << endl <<
1664 endl <<
1665 indent() << "iprot->readMessageBegin(fname, mtype, seqid);" << endl <<
1666 endl <<
1667 indent() << "if (mtype != facebook::thrift::protocol::T_CALL) {" << endl <<
1668 indent() << " iprot->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1669 indent() << " iprot->readMessageEnd();" << endl <<
1670 indent() << " iprot->getTransport()->readEnd();" << endl <<
1671 indent() << " facebook::thrift::TApplicationException x(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1672 indent() << " oprot->writeMessageBegin(fname, facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1673 indent() << " x.write(oprot);" << endl <<
1674 indent() << " oprot->writeMessageEnd();" << endl <<
1675 indent() << " oprot->getTransport()->flush();" << endl <<
1676 indent() << " oprot->getTransport()->writeEnd();" << endl <<
1677 indent() << " return true;" << endl <<
1678 indent() << "}" << endl <<
1679 endl <<
1680 indent() << "return process_fn(iprot, oprot, fname, seqid);" <<
1681 endl;
1683 indent_down();
1684 f_service_ <<
1685 indent() << "}" << endl <<
1686 endl;
1688 f_service_ <<
1689 "bool " << service_name_ << "Processor::process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid) {" << endl;
1690 indent_up();
1692 // HOT: member function pointer map
1693 f_service_ <<
1694 indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)>::iterator pfn;" << endl <<
1695 indent() << "pfn = processMap_.find(fname);" << endl <<
1696 indent() << "if (pfn == processMap_.end()) {" << endl;
1697 if (extends.empty()) {
1698 f_service_ <<
1699 indent() << " iprot->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1700 indent() << " iprot->readMessageEnd();" << endl <<
1701 indent() << " iprot->getTransport()->readEnd();" << endl <<
1702 indent() << " facebook::thrift::TApplicationException x(facebook::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: '\"+fname+\"'\");" << endl <<
1703 indent() << " oprot->writeMessageBegin(fname, facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1704 indent() << " x.write(oprot);" << endl <<
1705 indent() << " oprot->writeMessageEnd();" << endl <<
1706 indent() << " oprot->getTransport()->flush();" << endl <<
1707 indent() << " oprot->getTransport()->writeEnd();" << endl <<
1708 indent() << " return true;" << endl;
1709 } else {
1710 f_service_ <<
1711 indent() << " return " << extends << "Processor::process_fn(iprot, oprot, fname, seqid);" << endl;
1713 f_service_ <<
1714 indent() << "} else {" << endl <<
1715 indent() << " (this->*(pfn->second))(seqid, iprot, oprot);" << endl <<
1716 indent() << "}" << endl;
1718 // Read end of args field, the T_STOP, and the struct close
1719 f_service_ <<
1720 indent() << "return true;" << endl;
1722 indent_down();
1723 f_service_ <<
1724 "}" << endl <<
1725 endl;
1727 // Generate the process subfunctions
1728 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1729 generate_process_function(tservice, *f_iter);
1734 * Generates a struct and helpers for a function.
1736 * @param tfunction The function
1738 void t_cpp_generator::generate_function_helpers(t_service* tservice,
1739 t_function* tfunction) {
1740 if (tfunction->is_async()) {
1741 return;
1744 t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result");
1745 t_field success(tfunction->get_returntype(), "success", 0);
1746 if (!tfunction->get_returntype()->is_void()) {
1747 result.append(&success);
1750 t_struct* xs = tfunction->get_xceptions();
1751 const vector<t_field*>& fields = xs->get_members();
1752 vector<t_field*>::const_iterator f_iter;
1753 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1754 result.append(*f_iter);
1757 generate_struct_definition(f_header_, &result, false);
1758 generate_struct_reader(f_service_, &result);
1759 generate_struct_result_writer(f_service_, &result);
1761 result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
1762 generate_struct_definition(f_header_, &result, false, true, true, false);
1763 generate_struct_reader(f_service_, &result, true);
1768 * Generates a process function definition.
1770 * @param tfunction The function to write a dispatcher for
1772 void t_cpp_generator::generate_process_function(t_service* tservice,
1773 t_function* tfunction) {
1774 // Open function
1775 f_service_ <<
1776 "void " << tservice->get_name() << "Processor::" <<
1777 "process_" << tfunction->get_name() <<
1778 "(int32_t seqid, facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot)" << endl;
1779 scope_up(f_service_);
1781 string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
1782 string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
1784 f_service_ <<
1785 indent() << argsname << " args;" << endl <<
1786 indent() << "args.read(iprot);" << endl <<
1787 indent() << "iprot->readMessageEnd();" << endl <<
1788 indent() << "iprot->getTransport()->readEnd();" << endl <<
1789 endl;
1791 t_struct* xs = tfunction->get_xceptions();
1792 const std::vector<t_field*>& xceptions = xs->get_members();
1793 vector<t_field*>::const_iterator x_iter;
1795 // Declare result
1796 if (!tfunction->is_async()) {
1797 f_service_ <<
1798 indent() << resultname << " result;" << endl;
1801 // Try block for functions with exceptions
1802 f_service_ <<
1803 indent() << "try {" << endl;
1804 indent_up();
1806 // Generate the function call
1807 t_struct* arg_struct = tfunction->get_arglist();
1808 const std::vector<t_field*>& fields = arg_struct->get_members();
1809 vector<t_field*>::const_iterator f_iter;
1811 bool first = true;
1812 f_service_ << indent();
1813 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1814 if (is_complex_type(tfunction->get_returntype())) {
1815 first = false;
1816 f_service_ << "iface_->" << tfunction->get_name() << "(result.success";
1817 } else {
1818 f_service_ << "result.success = iface_->" << tfunction->get_name() << "(";
1820 } else {
1821 f_service_ <<
1822 "iface_->" << tfunction->get_name() << "(";
1824 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1825 if (first) {
1826 first = false;
1827 } else {
1828 f_service_ << ", ";
1830 f_service_ << "args." << (*f_iter)->get_name();
1832 f_service_ << ");" << endl;
1834 // Set isset on success field
1835 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1836 f_service_ <<
1837 indent() << "result.__isset.success = true;" << endl;
1840 indent_down();
1841 f_service_ << indent() << "}";
1843 if (!tfunction->is_async()) {
1844 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1845 f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " &" << (*x_iter)->get_name() << ") {" << endl;
1846 if (!tfunction->is_async()) {
1847 indent_up();
1848 f_service_ <<
1849 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
1850 indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
1851 indent_down();
1852 f_service_ << indent() << "}";
1853 } else {
1854 f_service_ << "}";
1859 f_service_ << " catch (const std::exception& e) {" << endl;
1861 if (!tfunction->is_async()) {
1862 indent_up();
1863 f_service_ <<
1864 indent() << "facebook::thrift::TApplicationException x(e.what());" << endl <<
1865 indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1866 indent() << "x.write(oprot);" << endl <<
1867 indent() << "oprot->writeMessageEnd();" << endl <<
1868 indent() << "oprot->getTransport()->flush();" << endl <<
1869 indent() << "oprot->getTransport()->writeEnd();" << endl <<
1870 indent() << "return;" << endl;
1871 indent_down();
1873 f_service_ << indent() << "}" << endl;
1875 // Shortcut out here for async functions
1876 if (tfunction->is_async()) {
1877 f_service_ <<
1878 indent() << "return;" << endl;
1879 indent_down();
1880 f_service_ << "}" << endl <<
1881 endl;
1882 return;
1885 // Serialize the result into a struct
1886 f_service_ <<
1887 endl <<
1888 indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_REPLY, seqid);" << endl <<
1889 indent() << "result.write(oprot);" << endl <<
1890 indent() << "oprot->writeMessageEnd();" << endl <<
1891 indent() << "oprot->getTransport()->flush();" << endl <<
1892 indent() << "oprot->getTransport()->writeEnd();" << endl;
1894 // Close function
1895 scope_down(f_service_);
1896 f_service_ << endl;
1900 * Helper function for generate_service_limited_reflector.
1901 * Generates a reflection of a single simple type.
1903 * @param ttype The type to reflect
1904 * @param target The name of the lvalue to reflect onto
1905 * @return true iff the type really is simple
1907 * Note: don't let this function output anything unless it is going to return true.
1909 bool t_cpp_generator::generate_simple_type_limited_reflection(ostream & out, t_type* ttype, string target) {
1910 if (ttype->is_base_type()) {
1911 string type;
1912 switch (((t_base_type*)ttype)->get_base()) {
1913 case t_base_type::TYPE_VOID : type = "T_VOID;" ; break;
1914 case t_base_type::TYPE_STRING : type = "T_STRING;" ; break;
1915 case t_base_type::TYPE_BOOL : type = "T_BOOL;" ; break;
1916 case t_base_type::TYPE_BYTE : type = "T_BYTE;" ; break;
1917 case t_base_type::TYPE_I16 : type = "T_I16;" ; break;
1918 case t_base_type::TYPE_I32 : type = "T_I32;" ; break;
1919 case t_base_type::TYPE_I64 : type = "T_I64;" ; break;
1920 case t_base_type::TYPE_DOUBLE : type = "T_DOUBLE;" ; break;
1921 default: return false;
1923 out << indent() << target << ".ttype = " << type << endl;
1924 return true;
1927 if (ttype->is_enum()) {
1928 out <<
1929 indent() << target << ".ttype = T_ENUM;" << endl <<
1930 indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl;
1933 if (ttype->is_struct()) {
1934 out <<
1935 indent() << target << ".ttype = T_STRUCT;" << endl <<
1936 indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl;
1937 return true;
1940 return false;
1944 * Helper function for generate_service_limited_reflector.
1945 * Generates a reflection of a single type.
1947 * @param ttype The type to reflect
1948 * @param target The name of the lvalue to reflect onto
1950 bool t_cpp_generator::generate_type_limited_reflection(t_type* ttype, string target) {
1951 bool is_simple = generate_simple_type_limited_reflection(f_service_, ttype, target + ".simple_type");
1952 if (is_simple) {
1953 f_service_ <<
1954 indent() << target << ".is_container = false;" << endl <<
1955 indent() << target << ".__isset.simple_type = true;" << endl;
1956 return true;
1959 ostringstream out;
1961 out <<
1962 indent() << target << ".is_container = true;" << endl <<
1963 indent() << target << ".__isset.container_type = true;" << endl <<
1964 indent() << target << ".container_type.ttype = ";
1966 if (ttype->is_list()) out << "T_LIST;" << endl;
1967 if (ttype->is_set()) out << "T_SET;" << endl;
1968 if (ttype->is_map()) out << "T_MAP;" << endl;
1970 bool reflected = false;
1972 if (ttype->is_list()) {
1973 reflected = generate_simple_type_limited_reflection(
1974 out, ((t_list*)ttype)->get_elem_type(), target + ".container_type.subtype1");
1976 if (ttype->is_set()) {
1977 reflected = generate_simple_type_limited_reflection(
1978 out, ((t_set*)ttype)->get_elem_type(), target + ".container_type.subtype1");
1980 if (ttype->is_map()) {
1981 reflected =
1982 generate_simple_type_limited_reflection(
1983 out, ((t_map*)ttype)->get_key_type(), target + ".container_type.subtype1")
1985 generate_simple_type_limited_reflection(
1986 out, ((t_map*)ttype)->get_val_type(), target + ".container_type.subtype2");
1987 out << indent() << target << ".container_type.__isset.subtype2 = true;" << endl;
1990 if (reflected) {
1991 f_service_ << out.str();
1992 return true;
1993 } else {
1994 f_service_ <<
1995 indent() << target << ".is_container = false;" << endl <<
1996 indent() << target << ".__isset.simple_type = true;" << endl;
1997 f_service_ << indent() << target << ".simple_type.ttype = T_NOT_REFLECTED;" << endl;
1998 return false;
2003 * Generates a service reflector definition.
2004 * This uses thrift::reflection::limited.
2006 * @param tservice The service to write a reflector for
2008 void t_cpp_generator::generate_service_limited_reflector(t_service* tservice) {
2009 // Open function
2010 f_service_ <<
2011 indent() << "void " << tservice->get_name() << "If::getStaticLimitedReflection" <<
2012 "(facebook::thrift::reflection::limited::Service & _return) ";
2013 scope_up(f_service_);
2015 f_service_ << indent() << "using namespace facebook::thrift::reflection::limited;" << endl;
2017 f_service_ << indent() << "_return.name = \"" << tservice->get_name() << "\";" << endl;
2018 f_service_ << indent() << "_return.fully_reflected = true;" << endl;
2020 bool all_reflectable = true;
2021 bool one_reflectable;
2023 const vector<t_function*> & funcs = tservice->get_functions();
2024 vector<t_function*>::const_iterator f_iter;
2025 for (f_iter = funcs.begin(); f_iter != funcs.end(); ++f_iter) {
2027 f_service_ << indent() << "_return.methods.resize(_return.methods.size() + 1);" << endl;
2028 f_service_ << indent() << "_return.methods.back().name = \"" << (*f_iter)->get_name() << "\";" << endl;
2029 one_reflectable = generate_type_limited_reflection(
2030 (*f_iter)->get_returntype(), "_return.methods.back().return_type");
2031 all_reflectable = all_reflectable && one_reflectable;
2033 t_struct* arglist = (*f_iter)->get_arglist();
2034 const vector<t_field*> & args = arglist->get_members();
2035 vector<t_field*>::const_iterator a_iter;
2036 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
2037 f_service_ <<
2038 indent() << "_return.methods.back().arguments.resize("
2039 "_return.methods.back().arguments.size() + 1);" << endl <<
2040 indent() << "_return.methods.back().arguments.back().name = \"" <<
2041 (*a_iter)->get_name() << "\";" << endl <<
2042 indent() << "_return.methods.back().arguments.back().key = " <<
2043 (*a_iter)->get_key() << ";" << endl;
2044 one_reflectable = generate_type_limited_reflection(
2045 (*a_iter)->get_type(), "_return.methods.back().arguments.back().type");
2046 all_reflectable = all_reflectable && one_reflectable;
2050 if (!all_reflectable) {
2051 f_service_ << indent() << "_return.fully_reflected = false;" << endl;
2054 // Close function
2055 scope_down(f_service_);
2056 f_service_ << endl;
2060 * Generates a skeleton file of a server
2062 * @param tservice The service to generate a server for.
2064 void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
2065 string svcname = tservice->get_name();
2067 // Service implementation file includes
2068 string f_skeleton_name = string(T_CPP_DIR)+"/"+svcname+"_server.skeleton.cpp";
2070 string ns = namespace_prefix(tservice->get_program()->get_cpp_namespace());
2072 ofstream f_skeleton;
2073 f_skeleton.open(f_skeleton_name.c_str());
2074 f_skeleton <<
2075 "// This autogenerated skeleton file illustrates how to build a server." << endl <<
2076 "// You should copy it to another filename to avoid overwriting it." << endl <<
2077 endl <<
2078 "#include \"" << svcname << ".h\"" << endl <<
2079 "#include <protocol/TBinaryProtocol.h>" << endl <<
2080 "#include <server/TSimpleServer.h>" << endl <<
2081 "#include <transport/TServerSocket.h>" << endl <<
2082 "#include <transport/TTransportUtils.h>" << endl <<
2083 endl <<
2084 "using namespace facebook::thrift;" << endl <<
2085 "using namespace facebook::thrift::protocol;" << endl <<
2086 "using namespace facebook::thrift::transport;" << endl <<
2087 "using namespace facebook::thrift::server;" << endl <<
2088 endl <<
2089 "using boost::shared_ptr;" << endl <<
2090 endl;
2092 if (!ns.empty()) {
2093 f_skeleton <<
2094 "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
2095 endl;
2098 f_skeleton <<
2099 "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl <<
2100 " public:" << endl;
2101 indent_up();
2102 f_skeleton <<
2103 indent() << svcname << "Handler() {" << endl <<
2104 indent() << " // Your initialization goes here" << endl <<
2105 indent() << "}" << endl <<
2106 endl;
2108 vector<t_function*> functions = tservice->get_functions();
2109 vector<t_function*>::iterator f_iter;
2110 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2111 f_skeleton <<
2112 indent() << function_signature(*f_iter) << " {" << endl <<
2113 indent() << " // Your implementation goes here" << endl <<
2114 indent() << " printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl <<
2115 indent() << "}" << endl <<
2116 endl;
2119 indent_down();
2120 f_skeleton <<
2121 "};" << endl <<
2122 endl;
2124 f_skeleton <<
2125 indent() << "int main(int argc, char **argv) {" << endl;
2126 indent_up();
2127 f_skeleton <<
2128 indent() << "int port = 9090;" << endl <<
2129 indent() << "shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl <<
2130 indent() << "shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl <<
2131 indent() << "shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));" << endl <<
2132 indent() << "shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl <<
2133 indent() << "shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());" << endl <<
2134 endl <<
2135 indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl <<
2136 indent() << "server.serve();" << endl <<
2137 indent() << "return 0;" << endl;
2138 indent_down();
2139 f_skeleton <<
2140 "}" << endl <<
2141 endl;
2143 // Close the files
2144 f_skeleton.close();
2148 * Deserializes a field of any type.
2150 void t_cpp_generator::generate_deserialize_field(ofstream& out,
2151 t_field* tfield,
2152 string prefix,
2153 string suffix) {
2154 t_type* type = get_true_type(tfield->get_type());
2156 if (type->is_void()) {
2157 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
2158 prefix + tfield->get_name();
2161 string name = prefix + tfield->get_name() + suffix;
2163 if (type->is_struct() || type->is_xception()) {
2164 generate_deserialize_struct(out, (t_struct*)type, name);
2165 } else if (type->is_container()) {
2166 generate_deserialize_container(out, type, name);
2167 } else if (type->is_base_type()) {
2168 indent(out) <<
2169 "xfer += iprot->";
2170 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2171 switch (tbase) {
2172 case t_base_type::TYPE_VOID:
2173 throw "compiler error: cannot serialize void field in a struct: " + name;
2174 break;
2175 case t_base_type::TYPE_STRING:
2176 out << "readString(" << name << ");";
2177 break;
2178 case t_base_type::TYPE_BOOL:
2179 out << "readBool(" << name << ");";
2180 break;
2181 case t_base_type::TYPE_BYTE:
2182 out << "readByte(" << name << ");";
2183 break;
2184 case t_base_type::TYPE_I16:
2185 out << "readI16(" << name << ");";
2186 break;
2187 case t_base_type::TYPE_I32:
2188 out << "readI32(" << name << ");";
2189 break;
2190 case t_base_type::TYPE_I64:
2191 out << "readI64(" << name << ");";
2192 break;
2193 case t_base_type::TYPE_DOUBLE:
2194 out << "readDouble(" << name << ");";
2195 break;
2196 default:
2197 throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
2199 out <<
2200 endl;
2201 } else if (type->is_enum()) {
2202 string t = tmp("ecast");
2203 out <<
2204 indent() << "int32_t " << t << ";" << endl <<
2205 indent() << "xfer += iprot->readI32(" << t << ");" << endl <<
2206 indent() << name << " = (" << type->get_name() << ")" << t << ";" << endl;
2207 } else {
2208 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
2209 tfield->get_name().c_str(), type_name(type).c_str());
2214 * Generates an unserializer for a variable. This makes two key assumptions,
2215 * first that there is a const char* variable named data that points to the
2216 * buffer for deserialization, and that there is a variable protocol which
2217 * is a reference to a TProtocol serialization object.
2219 void t_cpp_generator::generate_deserialize_struct(ofstream& out,
2220 t_struct* tstruct,
2221 string prefix) {
2222 indent(out) <<
2223 "xfer += " << prefix << ".read(iprot);" << endl;
2226 void t_cpp_generator::generate_deserialize_container(ofstream& out,
2227 t_type* ttype,
2228 string prefix) {
2229 scope_up(out);
2231 string size = tmp("_size");
2232 string ktype = tmp("_ktype");
2233 string vtype = tmp("_vtype");
2234 string etype = tmp("_etype");
2236 indent(out) <<
2237 prefix << ".clear();" << endl <<
2238 indent() << "uint32_t " << size << ";" << endl;
2240 // Declare variables, read header
2241 if (ttype->is_map()) {
2242 out <<
2243 indent() << "facebook::thrift::protocol::TType " << ktype << ";" << endl <<
2244 indent() << "facebook::thrift::protocol::TType " << vtype << ";" << endl <<
2245 indent() << "iprot->readMapBegin(" <<
2246 ktype << ", " << vtype << ", " << size << ");" << endl;
2247 } else if (ttype->is_set()) {
2248 out <<
2249 indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
2250 indent() << "iprot->readSetBegin(" <<
2251 etype << ", " << size << ");" << endl;
2252 } else if (ttype->is_list()) {
2253 out <<
2254 indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
2255 indent() << "iprot->readListBegin(" <<
2256 etype << ", " << size << ");" << endl;
2260 // For loop iterates over elements
2261 string i = tmp("_i");
2262 out <<
2263 indent() << "uint32_t " << i << ";" << endl <<
2264 indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
2266 scope_up(out);
2268 if (ttype->is_map()) {
2269 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
2270 } else if (ttype->is_set()) {
2271 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
2272 } else if (ttype->is_list()) {
2273 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
2276 scope_down(out);
2278 // Read container end
2279 if (ttype->is_map()) {
2280 indent(out) << "iprot->readMapEnd();" << endl;
2281 } else if (ttype->is_set()) {
2282 indent(out) << "iprot->readSetEnd();" << endl;
2283 } else if (ttype->is_list()) {
2284 indent(out) << "iprot->readListEnd();" << endl;
2287 scope_down(out);
2292 * Generates code to deserialize a map
2294 void t_cpp_generator::generate_deserialize_map_element(ofstream& out,
2295 t_map* tmap,
2296 string prefix) {
2297 string key = tmp("_key");
2298 string val = tmp("_val");
2299 t_field fkey(tmap->get_key_type(), key);
2300 t_field fval(tmap->get_val_type(), val);
2302 out <<
2303 indent() << declare_field(&fkey) << endl <<
2304 indent() << declare_field(&fval) << endl;
2306 generate_deserialize_field(out, &fkey);
2307 generate_deserialize_field(out, &fval);
2309 indent(out) <<
2310 prefix << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
2313 void t_cpp_generator::generate_deserialize_set_element(ofstream& out,
2314 t_set* tset,
2315 string prefix) {
2316 string elem = tmp("_elem");
2317 t_field felem(tset->get_elem_type(), elem);
2319 indent(out) <<
2320 declare_field(&felem) << endl;
2322 generate_deserialize_field(out, &felem);
2324 indent(out) <<
2325 prefix << ".insert(" << elem << ");" << endl;
2328 void t_cpp_generator::generate_deserialize_list_element(ofstream& out,
2329 t_list* tlist,
2330 string prefix) {
2331 string elem = tmp("_elem");
2332 t_field felem(tlist->get_elem_type(), elem);
2334 indent(out) <<
2335 declare_field(&felem) << endl;
2337 generate_deserialize_field(out, &felem);
2339 indent(out) <<
2340 prefix << ".push_back(" << elem << ");" << endl;
2345 * Serializes a field of any type.
2347 * @param tfield The field to serialize
2348 * @param prefix Name to prepend to field name
2350 void t_cpp_generator::generate_serialize_field(ofstream& out,
2351 t_field* tfield,
2352 string prefix,
2353 string suffix) {
2354 t_type* type = get_true_type(tfield->get_type());
2356 string name = prefix + tfield->get_name() + suffix;
2358 // Do nothing for void types
2359 if (type->is_void()) {
2360 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
2365 if (type->is_struct() || type->is_xception()) {
2366 generate_serialize_struct(out,
2367 (t_struct*)type,
2368 name);
2369 } else if (type->is_container()) {
2370 generate_serialize_container(out, type, name);
2371 } else if (type->is_base_type() || type->is_enum()) {
2373 indent(out) <<
2374 "xfer += oprot->";
2376 if (type->is_base_type()) {
2377 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2378 switch (tbase) {
2379 case t_base_type::TYPE_VOID:
2380 throw
2381 "compiler error: cannot serialize void field in a struct: " + name;
2382 break;
2383 case t_base_type::TYPE_STRING:
2384 out << "writeString(" << name << ");";
2385 break;
2386 case t_base_type::TYPE_BOOL:
2387 out << "writeBool(" << name << ");";
2388 break;
2389 case t_base_type::TYPE_BYTE:
2390 out << "writeByte(" << name << ");";
2391 break;
2392 case t_base_type::TYPE_I16:
2393 out << "writeI16(" << name << ");";
2394 break;
2395 case t_base_type::TYPE_I32:
2396 out << "writeI32(" << name << ");";
2397 break;
2398 case t_base_type::TYPE_I64:
2399 out << "writeI64(" << name << ");";
2400 break;
2401 case t_base_type::TYPE_DOUBLE:
2402 out << "writeDouble(" << name << ");";
2403 break;
2404 default:
2405 throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + name;
2407 } else if (type->is_enum()) {
2408 out << "writeI32((int32_t)" << name << ");";
2410 out << endl;
2411 } else {
2412 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
2413 name.c_str(),
2414 type_name(type).c_str());
2419 * Serializes all the members of a struct.
2421 * @param tstruct The struct to serialize
2422 * @param prefix String prefix to attach to all fields
2424 void t_cpp_generator::generate_serialize_struct(ofstream& out,
2425 t_struct* tstruct,
2426 string prefix) {
2427 indent(out) <<
2428 "xfer += " << prefix << ".write(oprot);" << endl;
2431 void t_cpp_generator::generate_serialize_container(ofstream& out,
2432 t_type* ttype,
2433 string prefix) {
2434 scope_up(out);
2436 if (ttype->is_map()) {
2437 indent(out) <<
2438 "xfer += oprot->writeMapBegin(" <<
2439 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
2440 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
2441 prefix << ".size());" << endl;
2442 } else if (ttype->is_set()) {
2443 indent(out) <<
2444 "xfer += oprot->writeSetBegin(" <<
2445 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
2446 prefix << ".size());" << endl;
2447 } else if (ttype->is_list()) {
2448 indent(out) <<
2449 "xfer += oprot->writeListBegin(" <<
2450 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
2451 prefix << ".size());" << endl;
2454 string iter = tmp("_iter");
2455 out <<
2456 indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl <<
2457 indent() << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl;
2458 scope_up(out);
2459 if (ttype->is_map()) {
2460 generate_serialize_map_element(out, (t_map*)ttype, iter);
2461 } else if (ttype->is_set()) {
2462 generate_serialize_set_element(out, (t_set*)ttype, iter);
2463 } else if (ttype->is_list()) {
2464 generate_serialize_list_element(out, (t_list*)ttype, iter);
2466 scope_down(out);
2468 if (ttype->is_map()) {
2469 indent(out) <<
2470 "xfer += oprot->writeMapEnd();" << endl;
2471 } else if (ttype->is_set()) {
2472 indent(out) <<
2473 "xfer += oprot->writeSetEnd();" << endl;
2474 } else if (ttype->is_list()) {
2475 indent(out) <<
2476 "xfer += oprot->writeListEnd();" << endl;
2479 scope_down(out);
2483 * Serializes the members of a map.
2486 void t_cpp_generator::generate_serialize_map_element(ofstream& out,
2487 t_map* tmap,
2488 string iter) {
2489 t_field kfield(tmap->get_key_type(), iter + "->first");
2490 generate_serialize_field(out, &kfield, "");
2492 t_field vfield(tmap->get_val_type(), iter + "->second");
2493 generate_serialize_field(out, &vfield, "");
2497 * Serializes the members of a set.
2499 void t_cpp_generator::generate_serialize_set_element(ofstream& out,
2500 t_set* tset,
2501 string iter) {
2502 t_field efield(tset->get_elem_type(), "(*" + iter + ")");
2503 generate_serialize_field(out, &efield, "");
2507 * Serializes the members of a list.
2509 void t_cpp_generator::generate_serialize_list_element(ofstream& out,
2510 t_list* tlist,
2511 string iter) {
2512 t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
2513 generate_serialize_field(out, &efield, "");
2517 * Makes a :: prefix for a namespace
2519 * @param ns The namepsace, w/ periods in it
2520 * @return Namespaces
2522 string t_cpp_generator::namespace_prefix(string ns) {
2523 if (ns.size() == 0) {
2524 return "";
2526 string result = "";
2527 string::size_type loc;
2528 while ((loc = ns.find(".")) != string::npos) {
2529 result += ns.substr(0, loc);
2530 result += "::";
2531 ns = ns.substr(loc+1);
2533 if (ns.size() > 0) {
2534 result += ns + "::";
2536 return result;
2540 * Opens namespace.
2542 * @param ns The namepsace, w/ periods in it
2543 * @return Namespaces
2545 string t_cpp_generator::namespace_open(string ns) {
2546 if (ns.size() == 0) {
2547 return "";
2549 string result = "";
2550 string separator = "";
2551 string::size_type loc;
2552 while ((loc = ns.find(".")) != string::npos) {
2553 result += separator;
2554 result += "namespace ";
2555 result += ns.substr(0, loc);
2556 result += " {";
2557 separator = " ";
2558 ns = ns.substr(loc+1);
2560 if (ns.size() > 0) {
2561 result += separator + "namespace " + ns + " {";
2563 return result;
2567 * Closes namespace.
2569 * @param ns The namepsace, w/ periods in it
2570 * @return Namespaces
2572 string t_cpp_generator::namespace_close(string ns) {
2573 if (ns.size() == 0) {
2574 return "";
2576 string result = "}";
2577 string::size_type loc;
2578 while ((loc = ns.find(".")) != string::npos) {
2579 result += "}";
2580 ns = ns.substr(loc+1);
2582 result += " // namespace";
2583 return result;
2587 * Returns a C++ type name
2589 * @param ttype The type
2590 * @return String of the type name, i.e. std::set<type>
2592 string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
2593 if (ttype->is_base_type()) {
2594 string bname = base_type_name(((t_base_type*)ttype)->get_base());
2595 if (!arg) {
2596 return bname;
2599 if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) {
2600 return "const " + bname + "&";
2601 } else {
2602 return "const " + bname;
2606 // Check for a custom overloaded C++ name
2607 if (ttype->is_container()) {
2608 string cname;
2610 t_container* tcontainer = (t_container*) ttype;
2611 if (tcontainer->has_cpp_name()) {
2612 cname = tcontainer->get_cpp_name();
2613 } else if (ttype->is_map()) {
2614 t_map* tmap = (t_map*) ttype;
2615 cname = "std::map<" +
2616 type_name(tmap->get_key_type(), in_typedef) + ", " +
2617 type_name(tmap->get_val_type(), in_typedef) + "> ";
2618 } else if (ttype->is_set()) {
2619 t_set* tset = (t_set*) ttype;
2620 cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> ";
2621 } else if (ttype->is_list()) {
2622 t_list* tlist = (t_list*) ttype;
2623 cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
2626 if (arg) {
2627 return "const " + cname + "&";
2628 } else {
2629 return cname;
2633 string class_prefix;
2634 if (in_typedef && (ttype->is_struct() || ttype->is_xception())) {
2635 class_prefix = "class ";
2638 // Check if it needs to be namespaced
2639 string pname;
2640 t_program* program = ttype->get_program();
2641 if (program != NULL && program != program_) {
2642 pname =
2643 class_prefix +
2644 namespace_prefix(program->get_cpp_namespace()) +
2645 ttype->get_name();
2646 } else {
2647 pname = class_prefix + ttype->get_name();
2650 if (arg) {
2651 if (is_complex_type(ttype)) {
2652 return "const " + pname + "&";
2653 } else {
2654 return "const " + pname;
2656 } else {
2657 return pname;
2662 * Returns the C++ type that corresponds to the thrift type.
2664 * @param tbase The base type
2665 * @return Explicit C++ type, i.e. "int32_t"
2667 string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
2668 switch (tbase) {
2669 case t_base_type::TYPE_VOID:
2670 return "void";
2671 case t_base_type::TYPE_STRING:
2672 return "std::string";
2673 case t_base_type::TYPE_BOOL:
2674 return "bool";
2675 case t_base_type::TYPE_BYTE:
2676 return "int8_t";
2677 case t_base_type::TYPE_I16:
2678 return "int16_t";
2679 case t_base_type::TYPE_I32:
2680 return "int32_t";
2681 case t_base_type::TYPE_I64:
2682 return "int64_t";
2683 case t_base_type::TYPE_DOUBLE:
2684 return "double";
2685 default:
2686 throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
2691 * Declares a field, which may include initialization as necessary.
2693 * @param ttype The type
2694 * @return Field declaration, i.e. int x = 0;
2696 string t_cpp_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant) {
2697 // TODO(mcslee): do we ever need to initialize the field?
2698 string result = "";
2699 if (constant) {
2700 result += "const ";
2702 result += type_name(tfield->get_type());
2703 if (pointer) {
2704 result += "*";
2706 result += " " + tfield->get_name();
2707 if (init) {
2708 t_type* type = get_true_type(tfield->get_type());
2710 if (type->is_base_type()) {
2711 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2712 switch (tbase) {
2713 case t_base_type::TYPE_VOID:
2714 break;
2715 case t_base_type::TYPE_STRING:
2716 result += " = \"\"";
2717 break;
2718 case t_base_type::TYPE_BOOL:
2719 result += " = false";
2720 break;
2721 case t_base_type::TYPE_BYTE:
2722 case t_base_type::TYPE_I16:
2723 case t_base_type::TYPE_I32:
2724 case t_base_type::TYPE_I64:
2725 result += " = 0";
2726 break;
2727 case t_base_type::TYPE_DOUBLE:
2728 result += " = (double)0";
2729 break;
2730 default:
2731 throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase);
2733 } else if (type->is_enum()) {
2734 result += " = (" + type_name(type) + ")0";
2737 return result + ";";
2741 * Renders a function signature of the form 'type name(args)'
2743 * @param tfunction Function definition
2744 * @return String of rendered function definition
2746 string t_cpp_generator::function_signature(t_function* tfunction,
2747 string prefix) {
2748 t_type* ttype = tfunction->get_returntype();
2749 t_struct* arglist = tfunction->get_arglist();
2751 if (is_complex_type(ttype)) {
2752 bool empty = arglist->get_members().size() == 0;
2753 return
2754 "void " + prefix + tfunction->get_name() +
2755 "(" + type_name(ttype) + "& _return" +
2756 (empty ? "" : (", " + argument_list(arglist))) + ")";
2757 } else {
2758 return
2759 type_name(ttype) + " " + prefix + tfunction->get_name() +
2760 "(" + argument_list(arglist) + ")";
2765 * Renders a field list
2767 * @param tstruct The struct definition
2768 * @return Comma sepearated list of all field names in that struct
2770 string t_cpp_generator::argument_list(t_struct* tstruct) {
2771 string result = "";
2773 const vector<t_field*>& fields = tstruct->get_members();
2774 vector<t_field*>::const_iterator f_iter;
2775 bool first = true;
2776 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2777 if (first) {
2778 first = false;
2779 } else {
2780 result += ", ";
2782 result += type_name((*f_iter)->get_type(), false, true) + " " + (*f_iter)->get_name();
2784 return result;
2788 * Converts the parse type to a C++ enum string for the given type.
2790 * @param type Thrift Type
2791 * @return String of C++ code to definition of that type constant
2793 string t_cpp_generator::type_to_enum(t_type* type) {
2794 type = get_true_type(type);
2796 if (type->is_base_type()) {
2797 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2798 switch (tbase) {
2799 case t_base_type::TYPE_VOID:
2800 throw "NO T_VOID CONSTRUCT";
2801 case t_base_type::TYPE_STRING:
2802 return "facebook::thrift::protocol::T_STRING";
2803 case t_base_type::TYPE_BOOL:
2804 return "facebook::thrift::protocol::T_BOOL";
2805 case t_base_type::TYPE_BYTE:
2806 return "facebook::thrift::protocol::T_BYTE";
2807 case t_base_type::TYPE_I16:
2808 return "facebook::thrift::protocol::T_I16";
2809 case t_base_type::TYPE_I32:
2810 return "facebook::thrift::protocol::T_I32";
2811 case t_base_type::TYPE_I64:
2812 return "facebook::thrift::protocol::T_I64";
2813 case t_base_type::TYPE_DOUBLE:
2814 return "facebook::thrift::protocol::T_DOUBLE";
2816 } else if (type->is_enum()) {
2817 return "facebook::thrift::protocol::T_I32";
2818 } else if (type->is_struct()) {
2819 return "facebook::thrift::protocol::T_STRUCT";
2820 } else if (type->is_xception()) {
2821 return "facebook::thrift::protocol::T_STRUCT";
2822 } else if (type->is_map()) {
2823 return "facebook::thrift::protocol::T_MAP";
2824 } else if (type->is_set()) {
2825 return "facebook::thrift::protocol::T_SET";
2826 } else if (type->is_list()) {
2827 return "facebook::thrift::protocol::T_LIST";
2830 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2834 * Returns the symbol name of the local reflection of a type.
2836 string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype) {
2837 ttype = get_true_type(ttype);
2839 // We have to use the program name as part of the identifier because
2840 // if two thrift "programs" are compiled into one actual program
2841 // you would get a symbol collison if they both defined list<i32>.
2842 // trlo = Thrift Reflection LOcal.
2843 string prog;
2844 string name;
2846 // TODO(dreiss): Would it be better to pregenerate the base types
2847 // and put them in Thrift.{h,cpp} ?
2849 if (ttype->is_base_type()) {
2850 //name = ttype->get_name();
2851 prog = program_->get_name();
2852 name = ttype->get_ascii_fingerprint();
2853 } else if (ttype->is_enum()) {
2854 //name = "enum";
2855 prog = program_->get_name();
2856 name = ttype->get_ascii_fingerprint();
2857 } else if (ttype->is_container()) {
2858 prog = program_->get_name();
2859 name = ttype->get_ascii_fingerprint();
2860 } else {
2861 assert(ttype->is_struct() || ttype->is_xception());
2862 assert(ttype->get_program() != NULL);
2863 prog = ttype->get_program()->get_name();
2864 name = ttype->get_ascii_fingerprint();
2867 return string() + "trlo_" + prefix + "_" + prog + "_" + name;