Introduce a bidirectional one-to-many map for class initializer merging
The bidirectional one-to-many map will be used to represent the original method signatures for horizontally merged class initializers (where many are merged into a single).
This CL also adds a few extra methods for mutation the existing many-to-one collections.
Change-Id: I3f92f6b5f989feeac65979d27d13fb198f08c023
diff --git a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
index 586e257..8ea4e1f 100644
--- a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
@@ -25,7 +24,7 @@
super(
ImmutableMap.of(),
ImmutableMap.of(),
- new BidirectionalManyToOneRepresentativeHashMap<>(),
+ new EmptyBidirectionalOneToOneMap<>(),
new EmptyBidirectionalOneToOneMap<>(),
appView.graphLens(),
appView.dexItemFactory());
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java
index 599fddd..c217e91 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java
@@ -27,6 +27,12 @@
}
@Override
+ public void clear() {
+ backing.clear();
+ inverse.clear();
+ }
+
+ @Override
public boolean containsKey(K key) {
return backing.containsKey(key);
}
@@ -101,6 +107,11 @@
}
@Override
+ public void removeAll(Iterable<K> keys) {
+ keys.forEach(this::remove);
+ }
+
+ @Override
public Set<K> removeValue(V value) {
Set<K> keys = inverse.remove(value);
if (keys == null) {
@@ -121,6 +132,11 @@
}
@Override
+ public void put(Iterable<K> keys, V value) {
+ keys.forEach(key -> put(key, value));
+ }
+
+ @Override
public Set<V> values() {
return inverse.keySet();
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java
index 8126051..15e1bec 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java
@@ -16,6 +16,12 @@
private final Map<V, K> representatives = new IdentityHashMap<>();
@Override
+ public void clear() {
+ super.clear();
+ representatives.clear();
+ }
+
+ @Override
public K removeRepresentativeFor(V value) {
return representatives.remove(value);
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyHashMap.java
new file mode 100644
index 0000000..552a406
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyHashMap.java
@@ -0,0 +1,137 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class BidirectionalOneToManyHashMap<K, V> implements MutableBidirectionalOneToManyMap<K, V> {
+
+ private final Map<K, Set<V>> backing;
+ private final Map<V, K> inverse;
+
+ public BidirectionalOneToManyHashMap() {
+ this(new IdentityHashMap<>(), new IdentityHashMap<>());
+ }
+
+ private BidirectionalOneToManyHashMap(Map<K, Set<V>> backing, Map<V, K> inverse) {
+ this.backing = backing;
+ this.inverse = inverse;
+ }
+
+ @Override
+ public void clear() {
+ backing.clear();
+ inverse.clear();
+ }
+
+ @Override
+ public boolean containsKey(K key) {
+ return backing.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(V value) {
+ return inverse.containsKey(value);
+ }
+
+ @Override
+ public void forEach(BiConsumer<? super K, ? super V> consumer) {
+ backing.forEach((key, values) -> values.forEach(value -> consumer.accept(key, value)));
+ }
+
+ @Override
+ public void forEachKey(Consumer<? super K> consumer) {
+ backing.keySet().forEach(consumer);
+ }
+
+ @Override
+ public void forEachOneToManyMapping(BiConsumer<K, Set<V>> consumer) {
+ backing.forEach(consumer);
+ }
+
+ @Override
+ public Set<V> get(Object key) {
+ return backing.get(key);
+ }
+
+ @Override
+ public Set<V> getOrDefault(Object key, Set<V> value) {
+ return backing.getOrDefault(key, value);
+ }
+
+ @Override
+ public K getKey(V value) {
+ return inverse.get(value);
+ }
+
+ @Override
+ public Set<K> getKeys(V value) {
+ K key = inverse.get(value);
+ return key != null ? Collections.singleton(key) : Collections.emptySet();
+ }
+
+ @Override
+ public Set<V> getValues(K key) {
+ return getOrDefault(key, Collections.emptySet());
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return backing.isEmpty();
+ }
+
+ public Set<K> keySet() {
+ return backing.keySet();
+ }
+
+ @Override
+ public Set<V> remove(K key) {
+ Set<V> values = backing.remove(key);
+ if (values == null) {
+ return Collections.emptySet();
+ }
+ for (V value : values) {
+ K removedKey = inverse.remove(value);
+ assert removedKey == key;
+ }
+ return values;
+ }
+
+ @Override
+ public void removeAll(Iterable<K> keys) {
+ keys.forEach(this::remove);
+ }
+
+ @Override
+ public K removeValue(V value) {
+ K key = inverse.remove(value);
+ if (key != null) {
+ Set<V> values = backing.get(key);
+ values.remove(value);
+ if (values.isEmpty()) {
+ backing.remove(key);
+ }
+ }
+ return key;
+ }
+
+ @Override
+ public void put(K key, V value) {
+ removeValue(value);
+ backing.computeIfAbsent(key, ignore -> new LinkedHashSet<>()).add(value);
+ inverse.put(value, key);
+ }
+
+ @Override
+ public void put(K key, Set<V> values) {
+ values.forEach(value -> put(key, value));
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyMap.java
new file mode 100644
index 0000000..addb1ed
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyMap.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+/**
+ * Interface that accommodates many-to-many mappings.
+ *
+ * <p>This interface inherits from {@link BidirectionalManyToManyMap} to allow implementing
+ * many-to-many mappings using many-to-one mappings.
+ */
+public interface BidirectionalOneToManyMap<K, V> extends BidirectionalManyToManyMap<K, V> {
+
+ void forEachOneToManyMapping(BiConsumer<K, Set<V>> consumer);
+
+ Set<V> get(Object key);
+
+ Set<V> getOrDefault(Object key, Set<V> defaultValue);
+
+ K getKey(V value);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeHashMap.java
new file mode 100644
index 0000000..93562e7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeHashMap.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import com.google.common.collect.Streams;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class BidirectionalOneToManyRepresentativeHashMap<K, V>
+ extends BidirectionalOneToManyHashMap<K, V>
+ implements MutableBidirectionalOneToManyRepresentativeMap<K, V> {
+
+ private final Map<K, V> representatives = new IdentityHashMap<>();
+
+ @Override
+ public void clear() {
+ super.clear();
+ representatives.clear();
+ }
+
+ @Override
+ public K getRepresentativeKey(V value) {
+ return getKey(value);
+ }
+
+ @Override
+ public V getRepresentativeValue(K key) {
+ Set<V> values = getValues(key);
+ if (!values.isEmpty()) {
+ return values.size() == 1 ? values.iterator().next() : representatives.get(key);
+ }
+ return null;
+ }
+
+ @Override
+ public Set<V> remove(K key) {
+ Set<V> values = super.remove(key);
+ removeRepresentativeFor(key);
+ return values;
+ }
+
+ @Override
+ public void removeAll(Iterable<K> keys) {
+ super.removeAll(keys);
+ assert Streams.stream(keys).noneMatch(representatives::containsKey);
+ }
+
+ @Override
+ public V removeRepresentativeFor(K key) {
+ return representatives.remove(key);
+ }
+
+ @Override
+ public K removeValue(V value) {
+ K key = super.removeValue(value);
+ if (getValues(key).size() <= 1 || getRepresentativeValue(key) == value) {
+ removeRepresentativeFor(key);
+ }
+ return key;
+ }
+
+ @Override
+ public void setRepresentative(K key, V representative) {
+ assert getValues(key).size() > 1;
+ assert getValues(key).contains(representative);
+ representatives.put(key, representative);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeMap.java
new file mode 100644
index 0000000..557173c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeMap.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+/**
+ * Interface that accommodates one-to-many mappings.
+ *
+ * <p>This interface implicitly adds a "representative" for each many-to-one mapping by inheriting
+ * from {@link BidirectionalManyToManyRepresentativeMap}.
+ */
+public interface BidirectionalOneToManyRepresentativeMap<K, V>
+ extends BidirectionalOneToManyMap<K, V>, BidirectionalManyToManyRepresentativeMap<K, V> {}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneMap.java
index 3e1a198..7953e91 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneMap.java
@@ -6,17 +6,18 @@
import java.util.Set;
-/**
- * Interface that accommodates many-to-one mappings.
- *
- * <p>This interface inherits from {@link BidirectionalManyToManyMap} to allow implementing
- * many-to-many mappings using many-to-one mappings.
- */
+/** Interface that provides mutable access to the implementation of a many-to-one mapping. */
public interface MutableBidirectionalManyToOneMap<K, V> extends BidirectionalManyToOneMap<K, V> {
+ void clear();
+
void put(K key, V value);
+ void put(Iterable<K> key, V value);
+
V remove(K key);
+ void removeAll(Iterable<K> keys);
+
Set<K> removeValue(V value);
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneRepresentativeMap.java
index defacae..24f91ac 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneRepresentativeMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneRepresentativeMap.java
@@ -4,12 +4,7 @@
package com.android.tools.r8.utils.collections;
-/**
- * Interface that accommodates many-to-one mappings.
- *
- * <p>This interface implicitly adds a "representative" for each many-to-one mapping by inheriting
- * from {@link BidirectionalManyToManyRepresentativeMap}.
- */
+/** Interface that provides mutable access to the implementation of a many-to-one mapping. */
public interface MutableBidirectionalManyToOneRepresentativeMap<K, V>
extends MutableBidirectionalManyToOneMap<K, V>, BidirectionalManyToOneRepresentativeMap<K, V> {
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyMap.java
new file mode 100644
index 0000000..1b9d464
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyMap.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Set;
+
+/** Interface that provides mutable access to the implementation of a one-to-many mapping. */
+public interface MutableBidirectionalOneToManyMap<K, V> extends BidirectionalOneToManyMap<K, V> {
+
+ void clear();
+
+ Set<V> remove(K key);
+
+ void removeAll(Iterable<K> keys);
+
+ K removeValue(V value);
+
+ void put(K key, V value);
+
+ void put(K key, Set<V> values);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyRepresentativeMap.java
new file mode 100644
index 0000000..987eb6f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyRepresentativeMap.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+/** Interface that provides mutable access to the implementation of a one-to-many mapping. */
+public interface MutableBidirectionalOneToManyRepresentativeMap<K, V>
+ extends MutableBidirectionalOneToManyMap<K, V>, BidirectionalOneToManyRepresentativeMap<K, V> {
+
+ V removeRepresentativeFor(K key);
+
+ void setRepresentative(K key, V representative);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToOneMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToOneMap.java
index 08ceee8..5e5f469 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToOneMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToOneMap.java
@@ -4,12 +4,7 @@
package com.android.tools.r8.utils.collections;
-/**
- * Interface that accommodates one-to-one mappings.
- *
- * <p>This interface inherits from {@link BidirectionalManyToManyRepresentativeMap} to allow
- * implementing many-to-many mappings using one-to-one mappings.
- */
+/** Interface that provides mutable access to the implementation of a one-to-one mapping. */
public interface MutableBidirectionalOneToOneMap<K, V> extends BidirectionalOneToOneMap<K, V> {
V put(K key, V value);