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();