r1459@opsdev009 (orig r77477): dreiss | 2008-01-11 12:59:03 -0800
[amiethrift.git] / compiler / cpp / src / generate / t_cpp_generator.cc
blob620d09ef5ae4faf31b0ed3c593ce35b09e3e0239
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 \"" << includes[i]->get_name() << "_types.h\"" << endl;
59 f_types_ << endl;
61 // Include custom headers
62 const vector<string>& cpp_includes = program_->get_cpp_includes();
63 for (size_t i = 0; i < cpp_includes.size(); ++i) {
64 f_types_ <<
65 "#include \"" << cpp_includes[i] << "\"" << endl;
67 f_types_ <<
68 endl;
70 // Include the types file
71 f_types_impl_ <<
72 "#include \"" << program_name_ << "_types.h\"" << endl <<
73 endl;
75 // If we are generating local reflection metadata, we need to include
76 // the definition of TypeSpec.
77 if (gen_dense_) {
78 f_types_impl_ <<
79 "#include <TReflectionLocal.h>" << endl <<
80 endl;
83 // Open namespace
84 ns_open_ = namespace_open(program_->get_cpp_namespace());
85 ns_close_ = namespace_close(program_->get_cpp_namespace());
87 f_types_ <<
88 ns_open_ << endl <<
89 endl;
91 f_types_impl_ <<
92 ns_open_ << endl <<
93 endl;
96 /**
97 * Closes the output files.
99 void t_cpp_generator::close_generator() {
100 // Close namespace
101 f_types_ <<
102 ns_close_ << endl <<
103 endl;
104 f_types_impl_ <<
105 ns_close_ << endl;
107 // Close ifndef
108 f_types_ <<
109 "#endif" << endl;
111 // Close output file
112 f_types_.close();
113 f_types_impl_.close();
117 * Generates a typedef. This is just a simple 1-liner in C++
119 * @param ttypedef The type definition
121 void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
122 f_types_ <<
123 indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << ttypedef->get_symbolic() << ";" << endl <<
124 endl;
128 * Generates code for an enumerated type. In C++, this is essentially the same
129 * as the thrift definition itself, using the enum keyword in C++.
131 * @param tenum The enumeration
133 void t_cpp_generator::generate_enum(t_enum* tenum) {
134 f_types_ <<
135 indent() << "enum " << tenum->get_name() << " {" << endl;
136 indent_up();
138 vector<t_enum_value*> constants = tenum->get_constants();
139 vector<t_enum_value*>::iterator c_iter;
140 bool first = true;
141 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
142 if (first) {
143 first = false;
144 } else {
145 f_types_ <<
146 "," << endl;
148 f_types_ <<
149 indent() << (*c_iter)->get_name();
150 if ((*c_iter)->has_value()) {
151 f_types_ <<
152 " = " << (*c_iter)->get_value();
156 indent_down();
157 f_types_ <<
158 endl <<
159 "};" << endl <<
160 endl;
164 * Generates a class that holds all the constants.
166 void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
167 string f_consts_name = get_out_dir()+program_name_+"_constants.h";
168 ofstream f_consts;
169 f_consts.open(f_consts_name.c_str());
171 string f_consts_impl_name = get_out_dir()+program_name_+"_constants.cpp";
172 ofstream f_consts_impl;
173 f_consts_impl.open(f_consts_impl_name.c_str());
175 // Print header
176 f_consts <<
177 autogen_comment();
178 f_consts_impl <<
179 autogen_comment();
181 // Start ifndef
182 f_consts <<
183 "#ifndef " << program_name_ << "_CONSTANTS_H" << endl <<
184 "#define " << program_name_ << "_CONSTANTS_H" << endl <<
185 endl <<
186 "#include \"" << program_name_ << "_types.h\"" << endl <<
187 endl <<
188 ns_open_ << endl <<
189 endl;
191 f_consts_impl <<
192 "#include \"" << program_name_ << "_constants.h\"" << endl <<
193 endl <<
194 ns_open_ << endl <<
195 endl;
197 f_consts <<
198 "class " << program_name_ << "Constants {" << endl <<
199 " public:" << endl <<
200 " " << program_name_ << "Constants();" << endl <<
201 endl;
202 indent_up();
203 vector<t_const*>::iterator c_iter;
204 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
205 string name = (*c_iter)->get_name();
206 t_type* type = (*c_iter)->get_type();
207 f_consts <<
208 indent() << type_name(type) << " " << name << ";" << endl;
210 indent_down();
211 f_consts <<
212 "};" << endl;
214 f_consts_impl <<
215 "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
216 endl <<
217 program_name_ << "Constants::" << program_name_ << "Constants() {" << endl;
218 indent_up();
219 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
220 print_const_value(f_consts_impl,
221 (*c_iter)->get_name(),
222 (*c_iter)->get_type(),
223 (*c_iter)->get_value());
225 indent_down();
226 indent(f_consts_impl) <<
227 "}" << endl;
229 f_consts <<
230 endl <<
231 "extern const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
232 endl <<
233 ns_close_ << endl <<
234 endl <<
235 "#endif" << endl;
236 f_consts.close();
238 f_consts_impl <<
239 endl <<
240 ns_close_ << endl <<
241 endl;
245 * Prints the value of a constant with the given type. Note that type checking
246 * is NOT performed in this function as it is always run beforehand using the
247 * validate_types method in main.cc
249 void t_cpp_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
250 if (type->is_base_type()) {
251 string v2 = render_const_value(out, name, type, value);
252 indent(out) << name << " = " << v2 << ";" << endl <<
253 endl;
254 } else if (type->is_enum()) {
255 indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl <<
256 endl;
257 } else if (type->is_struct() || type->is_xception()) {
258 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
259 vector<t_field*>::const_iterator f_iter;
260 const map<t_const_value*, t_const_value*>& val = value->get_map();
261 map<t_const_value*, t_const_value*>::const_iterator v_iter;
262 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
263 t_type* field_type = NULL;
264 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
265 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
266 field_type = (*f_iter)->get_type();
269 if (field_type == NULL) {
270 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
272 string val = render_const_value(out, name, field_type, v_iter->second);
273 indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
274 indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
276 out << endl;
277 } else if (type->is_map()) {
278 t_type* ktype = ((t_map*)type)->get_key_type();
279 t_type* vtype = ((t_map*)type)->get_val_type();
280 const map<t_const_value*, t_const_value*>& val = value->get_map();
281 map<t_const_value*, t_const_value*>::const_iterator v_iter;
282 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
283 string key = render_const_value(out, name, ktype, v_iter->first);
284 string val = render_const_value(out, name, vtype, v_iter->second);
285 indent(out) << name << "[" << key << "] = " << val << ";" << endl;
287 out << endl;
288 } else if (type->is_list()) {
289 t_type* etype = ((t_list*)type)->get_elem_type();
290 const vector<t_const_value*>& val = value->get_list();
291 vector<t_const_value*>::const_iterator v_iter;
292 int i = 0;
293 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
294 string val = render_const_value(out, name, etype, *v_iter);
295 indent(out) << name << "[" << (i++) << "] = " << val << ";" << endl;
297 out << endl;
298 } else if (type->is_set()) {
299 t_type* etype = ((t_set*)type)->get_elem_type();
300 const vector<t_const_value*>& val = value->get_list();
301 vector<t_const_value*>::const_iterator v_iter;
302 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
303 string val = render_const_value(out, name, etype, *v_iter);
304 indent(out) << name << ".insert(" << val << ");" << endl;
306 out << endl;
313 string t_cpp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
314 std::ostringstream render;
316 if (type->is_base_type()) {
317 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
318 switch (tbase) {
319 case t_base_type::TYPE_STRING:
320 render << "\"" + value->get_string() + "\"";
321 break;
322 case t_base_type::TYPE_BOOL:
323 render << ((value->get_integer() > 0) ? "true" : "false");
324 break;
325 case t_base_type::TYPE_BYTE:
326 case t_base_type::TYPE_I16:
327 case t_base_type::TYPE_I32:
328 case t_base_type::TYPE_I64:
329 render << value->get_integer();
330 break;
331 case t_base_type::TYPE_DOUBLE:
332 if (value->get_type() == t_const_value::CV_INTEGER) {
333 render << value->get_integer();
334 } else {
335 render << value->get_double();
337 break;
338 default:
339 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
341 } else if (type->is_enum()) {
342 render << "(" << type_name(type) << ")" << value->get_integer();
343 } else {
344 string t = tmp("tmp");
345 indent(out) << type_name(type) << " " << t << ";" << endl;
346 print_const_value(out, t, type, value);
347 render << t;
350 return render.str();
354 * Generates a struct definition for a thrift data type. This is a class
355 * with data members and a read/write() function, plus a mirroring isset
356 * inner class.
358 * @param tstruct The struct definition
360 void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) {
361 generate_struct_definition(f_types_, tstruct, is_exception);
362 generate_struct_fingerprint(f_types_impl_, tstruct, true);
363 generate_local_reflection(f_types_, tstruct, false);
364 generate_local_reflection(f_types_impl_, tstruct, true);
365 generate_local_reflection_pointer(f_types_impl_, tstruct);
366 generate_struct_reader(f_types_impl_, tstruct);
367 generate_struct_writer(f_types_impl_, tstruct);
371 * Writes the struct definition into the header file
373 * @param out Output stream
374 * @param tstruct The struct
376 void t_cpp_generator::generate_struct_definition(ofstream& out,
377 t_struct* tstruct,
378 bool is_exception,
379 bool pointers,
380 bool read,
381 bool write) {
382 string extends = "";
383 if (is_exception) {
384 extends = " : public facebook::thrift::TException";
387 // Open struct def
388 out <<
389 indent() << "class " << tstruct->get_name() << extends << " {" << endl <<
390 indent() << " public:" << endl <<
391 endl;
392 indent_up();
394 // Put the fingerprint up top for all to see.
395 generate_struct_fingerprint(out, tstruct, false);
397 // Get members
398 vector<t_field*>::const_iterator m_iter;
399 const vector<t_field*>& members = tstruct->get_members();
401 if (!pointers) {
402 // Default constructor
403 indent(out) <<
404 tstruct->get_name() << "()";
406 bool init_ctor = false;
408 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
409 t_type* t = get_true_type((*m_iter)->get_type());
410 if (t->is_base_type()) {
411 string dval;
412 if (t->is_enum()) {
413 dval += "(" + type_name(t) + ")";
415 dval += t->is_string() ? "\"\"" : "0";
416 t_const_value* cv = (*m_iter)->get_value();
417 if (cv != NULL) {
418 dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
420 if (!init_ctor) {
421 init_ctor = true;
422 out << " : ";
423 out << (*m_iter)->get_name() << "(" << dval << ")";
424 } else {
425 out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
429 out << " {" << endl;
430 indent_up();
431 // TODO(dreiss): When everything else in Thrift is perfect,
432 // do more of these in the initializer list.
433 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
434 t_type* t = get_true_type((*m_iter)->get_type());
436 if (!t->is_base_type()) {
437 t_const_value* cv = (*m_iter)->get_value();
438 if (cv != NULL) {
439 print_const_value(out, (*m_iter)->get_name(), t, cv);
443 scope_down(out);
446 out <<
447 endl <<
448 indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
450 // Pointer to this structure's reflection local typespec.
451 if (gen_dense_) {
452 indent(out) <<
453 "static facebook::thrift::reflection::local::TypeSpec* local_reflection;" <<
454 endl << endl;
457 // Declare all fields
458 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
459 indent(out) <<
460 declare_field(*m_iter, false, pointers && !(*m_iter)->get_type()->is_xception(), !read) << endl;
463 // Isset struct has boolean fields, but only for non-required fields.
464 bool has_nonrequired_fields = false;
465 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
466 if ((*m_iter)->get_req() != t_field::T_REQUIRED)
467 has_nonrequired_fields = true;
470 if (has_nonrequired_fields && (!pointers || read)) {
471 out <<
472 endl <<
473 indent() << "struct __isset {" << endl;
474 indent_up();
476 indent(out) <<
477 "__isset() : ";
478 bool first = true;
479 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
480 if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
481 continue;
483 if (first) {
484 first = false;
485 out <<
486 (*m_iter)->get_name() << "(false)";
487 } else {
488 out <<
489 ", " << (*m_iter)->get_name() << "(false)";
492 out << " {}" << endl;
494 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
495 if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
496 indent(out) <<
497 "bool " << (*m_iter)->get_name() << ";" << endl;
501 indent_down();
502 indent(out) <<
503 "} __isset;" << endl;
506 out << endl;
508 if (!pointers) {
509 // Generate an equality testing operator. Make it inline since the compiler
510 // will do a better job than we would when deciding whether to inline it.
511 out <<
512 indent() << "bool operator == (const " << tstruct->get_name() << " & rhs) const" << endl;
513 scope_up(out);
514 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
515 // Most existing Thrift code does not use isset or optional/required,
516 // so we treat "default" fields as required.
517 if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
518 out <<
519 indent() << "if (!(" << (*m_iter)->get_name()
520 << " == rhs." << (*m_iter)->get_name() << "))" << endl <<
521 indent() << " return false;" << endl;
522 } else {
523 out <<
524 indent() << "if (__isset." << (*m_iter)->get_name()
525 << " != rhs.__isset." << (*m_iter)->get_name() << ")" << endl <<
526 indent() << " return false;" << endl <<
527 indent() << "else if (__isset." << (*m_iter)->get_name() << " && !("
528 << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name()
529 << "))" << endl <<
530 indent() << " return false;" << endl;
533 indent(out) << "return true;" << endl;
534 scope_down(out);
535 out <<
536 indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" << endl <<
537 indent() << " return !(*this == rhs);" << endl <<
538 indent() << "}" << endl << endl;
540 if (read) {
541 out <<
542 indent() << "uint32_t read(facebook::thrift::protocol::TProtocol* iprot);" << endl;
544 if (write) {
545 out <<
546 indent() << "uint32_t write(facebook::thrift::protocol::TProtocol* oprot) const;" << endl;
548 out << endl;
550 indent_down();
551 indent(out) <<
552 "};" << endl <<
553 endl;
557 * Writes the fingerprint of a struct to either the header or implementation.
559 * @param out Output stream
560 * @param tstruct The struct
562 void t_cpp_generator::generate_struct_fingerprint(ofstream& out,
563 t_struct* tstruct,
564 bool is_definition) {
565 string stat, nspace, comment;
566 if (is_definition) {
567 stat = "";
568 nspace = tstruct->get_name() + "::";
569 comment = " ";
570 } else {
571 stat = "static ";
572 nspace = "";
573 comment = "; // ";
576 if (tstruct->has_fingerprint()) {
577 out <<
578 indent() << stat << "const char* " << nspace
579 << "ascii_fingerprint" << comment << "= \"" <<
580 tstruct->get_ascii_fingerprint() << "\";" << endl <<
581 indent() << stat << "const uint8_t " << nspace <<
582 "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {";
583 char* comma = "";
584 for (int i = 0; i < t_type::fingerprint_len; i++) {
585 out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]);
586 comma = ",";
588 out << "};" << endl << endl;
593 * Writes the local reflection of a type (either declaration or definition).
595 void t_cpp_generator::generate_local_reflection(std::ofstream& out,
596 t_type* ttype,
597 bool is_definition) {
598 if (!gen_dense_) {
599 return;
601 ttype = get_true_type(ttype);
602 assert(ttype->has_fingerprint());
603 string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl");
604 // Note that we have generated this fingerprint. If we already did, bail out.
605 if (!reflected_fingerprints_.insert(key).second) {
606 return;
608 // Let each program handle its own structures.
609 if (ttype->get_program() != NULL && ttype->get_program() != program_) {
610 return;
613 // Do dependencies.
614 if (ttype->is_list()) {
615 generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition);
616 } else if (ttype->is_set()) {
617 generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition);
618 } else if (ttype->is_map()) {
619 generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition);
620 generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition);
621 } else if (ttype->is_struct() || ttype->is_xception()) {
622 // Hacky hacky. For efficiency and convenience, we need a dummy "T_STOP"
623 // type at the end of our typespec array. Unfortunately, there is no
624 // T_STOP type, so we use the global void type, and special case it when
625 // generating its typespec.
627 const vector<t_field*>& members = ((t_struct*)ttype)->get_members();
628 vector<t_field*>::const_iterator m_iter;
629 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
630 generate_local_reflection(out, (**m_iter).get_type(), is_definition);
632 generate_local_reflection(out, g_type_void, is_definition);
634 // For definitions of structures, do the arrays of metas and field specs also.
635 if (is_definition) {
636 out <<
637 indent() << "facebook::thrift::reflection::local::FieldMeta" << endl <<
638 indent() << local_reflection_name("metas", ttype) <<"[] = {" << endl;
639 indent_up();
640 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
641 indent(out) << "{ " << (*m_iter)->get_key() << ", " <<
642 (((*m_iter)->get_req() == t_field::T_OPTIONAL) ? "true" : "false") <<
643 " }," << endl;
645 // Zero for the T_STOP marker.
646 indent(out) << "{ 0, false }" << endl << "};" << endl;
647 indent_down();
649 out <<
650 indent() << "facebook::thrift::reflection::local::TypeSpec*" << endl <<
651 indent() << local_reflection_name("specs", ttype) <<"[] = {" << endl;
652 indent_up();
653 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
654 indent(out) << "&" <<
655 local_reflection_name("typespec", (*m_iter)->get_type()) << "," << endl;
657 indent(out) << "&" <<
658 local_reflection_name("typespec", g_type_void) << "," << endl;
659 indent_down();
660 indent(out) << "};" << endl;
664 out <<
665 indent() << "// " << ttype->get_fingerprint_material() << endl <<
666 indent() << (is_definition ? "" : "extern ") <<
667 "facebook::thrift::reflection::local::TypeSpec" << endl <<
668 local_reflection_name("typespec", ttype) <<
669 (is_definition ? "(" : ";") << endl;
671 if (!is_definition) {
672 out << endl;
673 return;
676 indent_up();
678 if (ttype->is_void()) {
679 indent(out) << "facebook::thrift::protocol::T_STOP";
680 } else {
681 indent(out) << type_to_enum(ttype);
684 if (ttype->is_struct()) {
685 out << "," << endl <<
686 indent() << type_name(ttype) << "::binary_fingerprint," << endl <<
687 indent() << local_reflection_name("metas", ttype) << "," << endl <<
688 indent() << local_reflection_name("specs", ttype);
689 } else if (ttype->is_list()) {
690 out << "," << endl <<
691 indent() << "&" << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type()) << "," << endl <<
692 indent() << "NULL";
693 } else if (ttype->is_set()) {
694 out << "," << endl <<
695 indent() << "&" << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type()) << "," << endl <<
696 indent() << "NULL";
697 } else if (ttype->is_map()) {
698 out << "," << endl <<
699 indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type()) << "," << endl <<
700 indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type());
703 out << ");" << endl << endl;
705 indent_down();
709 * Writes the structure's static pointer to its local reflection typespec
710 * into the implementation file.
712 void t_cpp_generator::generate_local_reflection_pointer(std::ofstream& out,
713 t_type* ttype) {
714 if (!gen_dense_) {
715 return;
717 indent(out) <<
718 "facebook::thrift::reflection::local::TypeSpec* " <<
719 ttype->get_name() << "::local_reflection = " << endl <<
720 indent() << " &" << local_reflection_name("typespec", ttype) << ";" <<
721 endl << endl;
725 * Makes a helper function to gen a struct reader.
727 * @param out Stream to write to
728 * @param tstruct The struct
730 void t_cpp_generator::generate_struct_reader(ofstream& out,
731 t_struct* tstruct,
732 bool pointers) {
733 indent(out) <<
734 "uint32_t " << tstruct->get_name() << "::read(facebook::thrift::protocol::TProtocol* iprot) {" << endl;
735 indent_up();
737 const vector<t_field*>& fields = tstruct->get_members();
738 vector<t_field*>::const_iterator f_iter;
740 // Declare stack tmp variables
741 out <<
742 endl <<
743 indent() << "uint32_t xfer = 0;" << endl <<
744 indent() << "std::string fname;" << endl <<
745 indent() << "facebook::thrift::protocol::TType ftype;" << endl <<
746 indent() << "int16_t fid;" << endl <<
747 endl <<
748 indent() << "xfer += iprot->readStructBegin(fname);" << endl <<
749 endl <<
750 indent() << "using facebook::thrift::protocol::TProtocolException;" << endl <<
751 endl;
753 // Required variables aren't in __isset, so we need tmp vars to check them.
754 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
755 if ((*f_iter)->get_req() == t_field::T_REQUIRED)
756 indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
758 out << endl;
761 // Loop over reading in fields
762 indent(out) <<
763 "while (true)" << endl;
764 scope_up(out);
766 // Read beginning field marker
767 indent(out) <<
768 "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
770 // Check for field STOP marker
771 out <<
772 indent() << "if (ftype == facebook::thrift::protocol::T_STOP) {" << endl <<
773 indent() << " break;" << endl <<
774 indent() << "}" << endl;
776 // Switch statement on the field we are reading
777 indent(out) <<
778 "switch (fid)" << endl;
780 scope_up(out);
782 // Generate deserialization code for known cases
783 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
784 indent(out) <<
785 "case " << (*f_iter)->get_key() << ":" << endl;
786 indent_up();
787 indent(out) <<
788 "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
789 indent_up();
791 const char *isset_prefix =
792 ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." : "isset_";
794 #if 0
795 // This code throws an exception if the same field is encountered twice.
796 // We've decided to leave it out for performance reasons.
797 // TODO(dreiss): Generate this code and "if" it out to make it easier
798 // for people recompiling thrift to include it.
799 out <<
800 indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl <<
801 indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
802 #endif
804 if (pointers && !(*f_iter)->get_type()->is_xception()) {
805 generate_deserialize_field(out, *f_iter, "(*(this->", "))");
806 } else {
807 generate_deserialize_field(out, *f_iter, "this->");
809 out <<
810 indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl;
811 indent_down();
812 out <<
813 indent() << "} else {" << endl <<
814 indent() << " xfer += iprot->skip(ftype);" << endl <<
815 // TODO(dreiss): Make this an option when thrift structs
816 // have a common base class.
817 // indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl <<
818 indent() << "}" << endl <<
819 indent() << "break;" << endl;
820 indent_down();
823 // In the default case we skip the field
824 out <<
825 indent() << "default:" << endl <<
826 indent() << " xfer += iprot->skip(ftype);" << endl <<
827 indent() << " break;" << endl;
829 scope_down(out);
831 // Read field end marker
832 indent(out) <<
833 "xfer += iprot->readFieldEnd();" << endl;
835 scope_down(out);
837 out <<
838 endl <<
839 indent() << "xfer += iprot->readStructEnd();" << endl;
841 // Throw if any required fields are missing.
842 // We do this after reading the struct end so that
843 // there might possibly be a chance of continuing.
844 out << endl;
845 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
846 if ((*f_iter)->get_req() == t_field::T_REQUIRED)
847 out <<
848 indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
849 indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
852 indent(out) << "return xfer;" << endl;
854 indent_down();
855 indent(out) <<
856 "}" << endl << endl;
860 * Generates the write function.
862 * @param out Stream to write to
863 * @param tstruct The struct
865 void t_cpp_generator::generate_struct_writer(ofstream& out,
866 t_struct* tstruct,
867 bool pointers) {
868 string name = tstruct->get_name();
869 const vector<t_field*>& fields = tstruct->get_members();
870 vector<t_field*>::const_iterator f_iter;
872 indent(out) <<
873 "uint32_t " << tstruct->get_name() << "::write(facebook::thrift::protocol::TProtocol* oprot) const {" << endl;
874 indent_up();
876 out <<
877 indent() << "uint32_t xfer = 0;" << endl;
879 indent(out) <<
880 "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
881 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
882 if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
883 indent(out) << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
884 indent_up();
886 // Write field header
887 out <<
888 indent() << "xfer += oprot->writeFieldBegin(" <<
889 "\"" << (*f_iter)->get_name() << "\", " <<
890 type_to_enum((*f_iter)->get_type()) << ", " <<
891 (*f_iter)->get_key() << ");" << endl;
892 // Write field contents
893 if (pointers) {
894 generate_serialize_field(out, *f_iter, "(*(this->", "))");
895 } else {
896 generate_serialize_field(out, *f_iter, "this->");
898 // Write field closer
899 indent(out) <<
900 "xfer += oprot->writeFieldEnd();" << endl;
901 if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
902 indent_down();
903 indent(out) << '}' << endl;
907 // Write the struct map
908 out <<
909 indent() << "xfer += oprot->writeFieldStop();" << endl <<
910 indent() << "xfer += oprot->writeStructEnd();" << endl <<
911 indent() << "return xfer;" << endl;
913 indent_down();
914 indent(out) <<
915 "}" << endl <<
916 endl;
920 * Struct writer for result of a function, which can have only one of its
921 * fields set and does a conditional if else look up into the __isset field
922 * of the struct.
924 * @param out Output stream
925 * @param tstruct The result struct
927 void t_cpp_generator::generate_struct_result_writer(ofstream& out,
928 t_struct* tstruct,
929 bool pointers) {
930 string name = tstruct->get_name();
931 const vector<t_field*>& fields = tstruct->get_members();
932 vector<t_field*>::const_iterator f_iter;
934 indent(out) <<
935 "uint32_t " << tstruct->get_name() << "::write(facebook::thrift::protocol::TProtocol* oprot) const {" << endl;
936 indent_up();
938 out <<
939 endl <<
940 indent() << "uint32_t xfer = 0;" << endl <<
941 endl;
943 indent(out) <<
944 "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
946 bool first = true;
947 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
948 if (first) {
949 first = false;
950 out <<
951 endl <<
952 indent() << "if ";
953 } else {
954 out <<
955 " else if ";
958 out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
960 indent_up();
962 // Write field header
963 out <<
964 indent() << "xfer += oprot->writeFieldBegin(" <<
965 "\"" << (*f_iter)->get_name() << "\", " <<
966 type_to_enum((*f_iter)->get_type()) << ", " <<
967 (*f_iter)->get_key() << ");" << endl;
968 // Write field contents
969 if (pointers) {
970 generate_serialize_field(out, *f_iter, "(*(this->", "))");
971 } else {
972 generate_serialize_field(out, *f_iter, "this->");
974 // Write field closer
975 indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
977 indent_down();
978 indent(out) << "}";
981 // Write the struct map
982 out <<
983 endl <<
984 indent() << "xfer += oprot->writeFieldStop();" << endl <<
985 indent() << "xfer += oprot->writeStructEnd();" << endl <<
986 indent() << "return xfer;" << endl;
988 indent_down();
989 indent(out) <<
990 "}" << endl <<
991 endl;
995 * Generates a thrift service. In C++, this comprises an entirely separate
996 * header and source file. The header file defines the methods and includes
997 * the data types defined in the main header file, and the implementation
998 * file contains implementations of the basic printer and default interfaces.
1000 * @param tservice The service definition
1002 void t_cpp_generator::generate_service(t_service* tservice) {
1003 string svcname = tservice->get_name();
1005 // Make output files
1006 string f_header_name = get_out_dir()+svcname+".h";
1007 f_header_.open(f_header_name.c_str());
1009 // Print header file includes
1010 f_header_ <<
1011 autogen_comment();
1012 f_header_ <<
1013 "#ifndef " << svcname << "_H" << endl <<
1014 "#define " << svcname << "_H" << endl <<
1015 endl <<
1016 "#include <TProcessor.h>" << endl <<
1017 "#include \"" << program_name_ << "_types.h\"" << endl;
1019 if (tservice->get_extends() != NULL) {
1020 f_header_ <<
1021 "#include \"" << tservice->get_extends()->get_name() << ".h\"" << endl;
1024 f_header_ <<
1025 endl <<
1026 ns_open_ << endl <<
1027 endl;
1029 // Service implementation file includes
1030 string f_service_name = get_out_dir()+svcname+".cpp";
1031 f_service_.open(f_service_name.c_str());
1032 f_service_ <<
1033 autogen_comment();
1034 f_service_ <<
1035 "#include \"" << svcname << ".h\"" << endl <<
1036 endl <<
1037 ns_open_ << endl <<
1038 endl;
1040 // Generate all the components
1041 generate_service_interface(tservice);
1042 generate_service_null(tservice);
1043 generate_service_helpers(tservice);
1044 generate_service_client(tservice);
1045 generate_service_processor(tservice);
1046 generate_service_multiface(tservice);
1047 generate_service_skeleton(tservice);
1049 // Close the namespace
1050 f_service_ <<
1051 ns_close_ << endl <<
1052 endl;
1053 f_header_ <<
1054 ns_close_ << endl <<
1055 endl;
1056 f_header_ <<
1057 "#endif" << endl;
1059 // Close the files
1060 f_service_.close();
1061 f_header_.close();
1065 * Generates helper functions for a service. Basically, this generates types
1066 * for all the arguments and results to functions.
1068 * @param tservice The service to generate a header definition for
1070 void t_cpp_generator::generate_service_helpers(t_service* tservice) {
1071 vector<t_function*> functions = tservice->get_functions();
1072 vector<t_function*>::iterator f_iter;
1073 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1074 t_struct* ts = (*f_iter)->get_arglist();
1075 string name_orig = ts->get_name();
1077 ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
1078 generate_struct_definition(f_header_, ts, false);
1079 generate_struct_reader(f_service_, ts);
1080 generate_struct_writer(f_service_, ts);
1081 ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
1082 generate_struct_definition(f_header_, ts, false, true, false, true);
1083 generate_struct_writer(f_service_, ts, true);
1084 ts->set_name(name_orig);
1086 generate_function_helpers(tservice, *f_iter);
1089 generate_service_limited_reflector(tservice);
1093 * Generates a service interface definition.
1095 * @param tservice The service to generate a header definition for
1097 void t_cpp_generator::generate_service_interface(t_service* tservice) {
1098 string extends = "";
1099 if (tservice->get_extends() != NULL) {
1100 extends = " : virtual public " + type_name(tservice->get_extends()) + "If";
1102 f_header_ <<
1103 "class " << service_name_ << "If" << extends << " {" << endl <<
1104 " public:" << endl;
1105 indent_up();
1106 f_header_ <<
1107 indent() << "virtual ~" << service_name_ << "If() {}" << endl;
1109 f_header_ <<
1110 indent() << "static void getStaticLimitedReflection" <<
1111 "(facebook::thrift::reflection::limited::Service & _return);" << endl;
1112 // TODO(dreiss): Uncomment and test this if we decide we need
1113 // a virtual function with this effect.
1114 //f_header_ <<
1115 // indent() << "virtual void getVirtualLimitedReflection" <<
1116 // "(facebook::thrift::reflection::limited::Service & _return) ";
1117 //scope_up(f_header_);
1118 //f_header_ <<
1119 // indent() << "getStaticLimitedReflection(_return);" << endl;
1120 //scope_down(f_header_);
1122 vector<t_function*> functions = tservice->get_functions();
1123 vector<t_function*>::iterator f_iter;
1124 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1125 f_header_ <<
1126 indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
1128 indent_down();
1129 f_header_ <<
1130 "};" << endl << endl;
1134 * Generates a null implementation of the service.
1136 * @param tservice The service to generate a header definition for
1138 void t_cpp_generator::generate_service_null(t_service* tservice) {
1139 string extends = "";
1140 if (tservice->get_extends() != NULL) {
1141 extends = " , virtual public " + type_name(tservice->get_extends()) + "Null";
1143 f_header_ <<
1144 "class " << service_name_ << "Null : virtual public " << service_name_ << "If" << extends << " {" << endl <<
1145 " public:" << endl;
1146 indent_up();
1147 f_header_ <<
1148 indent() << "virtual ~" << service_name_ << "Null() {}" << endl;
1149 vector<t_function*> functions = tservice->get_functions();
1150 vector<t_function*>::iterator f_iter;
1151 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1152 f_header_ <<
1153 indent() << function_signature(*f_iter) << " {" << endl;
1154 indent_up();
1155 t_type* returntype = (*f_iter)->get_returntype();
1156 if (returntype->is_void()) {
1157 f_header_ <<
1158 indent() << "return;" << endl;
1159 } else {
1160 if (is_complex_type(returntype)) {
1161 f_header_ <<
1162 indent() << "return;" << endl;
1163 } else {
1164 t_field returnfield(returntype, "_return");
1165 f_header_ <<
1166 indent() << declare_field(&returnfield, true) << endl <<
1167 indent() << "return _return;" << endl;
1170 indent_down();
1171 f_header_ <<
1172 indent() << "}" << endl;
1174 indent_down();
1175 f_header_ <<
1176 "};" << endl << endl;
1181 * Generates a multiface, which is a single server that just takes a set
1182 * of objects implementing the interface and calls them all, returning the
1183 * value of the last one to be called.
1185 * @param tservice The service to generate a multiserver for.
1187 void t_cpp_generator::generate_service_multiface(t_service* tservice) {
1188 // Generate the dispatch methods
1189 vector<t_function*> functions = tservice->get_functions();
1190 vector<t_function*>::iterator f_iter;
1192 string extends = "";
1193 string extends_multiface = "";
1194 if (tservice->get_extends() != NULL) {
1195 extends = type_name(tservice->get_extends());
1196 extends_multiface = ", public " + extends + "Multiface";
1199 string list_type = string("std::vector<boost::shared_ptr<") + service_name_ + "If> >";
1201 // Generate the header portion
1202 f_header_ <<
1203 "class " << service_name_ << "Multiface : " <<
1204 "virtual public " << service_name_ << "If" <<
1205 extends_multiface << " {" << endl <<
1206 " public:" << endl;
1207 indent_up();
1208 f_header_ <<
1209 indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
1210 if (!extends.empty()) {
1211 f_header_ <<
1212 indent() << " std::vector<boost::shared_ptr<" + service_name_ + "If> >::iterator iter;" << endl <<
1213 indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl <<
1214 indent() << " " << extends << "Multiface::add(*iter);" << endl <<
1215 indent() << " }" << endl;
1217 f_header_ <<
1218 indent() << "}" << endl <<
1219 indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl;
1220 indent_down();
1222 // Protected data members
1223 f_header_ <<
1224 " protected:" << endl;
1225 indent_up();
1226 f_header_ <<
1227 indent() << list_type << " ifaces_;" << endl <<
1228 indent() << service_name_ << "Multiface() {}" << endl <<
1229 indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) {" << endl;
1230 if (!extends.empty()) {
1231 f_header_ <<
1232 indent() << " " << extends << "Multiface::add(iface);" << endl;
1234 f_header_ <<
1235 indent() << " ifaces_.push_back(iface);" << endl <<
1236 indent() << "}" << endl;
1237 indent_down();
1239 f_header_ <<
1240 indent() << " public:" << endl;
1241 indent_up();
1243 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1244 t_struct* arglist = (*f_iter)->get_arglist();
1245 const vector<t_field*>& args = arglist->get_members();
1246 vector<t_field*>::const_iterator a_iter;
1248 string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
1249 bool first = true;
1250 if (is_complex_type((*f_iter)->get_returntype())) {
1251 call += "_return";
1252 first = false;
1254 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
1255 if (first) {
1256 first = false;
1257 } else {
1258 call += ", ";
1260 call += (*a_iter)->get_name();
1262 call += ")";
1264 f_header_ <<
1265 indent() << function_signature(*f_iter) << " {" << endl;
1266 indent_up();
1267 f_header_ <<
1268 indent() << "uint32_t sz = ifaces_.size();" << endl <<
1269 indent() << "for (uint32_t i = 0; i < sz; ++i) {" << endl;
1270 if (!(*f_iter)->get_returntype()->is_void()) {
1271 f_header_ <<
1272 indent() << " if (i == sz - 1) {" << endl;
1273 if (is_complex_type((*f_iter)->get_returntype())) {
1274 f_header_ <<
1275 indent() << " " << call << ";" << endl <<
1276 indent() << " return;" << endl;
1277 } else {
1278 f_header_ <<
1279 indent() << " return " << call << ";" << endl;
1281 f_header_ <<
1282 indent() << " } else {" << endl <<
1283 indent() << " " << call << ";" << endl <<
1284 indent() << " }" << endl;
1285 } else {
1286 f_header_ <<
1287 indent() << " " << call << ";" << endl;
1290 f_header_ <<
1291 indent() << "}" << endl;
1293 indent_down();
1294 f_header_ <<
1295 indent() << "}" << endl <<
1296 endl;
1299 indent_down();
1300 f_header_ <<
1301 indent() << "};" << endl <<
1302 endl;
1306 * Generates a service client definition.
1308 * @param tservice The service to generate a server for.
1310 void t_cpp_generator::generate_service_client(t_service* tservice) {
1311 string extends = "";
1312 string extends_client = "";
1313 if (tservice->get_extends() != NULL) {
1314 extends = type_name(tservice->get_extends());
1315 extends_client = ", public " + extends + "Client";
1318 // Generate the header portion
1319 f_header_ <<
1320 "class " << service_name_ << "Client : " <<
1321 "virtual public " << service_name_ << "If" <<
1322 extends_client << " {" << endl <<
1323 " public:" << endl;
1325 indent_up();
1326 f_header_ <<
1327 indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> prot) :" << endl;
1328 if (extends.empty()) {
1329 f_header_ <<
1330 indent() << " piprot_(prot)," << endl <<
1331 indent() << " poprot_(prot) {" << endl <<
1332 indent() << " iprot_ = prot.get();" << endl <<
1333 indent() << " oprot_ = prot.get();" << endl <<
1334 indent() << "}" << endl;
1335 } else {
1336 f_header_ <<
1337 indent() << " " << extends << "Client(prot, prot) {}" << endl;
1340 f_header_ <<
1341 indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) :" << endl;
1342 if (extends.empty()) {
1343 f_header_ <<
1344 indent() << " piprot_(iprot)," << endl <<
1345 indent() << " poprot_(oprot) {" << endl <<
1346 indent() << " iprot_ = iprot.get();" << endl <<
1347 indent() << " oprot_ = oprot.get();" << endl <<
1348 indent() << "}" << endl;
1349 } else {
1350 f_header_ <<
1351 indent() << " " << extends << "Client(iprot, oprot) {}" << endl;
1354 vector<t_function*> functions = tservice->get_functions();
1355 vector<t_function*>::const_iterator f_iter;
1356 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1357 t_function send_function(g_type_void,
1358 string("send_") + (*f_iter)->get_name(),
1359 (*f_iter)->get_arglist());
1360 indent(f_header_) << function_signature(*f_iter) << ";" << endl;
1361 indent(f_header_) << function_signature(&send_function) << ";" << endl;
1362 if (!(*f_iter)->is_async()) {
1363 t_struct noargs(program_);
1364 t_function recv_function((*f_iter)->get_returntype(),
1365 string("recv_") + (*f_iter)->get_name(),
1366 &noargs);
1367 indent(f_header_) << function_signature(&recv_function) << ";" << endl;
1370 indent_down();
1372 if (extends.empty()) {
1373 f_header_ <<
1374 " protected:" << endl;
1375 indent_up();
1376 f_header_ <<
1377 indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot_;" << endl <<
1378 indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot_;" << endl <<
1379 indent() << "facebook::thrift::protocol::TProtocol* iprot_;" << endl <<
1380 indent() << "facebook::thrift::protocol::TProtocol* oprot_;" << endl;
1381 indent_down();
1384 f_header_ <<
1385 "};" << endl <<
1386 endl;
1388 string scope = service_name_ + "Client::";
1390 // Generate client method implementations
1391 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1392 string funname = (*f_iter)->get_name();
1394 // Open function
1395 indent(f_service_) <<
1396 function_signature(*f_iter, scope) << endl;
1397 scope_up(f_service_);
1398 indent(f_service_) <<
1399 "send_" << funname << "(";
1401 // Get the struct of function call params
1402 t_struct* arg_struct = (*f_iter)->get_arglist();
1404 // Declare the function arguments
1405 const vector<t_field*>& fields = arg_struct->get_members();
1406 vector<t_field*>::const_iterator fld_iter;
1407 bool first = true;
1408 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1409 if (first) {
1410 first = false;
1411 } else {
1412 f_service_ << ", ";
1414 f_service_ << (*fld_iter)->get_name();
1416 f_service_ << ");" << endl;
1418 if (!(*f_iter)->is_async()) {
1419 f_service_ << indent();
1420 if (!(*f_iter)->get_returntype()->is_void()) {
1421 if (is_complex_type((*f_iter)->get_returntype())) {
1422 f_service_ << "recv_" << funname << "(_return);" << endl;
1423 } else {
1424 f_service_ << "return recv_" << funname << "();" << endl;
1426 } else {
1427 f_service_ <<
1428 "recv_" << funname << "();" << endl;
1431 scope_down(f_service_);
1432 f_service_ << endl;
1434 // Function for sending
1435 t_function send_function(g_type_void,
1436 string("send_") + (*f_iter)->get_name(),
1437 (*f_iter)->get_arglist());
1439 // Open the send function
1440 indent(f_service_) <<
1441 function_signature(&send_function, scope) << endl;
1442 scope_up(f_service_);
1444 // Function arguments and results
1445 string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs";
1446 string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult";
1448 // Serialize the request
1449 f_service_ <<
1450 indent() << "int32_t cseqid = 0;" << endl <<
1451 indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl <<
1452 endl <<
1453 indent() << argsname << " args;" << endl;
1455 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1456 f_service_ <<
1457 indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl;
1460 f_service_ <<
1461 indent() << "args.write(oprot_);" << endl <<
1462 endl <<
1463 indent() << "oprot_->writeMessageEnd();" << endl <<
1464 indent() << "oprot_->getTransport()->flush();" << endl <<
1465 indent() << "oprot_->getTransport()->writeEnd();" << endl;
1467 scope_down(f_service_);
1468 f_service_ << endl;
1470 // Generate recv function only if not an async function
1471 if (!(*f_iter)->is_async()) {
1472 t_struct noargs(program_);
1473 t_function recv_function((*f_iter)->get_returntype(),
1474 string("recv_") + (*f_iter)->get_name(),
1475 &noargs);
1476 // Open function
1477 indent(f_service_) <<
1478 function_signature(&recv_function, scope) << endl;
1479 scope_up(f_service_);
1481 f_service_ <<
1482 endl <<
1483 indent() << "int32_t rseqid = 0;" << endl <<
1484 indent() << "std::string fname;" << endl <<
1485 indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
1486 endl <<
1487 indent() << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl <<
1488 indent() << "if (mtype == facebook::thrift::protocol::T_EXCEPTION) {" << endl <<
1489 indent() << " facebook::thrift::TApplicationException x;" << endl <<
1490 indent() << " x.read(iprot_);" << endl <<
1491 indent() << " iprot_->readMessageEnd();" << endl <<
1492 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1493 indent() << " throw x;" << endl <<
1494 indent() << "}" << endl <<
1495 indent() << "if (mtype != facebook::thrift::protocol::T_REPLY) {" << endl <<
1496 indent() << " iprot_->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1497 indent() << " iprot_->readMessageEnd();" << endl <<
1498 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1499 indent() << " throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1500 indent() << "}" << endl <<
1501 indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl <<
1502 indent() << " iprot_->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1503 indent() << " iprot_->readMessageEnd();" << endl <<
1504 indent() << " iprot_->getTransport()->readEnd();" << endl <<
1505 indent() << " throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::WRONG_METHOD_NAME);" << endl <<
1506 indent() << "}" << endl;
1508 if (!(*f_iter)->get_returntype()->is_void() &&
1509 !is_complex_type((*f_iter)->get_returntype())) {
1510 t_field returnfield((*f_iter)->get_returntype(), "_return");
1511 f_service_ <<
1512 indent() << declare_field(&returnfield) << endl;
1515 f_service_ <<
1516 indent() << resultname << " result;" << endl;
1518 if (!(*f_iter)->get_returntype()->is_void()) {
1519 f_service_ <<
1520 indent() << "result.success = &_return;" << endl;
1523 f_service_ <<
1524 indent() << "result.read(iprot_);" << endl <<
1525 indent() << "iprot_->readMessageEnd();" << endl <<
1526 indent() << "iprot_->getTransport()->readEnd();" << endl <<
1527 endl;
1529 // Careful, only look for _result if not a void function
1530 if (!(*f_iter)->get_returntype()->is_void()) {
1531 if (is_complex_type((*f_iter)->get_returntype())) {
1532 f_service_ <<
1533 indent() << "if (result.__isset.success) {" << endl <<
1534 indent() << " // _return pointer has now been filled" << endl <<
1535 indent() << " return;" << endl <<
1536 indent() << "}" << endl;
1537 } else {
1538 f_service_ <<
1539 indent() << "if (result.__isset.success) {" << endl <<
1540 indent() << " return _return;" << endl <<
1541 indent() << "}" << endl;
1545 t_struct* xs = (*f_iter)->get_xceptions();
1546 const std::vector<t_field*>& xceptions = xs->get_members();
1547 vector<t_field*>::const_iterator x_iter;
1548 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1549 f_service_ <<
1550 indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
1551 indent() << " throw result." << (*x_iter)->get_name() << ";" << endl <<
1552 indent() << "}" << endl;
1555 // We only get here if we are a void function
1556 if ((*f_iter)->get_returntype()->is_void()) {
1557 indent(f_service_) <<
1558 "return;" << endl;
1559 } else {
1560 f_service_ <<
1561 indent() << "throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1564 // Close function
1565 scope_down(f_service_);
1566 f_service_ << endl;
1572 * Generates a service server definition.
1574 * @param tservice The service to generate a server for.
1576 void t_cpp_generator::generate_service_processor(t_service* tservice) {
1577 // Generate the dispatch methods
1578 vector<t_function*> functions = tservice->get_functions();
1579 vector<t_function*>::iterator f_iter;
1581 string extends = "";
1582 string extends_processor = "";
1583 if (tservice->get_extends() != NULL) {
1584 extends = type_name(tservice->get_extends());
1585 extends_processor = ", public " + extends + "Processor";
1588 // Generate the header portion
1589 f_header_ <<
1590 "class " << service_name_ << "Processor : " <<
1591 "virtual public facebook::thrift::TProcessor" <<
1592 extends_processor << " {" << endl;
1594 // Protected data members
1595 f_header_ <<
1596 " protected:" << endl;
1597 indent_up();
1598 f_header_ <<
1599 indent() << "boost::shared_ptr<" << service_name_ << "If> iface_;" << endl;
1600 f_header_ <<
1601 indent() << "virtual bool process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid);" << endl;
1602 indent_down();
1604 // Process function declarations
1605 f_header_ <<
1606 " private:" << endl;
1607 indent_up();
1608 f_header_ <<
1609 indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)> processMap_;" << endl;
1610 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1611 indent(f_header_) <<
1612 "void process_" << (*f_iter)->get_name() << "(int32_t seqid, facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot);" << endl;
1614 indent_down();
1616 indent_up();
1617 string declare_map = "";
1618 indent_up();
1620 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1621 declare_map += indent();
1622 declare_map += "processMap_[\"";
1623 declare_map += (*f_iter)->get_name();
1624 declare_map += "\"] = &";
1625 declare_map += service_name_;
1626 declare_map += "Processor::process_";
1627 declare_map += (*f_iter)->get_name();
1628 declare_map += ";\n";
1630 indent_down();
1632 f_header_ <<
1633 " public:" << endl <<
1634 indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface) :" << endl;
1635 if (extends.empty()) {
1636 f_header_ <<
1637 indent() << " iface_(iface) {" << endl;
1638 } else {
1639 f_header_ <<
1640 indent() << " " << extends << "Processor(iface)," << endl <<
1641 indent() << " iface_(iface) {" << endl;
1643 f_header_ <<
1644 declare_map <<
1645 indent() << "}" << endl <<
1646 endl <<
1647 indent() << "virtual bool process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot);" << endl <<
1648 indent() << "virtual ~" << service_name_ << "Processor() {}" << endl;
1649 indent_down();
1650 f_header_ <<
1651 "};" << endl << endl;
1653 // Generate the server implementation
1654 f_service_ <<
1655 "bool " << service_name_ << "Processor::process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> piprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> poprot) {" << endl;
1656 indent_up();
1658 f_service_ <<
1659 endl <<
1660 indent() << "facebook::thrift::protocol::TProtocol* iprot = piprot.get();" << endl <<
1661 indent() << "facebook::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
1662 indent() << "std::string fname;" << endl <<
1663 indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
1664 indent() << "int32_t seqid;" << endl <<
1665 endl <<
1666 indent() << "iprot->readMessageBegin(fname, mtype, seqid);" << endl <<
1667 endl <<
1668 indent() << "if (mtype != facebook::thrift::protocol::T_CALL) {" << endl <<
1669 indent() << " iprot->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1670 indent() << " iprot->readMessageEnd();" << endl <<
1671 indent() << " iprot->getTransport()->readEnd();" << endl <<
1672 indent() << " facebook::thrift::TApplicationException x(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
1673 indent() << " oprot->writeMessageBegin(fname, facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1674 indent() << " x.write(oprot);" << endl <<
1675 indent() << " oprot->writeMessageEnd();" << endl <<
1676 indent() << " oprot->getTransport()->flush();" << endl <<
1677 indent() << " oprot->getTransport()->writeEnd();" << endl <<
1678 indent() << " return true;" << endl <<
1679 indent() << "}" << endl <<
1680 endl <<
1681 indent() << "return process_fn(iprot, oprot, fname, seqid);" <<
1682 endl;
1684 indent_down();
1685 f_service_ <<
1686 indent() << "}" << endl <<
1687 endl;
1689 f_service_ <<
1690 "bool " << service_name_ << "Processor::process_fn(facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid) {" << endl;
1691 indent_up();
1693 // HOT: member function pointer map
1694 f_service_ <<
1695 indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, facebook::thrift::protocol::TProtocol*, facebook::thrift::protocol::TProtocol*)>::iterator pfn;" << endl <<
1696 indent() << "pfn = processMap_.find(fname);" << endl <<
1697 indent() << "if (pfn == processMap_.end()) {" << endl;
1698 if (extends.empty()) {
1699 f_service_ <<
1700 indent() << " iprot->skip(facebook::thrift::protocol::T_STRUCT);" << endl <<
1701 indent() << " iprot->readMessageEnd();" << endl <<
1702 indent() << " iprot->getTransport()->readEnd();" << endl <<
1703 indent() << " facebook::thrift::TApplicationException x(facebook::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: '\"+fname+\"'\");" << endl <<
1704 indent() << " oprot->writeMessageBegin(fname, facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1705 indent() << " x.write(oprot);" << endl <<
1706 indent() << " oprot->writeMessageEnd();" << endl <<
1707 indent() << " oprot->getTransport()->flush();" << endl <<
1708 indent() << " oprot->getTransport()->writeEnd();" << endl <<
1709 indent() << " return true;" << endl;
1710 } else {
1711 f_service_ <<
1712 indent() << " return " << extends << "Processor::process_fn(iprot, oprot, fname, seqid);" << endl;
1714 f_service_ <<
1715 indent() << "} else {" << endl <<
1716 indent() << " (this->*(pfn->second))(seqid, iprot, oprot);" << endl <<
1717 indent() << "}" << endl;
1719 // Read end of args field, the T_STOP, and the struct close
1720 f_service_ <<
1721 indent() << "return true;" << endl;
1723 indent_down();
1724 f_service_ <<
1725 "}" << endl <<
1726 endl;
1728 // Generate the process subfunctions
1729 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1730 generate_process_function(tservice, *f_iter);
1735 * Generates a struct and helpers for a function.
1737 * @param tfunction The function
1739 void t_cpp_generator::generate_function_helpers(t_service* tservice,
1740 t_function* tfunction) {
1741 if (tfunction->is_async()) {
1742 return;
1745 t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result");
1746 t_field success(tfunction->get_returntype(), "success", 0);
1747 if (!tfunction->get_returntype()->is_void()) {
1748 result.append(&success);
1751 t_struct* xs = tfunction->get_xceptions();
1752 const vector<t_field*>& fields = xs->get_members();
1753 vector<t_field*>::const_iterator f_iter;
1754 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1755 result.append(*f_iter);
1758 generate_struct_definition(f_header_, &result, false);
1759 generate_struct_reader(f_service_, &result);
1760 generate_struct_result_writer(f_service_, &result);
1762 result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
1763 generate_struct_definition(f_header_, &result, false, true, true, false);
1764 generate_struct_reader(f_service_, &result, true);
1769 * Generates a process function definition.
1771 * @param tfunction The function to write a dispatcher for
1773 void t_cpp_generator::generate_process_function(t_service* tservice,
1774 t_function* tfunction) {
1775 // Open function
1776 f_service_ <<
1777 "void " << tservice->get_name() << "Processor::" <<
1778 "process_" << tfunction->get_name() <<
1779 "(int32_t seqid, facebook::thrift::protocol::TProtocol* iprot, facebook::thrift::protocol::TProtocol* oprot)" << endl;
1780 scope_up(f_service_);
1782 string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
1783 string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
1785 f_service_ <<
1786 indent() << argsname << " args;" << endl <<
1787 indent() << "args.read(iprot);" << endl <<
1788 indent() << "iprot->readMessageEnd();" << endl <<
1789 indent() << "iprot->getTransport()->readEnd();" << endl <<
1790 endl;
1792 t_struct* xs = tfunction->get_xceptions();
1793 const std::vector<t_field*>& xceptions = xs->get_members();
1794 vector<t_field*>::const_iterator x_iter;
1796 // Declare result
1797 if (!tfunction->is_async()) {
1798 f_service_ <<
1799 indent() << resultname << " result;" << endl;
1802 // Try block for functions with exceptions
1803 f_service_ <<
1804 indent() << "try {" << endl;
1805 indent_up();
1807 // Generate the function call
1808 t_struct* arg_struct = tfunction->get_arglist();
1809 const std::vector<t_field*>& fields = arg_struct->get_members();
1810 vector<t_field*>::const_iterator f_iter;
1812 bool first = true;
1813 f_service_ << indent();
1814 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1815 if (is_complex_type(tfunction->get_returntype())) {
1816 first = false;
1817 f_service_ << "iface_->" << tfunction->get_name() << "(result.success";
1818 } else {
1819 f_service_ << "result.success = iface_->" << tfunction->get_name() << "(";
1821 } else {
1822 f_service_ <<
1823 "iface_->" << tfunction->get_name() << "(";
1825 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1826 if (first) {
1827 first = false;
1828 } else {
1829 f_service_ << ", ";
1831 f_service_ << "args." << (*f_iter)->get_name();
1833 f_service_ << ");" << endl;
1835 // Set isset on success field
1836 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
1837 f_service_ <<
1838 indent() << "result.__isset.success = true;" << endl;
1841 indent_down();
1842 f_service_ << indent() << "}";
1844 if (!tfunction->is_async()) {
1845 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1846 f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " &" << (*x_iter)->get_name() << ") {" << endl;
1847 if (!tfunction->is_async()) {
1848 indent_up();
1849 f_service_ <<
1850 indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
1851 indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
1852 indent_down();
1853 f_service_ << indent() << "}";
1854 } else {
1855 f_service_ << "}";
1860 f_service_ << " catch (const std::exception& e) {" << endl;
1862 if (!tfunction->is_async()) {
1863 indent_up();
1864 f_service_ <<
1865 indent() << "facebook::thrift::TApplicationException x(e.what());" << endl <<
1866 indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
1867 indent() << "x.write(oprot);" << endl <<
1868 indent() << "oprot->writeMessageEnd();" << endl <<
1869 indent() << "oprot->getTransport()->flush();" << endl <<
1870 indent() << "oprot->getTransport()->writeEnd();" << endl <<
1871 indent() << "return;" << endl;
1872 indent_down();
1874 f_service_ << indent() << "}" << endl;
1876 // Shortcut out here for async functions
1877 if (tfunction->is_async()) {
1878 f_service_ <<
1879 indent() << "return;" << endl;
1880 indent_down();
1881 f_service_ << "}" << endl <<
1882 endl;
1883 return;
1886 // Serialize the result into a struct
1887 f_service_ <<
1888 endl <<
1889 indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_REPLY, seqid);" << endl <<
1890 indent() << "result.write(oprot);" << endl <<
1891 indent() << "oprot->writeMessageEnd();" << endl <<
1892 indent() << "oprot->getTransport()->flush();" << endl <<
1893 indent() << "oprot->getTransport()->writeEnd();" << endl;
1895 // Close function
1896 scope_down(f_service_);
1897 f_service_ << endl;
1901 * Helper function for generate_service_limited_reflector.
1902 * Generates a reflection of a single simple type.
1904 * @param ttype The type to reflect
1905 * @param target The name of the lvalue to reflect onto
1906 * @return true iff the type really is simple
1908 * Note: don't let this function output anything unless it is going to return true.
1910 bool t_cpp_generator::generate_simple_type_limited_reflection(ostream & out, t_type* ttype, string target) {
1911 if (ttype->is_base_type()) {
1912 string type;
1913 switch (((t_base_type*)ttype)->get_base()) {
1914 case t_base_type::TYPE_VOID : type = "T_VOID;" ; break;
1915 case t_base_type::TYPE_STRING : type = "T_STRING;" ; break;
1916 case t_base_type::TYPE_BOOL : type = "T_BOOL;" ; break;
1917 case t_base_type::TYPE_BYTE : type = "T_BYTE;" ; break;
1918 case t_base_type::TYPE_I16 : type = "T_I16;" ; break;
1919 case t_base_type::TYPE_I32 : type = "T_I32;" ; break;
1920 case t_base_type::TYPE_I64 : type = "T_I64;" ; break;
1921 case t_base_type::TYPE_DOUBLE : type = "T_DOUBLE;" ; break;
1922 default: return false;
1924 out << indent() << target << ".ttype = " << type << endl;
1925 return true;
1928 if (ttype->is_enum()) {
1929 out <<
1930 indent() << target << ".ttype = T_ENUM;" << endl <<
1931 indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl;
1934 if (ttype->is_struct()) {
1935 out <<
1936 indent() << target << ".ttype = T_STRUCT;" << endl <<
1937 indent() << target << ".name = \"" << ttype->get_name() << "\";" << endl;
1938 return true;
1941 return false;
1945 * Helper function for generate_service_limited_reflector.
1946 * Generates a reflection of a single type.
1948 * @param ttype The type to reflect
1949 * @param target The name of the lvalue to reflect onto
1951 bool t_cpp_generator::generate_type_limited_reflection(t_type* ttype, string target) {
1952 bool is_simple = generate_simple_type_limited_reflection(f_service_, ttype, target + ".simple_type");
1953 if (is_simple) {
1954 f_service_ <<
1955 indent() << target << ".is_container = false;" << endl <<
1956 indent() << target << ".__isset.simple_type = true;" << endl;
1957 return true;
1960 ostringstream out;
1962 out <<
1963 indent() << target << ".is_container = true;" << endl <<
1964 indent() << target << ".__isset.container_type = true;" << endl <<
1965 indent() << target << ".container_type.ttype = ";
1967 if (ttype->is_list()) out << "T_LIST;" << endl;
1968 if (ttype->is_set()) out << "T_SET;" << endl;
1969 if (ttype->is_map()) out << "T_MAP;" << endl;
1971 bool reflected = false;
1973 if (ttype->is_list()) {
1974 reflected = generate_simple_type_limited_reflection(
1975 out, ((t_list*)ttype)->get_elem_type(), target + ".container_type.subtype1");
1977 if (ttype->is_set()) {
1978 reflected = generate_simple_type_limited_reflection(
1979 out, ((t_set*)ttype)->get_elem_type(), target + ".container_type.subtype1");
1981 if (ttype->is_map()) {
1982 reflected =
1983 generate_simple_type_limited_reflection(
1984 out, ((t_map*)ttype)->get_key_type(), target + ".container_type.subtype1")
1986 generate_simple_type_limited_reflection(
1987 out, ((t_map*)ttype)->get_val_type(), target + ".container_type.subtype2");
1988 out << indent() << target << ".container_type.__isset.subtype2 = true;" << endl;
1991 if (reflected) {
1992 f_service_ << out.str();
1993 return true;
1994 } else {
1995 f_service_ <<
1996 indent() << target << ".is_container = false;" << endl <<
1997 indent() << target << ".__isset.simple_type = true;" << endl;
1998 f_service_ << indent() << target << ".simple_type.ttype = T_NOT_REFLECTED;" << endl;
1999 return false;
2004 * Generates a service reflector definition.
2005 * This uses thrift::reflection::limited.
2007 * @param tservice The service to write a reflector for
2009 void t_cpp_generator::generate_service_limited_reflector(t_service* tservice) {
2010 // Open function
2011 f_service_ <<
2012 indent() << "void " << tservice->get_name() << "If::getStaticLimitedReflection" <<
2013 "(facebook::thrift::reflection::limited::Service & _return) ";
2014 scope_up(f_service_);
2016 f_service_ << indent() << "using namespace facebook::thrift::reflection::limited;" << endl;
2018 f_service_ << indent() << "_return.name = \"" << tservice->get_name() << "\";" << endl;
2019 f_service_ << indent() << "_return.fully_reflected = true;" << endl;
2021 bool all_reflectable = true;
2022 bool one_reflectable;
2024 const vector<t_function*> & funcs = tservice->get_functions();
2025 vector<t_function*>::const_iterator f_iter;
2026 for (f_iter = funcs.begin(); f_iter != funcs.end(); ++f_iter) {
2028 f_service_ << indent() << "_return.methods.resize(_return.methods.size() + 1);" << endl;
2029 f_service_ << indent() << "_return.methods.back().name = \"" << (*f_iter)->get_name() << "\";" << endl;
2030 one_reflectable = generate_type_limited_reflection(
2031 (*f_iter)->get_returntype(), "_return.methods.back().return_type");
2032 all_reflectable = all_reflectable && one_reflectable;
2034 t_struct* arglist = (*f_iter)->get_arglist();
2035 const vector<t_field*> & args = arglist->get_members();
2036 vector<t_field*>::const_iterator a_iter;
2037 for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
2038 f_service_ <<
2039 indent() << "_return.methods.back().arguments.resize("
2040 "_return.methods.back().arguments.size() + 1);" << endl <<
2041 indent() << "_return.methods.back().arguments.back().name = \"" <<
2042 (*a_iter)->get_name() << "\";" << endl <<
2043 indent() << "_return.methods.back().arguments.back().key = " <<
2044 (*a_iter)->get_key() << ";" << endl;
2045 one_reflectable = generate_type_limited_reflection(
2046 (*a_iter)->get_type(), "_return.methods.back().arguments.back().type");
2047 all_reflectable = all_reflectable && one_reflectable;
2051 if (!all_reflectable) {
2052 f_service_ << indent() << "_return.fully_reflected = false;" << endl;
2055 // Close function
2056 scope_down(f_service_);
2057 f_service_ << endl;
2061 * Generates a skeleton file of a server
2063 * @param tservice The service to generate a server for.
2065 void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
2066 string svcname = tservice->get_name();
2068 // Service implementation file includes
2069 string f_skeleton_name = get_out_dir()+svcname+"_server.skeleton.cpp";
2071 string ns = namespace_prefix(tservice->get_program()->get_cpp_namespace());
2073 ofstream f_skeleton;
2074 f_skeleton.open(f_skeleton_name.c_str());
2075 f_skeleton <<
2076 "// This autogenerated skeleton file illustrates how to build a server." << endl <<
2077 "// You should copy it to another filename to avoid overwriting it." << endl <<
2078 endl <<
2079 "#include \"" << svcname << ".h\"" << endl <<
2080 "#include <protocol/TBinaryProtocol.h>" << endl <<
2081 "#include <server/TSimpleServer.h>" << endl <<
2082 "#include <transport/TServerSocket.h>" << endl <<
2083 "#include <transport/TTransportUtils.h>" << endl <<
2084 endl <<
2085 "using namespace facebook::thrift;" << endl <<
2086 "using namespace facebook::thrift::protocol;" << endl <<
2087 "using namespace facebook::thrift::transport;" << endl <<
2088 "using namespace facebook::thrift::server;" << endl <<
2089 endl <<
2090 "using boost::shared_ptr;" << endl <<
2091 endl;
2093 if (!ns.empty()) {
2094 f_skeleton <<
2095 "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
2096 endl;
2099 f_skeleton <<
2100 "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl <<
2101 " public:" << endl;
2102 indent_up();
2103 f_skeleton <<
2104 indent() << svcname << "Handler() {" << endl <<
2105 indent() << " // Your initialization goes here" << endl <<
2106 indent() << "}" << endl <<
2107 endl;
2109 vector<t_function*> functions = tservice->get_functions();
2110 vector<t_function*>::iterator f_iter;
2111 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2112 f_skeleton <<
2113 indent() << function_signature(*f_iter) << " {" << endl <<
2114 indent() << " // Your implementation goes here" << endl <<
2115 indent() << " printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl <<
2116 indent() << "}" << endl <<
2117 endl;
2120 indent_down();
2121 f_skeleton <<
2122 "};" << endl <<
2123 endl;
2125 f_skeleton <<
2126 indent() << "int main(int argc, char **argv) {" << endl;
2127 indent_up();
2128 f_skeleton <<
2129 indent() << "int port = 9090;" << endl <<
2130 indent() << "shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl <<
2131 indent() << "shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl <<
2132 indent() << "shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));" << endl <<
2133 indent() << "shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl <<
2134 indent() << "shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());" << endl <<
2135 endl <<
2136 indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl <<
2137 indent() << "server.serve();" << endl <<
2138 indent() << "return 0;" << endl;
2139 indent_down();
2140 f_skeleton <<
2141 "}" << endl <<
2142 endl;
2144 // Close the files
2145 f_skeleton.close();
2149 * Deserializes a field of any type.
2151 void t_cpp_generator::generate_deserialize_field(ofstream& out,
2152 t_field* tfield,
2153 string prefix,
2154 string suffix) {
2155 t_type* type = get_true_type(tfield->get_type());
2157 if (type->is_void()) {
2158 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
2159 prefix + tfield->get_name();
2162 string name = prefix + tfield->get_name() + suffix;
2164 if (type->is_struct() || type->is_xception()) {
2165 generate_deserialize_struct(out, (t_struct*)type, name);
2166 } else if (type->is_container()) {
2167 generate_deserialize_container(out, type, name);
2168 } else if (type->is_base_type()) {
2169 indent(out) <<
2170 "xfer += iprot->";
2171 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2172 switch (tbase) {
2173 case t_base_type::TYPE_VOID:
2174 throw "compiler error: cannot serialize void field in a struct: " + name;
2175 break;
2176 case t_base_type::TYPE_STRING:
2177 out << "readString(" << name << ");";
2178 break;
2179 case t_base_type::TYPE_BOOL:
2180 out << "readBool(" << name << ");";
2181 break;
2182 case t_base_type::TYPE_BYTE:
2183 out << "readByte(" << name << ");";
2184 break;
2185 case t_base_type::TYPE_I16:
2186 out << "readI16(" << name << ");";
2187 break;
2188 case t_base_type::TYPE_I32:
2189 out << "readI32(" << name << ");";
2190 break;
2191 case t_base_type::TYPE_I64:
2192 out << "readI64(" << name << ");";
2193 break;
2194 case t_base_type::TYPE_DOUBLE:
2195 out << "readDouble(" << name << ");";
2196 break;
2197 default:
2198 throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
2200 out <<
2201 endl;
2202 } else if (type->is_enum()) {
2203 string t = tmp("ecast");
2204 out <<
2205 indent() << "int32_t " << t << ";" << endl <<
2206 indent() << "xfer += iprot->readI32(" << t << ");" << endl <<
2207 indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
2208 } else {
2209 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
2210 tfield->get_name().c_str(), type_name(type).c_str());
2215 * Generates an unserializer for a variable. This makes two key assumptions,
2216 * first that there is a const char* variable named data that points to the
2217 * buffer for deserialization, and that there is a variable protocol which
2218 * is a reference to a TProtocol serialization object.
2220 void t_cpp_generator::generate_deserialize_struct(ofstream& out,
2221 t_struct* tstruct,
2222 string prefix) {
2223 indent(out) <<
2224 "xfer += " << prefix << ".read(iprot);" << endl;
2227 void t_cpp_generator::generate_deserialize_container(ofstream& out,
2228 t_type* ttype,
2229 string prefix) {
2230 scope_up(out);
2232 string size = tmp("_size");
2233 string ktype = tmp("_ktype");
2234 string vtype = tmp("_vtype");
2235 string etype = tmp("_etype");
2237 indent(out) <<
2238 prefix << ".clear();" << endl <<
2239 indent() << "uint32_t " << size << ";" << endl;
2241 // Declare variables, read header
2242 if (ttype->is_map()) {
2243 out <<
2244 indent() << "facebook::thrift::protocol::TType " << ktype << ";" << endl <<
2245 indent() << "facebook::thrift::protocol::TType " << vtype << ";" << endl <<
2246 indent() << "iprot->readMapBegin(" <<
2247 ktype << ", " << vtype << ", " << size << ");" << endl;
2248 } else if (ttype->is_set()) {
2249 out <<
2250 indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
2251 indent() << "iprot->readSetBegin(" <<
2252 etype << ", " << size << ");" << endl;
2253 } else if (ttype->is_list()) {
2254 out <<
2255 indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
2256 indent() << "iprot->readListBegin(" <<
2257 etype << ", " << size << ");" << endl;
2261 // For loop iterates over elements
2262 string i = tmp("_i");
2263 out <<
2264 indent() << "uint32_t " << i << ";" << endl <<
2265 indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
2267 scope_up(out);
2269 if (ttype->is_map()) {
2270 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
2271 } else if (ttype->is_set()) {
2272 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
2273 } else if (ttype->is_list()) {
2274 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
2277 scope_down(out);
2279 // Read container end
2280 if (ttype->is_map()) {
2281 indent(out) << "iprot->readMapEnd();" << endl;
2282 } else if (ttype->is_set()) {
2283 indent(out) << "iprot->readSetEnd();" << endl;
2284 } else if (ttype->is_list()) {
2285 indent(out) << "iprot->readListEnd();" << endl;
2288 scope_down(out);
2293 * Generates code to deserialize a map
2295 void t_cpp_generator::generate_deserialize_map_element(ofstream& out,
2296 t_map* tmap,
2297 string prefix) {
2298 string key = tmp("_key");
2299 string val = tmp("_val");
2300 t_field fkey(tmap->get_key_type(), key);
2301 t_field fval(tmap->get_val_type(), val);
2303 out <<
2304 indent() << declare_field(&fkey) << endl <<
2305 indent() << declare_field(&fval) << endl;
2307 generate_deserialize_field(out, &fkey);
2308 generate_deserialize_field(out, &fval);
2310 indent(out) <<
2311 prefix << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
2314 void t_cpp_generator::generate_deserialize_set_element(ofstream& out,
2315 t_set* tset,
2316 string prefix) {
2317 string elem = tmp("_elem");
2318 t_field felem(tset->get_elem_type(), elem);
2320 indent(out) <<
2321 declare_field(&felem) << endl;
2323 generate_deserialize_field(out, &felem);
2325 indent(out) <<
2326 prefix << ".insert(" << elem << ");" << endl;
2329 void t_cpp_generator::generate_deserialize_list_element(ofstream& out,
2330 t_list* tlist,
2331 string prefix) {
2332 string elem = tmp("_elem");
2333 t_field felem(tlist->get_elem_type(), elem);
2335 indent(out) <<
2336 declare_field(&felem) << endl;
2338 generate_deserialize_field(out, &felem);
2340 indent(out) <<
2341 prefix << ".push_back(" << elem << ");" << endl;
2346 * Serializes a field of any type.
2348 * @param tfield The field to serialize
2349 * @param prefix Name to prepend to field name
2351 void t_cpp_generator::generate_serialize_field(ofstream& out,
2352 t_field* tfield,
2353 string prefix,
2354 string suffix) {
2355 t_type* type = get_true_type(tfield->get_type());
2357 string name = prefix + tfield->get_name() + suffix;
2359 // Do nothing for void types
2360 if (type->is_void()) {
2361 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
2366 if (type->is_struct() || type->is_xception()) {
2367 generate_serialize_struct(out,
2368 (t_struct*)type,
2369 name);
2370 } else if (type->is_container()) {
2371 generate_serialize_container(out, type, name);
2372 } else if (type->is_base_type() || type->is_enum()) {
2374 indent(out) <<
2375 "xfer += oprot->";
2377 if (type->is_base_type()) {
2378 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2379 switch (tbase) {
2380 case t_base_type::TYPE_VOID:
2381 throw
2382 "compiler error: cannot serialize void field in a struct: " + name;
2383 break;
2384 case t_base_type::TYPE_STRING:
2385 out << "writeString(" << name << ");";
2386 break;
2387 case t_base_type::TYPE_BOOL:
2388 out << "writeBool(" << name << ");";
2389 break;
2390 case t_base_type::TYPE_BYTE:
2391 out << "writeByte(" << name << ");";
2392 break;
2393 case t_base_type::TYPE_I16:
2394 out << "writeI16(" << name << ");";
2395 break;
2396 case t_base_type::TYPE_I32:
2397 out << "writeI32(" << name << ");";
2398 break;
2399 case t_base_type::TYPE_I64:
2400 out << "writeI64(" << name << ");";
2401 break;
2402 case t_base_type::TYPE_DOUBLE:
2403 out << "writeDouble(" << name << ");";
2404 break;
2405 default:
2406 throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + name;
2408 } else if (type->is_enum()) {
2409 out << "writeI32((int32_t)" << name << ");";
2411 out << endl;
2412 } else {
2413 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
2414 name.c_str(),
2415 type_name(type).c_str());
2420 * Serializes all the members of a struct.
2422 * @param tstruct The struct to serialize
2423 * @param prefix String prefix to attach to all fields
2425 void t_cpp_generator::generate_serialize_struct(ofstream& out,
2426 t_struct* tstruct,
2427 string prefix) {
2428 indent(out) <<
2429 "xfer += " << prefix << ".write(oprot);" << endl;
2432 void t_cpp_generator::generate_serialize_container(ofstream& out,
2433 t_type* ttype,
2434 string prefix) {
2435 scope_up(out);
2437 if (ttype->is_map()) {
2438 indent(out) <<
2439 "xfer += oprot->writeMapBegin(" <<
2440 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
2441 type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
2442 prefix << ".size());" << endl;
2443 } else if (ttype->is_set()) {
2444 indent(out) <<
2445 "xfer += oprot->writeSetBegin(" <<
2446 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
2447 prefix << ".size());" << endl;
2448 } else if (ttype->is_list()) {
2449 indent(out) <<
2450 "xfer += oprot->writeListBegin(" <<
2451 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
2452 prefix << ".size());" << endl;
2455 string iter = tmp("_iter");
2456 out <<
2457 indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl <<
2458 indent() << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl;
2459 scope_up(out);
2460 if (ttype->is_map()) {
2461 generate_serialize_map_element(out, (t_map*)ttype, iter);
2462 } else if (ttype->is_set()) {
2463 generate_serialize_set_element(out, (t_set*)ttype, iter);
2464 } else if (ttype->is_list()) {
2465 generate_serialize_list_element(out, (t_list*)ttype, iter);
2467 scope_down(out);
2469 if (ttype->is_map()) {
2470 indent(out) <<
2471 "xfer += oprot->writeMapEnd();" << endl;
2472 } else if (ttype->is_set()) {
2473 indent(out) <<
2474 "xfer += oprot->writeSetEnd();" << endl;
2475 } else if (ttype->is_list()) {
2476 indent(out) <<
2477 "xfer += oprot->writeListEnd();" << endl;
2480 scope_down(out);
2484 * Serializes the members of a map.
2487 void t_cpp_generator::generate_serialize_map_element(ofstream& out,
2488 t_map* tmap,
2489 string iter) {
2490 t_field kfield(tmap->get_key_type(), iter + "->first");
2491 generate_serialize_field(out, &kfield, "");
2493 t_field vfield(tmap->get_val_type(), iter + "->second");
2494 generate_serialize_field(out, &vfield, "");
2498 * Serializes the members of a set.
2500 void t_cpp_generator::generate_serialize_set_element(ofstream& out,
2501 t_set* tset,
2502 string iter) {
2503 t_field efield(tset->get_elem_type(), "(*" + iter + ")");
2504 generate_serialize_field(out, &efield, "");
2508 * Serializes the members of a list.
2510 void t_cpp_generator::generate_serialize_list_element(ofstream& out,
2511 t_list* tlist,
2512 string iter) {
2513 t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
2514 generate_serialize_field(out, &efield, "");
2518 * Makes a :: prefix for a namespace
2520 * @param ns The namepsace, w/ periods in it
2521 * @return Namespaces
2523 string t_cpp_generator::namespace_prefix(string ns) {
2524 if (ns.size() == 0) {
2525 return "";
2527 string result = "";
2528 string::size_type loc;
2529 while ((loc = ns.find(".")) != string::npos) {
2530 result += ns.substr(0, loc);
2531 result += "::";
2532 ns = ns.substr(loc+1);
2534 if (ns.size() > 0) {
2535 result += ns + "::";
2537 return result;
2541 * Opens namespace.
2543 * @param ns The namepsace, w/ periods in it
2544 * @return Namespaces
2546 string t_cpp_generator::namespace_open(string ns) {
2547 if (ns.size() == 0) {
2548 return "";
2550 string result = "";
2551 string separator = "";
2552 string::size_type loc;
2553 while ((loc = ns.find(".")) != string::npos) {
2554 result += separator;
2555 result += "namespace ";
2556 result += ns.substr(0, loc);
2557 result += " {";
2558 separator = " ";
2559 ns = ns.substr(loc+1);
2561 if (ns.size() > 0) {
2562 result += separator + "namespace " + ns + " {";
2564 return result;
2568 * Closes namespace.
2570 * @param ns The namepsace, w/ periods in it
2571 * @return Namespaces
2573 string t_cpp_generator::namespace_close(string ns) {
2574 if (ns.size() == 0) {
2575 return "";
2577 string result = "}";
2578 string::size_type loc;
2579 while ((loc = ns.find(".")) != string::npos) {
2580 result += "}";
2581 ns = ns.substr(loc+1);
2583 result += " // namespace";
2584 return result;
2588 * Returns a C++ type name
2590 * @param ttype The type
2591 * @return String of the type name, i.e. std::set<type>
2593 string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
2594 if (ttype->is_base_type()) {
2595 string bname = base_type_name(((t_base_type*)ttype)->get_base());
2596 if (!arg) {
2597 return bname;
2600 if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) {
2601 return "const " + bname + "&";
2602 } else {
2603 return "const " + bname;
2607 // Check for a custom overloaded C++ name
2608 if (ttype->is_container()) {
2609 string cname;
2611 t_container* tcontainer = (t_container*) ttype;
2612 if (tcontainer->has_cpp_name()) {
2613 cname = tcontainer->get_cpp_name();
2614 } else if (ttype->is_map()) {
2615 t_map* tmap = (t_map*) ttype;
2616 cname = "std::map<" +
2617 type_name(tmap->get_key_type(), in_typedef) + ", " +
2618 type_name(tmap->get_val_type(), in_typedef) + "> ";
2619 } else if (ttype->is_set()) {
2620 t_set* tset = (t_set*) ttype;
2621 cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> ";
2622 } else if (ttype->is_list()) {
2623 t_list* tlist = (t_list*) ttype;
2624 cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
2627 if (arg) {
2628 return "const " + cname + "&";
2629 } else {
2630 return cname;
2634 string class_prefix;
2635 if (in_typedef && (ttype->is_struct() || ttype->is_xception())) {
2636 class_prefix = "class ";
2639 // Check if it needs to be namespaced
2640 string pname;
2641 t_program* program = ttype->get_program();
2642 if (program != NULL && program != program_) {
2643 pname =
2644 class_prefix +
2645 namespace_prefix(program->get_cpp_namespace()) +
2646 ttype->get_name();
2647 } else {
2648 pname = class_prefix + ttype->get_name();
2651 if (arg) {
2652 if (is_complex_type(ttype)) {
2653 return "const " + pname + "&";
2654 } else {
2655 return "const " + pname;
2657 } else {
2658 return pname;
2663 * Returns the C++ type that corresponds to the thrift type.
2665 * @param tbase The base type
2666 * @return Explicit C++ type, i.e. "int32_t"
2668 string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
2669 switch (tbase) {
2670 case t_base_type::TYPE_VOID:
2671 return "void";
2672 case t_base_type::TYPE_STRING:
2673 return "std::string";
2674 case t_base_type::TYPE_BOOL:
2675 return "bool";
2676 case t_base_type::TYPE_BYTE:
2677 return "int8_t";
2678 case t_base_type::TYPE_I16:
2679 return "int16_t";
2680 case t_base_type::TYPE_I32:
2681 return "int32_t";
2682 case t_base_type::TYPE_I64:
2683 return "int64_t";
2684 case t_base_type::TYPE_DOUBLE:
2685 return "double";
2686 default:
2687 throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
2692 * Declares a field, which may include initialization as necessary.
2694 * @param ttype The type
2695 * @return Field declaration, i.e. int x = 0;
2697 string t_cpp_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant) {
2698 // TODO(mcslee): do we ever need to initialize the field?
2699 string result = "";
2700 if (constant) {
2701 result += "const ";
2703 result += type_name(tfield->get_type());
2704 if (pointer) {
2705 result += "*";
2707 result += " " + tfield->get_name();
2708 if (init) {
2709 t_type* type = get_true_type(tfield->get_type());
2711 if (type->is_base_type()) {
2712 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2713 switch (tbase) {
2714 case t_base_type::TYPE_VOID:
2715 break;
2716 case t_base_type::TYPE_STRING:
2717 result += " = \"\"";
2718 break;
2719 case t_base_type::TYPE_BOOL:
2720 result += " = false";
2721 break;
2722 case t_base_type::TYPE_BYTE:
2723 case t_base_type::TYPE_I16:
2724 case t_base_type::TYPE_I32:
2725 case t_base_type::TYPE_I64:
2726 result += " = 0";
2727 break;
2728 case t_base_type::TYPE_DOUBLE:
2729 result += " = (double)0";
2730 break;
2731 default:
2732 throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase);
2734 } else if (type->is_enum()) {
2735 result += " = (" + type_name(type) + ")0";
2738 return result + ";";
2742 * Renders a function signature of the form 'type name(args)'
2744 * @param tfunction Function definition
2745 * @return String of rendered function definition
2747 string t_cpp_generator::function_signature(t_function* tfunction,
2748 string prefix) {
2749 t_type* ttype = tfunction->get_returntype();
2750 t_struct* arglist = tfunction->get_arglist();
2752 if (is_complex_type(ttype)) {
2753 bool empty = arglist->get_members().size() == 0;
2754 return
2755 "void " + prefix + tfunction->get_name() +
2756 "(" + type_name(ttype) + "& _return" +
2757 (empty ? "" : (", " + argument_list(arglist))) + ")";
2758 } else {
2759 return
2760 type_name(ttype) + " " + prefix + tfunction->get_name() +
2761 "(" + argument_list(arglist) + ")";
2766 * Renders a field list
2768 * @param tstruct The struct definition
2769 * @return Comma sepearated list of all field names in that struct
2771 string t_cpp_generator::argument_list(t_struct* tstruct) {
2772 string result = "";
2774 const vector<t_field*>& fields = tstruct->get_members();
2775 vector<t_field*>::const_iterator f_iter;
2776 bool first = true;
2777 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2778 if (first) {
2779 first = false;
2780 } else {
2781 result += ", ";
2783 result += type_name((*f_iter)->get_type(), false, true) + " " + (*f_iter)->get_name();
2785 return result;
2789 * Converts the parse type to a C++ enum string for the given type.
2791 * @param type Thrift Type
2792 * @return String of C++ code to definition of that type constant
2794 string t_cpp_generator::type_to_enum(t_type* type) {
2795 type = get_true_type(type);
2797 if (type->is_base_type()) {
2798 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2799 switch (tbase) {
2800 case t_base_type::TYPE_VOID:
2801 throw "NO T_VOID CONSTRUCT";
2802 case t_base_type::TYPE_STRING:
2803 return "facebook::thrift::protocol::T_STRING";
2804 case t_base_type::TYPE_BOOL:
2805 return "facebook::thrift::protocol::T_BOOL";
2806 case t_base_type::TYPE_BYTE:
2807 return "facebook::thrift::protocol::T_BYTE";
2808 case t_base_type::TYPE_I16:
2809 return "facebook::thrift::protocol::T_I16";
2810 case t_base_type::TYPE_I32:
2811 return "facebook::thrift::protocol::T_I32";
2812 case t_base_type::TYPE_I64:
2813 return "facebook::thrift::protocol::T_I64";
2814 case t_base_type::TYPE_DOUBLE:
2815 return "facebook::thrift::protocol::T_DOUBLE";
2817 } else if (type->is_enum()) {
2818 return "facebook::thrift::protocol::T_I32";
2819 } else if (type->is_struct()) {
2820 return "facebook::thrift::protocol::T_STRUCT";
2821 } else if (type->is_xception()) {
2822 return "facebook::thrift::protocol::T_STRUCT";
2823 } else if (type->is_map()) {
2824 return "facebook::thrift::protocol::T_MAP";
2825 } else if (type->is_set()) {
2826 return "facebook::thrift::protocol::T_SET";
2827 } else if (type->is_list()) {
2828 return "facebook::thrift::protocol::T_LIST";
2831 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2835 * Returns the symbol name of the local reflection of a type.
2837 string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype) {
2838 ttype = get_true_type(ttype);
2840 // We have to use the program name as part of the identifier because
2841 // if two thrift "programs" are compiled into one actual program
2842 // you would get a symbol collison if they both defined list<i32>.
2843 // trlo = Thrift Reflection LOcal.
2844 string prog;
2845 string name;
2847 // TODO(dreiss): Would it be better to pregenerate the base types
2848 // and put them in Thrift.{h,cpp} ?
2850 if (ttype->is_base_type()) {
2851 //name = ttype->get_name();
2852 prog = program_->get_name();
2853 name = ttype->get_ascii_fingerprint();
2854 } else if (ttype->is_enum()) {
2855 //name = "enum";
2856 prog = program_->get_name();
2857 name = ttype->get_ascii_fingerprint();
2858 } else if (ttype->is_container()) {
2859 prog = program_->get_name();
2860 name = ttype->get_ascii_fingerprint();
2861 } else {
2862 assert(ttype->is_struct() || ttype->is_xception());
2863 assert(ttype->get_program() != NULL);
2864 prog = ttype->get_program()->get_name();
2865 name = ttype->get_ascii_fingerprint();
2868 return string() + "trlo_" + prefix + "_" + prog + "_" + name;