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        
070        @Override
071        @SuppressWarnings("unchecked")
072        public ComparisonChain compare(
073            Comparable left, Comparable right) {
074          return classify(left.compareTo(right));
075        }
076        
077        @Override
078        public <T> ComparisonChain compare(
079            @Nullable T left, @Nullable T right, Comparator<T> comparator) {
080          return classify(comparator.compare(left, right));
081        }
082        
083        @Override
084        public ComparisonChain compare(int left, int right) {
085          return classify(Ints.compare(left, right));
086        }
087        
088        @Override
089        public ComparisonChain compare(long left, long right) {
090          return classify(Longs.compare(left, right));
091        }
092        
093        @Override
094        public ComparisonChain compare(float left, float right) {
095          return classify(Float.compare(left, right));
096        }
097        
098        @Override
099        public ComparisonChain compare(double left, double right) {
100          return classify(Double.compare(left, right));
101        }
102        
103        @Override
104        public ComparisonChain compareTrueFirst(boolean left, boolean right) {
105          return classify(Booleans.compare(right, left)); // reversed
106        }
107        
108        @Override
109        public ComparisonChain compareFalseFirst(boolean left, boolean right) {
110          return classify(Booleans.compare(left, right));
111        }
112        ComparisonChain classify(int result) {
113          return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
114        }
115        
116        @Override
117        public int result() {
118          return 0;
119        }
120      };
121    
122      private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
123    
124      private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
125    
126      private static final class InactiveComparisonChain extends ComparisonChain {
127        final int result;
128    
129        InactiveComparisonChain(int result) {
130          this.result = result;
131        }
132        
133        @Override
134        public ComparisonChain compare(
135            @Nullable Comparable left, @Nullable Comparable right) {
136          return this;
137        }
138        
139        @Override
140        public <T> ComparisonChain compare(@Nullable T left,
141            @Nullable T right, @Nullable Comparator<T> comparator) {
142          return this;
143        }
144        
145        @Override
146        public ComparisonChain compare(int left, int right) {
147          return this;
148        }
149        
150        @Override
151        public ComparisonChain compare(long left, long right) {
152          return this;
153        }
154        
155        @Override
156        public ComparisonChain compare(float left, float right) {
157          return this;
158        }
159        
160        @Override
161        public ComparisonChain compare(double left, double right) {
162          return this;
163        }
164        
165        @Override
166        public ComparisonChain compareTrueFirst(boolean left, boolean right) {
167          return this;
168        }
169        
170        @Override
171        public ComparisonChain compareFalseFirst(boolean left, boolean right) {
172          return this;
173        }
174        
175        @Override
176        public int result() {
177          return result;
178        }
179      }
180    
181      /**
182       * Compares two comparable objects as specified by {@link
183       * Comparable#compareTo}, <i>if</i> the result of this comparison chain
184       * has not already been determined.
185       */
186      public abstract ComparisonChain compare(
187          Comparable<?> left, Comparable<?> right);
188    
189      /**
190       * Compares two objects using a comparator, <i>if</i> the result of this
191       * comparison chain has not already been determined.
192       */
193      public abstract <T> ComparisonChain compare(
194          @Nullable T left, @Nullable T right, Comparator<T> comparator);
195    
196      /**
197       * Compares two {@code int} values as specified by {@link Ints#compare},
198       * <i>if</i> the result of this comparison chain has not already been
199       * determined.
200       */
201      public abstract ComparisonChain compare(int left, int right);
202    
203      /**
204       * Compares two {@code long} values as specified by {@link Longs#compare},
205       * <i>if</i> the result of this comparison chain has not already been
206       * determined.
207       */
208      public abstract ComparisonChain compare(long left, long right);
209    
210      /**
211       * Compares two {@code float} values as specified by {@link
212       * Float#compare}, <i>if</i> the result of this comparison chain has not
213       * already been determined.
214       */
215      public abstract ComparisonChain compare(float left, float right);
216    
217      /**
218       * Compares two {@code double} values as specified by {@link
219       * Double#compare}, <i>if</i> the result of this comparison chain has not
220       * already been determined.
221       */
222      public abstract ComparisonChain compare(double left, double right);
223    
224      /**
225       * Compares two {@code boolean} values, considering {@code true} to be less
226       * than {@code false}, <i>if</i> the result of this comparison chain has not
227       * already been determined.
228       *
229       * @since 12.0
230       */
231      public abstract ComparisonChain compareTrueFirst(boolean left, boolean right);
232    
233      /**
234       * Compares two {@code boolean} values, considering {@code false} to be less
235       * than {@code true}, <i>if</i> the result of this comparison chain has not
236       * already been determined.
237       *
238       * @since 12.0 (present as {@code compare} since 2.0)
239       */
240      public abstract ComparisonChain compareFalseFirst(boolean left, boolean right);
241    
242      /**
243       * Old name of {@link #compareFalseFirst}.
244       *
245       * @deprecated Use {@link #compareFalseFirst}; or, if the parameters passed
246       *     are being either negated or reversed, undo the negation or reversal and
247       *     use {@link #compareTrueFirst}. <b>This method is scheduled for deletion
248       *     in September 2013.</b>
249       */
250      @Deprecated
251      public final ComparisonChain compare(boolean left, boolean right) {
252        return compareFalseFirst(left, right);
253      }
254    
255      /**
256       * Ends this comparison chain and returns its result: a value having the
257       * same sign as the first nonzero comparison result in the chain, or zero if
258       * every result was zero.
259       */
260      public abstract int result();
261    }