| // 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 static boolean DEBUG = false; |
| |
| // Helper to debug insert a breakpoint on order values. |
| public static int debug(int order) { |
| if (DEBUG && order != 0) { |
| return order; |
| } |
| return order; |
| } |
| |
| @Override |
| public final int visitBool(boolean value1, boolean value2) { |
| return debug(Boolean.compare(value1, value2)); |
| } |
| |
| @Override |
| public final int visitInt(int value1, int value2) { |
| return debug(Integer.compare(value1, value2)); |
| } |
| |
| @Override |
| public int visitLong(long value1, long value2) { |
| return debug(Long.compare(value1, value2)); |
| } |
| |
| @Override |
| public int visitFloat(float value1, float value2) { |
| return debug(Float.compare(value1, value2)); |
| } |
| |
| @Override |
| public int visitDouble(double value1, double value2) { |
| return debug(Double.compare(value1, value2)); |
| } |
| |
| @Override |
| public <S> int visitItemIterator( |
| Iterator<S> it1, Iterator<S> it2, CompareToAccept<S> compareToAccept) { |
| int order = 0; |
| while (order == 0 && it1.hasNext() && it2.hasNext()) { |
| order = compareToAccept.acceptCompareTo(it1.next(), it2.next(), this); |
| } |
| if (order == 0) { |
| order = visitBool(it1.hasNext(), it2.hasNext()); |
| } |
| return debug(order); |
| } |
| |
| @Override |
| public int visitDexString(DexString string1, DexString string2) { |
| return debug(string1.compareTo(string2)); |
| } |
| |
| @Override |
| public int visitDexReference(DexReference reference1, DexReference reference2) { |
| int order = visitInt(reference1.referenceTypeOrder(), reference2.referenceTypeOrder()); |
| if (order == 0) { |
| assert reference1.getClass() == reference2.getClass(); |
| if (reference1.isDexType()) { |
| order = visitDexType(reference1.asDexType(), reference2.asDexType()); |
| } else if (reference1.isDexField()) { |
| order = visitDexField(reference1.asDexField(), reference2.asDexField()); |
| } else { |
| order = visitDexMethod(reference1.asDexMethod(), reference2.asDexMethod()); |
| } |
| } |
| return debug(order); |
| } |
| |
| @Override |
| public final <S> int visit(S item1, S item2, Comparator<S> comparator) { |
| return debug(comparator.compare(item1, item2)); |
| } |
| |
| @Override |
| public final <S> int visit(S item1, S item2, StructuralMapping<S> accept) { |
| ItemSpecification<S> itemVisitor = new ItemSpecification<>(item1, item2, this); |
| accept.apply(itemVisitor); |
| return debug(itemVisitor.order); |
| } |
| |
| private static class ItemSpecification<T> |
| extends StructuralSpecification<T, ItemSpecification<T>> { |
| |
| private final CompareToVisitorBase parent; |
| private final T item1; |
| private final T item2; |
| private int order = 0; |
| |
| private ItemSpecification(T item1, T item2, CompareToVisitorBase parent) { |
| this.item1 = item1; |
| this.item2 = item2; |
| this.parent = parent; |
| } |
| |
| @Override |
| ItemSpecification<T> self() { |
| return this; |
| } |
| |
| @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 (order == 0) { |
| order = parent.visitBool(getter.test(item1), getter.test(item2)); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withInt(ToIntFunction<T> getter) { |
| if (order == 0) { |
| order = parent.visitInt(getter.applyAsInt(item1), getter.applyAsInt(item2)); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withLong(ToLongFunction<T> getter) { |
| if (order == 0) { |
| order = parent.visitLong(getter.applyAsLong(item1), getter.applyAsLong(item2)); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withDouble(ToDoubleFunction<T> getter) { |
| if (order == 0) { |
| order = parent.visitDouble(getter.applyAsDouble(item1), getter.applyAsDouble(item2)); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withIntArray(Function<T, int[]> getter) { |
| if (order == 0) { |
| int[] is1 = getter.apply(item1); |
| int[] is2 = getter.apply(item2); |
| int minLength = Math.min(is1.length, is2.length); |
| for (int i = 0; i < minLength && order == 0; i++) { |
| order = parent.visitInt(is1[i], is2[i]); |
| } |
| if (order == 0) { |
| order = parent.visitInt(is1.length, is2.length); |
| } |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withShortArray(Function<T, short[]> getter) { |
| if (order == 0) { |
| short[] is1 = getter.apply(item1); |
| short[] is2 = getter.apply(item2); |
| int minLength = Math.min(is1.length, is2.length); |
| for (int i = 0; i < minLength && order == 0; i++) { |
| order = parent.visitInt(is1[i], is2[i]); |
| } |
| if (order == 0) { |
| order = 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 (order == 0) { |
| boolean test1 = predicate.test(item1); |
| boolean test2 = predicate.test(item2); |
| if (test1 && test2) { |
| order = compare.acceptCompareTo(getter.apply(item1), getter.apply(item2), parent); |
| } else { |
| order = parent.visitBool(test1, test2); |
| } |
| } |
| return this; |
| } |
| |
| @Override |
| protected <S> ItemSpecification<T> withCustomItemIterator( |
| Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) { |
| if (order == 0) { |
| order = parent.visitItemIterator(getter.apply(item1), getter.apply(item2), compare); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withDexReference(Function<T, DexReference> getter) { |
| if (order == 0) { |
| order = parent.visitDexReference(getter.apply(item1), getter.apply(item2)); |
| } |
| return this; |
| } |
| } |
| } |