Merge commit 'remotes/trunk'
[amiethrift.git] / compiler / cpp / src / generate / t_cpp_generator.cc
blob755fbb5975521d0ebe151d21aab680faaeff1bef
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 #include "platform.h"
14 using namespace std;
16 /**
17 * Prepares for file generation by opening up the necessary file output
18 * streams.
20 * @param tprogram The program to generate
22 void t_cpp_generator::init_generator() {
23 // Make output directory
24 MKDIR(get_out_dir().c_str());
26 // Make output file
27 string f_types_name = get_out_dir()+program_name_+"_types.h";
28 f_types_.open(f_types_name.c_str());
30 string f_types_impl_name = get_out_dir()+program_name_+"_types.cpp";
31 f_types_impl_.open(f_types_impl_name.c_str());
33 // Print header
34 f_types_ <<
35 autogen_comment();
36 f_types_impl_ <<
37 autogen_comment();
39 // Start ifndef
40 f_types_ <<
41 "#ifndef " << program_name_ << "_TYPES_H" << endl <<
42 "#define " << program_name_ << "_TYPES_H" << endl <<
43 endl;
45 // Include base types
46 f_types_ <<
47 "#include <Thrift.h>" << endl <<
48 "#include <reflection_limited_types.h>" << endl <<
49 "#include <protocol/TProtocol.h>" << endl <<
50 "#include <transport/TTransport.h>" << endl <<
51 endl;
53 // Include other Thrift includes
54 const vector<t_program*>& includes = program_->get_includes();
55 for (size_t i = 0; i < includes.size(); ++i) {
56 f_types_ <<
57 "#include \"" << get_include_prefix(*(includes[i])) <<
58 includes[i]->get_name() << "_types.h\"" << endl;
60 f_types_ << endl;
62 // Include custom headers
63 const vector<string>& cpp_includes = program_->get_cpp_includes();
64 for (size_t i = 0; i < cpp_includes.size(); ++i) {
65 f_types_ <<
66 "#include \"" << cpp_includes[i] << "\"" << endl;
68 f_types_ <<
69 endl;
71 // Include the types file
72 f_types_impl_ <<
73 "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
74 "_types.h\"" << endl <<
75 endl;
77 // If we are generating local reflection metadata, we need to include
78 // the definition of TypeSpec.
79 if (gen_dense_) {
80 f_types_impl_ <<
81 "#include <TReflectionLocal.h>" << endl <<
82 endl;
85 // Open namespace
86 ns_open_ = namespace_open(program_->get_cpp_namespace());
87 ns_close_ = namespace_close(program_->get_cpp_namespace());
89 f_types_ <<
90 ns_open_ << endl <<
91 endl;
93 f_types_impl_ <<
94 ns_open_ << endl <<
95 endl;
98 /**
99 * Closes the output files.
101 void t_cpp_generator::close_generator() {
102 // Close namespace
103 f_types_ <<
104 ns_close_ << endl <<
105 endl;
106 f_types_impl_ <<
107 ns_close_ << endl;
109 // Close ifndef
110 f_types_ <<
111 "#endif" << endl;
113 // Close output file
114 f_types_.close();
115 f_types_impl_.close();
119 * Generates a typedef. This is just a simple 1-liner in C++
121 * @param ttypedef The type definition
123 void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
124 f_types_ <<
125 indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << ttypedef->get_symbolic() << ";" << endl <<
126 endl;
130 * Generates code for an enumerated type. In C++, this is essentially the same
131 * as the thrift definition itself, using the enum keyword in C++.
133 * @param tenum The enumeration
135 void t_cpp_generator::generate_enum(t_enum* tenum) {
136 f_types_ <<
137 indent() << "enum " << tenum->get_name() << " {" << endl;
138 indent_up();
140 vector<t_enum_value*> constants = tenum->get_constants();
141 vector<t_enum_value*>::iterator c_iter;
142 bool first = true;
143 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
144 if (first) {
145 first = false;
146 } else {
147 f_types_ <<
148 "," << endl;
150 f_types_ <<
151 indent() << (*c_iter)->get_name();
152 if ((*c_iter)->has_value()) {
153 f_types_ <<
154 " = " << (*c_iter)->get_value();
158 indent_down();
159 f_types_ <<
160 endl <<
161 "};" << endl <<
162 endl;
166 * Generates a class that holds all the constants.
168 void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
169 string f_consts_name = get_out_dir()+program_name_+"_constants.h";
170 ofstream f_consts;
171 f_consts.open(f_consts_name.c_str());
173 string f_consts_impl_name = get_out_dir()+program_name_+"_constants.cpp";
174 ofstream f_consts_impl;
175 f_consts_impl.open(f_consts_impl_name.c_str());
177 // Print header
178 f_consts <<
179 autogen_comment();
180 f_consts_impl <<
181 autogen_comment();
183 // Start ifndef
184 f_consts <<
185 "#ifndef " << program_name_ << "_CONSTANTS_H" << endl <<
186 "#define " << program_name_ << "_CONSTANTS_H" << endl <<
187 endl <<
188 "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
189 "_types.h\"" << endl <<
190 endl <<
191 ns_open_ << endl <<
192 endl;
194 f_consts_impl <<
195 "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
196 "_constants.h\"" << endl <<
197 endl <<
198 ns_open_ << endl <<
199 endl;
201 f_consts <<
202 "class " << program_name_ << "Constants {" << endl <<
203 " public:" << endl <<
204 " " << program_name_ << "Constants();" << endl <<
205 endl;
206 indent_up();
207 vector<t_const*>::iterator c_iter;
208 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
209 string name = (*c_iter)->get_name();
210 t_type* type = (*c_iter)->get_type();
211 f_consts <<
212 indent() << type_name(type) << " " << name << ";" << endl;
214 indent_down();
215 f_consts <<
216 "};" << endl;
218 f_consts_impl <<
219 "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
220 endl <<
221 program_name_ << "Constants::" << program_name_ << "Constants() {" << endl;
222 indent_up();
223 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
224 print_const_value(f_consts_impl,
225 (*c_iter)->get_name(),
226 (*c_iter)->get_type(),
227 (*c_iter)->get_value());
229 indent_down();
230 indent(f_consts_impl) <<
231 "}" << endl;
233 f_consts <<
234 endl <<
235 "extern const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
236 endl <<
237 ns_close_ << endl <<
238 endl <<
239 "#endif" << endl;
240 f_consts.close();
242 f_consts_impl <<
243 endl <<
244 ns_close_ << endl <<
245 endl;
249 * Prints the value of a constant with the given type. Note that type checking
250 * is NOT performed in this function as it is always run beforehand using the
251 * validate_types method in main.cc
253 void t_cpp_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
254 if (type->is_base_type()) {
255 string v2 = render_const_value(out, name, type, value);
256 indent(out) << name << " = " << v2 << ";" << endl <<
257 endl;
258 } else if (type->is_enum()) {
259 indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl <<
260 endl;
261 } else if (type->is_struct() || type->is_xception()) {
262 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
263 vector<t_field*>::const_iterator f_iter;
264 const map<t_const_value*, t_const_value*>& val = value->get_map();
265 map<t_const_value*, t_const_value*>::const_iterator v_iter;
266 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
267 t_type* field_type = NULL;
268 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
269 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
270 field_type = (*f_iter)->get_type();
273 if (field_type == NULL) {
274 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
276 string val = render_const_value(out, name, field_type, v_iter->second);
277 indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
278 indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
280 out << endl;
281 } else if (type->is_map()) {
282 t_type* ktype = ((t_map*)type)->get_key_type();
283 t_type* vtype = ((t_map*)type)->get_val_type();
284 const map<t_const_value*, t_const_value*>& val = value->get_map();
285 map<t_const_value*, t_const_value*>::const_iterator v_iter;
286 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
287 string key = render_const_value(out, name, ktype, v_iter->first);
288 string val = render_const_value(out, name, vtype, v_iter->second);
289 indent(out) << name << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
291 out << endl;
292 } else if (type->is_list()) {
293 t_type* etype = ((t_list*)type)->get_elem_type();
294 const vector<t_const_value*>& val = value->get_list();
295 vector<t_const_value*>::const_iterator v_iter;
296 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
297 string val = render_const_value(out, name, etype, *v_iter);
298 indent(out) << name << ".push_back(" << val << ");" << endl;
300 out << endl;
301 } else if (type->is_set()) {
302 t_type* etype = ((t_set*)type)->get_elem_type();
303 const vector<t_const_value*>& val = value->get_list();
304 vector<t_const_value*>::const_iterator v_iter;
305 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
306 string val = render_const_value(out, name, etype, *v_iter);
307 indent(out) << name << ".insert(" << val << ");" << endl;
309 out << endl;
316 string t_cpp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
317 std::ostringstream render;
319 if (type->is_base_type()) {
320 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
321 switch (tbase) {
322 case t_base_type::TYPE_STRING:
323 render << "\"" + value->get_string() + "\"";
324 break;
325 case t_base_type::TYPE_BOOL:
326 render << ((value->get_integer() > 0) ? "true" : "false");
327 break;
328 case t_base_type::TYPE_BYTE:
329 case t_base_type::TYPE_I16:
330 case t_base_type::TYPE_I32:
331 case t_base_type::TYPE_I64:
332 render << value->get_integer();
333 break;
334 case t_base_type::TYPE_DOUBLE:
335 if (value->get_type() == t_const_value::CV_INTEGER) {
336 render << value->get_integer();
337 } else {
338 render << value->get_double();
340 break;
341 default:
342 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
344 } else if (type->is_enum()) {
345 render << "(" << type_name(type) << ")" << value->get_integer();
346 } else {
347 string t = tmp("tmp");
348 indent(out) << type_name(type) << " " << t << ";" << endl;
349 print_const_value(out, t, type, value);
350 render << t;
353 return render.str();
357 * Generates a struct definition for a thrift data type. This is a class
358 * with data members and a read/write() function, plus a mirroring isset
359 * inner class.
361 * @param tstruct The struct definition
363 void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) {
364 generate_struct_definition(f_types_, tstruct, is_exception);
365 generate_struct_fingerprint(f_types_impl_, tstruct, true);
366 generate_local_reflection(f_types_, tstruct, false);
367 generate_local_reflection(f_types_impl_, tstruct, true);
368 generate_local_reflection_pointer(f_types_impl_, tstruct);
369 generate_struct_reader(f_types_impl_, tstruct);
370 generate_struct_writer(f_types_impl_, tstruct);
374 * Writes the struct definition into the header file
376 * @param out Output stream
377 * @param tstruct The struct
379 void t_cpp_generator::generate_struct_definition(ofstream& out,
380 t_struct* tstruct,
381 bool is_exception,
382 bool pointers,
383 bool read,
384 bool write) {
385 string extends = "";
386 if (is_exception) {
387 extends = " : public facebook::thrift::TException";
390 // Open struct def
391 out <<
392 indent() << "class " << tstruct->get_name() << extends << " {" << endl <<
393 indent() << " public:" << endl <<
394 endl;
395 indent_up();
397 // Put the fingerprint up top for all to see.
398 generate_struct_fingerprint(out, tstruct, false);
400 // Get members
401 vector<t_field*>::const_iterator m_iter;
402 const vector<t_field*>& members = tstruct->get_members();
404 if (!pointers) {
405 // Default constructor
406 indent(out) <<
407 tstruct->get_name() << "()";
409 bool init_ctor = false;
411 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
412 t_type* t = get_true_type((*m_iter)->get_type());
413 if (t->is_base_type()) {
414 string dval;
415 if (t->is_enum()) {
416 dval += "(" + type_name(t) + ")";
418 dval += t->is_string() ? "\"\"" : "0";
419 t_const_value* cv = (*m_iter)->get_value();
420 if (cv != NULL) {
421 dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
423 if (!init_ctor) {
424 init_ctor = true;
425 out << " : ";
426 out << (*m_iter)->get_name() << "(" << dval << ")";
427 } else {
428 out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
432 out << " {" << endl;
433 indent_up();
434 // TODO(dreiss): When everything else in Thrift is perfect,
435 // do more of these in the initializer list.
436 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
437 t_type* t = get_true_type((*m_iter)->get_type());
439 if (!t->is_base_type()) {
440 t_const_value* cv = (*m_iter)->get_value();
441 if (cv != NULL) {
442 print_const_value(out, (*m_iter)->get_name(), t, cv);
446 scope_down(out);
449 out <<
450 endl <<
451 indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
453 // Pointer to this structure's reflection local typespec.
454 if (gen_dense_) {
455 indent(out) <<
456 "static facebook::thrift::reflection::local::TypeSpec* local_reflection;" <<
457 endl << endl;
460 // Declare all fields
461 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
462 indent(out) <<
463 declare_field(*m_iter, false, pointers && !(*m_iter)->get_type()->is_xception(), !read) << endl;
466 // Isset struct has boolean fields, but only for non-required fields.
467 bool has_nonrequired_fields = false;
468 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
469 if ((*m_iter)->get_req() != t_field::T_REQUIRED)
470 has_nonrequired_fields = true;
473 if (has_nonrequired_fields && (!pointers || read)) {
474 out <<
475 endl <<
476 indent() << "struct __isset {" << endl;
477 indent_up();
479 indent(out) <<
480 "__isset() : ";
481 bool first = true;
482 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
483 if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
484 continue;
486 if (first) {
487 first = false;
488 out <<
489 (*m_iter)->get_name() << "(false)";
490 } else {
491 out <<
492 ", " << (*m_iter)->get_name() << "(false)";
495 out << " {}" << endl;
497 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
498 if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
499 indent(out) <<
500 "bool " << (*m_iter)->get_name() << ";" << endl;
504 indent_down();
505 indent(out) <<
506 "} __isset;" << endl;
509 out << endl;
511 if (!pointers) {
512 // Generate an equality testing operator. Make it inline since the compiler
513 // will do a better job than we would when deciding whether to inline it.
514 out <<
515 indent() << "bool operator == (const " << tstruct->get_name() << " & rhs) const" << endl;
516 scope_up(out);
517 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
518 // Most existing Thrift code does not use isset or optional/required,
519 // so we treat "default" fields as required.
520 if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
521 out <<
522 indent() << "if (!(" << (*m_iter)->get_name()
523 << " == rhs." << (*m_iter)->get_name() << "))" << endl <<
524 indent() << " return false;" << endl;
525 } else {
526 out <<
527 indent() << "if (__isset." << (*m_iter)->get_name()
528 << " != rhs.__isset." << (*m_iter)->get_name() << ")" << endl <<
529 indent() << " return false;" << endl <<
530 indent() << "else if (__isset." << (*m_iter)->get_name() << " && !("
531 << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name()
532 << "))" << endl <<
533 indent() << " return false;" << endl;
536 indent(out) << "return true;" << endl;
537 scope_down(out);
538 out <<
539 indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" << endl <<
540 indent() << " return !(*this == rhs);" << endl <<
541 indent() << "}" << endl << endl;
543 if (read) {
544 out <<
545 indent() << "uint32_t read(facebook::thrift::protocol::TProtocol* iprot);" << endl;
547 if (write) {
548 out <<
549 indent() << "uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const;" << endl;
551 out << endl;
553 indent_down();
554 indent(out) <<
555 "};" << endl <<
556 endl;
560 * Writes the fingerprint of a struct to either the header or implementation.
562 * @param out Output stream
563 * @param tstruct The struct
565 void t_cpp_generator::generate_struct_fingerprint(ofstream& out,
566 t_struct* tstruct,
567 bool is_definition) {
568 string stat, nspace, comment;
569 if (is_definition) {
570 stat = "";
571 nspace = tstruct->get_name() + "::";
572 comment = " ";
573 } else {
574 stat = "static ";
575 nspace = "";
576 comment = "; // ";
579 if (tstruct->has_fingerprint()) {
580 out <<
581 indent() << stat << "const char* " << nspace
582 << "ascii_fingerprint" << comment << "= \"" <<
583 tstruct->get_ascii_fingerprint() << "\";" << endl <<
584 indent() << stat << "const uint8_t " << nspace <<
585 "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {";
586 char* comma = "";
587 for (int i = 0; i < t_type::fingerprint_len; i++) {
588 out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]);
589 comma = ",";
591 out << "};" << endl << endl;
596 * Writes the local reflection of a type (either declaration or definition).
598 void t_cpp_generator::generate_local_reflection(std::ofstream& out,
599 t_type* ttype,
600 bool is_definition) {
601 if (!gen_dense_) {
602 return;
604 ttype = get_true_type(ttype);
605 assert(ttype->has_fingerprint());
606 string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl");
607 // Note that we have generated this fingerprint. If we already did, bail out.
608 if (!reflected_fingerprints_.insert(key).second) {
609 return;
611 // Let each program handle its own structures.
612 if (ttype->get_program() != NULL && ttype->get_program() != program_) {
613 return;
616 // Do dependencies.
617 if (ttype->is_list()) {
618 generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition);
619 } else if (ttype->is_set()) {
620 generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition);
621 } else if (ttype->is_map()) {
622 generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition);
623 generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition);
624 } else if (ttype->is_struct() || ttype->is_xception()) {
625 // Hacky hacky. For efficiency and convenience, we need a dummy "T_STOP"
626 // type at the end of our typespec array. Unfortunately, there is no
627 // T_STOP type, so we use the global void type, and special case it when
628 // generating its typespec.
630 const vector<t_field*>& members = ((t_struct*)ttype)->get_members();
631 vector<t_field*>::const_iterator m_iter;
632 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
633 generate_local_reflection(out, (**m_iter).get_type(), is_definition);
635 generate_local_reflection(out, g_type_void, is_definition);
637 // For definitions of structures, do the arrays of metas and field specs also.
638 if (is_definition) {
639 out <<
640 indent() << "facebook::thrift::reflection::local::FieldMeta" << endl <<
641 indent() << local_reflection_name("metas", ttype) <<"[] = {" << endl;
642 indent_up();
643 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
644 indent(out) << "{ " << (*m_iter)->get_key() << ", " <<
645 (((*m_iter)->get_req() == t_field::T_OPTIONAL) ? "true" : "false") <<
646 " }," << endl;
648 // Zero for the T_STOP marker.
649 indent(out) << "{ 0, false }" << endl << "};" << endl;
650 indent_down();
652 out <<
653 indent() << "facebook::thrift::reflection::local::TypeSpec*" << endl <<
654 indent() << local_reflection_name("specs", ttype) <<"[] = {" << endl;
655 indent_up();
656 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
657 indent(out) << "&" <<
658 local_reflection_name("typespec", (*m_iter)->get_type()) << "," << endl;
660 indent(out) << "&" <<
661 local_reflection_name("typespec", g_type_void) << "," << endl;
662 indent_down();
663 indent(out) << "};" << endl;
667 out <<
668 indent() << "// " << ttype->get_fingerprint_material() << endl <<
669 indent() << (is_definition ? "" : "extern ") <<
670 "facebook::thrift::reflection::local::TypeSpec" << endl <<
671 local_reflection_name("typespec", ttype) <<
672 (is_definition ? "(" : ";") << endl;
674 if (!is_definition) {
675 out << endl;
676 return;
679 indent_up();
681 if (ttype->is_void()) {
682 indent(out) << "facebook::thrift::protocol::T_STOP";
683 } else {
684 indent(out) << type_to_enum(ttype);
687 if (ttype->is_struct()) {
688 out << "," << endl <<
689 indent() << type_name(ttype) << "::binary_fingerprint," << endl <<
690 indent() << local_reflection_name("metas", ttype) << "," << endl <<
691 indent() << local_reflection_name("specs", ttype);
692 } else if (ttype->is_list()) {
693 out << "," << endl <<
694 indent() << "&" << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type()) << "," << endl <<
695 indent() << "NULL";
696 } else if (ttype->is_set()) {
697 out << "," << endl <<
698 indent() << "&" << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type()) << "," << endl <<
699 indent() << "NULL";
700 } else if (ttype->is_map()) {
701 out << "," << endl <<
702 indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type()) << "," << endl <<
703 indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type());
706 out << ");" << endl << endl;
708 indent_down();
712 * Writes the structure's static pointer to its local reflection typespec
713 * into the implementation file.
715 void t_cpp_generator::generate_local_reflection_pointer(std::ofstream& out,
716 t_type* ttype) {
717 if (!gen_dense_) {
718 return;
720 indent(out) <<
721 "facebook::thrift::reflection::local::TypeSpec* " <<
722 ttype->get_name() << "::local_reflection = " << endl <<
723 indent() << " &" << local_reflection_name("typespec", ttype) << ";" <<
724 endl << endl;
728 * Makes a helper function to gen a struct reader.
730 * @param out Stream to write to
731 * @param tstruct The struct
733 void t_cpp_generator::generate_struct_reader(ofstream& out,
734 t_struct* tstruct,
735 bool pointers) {
736 indent(out) <<
737 "uint32_t " << tstruct->get_name() << "::read(facebook::thrift::protocol::TProtocol* iprot) {" << endl;
738 indent_up();
740 const vector<t_field*>& fields = tstruct->get_members();
741 vector<t_field*>::const_iterator f_iter;
743 // Declare stack tmp variables
744 out <<
745 endl <<
746 indent() << "uint32_t xfer = 0;" << endl <<
747 indent() << "std::string fname;" << endl <<
748 indent() << "facebook::thrift::protocol::TType ftype;" << endl <<
749 indent() << "int16_t fid;" << endl <<
750 endl <<
751 indent() << "xfer += iprot->readStructBegin(fname);" << endl <<
752 endl <<
753 indent() << "using facebook::thrift::protocol::TProtocolException;" << endl <<
754 endl;
756 // Required variables aren't in __isset, so we need tmp vars to check them.
757 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
758 if ((*f_iter)->get_req() == t_field::T_REQUIRED)
759 indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
761 out << endl;
764 // Loop over reading in fields
765 indent(out) <<
766 "while (true)" << endl;
767 scope_up(out);
769 // Read beginning field marker
770 indent(out) <<
771 "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
773 // Check for field STOP marker
774 out <<
775 indent() << "if (ftype == facebook::thrift::protocol::T_STOP) {" << endl <<
776 indent() << " break;" << endl <<
777 indent() << "}" << endl;
779 // Switch statement on the field we are reading
780 indent(out) <<
781 "switch (fid)" << endl;
783 scope_up(out);
785 // Generate deserialization code for known cases
786 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
787 indent(out) <<
788 "case " << (*f_iter)->get_key() << ":" << endl;
789 indent_up();
790 indent(out) <<
791 "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
792 indent_up();
794 const char *isset_prefix =
795 ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." : "isset_";
797 #if 0
798 // This code throws an exception if the same field is encountered twice.
799 // We've decided to leave it out for performance reasons.
800 // TODO(dreiss): Generate this code and "if" it out to make it easier
801 // for people recompiling thrift to include it.
802 out <<
803 indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl <<
804 indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
805 #endif
807 if (pointers && !(*f_iter)->get_type()->is_xception()) {
808 generate_deserialize_field(out, *f_iter, "(*(this->", "))");
809 } else {
810 generate_deserialize_field(out, *f_iter, "this->");
812 out <<
813 indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl;
814 indent_down();
815 out <<
816 indent() << "} else {" << endl <<
817 indent() << " xfer += iprot->skip(ftype);" << endl <<
818 // TODO(dreiss): Make this an option when thrift structs
819 // have a common base class.
820 // indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl <<
821 indent() << "}" << endl <<
822 indent() << "break;" << endl;
823 indent_down();
826 // In the default case we skip the field
827 out <<
828 indent() << "default:" << endl <<
829 indent() << " xfer += iprot->skip(ftype);" << endl <<
830 indent() << " break;" << endl;
832 scope_down(out);
834 // Read field end marker
835 indent(out) <<
836 "xfer += iprot->readFieldEnd();" << endl;
838 scope_down(out);
840 out <<
841 endl <<
842 indent() << "xfer += iprot->readStructEnd();" << endl;
844 // Throw if any required fields are missing.
845 // We do this after reading the struct end so that
846 // there might possibly be a chance of continuing.
847 out << endl;
848 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
849 if ((*f_iter)->get_req() == t_field::T_REQUIRED)
850 out <<
851 indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
852 indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
855 indent(out) << "return xfer;" << endl;
857 indent_down();
858 indent(out) <<
859 "}" << endl << endl;
863 * Generates the write function.
865 * @param out Stream to write to
866 * @param tstruct The struct
868 void t_cpp_generator::generate_struct_writer(ofstream& out,
869 t_struct* tstruct,
870 bool pointers) {
871 string name = tstruct->get_name();
872 const vector<t_field*>& fields = tstruct->get_members();
873 vector<t_field*>::const_iterator f_iter;
875 indent(out) <<
876 "uint32_t " << tstruct->get_name() << "::write(facebook::thrift::protocol::TProtocol* oprot) const {" << endl;
877 indent_up();
879 out <<
880 indent() << "uint32_t xfer = 0;" << endl;
882 indent(out) <<
883 "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
884 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
885 if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
886 indent(out) << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
887 indent_up();
889 // Write field header
890 out <<
891 indent() << "xfer += oprot->writeFieldBegin(" <<
892 "\"" << (*f_iter)->get_name() << "\", " <<
893 type_to_enum((*f_iter)->get_type()) << ", " <<
894 (*f_iter)->get_key() << ");" << endl;
895 // Write field contents
896 if (pointers) {
897 generate_serialize_field(out, *f_iter, "(*(this->", "))");
898 } else {
899 generate_serialize_field(out, *f_iter, "this->");
901 // Write field closer
902 indent(out) <<
903 "xfer += oprot->writeFieldEnd();" << endl;
904 if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
905 indent_down();
906 indent(out) << '}' << endl;
910 // Write the struct map
911 out <<
912 indent() << "xfer += oprot->writeFieldStop();" << endl <<
913 indent() << "xfer += oprot->writeStructEnd();" << endl <<
914 indent() << "return xfer;" << endl;
916 indent_down();
917 indent(out) <<
918 "}" << endl <<
919 endl;
923 * Struct writer for result of a function, which can have only one of its
924 * fields set and does a conditional if else look up into the __isset field
925 * of the struct.
927 * @param out Output stream
928 * @param tstruct The result struct
930 void t_cpp_generator::generate_struct_result_writer(ofstream& out,
931 t_struct* tstruct,
932 bool pointers) {
933 string name = tstruct->get_name();
934 const vector<t_field*>& fields = tstruct->get_members();
935 vector<t_field*>::const_iterator f_iter;
937 indent(out) <<
938 "uint32_t " << tstruct->get_name() << "::write(facebook::thrift::protocol::TProtocol* oprot) const {" << endl;
939 indent_up();
941 out <<
942 endl <<
943 indent() << "uint32_t xfer = 0;" << endl <<
944 endl;
946 indent(out) <<
947 "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
949 bool first = true;
950 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
951 if (first) {
952 first = false;
953 out <<
954 endl <<
955 indent() << "if ";
956 } else {
957 out <<
958 " else if ";
961 out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
963 indent_up();
965 // Write field header
966 out <<
967 indent() << "xfer += oprot->writeFieldBegin(" <<
968 "\"" << (*f_iter)->get_name() << "\", " <<
969 type_to_enum((*f_iter)->get_type()) << ", " <<
970 (*f_iter)->get_key() << ");" << endl;
971 // Write field contents
972 if (pointers) {
973 generate_serialize_field(out, *f_iter, "(*(this->", "))");
974 } else {
975 generate_serialize_field(out, *f_iter, "this->");
977 // Write field closer
978 indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
980 indent_down();
981 indent(out) << "}";
984 // Write the struct map
985 out <<
986 endl <<
987 indent() << "xfer += oprot->writeFieldStop();" << endl <<
988 indent() << "xfer += oprot->writeStructEnd();" << endl <<
989 indent() << "return xfer;" << endl;
991 indent_down();
992 indent(out) <<
993 "}" << endl <<
994 endl;
998 * Generates a thrift service. In C++, this comprises an entirely separate
999 * header and source file. The header file defines the methods and includes
1000 * the data types defined in the main header file, and the implementation
1001 * file contains implementations of the basic printer and default interfaces.
1003 * @param tservice The service definition
1005 void t_cpp_generator::generate_service(t_service* tservice) {
1006 string svcname = tservice->get_name();
1008 // Make output files
1009 string f_header_name = get_out_dir()+svcname+".h";
1010 f_header_.open(f_header_name.c_str());
1012 // Print header file includes
1013 f_header_ <<
1014 autogen_comment();
1015 f_header_ <<
1016 "#ifndef " << svcname << "_H" << endl <<
1017 "#define " << svcname << "_H" << endl <<
1018 endl <<
1019 "#include <TProcessor.h>" << endl <<
1020 "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
1021 "_types.h\"" << endl;
1023 t_service* extends_service = tservice->get_extends();
1024 if (extends_service != NULL) {
1025 f_header_ <<
1026 "#include \"" << get_include_prefix(*(extends_service->get_program())) <<
1027 extends_service->get_name() << ".h\"" << endl;
1030 f_header_ <<
1031 endl <<
1032 ns_open_ << endl <<
1033 endl;
1035 // Service implementation file includes
1036 string f_service_name = get_out_dir()+svcname+".cpp";
1037 f_service_.open(f_service_name.c_str());
1038 f_service_ <<
1039 autogen_comment();
1040 f_service_ <<
1041 "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" <<
1042 endl <<
1043 endl <<
1044 ns_open_ << endl <<
1045 endl;
1047 // Generate all the components
1048 generate_service_interface(tservice);
1049 generate_service_null(tservice);
1050 generate_service_helpers(tservice);
1051 generate_service_client(tservice);
1052 generate_service_processor(tservice);
1053 generate_service_multiface(tservice);
1054 generate_service_skeleton(tservice);
1056 // Close the namespace
1057 f_service_ <<
1058 ns_close_ << endl <<
1059 endl;
1060 f_header_ <<
1061 ns_close_ << endl <<
1062 endl;
1063 f_header_ <<
1064 "#endif" << endl;
1066 // Close the files
1067 f_service_.close();
1068 f_header_.close();
1072 * Generates helper functions for a service. Basically, this generates types
1073 * for all the arguments and results to functions.
1075 * @param tservice The service to generate a header definition for
1077 void t_cpp_generator::generate_service_helpers(t_service* tservice) {
1078 vector<t_function*> functions = tservice->get_functions();
1079 vector<t_function*>::iterator f_iter;
1080 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1081 t_struct* ts = (*f_iter)->get_arglist();
1082 string name_orig = ts->get_name();
1084 ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
1085 generate_struct_definition(f_header_, ts, false);
1086 generate_struct_reader(f_service_, ts);
1087 generate_struct_writer(f_service_, ts);
1088 ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
1089 generate_struct_definition(f_header_, ts, false, true, false, true);
1090 generate_struct_writer(f_service_, ts, true);
1091 ts->set_name(name_orig);
1093 generate_function_helpers(tservice, *f_iter);
1096 generate_service_limited_reflector(tservice);
1100 * Generates a service interface definition.
1102 * @param tservice The service to generate a header definition for
1104 void t_cpp_generator::generate_service_interface(t_service* tservice) {
1105 string extends = "";
1106 if (tservice->get_extends() != NULL) {
1107 extends = " : virtual public " + type_name(tservice->get_extends()) + "If";
1109 f_header_ <<
1110 "class " << service_name_ << "If" << extends << " {" << endl <<
1111 " public:" << endl;
1112 indent_up();
1113 f_header_ <<
1114 indent() << "virtual ~" << service_name_ << "If() {}" << endl;
1116 f_header_ <<
1117 indent() << "static void getStaticLimitedReflection" <<
1118 "(facebook::thrift::reflection::limited::Service & _return);" << endl;
1119 // TODO(dreiss): Uncomment and test this if we decide we need
1120 // a virtual function with this effect.
1121 //f_header_ <<
1122 // indent() << "virtual void getVirtualLimitedReflection" <<
1123 // "(facebook::thrift::reflection::limited::Service & _return) ";
1124 //scope_up(f_header_);
1125 //f_header_ <<
1126 // indent() << "getStaticLimitedReflection(_return);" << endl;
1127 //scope_down(f_header_);
1129 vector<t_function*> functions = tservice->get_functions();
1130 vector<t_function*>::iterator f_iter;
1131 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1132 f_header_ <<
1133 indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
1135 indent_down();
1136 f_header_ <<
1137 "};" << endl << endl;
1141 * Generates a null implementation of the service.
1143 * @param tservice The service to generate a header definition for
1145 void t_cpp_generator::generate_service_null(t_service* tservice) {
1146 string extends = "";
1147 if (tservice->get_extends() != NULL) {
1148 extends = " , virtual public " + type_name(tservice->get_extends()) + "Null";
1150 f_header_ <<
1151 "class " << service_name_ << "Null : virtual public " << service_name_ << "If" << extends << " {" << endl <<
1152 " public:" << endl;
1153 indent_up();
1154 f_header_ <<
1155 indent() << "virtual ~" << service_name_ << "Null() {}" << endl;
1156 vector<t_function*> functions = tservice->get_functions();
1157 vector<t_function*>::iterator f_iter;
1158 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1159 f_header_ <<
1160 indent() << function_signature(*f_iter) << " {" << endl;
1161 indent_up();
1162 t_type* returntype = (*f_iter)->get_returntype();
1163 if (returntype->is_void()) {
1164 f_header_ <<
1165 indent() << "return;" << endl;
1166 } else {
1167 if (is_complex_type(returntype)) {
1168 f_header_ <<
1169 indent() << "return;" << endl;
1170 } else {
1171 t_field returnfield(returntype, "_return");
1172 f_header_ <<
1173 indent() << declare_field(&returnfield, true) << endl <<
1174 indent() << "return _return;" << endl;
1177 indent_down();
1178 f_header_ <<
1179 indent() << "}" << endl;
1181 indent_down();
1182 f_header_ <<
1183 "};" << endl << endl;
1188 * Generates a multiface, which is a single server that just takes a set
1189 * of objects implementing the interface and calls them all, returning the
1190 * value of the last one to be called.
1192 * @param tservice The service to generate a multiserver for.
1194 void t_cpp_generator::generate_service_multiface(t_service* tservice) {
1195 // Generate the dispatch methods
1196 vector<t_function*> functions = tservice->get_functions();
1197 vector<t_function*>::iterator f_iter;
1199 string extends = "";
1200 string extends_multiface = "";
1201 if (tservice->get_extends() != NULL) {
1202 extends = type_name(tservice->get_extends());
1203 extends_multiface = ", public " + extends + "Multiface";
1206 string list_type = string("std::vector<boost::shared_ptr<") + service_name_ + "If> >";
1208 // Generate the header portion
1209 f_header_ <<
1210 "class " << service_name_ << "Multiface : " <<
1211 "virtual public " << service_name_ << "If" <<
1212 extends_multiface << " {" << endl <<
1213 " public:" << endl;
1214 indent_up();
1215 f_header_ <<
1216 indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
1217 if (!extends.empty()) {
1218 f_header_ <<
1219 indent() << " std::vector<boost::shared_ptr<" + service_name_ + "If> >::iterator iter;" << endl <<
1220 indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl <<
1221 indent() << " " << extends << "Multiface::add(*iter);" << endl <<
1222 indent() << " }" << endl;
1224 f_header_ <<
1225 indent() << "}" << endl <<
1226 indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl;
1227 indent_down();
1229 // Protected data members
1230 f_header_ <<
1231 " protected:" << endl;
1232 indent_up();
1233 f_header_ <<
1234 indent() << list_type << " ifaces_;" << endl <<
1235 indent() << service_name_ << "Multiface() {}" << endl <<
1236 indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) {" << endl;
1237 if (!extends.empty()) {
1238 f_header_ <<
1239 indent() << " " << extends << "Multiface::add(iface);" << endl;
1241 f_header_ <<
1242 indent() << " ifaces_.push_back(iface);" << endl <<
1243 indent() << "}" << endl;
1244 indent_down();
1246 f_header_ <<
1247 indent() << " public:" << endl;
1248 indent_up();
1250 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1251 t_struct* arglist = (*f_iter)->get_arglist();
1252 const vector<t_field*>& args = arglist->get_members();
1253 vector<t_field*>::const_iterator a_iter;
1255 string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
1256 bool first = true;
1257 if (is_complex_type((*f_iter)->get_returntype())) {
1258 call += "_return";
1259 first = false;
1261 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
1262 if (first) {
1263 first = false;
1264 } else {
1265 call += ", ";
1267 call += (*a_iter)->get_name();
1269 call += ")";
1271 f_header_ <<
1272 indent() << function_signature(*f_iter) << " {" << endl;
1273 indent_up();
1274 f_header_ <<
1275 indent() << "uint32_t sz = ifaces_.size();" << endl <<
1276 indent() << "for (uint32_t i = 0; i < sz; ++i) {" << endl;
1277 if (!(*f_iter)->get_returntype()->is_void()) {
1278 f_header_ <<
1279 indent() << " if (i == sz - 1) {" << endl;
1280 if (is_complex_type((*f_iter)->get_returntype())) {
1281 f_header_ <<
1282 indent() << " " << call << ";" << endl <<
1283 indent() << " return;" << endl;
1284 } else {
1285 f_header_ <<
1286 indent() << " return " << call << ";" << endl;
1288 f_header_ <<
1289 indent() << " } else {" << endl <<
1290 indent() << " " << call << ";" << endl <<
1291 indent() << " }" << endl;
1292 } else {
1293 f_header_ <<
1294 indent() << " " << call << ";" << endl;
1297 f_header_ <<
1298 indent() << "}" << endl;
1300 indent_down();
1301 f_header_ <<
1302 indent() << "}" << endl <<
1303 endl;
1306 indent_down();
1307 f_header_ <<
1308 indent() << "};" << endl <<
1309 endl;
1313 * Generates a service client definition.
1315 * @param tservice The service to generate a server for.
1317 void t_cpp_generator::generate_service_client(t_service* tservice) {
1318 string extends = "";
1319 string extends_client = "";
1320 if (tservice->get_extends() != NULL) {
1321 extends = type_name(tservice->get_extends());
1322 extends_client = ", public " + extends + "Client";
1325 // Generate the header portion
1326 f_header_ <<
1327 "class " << service_name_ << "Client : " <<
1328 "virtual public " << service_name_ << "If" <<
1329 extends_client << " {" << endl <<
1330 " public:" << endl;
1332 indent_up();
1333 f_header_ <<
1334 indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> prot) :" << endl;
1335 if (extends.empty()) {
1336 f_header_ <<
1337 indent() << " piprot_(prot)," << endl <<
1338 indent() << " poprot_(prot) {" << endl <<
1339 indent() << " iprot_ = prot.get();" << endl <<
1340 indent() << " oprot_ = prot.get();" << endl <<
1341 indent() << "}" << endl;
1342 } else {
1343 f_header_ <<
1344 indent() << " " << extends << "Client(prot, prot) {}" << endl;
1347 f_header_ <<
1348 indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) :" << endl;
1349 if (extends.empty()) {
1350 f_header_ <<
1351 indent() << " piprot_(iprot)," << endl <<
1352 indent() << " poprot_(oprot) {" << endl <<
1353 indent() << " iprot_ = iprot.get();" << endl <<
1354 indent() << " oprot_ = oprot.get();" << endl <<
1355 indent() << "}" << endl;
1356 } else {
1357 f_header_ <<
1358 indent() << " " << extends << "Client(iprot, oprot) {}" << endl;
1361 vector<t_function*> functions = tservice->get_functions();
1362 vector<t_function*>::const_iterator f_iter;
1363 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1364 t_function send_function(g_type_void,
1365 string("send_") + (*f_iter)->get_name(),
1366 (*f_iter)->get_arglist());
1367 indent(f_header_) << function_signature(*f_iter) << ";" << endl;
1368 indent(f_header_) << function_signature(&send_function) << ";" << endl;
1369 if (!(*f_iter)->is_async()) {
1370 t_struct noargs(program_);
1371 t_function recv_function((*f_iter)->get_returntype(),
1372 string("recv_") + (*f_iter)->get_name(),
1373 &noargs);
1374 indent(f_header_) << function_signature(&recv_function) << ";" << endl;
1377 indent_down();
1379 if (extends.empty()) {
1380 f_header_ <<
1381 " protected:" << endl;
1382 indent_up();
1383 f_header_ <<
1384 indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot_;" << endl <<
1385 indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot_;" << endl <<
1386 indent() << "facebook::thrift::protocol::TProtocol* iprot_;" << endl <<
1387 indent() << "facebook::thrift::protocol::TProtocol* oprot_;" << endl;
1388 indent_down();
1391 f_header_ <<
1392 "};" << endl <<
1393 endl;
1395 string scope = service_name_ + "Client::";
1397 // Generate client method implementations
1398 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1399 string funname = (*f_iter)->get_name();
1401 // Open function
1402 indent(f_service_) <<
1403 function_signature(*f_iter, scope) << endl;
1404 scope_up(f_service_);
1405 indent(f_service_) <<
1406 "send_" << funname << "(";
1408 // Get the struct of function call params
1409 t_struct* arg_struct = (*f_iter)->get_arglist();
1411 // Declare the function arguments
1412 const vector<t_field*>& fields = arg_struct->get_members();
1413 vector<t_field*>::const_iterator fld_iter;
1414 bool first = true;
1415 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1416 if (first) {
1417 first = false;
1418 } else {
1419 f_service_ << ", ";
1421 f_service_ << (*fld_iter)->get_name();
1423 f_service_ << ");" << endl;
1425 if (!(*f_iter)->is_async()) {
1426 f_service_ << indent();
1427 if (!(*f_iter)->get_returntype()->is_void()) {
1428 if (is_complex_type((*f_iter)->get_returntype())) {
1429 f_service_ << "recv_" << funname << "(_return);" << endl;
1430 } else {
1431 f_service_ << "return recv_" << funname << "();" << endl;
1433 } else {
1434 f_service_ <<
1435 "recv_" << funname << "();" << endl;
1438 scope_down(f_service_);
1439 f_service_ << endl;
1441 // Function for sending
1442 t_function send_function(g_type_void,
1443 string("send_") + (*f_iter)->get_name(),
1444 (*f_iter)->get_arglist());
1446 // Open the send function
1447 indent(f_service_) <<
1448 function_signature(&send_function, scope) << endl;
1449 scope_up(f_service_);
1451 // Function arguments and results
1452 string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs";
1453 string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult";
1455 // Serialize the request
1456 f_service_ <<
1457 indent() << "int32_t cseqid = 0;" << endl <<
1458 indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl <<
1459 endl <<
1460 indent() << argsname << " args;" << endl;
1462 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1463 f_service_ <<
1464 indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl;
1467 f_service_ <<
1468 indent() << "args.write(oprot_);" << endl <<
1469 endl <<
1470 indent() << "oprot_->writeMessageEnd();" << endl <<
1471 indent() << "oprot_->getTransport()->flush();" << endl <<
1472 indent() << "oprot_->getTransport()->writeEnd();" << endl;
1474 scope_down(f_service_);
1475 f_service_ << endl;
1477 // Generate recv function only if not an async function
1478 if (!(*f_iter)->is_async()) {
1479 t_struct noargs(program_);
1480 t_function recv_function((*f_iter)->get_returntype(),
1481 string("recv_") + (*f_iter)->get_name(),
1482 &noargs);
1483 // Open function
1484 indent(f_service_) <<
1485 function_signature(&recv_function, scope) << endl;
1486 scope_up(f_service_);
1488 f_service_ <<
1489 endl <<
1490 indent() << "int32_t rseqid = 0;" << endl <<
1491 indent() << "std::string fname;" << endl <<
1492 indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
1493 endl <<
1494 indent() << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl <<
1495 indent() << "if (mtype == facebook::thrift::protocol::T_EXCEPTION) {" << endl <<
1496 indent() << " facebook::thrift::TApplicationException x;" << endl <<
1497 indent() << " x.read(iprot_);" << endl <<
1498 indent() << " iprot_->readMessageEnd();" << endl <<
1499 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1500 indent() << " throw x;" << endl <<
1501 indent() << "}" << endl <<
1502 indent() << "if (mtype != facebook::thrift::protocol::T_REPLY) {" << endl <<
1503 indent() << " iprot_->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1504 indent() << " iprot_->readMessageEnd();" << endl <<
1505 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1506 indent() << " throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1507 indent() << "}" << endl <<
1508 indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl <<
1509 indent() << " iprot_->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1510 indent() << " iprot_->readMessageEnd();" << endl <<
1511 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1512 indent() << " throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::WRONG_METHOD_NAME);" << endl <<
1513 indent() << "}" << endl;
1515 if (!(*f_iter)->get_returntype()->is_void() &&
1516 !is_complex_type((*f_iter)->get_returntype())) {
1517 t_field returnfield((*f_iter)->get_returntype(), "_return");
1518 f_service_ <<
1519 indent() << declare_field(&returnfield) << endl;
1522 f_service_ <<
1523 indent() << resultname << " result;" << endl;
1525 if (!(*f_iter)->get_returntype()->is_void()) {
1526 f_service_ <<
1527 indent() << "result.success = &_return;" << endl;
1530 f_service_ <<
1531 indent() << "result.read(iprot_);" << endl <<
1532 indent() << "iprot_->readMessageEnd();" << endl <<
1533 indent() << "iprot_->getTransport()->readEnd();" << endl <<
1534 endl;
1536 // Careful, only look for _result if not a void function
1537 if (!(*f_iter)->get_returntype()->is_void()) {
1538 if (is_complex_type((*f_iter)->get_returntype())) {
1539 f_service_ <<
1540 indent() << "if (result.__isset.success) {" << endl <<
1541 indent() << " // _return pointer has now been filled" << endl <<
1542 indent() << " return;" << endl <<
1543 indent() << "}" << endl;
1544 } else {
1545 f_service_ <<
1546 indent() << "if (result.__isset.success) {" << endl <<
1547 indent() << " return _return;" << endl <<
1548 indent() << "}" << endl;
1552 t_struct* xs = (*f_iter)->get_xceptions();
1553 const std::vector<t_field*>& xceptions = xs->get_members();
1554 vector<t_field*>::const_iterator x_iter;
1555 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1556 f_service_ <<
1557 indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
1558 indent() << " throw result." << (*x_iter)->get_name() << ";" << endl <<
1559 indent() << "}" << endl;
1562 // We only get here if we are a void function
1563 if ((*f_iter)->get_returntype()->is_void()) {
1564 indent(f_service_) <<
1565 "return;" << endl;
1566 } else {
1567 f_service_ <<
1568 indent() << "throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1571 // Close function
1572 scope_down(f_service_);
1573 f_service_ << endl;
1579 * Generates a service server definition.
1581 * @param tservice The service to generate a server for.
1583 void t_cpp_generator::generate_service_processor(t_service* tservice) {
1584 // Generate the dispatch methods
1585 vector<t_function*> functions = tservice->get_functions();
1586 vector<t_function*>::iterator f_iter;
1588 string extends = "";
1589 string extends_processor = "";
1590 if (tservice->get_extends() != NULL) {
1591 extends = type_name(tservice->get_extends());
1592 extends_processor = ", public " + extends + "Processor";
1595 // Generate the header portion
1596 f_header_ <<
1597 "class " << service_name_ << "Processor : " <<
1598 "virtual public facebook::thrift::TProcessor" <<
1599 extends_processor << " {" << endl;
1601 // Protected data members
1602 f_header_ <<
1603 " protected:" << endl;
1604 indent_up();
1605 f_header_ <<
1606 indent() << "boost::shared_ptr<" << service_name_ << "If> iface_;" << endl;
1607 f_header_ <<
1608 indent() << "virtual bool process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid);" << endl;
1609 indent_down();
1611 // Process function declarations
1612 f_header_ <<
1613 " private:" << endl;
1614 indent_up();
1615 f_header_ <<
1616 indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)> processMap_;" << endl;
1617 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1618 indent(f_header_) <<
1619 "void process_" << (*f_iter)->get_name() << "(int32_t seqid, facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot);" << endl;
1621 indent_down();
1623 indent_up();
1624 string declare_map = "";
1625 indent_up();
1627 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1628 declare_map += indent();
1629 declare_map += "processMap_[\"";
1630 declare_map += (*f_iter)->get_name();
1631 declare_map += "\"] = &";
1632 declare_map += service_name_;
1633 declare_map += "Processor::process_";
1634 declare_map += (*f_iter)->get_name();
1635 declare_map += ";\n";
1637 indent_down();
1639 f_header_ <<
1640 " public:" << endl <<
1641 indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface) :" << endl;
1642 if (extends.empty()) {
1643 f_header_ <<
1644 indent() << " iface_(iface) {" << endl;
1645 } else {
1646 f_header_ <<
1647 indent() << " " << extends << "Processor(iface)," << endl <<
1648 indent() << " iface_(iface) {" << endl;
1650 f_header_ <<
1651 declare_map <<
1652 indent() << "}" << endl <<
1653 endl <<
1654 indent() << "virtual bool process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot);" << endl <<
1655 indent() << "virtual ~" << service_name_ << "Processor() {}" << endl;
1656 indent_down();
1657 f_header_ <<
1658 "};" << endl << endl;
1660 // Generate the server implementation
1661 f_service_ <<
1662 "bool " << service_name_ << "Processor::process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot) {" << endl;
1663 indent_up();
1665 f_service_ <<
1666 endl <<
1667 indent() << "facebook::thrift::protocol::TProtocol* iprot = piprot.get();" << endl <<
1668 indent() << "facebook::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
1669 indent() << "std::string fname;" << endl <<
1670 indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
1671 indent() << "int32_t seqid;" << endl <<
1672 endl <<
1673 indent() << "iprot->readMessageBegin(fname, mtype, seqid);" << endl <<
1674 endl <<
1675 indent() << "if (mtype != facebook::thrift::protocol::T_CALL) {" << endl <<
1676 indent() << " iprot->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1677 indent() << " iprot->readMessageEnd();" << endl <<
1678 indent() << " iprot->getTransport()->readEnd();" << endl <<
1679 indent() << " facebook::thrift::TApplicationException x(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1680 indent() << " oprot->writeMessageBegin(fname, facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1681 indent() << " x.write(oprot);" << endl <<
1682 indent() << " oprot->writeMessageEnd();" << endl <<
1683 indent() << " oprot->getTransport()->flush();" << endl <<
1684 indent() << " oprot->getTransport()->writeEnd();" << endl <<
1685 indent() << " return true;" << endl <<
1686 indent() << "}" << endl <<
1687 endl <<
1688 indent() << "return process_fn(iprot, oprot, fname, seqid);" <<
1689 endl;
1691 indent_down();
1692 f_service_ <<
1693 indent() << "}" << endl <<
1694 endl;
1696 f_service_ <<
1697 "bool " << service_name_ << "Processor::process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid) {" << endl;
1698 indent_up();
1700 // HOT: member function pointer map
1701 f_service_ <<
1702 indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)>::iterator pfn;" << endl <<
1703 indent() << "pfn = processMap_.find(fname);" << endl <<
1704 indent() << "if (pfn == processMap_.end()) {" << endl;
1705 if (extends.empty()) {
1706 f_service_ <<
1707 indent() << " iprot->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1708 indent() << " iprot->readMessageEnd();" << endl <<
1709 indent() << " iprot->getTransport()->readEnd();" << endl <<
1710 indent() << " facebook::thrift::TApplicationException x(facebook::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: '\"+fname+\"'\");" << endl <<
1711 indent() << " oprot->writeMessageBegin(fname, facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1712 indent() << " x.write(oprot);" << endl <<
1713 indent() << " oprot->writeMessageEnd();" << endl <<
1714 indent() << " oprot->getTransport()->flush();" << endl <<
1715 indent() << " oprot->getTransport()->writeEnd();" << endl <<
1716 indent() << " return true;" << endl;
1717 } else {
1718 f_service_ <<
1719 indent() << " return " << extends << "Processor::process_fn(iprot, oprot, fname, seqid);" << endl;
1721 f_service_ <<
1722 indent() << "} else {" << endl <<
1723 indent() << " (this->*(pfn->second))(seqid, iprot, oprot);" << endl <<
1724 indent() << "}" << endl;
1726 // Read end of args field, the T_STOP, and the struct close
1727 f_service_ <<
1728 indent() << "return true;" << endl;
1730 indent_down();
1731 f_service_ <<
1732 "}" << endl <<
1733 endl;
1735 // Generate the process subfunctions
1736 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1737 generate_process_function(tservice, *f_iter);
1742 * Generates a struct and helpers for a function.
1744 * @param tfunction The function
1746 void t_cpp_generator::generate_function_helpers(t_service* tservice,
1747 t_function* tfunction) {
1748 if (tfunction->is_async()) {
1749 return;
1752 t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result");
1753 t_field success(tfunction->get_returntype(), "success", 0);
1754 if (!tfunction->get_returntype()->is_void()) {
1755 result.append(&success);
1758 t_struct* xs = tfunction->get_xceptions();
1759 const vector<t_field*>& fields = xs->get_members();
1760 vector<t_field*>::const_iterator f_iter;
1761 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1762 result.append(*f_iter);
1765 generate_struct_definition(f_header_, &result, false);
1766 generate_struct_reader(f_service_, &result);
1767 generate_struct_result_writer(f_service_, &result);
1769 result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
1770 generate_struct_definition(f_header_, &result, false, true, true, false);
1771 generate_struct_reader(f_service_, &result, true);
1776 * Generates a process function definition.
1778 * @param tfunction The function to write a dispatcher for
1780 void t_cpp_generator::generate_process_function(t_service* tservice,
1781 t_function* tfunction) {
1782 // Open function
1783 f_service_ <<
1784 "void " << tservice->get_name() << "Processor::" <<
1785 "process_" << tfunction->get_name() <<
1786 "(int32_t seqid, facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot)" << endl;
1787 scope_up(f_service_);
1789 string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
1790 string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
1792 f_service_ <<
1793 indent() << argsname << " args;" << endl <<
1794 indent() << "args.read(iprot);" << endl <<
1795 indent() << "iprot->readMessageEnd();" << endl <<
1796 indent() << "iprot->getTransport()->readEnd();" << endl <<
1797 endl;
1799 t_struct* xs = tfunction->get_xceptions();
1800 const std::vector<t_field*>& xceptions = xs->get_members();
1801 vector<t_field*>::const_iterator x_iter;
1803 // Declare result
1804 if (!tfunction->is_async()) {
1805 f_service_ <<
1806 indent() << resultname << " result;" << endl;
1809 // Try block for functions with exceptions
1810 f_service_ <<
1811 indent() << "try {" << endl;
1812 indent_up();
1814 // Generate the function call
1815 t_struct* arg_struct = tfunction->get_arglist();
1816 const std::vector<t_field*>& fields = arg_struct->get_members();
1817 vector<t_field*>::const_iterator f_iter;
1819 bool first = true;
1820 f_service_ << indent();
1821 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1822 if (is_complex_type(tfunction->get_returntype())) {
1823 first = false;
1824 f_service_ << "iface_->" << tfunction->get_name() << "(result.success";
1825 } else {
1826 f_service_ << "result.success = iface_->" << tfunction->get_name() << "(";
1828 } else {
1829 f_service_ <<
1830 "iface_->" << tfunction->get_name() << "(";
1832 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1833 if (first) {
1834 first = false;
1835 } else {
1836 f_service_ << ", ";
1838 f_service_ << "args." << (*f_iter)->get_name();
1840 f_service_ << ");" << endl;
1842 // Set isset on success field
1843 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1844 f_service_ <<
1845 indent() << "result.__isset.success = true;" << endl;
1848 indent_down();
1849 f_service_ << indent() << "}";
1851 if (!tfunction->is_async()) {
1852 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1853 f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " &" << (*x_iter)->get_name() << ") {" << endl;
1854 if (!tfunction->is_async()) {
1855 indent_up();
1856 f_service_ <<
1857 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
1858 indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
1859 indent_down();
1860 f_service_ << indent() << "}";
1861 } else {
1862 f_service_ << "}";
1867 f_service_ << " catch (const std::exception& e) {" << endl;
1869 if (!tfunction->is_async()) {
1870 indent_up();
1871 f_service_ <<
1872 indent() << "facebook::thrift::TApplicationException x(e.what());" << endl <<
1873 indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1874 indent() << "x.write(oprot);" << endl <<
1875 indent() << "oprot->writeMessageEnd();" << endl <<
1876 indent() << "oprot->getTransport()->flush();" << endl <<
1877 indent() << "oprot->getTransport()->writeEnd();" << endl <<
1878 indent() << "return;" << endl;
1879 indent_down();
1881 f_service_ << indent() << "}" << endl;
1883 // Shortcut out here for async functions
1884 if (tfunction->is_async()) {
1885 f_service_ <<
1886 indent() << "return;" << endl;
1887 indent_down();
1888 f_service_ << "}" << endl <<
1889 endl;
1890 return;
1893 // Serialize the result into a struct
1894 f_service_ <<
1895 endl <<
1896 indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_REPLY, seqid);" << endl <<
1897 indent() << "result.write(oprot);" << endl <<
1898 indent() << "oprot->writeMessageEnd();" << endl <<
1899 indent() << "oprot->getTransport()->flush();" << endl <<
1900 indent() << "oprot->getTransport()->writeEnd();" << endl;
1902 // Close function
1903 scope_down(f_service_);
1904 f_service_ << endl;
1908 * Helper function for generate_service_limited_reflector.
1909 * Generates a reflection of a single simple type.
1911 * @param ttype The type to reflect
1912 * @param target The name of the lvalue to reflect onto
1913 * @return true iff the type really is simple
1915 * Note: don't let this function output anything unless it is going to return true.
1917 bool t_cpp_generator::generate_simple_type_limited_reflection(ostream & out, t_type* ttype, string target) {
1918 if (ttype->is_base_type()) {
1919 string type;
1920 switch (((t_base_type*)ttype)->get_base()) {
1921 case t_base_type::TYPE_VOID : type = "T_VOID;" ; break;
1922 case t_base_type::TYPE_STRING : type = "T_STRING;" ; break;
1923 case t_base_type::TYPE_BOOL : type = "T_BOOL;" ; break;
1924 case t_base_type::TYPE_BYTE : type = "T_BYTE;" ; break;
1925 case t_base_type::TYPE_I16 : type = "T_I16;" ; break;
1926 case t_base_type::TYPE_I32 : type = "T_I32;" ; break;
1927 case t_base_type::TYPE_I64 : type = "T_I64;" ; break;
1928 case t_base_type::TYPE_DOUBLE : type = "T_DOUBLE;" ; break;
1929 default: return false;
1931 out << indent() << target << ".ttype = " << type << endl;
1932 return true;
1935 if (ttype->is_enum()) {
1936 out <<
1937 indent() << target << ".ttype = T_ENUM;" << endl <<
1938 indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl;
1941 if (ttype->is_struct()) {
1942 out <<
1943 indent() << target << ".ttype = T_STRUCT;" << endl <<
1944 indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl;
1945 return true;
1948 return false;
1952 * Helper function for generate_service_limited_reflector.
1953 * Generates a reflection of a single type.
1955 * @param ttype The type to reflect
1956 * @param target The name of the lvalue to reflect onto
1958 bool t_cpp_generator::generate_type_limited_reflection(t_type* ttype, string target) {
1959 bool is_simple = generate_simple_type_limited_reflection(f_service_, ttype, target + ".simple_type");
1960 if (is_simple) {
1961 f_service_ <<
1962 indent() << target << ".is_container = false;" << endl <<
1963 indent() << target << ".__isset.simple_type = true;" << endl;
1964 return true;
1967 ostringstream out;
1969 out <<
1970 indent() << target << ".is_container = true;" << endl <<
1971 indent() << target << ".__isset.container_type = true;" << endl <<
1972 indent() << target << ".container_type.ttype = ";
1974 if (ttype->is_list()) out << "T_LIST;" << endl;
1975 if (ttype->is_set()) out << "T_SET;" << endl;
1976 if (ttype->is_map()) out << "T_MAP;" << endl;
1978 bool reflected = false;
1980 if (ttype->is_list()) {
1981 reflected = generate_simple_type_limited_reflection(
1982 out, ((t_list*)ttype)->get_elem_type(), target + ".container_type.subtype1");
1984 if (ttype->is_set()) {
1985 reflected = generate_simple_type_limited_reflection(
1986 out, ((t_set*)ttype)->get_elem_type(), target + ".container_type.subtype1");
1988 if (ttype->is_map()) {
1989 reflected =
1990 generate_simple_type_limited_reflection(
1991 out, ((t_map*)ttype)->get_key_type(), target + ".container_type.subtype1")
1993 generate_simple_type_limited_reflection(
1994 out, ((t_map*)ttype)->get_val_type(), target + ".container_type.subtype2");
1995 out << indent() << target << ".container_type.__isset.subtype2 = true;" << endl;
1998 if (reflected) {
1999 f_service_ << out.str();
2000 return true;
2001 } else {
2002 f_service_ <<
2003 indent() << target << ".is_container = false;" << endl <<
2004 indent() << target << ".__isset.simple_type = true;" << endl;
2005 f_service_ << indent() << target << ".simple_type.ttype = T_NOT_REFLECTED;" << endl;
2006 return false;
2011 * Generates a service reflector definition.
2012 * This uses thrift::reflection::limited.
2014 * @param tservice The service to write a reflector for
2016 void t_cpp_generator::generate_service_limited_reflector(t_service* tservice) {
2017 // Open function
2018 f_service_ <<
2019 indent() << "void " << tservice->get_name() << "If::getStaticLimitedReflection" <<
2020 "(facebook::thrift::reflection::limited::Service & _return) ";
2021 scope_up(f_service_);
2023 f_service_ << indent() << "using namespace facebook::thrift::reflection::limited;" << endl;
2025 f_service_ << indent() << "_return.name = \"" << tservice->get_name() << "\";" << endl;
2026 f_service_ << indent() << "_return.fully_reflected = true;" << endl;
2028 bool all_reflectable = true;
2029 bool one_reflectable;
2031 const vector<t_function*> & funcs = tservice->get_functions();
2032 vector<t_function*>::const_iterator f_iter;
2033 for (f_iter = funcs.begin(); f_iter != funcs.end(); ++f_iter) {
2035 f_service_ << indent() << "_return.methods.resize(_return.methods.size() + 1);" << endl;
2036 f_service_ << indent() << "_return.methods.back().name = \"" << (*f_iter)->get_name() << "\";" << endl;
2037 one_reflectable = generate_type_limited_reflection(
2038 (*f_iter)->get_returntype(), "_return.methods.back().return_type");
2039 all_reflectable = all_reflectable && one_reflectable;
2041 t_struct* arglist = (*f_iter)->get_arglist();
2042 const vector<t_field*> & args = arglist->get_members();
2043 vector<t_field*>::const_iterator a_iter;
2044 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
2045 f_service_ <<
2046 indent() << "_return.methods.back().arguments.resize("
2047 "_return.methods.back().arguments.size() + 1);" << endl <<
2048 indent() << "_return.methods.back().arguments.back().name = \"" <<
2049 (*a_iter)->get_name() << "\";" << endl <<
2050 indent() << "_return.methods.back().arguments.back().key = " <<
2051 (*a_iter)->get_key() << ";" << endl;
2052 one_reflectable = generate_type_limited_reflection(
2053 (*a_iter)->get_type(), "_return.methods.back().arguments.back().type");
2054 all_reflectable = all_reflectable && one_reflectable;
2058 if (!all_reflectable) {
2059 f_service_ << indent() << "_return.fully_reflected = false;" << endl;
2062 // Close function
2063 scope_down(f_service_);
2064 f_service_ << endl;
2068 * Generates a skeleton file of a server
2070 * @param tservice The service to generate a server for.
2072 void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
2073 string svcname = tservice->get_name();
2075 // Service implementation file includes
2076 string f_skeleton_name = get_out_dir()+svcname+"_server.skeleton.cpp";
2078 string ns = namespace_prefix(tservice->get_program()->get_cpp_namespace());
2080 ofstream f_skeleton;
2081 f_skeleton.open(f_skeleton_name.c_str());
2082 f_skeleton <<
2083 "// This autogenerated skeleton file illustrates how to build a server." << endl <<
2084 "// You should copy it to another filename to avoid overwriting it." << endl <<
2085 endl <<
2086 "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl <<
2087 "#include <protocol/TBinaryProtocol.h>" << endl <<
2088 "#include <server/TSimpleServer.h>" << endl <<
2089 "#include <transport/TServerSocket.h>" << endl <<
2090 "#include <transport/TTransportUtils.h>" << endl <<
2091 endl <<
2092 "using namespace facebook::thrift;" << endl <<
2093 "using namespace facebook::thrift::protocol;" << endl <<
2094 "using namespace facebook::thrift::transport;" << endl <<
2095 "using namespace facebook::thrift::server;" << endl <<
2096 endl <<
2097 "using boost::shared_ptr;" << endl <<
2098 endl;
2100 if (!ns.empty()) {
2101 f_skeleton <<
2102 "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
2103 endl;
2106 f_skeleton <<
2107 "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl <<
2108 " public:" << endl;
2109 indent_up();
2110 f_skeleton <<
2111 indent() << svcname << "Handler() {" << endl <<
2112 indent() << " // Your initialization goes here" << endl <<
2113 indent() << "}" << endl <<
2114 endl;
2116 vector<t_function*> functions = tservice->get_functions();
2117 vector<t_function*>::iterator f_iter;
2118 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2119 f_skeleton <<
2120 indent() << function_signature(*f_iter) << " {" << endl <<
2121 indent() << " // Your implementation goes here" << endl <<
2122 indent() << " printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl <<
2123 indent() << "}" << endl <<
2124 endl;
2127 indent_down();
2128 f_skeleton <<
2129 "};" << endl <<
2130 endl;
2132 f_skeleton <<
2133 indent() << "int main(int argc, char **argv) {" << endl;
2134 indent_up();
2135 f_skeleton <<
2136 indent() << "int port = 9090;" << endl <<
2137 indent() << "shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl <<
2138 indent() << "shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl <<
2139 indent() << "shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));" << endl <<
2140 indent() << "shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl <<
2141 indent() << "shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());" << endl <<
2142 endl <<
2143 indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl <<
2144 indent() << "server.serve();" << endl <<
2145 indent() << "return 0;" << endl;
2146 indent_down();
2147 f_skeleton <<
2148 "}" << endl <<
2149 endl;
2151 // Close the files
2152 f_skeleton.close();
2156 * Deserializes a field of any type.
2158 void t_cpp_generator::generate_deserialize_field(ofstream& out,
2159 t_field* tfield,
2160 string prefix,
2161 string suffix) {
2162 t_type* type = get_true_type(tfield->get_type());
2164 if (type->is_void()) {
2165 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
2166 prefix + tfield->get_name();
2169 string name = prefix + tfield->get_name() + suffix;
2171 if (type->is_struct() || type->is_xception()) {
2172 generate_deserialize_struct(out, (t_struct*)type, name);
2173 } else if (type->is_container()) {
2174 generate_deserialize_container(out, type, name);
2175 } else if (type->is_base_type()) {
2176 indent(out) <<
2177 "xfer += iprot->";
2178 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2179 switch (tbase) {
2180 case t_base_type::TYPE_VOID:
2181 throw "compiler error: cannot serialize void field in a struct: " + name;
2182 break;
2183 case t_base_type::TYPE_STRING:
2184 out << "readString(" << name << ");";
2185 break;
2186 case t_base_type::TYPE_BOOL:
2187 out << "readBool(" << name << ");";
2188 break;
2189 case t_base_type::TYPE_BYTE:
2190 out << "readByte(" << name << ");";
2191 break;
2192 case t_base_type::TYPE_I16:
2193 out << "readI16(" << name << ");";
2194 break;
2195 case t_base_type::TYPE_I32:
2196 out << "readI32(" << name << ");";
2197 break;
2198 case t_base_type::TYPE_I64:
2199 out << "readI64(" << name << ");";
2200 break;
2201 case t_base_type::TYPE_DOUBLE:
2202 out << "readDouble(" << name << ");";
2203 break;
2204 default:
2205 throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
2207 out <<
2208 endl;
2209 } else if (type->is_enum()) {
2210 string t = tmp("ecast");
2211 out <<
2212 indent() << "int32_t " << t << ";" << endl <<
2213 indent() << "xfer += iprot->readI32(" << t << ");" << endl <<
2214 indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
2215 } else {
2216 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
2217 tfield->get_name().c_str(), type_name(type).c_str());
2222 * Generates an unserializer for a variable. This makes two key assumptions,
2223 * first that there is a const char* variable named data that points to the
2224 * buffer for deserialization, and that there is a variable protocol which
2225 * is a reference to a TProtocol serialization object.
2227 void t_cpp_generator::generate_deserialize_struct(ofstream& out,
2228 t_struct* tstruct,
2229 string prefix) {
2230 indent(out) <<
2231 "xfer += " << prefix << ".read(iprot);" << endl;
2234 void t_cpp_generator::generate_deserialize_container(ofstream& out,
2235 t_type* ttype,
2236 string prefix) {
2237 scope_up(out);
2239 string size = tmp("_size");
2240 string ktype = tmp("_ktype");
2241 string vtype = tmp("_vtype");
2242 string etype = tmp("_etype");
2244 indent(out) <<
2245 prefix << ".clear();" << endl <<
2246 indent() << "uint32_t " << size << ";" << endl;
2248 // Declare variables, read header
2249 if (ttype->is_map()) {
2250 out <<
2251 indent() << "facebook::thrift::protocol::TType " << ktype << ";" << endl <<
2252 indent() << "facebook::thrift::protocol::TType " << vtype << ";" << endl <<
2253 indent() << "iprot->readMapBegin(" <<
2254 ktype << ", " << vtype << ", " << size << ");" << endl;
2255 } else if (ttype->is_set()) {
2256 out <<
2257 indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
2258 indent() << "iprot->readSetBegin(" <<
2259 etype << ", " << size << ");" << endl;
2260 } else if (ttype->is_list()) {
2261 out <<
2262 indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
2263 indent() << "iprot->readListBegin(" <<
2264 etype << ", " << size << ");" << endl <<
2265 indent() << prefix << ".resize(" << size << ");";
2269 // For loop iterates over elements
2270 string i = tmp("_i");
2271 out <<
2272 indent() << "uint32_t " << i << ";" << endl <<
2273 indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
2275 scope_up(out);
2277 if (ttype->is_map()) {
2278 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
2279 } else if (ttype->is_set()) {
2280 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
2281 } else if (ttype->is_list()) {
2282 generate_deserialize_list_element(out, (t_list*)ttype, prefix, i);
2285 scope_down(out);
2287 // Read container end
2288 if (ttype->is_map()) {
2289 indent(out) << "iprot->readMapEnd();" << endl;
2290 } else if (ttype->is_set()) {
2291 indent(out) << "iprot->readSetEnd();" << endl;
2292 } else if (ttype->is_list()) {
2293 indent(out) << "iprot->readListEnd();" << endl;
2296 scope_down(out);
2301 * Generates code to deserialize a map
2303 void t_cpp_generator::generate_deserialize_map_element(ofstream& out,
2304 t_map* tmap,
2305 string prefix) {
2306 string key = tmp("_key");
2307 string val = tmp("_val");
2308 t_field fkey(tmap->get_key_type(), key);
2309 t_field fval(tmap->get_val_type(), val);
2311 out <<
2312 indent() << declare_field(&fkey) << endl;
2314 generate_deserialize_field(out, &fkey);
2315 indent(out) <<
2316 declare_field(&fval, false, false, false, true) << " = " <<
2317 prefix << "[" << key << "];" << endl;
2319 generate_deserialize_field(out, &fval);
2322 void t_cpp_generator::generate_deserialize_set_element(ofstream& out,
2323 t_set* tset,
2324 string prefix) {
2325 string elem = tmp("_elem");
2326 t_field felem(tset->get_elem_type(), elem);
2328 indent(out) <<
2329 declare_field(&felem) << endl;
2331 generate_deserialize_field(out, &felem);
2333 indent(out) <<
2334 prefix << ".insert(" << elem << ");" << endl;
2337 void t_cpp_generator::generate_deserialize_list_element(ofstream& out,
2338 t_list* tlist,
2339 string prefix,
2340 string index) {
2341 t_field felem(tlist->get_elem_type(), prefix + "[" + index + "]");
2342 generate_deserialize_field(out, &felem);
2347 * Serializes a field of any type.
2349 * @param tfield The field to serialize
2350 * @param prefix Name to prepend to field name
2352 void t_cpp_generator::generate_serialize_field(ofstream& out,
2353 t_field* tfield,
2354 string prefix,
2355 string suffix) {
2356 t_type* type = get_true_type(tfield->get_type());
2358 string name = prefix + tfield->get_name() + suffix;
2360 // Do nothing for void types
2361 if (type->is_void()) {
2362 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
2367 if (type->is_struct() || type->is_xception()) {
2368 generate_serialize_struct(out,
2369 (t_struct*)type,
2370 name);
2371 } else if (type->is_container()) {
2372 generate_serialize_container(out, type, name);
2373 } else if (type->is_base_type() || type->is_enum()) {
2375 indent(out) <<
2376 "xfer += oprot->";
2378 if (type->is_base_type()) {
2379 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2380 switch (tbase) {
2381 case t_base_type::TYPE_VOID:
2382 throw
2383 "compiler error: cannot serialize void field in a struct: " + name;
2384 break;
2385 case t_base_type::TYPE_STRING:
2386 out << "writeString(" << name << ");";
2387 break;
2388 case t_base_type::TYPE_BOOL:
2389 out << "writeBool(" << name << ");";
2390 break;
2391 case t_base_type::TYPE_BYTE:
2392 out << "writeByte(" << name << ");";
2393 break;
2394 case t_base_type::TYPE_I16:
2395 out << "writeI16(" << name << ");";
2396 break;
2397 case t_base_type::TYPE_I32:
2398 out << "writeI32(" << name << ");";
2399 break;
2400 case t_base_type::TYPE_I64:
2401 out << "writeI64(" << name << ");";
2402 break;
2403 case t_base_type::TYPE_DOUBLE:
2404 out << "writeDouble(" << name << ");";
2405 break;
2406 default:
2407 throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + name;
2409 } else if (type->is_enum()) {
2410 out << "writeI32((int32_t)" << name << ");";
2412 out << endl;
2413 } else {
2414 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
2415 name.c_str(),
2416 type_name(type).c_str());
2421 * Serializes all the members of a struct.
2423 * @param tstruct The struct to serialize
2424 * @param prefix String prefix to attach to all fields
2426 void t_cpp_generator::generate_serialize_struct(ofstream& out,
2427 t_struct* tstruct,
2428 string prefix) {
2429 indent(out) <<
2430 "xfer += " << prefix << ".write(oprot);" << endl;
2433 void t_cpp_generator::generate_serialize_container(ofstream& out,
2434 t_type* ttype,
2435 string prefix) {
2436 scope_up(out);
2438 if (ttype->is_map()) {
2439 indent(out) <<
2440 "xfer += oprot->writeMapBegin(" <<
2441 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
2442 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
2443 prefix << ".size());" << endl;
2444 } else if (ttype->is_set()) {
2445 indent(out) <<
2446 "xfer += oprot->writeSetBegin(" <<
2447 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
2448 prefix << ".size());" << endl;
2449 } else if (ttype->is_list()) {
2450 indent(out) <<
2451 "xfer += oprot->writeListBegin(" <<
2452 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
2453 prefix << ".size());" << endl;
2456 string iter = tmp("_iter");
2457 out <<
2458 indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl <<
2459 indent() << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl;
2460 scope_up(out);
2461 if (ttype->is_map()) {
2462 generate_serialize_map_element(out, (t_map*)ttype, iter);
2463 } else if (ttype->is_set()) {
2464 generate_serialize_set_element(out, (t_set*)ttype, iter);
2465 } else if (ttype->is_list()) {
2466 generate_serialize_list_element(out, (t_list*)ttype, iter);
2468 scope_down(out);
2470 if (ttype->is_map()) {
2471 indent(out) <<
2472 "xfer += oprot->writeMapEnd();" << endl;
2473 } else if (ttype->is_set()) {
2474 indent(out) <<
2475 "xfer += oprot->writeSetEnd();" << endl;
2476 } else if (ttype->is_list()) {
2477 indent(out) <<
2478 "xfer += oprot->writeListEnd();" << endl;
2481 scope_down(out);
2485 * Serializes the members of a map.
2488 void t_cpp_generator::generate_serialize_map_element(ofstream& out,
2489 t_map* tmap,
2490 string iter) {
2491 t_field kfield(tmap->get_key_type(), iter + "->first");
2492 generate_serialize_field(out, &kfield, "");
2494 t_field vfield(tmap->get_val_type(), iter + "->second");
2495 generate_serialize_field(out, &vfield, "");
2499 * Serializes the members of a set.
2501 void t_cpp_generator::generate_serialize_set_element(ofstream& out,
2502 t_set* tset,
2503 string iter) {
2504 t_field efield(tset->get_elem_type(), "(*" + iter + ")");
2505 generate_serialize_field(out, &efield, "");
2509 * Serializes the members of a list.
2511 void t_cpp_generator::generate_serialize_list_element(ofstream& out,
2512 t_list* tlist,
2513 string iter) {
2514 t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
2515 generate_serialize_field(out, &efield, "");
2519 * Makes a :: prefix for a namespace
2521 * @param ns The namepsace, w/ periods in it
2522 * @return Namespaces
2524 string t_cpp_generator::namespace_prefix(string ns) {
2525 if (ns.size() == 0) {
2526 return "";
2528 string result = "";
2529 string::size_type loc;
2530 while ((loc = ns.find(".")) != string::npos) {
2531 result += ns.substr(0, loc);
2532 result += "::";
2533 ns = ns.substr(loc+1);
2535 if (ns.size() > 0) {
2536 result += ns + "::";
2538 return result;
2542 * Opens namespace.
2544 * @param ns The namepsace, w/ periods in it
2545 * @return Namespaces
2547 string t_cpp_generator::namespace_open(string ns) {
2548 if (ns.size() == 0) {
2549 return "";
2551 string result = "";
2552 string separator = "";
2553 string::size_type loc;
2554 while ((loc = ns.find(".")) != string::npos) {
2555 result += separator;
2556 result += "namespace ";
2557 result += ns.substr(0, loc);
2558 result += " {";
2559 separator = " ";
2560 ns = ns.substr(loc+1);
2562 if (ns.size() > 0) {
2563 result += separator + "namespace " + ns + " {";
2565 return result;
2569 * Closes namespace.
2571 * @param ns The namepsace, w/ periods in it
2572 * @return Namespaces
2574 string t_cpp_generator::namespace_close(string ns) {
2575 if (ns.size() == 0) {
2576 return "";
2578 string result = "}";
2579 string::size_type loc;
2580 while ((loc = ns.find(".")) != string::npos) {
2581 result += "}";
2582 ns = ns.substr(loc+1);
2584 result += " // namespace";
2585 return result;
2589 * Returns a C++ type name
2591 * @param ttype The type
2592 * @return String of the type name, i.e. std::set<type>
2594 string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
2595 if (ttype->is_base_type()) {
2596 string bname = base_type_name(((t_base_type*)ttype)->get_base());
2597 if (!arg) {
2598 return bname;
2601 if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) {
2602 return "const " + bname + "&";
2603 } else {
2604 return "const " + bname;
2608 // Check for a custom overloaded C++ name
2609 if (ttype->is_container()) {
2610 string cname;
2612 t_container* tcontainer = (t_container*) ttype;
2613 if (tcontainer->has_cpp_name()) {
2614 cname = tcontainer->get_cpp_name();
2615 } else if (ttype->is_map()) {
2616 t_map* tmap = (t_map*) ttype;
2617 cname = "std::map<" +
2618 type_name(tmap->get_key_type(), in_typedef) + ", " +
2619 type_name(tmap->get_val_type(), in_typedef) + "> ";
2620 } else if (ttype->is_set()) {
2621 t_set* tset = (t_set*) ttype;
2622 cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> ";
2623 } else if (ttype->is_list()) {
2624 t_list* tlist = (t_list*) ttype;
2625 cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
2628 if (arg) {
2629 return "const " + cname + "&";
2630 } else {
2631 return cname;
2635 string class_prefix;
2636 if (in_typedef && (ttype->is_struct() || ttype->is_xception())) {
2637 class_prefix = "class ";
2640 // Check if it needs to be namespaced
2641 string pname;
2642 t_program* program = ttype->get_program();
2643 if (program != NULL && program != program_) {
2644 pname =
2645 class_prefix +
2646 namespace_prefix(program->get_cpp_namespace()) +
2647 ttype->get_name();
2648 } else {
2649 pname = class_prefix + ttype->get_name();
2652 if (arg) {
2653 if (is_complex_type(ttype)) {
2654 return "const " + pname + "&";
2655 } else {
2656 return "const " + pname;
2658 } else {
2659 return pname;
2664 * Returns the C++ type that corresponds to the thrift type.
2666 * @param tbase The base type
2667 * @return Explicit C++ type, i.e. "int32_t"
2669 string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
2670 switch (tbase) {
2671 case t_base_type::TYPE_VOID:
2672 return "void";
2673 case t_base_type::TYPE_STRING:
2674 return "std::string";
2675 case t_base_type::TYPE_BOOL:
2676 return "bool";
2677 case t_base_type::TYPE_BYTE:
2678 return "int8_t";
2679 case t_base_type::TYPE_I16:
2680 return "int16_t";
2681 case t_base_type::TYPE_I32:
2682 return "int32_t";
2683 case t_base_type::TYPE_I64:
2684 return "int64_t";
2685 case t_base_type::TYPE_DOUBLE:
2686 return "double";
2687 default:
2688 throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
2693 * Declares a field, which may include initialization as necessary.
2695 * @param ttype The type
2696 * @return Field declaration, i.e. int x = 0;
2698 string t_cpp_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant, bool reference) {
2699 // TODO(mcslee): do we ever need to initialize the field?
2700 string result = "";
2701 if (constant) {
2702 result += "const ";
2704 result += type_name(tfield->get_type());
2705 if (pointer) {
2706 result += "*";
2708 if (reference) {
2709 result += "&";
2711 result += " " + tfield->get_name();
2712 if (init) {
2713 t_type* type = get_true_type(tfield->get_type());
2715 if (type->is_base_type()) {
2716 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2717 switch (tbase) {
2718 case t_base_type::TYPE_VOID:
2719 break;
2720 case t_base_type::TYPE_STRING:
2721 result += " = \"\"";
2722 break;
2723 case t_base_type::TYPE_BOOL:
2724 result += " = false";
2725 break;
2726 case t_base_type::TYPE_BYTE:
2727 case t_base_type::TYPE_I16:
2728 case t_base_type::TYPE_I32:
2729 case t_base_type::TYPE_I64:
2730 result += " = 0";
2731 break;
2732 case t_base_type::TYPE_DOUBLE:
2733 result += " = (double)0";
2734 break;
2735 default:
2736 throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase);
2738 } else if (type->is_enum()) {
2739 result += " = (" + type_name(type) + ")0";
2742 if (!reference) {
2743 result += ";";
2745 return result;
2749 * Renders a function signature of the form 'type name(args)'
2751 * @param tfunction Function definition
2752 * @return String of rendered function definition
2754 string t_cpp_generator::function_signature(t_function* tfunction,
2755 string prefix) {
2756 t_type* ttype = tfunction->get_returntype();
2757 t_struct* arglist = tfunction->get_arglist();
2759 if (is_complex_type(ttype)) {
2760 bool empty = arglist->get_members().size() == 0;
2761 return
2762 "void " + prefix + tfunction->get_name() +
2763 "(" + type_name(ttype) + "& _return" +
2764 (empty ? "" : (", " + argument_list(arglist))) + ")";
2765 } else {
2766 return
2767 type_name(ttype) + " " + prefix + tfunction->get_name() +
2768 "(" + argument_list(arglist) + ")";
2773 * Renders a field list
2775 * @param tstruct The struct definition
2776 * @return Comma sepearated list of all field names in that struct
2778 string t_cpp_generator::argument_list(t_struct* tstruct) {
2779 string result = "";
2781 const vector<t_field*>& fields = tstruct->get_members();
2782 vector<t_field*>::const_iterator f_iter;
2783 bool first = true;
2784 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2785 if (first) {
2786 first = false;
2787 } else {
2788 result += ", ";
2790 result += type_name((*f_iter)->get_type(), false, true) + " " + (*f_iter)->get_name();
2792 return result;
2796 * Converts the parse type to a C++ enum string for the given type.
2798 * @param type Thrift Type
2799 * @return String of C++ code to definition of that type constant
2801 string t_cpp_generator::type_to_enum(t_type* type) {
2802 type = get_true_type(type);
2804 if (type->is_base_type()) {
2805 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2806 switch (tbase) {
2807 case t_base_type::TYPE_VOID:
2808 throw "NO T_VOID CONSTRUCT";
2809 case t_base_type::TYPE_STRING:
2810 return "facebook::thrift::protocol::T_STRING";
2811 case t_base_type::TYPE_BOOL:
2812 return "facebook::thrift::protocol::T_BOOL";
2813 case t_base_type::TYPE_BYTE:
2814 return "facebook::thrift::protocol::T_BYTE";
2815 case t_base_type::TYPE_I16:
2816 return "facebook::thrift::protocol::T_I16";
2817 case t_base_type::TYPE_I32:
2818 return "facebook::thrift::protocol::T_I32";
2819 case t_base_type::TYPE_I64:
2820 return "facebook::thrift::protocol::T_I64";
2821 case t_base_type::TYPE_DOUBLE:
2822 return "facebook::thrift::protocol::T_DOUBLE";
2824 } else if (type->is_enum()) {
2825 return "facebook::thrift::protocol::T_I32";
2826 } else if (type->is_struct()) {
2827 return "facebook::thrift::protocol::T_STRUCT";
2828 } else if (type->is_xception()) {
2829 return "facebook::thrift::protocol::T_STRUCT";
2830 } else if (type->is_map()) {
2831 return "facebook::thrift::protocol::T_MAP";
2832 } else if (type->is_set()) {
2833 return "facebook::thrift::protocol::T_SET";
2834 } else if (type->is_list()) {
2835 return "facebook::thrift::protocol::T_LIST";
2838 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2842 * Returns the symbol name of the local reflection of a type.
2844 string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype) {
2845 ttype = get_true_type(ttype);
2847 // We have to use the program name as part of the identifier because
2848 // if two thrift "programs" are compiled into one actual program
2849 // you would get a symbol collison if they both defined list<i32>.
2850 // trlo = Thrift Reflection LOcal.
2851 string prog;
2852 string name;
2854 // TODO(dreiss): Would it be better to pregenerate the base types
2855 // and put them in Thrift.{h,cpp} ?
2857 if (ttype->is_base_type()) {
2858 //name = ttype->get_name();
2859 prog = program_->get_name();
2860 name = ttype->get_ascii_fingerprint();
2861 } else if (ttype->is_enum()) {
2862 //name = "enum";
2863 prog = program_->get_name();
2864 name = ttype->get_ascii_fingerprint();
2865 } else if (ttype->is_container()) {
2866 prog = program_->get_name();
2867 name = ttype->get_ascii_fingerprint();
2868 } else {
2869 assert(ttype->is_struct() || ttype->is_xception());
2870 assert(ttype->get_program() != NULL);
2871 prog = ttype->get_program()->get_name();
2872 name = ttype->get_ascii_fingerprint();
2875 return string() + "trlo_" + prefix + "_" + prog + "_" + name;
2878 string t_cpp_generator::get_include_prefix(const t_program& program) const {
2879 string include_prefix = program.get_include_prefix();
2880 if (!use_include_prefix_ ||
2881 (include_prefix.size() > 0 && include_prefix[0] == '/')) {
2882 // if flag is turned off or this is absolute path, return empty prefix
2883 return "";
2886 string::size_type last_slash = string::npos;
2887 if ((last_slash = include_prefix.rfind("/")) != string::npos) {
2888 return include_prefix.substr(0, last_slash) + "/" + out_dir_base_ + "/";
2891 return "";