All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.index.query.Predicate Maven / Gradle / Ivy

There is a newer version: 3.11.0-rc3
Show newest version
// 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.index.query;

import static com.google.common.base.Preconditions.checkArgument;
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.
 *
 * 

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. * *

However, implementations may 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)}. * *

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 type of object the predicate can evaluate in memory. */ public abstract class Predicate { /** A predicate that matches any input, always, with no cost. */ @SuppressWarnings("unchecked") public static Predicate any() { return (Predicate) Any.INSTANCE; } /** Combine the passed predicates into a single AND node. */ @SafeVarargs public static Predicate and(Predicate... that) { if (that.length == 1) { return that[0]; } return new AndPredicate<>(that); } /** Combine the passed predicates into a single AND node. */ public static Predicate and(Collection> 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 Predicate or(Predicate... that) { if (that.length == 1) { return that[0]; } return new OrPredicate<>(that); } /** Combine the passed predicates into a single OR node. */ public static Predicate or(Collection> that) { if (that.size() == 1) { return Iterables.getOnlyElement(that); } return new OrPredicate<>(that); } /** Invert the passed node. */ public static Predicate not(Predicate that) { checkArgument( !(that instanceof Any), "negating any() is unsafe because it post-filters all results"); 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> getChildren() { return Collections.emptyList(); } /** Same as {@code getChildren().size()} */ public int getChildCount() { return getChildren().size(); } /** Same as {@code getChildren().get(i)} */ public Predicate getChild(int i) { return getChildren().get(i); } /** Get the number of leaf terms in this predicate. */ public int getLeafCount() { int leafCount = 0; for (Predicate childPredicate : getChildren()) { if (childPredicate instanceof IndexPredicate) { leafCount++; } leafCount += childPredicate.getLeafCount(); } return leafCount; } /** Create a copy of this predicate, with new children. */ public abstract Predicate copy(Collection> children); public boolean isMatchable() { return this instanceof Matchable; } @SuppressWarnings("unchecked") public Matchable asMatchable() { checkState(isMatchable(), "not matchable"); return (Matchable) 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 extends Predicate implements Matchable { private static final Any INSTANCE = new Any<>(); private Any() {} @Override public Predicate copy(Collection> 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; } } }