Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2009 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.collect;
     18 
     19 import com.google.common.primitives.Booleans;
     20 import com.google.common.primitives.Ints;
     21 import com.google.common.primitives.Longs;
     22 
     23 import java.util.Comparator;
     24 
     25 import javax.annotation.Nullable;
     26 
     27 /**
     28  * A utility for performing a "lazy" chained comparison statement, which
     29  * performs comparisons only until it finds a nonzero result. For example:
     30  *
     31  * <pre class="code">   {@code
     32  *
     33  *   public int compareTo(Foo that) {
     34  *     return ComparisonChain.start()
     35  *         .compare(this.aString, that.aString)
     36  *         .compare(this.anInt, that.anInt)
     37  *         .compare(this.anEnum, that.anEnum, Ordering.nullsLast())
     38  *         .result();
     39  *   }}</pre>
     40  *
     41  * The value of this expression will have the same sign as the <i>first
     42  * nonzero</i> comparison result in the chain, or will be zero if every
     43  * comparison result was zero.
     44  *
     45  * <p>Once any comparison returns a nonzero value, remaining comparisons are
     46  * "short-circuited".
     47  *
     48  * @author Mark Davis
     49  * @author Kevin Bourrillion
     50  * @since 2010.01.04 <b>tentative</b>
     51  */
     52 public abstract class ComparisonChain {
     53   private ComparisonChain() {}
     54 
     55   /**
     56    * Begins a new chained comparison statement. See example in the class
     57    * documentation.
     58    */
     59   public static ComparisonChain start() {
     60     return ACTIVE;
     61   }
     62 
     63   private static final ComparisonChain ACTIVE = new ComparisonChain() {
     64     @SuppressWarnings("unchecked")
     65     @Override public ComparisonChain compare(
     66         Comparable left, Comparable right) {
     67       return classify(left.compareTo(right));
     68     }
     69     @Override public <T> ComparisonChain compare(
     70         @Nullable T left, @Nullable T right, Comparator<T> comparator) {
     71       return classify(comparator.compare(left, right));
     72     }
     73     @Override public ComparisonChain compare(int left, int right) {
     74       return classify(Ints.compare(left, right));
     75     }
     76     @Override public ComparisonChain compare(long left, long right) {
     77       return classify(Longs.compare(left, right));
     78     }
     79     @Override public ComparisonChain compare(float left, float right) {
     80       return classify(Float.compare(left, right));
     81     }
     82     @Override public ComparisonChain compare(double left, double right) {
     83       return classify(Double.compare(left, right));
     84     }
     85     @Override public ComparisonChain compare(boolean left, boolean right) {
     86       return classify(Booleans.compare(left, right));
     87     }
     88     ComparisonChain classify(int result) {
     89       return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
     90     }
     91     @Override public int result() {
     92       return 0;
     93     }
     94   };
     95 
     96   private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
     97 
     98   private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
     99 
    100   private static final class InactiveComparisonChain extends ComparisonChain {
    101     final int result;
    102 
    103     InactiveComparisonChain(int result) {
    104       this.result = result;
    105     }
    106     @SuppressWarnings("unchecked")
    107     @Override public ComparisonChain compare(
    108         @Nullable Comparable left, @Nullable Comparable right) {
    109       return this;
    110     }
    111     @Override public <T> ComparisonChain compare(@Nullable T left,
    112         @Nullable T right, @Nullable Comparator<T> comparator) {
    113       return this;
    114     }
    115     @Override public ComparisonChain compare(int left, int right) {
    116       return this;
    117     }
    118     @Override public ComparisonChain compare(long left, long right) {
    119       return this;
    120     }
    121     @Override public ComparisonChain compare(float left, float right) {
    122       return this;
    123     }
    124     @Override public ComparisonChain compare(double left, double right) {
    125       return this;
    126     }
    127     @Override public ComparisonChain compare(boolean left, boolean right) {
    128       return this;
    129     }
    130     @Override public int result() {
    131       return result;
    132     }
    133   }
    134 
    135   /**
    136    * Compares two comparable objects as specified by {@link
    137    * Comparable#compareTo}, <i>if</i> the result of this comparison chain
    138    * has not already been determined.
    139    */
    140   public abstract ComparisonChain compare(
    141       Comparable<?> left, Comparable<?> right);
    142 
    143   /**
    144    * Compares two objects using a comparator, <i>if</i> the result of this
    145    * comparison chain has not already been determined.
    146    */
    147   public abstract <T> ComparisonChain compare(
    148       @Nullable T left, @Nullable T right, Comparator<T> comparator);
    149 
    150   /**
    151    * Compares two {@code int} values as specified by {@link Ints#compare},
    152    * <i>if</i> the result of this comparison chain has not already been
    153    * determined.
    154    */
    155   public abstract ComparisonChain compare(int left, int right);
    156 
    157   /**
    158    * Compares two {@code long} values as specified by {@link Longs#compare},
    159    * <i>if</i> the result of this comparison chain has not already been
    160    * determined.
    161    */
    162   public abstract ComparisonChain compare(long left, long right);
    163 
    164   /**
    165    * Compares two {@code float} values as specified by {@link
    166    * Float#compare}, <i>if</i> the result of this comparison chain has not
    167    * already been determined.
    168    */
    169   public abstract ComparisonChain compare(float left, float right);
    170 
    171   /**
    172    * Compares two {@code double} values as specified by {@link
    173    * Double#compare}, <i>if</i> the result of this comparison chain has not
    174    * already been determined.
    175    */
    176   public abstract ComparisonChain compare(double left, double right);
    177 
    178   /**
    179    * Compares two {@code boolean} values as specified by {@link
    180    * Booleans#compare}, <i>if</i> the result of this comparison chain has not
    181    * already been determined.
    182    */
    183   public abstract ComparisonChain compare(boolean left, boolean right);
    184 
    185   /**
    186    * Ends this comparison chain and returns its result: a value having the
    187    * same sign as the first nonzero comparison result in the chain, or zero if
    188    * every result was zero.
    189    */
    190   public abstract int result();
    191 }
    192