| // 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.utils.structural.StructuralItem.CompareToAccept; |
| import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| 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; |
| |
| /** Base class to share most visiting methods */ |
| public abstract class CompareToVisitorBase extends CompareToVisitor { |
| |
| private int order = 0; |
| |
| public final boolean stillEqual() { |
| return order == 0; |
| } |
| |
| public final int getOrder() { |
| return order; |
| } |
| |
| public final void setOrder(int order) { |
| this.order = order; |
| } |
| |
| @Override |
| public final void visitBool(boolean value1, boolean value2) { |
| if (stillEqual()) { |
| setOrder(Boolean.compare(value1, value2)); |
| } |
| } |
| |
| @Override |
| public final void visitInt(int value1, int value2) { |
| if (stillEqual()) { |
| setOrder(Integer.compare(value1, value2)); |
| } |
| } |
| |
| @Override |
| public void visitLong(long value1, long value2) { |
| if (stillEqual()) { |
| setOrder(Long.compare(value1, value2)); |
| } |
| } |
| |
| @Override |
| public void visitFloat(float value1, float value2) { |
| if (stillEqual()) { |
| setOrder(Float.compare(value1, value2)); |
| } |
| } |
| |
| @Override |
| public void visitDouble(double value1, double value2) { |
| if (stillEqual()) { |
| setOrder(Double.compare(value1, value2)); |
| } |
| } |
| |
| @Override |
| public <S> void visitItemIterator( |
| Iterator<S> it1, Iterator<S> it2, CompareToAccept<S> compareToAccept) { |
| while (stillEqual() && it1.hasNext() && it2.hasNext()) { |
| compareToAccept.acceptCompareTo(it1.next(), it2.next(), this); |
| } |
| if (stillEqual()) { |
| visitBool(it1.hasNext(), it2.hasNext()); |
| } |
| } |
| |
| @Override |
| public void visitDexString(DexString string1, DexString string2) { |
| if (stillEqual()) { |
| setOrder(string1.compareTo(string2)); |
| } |
| } |
| |
| @Override |
| public void visitDexReference(DexReference reference1, DexReference reference2) { |
| if (stillEqual()) { |
| visitInt(reference1.referenceTypeOrder(), reference2.referenceTypeOrder()); |
| if (stillEqual()) { |
| assert reference1.getClass() == reference2.getClass(); |
| if (reference1.isDexType()) { |
| visitDexType(reference1.asDexType(), reference2.asDexType()); |
| } else if (reference1.isDexField()) { |
| visitDexField(reference1.asDexField(), reference2.asDexField()); |
| } else { |
| visitDexMethod(reference1.asDexMethod(), reference2.asDexMethod()); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public final <S> void visit(S item1, S item2, Comparator<S> comparator) { |
| if (stillEqual()) { |
| setOrder(comparator.compare(item1, item2)); |
| } |
| } |
| |
| @Override |
| public final <S> void visit(S item1, S item2, StructuralAccept<S> accept) { |
| if (stillEqual()) { |
| accept.apply(new ItemSpecification<>(item1, item2, this)); |
| } |
| } |
| |
| private static class ItemSpecification<T> |
| extends StructuralSpecification<T, ItemSpecification<T>> { |
| |
| private final CompareToVisitorBase parent; |
| private final T item1; |
| private final T item2; |
| |
| private ItemSpecification(T item1, T item2, CompareToVisitorBase parent) { |
| this.item1 = item1; |
| this.item2 = item2; |
| this.parent = parent; |
| } |
| |
| @Override |
| public ItemSpecification<T> withAssert(Predicate<T> predicate) { |
| assert predicate.test(item1); |
| assert predicate.test(item2); |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withBool(Predicate<T> getter) { |
| if (parent.stillEqual()) { |
| parent.visitBool(getter.test(item1), getter.test(item2)); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withInt(ToIntFunction<T> getter) { |
| if (parent.stillEqual()) { |
| parent.visitInt(getter.applyAsInt(item1), getter.applyAsInt(item2)); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withLong(ToLongFunction<T> getter) { |
| if (parent.stillEqual()) { |
| parent.visitLong(getter.applyAsLong(item1), getter.applyAsLong(item2)); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withDouble(ToDoubleFunction<T> getter) { |
| if (parent.stillEqual()) { |
| parent.visitDouble(getter.applyAsDouble(item1), getter.applyAsDouble(item2)); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withIntArray(Function<T, int[]> getter) { |
| if (parent.stillEqual()) { |
| int[] is1 = getter.apply(item1); |
| int[] is2 = getter.apply(item2); |
| int minLength = Math.min(is1.length, is2.length); |
| for (int i = 0; i < minLength && parent.stillEqual(); i++) { |
| parent.visitInt(is1[i], is2[i]); |
| } |
| if (parent.stillEqual()) { |
| parent.visitInt(is1.length, is2.length); |
| } |
| } |
| return this; |
| } |
| |
| @Override |
| public <S> ItemSpecification<T> withConditionalCustomItem( |
| Predicate<T> predicate, |
| Function<T, S> getter, |
| CompareToAccept<S> compare, |
| HashingAccept<S> hasher) { |
| if (parent.stillEqual()) { |
| boolean test1 = predicate.test(item1); |
| boolean test2 = predicate.test(item2); |
| if (test1 && test2) { |
| compare.acceptCompareTo(getter.apply(item1), getter.apply(item2), parent); |
| } else { |
| parent.visitBool(test1, test2); |
| } |
| } |
| return this; |
| } |
| |
| @Override |
| protected <S> ItemSpecification<T> withItemIterator( |
| Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) { |
| if (parent.stillEqual()) { |
| parent.visitItemIterator(getter.apply(item1), getter.apply(item2), compare); |
| } |
| return this; |
| } |
| } |
| } |