    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     * @author Mark Davis
    049     * @author Kevin Bourrillion
    050     * @since 2.0
    051     */
    052    @GwtCompatible
    053    public abstract class ComparisonChain {
    054      private ComparisonChain() {}
    055
    056      /**
    057       * Begins a new chained comparison statement. See example in the class
    058       * documentation.
    059       */
    060      public static ComparisonChain start() {
    061        return ACTIVE;
    062      }
    063
    064      private static final ComparisonChain ACTIVE = new ComparisonChain() {
    065        @SuppressWarnings("unchecked")
    066        @Override public ComparisonChain compare(
    067            Comparable left, Comparable right) {
    068          return classify(left.compareTo(right));
    069        }
    070        @Override public <T> ComparisonChain compare(
    071            @Nullable T left, @Nullable T right, Comparator<T> comparator) {
    072          return classify(comparator.compare(left, right));
    073        }
    074        @Override public ComparisonChain compare(int left, int right) {
    075          return classify(Ints.compare(left, right));
    076        }
    077        @Override public ComparisonChain compare(long left, long right) {
    078          return classify(Longs.compare(left, right));
    079        }
    080        @Override public ComparisonChain compare(float left, float right) {
    081          return classify(Float.compare(left, right));
    082        }
    083        @Override public ComparisonChain compare(double left, double right) {
    084          return classify(Double.compare(left, right));
    085        }
    086        @Override public ComparisonChain compare(boolean left, boolean right) {
    087          return classify(Booleans.compare(left, right));
    088        }
    089        ComparisonChain classify(int result) {
    090          return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
    091        }
    092        @Override public int result() {
    093          return 0;
    094        }
    095      };
    096
    097      private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
    098
    099      private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
    100
    101      private static final class InactiveComparisonChain extends ComparisonChain {
    102        final int result;
    103
    104        InactiveComparisonChain(int result) {
    105          this.result = result;
    106        }
    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    }