regex-instance: Fix CompatibilityMatrix::combine to use regex API

combine() is used when a framework compatibility matrix is formed.
Fix it so that the generated FCM contains <regex-instance> as well.

Caveat: In the old code, combine() considered two HAL versions
replacement of each other when their package, interface and
instance are equal. (For example,
if  1.xml states audio@2.0::IDeviceFactory/default
and 2.xml states audio@4.0::IDeviceFactory/default
then generated matrix only requires one of them to exist.
With the introduction of <regex-instanece>, combine() only combines
two versions if the regex pattern *exactly matches*; that is (for
example)

if 1.xml states
camera@1.0::ICamera/legacy/0 AND camera@1.0::ICamera/legacy/[0-9]+
and 2.xml states
camera@3.0::ICamera/legacy/[0-9]+

combine() requires
camera@1.0::ICamera/legacy/0 AND
(camera@1.0::ICamera/legacy[0-9]+ OR camera@3.0::ICamera/legacy[0-9]+)

... because the pattern "legacy[0-9]+" are exactly the same. It will not
combine even if two regex patterns has the same meaning, e.g. when
one of them is "legacy/[0-9]{1,}".

Bug: 73738616
Test: libvintf_test
Test: vintf_object_test
Test: vts_treble_vintf_test

Change-Id: Ie34f0f1ccab1e942f6aa9e9e40aa20140f220844
Merged-In: Ie34f0f1ccab1e942f6aa9e9e40aa20140f220844
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 840899d..88ecd26 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -82,19 +82,38 @@
 // - Remove interface/instance from existingHal, and return a new MatrixHal (that is added
 //   to "this") that contains only interface/instance.
 MatrixHal* CompatibilityMatrix::splitInstance(MatrixHal* existingHal, const std::string& interface,
-                                              const std::string& instance) {
-    if (!existingHal->hasInstance(interface, instance)) {
+                                              const std::string& instanceOrPattern, bool isRegex) {
+    bool found = false;
+    bool foundOthers = false;
+    existingHal->forEachInstance([&](const auto& matrixInstance) {
+        bool interfaceMatch = matrixInstance.interface() == interface;
+        bool instanceMatch = false;
+        if (matrixInstance.isRegex() && isRegex) {
+            instanceMatch = (matrixInstance.regexPattern() == instanceOrPattern);
+        } else if (!matrixInstance.isRegex() && !isRegex) {
+            instanceMatch = (matrixInstance.exactInstance() == instanceOrPattern);
+        }
+
+        bool match = interfaceMatch && instanceMatch;
+
+        found |= match;
+        foundOthers |= (!match);
+
+        return !found || !foundOthers;
+    });
+
+    if (!found) {
         return nullptr;
     }
 
-    if (existingHal->hasOnlyInstance(interface, instance)) {
+    if (!foundOthers) {
         return existingHal;
     }
 
-    existingHal->removeInstance(interface, instance);
+    existingHal->removeInstance(interface, instanceOrPattern, isRegex);
     MatrixHal copy = *existingHal;
     copy.clearInstances();
-    copy.insertInstance(interface, instance);
+    copy.insertInstance(interface, instanceOrPattern, isRegex);
 
     return addInternal(std::move(copy));
 }
@@ -114,16 +133,22 @@
         MatrixHal& halToAdd = pair.second;
 
         std::set<std::pair<std::string, std::string>> insertedInstances;
+        std::set<std::pair<std::string, std::string>> insertedRegex;
         auto existingHals = getHals(name);
 
         halToAdd.forEachInstance([&](const std::vector<VersionRange>& versionRanges,
-                                     const std::string& interface, const std::string& instance,
-                                     bool /* isRegex */) {
+                                     const std::string& interface,
+                                     const std::string& instanceOrPattern, bool isRegex) {
             for (auto* existingHal : existingHals) {
-                MatrixHal* splitInstance = this->splitInstance(existingHal, interface, instance);
+                MatrixHal* splitInstance =
+                    this->splitInstance(existingHal, interface, instanceOrPattern, isRegex);
                 if (splitInstance != nullptr) {
                     splitInstance->insertVersionRanges(versionRanges);
-                    insertedInstances.insert(std::make_pair(interface, instance));
+                    if (isRegex) {
+                        insertedRegex.insert(std::make_pair(interface, instanceOrPattern));
+                    } else {
+                        insertedInstances.insert(std::make_pair(interface, instanceOrPattern));
+                    }
                 }
             }
             return true;
@@ -131,7 +156,10 @@
 
         // Add the remaining instances.
         for (const auto& pair : insertedInstances) {
-            halToAdd.removeInstance(pair.first, pair.second);
+            halToAdd.removeInstance(pair.first, pair.second, false /* isRegex */);
+        }
+        for (const auto& pair : insertedRegex) {
+            halToAdd.removeInstance(pair.first, pair.second, true /* isRegex */);
         }
 
         if (halToAdd.instancesCount() > 0) {