Thrift: Generate fingerprints for non-structs.

Summary:
This is going to be needed to support TDenseProtocol.

Reviewed By: mcslee

Test Plan:
Clean build of Thrift.
Ran if/regen.sh.  No change to generated C++ or Python.
gdb thrift -cpp ThriftTest.thrift.  Made sure they were being generated.

Revert Plan: ok


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665237 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 6218b0c..2fa1ccd 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -559,9 +559,9 @@
         << "ascii_fingerprint" << comment << "= \"" <<
         tstruct->get_ascii_fingerprint() << "\";" << endl <<
       indent() << stat << "char " << nspace <<
-        "binary_fingerprint[" << t_struct::fingerprint_len << "]" << comment << "= {";
+        "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {";
     char* comma = "";
-    for (int i = 0; i < t_struct::fingerprint_len; i++) {
+    for (int i = 0; i < t_type::fingerprint_len; i++) {
       out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]);
       comma = ",";
     }
diff --git a/compiler/cpp/src/parse/t_list.h b/compiler/cpp/src/parse/t_list.h
index 32dc90b..23a006a 100644
--- a/compiler/cpp/src/parse/t_list.h
+++ b/compiler/cpp/src/parse/t_list.h
@@ -31,6 +31,11 @@
     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 8876858..b5e051e 100644
--- a/compiler/cpp/src/parse/t_map.h
+++ b/compiler/cpp/src/parse/t_map.h
@@ -38,6 +38,12 @@
       "," + 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_set.h b/compiler/cpp/src/parse/t_set.h
index 68a0029..c52421a 100644
--- a/compiler/cpp/src/parse/t_set.h
+++ b/compiler/cpp/src/parse/t_set.h
@@ -31,6 +31,11 @@
     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 ad12677..d296473 100644
--- a/compiler/cpp/src/parse/t_struct.h
+++ b/compiler/cpp/src/parse/t_struct.h
@@ -14,9 +14,6 @@
 #include "t_type.h"
 #include "t_field.h"
 
-// What's worse?  This, or making a src/parse/non_inlined.cc?
-#include "md5.h"
-
 // Forward declare that puppy
 class t_program;
 
@@ -87,69 +84,20 @@
     return rv;
   }
 
-  // Fingerprint should change whenever (and only when)
-  // the encoding via TDenseProtocol changes.
-  static const int fingerprint_len = 16;
-
-  // Call this before trying get_*_fingerprint().
-  void generate_fingerprint() {
-    std::string material = get_fingerprint_material();
-    MD5_CTX ctx;
-    MD5Init(&ctx);
-    MD5Update(&ctx, (unsigned char*)(material.data()), material.size());
-    MD5Final(fingerprint_, &ctx);
-    //std::cout << get_name() << std::endl;
-    //std::cout << material << std::endl;
-    //std::cout << get_ascii_fingerprint() << std::endl << std::endl;
-  }
-
-  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() const {
-    return fingerprint_;
-  }
-
-  std::string get_ascii_fingerprint() const {
-    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) {
-      return '0' + num;
-    } else {
-      return 'A' + num - 10;
+  virtual void generate_fingerprint() {
+    t_type::generate_fingerprint();
+    std::vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members_.begin(); m_iter != members_.end(); ++m_iter) {
+      (**m_iter).get_type()->generate_fingerprint();
     }
   }
 
-  static std::string byte_to_hex(uint8_t byte) {
-    std::string rv;
-    rv += nybble_to_xdigit(byte >> 4);
-    rv += nybble_to_xdigit(byte & 0x0f);
-    return rv;
-  }
-
-
  private:
 
   std::vector<t_field*> members_;
   bool is_xception_;
 
   bool xsd_all_;
-
-  uint8_t fingerprint_[fingerprint_len];
 };
 
 #endif
diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h
index 44f7cc8..0a6fbbc 100644
--- a/compiler/cpp/src/parse/t_type.h
+++ b/compiler/cpp/src/parse/t_type.h
@@ -10,6 +10,9 @@
 #include <string>
 #include "t_doc.h"
 
+// What's worse?  This, or making a src/parse/non_inlined.cc?
+#include "md5.h"
+
 class t_program;
 
 /**
@@ -50,11 +53,69 @@
     return program_;
   }
 
+
   // 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() {
+    std::string material = get_fingerprint_material();
+    MD5_CTX ctx;
+    MD5Init(&ctx);
+    MD5Update(&ctx, (unsigned char*)(material.data()), material.size());
+    MD5Final(fingerprint_, &ctx);
+    //std::cout << get_name() << std::endl;
+    //std::cout << material << std::endl;
+    //std::cout << get_ascii_fingerprint() << std::endl << std::endl;
+  }
+
+  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() const {
+    return fingerprint_;
+  }
+
+  std::string get_ascii_fingerprint() const {
+    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) {
+      return '0' + num;
+    } else {
+      return 'A' + num - 10;
+    }
+  }
+
+  static std::string byte_to_hex(uint8_t byte) {
+    std::string rv;
+    rv += nybble_to_xdigit(byte >> 4);
+    rv += nybble_to_xdigit(byte & 0x0f);
+    return rv;
+  }
+
+
  protected:
   t_type() {}
 
@@ -71,6 +132,7 @@
   t_program* program_;
   std::string name_;
 
+  uint8_t fingerprint_[fingerprint_len];
 };
 
 #endif