LCOV - code coverage report
Current view: top level - index/query - Predicate.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 51 58 87.9 %
Date: 2022-11-19 15:00:39 Functions: 21 27 77.8 %

          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.checkArgument;
      18             : import static com.google.common.base.Preconditions.checkState;
      19             : 
      20             : import com.google.common.collect.Iterables;
      21             : import java.util.ArrayDeque;
      22             : import java.util.ArrayList;
      23             : import java.util.Collection;
      24             : import java.util.Collections;
      25             : import java.util.List;
      26             : import java.util.Queue;
      27             : 
      28             : /**
      29             :  * An abstract predicate tree for any form of query.
      30             :  *
      31             :  * <p>Implementations should be immutable, such that the meaning of a predicate never changes once
      32             :  * constructed. They should ensure their immutable promise by defensively copying any structures
      33             :  * which might be modified externally, but was passed into the object's constructor.
      34             :  *
      35             :  * <p>However, implementations <i>may</i> retain non-thread-safe caches internally, to speed up
      36             :  * evaluation operations within the context of one thread's evaluation of the predicate. As a
      37             :  * result, callers should assume predicates are not thread-safe, but that two predicate graphs
      38             :  * produce the same results given the same inputs if they are {@link #equals(Object)}.
      39             :  *
      40             :  * <p>Predicates should support deep inspection whenever possible, so that generic algorithms can be
      41             :  * written to operate against them. Predicates which contain other predicates should override {@link
      42             :  * #getChildren()} to return the list of children nested within the predicate.
      43             :  *
      44             :  * @param <T> type of object the predicate can evaluate in memory.
      45             :  */
      46         153 : public abstract class Predicate<T> {
      47             :   /** Query String that was used to create this predicate. Only set from the Antlr query parser. */
      48         153 :   private String predicateString = null;
      49             : 
      50             :   /**
      51             :    * Boolean indicating if this predicate is a leaf predicate in a composite expression. Only set
      52             :    * from the Antlr query parser.
      53             :    */
      54         153 :   private boolean isLeaf = false;
      55             : 
      56             :   /** Sets the {@link #predicateString} field. This can only be set once. */
      57             :   void setPredicateString(String predicateString) {
      58          50 :     this.predicateString = this.predicateString == null ? predicateString : this.predicateString;
      59          50 :   }
      60             : 
      61             :   public String getPredicateString() {
      62           3 :     return predicateString;
      63             :   }
      64             : 
      65             :   void setLeaf(boolean isLeaf) {
      66          48 :     this.isLeaf = isLeaf;
      67          48 :   }
      68             : 
      69             :   public boolean isLeaf() {
      70           3 :     return isLeaf;
      71             :   }
      72             : 
      73             :   /** A predicate that matches any input, always, with no cost. */
      74             :   @SuppressWarnings("unchecked")
      75             :   public static <T> Predicate<T> any() {
      76           6 :     return (Predicate<T>) Any.INSTANCE;
      77             :   }
      78             : 
      79             :   /** Combine the passed predicates into a single AND node. */
      80             :   @SafeVarargs
      81             :   public static <T> Predicate<T> and(Predicate<T>... that) {
      82         111 :     if (that.length == 1) {
      83           0 :       return that[0];
      84             :     }
      85         111 :     return new AndPredicate<>(that);
      86             :   }
      87             : 
      88             :   /** Combine the passed predicates into a single AND node. */
      89             :   public static <T> Predicate<T> and(Collection<? extends Predicate<T>> that) {
      90          23 :     if (that.size() == 1) {
      91           8 :       return Iterables.getOnlyElement(that);
      92             :     }
      93          22 :     return new AndPredicate<>(that);
      94             :   }
      95             : 
      96             :   /** Combine the passed predicates into a single OR node. */
      97             :   @SafeVarargs
      98             :   public static <T> Predicate<T> or(Predicate<T>... that) {
      99          16 :     if (that.length == 1) {
     100           2 :       return that[0];
     101             :     }
     102          16 :     return new OrPredicate<>(that);
     103             :   }
     104             : 
     105             :   /** Combine the passed predicates into a single OR node. */
     106             :   public static <T> Predicate<T> or(Collection<? extends Predicate<T>> that) {
     107         121 :     if (that.size() == 1) {
     108         115 :       return Iterables.getOnlyElement(that);
     109             :     }
     110         121 :     return new OrPredicate<>(that);
     111             :   }
     112             : 
     113             :   /** Invert the passed node. */
     114             :   public static <T> Predicate<T> not(Predicate<T> that) {
     115          57 :     checkArgument(
     116             :         !(that instanceof Any), "negating any() is unsafe because it post-filters all results");
     117          57 :     if (that instanceof NotPredicate) {
     118             :       // Negate of a negate is the original predicate.
     119             :       //
     120           5 :       return that.getChild(0);
     121             :     }
     122          57 :     return new NotPredicate<>(that);
     123             :   }
     124             : 
     125             :   /** Get the children of this predicate, if any. */
     126             :   public List<Predicate<T>> getChildren() {
     127         152 :     return Collections.emptyList();
     128             :   }
     129             : 
     130             :   /** Same as {@code getChildren().size()} */
     131             :   public int getChildCount() {
     132          76 :     return getChildren().size();
     133             :   }
     134             : 
     135             :   /** Same as {@code getChildren().get(i)} */
     136             :   public Predicate<T> getChild(int i) {
     137           0 :     return getChildren().get(i);
     138             :   }
     139             : 
     140             :   /** Get the number of leaf terms in this predicate. */
     141             :   public int getLeafCount() {
     142           1 :     int leafCount = 0;
     143           1 :     for (Predicate<?> childPredicate : getChildren()) {
     144           1 :       if (childPredicate instanceof IndexPredicate) {
     145           1 :         leafCount++;
     146             :       }
     147           1 :       leafCount += childPredicate.getLeafCount();
     148           1 :     }
     149           1 :     return leafCount;
     150             :   }
     151             : 
     152             :   /** Returns a list of this predicate and all its descendants. */
     153             :   public List<Predicate<T>> getFlattenedPredicateList() {
     154         151 :     List<Predicate<T>> result = new ArrayList<>();
     155         151 :     Queue<Predicate<T>> queue = new ArrayDeque<>();
     156         151 :     queue.add(this);
     157         151 :     while (!queue.isEmpty()) {
     158         151 :       Predicate<T> current = queue.poll();
     159         151 :       result.add(current);
     160         151 :       current.getChildren().forEach(p -> queue.add(p));
     161         151 :     }
     162         151 :     return result;
     163             :   }
     164             : 
     165             :   /** Create a copy of this predicate, with new children. */
     166             :   public abstract Predicate<T> copy(Collection<? extends Predicate<T>> children);
     167             : 
     168             :   public boolean isMatchable() {
     169         152 :     return this instanceof Matchable;
     170             :   }
     171             : 
     172             :   /** Whether this predicate can be used in search queries. */
     173             :   public boolean supportedForQueries() {
     174         151 :     return true;
     175             :   }
     176             : 
     177             :   @SuppressWarnings("unchecked")
     178             :   public Matchable<T> asMatchable() {
     179         152 :     checkState(isMatchable(), "not matchable");
     180         152 :     return (Matchable<T>) this;
     181             :   }
     182             : 
     183             :   /** Returns a cost estimate to run this predicate, higher figures cost more. */
     184             :   public int estimateCost() {
     185         125 :     if (!isMatchable()) {
     186          19 :       return 1;
     187             :     }
     188         122 :     return asMatchable().getCost();
     189             :   }
     190             : 
     191             :   @Override
     192             :   public abstract int hashCode();
     193             : 
     194             :   @Override
     195             :   public abstract boolean equals(Object other);
     196             : 
     197             :   private static class Any<T> extends Predicate<T> implements Matchable<T> {
     198           6 :     private static final Any<Object> INSTANCE = new Any<>();
     199             : 
     200             :     private Any() {}
     201             : 
     202             :     @Override
     203             :     public Predicate<T> copy(Collection<? extends Predicate<T>> children) {
     204           0 :       return this;
     205             :     }
     206             : 
     207             :     @Override
     208             :     public boolean match(T object) {
     209           0 :       return true;
     210             :     }
     211             : 
     212             :     @Override
     213             :     public int getCost() {
     214           0 :       return 0;
     215             :     }
     216             : 
     217             :     @Override
     218             :     public int hashCode() {
     219           0 :       return System.identityHashCode(this);
     220             :     }
     221             : 
     222             :     @Override
     223             :     public boolean equals(Object other) {
     224           0 :       return other == this;
     225             :     }
     226             :   }
     227             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750