THRIFT-925. cpp: Add _VALUES_TO_NAMES enum map

git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@1005143 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 f4b0316..55cb4ca 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -198,6 +198,12 @@
   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,
+                                   const char* prefix,
+                                   const char* suffix,
+                                   bool include_values);
+
   // 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);
@@ -441,6 +447,35 @@
     endl;
 }
 
+
+void t_cpp_generator::generate_enum_constant_list(std::ofstream& f,
+                                                  const vector<t_enum_value*>& constants,
+                                                  const char* prefix,
+                                                  const char* suffix,
+                                                  bool include_values) {
+  f << " {" << endl;
+  indent_up();
+
+  vector<t_enum_value*>::const_iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f << "," << endl;
+    }
+    indent(f)
+      << prefix << (*c_iter)->get_name() << suffix;
+    if (include_values && (*c_iter)->has_value()) {
+      f << " = " << (*c_iter)->get_value();
+    }
+  }
+
+  f << endl;
+  indent_down();
+  indent(f) << "};" << endl;
+}
+
 /**
  * Generates code for an enumerated type. In C++, this is essentially the same
  * as the thrift definition itself, using the enum keyword in C++.
@@ -448,6 +483,8 @@
  * @param tenum The enumeration
  */
 void t_cpp_generator::generate_enum(t_enum* tenum) {
+  vector<t_enum_value*> constants = tenum->get_constants();
+
   std::string enum_name = tenum->get_name();
   if (!gen_pure_enums_) {
     enum_name = "type";
@@ -456,28 +493,9 @@
     indent_up();
   }
   f_types_ <<
-    indent() << "enum " << enum_name << " {" << endl;
-  indent_up();
+    indent() << "enum " << enum_name;
 
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  bool first = true;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    if (first) {
-      first = false;
-    } else {
-      f_types_ <<
-        "," << endl;
-    }
-    f_types_ <<
-      indent() << (*c_iter)->get_name();
-    f_types_ <<
-      " = " << (*c_iter)->get_value();
-  }
-
-  indent_down();
-  f_types_ << endl;
-  indent(f_types_) << "};" << endl;
+  generate_enum_constant_list(f_types_, constants, "", "", true);
 
   if (!gen_pure_enums_) {
     indent_down();
@@ -486,6 +504,29 @@
 
   f_types_ << endl;
 
+  /**
+     Generate a character array of enum names for debugging purposes.
+  */
+  std::string prefix = tenum->get_name() + "::";
+  f_types_impl_ <<
+    indent() << "int _k" << tenum->get_name() << "Values[] =";
+  generate_enum_constant_list(f_types_impl_, constants, prefix.c_str(), "", false);
+
+  f_types_impl_ <<
+    indent() << "const char* _k" << tenum->get_name() << "Names[] =";
+  generate_enum_constant_list(f_types_impl_, constants, "\"", "\"", false);
+
+  f_types_ <<
+    indent() << "extern const std::map<int, const char*> _" <<
+    tenum->get_name() << "_VALUES_TO_NAMES;" << endl << endl;
+
+  f_types_impl_ <<
+    indent() << "const std::map<int, const char*> _" << tenum->get_name() <<
+    "_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(" << constants.size() <<
+    ", _k" << 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);
 }
diff --git a/lib/cpp/src/Thrift.h b/lib/cpp/src/Thrift.h
index a8bf2a8..cf766f2 100644
--- a/lib/cpp/src/Thrift.h
+++ b/lib/cpp/src/Thrift.h
@@ -24,6 +24,7 @@
 #include "config.h"
 #endif
 #include <stdio.h>
+#include <assert.h>
 
 #include <sys/types.h>
 #include <netinet/in.h>
@@ -42,6 +43,34 @@
 
 namespace apache { namespace thrift {
 
+class TEnumIterator {
+ public:
+  TEnumIterator(int n,
+                int* enums,
+                const char** names) :
+      ii_(0), n_(n), enums_(enums), names_(names) {
+  }
+
+  int operator ++() {
+    return ++ii_;
+  }
+
+  bool operator !=(const TEnumIterator& end) {
+    assert(end.n_ == -1);
+    return (ii_ != n_);
+  }
+
+  std::pair<int, const char*> operator*() const {
+    return std::make_pair(enums_[ii_], names_[ii_]);
+  }
+
+ private:
+  int ii_;
+  const int n_;
+  int* enums_;
+  const char** names_;
+};
+
 class TOutput {
  public:
   TOutput() : f_(&errorTimeWrapper) {}