diff options
author | Randy Abernethy <ra@apache.org> | 2015-08-01 22:57:02 -0700 |
---|---|---|
committer | Randy Abernethy <ra@apache.org> | 2015-08-01 22:57:02 -0700 |
commit | 8dbe5f60a7c1401302e10aec41069f9c385d34a1 (patch) | |
tree | 86898a14c76a1d246b08480195918ef74e213769 | |
parent | 54f392b8fd90d53deabbf107565ec92c985d47f5 (diff) | |
download | thrift-8dbe5f60a7c1401302e10aec41069f9c385d34a1.tar.gz |
THRIFT-2199:Remove dense protocol
Client: C++ library and compiler
Patch: Randy Abernethy
25 files changed, 17 insertions, 2038 deletions
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc index f591107d9..e351f8a46 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.cc +++ b/compiler/cpp/src/generate/t_cpp_generator.cc @@ -58,9 +58,6 @@ public: iter = parsed_options.find("pure_enums"); gen_pure_enums_ = (iter != parsed_options.end()); - iter = parsed_options.find("dense"); - gen_dense_ = (iter != parsed_options.end()); - iter = parsed_options.find("include_prefix"); use_include_prefix_ = (iter != parsed_options.end()); @@ -132,7 +129,6 @@ public: 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); void generate_struct_result_writer(std::ofstream& out, t_struct* tstruct, bool pointers = false); @@ -231,7 +227,6 @@ public: bool name_params = true); std::string argument_list(t_struct* tstruct, bool name_params = true, bool start_comma = false); std::string type_to_enum(t_type* ttype); - std::string local_reflection_name(const char*, t_type* ttype, bool external = false); void generate_enum_constant_list(std::ofstream& f, const vector<t_enum_value*>& constants, @@ -244,10 +239,6 @@ public: t_struct* tstruct, bool external = false); - // These handles checking gen_dense_ and checking for duplicates. - void generate_local_reflection(std::ofstream& out, t_type* ttype, bool is_definition); - void generate_local_reflection_pointer(std::ofstream& out, t_type* ttype); - bool is_reference(t_field* tfield) { return tfield->get_reference(); } bool is_complex_type(t_type* ttype) { @@ -273,11 +264,6 @@ private: bool gen_pure_enums_; /** - * True if we should generate local reflection metadata for TDenseProtocol. - */ - bool gen_dense_; - - /** * True if we should generate templatized reader/writer methods. */ bool gen_templates_; @@ -333,11 +319,6 @@ private: std::ofstream f_service_; std::ofstream f_service_tcc_; - /** - * When generating local reflections, make sure we don't generate duplicates. - */ - std::set<std::string> reflected_fingerprints_; - // The ProcessorGenerator is used to generate parts of the code, // so it needs access to many of our protected members and methods. // @@ -418,12 +399,6 @@ void t_cpp_generator::init_generator() { f_types_tcc_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\"" << endl << endl; - // If we are generating local reflection metadata, we need to include - // the definition of TypeSpec. - if (gen_dense_) { - f_types_impl_ << "#include <thrift/TReflectionLocal.h>" << endl << endl; - } - // The swap() code needs <algorithm> for std::swap() f_types_impl_ << "#include <algorithm>" << endl; // for operator<< @@ -553,9 +528,6 @@ void t_cpp_generator::generate_enum(t_enum* tenum) { << tenum->get_name() << "Values" << ", _k" << tenum->get_name() << "Names), " << "::apache::thrift::TEnumIterator(-1, NULL, NULL));" << endl << endl; - - generate_local_reflection(f_types_, tenum, false); - generate_local_reflection(f_types_impl_, tenum, true); } /** @@ -753,10 +725,6 @@ void t_cpp_generator::generate_forward_declaration(t_struct* tstruct) { void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) { generate_struct_declaration(f_types_, tstruct, is_exception, false, true, true, true); generate_struct_definition(f_types_impl_, f_types_impl_, tstruct); - generate_struct_fingerprint(f_types_impl_, tstruct, true); - generate_local_reflection(f_types_, tstruct, false); - generate_local_reflection(f_types_impl_, tstruct, true); - generate_local_reflection_pointer(f_types_impl_, tstruct); std::ofstream& out = (gen_templates_ ? f_types_tcc_ : f_types_impl_); generate_struct_reader(out, tstruct); @@ -957,9 +925,6 @@ void t_cpp_generator::generate_struct_declaration(ofstream& out, << " public:" << endl << endl; indent_up(); - // Put the fingerprint up top for all to see. - generate_struct_fingerprint(out, tstruct, false); - if (!pointers) { // Copy constructor indent(out) << tstruct->get_name() << "(const " << tstruct->get_name() << "&);" << endl; @@ -1025,12 +990,6 @@ void t_cpp_generator::generate_struct_declaration(ofstream& out, out << endl << indent() << "virtual ~" << tstruct->get_name() << "() throw();" << endl; } - // Pointer to this structure's reflection local typespec. - if (gen_dense_) { - indent(out) << "static ::apache::thrift::reflection::local::TypeSpec* local_reflection;" << endl - << endl; - } - // Declare all fields for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << declare_field(*m_iter, @@ -1187,165 +1146,6 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, } out << endl; } -/** - * Writes the fingerprint of a struct to either the header or implementation. - * - * @param out Output stream - * @param tstruct The struct - */ -void t_cpp_generator::generate_struct_fingerprint(ofstream& out, - t_struct* tstruct, - bool is_definition) { - string stat, nspace, comment; - if (is_definition) { - stat = ""; - nspace = tstruct->get_name() + "::"; - comment = " "; - } else { - stat = "static "; - nspace = ""; - comment = "; // "; - } - - if (!tstruct->has_fingerprint()) { - tstruct->generate_fingerprint(); // lazy fingerprint generation - } - if (tstruct->has_fingerprint()) { - out << indent() << stat << "const char* " << nspace << "ascii_fingerprint" << comment << "= \"" - << tstruct->get_ascii_fingerprint() << "\";" << endl << indent() << stat << "const uint8_t " - << nspace << "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {"; - const char* comma = ""; - for (int i = 0; i < t_type::fingerprint_len; i++) { - out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]); - comma = ","; - } - out << "};" << endl << endl; - } -} - -/** - * Writes the local reflection of a type (either declaration or definition). - */ -void t_cpp_generator::generate_local_reflection(std::ofstream& out, - t_type* ttype, - bool is_definition) { - if (!gen_dense_) { - return; - } - ttype = get_true_type(ttype); - string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl"); - assert(ttype->has_fingerprint()); // test AFTER get due to lazy fingerprint generation - - // Note that we have generated this fingerprint. If we already did, bail out. - if (!reflected_fingerprints_.insert(key).second) { - return; - } - // Let each program handle its own structures. - if (ttype->get_program() != NULL && ttype->get_program() != program_) { - return; - } - - // Do dependencies. - if (ttype->is_list()) { - generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition); - } else if (ttype->is_set()) { - generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition); - } else if (ttype->is_map()) { - generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition); - generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition); - } else if (ttype->is_struct() || ttype->is_xception()) { - // Hacky hacky. For efficiency and convenience, we need a dummy "T_STOP" - // type at the end of our typespec array. Unfortunately, there is no - // T_STOP type, so we use the global void type, and special case it when - // generating its typespec. - - const vector<t_field*>& members = ((t_struct*)ttype)->get_sorted_members(); - vector<t_field*>::const_iterator m_iter; - for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { - generate_local_reflection(out, (**m_iter).get_type(), is_definition); - } - generate_local_reflection(out, g_type_void, is_definition); - - // For definitions of structures, do the arrays of metas and field specs also. - if (is_definition) { - out << indent() << "::apache::thrift::reflection::local::FieldMeta" << endl << indent() - << local_reflection_name("metas", ttype) << "[] = {" << endl; - indent_up(); - for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { - indent(out) << "{ " << (*m_iter)->get_key() << ", " - << (((*m_iter)->get_req() == t_field::T_OPTIONAL) ? "true" : "false") << " }," - << endl; - } - // Zero for the T_STOP marker. - indent(out) << "{ 0, false }" << endl << "};" << endl; - indent_down(); - - out << indent() << "::apache::thrift::reflection::local::TypeSpec*" << endl << indent() - << local_reflection_name("specs", ttype) << "[] = {" << endl; - indent_up(); - for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { - indent(out) << "&" << local_reflection_name("typespec", (*m_iter)->get_type(), true) << "," - << endl; - } - indent(out) << "&" << local_reflection_name("typespec", g_type_void) << "," << endl; - indent_down(); - indent(out) << "};" << endl; - } - } - - out << indent() << "// " << ttype->get_fingerprint_material() << endl << indent() - << (is_definition ? "" : "extern ") << "::apache::thrift::reflection::local::TypeSpec" << endl - << local_reflection_name("typespec", ttype) << (is_definition ? "(" : ";") << endl; - - if (!is_definition) { - out << endl; - return; - } - - indent_up(); - - if (ttype->is_void()) { - indent(out) << "::apache::thrift::protocol::T_STOP"; - } else { - indent(out) << type_to_enum(ttype); - } - - if (ttype->is_struct()) { - out << "," << endl << indent() << type_name(ttype) << "::binary_fingerprint," << endl - << indent() << local_reflection_name("metas", ttype) << "," << endl << indent() - << local_reflection_name("specs", ttype); - } else if (ttype->is_list()) { - out << "," << endl << indent() << "&" - << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type(), true) << "," << endl - << indent() << "NULL"; - } else if (ttype->is_set()) { - out << "," << endl << indent() << "&" - << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type(), true) << "," << endl - << indent() << "NULL"; - } else if (ttype->is_map()) { - out << "," << endl << indent() << "&" - << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type(), true) << "," << endl - << indent() << "&" - << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type(), true); - } - - out << ");" << endl << endl; - - indent_down(); -} - -/** - * Writes the structure's static pointer to its local reflection typespec - * into the implementation file. - */ -void t_cpp_generator::generate_local_reflection_pointer(std::ofstream& out, t_type* ttype) { - if (!gen_dense_) { - return; - } - indent(out) << "::apache::thrift::reflection::local::TypeSpec* " << ttype->get_name() - << "::local_reflection = " << endl << indent() << " &" - << local_reflection_name("typespec", ttype) << ";" << endl << endl; -} /** * Makes a helper function to gen a struct reader. @@ -4519,47 +4319,6 @@ string t_cpp_generator::type_to_enum(t_type* type) { throw "INVALID TYPE IN type_to_enum: " + type->get_name(); } -/** - * Returns the symbol name of the local reflection of a type. - */ -string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype, bool external) { - ttype = get_true_type(ttype); - - // We have to use the program name as part of the identifier because - // if two thrift "programs" are compiled into one actual program - // you would get a symbol collision if they both defined list<i32>. - // trlo = Thrift Reflection LOcal. - string prog; - string name; - string nspace; - - // TODO(dreiss): Would it be better to pregenerate the base types - // and put them in Thrift.{h,cpp} ? - - if (ttype->is_base_type()) { - prog = program_->get_name(); - name = ttype->get_ascii_fingerprint(); - } else if (ttype->is_enum()) { - assert(ttype->get_program() != NULL); - prog = ttype->get_program()->get_name(); - name = ttype->get_ascii_fingerprint(); - } else if (ttype->is_container()) { - prog = program_->get_name(); - name = ttype->get_ascii_fingerprint(); - } else { - assert(ttype->is_struct() || ttype->is_xception()); - assert(ttype->get_program() != NULL); - prog = ttype->get_program()->get_name(); - name = ttype->get_ascii_fingerprint(); - } - - if (external && ttype->get_program() != NULL && ttype->get_program() != program_) { - nspace = namespace_prefix(ttype->get_program()->get_namespace("cpp")); - } - - return nspace + "trlo_" + prefix + "_" + prog + "_" + name; -} - string t_cpp_generator::get_include_prefix(const t_program& program) const { string include_prefix = program.get_include_prefix(); if (!use_include_prefix_ || (include_prefix.size() > 0 && include_prefix[0] == '/')) { @@ -4586,6 +4345,5 @@ THRIFT_REGISTER_GENERATOR( " Omits generation of default operators ==, != and <\n" " 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" " moveable_types: Generate move constructors and assignment operators.\n") diff --git a/compiler/cpp/src/generate/t_json_generator.cc b/compiler/cpp/src/generate/t_json_generator.cc index 154a64d87..3f44a8206 100644 --- a/compiler/cpp/src/generate/t_json_generator.cc +++ b/compiler/cpp/src/generate/t_json_generator.cc @@ -701,10 +701,8 @@ string t_json_generator::get_type_name(t_type* ttype) { if (ttype->is_xception()) { return "exception"; } - if (ttype->is_base_type() && ((t_base_type*)ttype)->is_binary()) { - return "binary"; - } - return ttype->get_fingerprint_material(); + //if (ttype->is_base_type() && ((t_base_type*)ttype)->is_binary()) { + return "binary"; } string t_json_generator::get_qualified_name(t_type* ttype) { diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc index a337cc693..e11d9b04c 100644 --- a/compiler/cpp/src/main.cc +++ b/compiler/cpp/src/main.cc @@ -631,43 +631,6 @@ void dump_docstrings(t_program* program) { } /** - * Call generate_fingerprint for every structure and enum. - */ -void generate_all_fingerprints(t_program* program) { - const vector<t_struct*>& structs = program->get_structs(); - vector<t_struct*>::const_iterator s_iter; - for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) { - t_struct* st = *s_iter; - st->generate_fingerprint(); - } - - const vector<t_struct*>& xceptions = program->get_xceptions(); - vector<t_struct*>::const_iterator x_iter; - for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { - t_struct* st = *x_iter; - st->generate_fingerprint(); - } - - const vector<t_enum*>& enums = program->get_enums(); - vector<t_enum*>::const_iterator e_iter; - for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) { - t_enum* e = *e_iter; - e->generate_fingerprint(); - } - - g_type_void->generate_fingerprint(); - - // If you want to generate fingerprints for implicit structures, start here. - /* - const vector<t_service*>& services = program->get_services(); - vector<t_service*>::const_iterator v_iter; - for (v_iter = services.begin(); v_iter != services.end(); ++v_iter) { - t_service* sv = *v_iter; - } - */ -} - -/** * Emits a warning on list<byte>, binary type is typically a much better choice. */ void check_for_list_of_bytes(t_type* list_elem_type) { diff --git a/compiler/cpp/src/parse/parse.cc b/compiler/cpp/src/parse/parse.cc index 7f94bab0a..b22ee5281 100644 --- a/compiler/cpp/src/parse/parse.cc +++ b/compiler/cpp/src/parse/parse.cc @@ -20,20 +20,8 @@ #include "t_type.h" #include "t_typedef.h" -#include "md5.h" #include "main.h" -void t_type::generate_fingerprint() { - if (!has_fingerprint()) { - pdebug("generating fingerprint for %s", get_name().c_str()); - std::string material = get_fingerprint_material(); - md5_state_t ctx; - md5_init(&ctx); - md5_append(&ctx, (md5_byte_t*)(material.data()), (int)material.size()); - md5_finish(&ctx, (md5_byte_t*)fingerprint_); - } -} - t_type* t_type::get_true_type() { t_type* type = this; while (type->is_typedef()) { diff --git a/compiler/cpp/src/parse/t_base_type.h b/compiler/cpp/src/parse/t_base_type.h index 34ff9616c..9be1f803b 100644 --- a/compiler/cpp/src/parse/t_base_type.h +++ b/compiler/cpp/src/parse/t_base_type.h @@ -73,14 +73,6 @@ public: bool is_base_type() const { return true; } - virtual std::string get_fingerprint_material() const { - std::string rv = t_base_name(base_); - if (rv == "(unknown)") { - throw "BUG: Can't get fingerprint material for this base type."; - } - return rv; - } - static std::string t_base_name(t_base tbase) { switch (tbase) { case TYPE_VOID: diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h index c4e30e37d..eece7bb14 100644 --- a/compiler/cpp/src/parse/t_field.h +++ b/compiler/cpp/src/parse/t_field.h @@ -86,15 +86,6 @@ public: t_struct* get_xsd_attrs() { return xsd_attrs_; } - // This is not the same function as t_type::get_fingerprint_material, - // but it does the same thing. - std::string get_fingerprint_material() const { - std::ostringstream keystm; - keystm << key_; - return keystm.str() + ":" + ((req_ == T_OPTIONAL) ? "opt-" : "") - + type_->get_fingerprint_material(); - } - /** * Comparator to sort fields in ascending order by key. * Make this a functor instead of a function to help GCC inline it. diff --git a/compiler/cpp/src/parse/t_list.h b/compiler/cpp/src/parse/t_list.h index e121d1d51..ac0d98152 100644 --- a/compiler/cpp/src/parse/t_list.h +++ b/compiler/cpp/src/parse/t_list.h @@ -34,15 +34,6 @@ public: bool is_list() const { return true; } - virtual std::string get_fingerprint_material() const { - return "list<" + elem_type_->get_fingerprint_material() + ">"; - } - - virtual void generate_fingerprint() { - t_type::generate_fingerprint(); - elem_type_->generate_fingerprint(); - } - private: t_type* elem_type_; }; diff --git a/compiler/cpp/src/parse/t_map.h b/compiler/cpp/src/parse/t_map.h index 479514756..269aeab58 100644 --- a/compiler/cpp/src/parse/t_map.h +++ b/compiler/cpp/src/parse/t_map.h @@ -37,17 +37,6 @@ public: bool is_map() const { return true; } - virtual std::string get_fingerprint_material() const { - return "map<" + key_type_->get_fingerprint_material() + "," - + val_type_->get_fingerprint_material() + ">"; - } - - virtual void generate_fingerprint() { - t_type::generate_fingerprint(); - key_type_->generate_fingerprint(); - val_type_->generate_fingerprint(); - } - private: t_type* key_type_; t_type* val_type_; diff --git a/compiler/cpp/src/parse/t_service.h b/compiler/cpp/src/parse/t_service.h index 1f499724f..2b01f9c45 100644 --- a/compiler/cpp/src/parse/t_service.h +++ b/compiler/cpp/src/parse/t_service.h @@ -51,11 +51,6 @@ public: t_service* get_extends() { return extends_; } - virtual std::string get_fingerprint_material() const { - // Services should never be used in fingerprints. - throw "BUG: Can't get fingerprint material for service."; - } - private: std::vector<t_function*> functions_; t_service* extends_; diff --git a/compiler/cpp/src/parse/t_set.h b/compiler/cpp/src/parse/t_set.h index ccfc7013a..8a4648050 100644 --- a/compiler/cpp/src/parse/t_set.h +++ b/compiler/cpp/src/parse/t_set.h @@ -34,15 +34,6 @@ public: bool is_set() const { return true; } - virtual std::string get_fingerprint_material() const { - return "set<" + elem_type_->get_fingerprint_material() + ">"; - } - - virtual void generate_fingerprint() { - t_type::generate_fingerprint(); - elem_type_->generate_fingerprint(); - } - private: t_type* elem_type_; }; diff --git a/compiler/cpp/src/parse/t_struct.h b/compiler/cpp/src/parse/t_struct.h index 228267673..93cb08966 100644 --- a/compiler/cpp/src/parse/t_struct.h +++ b/compiler/cpp/src/parse/t_struct.h @@ -133,33 +133,6 @@ public: bool is_union() const { return is_union_; } - virtual std::string get_fingerprint_material() const { - std::string rv = "{"; - bool do_reserve = (members_in_id_order_.size() > 1); - size_t estimation = 0; - members_type::const_iterator m_iter; - for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { - rv += (*m_iter)->get_fingerprint_material(); - rv += ";"; - - if (do_reserve) { - estimation = members_in_id_order_.size() * rv.size() + 16; - rv.reserve(estimation); - do_reserve = false; - } - } - rv += "}"; - return rv; - } - - virtual void generate_fingerprint() { - t_type::generate_fingerprint(); - members_type::const_iterator m_iter; - for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { - (*m_iter)->get_type()->generate_fingerprint(); - } - } - t_field* get_field_by_name(std::string field_name) { members_type::const_iterator m_iter; for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h index 20409f391..416cc6fa3 100644 --- a/compiler/cpp/src/parse/t_type.h +++ b/compiler/cpp/src/parse/t_type.h @@ -64,45 +64,6 @@ public: t_type* get_true_type(); - // Return a string that uniquely identifies this type - // from any other thrift type in the world, as far as - // TDenseProtocol is concerned. - // We don't cache this, which is a little sloppy, - // but the compiler is so fast that it doesn't really matter. - virtual std::string get_fingerprint_material() const = 0; - - // Fingerprint should change whenever (and only when) - // the encoding via TDenseProtocol changes. - static const int fingerprint_len = 16; - - // Call this before trying get_*_fingerprint(). - virtual void generate_fingerprint(); - - bool has_fingerprint() const { - for (int i = 0; i < fingerprint_len; i++) { - if (fingerprint_[i] != 0) { - return true; - } - } - return false; - } - - const uint8_t* get_binary_fingerprint() { - if (!has_fingerprint()) // lazy fingerprint generation, right now only used with the c++ - // generator - generate_fingerprint(); - return fingerprint_; - } - - std::string get_ascii_fingerprint() { - std::string rv; - const uint8_t* fp = get_binary_fingerprint(); - for (int i = 0; i < fingerprint_len; i++) { - rv += byte_to_hex(fp[i]); - } - return rv; - } - // This function will break (maybe badly) unless 0 <= num <= 16. static char nybble_to_xdigit(int num) { if (num < 10) { @@ -122,22 +83,16 @@ public: std::map<std::string, std::string> annotations_; protected: - t_type() : program_(NULL) { memset(fingerprint_, 0, sizeof(fingerprint_)); } + t_type() : program_(NULL) { ; } - t_type(t_program* program) : program_(program) { memset(fingerprint_, 0, sizeof(fingerprint_)); } + t_type(t_program* program) : program_(program) { ; } - t_type(t_program* program, std::string name) : program_(program), name_(name) { - memset(fingerprint_, 0, sizeof(fingerprint_)); - } + t_type(t_program* program, std::string name) : program_(program), name_(name) { ; } - t_type(std::string name) : program_(NULL), name_(name) { - memset(fingerprint_, 0, sizeof(fingerprint_)); - } + t_type(std::string name) : program_(NULL), name_(name) { ; } t_program* program_; std::string name_; - - uint8_t fingerprint_[fingerprint_len]; }; /** diff --git a/compiler/cpp/src/parse/t_typedef.h b/compiler/cpp/src/parse/t_typedef.h index 105190929..a39a246d2 100644 --- a/compiler/cpp/src/parse/t_typedef.h +++ b/compiler/cpp/src/parse/t_typedef.h @@ -57,23 +57,6 @@ public: bool is_typedef() const { return true; } - virtual std::string get_fingerprint_material() const { - if (!seen_) { - seen_ = true; - std::string ret = get_type()->get_fingerprint_material(); - seen_ = false; - return ret; - } - return ""; - } - - virtual void generate_fingerprint() { - t_type::generate_fingerprint(); - if (!get_type()->has_fingerprint()) { - get_type()->generate_fingerprint(); - } - } - private: t_type* type_; std::string symbolic_; diff --git a/lib/cpp/CMakeLists.txt b/lib/cpp/CMakeLists.txt index d6107bc34..4c7caebad 100755 --- a/lib/cpp/CMakeLists.txt +++ b/lib/cpp/CMakeLists.txt @@ -43,7 +43,6 @@ set( thriftcpp_SOURCES src/thrift/processor/PeekProcessor.cpp src/thrift/protocol/TBase64Utils.cpp src/thrift/protocol/TDebugProtocol.cpp - src/thrift/protocol/TDenseProtocol.cpp src/thrift/protocol/TJSONProtocol.cpp src/thrift/protocol/TMultiplexedProtocol.cpp src/thrift/protocol/TProtocol.cpp diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am index 7f2d4315a..4e5cde7f4 100755 --- a/lib/cpp/Makefile.am +++ b/lib/cpp/Makefile.am @@ -72,7 +72,6 @@ libthrift_la_SOURCES = src/thrift/TApplicationException.cpp \ src/thrift/concurrency/Util.cpp \ src/thrift/processor/PeekProcessor.cpp \ src/thrift/protocol/TDebugProtocol.cpp \ - src/thrift/protocol/TDenseProtocol.cpp \ src/thrift/protocol/TJSONProtocol.cpp \ src/thrift/protocol/TBase64Utils.cpp \ src/thrift/protocol/TMultiplexedProtocol.cpp \ @@ -153,7 +152,6 @@ include_thrift_HEADERS = \ src/thrift/TDispatchProcessor.h \ src/thrift/Thrift.h \ src/thrift/TOutput.h \ - src/thrift/TReflectionLocal.h \ src/thrift/TProcessor.h \ src/thrift/TApplicationException.h \ src/thrift/TLogging.h \ @@ -184,7 +182,6 @@ include_protocol_HEADERS = \ src/thrift/protocol/TBinaryProtocol.tcc \ src/thrift/protocol/TCompactProtocol.h \ src/thrift/protocol/TCompactProtocol.tcc \ - src/thrift/protocol/TDenseProtocol.h \ src/thrift/protocol/TDebugProtocol.h \ src/thrift/protocol/TBase64Utils.h \ src/thrift/protocol/TJSONProtocol.h \ diff --git a/lib/cpp/libthrift.vcxproj b/lib/cpp/libthrift.vcxproj index 1fc08b883..b4f1c501c 100644 --- a/lib/cpp/libthrift.vcxproj +++ b/lib/cpp/libthrift.vcxproj @@ -46,7 +46,6 @@ <ClCompile Include="src\thrift\processor\PeekProcessor.cpp"/> <ClCompile Include="src\thrift\protocol\TBase64Utils.cpp" /> <ClCompile Include="src\thrift\protocol\TDebugProtocol.cpp"/> - <ClCompile Include="src\thrift\protocol\TDenseProtocol.cpp"/> <ClCompile Include="src\thrift\protocol\TJSONProtocol.cpp"/> <ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp"/> <ClCompile Include="src\thrift\server\TSimpleServer.cpp"/> @@ -84,7 +83,6 @@ <ClInclude Include="src\thrift\processor\TMultiplexedProcessor.h" /> <ClInclude Include="src\thrift\protocol\TBinaryProtocol.h" /> <ClInclude Include="src\thrift\protocol\TDebugProtocol.h" /> - <ClInclude Include="src\thrift\protocol\TDenseProtocol.h" /> <ClInclude Include="src\thrift\protocol\TJSONProtocol.h" /> <ClInclude Include="src\thrift\protocol\TMultiplexedProtocol.h" /> <ClInclude Include="src\thrift\protocol\TProtocol.h" /> diff --git a/lib/cpp/libthrift.vcxproj.filters b/lib/cpp/libthrift.vcxproj.filters index 4effa8729..ec21886f6 100644 --- a/lib/cpp/libthrift.vcxproj.filters +++ b/lib/cpp/libthrift.vcxproj.filters @@ -27,9 +27,6 @@ <ClCompile Include="src\thrift\protocol\TDebugProtocol.cpp"> <Filter>protocol</Filter> </ClCompile> - <ClCompile Include="src\thrift\protocol\TDenseProtocol.cpp"> - <Filter>protocol</Filter> - </ClCompile> <ClCompile Include="src\thrift\protocol\TBase64Utils.cpp"> <Filter>protocol</Filter> </ClCompile> @@ -206,9 +203,6 @@ <ClInclude Include="src\thrift\protocol\TMultiplexedProtocol.h"> <Filter>protocol</Filter> </ClInclude> - <ClInclude Include="src\thrift\protocol\TDenseProtocol.h"> - <Filter>protocol</Filter> - </ClInclude> <ClInclude Include="src\thrift\protocol\TDebugProtocol.h"> <Filter>protocol</Filter> </ClInclude> @@ -280,4 +274,4 @@ <Filter>windows\tr1</Filter> </None> </ItemGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/lib/cpp/src/thrift/TReflectionLocal.h b/lib/cpp/src/thrift/TReflectionLocal.h deleted file mode 100644 index 2fc53c882..000000000 --- a/lib/cpp/src/thrift/TReflectionLocal.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef _THRIFT_TREFLECTIONLOCAL_H_ -#define _THRIFT_TREFLECTIONLOCAL_H_ 1 - -#include <stdint.h> -#include <cstring> -#include <thrift/protocol/TProtocol.h> - -/** - * Local Reflection is a blanket term referring to the the structure - * and generation of this particular representation of Thrift types. - * (It is called local because it cannot be serialized by Thrift). - * - */ - -namespace apache { -namespace thrift { -namespace reflection { -namespace local { - -using apache::thrift::protocol::TType; - -// We include this many bytes of the structure's fingerprint when serializing -// a top-level structure. Long enough to make collisions unlikely, short -// enough to not significantly affect the amount of memory used. -const int FP_PREFIX_LEN = 4; - -struct FieldMeta { - int16_t tag; - bool is_optional; -}; - -struct TypeSpec { - TType ttype; - uint8_t fp_prefix[FP_PREFIX_LEN]; - - // Use an anonymous union here so we can fit two TypeSpecs in one cache line. - union { - struct { - // Use parallel arrays here for denser packing (of the arrays). - FieldMeta* metas; - TypeSpec** specs; - } tstruct; - struct { - TypeSpec* subtype1; - TypeSpec* subtype2; - } tcontainer; - }; - - // Static initialization of unions isn't really possible, - // so take the plunge and use constructors. - // Hopefully they'll be evaluated at compile time. - - TypeSpec(TType ttype) : ttype(ttype) { std::memset(fp_prefix, 0, FP_PREFIX_LEN); } - - TypeSpec(TType ttype, const uint8_t* fingerprint, FieldMeta* metas, TypeSpec** specs) - : ttype(ttype) { - std::memcpy(fp_prefix, fingerprint, FP_PREFIX_LEN); - tstruct.metas = metas; - tstruct.specs = specs; - } - - TypeSpec(TType ttype, TypeSpec* subtype1, TypeSpec* subtype2) : ttype(ttype) { - std::memset(fp_prefix, 0, FP_PREFIX_LEN); - tcontainer.subtype1 = subtype1; - tcontainer.subtype2 = subtype2; - } -}; -} -} -} -} // apache::thrift::reflection::local - -#endif // #ifndef _THRIFT_TREFLECTIONLOCAL_H_ diff --git a/lib/cpp/src/thrift/Thrift.h b/lib/cpp/src/thrift/Thrift.h index 962b921ac..e8e70eba0 100644 --- a/lib/cpp/src/thrift/Thrift.h +++ b/lib/cpp/src/thrift/Thrift.h @@ -96,13 +96,6 @@ protected: std::string message_; }; -// Forward declare this structure used by TDenseProtocol -namespace reflection { -namespace local { -struct TypeSpec; -} -} - class TDelayedException { public: template <class E> diff --git a/lib/cpp/src/thrift/protocol/TBinaryProtocol.h b/lib/cpp/src/thrift/protocol/TBinaryProtocol.h index 7291988c5..e0650cf67 100644 --- a/lib/cpp/src/thrift/protocol/TBinaryProtocol.h +++ b/lib/cpp/src/thrift/protocol/TBinaryProtocol.h @@ -39,7 +39,7 @@ class TBinaryProtocolT : public TVirtualProtocol<TBinaryProtocolT<Transport_, By protected: static const int32_t VERSION_MASK = ((int32_t)0xffff0000); static const int32_t VERSION_1 = ((int32_t)0x80010000); - // VERSION_2 (0x80020000) is taken by TDenseProtocol. + // VERSION_2 (0x80020000) was taken by TDenseProtocol (which has since been removed) public: TBinaryProtocolT(boost::shared_ptr<Transport_> trans) diff --git a/lib/cpp/src/thrift/protocol/TDenseProtocol.cpp b/lib/cpp/src/thrift/protocol/TDenseProtocol.cpp deleted file mode 100644 index 259c68e8a..000000000 --- a/lib/cpp/src/thrift/protocol/TDenseProtocol.cpp +++ /dev/null @@ -1,753 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* - -IMPLEMENTATION DETAILS - -TDenseProtocol was designed to have a smaller serialized form than -TBinaryProtocol. This is accomplished using two techniques. The first is -variable-length integer encoding. We use the same technique that the Standard -MIDI File format uses for "variable-length quantities" -(http://en.wikipedia.org/wiki/Variable-length_quantity). -All integers (including i16, but not byte) are first cast to uint64_t, -then written out as variable-length quantities. This has the unfortunate side -effect that all negative numbers require 10 bytes, but negative numbers tend -to be far less common than positive ones. - -The second technique eliminating the field ids used by TBinaryProtocol. This -decision required support from the Thrift compiler and also sacrifices some of -the backward and forward compatibility of TBinaryProtocol. - -We considered implementing this technique by generating separate readers and -writers for the dense protocol (this is how Pillar, Thrift's predecessor, -worked), but this idea had a few problems: -- Our abstractions go out the window. -- We would have to maintain a second code generator. -- Preserving compatibility with old versions of the structures would be a - nightmare. - -Therefore, we chose an alternate implementation that stored the description of -the data neither in the data itself (like TBinaryProtocol) nor in the -serialization code (like Pillar), but instead in a separate data structure, -called a TypeSpec. TypeSpecs are generated by the Thrift compiler -(specifically in the t_cpp_generator), and their structure should be -documented there (TODO(dreiss): s/should be/is/). - -We maintain a stack of TypeSpecs within the protocol so it knows where the -generated code is in the reading/writing process. For example, if we are -writing an i32 contained in a struct bar, contained in a struct foo, then the -stack would look like: TOP , i32 , struct bar , struct foo , BOTTOM. -The following invariant: whenever we are about to read/write an object -(structBegin, containerBegin, or a scalar), the TypeSpec on the top of the -stack must match the type being read/written. The main reasons that this -invariant must be maintained is that if we ever start reading a structure, we -must have its exact TypeSpec in order to pass the right tags to the -deserializer. - -We use the following strategies for maintaining this invariant: - -- For structures, we have a separate stack of indexes, one for each structure - on the TypeSpec stack. These are indexes into the list of fields in the - structure's TypeSpec. When we {read,write}FieldBegin, we push on the - TypeSpec for the field. -- When we begin writing a list or set, we push on the TypeSpec for the - element type. -- For maps, we have a separate stack of booleans, one for each map on the - TypeSpec stack. The boolean is true if we are writing the key for that - map, and false if we are writing the value. Maps are the trickiest case - because the generated code does not call any protocol method between - the key and the value. As a result, we potentially have to switch - between map key state and map value state after reading/writing any object. -- This job is handled by the stateTransition method. It is called after - reading/writing every object. It pops the current TypeSpec off the stack, - then optionally pushes a new one on, depending on what the next TypeSpec is. - If it is a struct, the job is left to the next writeFieldBegin. If it is a - set or list, the just-popped typespec is pushed back on. If it is a map, - the top of the key/value stack is toggled, and the appropriate TypeSpec - is pushed. - -Optional fields are a little tricky also. We write a zero byte if they are -absent and prefix them with an 0x01 byte if they are present -*/ - -#include <stdint.h> -#include <thrift/protocol/TDenseProtocol.h> -#include <thrift/TReflectionLocal.h> - -// Leaving this on for now. Disabling it will turn off asserts, which should -// give a performance boost. When we have *really* thorough test cases, -// we should drop this. -#define DEBUG_TDENSEPROTOCOL - -// NOTE: Assertions should *only* be used to detect bugs in code, -// either in TDenseProtocol itself, or in code using it. -// (For example, using the wrong TypeSpec.) -// Invalid data should NEVER cause an assertion failure, -// no matter how grossly corrupted, nor how ingeniously crafted. -#ifdef DEBUG_TDENSEPROTOCOL -#undef NDEBUG -#else -#define NDEBUG -#endif -#include <cassert> - -using std::string; - -#ifdef __GNUC__ -#define UNLIKELY(val) (__builtin_expect((val), 0)) -#else -#define UNLIKELY(val) (val) -#endif - -namespace apache { -namespace thrift { -namespace protocol { - -const int TDenseProtocol::FP_PREFIX_LEN = apache::thrift::reflection::local::FP_PREFIX_LEN; - -// Top TypeSpec. TypeSpec of the structure being encoded. -#define TTS (ts_stack_.back()) // type = TypeSpec* -// InDeX. Index into TTS of the current/next field to encode. -#define IDX (idx_stack_.back()) // type = int -// Field TypeSpec. TypeSpec of the current/next field to encode. -#define FTS (TTS->tstruct.specs[IDX]) // type = TypeSpec* -// Field MeTa. Metadata of the current/next field to encode. -#define FMT (TTS->tstruct.metas[IDX]) // type = FieldMeta -// SubType 1/2. TypeSpec of the first/second subtype of this container. -#define ST1 (TTS->tcontainer.subtype1) -#define ST2 (TTS->tcontainer.subtype2) - -/** - * Checks that @c ttype is indeed the ttype that we should be writing, - * according to our typespec. Aborts if the test fails and debugging in on. - */ -inline void TDenseProtocol::checkTType(const TType ttype) { - assert(!ts_stack_.empty()); - assert(TTS->ttype == ttype); -} - -/** - * Makes sure that the TypeSpec stack is correct for the next object. - * See top-of-file comments. - */ -inline void TDenseProtocol::stateTransition() { - TypeSpec* old_tts = ts_stack_.back(); - ts_stack_.pop_back(); - - // If this is the end of the top-level write, we should have just popped - // the TypeSpec passed to the constructor. - if (ts_stack_.empty()) { - assert(old_tts == type_spec_); - return; - } - - switch (TTS->ttype) { - - case T_STRUCT: - assert(old_tts == FTS); - break; - - case T_LIST: - case T_SET: - assert(old_tts == ST1); - ts_stack_.push_back(old_tts); - break; - - case T_MAP: - assert(old_tts == (mkv_stack_.back() ? ST1 : ST2)); - mkv_stack_.back() = !mkv_stack_.back(); - ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2); - break; - - default: - assert(!"Invalid TType in stateTransition."); - break; - } -} - -/* - * Variable-length quantity functions. - */ - -inline uint32_t TDenseProtocol::vlqRead(uint64_t& vlq) { - uint32_t used = 0; - uint64_t val = 0; - uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes. - uint32_t buf_size = sizeof(buf); - const uint8_t* borrowed = trans_->borrow(buf, &buf_size); - - // Fast path. TODO(dreiss): Make it faster. - if (borrowed != NULL) { - while (true) { - uint8_t byte = borrowed[used]; - used++; - val = (val << 7) | (byte & 0x7f); - if (!(byte & 0x80)) { - vlq = val; - trans_->consume(used); - return used; - } - // Have to check for invalid data so we don't crash. - if (UNLIKELY(used == sizeof(buf))) { - resetState(); - throw TProtocolException(TProtocolException::INVALID_DATA, - "Variable-length int over 10 bytes."); - } - } - } - - // Slow path. - else { - while (true) { - uint8_t byte; - used += trans_->readAll(&byte, 1); - val = (val << 7) | (byte & 0x7f); - if (!(byte & 0x80)) { - vlq = val; - return used; - } - // Might as well check for invalid data on the slow path too. - if (UNLIKELY(used >= sizeof(buf))) { - resetState(); - throw TProtocolException(TProtocolException::INVALID_DATA, - "Variable-length int over 10 bytes."); - } - } - } -} - -inline uint32_t TDenseProtocol::vlqWrite(uint64_t vlq) { - uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes. - int32_t pos = sizeof(buf) - 1; - - // Write the thing from back to front. - buf[pos] = vlq & 0x7f; - vlq >>= 7; - pos--; - - while (vlq > 0) { - assert(pos >= 0); - buf[pos] = static_cast<uint8_t>(vlq | 0x80); - vlq >>= 7; - pos--; - } - - // Back up one step before writing. - pos++; - - trans_->write(buf + pos, static_cast<uint32_t>(sizeof(buf) - pos)); - return static_cast<uint32_t>(sizeof(buf) - pos); -} - -/* - * Writing functions. - */ - -uint32_t TDenseProtocol::writeMessageBegin(const std::string& name, - const TMessageType messageType, - const int32_t seqid) { - throw TException("TDenseProtocol doesn't work with messages (yet)."); - - int32_t version = (VERSION_2) | ((int32_t)messageType); - uint32_t wsize = 0; - wsize += subWriteI32(version); - wsize += subWriteString(name); - wsize += subWriteI32(seqid); - return wsize; -} - -uint32_t TDenseProtocol::writeMessageEnd() { - return 0; -} - -uint32_t TDenseProtocol::writeStructBegin(const char* name) { - (void)name; - uint32_t xfer = 0; - - // The TypeSpec stack should be empty if this is the top-level read/write. - // If it is, we push the TypeSpec passed to the constructor. - if (ts_stack_.empty()) { - assert(standalone_); - - if (type_spec_ == NULL) { - resetState(); - throw TException("TDenseProtocol: No type specified."); - } else { - assert(type_spec_->ttype == T_STRUCT); - ts_stack_.push_back(type_spec_); - // Write out a prefix of the structure fingerprint. - trans_->write(type_spec_->fp_prefix, FP_PREFIX_LEN); - xfer += FP_PREFIX_LEN; - } - } - - // We need a new field index for this structure. - idx_stack_.push_back(0); - return 0; -} - -uint32_t TDenseProtocol::writeStructEnd() { - idx_stack_.pop_back(); - stateTransition(); - return 0; -} - -uint32_t TDenseProtocol::writeFieldBegin(const char* name, - const TType fieldType, - const int16_t fieldId) { - (void)name; - uint32_t xfer = 0; - - // Skip over optional fields. - while (FMT.tag != fieldId) { - // TODO(dreiss): Old meta here. - assert(FTS->ttype != T_STOP); - assert(FMT.is_optional); - // Write a zero byte so the reader can skip it. - xfer += subWriteBool(false); - // And advance to the next field. - IDX++; - } - - // TODO(dreiss): give a better exception. - assert(FTS->ttype == fieldType); - - if (FMT.is_optional) { - subWriteBool(true); - xfer += 1; - } - - // writeFieldStop shares all lot of logic up to this point. - // Instead of replicating it all, we just call this method from that one - // and use a gross special case here. - if (UNLIKELY(FTS->ttype != T_STOP)) { - // For normal fields, push the TypeSpec that we're about to use. - ts_stack_.push_back(FTS); - } - return xfer; -} - -uint32_t TDenseProtocol::writeFieldEnd() { - // Just move on to the next field. - IDX++; - return 0; -} - -uint32_t TDenseProtocol::writeFieldStop() { - return TDenseProtocol::writeFieldBegin("", T_STOP, 0); -} - -uint32_t TDenseProtocol::writeMapBegin(const TType keyType, - const TType valType, - const uint32_t size) { - checkTType(T_MAP); - - assert(keyType == ST1->ttype); - assert(valType == ST2->ttype); - - ts_stack_.push_back(ST1); - mkv_stack_.push_back(true); - - return subWriteI32((int32_t)size); -} - -uint32_t TDenseProtocol::writeMapEnd() { - // Pop off the value type, as well as our entry in the map key/value stack. - // stateTransition takes care of popping off our TypeSpec. - ts_stack_.pop_back(); - mkv_stack_.pop_back(); - stateTransition(); - return 0; -} - -uint32_t TDenseProtocol::writeListBegin(const TType elemType, const uint32_t size) { - checkTType(T_LIST); - - assert(elemType == ST1->ttype); - ts_stack_.push_back(ST1); - return subWriteI32((int32_t)size); -} - -uint32_t TDenseProtocol::writeListEnd() { - // Pop off the element type. stateTransition takes care of popping off ours. - ts_stack_.pop_back(); - stateTransition(); - return 0; -} - -uint32_t TDenseProtocol::writeSetBegin(const TType elemType, const uint32_t size) { - checkTType(T_SET); - - assert(elemType == ST1->ttype); - ts_stack_.push_back(ST1); - return subWriteI32((int32_t)size); -} - -uint32_t TDenseProtocol::writeSetEnd() { - // Pop off the element type. stateTransition takes care of popping off ours. - ts_stack_.pop_back(); - stateTransition(); - return 0; -} - -uint32_t TDenseProtocol::writeBool(const bool value) { - checkTType(T_BOOL); - stateTransition(); - return TBinaryProtocol::writeBool(value); -} - -uint32_t TDenseProtocol::writeByte(const int8_t byte) { - checkTType(T_BYTE); - stateTransition(); - return TBinaryProtocol::writeByte(byte); -} - -uint32_t TDenseProtocol::writeI16(const int16_t i16) { - checkTType(T_I16); - stateTransition(); - return vlqWrite(i16); -} - -uint32_t TDenseProtocol::writeI32(const int32_t i32) { - checkTType(T_I32); - stateTransition(); - return vlqWrite(i32); -} - -uint32_t TDenseProtocol::writeI64(const int64_t i64) { - checkTType(T_I64); - stateTransition(); - return vlqWrite(i64); -} - -uint32_t TDenseProtocol::writeDouble(const double dub) { - checkTType(T_DOUBLE); - stateTransition(); - return TBinaryProtocol::writeDouble(dub); -} - -uint32_t TDenseProtocol::writeString(const std::string& str) { - checkTType(T_STRING); - stateTransition(); - return subWriteString(str); -} - -uint32_t TDenseProtocol::writeBinary(const std::string& str) { - return TDenseProtocol::writeString(str); -} - -inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) { - return vlqWrite(i32); -} - -uint32_t TDenseProtocol::subWriteString(const std::string& str) { - if (str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)())) - throw TProtocolException(TProtocolException::SIZE_LIMIT); - uint32_t size = static_cast<uint32_t>(str.size()); - uint32_t xfer = subWriteI32((int32_t)size); - if (size > 0) { - trans_->write((uint8_t*)str.data(), size); - } - return xfer + size; -} - -/* - * Reading functions - * - * These have a lot of the same logic as the writing functions, so if - * something is confusing, look for comments in the corresponding writer. - */ - -uint32_t TDenseProtocol::readMessageBegin(std::string& name, - TMessageType& messageType, - int32_t& seqid) { - throw TException("TDenseProtocol doesn't work with messages (yet)."); - - uint32_t xfer = 0; - int32_t sz; - xfer += subReadI32(sz); - - if (sz < 0) { - // Check for correct version number - int32_t version = sz & VERSION_MASK; - if (version != VERSION_2) { - throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier"); - } - messageType = (TMessageType)(sz & 0x000000ff); - xfer += subReadString(name); - xfer += subReadI32(seqid); - } else { - throw TProtocolException(TProtocolException::BAD_VERSION, - "No version identifier... old protocol client in strict mode?"); - } - return xfer; -} - -uint32_t TDenseProtocol::readMessageEnd() { - return 0; -} - -uint32_t TDenseProtocol::readStructBegin(string& name) { - (void)name; - uint32_t xfer = 0; - - if (ts_stack_.empty()) { - assert(standalone_); - - if (type_spec_ == NULL) { - resetState(); - throw TException("TDenseProtocol: No type specified."); - } else { - assert(type_spec_->ttype == T_STRUCT); - ts_stack_.push_back(type_spec_); - - // Check the fingerprint prefix. - uint8_t buf[FP_PREFIX_LEN]; - xfer += trans_->read(buf, FP_PREFIX_LEN); - if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) { - resetState(); - throw TProtocolException(TProtocolException::INVALID_DATA, - "Fingerprint in data does not match type_spec."); - } - } - } - - // We need a new field index for this structure. - idx_stack_.push_back(0); - return 0; -} - -uint32_t TDenseProtocol::readStructEnd() { - idx_stack_.pop_back(); - stateTransition(); - return 0; -} - -uint32_t TDenseProtocol::readFieldBegin(string& name, TType& fieldType, int16_t& fieldId) { - (void)name; - uint32_t xfer = 0; - - // For optional fields, check to see if they are there. - while (FMT.is_optional) { - bool is_present; - xfer += subReadBool(is_present); - if (is_present) { - break; - } - IDX++; - } - - // Once we hit a mandatory field, or an optional field that is present, - // we know that FMT and FTS point to the appropriate field. - - fieldId = FMT.tag; - fieldType = FTS->ttype; - - // Normally, we push the TypeSpec that we are about to read, - // but no reading is done for T_STOP. - if (FTS->ttype != T_STOP) { - ts_stack_.push_back(FTS); - } - return xfer; -} - -uint32_t TDenseProtocol::readFieldEnd() { - IDX++; - return 0; -} - -uint32_t TDenseProtocol::readMapBegin(TType& keyType, TType& valType, uint32_t& size) { - checkTType(T_MAP); - - uint32_t xfer = 0; - int32_t sizei; - xfer += subReadI32(sizei); - if (sizei < 0) { - resetState(); - throw TProtocolException(TProtocolException::NEGATIVE_SIZE); - } else if (container_limit_ && sizei > container_limit_) { - resetState(); - throw TProtocolException(TProtocolException::SIZE_LIMIT); - } - size = (uint32_t)sizei; - - keyType = ST1->ttype; - valType = ST2->ttype; - - ts_stack_.push_back(ST1); - mkv_stack_.push_back(true); - - return xfer; -} - -uint32_t TDenseProtocol::readMapEnd() { - ts_stack_.pop_back(); - mkv_stack_.pop_back(); - stateTransition(); - return 0; -} - -uint32_t TDenseProtocol::readListBegin(TType& elemType, uint32_t& size) { - checkTType(T_LIST); - - uint32_t xfer = 0; - int32_t sizei; - xfer += subReadI32(sizei); - if (sizei < 0) { - resetState(); - throw TProtocolException(TProtocolException::NEGATIVE_SIZE); - } else if (container_limit_ && sizei > container_limit_) { - resetState(); - throw TProtocolException(TProtocolException::SIZE_LIMIT); - } - size = (uint32_t)sizei; - - elemType = ST1->ttype; - - ts_stack_.push_back(ST1); - - return xfer; -} - -uint32_t TDenseProtocol::readListEnd() { - ts_stack_.pop_back(); - stateTransition(); - return 0; -} - -uint32_t TDenseProtocol::readSetBegin(TType& elemType, uint32_t& size) { - checkTType(T_SET); - - uint32_t xfer = 0; - int32_t sizei; - xfer += subReadI32(sizei); - if (sizei < 0) { - resetState(); - throw TProtocolException(TProtocolException::NEGATIVE_SIZE); - } else if (container_limit_ && sizei > container_limit_) { - resetState(); - throw TProtocolException(TProtocolException::SIZE_LIMIT); - } - size = (uint32_t)sizei; - - elemType = ST1->ttype; - - ts_stack_.push_back(ST1); - - return xfer; -} - -uint32_t TDenseProtocol::readSetEnd() { - ts_stack_.pop_back(); - stateTransition(); - return 0; -} - -uint32_t TDenseProtocol::readBool(bool& value) { - checkTType(T_BOOL); - stateTransition(); - return TBinaryProtocol::readBool(value); -} - -uint32_t TDenseProtocol::readByte(int8_t& byte) { - checkTType(T_BYTE); - stateTransition(); - return TBinaryProtocol::readByte(byte); -} - -uint32_t TDenseProtocol::readI16(int16_t& i16) { - checkTType(T_I16); - stateTransition(); - uint64_t u64; - uint32_t rv = vlqRead(u64); - int64_t val = (int64_t)u64; - if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) { - resetState(); - throw TProtocolException(TProtocolException::INVALID_DATA, "i16 out of range."); - } - i16 = (int16_t)val; - return rv; -} - -uint32_t TDenseProtocol::readI32(int32_t& i32) { - checkTType(T_I32); - stateTransition(); - uint64_t u64; - uint32_t rv = vlqRead(u64); - int64_t val = (int64_t)u64; - if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) { - resetState(); - throw TProtocolException(TProtocolException::INVALID_DATA, "i32 out of range."); - } - i32 = (int32_t)val; - return rv; -} - -uint32_t TDenseProtocol::readI64(int64_t& i64) { - checkTType(T_I64); - stateTransition(); - uint64_t u64; - uint32_t rv = vlqRead(u64); - int64_t val = (int64_t)u64; - if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) { - resetState(); - throw TProtocolException(TProtocolException::INVALID_DATA, "i64 out of range."); - } - i64 = (int64_t)val; - return rv; -} - -uint32_t TDenseProtocol::readDouble(double& dub) { - checkTType(T_DOUBLE); - stateTransition(); - return TBinaryProtocol::readDouble(dub); -} - -uint32_t TDenseProtocol::readString(std::string& str) { - checkTType(T_STRING); - stateTransition(); - return subReadString(str); -} - -uint32_t TDenseProtocol::readBinary(std::string& str) { - return TDenseProtocol::readString(str); -} - -uint32_t TDenseProtocol::subReadI32(int32_t& i32) { - uint64_t u64; - uint32_t rv = vlqRead(u64); - int64_t val = (int64_t)u64; - if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) { - resetState(); - throw TProtocolException(TProtocolException::INVALID_DATA, "i32 out of range."); - } - i32 = (int32_t)val; - return rv; -} - -uint32_t TDenseProtocol::subReadString(std::string& str) { - uint32_t xfer; - int32_t size; - xfer = subReadI32(size); - return xfer + readStringBody(str, size); -} -} -} -} // apache::thrift::protocol diff --git a/lib/cpp/src/thrift/protocol/TDenseProtocol.h b/lib/cpp/src/thrift/protocol/TDenseProtocol.h deleted file mode 100644 index d7a119a1e..000000000 --- a/lib/cpp/src/thrift/protocol/TDenseProtocol.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef _THRIFT_PROTOCOL_TDENSEPROTOCOL_H_ -#define _THRIFT_PROTOCOL_TDENSEPROTOCOL_H_ 1 - -#include <thrift/protocol/TBinaryProtocol.h> - -namespace apache { -namespace thrift { -namespace protocol { - -/** - * !!!WARNING!!! - * This class is still highly experimental. Incompatible changes - * WILL be made to it without notice. DO NOT USE IT YET unless - * you are coordinating your testing with the author. - * - * The dense protocol is designed to use as little space as possible. - * - * There are two types of dense protocol instances. Standalone instances - * are not used for RPC and just encoded and decode structures of - * a predetermined type. Non-standalone instances are used for RPC. - * Currently, only standalone instances exist. - * - * To use a standalone dense protocol object, you must set the type_spec - * property (either in the constructor, or with setTypeSpec) to the local - * reflection TypeSpec of the structures you will write to (or read from) the - * protocol instance. - * - * BEST PRACTICES: - * - Never use optional for primitives or containers. - * - Only use optional for structures if they are very big and very rarely set. - * - All integers are variable-length, so you can use i64 without bloating. - * - NEVER EVER change the struct definitions IN ANY WAY without either - * changing your cache keys or talking to dreiss. - * - * TODO(dreiss): New class write with old meta. - * - * We override all of TBinaryProtocol's methods. - * We inherit so that we can explicitly call TBPs's primitive-writing - * methods within our versions. - * - */ -class TDenseProtocol : public TVirtualProtocol<TDenseProtocol, TBinaryProtocol> { -protected: - static const int32_t VERSION_MASK = ((int32_t)0xffff0000); - // VERSION_1 (0x80010000) is taken by TBinaryProtocol. - static const int32_t VERSION_2 = ((int32_t)0x80020000); - -public: - typedef apache::thrift::reflection::local::TypeSpec TypeSpec; - static const int FP_PREFIX_LEN; - - /** - * @param tran The transport to use. - * @param type_spec The TypeSpec of the structures using this protocol. - */ - TDenseProtocol(boost::shared_ptr<TTransport> trans, TypeSpec* type_spec = NULL) - : TVirtualProtocol<TDenseProtocol, TBinaryProtocol>(trans), - type_spec_(type_spec), - standalone_(true) {} - - void setTypeSpec(TypeSpec* type_spec) { type_spec_ = type_spec; } - TypeSpec* getTypeSpec() { return type_spec_; } - - /* - * Writing functions. - */ - - uint32_t writeMessageBegin(const std::string& name, - const TMessageType messageType, - const int32_t seqid); - - uint32_t writeMessageEnd(); - - uint32_t writeStructBegin(const char* name); - - uint32_t writeStructEnd(); - - uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId); - - uint32_t writeFieldEnd(); - - uint32_t writeFieldStop(); - - uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size); - - uint32_t writeMapEnd(); - - uint32_t writeListBegin(const TType elemType, const uint32_t size); - - uint32_t writeListEnd(); - - uint32_t writeSetBegin(const TType elemType, const uint32_t size); - - uint32_t writeSetEnd(); - - uint32_t writeBool(const bool value); - - uint32_t writeByte(const int8_t byte); - - uint32_t writeI16(const int16_t i16); - - uint32_t writeI32(const int32_t i32); - - uint32_t writeI64(const int64_t i64); - - uint32_t writeDouble(const double dub); - - uint32_t writeString(const std::string& str); - - uint32_t writeBinary(const std::string& str); - - /* - * Helper writing functions (don't do state transitions). - */ - inline uint32_t subWriteI32(const int32_t i32); - - inline uint32_t subWriteString(const std::string& str); - - uint32_t subWriteBool(const bool value) { return TBinaryProtocol::writeBool(value); } - - /* - * Reading functions - */ - - uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid); - - uint32_t readMessageEnd(); - - uint32_t readStructBegin(std::string& name); - - uint32_t readStructEnd(); - - uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId); - - uint32_t readFieldEnd(); - - uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size); - - uint32_t readMapEnd(); - - uint32_t readListBegin(TType& elemType, uint32_t& size); - - uint32_t readListEnd(); - - uint32_t readSetBegin(TType& elemType, uint32_t& size); - - uint32_t readSetEnd(); - - uint32_t readBool(bool& value); - // Provide the default readBool() implementation for std::vector<bool> - using TVirtualProtocol<TDenseProtocol, TBinaryProtocol>::readBool; - - uint32_t readByte(int8_t& byte); - - uint32_t readI16(int16_t& i16); - - uint32_t readI32(int32_t& i32); - - uint32_t readI64(int64_t& i64); - - uint32_t readDouble(double& dub); - - uint32_t readString(std::string& str); - - uint32_t readBinary(std::string& str); - - /* - * Helper reading functions (don't do state transitions). - */ - inline uint32_t subReadI32(int32_t& i32); - - inline uint32_t subReadString(std::string& str); - - uint32_t subReadBool(bool& value) { return TBinaryProtocol::readBool(value); } - -private: - // Implementation functions, documented in the .cpp. - inline void checkTType(const TType ttype); - inline void stateTransition(); - - // Read and write variable-length integers. - // Uses the same technique as the MIDI file format. - inline uint32_t vlqRead(uint64_t& vlq); - inline uint32_t vlqWrite(uint64_t vlq); - - // Called before throwing an exception to make the object reusable. - void resetState() { - ts_stack_.clear(); - idx_stack_.clear(); - mkv_stack_.clear(); - } - - // TypeSpec of the top-level structure to write, - // for standalone protocol objects. - TypeSpec* type_spec_; - - std::vector<TypeSpec*> ts_stack_; // TypeSpec stack. - std::vector<int> idx_stack_; // InDeX stack. - std::vector<bool> mkv_stack_; // Map Key/Vlue stack. - // True = key, False = value. - - // True iff this is a standalone instance (no RPC). - bool standalone_; -}; -} -} -} // apache::thrift::protocol - -#endif // #ifndef _THRIFT_PROTOCOL_TDENSEPROTOCOL_H_ diff --git a/lib/cpp/test/CMakeLists.txt b/lib/cpp/test/CMakeLists.txt index 80c685250..9913f6c92 100644 --- a/lib/cpp/test/CMakeLists.txt +++ b/lib/cpp/test/CMakeLists.txt @@ -325,7 +325,7 @@ endif() add_custom_command(OUTPUT gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h gen-cpp/EmptyService.cpp gen-cpp/EmptyService.h - COMMAND thrift-compiler --gen cpp:dense ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift + COMMAND thrift-compiler --gen cpp ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift ) add_custom_command(OUTPUT gen-cpp/EnumTest_types.cpp gen-cpp/EnumTest_types.h @@ -337,7 +337,7 @@ add_custom_command(OUTPUT gen-cpp/TypedefTest_types.cpp gen-cpp/TypedefTest_type ) add_custom_command(OUTPUT gen-cpp/OptionalRequiredTest_types.cpp gen-cpp/OptionalRequiredTest_types.h - COMMAND thrift-compiler --gen cpp:dense ${PROJECT_SOURCE_DIR}/test/OptionalRequiredTest.thrift + COMMAND thrift-compiler --gen cpp ${PROJECT_SOURCE_DIR}/test/OptionalRequiredTest.thrift ) add_custom_command(OUTPUT gen-cpp/Recursive_types.cpp gen-cpp/Recursive_types.h @@ -345,11 +345,11 @@ add_custom_command(OUTPUT gen-cpp/Recursive_types.cpp gen-cpp/Recursive_types.h ) add_custom_command(OUTPUT gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp - COMMAND thrift-compiler --gen cpp:dense ${PROJECT_SOURCE_DIR}/test/StressTest.thrift + COMMAND thrift-compiler --gen cpp ${PROJECT_SOURCE_DIR}/test/StressTest.thrift ) add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h - COMMAND thrift-compiler --gen cpp:dense ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift + COMMAND thrift-compiler --gen cpp ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift ) add_custom_command(OUTPUT gen-cpp/ChildService.cpp gen-cpp/ChildService.h gen-cpp/ParentService.cpp gen-cpp/ParentService.h gen-cpp/proc_types.cpp gen-cpp/proc_types.h diff --git a/lib/cpp/test/DenseProtoTest.cpp b/lib/cpp/test/DenseProtoTest.cpp deleted file mode 100644 index 0beaa380b..000000000 --- a/lib/cpp/test/DenseProtoTest.cpp +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* -../compiler/cpp/thrift --gen cpp:dense DebugProtoTest.thrift -../compiler/cpp/thrift --gen cpp:dense OptionalRequiredTest.thrift -g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \ - gen-cpp/OptionalRequiredTest_types.cpp \ - gen-cpp/DebugProtoTest_types.cpp \ - DenseProtoTest.cpp ../lib/cpp/.libs/libthrift.a -o DenseProtoTest -./DenseProtoTest -*/ - -// I do this to reach into the guts of TDenseProtocol. Sorry. -#define private public -#define inline - -#undef NDEBUG -#include <cstdlib> -#include <cassert> -#include <cmath> -#include <string> -#include "gen-cpp/DebugProtoTest_types.h" -#include "gen-cpp/OptionalRequiredTest_types.h" -#include <thrift/protocol/TDenseProtocol.h> -#include <thrift/transport/TBufferTransports.h> - -#define BOOST_TEST_MODULE DenseProtoTest -#include <boost/test/unit_test.hpp> - -using std::string; -using boost::shared_ptr; -using namespace thrift::test; -using namespace thrift::test::debug; -using namespace apache::thrift::transport; -using namespace apache::thrift::protocol; - -// Can't use memcmp here. GCC is too smart. -bool my_memeq(const char* str1, const char* str2, int len) { - for (int i = 0; i < len; i++) { - if (str1[i] != str2[i]) { - return false; - } - } - return true; -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_1) { - OneOfEach ooe; - ooe.im_true = true; - ooe.im_false = false; - ooe.a_bite = 0xd6; - ooe.integer16 = 27000; - ooe.integer32 = 1 << 24; - ooe.integer64 = (uint64_t)6000 * 1000 * 1000; - ooe.double_precision = M_PI; - ooe.some_characters = "Debug THIS!"; - ooe.zomg_unicode = "\xd7\n\a\t"; - - // cout << apache::thrift::ThriftDebugString(ooe) << endl << endl; - - Nesting n; - n.my_ooe = ooe; - n.my_ooe.integer16 = 16; - n.my_ooe.integer32 = 32; - n.my_ooe.integer64 = 64; - n.my_ooe.double_precision = (std::sqrt(5) + 1) / 2; - n.my_ooe.some_characters = ":R (me going \"rrrr\")"; - n.my_ooe.zomg_unicode = "\xd3\x80\xe2\x85\xae\xce\x9d\x20" - "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e" - "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc"; - n.my_bonk.type = 31337; - n.my_bonk.message = "I am a bonk... xor!"; - - // cout << apache::thrift::ThriftDebugString(n) << endl << endl; - - HolyMoley hm; - - hm.big.push_back(ooe); - hm.big.push_back(n.my_ooe); - hm.big[0].a_bite = 0x22; - hm.big[1].a_bite = 0x33; - - std::vector<std::string> stage1; - stage1.push_back("and a one"); - stage1.push_back("and a two"); - hm.contain.insert(stage1); - stage1.clear(); - stage1.push_back("then a one, two"); - stage1.push_back("three!"); - stage1.push_back("FOUR!!"); - hm.contain.insert(stage1); - stage1.clear(); - hm.contain.insert(stage1); - - std::vector<Bonk> stage2; - hm.bonks["nothing"] = stage2; - stage2.resize(stage2.size() + 1); - stage2.back().type = 1; - stage2.back().message = "Wait."; - stage2.resize(stage2.size() + 1); - stage2.back().type = 2; - stage2.back().message = "What?"; - hm.bonks["something"] = stage2; - stage2.clear(); - stage2.resize(stage2.size() + 1); - stage2.back().type = 3; - stage2.back().message = "quoth"; - stage2.resize(stage2.size() + 1); - stage2.back().type = 4; - stage2.back().message = "the raven"; - stage2.resize(stage2.size() + 1); - stage2.back().type = 5; - stage2.back().message = "nevermore"; - hm.bonks["poe"] = stage2; - - // cout << apache::thrift::ThriftDebugString(hm) << endl << endl; - - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - proto->setTypeSpec(HolyMoley::local_reflection); - - hm.write(proto.get()); - HolyMoley hm2; - hm2.read(proto.get()); - - BOOST_CHECK(hm == hm2); -} - -/* - * Following Testcases are currently disabled, because vlqWrite and vlqRead are - * private members. - */ -#if 0 -#define checkout(i, c) \ - { \ - uint64_t vlq; \ - buffer->resetBuffer(); \ - proto->vlqWrite(i); \ - proto->getTransport()->flush(); \ - BOOST_CHECK(my_memeq(buffer->getBufferAsString().data(), c, sizeof(c) - 1));\ - proto->vlqRead(vlq); \ - assert(vlq == i); \ - } - -BOOST_AUTO_TEST_CASE(test_dense_proto_2) { - // Let's test out the variable-length ints, shall we? - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - - proto->setTypeSpec(HolyMoley::local_reflection); - - checkout(0x00000000, "\x00"); - checkout(0x00000040, "\x40"); - checkout(0x0000007F, "\x7F"); - checkout(0x00000080, "\x81\x00"); - checkout(0x00002000, "\xC0\x00"); - checkout(0x00003FFF, "\xFF\x7F"); - checkout(0x00004000, "\x81\x80\x00"); - checkout(0x00100000, "\xC0\x80\x00"); - checkout(0x001FFFFF, "\xFF\xFF\x7F"); - checkout(0x00200000, "\x81\x80\x80\x00"); - checkout(0x08000000, "\xC0\x80\x80\x00"); - checkout(0x0FFFFFFF, "\xFF\xFF\xFF\x7F"); - checkout(0x10000000, "\x81\x80\x80\x80\x00"); - checkout(0x20000000, "\x82\x80\x80\x80\x00"); - checkout(0x1FFFFFFF, "\x81\xFF\xFF\xFF\x7F"); - checkout(0xFFFFFFFF, "\x8F\xFF\xFF\xFF\x7F"); - - checkout(0x0000000100000000ull, "\x90\x80\x80\x80\x00"); - checkout(0x0000000200000000ull, "\xA0\x80\x80\x80\x00"); - checkout(0x0000000300000000ull, "\xB0\x80\x80\x80\x00"); - checkout(0x0000000700000000ull, "\xF0\x80\x80\x80\x00"); - checkout(0x00000007F0000000ull, "\xFF\x80\x80\x80\x00"); - checkout(0x00000007FFFFFFFFull, "\xFF\xFF\xFF\xFF\x7F"); - checkout(0x0000000800000000ull, "\x81\x80\x80\x80\x80\x00"); - checkout(0x1FFFFFFFFFFFFFFFull, "\x9F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); - checkout(0x7FFFFFFFFFFFFFFFull, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); - checkout(0xFFFFFFFFFFFFFFFFull, "\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_3) { - // Test out the slow path with a TBufferedTransport. - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - shared_ptr<TBufferedTransport> buff_trans(new TBufferedTransport(buffer, 3)); - - proto->setTypeSpec(HolyMoley::local_reflection); - proto.reset(new TDenseProtocol(buff_trans)); - - checkout(0x0000000100000000ull, "\x90\x80\x80\x80\x00"); - checkout(0x0000000200000000ull, "\xA0\x80\x80\x80\x00"); - checkout(0x0000000300000000ull, "\xB0\x80\x80\x80\x00"); - checkout(0x0000000700000000ull, "\xF0\x80\x80\x80\x00"); - checkout(0x00000007F0000000ull, "\xFF\x80\x80\x80\x00"); - checkout(0x00000007FFFFFFFFull, "\xFF\xFF\xFF\xFF\x7F"); - checkout(0x0000000800000000ull, "\x81\x80\x80\x80\x80\x00"); - checkout(0x1FFFFFFFFFFFFFFFull, "\x9F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); - checkout(0x7FFFFFFFFFFFFFFFull, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); - checkout(0xFFFFFFFFFFFFFFFFull, "\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); -} -#endif - -// Test optional stuff. -BOOST_AUTO_TEST_CASE(test_dense_proto_4_1) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - proto.reset(new TDenseProtocol(buffer)); - proto->setTypeSpec(ManyOpt::local_reflection); - - ManyOpt mo1, mo2; - mo1.opt1 = 923759347; - mo1.opt2 = 392749274; - mo1.opt3 = 395739402; - mo1.def4 = 294730928; - mo1.opt5 = 394309218; - mo1.opt6 = 832194723; - mo1.__isset.opt1 = true; - mo1.__isset.opt2 = true; - mo1.__isset.opt3 = true; - mo1.__isset.def4 = true; - mo1.__isset.opt5 = true; - mo1.__isset.opt6 = true; - - mo1.write(proto.get()); - mo2.read(proto.get()); - - BOOST_CHECK(mo2.__isset.opt1 == true); - BOOST_CHECK(mo2.__isset.opt2 == true); - BOOST_CHECK(mo2.__isset.opt3 == true); - BOOST_CHECK(mo2.__isset.def4 == true); - BOOST_CHECK(mo2.__isset.opt5 == true); - BOOST_CHECK(mo2.__isset.opt6 == true); - - BOOST_CHECK(mo1 == mo2); -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_4_2) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - proto.reset(new TDenseProtocol(buffer)); - proto->setTypeSpec(ManyOpt::local_reflection); - - ManyOpt mo1, mo2; - mo1.opt1 = 923759347; - mo1.opt2 = 392749274; - mo1.opt3 = 395739402; - mo1.def4 = 294730928; - mo1.opt5 = 394309218; - mo1.opt6 = 832194723; - mo1.__isset.opt1 = false; - mo1.__isset.opt2 = true; - mo1.__isset.opt3 = false; - mo1.__isset.def4 = true; - mo1.__isset.opt5 = false; - mo1.__isset.opt6 = true; - - mo1.write(proto.get()); - mo2.read(proto.get()); - - BOOST_CHECK(mo2.__isset.opt1 == false); - BOOST_CHECK(mo2.__isset.opt2 == true); - BOOST_CHECK(mo2.__isset.opt3 == false); - BOOST_CHECK(mo2.__isset.def4 == true); - BOOST_CHECK(mo2.__isset.opt5 == false); - BOOST_CHECK(mo2.__isset.opt6 == true); - - BOOST_CHECK(mo1 == mo2); -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_4_3) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - proto.reset(new TDenseProtocol(buffer)); - proto->setTypeSpec(ManyOpt::local_reflection); - - ManyOpt mo1, mo2; - mo1.opt1 = 923759347; - mo1.opt2 = 392749274; - mo1.opt3 = 395739402; - mo1.def4 = 294730928; - mo1.opt5 = 394309218; - mo1.opt6 = 832194723; - mo1.__isset.opt1 = true; - mo1.__isset.opt2 = false; - mo1.__isset.opt3 = true; - mo1.__isset.def4 = true; - mo1.__isset.opt5 = true; - mo1.__isset.opt6 = false; - - mo1.write(proto.get()); - mo2.read(proto.get()); - - BOOST_CHECK(mo2.__isset.opt1 == true); - BOOST_CHECK(mo2.__isset.opt2 == false); - BOOST_CHECK(mo2.__isset.opt3 == true); - BOOST_CHECK(mo2.__isset.def4 == true); - BOOST_CHECK(mo2.__isset.opt5 == true); - BOOST_CHECK(mo2.__isset.opt6 == false); - - BOOST_CHECK(mo1 == mo2); -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_4_4) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - proto.reset(new TDenseProtocol(buffer)); - proto->setTypeSpec(ManyOpt::local_reflection); - - ManyOpt mo1, mo2; - mo1.opt1 = 923759347; - mo1.opt2 = 392749274; - mo1.opt3 = 395739402; - mo1.def4 = 294730928; - mo1.opt5 = 394309218; - mo1.opt6 = 832194723; - mo1.__isset.opt1 = false; - mo1.__isset.opt2 = false; - mo1.__isset.opt3 = true; - mo1.__isset.def4 = true; - mo1.__isset.opt5 = false; - mo1.__isset.opt6 = false; - - mo1.write(proto.get()); - mo2.read(proto.get()); - - BOOST_CHECK(mo2.__isset.opt1 == false); - BOOST_CHECK(mo2.__isset.opt2 == false); - BOOST_CHECK(mo2.__isset.opt3 == true); - BOOST_CHECK(mo2.__isset.def4 == true); - BOOST_CHECK(mo2.__isset.opt5 == false); - BOOST_CHECK(mo2.__isset.opt6 == false); - - BOOST_CHECK(mo1 == mo2); -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_4_5) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - proto.reset(new TDenseProtocol(buffer)); - proto->setTypeSpec(ManyOpt::local_reflection); - - ManyOpt mo1, mo2; - mo1.opt1 = 923759347; - mo1.opt2 = 392749274; - mo1.opt3 = 395739402; - mo1.def4 = 294730928; - mo1.opt5 = 394309218; - mo1.opt6 = 832194723; - mo1.__isset.opt1 = false; - mo1.__isset.opt2 = false; - mo1.__isset.opt3 = false; - mo1.__isset.def4 = true; - mo1.__isset.opt5 = false; - mo1.__isset.opt6 = false; - - mo1.write(proto.get()); - mo2.read(proto.get()); - - BOOST_CHECK(mo2.__isset.opt1 == false); - BOOST_CHECK(mo2.__isset.opt2 == false); - BOOST_CHECK(mo2.__isset.opt3 == false); - BOOST_CHECK(mo2.__isset.def4 == true); - BOOST_CHECK(mo2.__isset.opt5 == false); - BOOST_CHECK(mo2.__isset.opt6 == false); - - BOOST_CHECK(mo1 == mo2); -} - -// Test fingerprint checking stuff. -BOOST_AUTO_TEST_CASE(test_dense_proto_5_1) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - - // Default and required have the same fingerprint. - Tricky1 t1; - Tricky3 t3; - BOOST_CHECK(string(Tricky1::ascii_fingerprint) == Tricky3::ascii_fingerprint); - proto->setTypeSpec(Tricky1::local_reflection); - t1.im_default = 227; - t1.write(proto.get()); - proto->setTypeSpec(Tricky3::local_reflection); - t3.read(proto.get()); - BOOST_CHECK(t3.im_required == 227); -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_5_2) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - - // Optional changes things. - Tricky1 t1; - Tricky2 t2; - BOOST_CHECK(string(Tricky1::ascii_fingerprint) != Tricky2::ascii_fingerprint); - proto->setTypeSpec(Tricky1::local_reflection); - t1.im_default = 227; - t1.write(proto.get()); - try { - proto->setTypeSpec(Tricky2::local_reflection); - t2.read(proto.get()); - BOOST_CHECK(false); - } catch (TProtocolException& ex) { - buffer->resetBuffer(); - } -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_5_3) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - - // Holy cow. We can use the Tricky1 typespec with the Tricky2 structure. - Tricky1 t1; - Tricky2 t2; - proto->setTypeSpec(Tricky1::local_reflection); - t1.im_default = 227; - t1.write(proto.get()); - t2.read(proto.get()); - BOOST_CHECK(t2.__isset.im_optional == true); - BOOST_CHECK(t2.im_optional == 227); -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_5_4) { - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - - // And totally off the wall. - Tricky1 t1; - OneOfEach ooe2; - BOOST_CHECK(string(Tricky1::ascii_fingerprint) != OneOfEach::ascii_fingerprint); - proto->setTypeSpec(Tricky1::local_reflection); - t1.im_default = 227; - t1.write(proto.get()); - try { - proto->setTypeSpec(OneOfEach::local_reflection); - ooe2.read(proto.get()); - BOOST_CHECK(false); - } catch (TProtocolException& ex) { - buffer->resetBuffer(); - } -} - -BOOST_AUTO_TEST_CASE(test_dense_proto_6) { - // Okay, this is really off the wall. - // Just don't crash. - shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer()); - shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer)); - - BOOST_TEST_MESSAGE("Starting fuzz test. This takes a while."); - std::srand(12345); - for (int i = 0; i < 2000; i++) { - if (i % 100 == 0) { - BOOST_TEST_MESSAGE("Do " << i / 100 << "/" << 2000 / 100); - } - buffer->resetBuffer(); - // Make sure the fingerprint prefix is right. - buffer->write(Nesting::binary_fingerprint, 4); - for (int j = 0; j < 1024 * 1024; j++) { - uint8_t r = std::rand(); - buffer->write(&r, 1); - } - Nesting n; - proto->setTypeSpec(OneOfEach::local_reflection); - try { - n.read(proto.get()); - } catch (TProtocolException& ex) { - } catch (TTransportException& ex) { - } - } -} diff --git a/lib/cpp/test/Makefile.am b/lib/cpp/test/Makefile.am index 70efa6b9a..dadbe38e5 100755 --- a/lib/cpp/test/Makefile.am +++ b/lib/cpp/test/Makefile.am @@ -89,8 +89,7 @@ check_PROGRAMS = \ TFileTransportTest \ link_test \ OpenSSLManualInitTest \ - EnumTest \ - DenseProtoTest + EnumTest if AMX_HAVE_LIBEVENT noinst_PROGRAMS += \ @@ -276,16 +275,6 @@ RecursiveTest_LDADD = \ $(BOOST_TEST_LDADD) # -# DenseProtoTest -# -DenseProtoTest_SOURCES = \ - DenseProtoTest.cpp - -DenseProtoTest_LDADD = \ - libtestgencpp.la \ - $(BOOST_TEST_LDADD) - -# # SpecializationTest # SpecializationTest_SOURCES = \ @@ -337,7 +326,7 @@ OpenSSLManualInitTest_LDADD = \ THRIFT = $(top_builddir)/compiler/cpp/thrift gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h gen-cpp/EmptyService.cpp gen-cpp/EmptyService.h: $(top_srcdir)/test/DebugProtoTest.thrift - $(THRIFT) --gen cpp:dense $< + $(THRIFT) --gen cpp $< gen-cpp/EnumTest_types.cpp gen-cpp/EnumTest_types.h: $(top_srcdir)/test/EnumTest.thrift $(THRIFT) --gen cpp $< @@ -346,16 +335,16 @@ gen-cpp/TypedefTest_types.cpp gen-cpp/TypedefTest_types.h: $(top_srcdir)/test/Ty $(THRIFT) --gen cpp $< gen-cpp/OptionalRequiredTest_types.cpp gen-cpp/OptionalRequiredTest_types.h: $(top_srcdir)/test/OptionalRequiredTest.thrift - $(THRIFT) --gen cpp:dense $< + $(THRIFT) --gen cpp $< gen-cpp/Recursive_types.cpp gen-cpp/Recursive_types.h: $(top_srcdir)/test/Recursive.thrift $(THRIFT) --gen cpp $< gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp: $(top_srcdir)/test/StressTest.thrift - $(THRIFT) --gen cpp:dense $< + $(THRIFT) --gen cpp $< gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h: $(top_srcdir)/test/ThriftTest.thrift - $(THRIFT) --gen cpp:dense $< + $(THRIFT) --gen cpp $< gen-cpp/ChildService.cpp gen-cpp/ChildService.h gen-cpp/ParentService.cpp gen-cpp/ParentService.h gen-cpp/proc_types.cpp gen-cpp/proc_types.h: processor/proc.thrift $(THRIFT) --gen cpp:templates,cob_style $< |