protozero: Improve runtime of cppgen enum/type gen

Also track seen enums/types in sets to avoid quadratic runtime of
lookup during recursion.

Bug: chromium:1017699
Change-Id: I52494c0d4e17abb8de49e052272481df8d17f33f
diff --git a/src/protozero/protoc_plugin/cppgen_plugin.cc b/src/protozero/protoc_plugin/cppgen_plugin.cc
index c4a6b0f..b396a67 100644
--- a/src/protozero/protoc_plugin/cppgen_plugin.cc
+++ b/src/protozero/protoc_plugin/cppgen_plugin.cc
@@ -72,13 +72,6 @@
   return full_type;
 }
 
-template <typename Container, typename Value>
-bool Contains(const Container& container, const Value& value) {
-  using std::begin;
-  using std::end;
-  return std::find(begin(container), end(container), value) != end(container);
-}
-
 class CppObjGenerator : public ::google::protobuf::compiler::CodeGenerator {
  public:
   CppObjGenerator();
@@ -178,15 +171,21 @@
 
   // Compute all nested types to generate forward declarations later.
 
+  std::set<const Descriptor*> all_types_seen;  // All deps
+  std::set<const EnumDescriptor*> all_enums_seen;
+
+  // We track the types additionally in vectors to guarantee a stable order in
+  // the generated output.
   std::vector<const Descriptor*> local_types;  // Cur .proto file only.
   std::vector<const Descriptor*> all_types;    // All deps
   std::vector<const EnumDescriptor*> local_enums;
   std::vector<const EnumDescriptor*> all_enums;
 
-  auto add_enum = [&local_enums, &all_enums,
+  auto add_enum = [&local_enums, &all_enums, &all_enums_seen,
                    &file](const EnumDescriptor* enum_desc) {
-    if (Contains(all_enums, enum_desc))
+    if (all_enums_seen.count(enum_desc))
       return;
+    all_enums_seen.insert(enum_desc);
     all_enums.push_back(enum_desc);
     if (enum_desc->file() == file)
       local_enums.push_back(enum_desc);
@@ -199,8 +198,9 @@
   while (!recursion_stack.empty()) {
     const Descriptor* msg = recursion_stack.top();
     recursion_stack.pop();
-    if (Contains(all_types, msg))
+    if (all_types_seen.count(msg))
       continue;
+    all_types_seen.insert(msg);
     all_types.push_back(msg);
     if (msg->file() == file)
       local_types.push_back(msg);