Add enum iteration to HIDL.

e.x.:
for (const auto v : hidl_enum_iterator<Foo>) {
    ...
}

Going with exposing an iterator interface completely
in the header because:
- this should only increase code size if it is used
- we want to be able to change this interface/implementation
  to be more efficient or to add new features without having
  to update all prebuilts

Bug: 68715899
Test: hidl_test
Change-Id: I613d5c71ebf3f58c5c92338888ad90172896178d
diff --git a/EnumType.cpp b/EnumType.cpp
index 0095165..98aa7c1 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -283,6 +283,35 @@
     out << "enum class " << localName() << " : " << storageType << ";\n";
 }
 
+void EnumType::emitIteratorDeclaration(Formatter& out) const {
+    size_t elementCount = 0;
+    for (const auto* type : typeChain()) {
+        elementCount += type->mValues.size();
+    }
+
+    out << "template<> struct hidl_enum_iterator<" << getCppStackType() << ">\n";
+    out.block([&] {
+        out << "const " << getCppStackType() << "* begin() { return static_begin(); }\n";
+        out << "const " << getCppStackType() << "* end() { return begin() + " << elementCount
+            << "; }\n";
+        out << "private:\n";
+        out << "static const " << getCppStackType() << "* static_begin() ";
+        out.block([&] {
+            out << "static const " << getCppStackType() << " kVals[" << elementCount << "] ";
+            out.block([&] {
+                auto enumerators = typeChain();
+                std::reverse(enumerators.begin(), enumerators.end());
+                for (const auto* type : enumerators) {
+                    for (const auto* enumValue : type->mValues) {
+                        out << fullName() << "::" << enumValue->name() << ",\n";
+                    }
+                }
+            }) << ";\n";
+            out << "return &kVals[0];\n";
+        });
+    }) << ";\n\n";
+}
+
 void EnumType::emitEnumBitwiseOperator(
         Formatter &out,
         bool lhsIsEnum,
@@ -348,6 +377,16 @@
     out << "}\n\n";
 }
 
+void EnumType::emitGlobalTypeDeclarations(Formatter& out) const {
+    out << "namespace android {\n";
+    out << "namespace hardware {\n";
+
+    emitIteratorDeclaration(out);
+
+    out << "}  // namespace hardware\n";
+    out << "}  // namespace android\n";
+}
+
 status_t EnumType::emitPackageTypeDeclarations(Formatter& out) const {
     emitEnumBitwiseOperator(out, true  /* lhsIsEnum */, true  /* rhsIsEnum */, "|");
     emitEnumBitwiseOperator(out, false /* lhsIsEnum */, true  /* rhsIsEnum */, "|");
diff --git a/EnumType.h b/EnumType.h
index c6cbbde..7e7a6dc 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -92,6 +92,7 @@
 
     status_t emitTypeDeclarations(Formatter &out) const override;
     void emitTypeForwardDeclaration(Formatter& out) const override;
+    void emitGlobalTypeDeclarations(Formatter& out) const override;
     status_t emitPackageTypeDeclarations(Formatter& out) const override;
     status_t emitTypeDefinitions(Formatter& out, const std::string& prefix) const override;
 
@@ -119,6 +120,9 @@
 
     const Annotation *findExportAnnotation() const;
 
+    void emitIteratorDeclaration(Formatter& out) const;
+    void emitIteratorDefinitions(Formatter& out) const;
+
     void emitEnumBitwiseOperator(
             Formatter &out,
             bool lhsIsEnum,
diff --git a/test/hidl_test/hidl_test_client.cpp b/test/hidl_test/hidl_test_client.cpp
index 797d914..fbb70fa 100644
--- a/test/hidl_test/hidl_test_client.cpp
+++ b/test/hidl_test/hidl_test_client.cpp
@@ -134,6 +134,9 @@
 using std::to_string;
 
 template <typename T>
+using hidl_enum_iterator = ::android::hardware::hidl_enum_iterator<T>;
+
+template <typename T>
 static inline ::testing::AssertionResult isOk(const ::android::hardware::Return<T> &ret) {
     return ret.isOk()
         ? (::testing::AssertionSuccess() << ret.description())
@@ -459,6 +462,38 @@
     EXPECT_NE(nullptr, IFoo::getService("\n", true /* getStub */).get());
 }
 
+TEST_F(HidlTest, EnumIteratorTest) {
+    using Empty = ::android::hardware::tests::foo::V1_0::EnumIterators::Empty;
+    using Grandchild = ::android::hardware::tests::foo::V1_0::EnumIterators::Grandchild;
+    using SkipsValues = ::android::hardware::tests::foo::V1_0::EnumIterators::SkipsValues;
+    using MultipleValues = ::android::hardware::tests::foo::V1_0::EnumIterators::MultipleValues;
+
+    for (const auto value : hidl_enum_iterator<Empty>()) {
+        (void)value;
+        EXPECT_TRUE(false) << "Empty iterator should not iterate";
+    }
+
+    auto it1 = hidl_enum_iterator<Grandchild>().begin();
+    EXPECT_EQ(Grandchild::A, *it1++);
+    EXPECT_EQ(Grandchild::B, *it1++);
+    EXPECT_EQ(hidl_enum_iterator<Grandchild>().end(), it1);
+
+    auto it2 = hidl_enum_iterator<SkipsValues>().begin();
+    EXPECT_EQ(SkipsValues::A, *it2++);
+    EXPECT_EQ(SkipsValues::B, *it2++);
+    EXPECT_EQ(SkipsValues::C, *it2++);
+    EXPECT_EQ(SkipsValues::D, *it2++);
+    EXPECT_EQ(SkipsValues::E, *it2++);
+    EXPECT_EQ(hidl_enum_iterator<SkipsValues>().end(), it2);
+
+    auto it3 = hidl_enum_iterator<MultipleValues>().begin();
+    EXPECT_EQ(MultipleValues::A, *it3++);
+    EXPECT_EQ(MultipleValues::B, *it3++);
+    EXPECT_EQ(MultipleValues::C, *it3++);
+    EXPECT_EQ(MultipleValues::D, *it3++);
+    EXPECT_EQ(hidl_enum_iterator<MultipleValues>().end(), it3);
+}
+
 TEST_F(HidlTest, EnumToStringTest) {
     using namespace std::string_literals;
     using ::android::hardware::tests::foo::V1_0::toString;