AAPT2: Add dominator tree analysis and resource removal

Added dominator tree analysis of resource configurations for each
resource entry to allow deduping of resource entries if:

1. The configuration for the resource entry's value is dominated by
a configuration with an equivalent entry value.

2. All compatible configurations for the entry (those not in conflict
and unrelated by domination with the configuration for the entry's
value) have an equivalent entry value.

Bug: 30051199
Test: make libaapt2_tests && libaapt2_tests
Change-Id: I66468d3014a2d6097a94b039ac1028f9f461c7d3
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index 6858c62..d801621 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -59,14 +59,50 @@
     ConfigDescription& operator=(const ConfigDescription& o);
     ConfigDescription& operator=(ConfigDescription&& o);
 
+    ConfigDescription copyWithoutSdkVersion() const;
+
+    /**
+     * A configuration X dominates another configuration Y, if X has at least the
+     * precedence of Y and X is strictly more general than Y: for any type defined
+     * by X, the same type is defined by Y with a value equal to or, in the case
+     * of ranges, more specific than that of X.
+     *
+     * For example, the configuration 'en-w800dp' dominates 'en-rGB-w1024dp'. It
+     * does not dominate 'fr', 'en-w720dp', or 'mcc001-en-w800dp'.
+     */
+    bool dominates(const ConfigDescription& o) const;
+
+    /**
+     * Returns true if this configuration defines a more important configuration
+     * parameter than o. For example, "en" has higher precedence than "v23",
+     * whereas "en" has the same precedence as "en-v23".
+     */
+    bool hasHigherPrecedenceThan(const ConfigDescription& o) const;
+
+    /**
+     * A configuration conflicts with another configuration if both
+     * configurations define an incompatible configuration parameter. An
+     * incompatible configuration parameter is a non-range, non-density parameter
+     * that is defined in both configurations as a different, non-default value.
+     */
+    bool conflictsWith(const ConfigDescription& o) const;
+
+    /**
+     * A configuration is compatible with another configuration if both
+     * configurations can match a common concrete device configuration and are
+     * unrelated by domination. For example, land-v11 conflicts with port-v21
+     * but is compatible with v21 (both land-v11 and v21 would match en-land-v23).
+     */
+    bool isCompatibleWith(const ConfigDescription& o) const;
+
+    bool matchWithDensity(const ConfigDescription& o) const;
+
     bool operator<(const ConfigDescription& o) const;
     bool operator<=(const ConfigDescription& o) const;
     bool operator==(const ConfigDescription& o) const;
     bool operator!=(const ConfigDescription& o) const;
     bool operator>=(const ConfigDescription& o) const;
     bool operator>(const ConfigDescription& o) const;
-
-    ConfigDescription copyWithoutSdkVersion() const;
 };
 
 inline ConfigDescription::ConfigDescription() {
@@ -103,6 +139,10 @@
     return *this;
 }
 
+inline bool ConfigDescription::matchWithDensity(const ConfigDescription& o) const {
+    return match(o) && (density == 0 || density == o.density);
+}
+
 inline bool ConfigDescription::operator<(const ConfigDescription& o) const {
     return compare(o) < 0;
 }