Merge "forward declare header string definitions" am: 04b5a124bc
am: 988958c08d

Change-Id: I1752cd91c0eca84e718dc16832ccb1e2f63b0ac7
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 00d394a..8126bfa 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -800,6 +800,27 @@
     out << "static inline std::string toString("
         << getCppArgumentType()
         << (mFields->empty() ? "" : " o")
+        << ");\n";
+
+    if (canCheckEquality()) {
+        out << "static inline bool operator==("
+            << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs);\n";
+
+        out << "static inline bool operator!=("
+            << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs);\n";
+    } else {
+        out << "// operator== and operator!= are not generated for " << localName() << "\n";
+    }
+
+    out.endl();
+}
+
+void CompoundType::emitPackageTypeHeaderDefinitions(Formatter& out) const {
+    Scope::emitPackageTypeHeaderDefinitions(out);
+
+    out << "static inline std::string toString("
+        << getCppArgumentType()
+        << (mFields->empty() ? "" : " o")
         << ") ";
 
     out.block([&] {
@@ -915,7 +936,7 @@
         }).endl().endl();
 
         out << "static inline bool operator!=("
-            << getCppArgumentType() << " lhs," << getCppArgumentType() << " rhs)";
+            << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs)";
         out.block([&] {
             out << "return !(lhs == rhs);\n";
         }).endl().endl();
diff --git a/CompoundType.h b/CompoundType.h
index ab29479..4f7cf57 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -125,6 +125,7 @@
     void emitTypeDeclarations(Formatter& out) const override;
     void emitTypeForwardDeclaration(Formatter& out) const override;
     void emitPackageTypeDeclarations(Formatter& out) const override;
+    void emitPackageTypeHeaderDefinitions(Formatter& out) const override;
     void emitPackageHwDeclarations(Formatter& out) const override;
 
     void emitTypeDefinitions(Formatter& out, const std::string& prefix) const override;
diff --git a/EnumType.cpp b/EnumType.cpp
index e0057ae..e84493f 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -281,7 +281,7 @@
         elementCount += type->mValues.size();
     }
 
-    out << "template<> struct hidl_enum_range<" << getCppStackType() << ">\n";
+    out << "template<> struct hidl_enum_range<" << getCppStackType() << "> ";
     out.block([&] {
         out << "const " << getCppStackType() << "* begin() { return static_begin(); }\n";
         out << "const " << getCppStackType() << "* end() { return begin() + " << elementCount
@@ -300,8 +300,8 @@
                 }
             }) << ";\n";
             out << "return &kVals[0];\n";
-        });
-    }) << ";\n\n";
+        }).endl();
+    }) << ";\n";
 }
 
 void EnumType::emitEnumBitwiseOperator(
@@ -347,7 +347,7 @@
         out << ");\n";
     });
 
-    out << "}\n\n";
+    out << "}\n";
 }
 
 void EnumType::emitBitFieldBitwiseAssignmentOperator(
@@ -366,7 +366,7 @@
         out << "return v;\n";
     });
 
