    001    /*
    002     * Copyright (C) 2009 The Guava Authors
    003     *
    004     * Licensed under the Apache License, Version 2.0 (the "License");
    005     * you may not use this file except in compliance with the License.
    006     * You may obtain a copy of the License at
    007     *
    008     * http://www.apache.org/licenses/LICENSE-2.0
    009     *
    010     * Unless required by applicable law or agreed to in writing, software
    011     * distributed under the License is distributed on an "AS IS" BASIS,
    012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    013     * See the License for the specific language governing permissions and
    014     * limitations under the License.
    015     */
    016
    017    package com.google.common.collect;
    018
    019    import com.google.common.annotations.GwtCompatible;
    020    import com.google.common.primitives.Booleans;
    021    import com.google.common.primitives.Ints;
    022    import com.google.common.primitives.Longs;
    023
    024    import java.util.Comparator;
    025
    026    import javax.annotation.Nullable;
    027
    028    /**
    029     * A utility for performing a "lazy" chained comparison statement, which
    030     * performs comparisons only until it finds a nonzero result. For example:
    031     * <pre>   {@code
    032     *
    033     *   public int compareTo(Foo that) {
    034     *     return ComparisonChain.start()
    035     *         .compare(this.aString, that.aString)
    036     *         .compare(this.anInt, that.anInt)
    037     *         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
    038     *         .result();
    039     *   }}</pre>
    040     *
    041     * The value of this expression will have the same sign as the <i>first
    042     * nonzero</i> comparison result in the chain, or will be zero if every
    043     * comparison result was zero.
    044     *
    045     * <p>Once any comparison returns a nonzero value, remaining comparisons are
    046     * "short-circuited".
    047     *
    048     * <p>See the Guava User Guide article on <a href=
    049     * "http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained#compare/compareTo">
    050     * {@code ComparisonChain}</a>.
    051     *
    052     * @author Mark Davis
    053     * @author Kevin Bourrillion
    054     * @since 2.0
    055     */
    056    @GwtCompatible
    057    public abstract class ComparisonChain {
    058      private ComparisonChain() {}
    059
    060      /**
    061       * Begins a new chained comparison statement. See example in the class
    062       * documentation.
    063       */
    064      public static ComparisonChain start() {
    065        return ACTIVE;
    066      }
    067
    068      private static final ComparisonChain ACTIVE = new ComparisonChain() {
    069        @SuppressWarnings("unchecked")
    070        @Override public ComparisonChain compare(
    071            Comparable left, Comparable right) {
    072          return classify(left.compareTo(right));
    073        }
    074        @Override public <T> ComparisonChain compare(
    075            @Nullable T left, @Nullable T right, Comparator<T> comparator) {
    076          return classify(comparator.compare(left, right));
    077        }
    078        @Override public ComparisonChain compare(int left, int right) {
    079          return classify(Ints.compare(left, right));
    080        }
    081        @Override public ComparisonChain compare(long left, long right) {
    082          return classify(Longs.compare(left, right));
    083        }
    084        @Override public ComparisonChain compare(float left, float right) {
    085          return classify(Float.compare(left, right));
    086        }
    087        @Override public ComparisonChain compare(double left, double right) {
    088          return classify(Double.compare(left, right));
    089        }
    090        @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
    091          return classify(Booleans.compare(right, left)); // reversed
    092        }
    093        @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
    094          return classify(Booleans.compare(left, right));
    095        }
    096        ComparisonChain classify(int result) {
    097          return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
    098        }
    099        @Override public int result() {
    100          return 0;
    101        }
    102      };
    103
    104      private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
    105
    106      private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
    107
    108      private static final class InactiveComparisonChain extends ComparisonChain {
    109        final int result;
    110
    111        InactiveComparisonChain(int result) {
    112          this.result = result;
    113        }
    114        @Override public ComparisonChain compare(
    115            @Nullable Comparable left, @Nullable Comparable right) {
    116          return this;
    117        }
    118        @Override public <T> ComparisonChain compare(@Nullable T left,
    119            @Nullable T right, @Nullable Comparator<T> comparator) {
    120          return this;
    121        }
    122        @Override public ComparisonChain compare(int left, int right) {
    123          return this;
    124        }
    125        @Override public ComparisonChain compare(long left, long right) {
    126          return this;
    127        }
    128        @Override public ComparisonChain compare(float left, float right) {
    129          return this;
    130        }
    131        @Override public ComparisonChain compare(double left, double right) {
    132          return this;
    133        }
    134        @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
    135          return this;
    136        }
    137        @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
    138          return this;
    139        }
    140        @Override public int result() {
    141          return result;
    142        }
    143      }
    144
    145      /**
    146       * Compares two comparable objects as specified by {@link
    147       * Comparable#compareTo}, <i>if</i> the result of this comparison chain
    148       * has not already been determined.
    149       */
    150      public abstract ComparisonChain compare(
    151          Comparable<?> left, Comparable<?> right);
    152
    153      /**
    154       * Compares two objects using a comparator, <i>if</i> the result of this
    155       * comparison chain has not already been determined.
    156       */
    157      public abstract <T> ComparisonChain compare(
    158          @Nullable T left, @Nullable T right, Comparator<T> comparator);
    159
    160      /**
    161       * Compares two {@code int} values as specified by {@link Ints#compare},
    162       * <i>if</i> the result of this comparison chain has not already been
    163       * determined.
    164       */
    165      public abstract ComparisonChain compare(int left, int right);
    166
    167      /**
    168       * Compares two {@code long} values as specified by {@link Longs#compare},
    169       * <i>if</i> the result of this comparison chain has not already been
    170       * determined.
    171       */
    172      public abstract ComparisonChain compare(long left, long right);
    173
    174      /**
    175       * Compares two {@code float} values as specified by {@link
    176       * Float#compare}, <i>if</i> the result of this comparison chain has not
    177       * already been determined.
    178       */
    179      public abstract ComparisonChain compare(float left, float right);
    180
    181      /**
    182       * Compares two {@code double} values as specified by {@link
    183       * Double#compare}, <i>if</i> the result of this comparison chain has not
    184       * already been determined.
    185       */
    186      public abstract ComparisonChain compare(double left, double right);
    187
    188      /**
    189       * Compares two {@code boolean} values, considering {@code true} to be less
    190       * than {@code false}, <i>if</i> the result of this comparison chain has not
    191       * already been determined.
    192       *
    193       * @since 12.0
    194       */
    195      public abstract ComparisonChain compareTrueFirst(boolean left, boolean right);
    196
    197      /**
    198       * Compares two {@code boolean} values, considering {@code false} to be less
    199       * than {@code true}, <i>if</i> the result of this comparison chain has not
    200       * already been determined.
    201       *
    202       * @since 12.0 (present as {@code compare} since 2.0)
    203       */
    204      public abstract ComparisonChain compareFalseFirst(boolean left, boolean right);
    205
    206      /**
    207       * Old name of {@link #compareFalseFirst}.
    208       *
    209       * @deprecated Use {@link #compareFalseFirst}; or, if the parameters passed
    210       *     are being either negated or reversed, undo the negation or reversal and
    211       *     use {@link #compareTrueFirst}. <b>This method is scheduled for deletion
    212       *     in September 2013.</b>
    213       */
    214      @Deprecated
    215      public final ComparisonChain compare(boolean left, boolean right) {
    216        return compareFalseFirst(left, right);
    217      }
    218
    219      /**
    220       * Ends this comparison chain and returns its result: a value having the
    221       * same sign as the first nonzero comparison result in the chain, or zero if
    222       * every result was zero.
    223       */
    224      public abstract int result();
    225    }