Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2009 The Guava Authors
      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.annotations.GwtCompatible;
     20 import com.google.common.primitives.Booleans;
     21 import com.google.common.primitives.Ints;
     22 import com.google.common.primitives.Longs;
     23 
     24 import java.util.Comparator;
     25 
     26 import javax.annotation.Nullable;
     27 
     28 /**
     29  * A utility for performing a chained comparison statement. For example:
     30  * <pre>   {@code
     31  *
     32  *   public int compareTo(Foo that) {
     33  *     return ComparisonChain.start()
     34  *         .compare(this.aString, that.aString)
     35  *         .compare(this.anInt, that.anInt)
     36  *         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
     37  *         .result();
     38  *   }}</pre>
     39  *
     40  * <p>The value of this expression will have the same sign as the <i>first
     41  * nonzero</i> comparison result in the chain, or will be zero if every
     42  * comparison result was zero.
     43  *
     44  * <p>Performance note: Even though the {@code ComparisonChain} caller always
     45  * invokes its {@code compare} methods unconditionally, the {@code
     46  * ComparisonChain} implementation stops calling its inputs' {@link
     47  * Comparable#compareTo compareTo} and {@link Comparator#compare compare}
     48  * methods as soon as one of them returns a nonzero result. This optimization is
     49  * typically important only in the presence of expensive {@code compareTo} and
     50  * {@code compare} implementations.
     51  *
     52  * <p>See the Guava User Guide article on <a href=
     53  * "http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained#compare/compareTo">
     54  * {@code ComparisonChain}</a>.
     55  *
     56  * @author Mark Davis
     57  * @author Kevin Bourrillion
     58  * @since 2.0
     59  */
     60 @GwtCompatible
     61 public abstract class ComparisonChain {
     62   private ComparisonChain() {}
     63 
     64   /**
     65    * Begins a new chained comparison statement. See example in the class
     66    * documentation.
     67    */
     68   public static ComparisonChain start() {
     69     return ACTIVE;
     70   }
     71 
     72   private static final ComparisonChain ACTIVE = new ComparisonChain() {
     73     @SuppressWarnings("unchecked")
     74     @Override public ComparisonChain compare(
     75         Comparable left, Comparable right) {
     76       return classify(left.compareTo(right));
     77     }
     78     @Override public <T> ComparisonChain compare(
     79         @Nullable T left, @Nullable T right, Comparator<T> comparator) {
     80       return classify(comparator.compare(left, right));
     81     }
     82     @Override public ComparisonChain compare(int left, int right) {
     83       return classify(Ints.compare(left, right));
     84     }
     85     @Override public ComparisonChain compare(long left, long right) {
     86       return classify(Longs.compare(left, right));
     87     }
     88     @Override public ComparisonChain compare(float left, float right) {
     89       return classify(Float.compare(left, right));
     90     }
     91     @Override public ComparisonChain compare(double left, double right) {
     92       return classify(Double.compare(left, right));
     93     }
     94     @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
     95       return classify(Booleans.compare(right, left)); // reversed
     96     }
     97     @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
     98       return classify(Booleans.compare(left, right));
     99     }
    100     ComparisonChain classify(int result) {
    101       return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
    102     }
    103     @Override public int result() {
    104       return 0;
    105     }
    106   };
    107 
    108   private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
    109 
    110   private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
    111 
    112   private static final class InactiveComparisonChain extends ComparisonChain {
    113     final int result;
    114 
    115     InactiveComparisonChain(int result) {
    116       this.result = result;
    117     }
    118     @Override public ComparisonChain compare(
    119         @Nullable Comparable left, @Nullable Comparable right) {
    120       return this;
    121     }
    122     @Override public <T> ComparisonChain compare(@Nullable T left,
    123         @Nullable T right, @Nullable Comparator<T> comparator) {
    124       return this;
    125     }
    126     @Override public ComparisonChain compare(int left, int right) {
    127       return this;
    128     }
    129     @Override public ComparisonChain compare(long left, long right) {
    130       return this;
    131     }
    132     @Override public ComparisonChain compare(float left, float right) {
    133       return this;
    134     }
    135     @Override public ComparisonChain compare(double left, double right) {
    136       return this;
    137     }
    138     @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
    139       return this;
    140     }
    141     @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
    142       return this;
    143     }
    144     @Override public int result() {
    145       return result;
    146     }
    147   }
    148 
    149   /**
    150    * Compares two comparable objects as specified by {@link
    151    * Comparable#compareTo}, <i>if</i> the result of this comparison chain
    152    * has not already been determined.
    153    */
    154   public abstract ComparisonChain compare(
    155       Comparable<?> left, Comparable<?> right);
    156 
    157   /**
    158    * Compares two objects using a comparator, <i>if</i> the result of this
    159    * comparison chain has not already been determined.
    160    */
    161   public abstract <T> ComparisonChain compare(
    162       @Nullable T left, @Nullable T right, Comparator<T> comparator);
    163 
    164   /**
    165    * Compares two {@code int} values as specified by {@link Ints#compare},
    166    * <i>if</i> the result of this comparison chain has not already been
    167    * determined.
    168    */
    169   public abstract ComparisonChain compare(int left, int right);
    170 
    171   /**
    172    * Compares two {@code long} values as specified by {@link Longs#compare},
    173    * <i>if</i> the result of this comparison chain has not already been
    174    * determined.
    175    */
    176   public abstract ComparisonChain compare(long left, long right);
    177 
    178   /**
    179    * Compares two {@code float} values as specified by {@link
    180    * Float#compare}, <i>if</i> the result of this comparison chain has not
    181    * already been determined.
    182    */
    183   public abstract ComparisonChain compare(float left, float right);
    184 
    185   /**
    186    * Compares two {@code double} values as specified by {@link
    187    * Double#compare}, <i>if</i> the result of this comparison chain has not
    188    * already been determined.
    189    */
    190   public abstract ComparisonChain compare(double left, double right);
    191 
    192   /**
    193    * Compares two {@code boolean} values, considering {@code true} to be less
    194    * than {@code false}, <i>if</i> the result of this comparison chain has not
    195    * already been determined.
    196    *
    197    * @since 12.0
    198    */
    199   public abstract ComparisonChain compareTrueFirst(boolean left, boolean right);
    200 
    201   /**
    202    * Compares two {@code boolean} values, considering {@code false} to be less
    203    * than {@code true}, <i>if</i> the result of this comparison chain has not
    204    * already been determined.
    205    *
    206    * @since 12.0 (present as {@code compare} since 2.0)
    207    */
    208   public abstract ComparisonChain compareFalseFirst(boolean left, boolean right);
    209 
    210   /**
    211    * Ends this comparison chain and returns its result: a value having the
    212    * same sign as the first nonzero comparison result in the chain, or zero if
    213    * every result was zero.
    214    */
    215   public abstract int result();
    216 }
    217