Line data Source code
1 : // Copyright (C) 2009 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.index.query; 16 : 17 : import static com.google.common.base.Preconditions.checkState; 18 : import static com.google.common.collect.ImmutableList.toImmutableList; 19 : 20 : import com.google.common.collect.ImmutableList; 21 : import java.util.ArrayList; 22 : import java.util.Arrays; 23 : import java.util.Collection; 24 : import java.util.Collections; 25 : import java.util.Comparator; 26 : import java.util.List; 27 : 28 : /** Requires all predicates to be true. */ 29 : public class AndPredicate<T> extends Predicate<T> 30 : implements Matchable<T>, Comparator<Predicate<T>> { 31 : private final List<Predicate<T>> children; 32 : private final int cost; 33 : 34 : @SafeVarargs 35 : protected AndPredicate(Predicate<T>... that) { 36 111 : this(Arrays.asList(that)); 37 111 : } 38 : 39 121 : protected AndPredicate(Collection<? extends Predicate<T>> that) { 40 121 : List<Predicate<T>> t = new ArrayList<>(that.size()); 41 121 : int c = 0; 42 121 : for (Predicate<T> p : sort(that)) { 43 121 : if (getClass() == p.getClass()) { 44 16 : for (Predicate<T> gp : p.getChildren()) { 45 16 : t.add(gp); 46 16 : c += gp.estimateCost(); 47 16 : } 48 : } else { 49 121 : t.add(p); 50 121 : c += p.estimateCost(); 51 : } 52 121 : } 53 121 : children = t; 54 121 : cost = c; 55 121 : } 56 : 57 : @Override 58 : public final List<Predicate<T>> getChildren() { 59 121 : return Collections.unmodifiableList(children); 60 : } 61 : 62 : @Override 63 : public final int getChildCount() { 64 114 : return children.size(); 65 : } 66 : 67 : @Override 68 : public final Predicate<T> getChild(int i) { 69 114 : return children.get(i); 70 : } 71 : 72 : @Override 73 : public Predicate<T> copy(Collection<? extends Predicate<T>> children) { 74 6 : return new AndPredicate<>(children); 75 : } 76 : 77 : @Override 78 : public boolean isMatchable() { 79 109 : for (Predicate<T> c : children) { 80 109 : if (!c.isMatchable()) { 81 16 : return false; 82 : } 83 103 : } 84 103 : return true; 85 : } 86 : 87 : @Override 88 : public boolean match(T object) { 89 103 : for (Predicate<T> c : children) { 90 103 : checkState( 91 103 : c.isMatchable(), 92 : "match invoked, but child predicate %s doesn't implement %s", 93 : c, 94 103 : Matchable.class.getName()); 95 103 : if (!c.asMatchable().match(object)) { 96 95 : return false; 97 : } 98 102 : } 99 93 : return true; 100 : } 101 : 102 : @Override 103 : public int getCost() { 104 14 : return cost; 105 : } 106 : 107 : @Override 108 : public int hashCode() { 109 1 : return getChild(0).hashCode() * 31 + getChild(1).hashCode(); 110 : } 111 : 112 : // Suppress the EqualsGetClass warning as this is legacy code. 113 : @SuppressWarnings("EqualsGetClass") 114 : @Override 115 : public boolean equals(Object other) { 116 7 : if (other == null) { 117 0 : return false; 118 : } 119 7 : return getClass() == other.getClass() 120 7 : && getChildren().equals(((Predicate<?>) other).getChildren()); 121 : } 122 : 123 : private ImmutableList<Predicate<T>> sort(Collection<? extends Predicate<T>> that) { 124 121 : return that.stream().sorted(this).collect(toImmutableList()); 125 : } 126 : 127 : @Override 128 : public int compare(Predicate<T> a, Predicate<T> b) { 129 111 : int ai = a instanceof DataSource ? 0 : 1; 130 111 : int bi = b instanceof DataSource ? 0 : 1; 131 111 : int cmp = ai - bi; 132 : 133 111 : if (cmp == 0) { 134 111 : cmp = a.estimateCost() - b.estimateCost(); 135 : } 136 : 137 111 : if (cmp == 0 && a instanceof DataSource && b instanceof DataSource) { 138 1 : DataSource<?> as = (DataSource<?>) a; 139 1 : DataSource<?> bs = (DataSource<?>) b; 140 1 : cmp = as.getCardinality() - bs.getCardinality(); 141 : } 142 111 : return cmp; 143 : } 144 : 145 : @Override 146 : public String toString() { 147 19 : final StringBuilder r = new StringBuilder(); 148 19 : r.append("("); 149 19 : for (int i = 0; i < getChildCount(); i++) { 150 19 : if (i != 0) { 151 15 : r.append(" "); 152 : } 153 19 : r.append(getChild(i)); 154 : } 155 19 : r.append(")"); 156 19 : return r.toString(); 157 : } 158 : }