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    }