001    /*
002     * Copyright (C) 2009 Google Inc.
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     *
032     * <pre class="code">   {@code
033     *
034     *   public int compareTo(Foo that) {
035     *     return ComparisonChain.start()
036     *         .compare(this.aString, that.aString)
037     *         .compare(this.anInt, that.anInt)
038     *         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
039     *         .result();
040     *   }}</pre>
041     *
042     * The value of this expression will have the same sign as the <i>first
043     * nonzero</i> comparison result in the chain, or will be zero if every
044     * comparison result was zero.
045     *
046     * <p>Once any comparison returns a nonzero value, remaining comparisons are
047     * "short-circuited".
048     *
049     * @author Mark Davis
050     * @author Kevin Bourrillion
051     * @since 2
052     */
053    @GwtCompatible
054    public abstract class ComparisonChain {
055      private ComparisonChain() {}
056    
057      /**
058       * Begins a new chained comparison statement. See example in the class
059       * documentation.
060       */
061      public static ComparisonChain start() {
062        return ACTIVE;
063      }
064    
065      private static final ComparisonChain ACTIVE = new ComparisonChain() {
066        @SuppressWarnings("unchecked")
067        @Override public ComparisonChain compare(
068            Comparable left, Comparable right) {
069          return classify(left.compareTo(right));
070        }
071        @Override public <T> ComparisonChain compare(
072            @Nullable T left, @Nullable T right, Comparator<T> comparator) {
073          return classify(comparator.compare(left, right));
074        }
075        @Override public ComparisonChain compare(int left, int right) {
076          return classify(Ints.compare(left, right));
077        }
078        @Override public ComparisonChain compare(long left, long right) {
079          return classify(Longs.compare(left, right));
080        }
081        @Override public ComparisonChain compare(float left, float right) {
082          return classify(Float.compare(left, right));
083        }
084        @Override public ComparisonChain compare(double left, double right) {
085          return classify(Double.compare(left, right));
086        }
087        @Override public ComparisonChain compare(boolean left, boolean right) {
088          return classify(Booleans.compare(left, right));
089        }
090        ComparisonChain classify(int result) {
091          return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
092        }
093        @Override public int result() {
094          return 0;
095        }
096      };
097    
098      private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
099    
100      private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
101    
102      private static final class InactiveComparisonChain extends ComparisonChain {
103        final int result;
104    
105        InactiveComparisonChain(int result) {
106          this.result = result;
107        }
108        @SuppressWarnings("unchecked")
109        @Override public ComparisonChain compare(
110            @Nullable Comparable left, @Nullable Comparable right) {
111          return this;
112        }
113        @Override public <T> ComparisonChain compare(@Nullable T left,
114            @Nullable T right, @Nullable Comparator<T> comparator) {
115          return this;
116        }
117        @Override public ComparisonChain compare(int left, int right) {
118          return this;
119        }
120        @Override public ComparisonChain compare(long left, long right) {
121          return this;
122        }
123        @Override public ComparisonChain compare(float left, float right) {
124          return this;
125        }
126        @Override public ComparisonChain compare(double left, double right) {
127          return this;
128        }
129        @Override public ComparisonChain compare(boolean left, boolean right) {
130          return this;
131        }
132        @Override public int result() {
133          return result;
134        }
135      }
136    
137      /**
138       * Compares two comparable objects as specified by {@link
139       * Comparable#compareTo}, <i>if</i> the result of this comparison chain
140       * has not already been determined.
141       */
142      public abstract ComparisonChain compare(
143          Comparable<?> left, Comparable<?> right);
144    
145      /**
146       * Compares two objects using a comparator, <i>if</i> the result of this
147       * comparison chain has not already been determined.
148       */
149      public abstract <T> ComparisonChain compare(
150          @Nullable T left, @Nullable T right, Comparator<T> comparator);
151    
152      /**
153       * Compares two {@code int} values as specified by {@link Ints#compare},
154       * <i>if</i> the result of this comparison chain has not already been
155       * determined.
156       */
157      public abstract ComparisonChain compare(int left, int right);
158    
159      /**
160       * Compares two {@code long} values as specified by {@link Longs#compare},
161       * <i>if</i> the result of this comparison chain has not already been
162       * determined.
163       */
164      public abstract ComparisonChain compare(long left, long right);
165    
166      /**
167       * Compares two {@code float} values as specified by {@link
168       * Float#compare}, <i>if</i> the result of this comparison chain has not
169       * already been determined.
170       */
171      public abstract ComparisonChain compare(float left, float right);
172    
173      /**
174       * Compares two {@code double} values as specified by {@link
175       * Double#compare}, <i>if</i> the result of this comparison chain has not
176       * already been determined.
177       */
178      public abstract ComparisonChain compare(double left, double right);
179    
180      /**
181       * Compares two {@code boolean} values as specified by {@link
182       * Booleans#compare}, <i>if</i> the result of this comparison chain has not
183       * already been determined.
184       */
185      public abstract ComparisonChain compare(boolean left, boolean right);
186    
187      /**
188       * Ends this comparison chain and returns its result: a value having the
189       * same sign as the first nonzero comparison result in the chain, or zero if
190       * every result was zero.
191       */
192      public abstract int result();
193    }