blob: ff0e4ba1cdc056b134d9eac9f985aaf4a0c4b89d [file] [log] [blame]
// 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.structural;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
import com.google.common.hash.Hasher;
import java.util.Iterator;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
/** Visitor for hashing a structural item under some assumed type equivalence. */
public class HashingVisitorWithTypeEquivalence extends HashingVisitor {
public static <T> void run(
T item, Hasher hasher, RepresentativeMap map, StructuralMapping<T> accept) {
run(item, hasher, map, (i, visitor) -> visitor.visit(i, accept));
}
public static <T> void run(
T item, Hasher hasher, RepresentativeMap map, HashingAccept<T> hashingAccept) {
hashingAccept.acceptHashing(item, new HashingVisitorWithTypeEquivalence(hasher, map));
}
private final Hasher hash;
private final RepresentativeMap representatives;
private HashingVisitorWithTypeEquivalence(Hasher hash, RepresentativeMap representatives) {
this.hash = hash;
this.representatives = representatives;
}
@Override
public void visitBool(boolean value) {
hash.putBoolean(value);
}
@Override
public void visitInt(int value) {
hash.putInt(value);
}
@Override
public void visitFloat(float value) {
hash.putFloat(value);
}
@Override
public void visitLong(long value) {
hash.putLong(value);
}
@Override
public void visitDouble(double value) {
hash.putDouble(value);
}
@Override
public void visitDexString(DexString string) {
hash.putBytes(string.content);
}
@Override
public void visitDexType(DexType type) {
visitDexString(representatives.getRepresentative(type).getDescriptor());
}
@Override
public <S> void visit(S item, StructuralMapping<S> accept) {
accept.apply(new ItemSpecification<>(item, this));
}
@Override
protected <S> void visitItemIterator(Iterator<S> it, HashingAccept<S> hashingAccept) {
while (it.hasNext()) {
hashingAccept.acceptHashing(it.next(), this);
}
}
@Override
public <S> void visit(S item, BiConsumer<S, Hasher> hasher) {
hasher.accept(item, hash);
}
private static class ItemSpecification<T>
extends StructuralSpecification<T, ItemSpecification<T>> {
private final HashingVisitorWithTypeEquivalence parent;
private final T item;
private ItemSpecification(T item, HashingVisitorWithTypeEquivalence parent) {
this.item = item;
this.parent = parent;
}
@Override
ItemSpecification<T> self() {
return this;
}
@Override
public ItemSpecification<T> withAssert(Predicate<T> predicate) {
assert predicate.test(item);
return this;
}
@Override
public ItemSpecification<T> withBool(Predicate<T> getter) {
parent.visitBool(getter.test(item));
return this;
}
@Override
public ItemSpecification<T> withInt(ToIntFunction<T> getter) {
parent.visitInt(getter.applyAsInt(item));
return this;
}
@Override
public ItemSpecification<T> withLong(ToLongFunction<T> getter) {
parent.visitLong(getter.applyAsLong(item));
return this;
}
@Override
public ItemSpecification<T> withDouble(ToDoubleFunction<T> getter) {
parent.visitDouble(getter.applyAsDouble(item));
return this;
}
@Override
public ItemSpecification<T> withIntArray(Function<T, int[]> getter) {
int[] ints = getter.apply(item);
for (int i = 0; i < ints.length; i++) {
parent.visitInt(ints[i]);
}
return this;
}
@Override
public ItemSpecification<T> withShortArray(Function<T, short[]> getter) {
short[] ints = getter.apply(item);
for (int i = 0; i < ints.length; i++) {
parent.visitInt(ints[i]);
}
return this;
}
@Override
protected <S> ItemSpecification<T> withConditionalCustomItem(
Predicate<T> predicate,
Function<T, S> getter,
CompareToAccept<S> compare,
HashingAccept<S> hasher) {
boolean test = predicate.test(item);
// Always hash the predicate result to distinguish, eg, {null, null} and {null}.
parent.visitBool(test);
if (test) {
hasher.acceptHashing(getter.apply(item), parent);
}
return this;
}
@Override
protected <S> ItemSpecification<T> withCustomItemIterator(
Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) {
parent.visitItemIterator(getter.apply(item), hasher);
return this;
}
@Override
public ItemSpecification<T> withDexReference(Function<T, DexReference> getter) {
parent.visitDexReference(getter.apply(item));
return this;
}
}
}