-    out << "}\n\n";
+    out << "}\n";
 }
 
 void EnumType::emitGlobalTypeDeclarations(Formatter& out) const {
@@ -376,10 +376,15 @@
     emitIteratorDeclaration(out);
 
     out << "}  // namespace hardware\n";
-    out << "}  // namespace android\n";
+    out << "}  // namespace android\n\n";
 }
 
 void EnumType::emitPackageTypeDeclarations(Formatter& out) const {
+    out << "template<typename>\n"
+        << "static inline std::string toString(" << resolveToScalarType()->getCppArgumentType()
+        << " o);\n";
+    out << "static inline std::string toString(" << getCppArgumentType() << " o);\n\n";
+
     emitEnumBitwiseOperator(out, true  /* lhsIsEnum */, true  /* rhsIsEnum */, "|");
     emitEnumBitwiseOperator(out, false /* lhsIsEnum */, true  /* rhsIsEnum */, "|");
     emitEnumBitwiseOperator(out, true  /* lhsIsEnum */, false /* rhsIsEnum */, "|");
@@ -390,12 +395,13 @@
     emitBitFieldBitwiseAssignmentOperator(out, "|");
     emitBitFieldBitwiseAssignmentOperator(out, "&");
 
+    out.endl();
+}
+
+void EnumType::emitPackageTypeHeaderDefinitions(Formatter& out) const {
     const ScalarType *scalarType = mStorageType->resolveToScalarType();
     CHECK(scalarType != nullptr);
 
-    out << "template<typename>\n"
-        << "static inline std::string toString(" << resolveToScalarType()->getCppArgumentType()
-        << " o);\n";
     out << "template<>\n"
         << "inline std::string toString<" << getCppStackType() << ">("
         << scalarType->getCppArgumentType() << " o) ";
diff --git a/EnumType.h b/EnumType.h
index 2854c25..45e20f2 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -93,6 +93,7 @@
     void emitTypeForwardDeclaration(Formatter& out) const override;
     void emitGlobalTypeDeclarations(Formatter& out) const override;
     void emitPackageTypeDeclarations(Formatter& out) const override;
+    void emitPackageTypeHeaderDefinitions(Formatter& out) const override;
 
     void emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const override;
 
diff --git a/Interface.cpp b/Interface.cpp
index dae7535..117dd65 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -849,6 +849,12 @@
 void Interface::emitPackageTypeDeclarations(Formatter& out) const {
     Scope::emitPackageTypeDeclarations(out);
 
+    out << "static inline std::string toString(" << getCppArgumentType() << " o);\n\n";
+}
+
+void Interface::emitPackageTypeHeaderDefinitions(Formatter& out) const {
+    Scope::emitPackageTypeHeaderDefinitions(out);
+
     out << "static inline std::string toString(" << getCppArgumentType() << " o) ";
 
     out.block([&] {
diff --git a/Interface.h b/Interface.h
index 2604c77..6ad09ff 100644
--- a/Interface.h
+++ b/Interface.h
@@ -113,6 +113,7 @@
             ErrorMode mode) const override;
 
     void emitPackageTypeDeclarations(Formatter& out) const override;
+    void emitPackageTypeHeaderDefinitions(Formatter& out) const override;
     void emitTypeDefinitions(Formatter& out, const std::string& prefix) const override;
 
     void getAlignmentAndSize(size_t* align, size_t* size) const override;
diff --git a/Scope.cpp b/Scope.cpp
index 5e61929..d4953aa 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -177,6 +177,12 @@
     }
 }
 
+void Scope::emitPackageTypeHeaderDefinitions(Formatter& out) const {
+    for (const Type* type : mTypes) {
+        type->emitPackageTypeHeaderDefinitions(out);
+    }
+}
+
 void Scope::emitPackageHwDeclarations(Formatter& out) const {
     for (const Type* type : mTypes) {
         type->emitPackageHwDeclarations(out);
diff --git a/Scope.h b/Scope.h
index cfef50e..bf7d1cd 100644
--- a/Scope.h
+++ b/Scope.h
@@ -66,6 +66,7 @@
     void emitTypeDeclarations(Formatter& out) const override;
     void emitGlobalTypeDeclarations(Formatter& out) const override;
     void emitPackageTypeDeclarations(Formatter& out) const override;
+    void emitPackageTypeHeaderDefinitions(Formatter& out) const override;
     void emitPackageHwDeclarations(Formatter& out) const override;
 
     void emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const override;
diff --git a/Type.cpp b/Type.cpp
index 6dba5c9..c749d85 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -623,6 +623,8 @@
 
 void Type::emitPackageTypeDeclarations(Formatter&) const {}
 
+void Type::emitPackageTypeHeaderDefinitions(Formatter&) const {}
+
 void Type::emitPackageHwDeclarations(Formatter&) const {}
 
 void Type::emitTypeDefinitions(Formatter&, const std::string&) const {}
diff --git a/Type.h b/Type.h
index 0cac877..81f2a2e 100644
--- a/Type.h
+++ b/Type.h
@@ -272,11 +272,20 @@
     virtual void emitTypeForwardDeclaration(Formatter& out) const;
 
     // Emit any declarations pertaining to this type that have to be
-    // at global scope, i.e. enum class operators.
+    // directly in a namespace, i.e. enum class operators.
     // For android.hardware.foo@1.0::*, this will be in namespace
     // android::hardware::foo::V1_0
     virtual void emitPackageTypeDeclarations(Formatter& out) const;
 
+    // Emit any definitions pertaining to this type that have to be
+    // directly in a namespace. Typically, these are things that are only
+    // used for a small subset of types, so by putting them in the header,
+    // the space cost is moved to the small number of clients that use the
+    // feature.
+    // For android.hardware.foo@1.0::*, this will be in namespace
+    // android::hardware::foo::V1_0
+    virtual void emitPackageTypeHeaderDefinitions(Formatter& out) const;
+
     // Emit any declarations pertaining to this type that have to be
     // at global scope for transport, e.g. read/writeEmbeddedTo/FromParcel
     // For android.hardware.foo@1.0::*, this will be in namespace
diff --git a/generateCpp.cpp b/generateCpp.cpp
index a98378c..adcf489 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -337,11 +337,22 @@
         out << "};\n\n";
     }
 
+    out << "//\n";
+    out << "// type declarations for package\n";
+    out << "//\n\n";
     mRootScope.emitPackageTypeDeclarations(out);
+    out << "//\n";
+    out << "// type header definitions for package\n";
+    out << "//\n\n";
+    mRootScope.emitPackageTypeHeaderDefinitions(out);
 
     out << "\n";
     enterLeaveNamespace(out, false /* enter */);
+    out << "\n";
 
+    out << "//\n";
+    out << "// global type declarations for package\n";
+    out << "//\n\n";
     mRootScope.emitGlobalTypeDeclarations(out);
 
     out << "\n#endif  // " << guard << "\n";