diff options
author | Nate Rosenblum <nater@maginatics.com> | 2014-11-17 09:46:48 -0800 |
---|---|---|
committer | Roger Meier <roger@apache.org> | 2014-12-13 21:22:47 +0100 |
commit | 3c5a788d8f243e23474b3ac09a795e4e15a8933f (patch) | |
tree | 0d84c0d641f8872cbfc230753f90ffa13c033e12 /compiler | |
parent | 714a9aa1c544508e430d1d74a39202fc784df947 (diff) | |
download | thrift-3c5a788d8f243e23474b3ac09a795e4e15a8933f.tar.gz |
THRIFT-2836 Add moveable_types option to C++ generator
Setting this option enables generation of MoveConstructible types,
allowing types to be bound via move in std::bind. This is especially
pleasant when using Thrift container types.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/cpp/src/generate/t_cpp_generator.cc | 106 |
1 files changed, 92 insertions, 14 deletions
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc index 05ac21662..3edd7c8a3 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.cc +++ b/compiler/cpp/src/generate/t_cpp_generator.cc @@ -78,6 +78,9 @@ public: gen_templates_only_ = (iter != parsed_options.end() && iter->second == "only"); + iter = parsed_options.find("moveable_types"); + gen_moveable_ = (iter != parsed_options.end()); + out_dir_base_ = "gen-cpp"; } @@ -121,7 +124,14 @@ public: t_struct* tstruct, bool setters = true); void generate_copy_constructor(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_move_constructor(std::ofstream& out, t_struct* tstruct, bool is_exception); + void generate_constructor_helper(std::ofstream& out, + t_struct* tstruct, + bool is_excpetion, + bool is_move); void generate_assignment_operator(std::ofstream& out, t_struct* tstruct); + void generate_move_assignment_operator(std::ofstream& out, t_struct* tstruct); + void generate_assignment_helper(std::ofstream& out, t_struct* tstruct, bool is_move); void generate_struct_fingerprint(std::ofstream& out, t_struct* tstruct, bool is_definition); void generate_struct_reader(std::ofstream& out, t_struct* tstruct, bool pointers = false); void generate_struct_writer(std::ofstream& out, t_struct* tstruct, bool pointers = false); @@ -275,6 +285,11 @@ private: bool gen_templates_only_; /** + * True if we should generate move constructors & assignment operators. + */ + bool gen_moveable_; + + /** * True iff we should use a path prefix in our #include statements for other * thrift-generated header files. */ @@ -744,17 +759,53 @@ void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) generate_struct_writer(out, tstruct); generate_struct_swap(f_types_impl_, tstruct); generate_copy_constructor(f_types_impl_, tstruct, is_exception); + if (gen_moveable_) { + generate_move_constructor(f_types_impl_, tstruct, is_exception); + } generate_assignment_operator(f_types_impl_, tstruct); + if (gen_moveable_) { + generate_move_assignment_operator(f_types_impl_, tstruct); + } generate_struct_ostream_operator(f_types_impl_, tstruct); } void t_cpp_generator::generate_copy_constructor(ofstream& out, t_struct* tstruct, bool is_exception) { + generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/false); +} + +void t_cpp_generator::generate_move_constructor(ofstream& out, + t_struct* tstruct, + bool is_exception) { + generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/true); +} + +namespace { +// Helper to convert a variable to rvalue, if move is enabled +std::string maybeMove(std::string const& other, bool move) { + if (move) { + return "std::move(" + other + ")"; + } + return other; +} +} + +void t_cpp_generator::generate_constructor_helper(ofstream& out, + t_struct* tstruct, + bool is_exception, + bool is_move) { + std::string tmp_name = tmp("other"); - indent(out) << tstruct->get_name() << "::" << tstruct->get_name() << "(const " - << tstruct->get_name() << "& " << tmp_name << ") "; + indent(out) << tstruct->get_name() << "::" << tstruct->get_name(); + + if (is_move) { + out << "( " << tstruct->get_name() << "&& "; + } else { + out << "(const " << tstruct->get_name() << "& "; + } + out << tmp_name << ") "; if (is_exception) out << ": TException() "; out << "{" << endl; @@ -771,23 +822,38 @@ void t_cpp_generator::generate_copy_constructor(ofstream& out, for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { if ((*f_iter)->get_req() != t_field::T_REQUIRED) has_nonrequired_fields = true; - indent(out) << (*f_iter)->get_name() << " = " << tmp_name << "." << (*f_iter)->get_name() << ";" - << endl; + indent(out) << (*f_iter)->get_name() << " = " + << maybeMove(tmp_name + "." + (*f_iter)->get_name(), is_move) << ";" << endl; } - if (has_nonrequired_fields) - indent(out) << "__isset = " << tmp_name << ".__isset;" << endl; + if (has_nonrequired_fields) { + indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", is_move) << ";" << endl; + } indent_down(); indent(out) << "}" << endl; } void t_cpp_generator::generate_assignment_operator(ofstream& out, t_struct* tstruct) { + generate_assignment_helper(out, tstruct, /*is_move=*/false); +} + +void t_cpp_generator::generate_move_assignment_operator(ofstream& out, t_struct* tstruct) { + generate_assignment_helper(out, tstruct, /*is_move=*/true); +} + +void t_cpp_generator::generate_assignment_helper(ofstream& out, t_struct* tstruct, bool is_move) { std::string tmp_name = tmp("other"); - indent(out) << tstruct->get_name() << "& " << tstruct->get_name() << "::" - "operator=(const " - << tstruct->get_name() << "& " << tmp_name << ") {" << endl; + indent(out) << tstruct->get_name() << "& " << tstruct->get_name() << "::operator=("; + + if (is_move) { + out << tstruct->get_name() << "&& "; + } else { + out << "const " << tstruct->get_name() << "& "; + } + out << tmp_name << ") {" << endl; + indent_up(); const vector<t_field*>& members = tstruct->get_members(); @@ -801,11 +867,12 @@ void t_cpp_generator::generate_assignment_operator(ofstream& out, t_struct* tstr for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) { if ((*f_iter)->get_req() != t_field::T_REQUIRED) has_nonrequired_fields = true; - indent(out) << (*f_iter)->get_name() << " = " << tmp_name << "." << (*f_iter)->get_name() << ";" - << endl; + indent(out) << (*f_iter)->get_name() << " = " + << maybeMove(tmp_name + "." + (*f_iter)->get_name(), is_move) << ";" << endl; + } + if (has_nonrequired_fields) { + indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", is_move) << ";" << endl; } - if (has_nonrequired_fields) - indent(out) << "__isset = " << tmp_name << ".__isset;" << endl; indent(out) << "return *this;" << endl; indent_down(); @@ -890,10 +957,20 @@ void t_cpp_generator::generate_struct_declaration(ofstream& out, // Copy constructor indent(out) << tstruct->get_name() << "(const " << tstruct->get_name() << "&);" << endl; + // Move constructor + if (gen_moveable_) { + indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&);" << endl; + } + // Assignment Operator indent(out) << tstruct->get_name() << "& operator=(const " << tstruct->get_name() << "&);" << endl; + // Move assignment operator + if (gen_moveable_) { + indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&);" << endl; + } + // Default constructor indent(out) << tstruct->get_name() << "()"; @@ -4288,4 +4365,5 @@ THRIFT_REGISTER_GENERATOR( " templates: Generate templatized reader/writer methods.\n" " pure_enums: Generate pure enums instead of wrapper classes.\n" " dense: Generate type specifications for the dense protocol.\n" - " include_prefix: Use full include paths in generated files.\n") + " include_prefix: Use full include paths in generated files.\n" + " moveable_types: Generate move constructors and assignment operators.\n") |