// Copyright (C) 2009 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.gerrit.server.query; import static com.google.common.base.Preconditions.checkState; import com.google.common.collect.Iterables; import java.util.Collection; import java.util.Collections; import java.util.List; /** * An abstract predicate tree for any form of query. * * <p>Implementations should be immutable, such that the meaning of a predicate never changes once * constructed. They should ensure their immutable promise by defensively copying any structures * which might be modified externally, but was passed into the object's constructor. * * <p>However, implementations <i>may</i> retain non-thread-safe caches internally, to speed up * evaluation operations within the context of one thread's evaluation of the predicate. As a * result, callers should assume predicates are not thread-safe, but that two predicate graphs * produce the same results given the same inputs if they are {@link #equals(Object)}. * * <p>Predicates should support deep inspection whenever possible, so that generic algorithms can be * written to operate against them. Predicates which contain other predicates should override {@link * #getChildren()} to return the list of children nested within the predicate. * * @param <T> type of object the predicate can evaluate in memory. */ public abstract class Predicate<T> { /** A predicate that matches any input, always, with no cost. */ @SuppressWarnings("unchecked") public static <T> Predicate<T> any() { return (Predicate<T>) Any.INSTANCE; } /** Combine the passed predicates into a single AND node. */ @SafeVarargs public static <T> Predicate<T> and(final Predicate<T>... that) { if (that.length == 1) { return that[0]; } return new AndPredicate<>(that); } /** Combine the passed predicates into a single AND node. */ public static <T> Predicate<T> and(final Collection<? extends Predicate<T>> that) { if (that.size() == 1) { return Iterables.getOnlyElement(that); } return new AndPredicate<>(that); } /** Combine the passed predicates into a single OR node. */ @SafeVarargs public static <T> Predicate<T> or(final Predicate<T>... that) { if (that.length == 1) { return that[0]; } return new OrPredicate<>(that); } /** Combine the passed predicates into a single OR node. */ public static <T> Predicate<T> or(final Collection<? extends Predicate<T>> that) { if (that.size() == 1) { return Iterables.getOnlyElement(that); } return new OrPredicate<>(that); } /** Invert the passed node. */ public static <T> Predicate<T> not(final Predicate<T> that) { if (that instanceof NotPredicate) { // Negate of a negate is the original predicate. // return that.getChild(0); } return new NotPredicate<>(that); } /** Get the children of this predicate, if any. */ public List<Predicate<T>> getChildren() { return Collections.emptyList(); } /** Same as {@code getChildren().size()} */ public int getChildCount() { return getChildren().size(); } /** Same as {@code getChildren().get(i)} */ public Predicate<T> getChild(final int i) { return getChildren().get(i); } /** Create a copy of this predicate, with new children. */ public abstract Predicate<T> copy(Collection<? extends Predicate<T>> children); public boolean isMatchable() { return this instanceof Matchable; } @SuppressWarnings("unchecked") public Matchable<T> asMatchable() { checkState(isMatchable(), "not matchable"); return (Matchable<T>) this; } /** @return a cost estimate to run this predicate, higher figures cost more. */ public int estimateCost() { if (!isMatchable()) { return 1; } return asMatchable().getCost(); } @Override public abstract int hashCode(); @Override public abstract boolean equals(Object other); private static class Any<T> extends Predicate<T> implements Matchable<T> { private static final Any<Object> INSTANCE = new Any<>(); private Any() {} @Override public Predicate<T> copy(Collection<? extends Predicate<T>> children) { return this; } @Override public boolean match(T object) { return true; } @Override public int getCost() { return 0; } @Override public int hashCode() { return System.identityHashCode(this); } @Override public boolean equals(Object other) { return other == this; } } }