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
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        @SuppressWarnings("unchecked")
108        @Override public ComparisonChain compare(
109            @Nullable Comparable left, @Nullable Comparable right) {
110          return this;
111        }
112        @Override public <T> ComparisonChain compare(@Nullable T left,
113            @Nullable T right, @Nullable Comparator<T> comparator) {
114          return this;
115        }
116        @Override public ComparisonChain compare(int left, int right) {
117          return this;
118        }
119        @Override public ComparisonChain compare(long left, long right) {
120          return this;
121        }
122        @Override public ComparisonChain compare(float left, float right) {
123          return this;
124        }
125        @Override public ComparisonChain compare(double left, double right) {
126          return this;
127        }
128        @Override public ComparisonChain compare(boolean left, boolean right) {
129          return this;
130        }
131        @Override public int result() {
132          return result;
133        }
134      }
135    
136      /**
137       * Compares two comparable objects as specified by {@link
138       * Comparable#compareTo}, <i>if</i> the result of this comparison chain
139       * has not already been determined.
140       */
141      public abstract ComparisonChain compare(
142          Comparable<?> left, Comparable<?> right);
143    
144      /**
145       * Compares two objects using a comparator, <i>if</i> the result of this
146       * comparison chain has not already been determined.
147       */
148      public abstract <T> ComparisonChain compare(
149          @Nullable T left, @Nullable T right, Comparator<T> comparator);
150    
151      /**
152       * Compares two {@code int} values as specified by {@link Ints#compare},
153       * <i>if</i> the result of this comparison chain has not already been
154       * determined.
155       */
156      public abstract ComparisonChain compare(int left, int right);
157    
158      /**
159       * Compares two {@code long} values as specified by {@link Longs#compare},
160       * <i>if</i> the result of this comparison chain has not already been
161       * determined.
162       */
163      public abstract ComparisonChain compare(long left, long right);
164    
165      /**
166       * Compares two {@code float} values as specified by {@link
167       * Float#compare}, <i>if</i> the result of this comparison chain has not
168       * already been determined.
169       */
170      public abstract ComparisonChain compare(float left, float right);
171    
172      /**
173       * Compares two {@code double} values as specified by {@link
174       * Double#compare}, <i>if</i> the result of this comparison chain has not
175       * already been determined.
176       */
177      public abstract ComparisonChain compare(double left, double right);
178    
179      /**
180       * Compares two {@code boolean} values as specified by {@link
181       * Booleans#compare}, <i>if</i> the result of this comparison chain has not
182       * already been determined.
183       */
184      public abstract ComparisonChain compare(boolean left, boolean right);
185    
186      /**
187       * Ends this comparison chain and returns its result: a value having the
188       * same sign as the first nonzero comparison result in the chain, or zero if
189       * every result was zero.
190       */
191      public abstract int result();
192    }