Thrift: Slight tweaks to local reflection.
Summary:
Local reflection typespecs for structs now have a dummy T_STOP field at the end
so we don't have to check the size on every iteration.
They also contain information about which fields are optional.
Also put a static pointer to the reflection in each structure.
Reviewed By: mcslee
Test Plan: test/DenseLinkingTest.thrift
Revert Plan: ok
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665246 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index 10127fc..4a6befd 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -445,6 +445,13 @@
endl <<
indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
+ // Pointer to this structure's reflection local typespec.
+ if (gen_dense_) {
+ indent(out) <<
+ "static facebook::thrift::reflection::local::TypeSpec* local_reflection;" <<
+ endl << endl;
+ }
+
// Declare all fields
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
indent(out) <<
@@ -610,22 +617,32 @@
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_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 tags and field specs also.
+ // For definitions of structures, do the arrays of metas and field specs also.
if (is_definition) {
- indent(out) << "int16_t " << local_reflection_name("ftags", ttype) <<"[] = {" << endl;
+ out <<
+ indent() << "facebook::thrift::reflection::local::FieldMeta" << endl <<
+ indent() << local_reflection_name("metas", ttype) <<"[] = {" << endl;
indent_up();
- indent(out);
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- out << (*m_iter)->get_key() << ", ";
+ indent(out) << "{ " << (*m_iter)->get_key() << ", " <<
+ (((*m_iter)->get_req() == t_field::OPTIONAL) ? "true" : "false") <<
+ " }," << endl;
}
+ // Zero for the T_STOP marker.
+ indent(out) << "{ 0, false }" << endl << "};" << endl;
indent_down();
- out << endl << "};" << endl;
out <<
indent() << "facebook::thrift::reflection::local::TypeSpec*" << endl <<
@@ -635,6 +652,8 @@
indent(out) << "&" <<
local_reflection_name("typespec", (*m_iter)->get_type()) << "," << endl;
}
+ indent(out) << "&" <<
+ local_reflection_name("typespec", g_type_void) << "," << endl;
indent_down();
indent(out) << "};" << endl;
}
@@ -654,12 +673,16 @@
indent_up();
- indent(out) << type_to_enum(ttype);
+ if (ttype->is_void()) {
+ indent(out) << "facebook::thrift::protocol::T_STOP";
+ } else {
+ indent(out) << type_to_enum(ttype);
+ }
if (ttype->is_struct()) {
out << "," << endl <<
indent() << ((t_struct*)ttype)->get_members().size() << "," << endl <<
- indent() << local_reflection_name("ftags", ttype) << "," << endl <<
+ indent() << local_reflection_name("metas", ttype) << "," << endl <<
indent() << local_reflection_name("specs", ttype);
} else if (ttype->is_list()) {
out << "," << endl <<
@@ -678,6 +701,16 @@
out << ");" << endl << endl;
indent_down();
+
+ // If this is a struct and we are in the implementaion file,
+ // also set the class's static pointer to its reflection.
+ if (ttype->is_struct() && is_definition) {
+ indent(out) <<
+ "facebook::thrift::reflection::local::TypeSpec* " <<
+ ttype->get_name() << "::local_reflection = " << endl <<
+ indent() << " &" << local_reflection_name("typespec", ttype) << ";" <<
+ endl << endl;
+ }
}
/**
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index e0ff21f..4362029 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -533,6 +533,8 @@
st->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();
diff --git a/lib/cpp/src/TReflectionLocal.h b/lib/cpp/src/TReflectionLocal.h
index 6f082e7..414a0eb 100644
--- a/lib/cpp/src/TReflectionLocal.h
+++ b/lib/cpp/src/TReflectionLocal.h
@@ -21,13 +21,21 @@
* @author David Reiss <dreiss@facebook.com>
*/
+struct FieldMeta {
+ int16_t tags;
+ bool is_optional;
+};
+
struct TypeSpec {
// 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).
- int16_t* ftags;
+ FieldMeta* metas;
TypeSpec** specs;
+ // n_fields is only used for debugging, but it should only add
+ // a minimimal amount to the effective size of this structure
+ // because of alignment restrictions.
int n_fields;
} tstruct;
struct {
@@ -47,11 +55,11 @@
TypeSpec(TType ttype) : ttype(ttype) {}
- TypeSpec(TType ttype, int n_fields, int16_t* ftags, TypeSpec** specs) :
+ TypeSpec(TType ttype, int n_fields, FieldMeta* metas, TypeSpec** specs) :
ttype(ttype)
{
tstruct.n_fields = n_fields;
- tstruct.ftags = ftags;
+ tstruct.metas = metas;
tstruct.specs = specs;
}