• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.primitives.Booleans;
21 import com.google.common.primitives.Ints;
22 import com.google.common.primitives.Longs;
23 
24 import java.util.Comparator;
25 
26 import javax.annotation.Nullable;
27 
28 /**
29  * A utility for performing a chained comparison statement. For example:
30  * <pre>   {@code
31  *
32  *   public int compareTo(Foo that) {
33  *     return ComparisonChain.start()
34  *         .compare(this.aString, that.aString)
35  *         .compare(this.anInt, that.anInt)
36  *         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
37  *         .result();
38  *   }}</pre>
39  *
40  * <p>The value of this expression will have the same sign as the <i>first
41  * nonzero</i> comparison result in the chain, or will be zero if every
42  * comparison result was zero.
43  *
44  * <p>Performance note: Even though the {@code ComparisonChain} caller always
45  * invokes its {@code compare} methods unconditionally, the {@code
46  * ComparisonChain} implementation stops calling its inputs' {@link
47  * Comparable#compareTo compareTo} and {@link Comparator#compare compare}
48  * methods as soon as one of them returns a nonzero result. This optimization is
49  * typically important only in the presence of expensive {@code compareTo} and
50  * {@code compare} implementations.
51  *
52  * <p>See the Guava User Guide article on <a href=
53  * "http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained#compare/compareTo">
54  * {@code ComparisonChain}</a>.
55  *
56  * @author Mark Davis
57  * @author Kevin Bourrillion
58  * @since 2.0
59  */
60 @GwtCompatible
61 public abstract class ComparisonChain {
ComparisonChain()62   private ComparisonChain() {}
63 
64   /**
65    * Begins a new chained comparison statement. See example in the class
66    * documentation.
67    */
start()68   public static ComparisonChain start() {
69     return ACTIVE;
70   }
71 
72   private static final ComparisonChain ACTIVE = new ComparisonChain() {
73     @SuppressWarnings("unchecked")
74     @Override public ComparisonChain compare(
75         Comparable left, Comparable right) {
76       return classify(left.compareTo(right));
77     }
78     @Override public <T> ComparisonChain compare(
79         @Nullable T left, @Nullable T right, Comparator<T> comparator) {
80       return classify(comparator.compare(left, right));
81     }
82     @Override public ComparisonChain compare(int left, int right) {
83       return classify(Ints.compare(left, right));
84     }
85     @Override public ComparisonChain compare(long left, long right) {
86       return classify(Longs.compare(left, right));
87     }
88     @Override public ComparisonChain compare(float left, float right) {
89       return classify(Float.compare(left, right));
90     }
91     @Override public ComparisonChain compare(double left, double right) {
92       return classify(Double.compare(left, right));
93     }
94     @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
95       return classify(Booleans.compare(right, left)); // reversed
96     }
97     @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
98       return classify(Booleans.compare(left, right));
99     }
100     ComparisonChain classify(int result) {
101       return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
102     }
103     @Override public int result() {
104       return 0;
105     }
106   };
107 
108   private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
109 
110   private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
111 
112   private static final class InactiveComparisonChain extends ComparisonChain {
113     final int result;
114 
InactiveComparisonChain(int result)115     InactiveComparisonChain(int result) {
116       this.result = result;
117     }
compare( @ullable Comparable left, @Nullable Comparable right)118     @Override public ComparisonChain compare(
119         @Nullable Comparable left, @Nullable Comparable right) {
120       return this;
121     }
compare(@ullable T left, @Nullable T right, @Nullable Comparator<T> comparator)122     @Override public <T> ComparisonChain compare(@Nullable T left,
123         @Nullable T right, @Nullable Comparator<T> comparator) {
124       return this;
125     }
compare(int left, int right)126     @Override public ComparisonChain compare(int left, int right) {
127       return this;
128     }
compare(long left, long right)129     @Override public ComparisonChain compare(long left, long right) {
130       return this;
131     }
compare(float left, float right)132     @Override public ComparisonChain compare(float left, float right) {
133       return this;
134     }
compare(double left, double right)135     @Override public ComparisonChain compare(double left, double right) {
136       return this;
137     }
compareTrueFirst(boolean left, boolean right)138     @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
139       return this;
140     }
compareFalseFirst(boolean left, boolean right)141     @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
142       return this;
143     }
result()144     @Override public int result() {
145       return result;
146     }
147   }
148 
149   /**
150    * Compares two comparable objects as specified by {@link
151    * Comparable#compareTo}, <i>if</i> the result of this comparison chain
152    * has not already been determined.
153    */
compare( Comparable<?> left, Comparable<?> right)154   public abstract ComparisonChain compare(
155       Comparable<?> left, Comparable<?> right);
156 
157   /**
158    * Compares two objects using a comparator, <i>if</i> the result of this
159    * comparison chain has not already been determined.
160    */
compare( @ullable T left, @Nullable T right, Comparator<T> comparator)161   public abstract <T> ComparisonChain compare(
162       @Nullable T left, @Nullable T right, Comparator<T> comparator);
163 
164   /**
165    * Compares two {@code int} values as specified by {@link Ints#compare},
166    * <i>if</i> the result of this comparison chain has not already been
167    * determined.
168    */
compare(int left, int right)169   public abstract ComparisonChain compare(int left, int right);
170 
171   /**
172    * Compares two {@code long} values as specified by {@link Longs#compare},
173    * <i>if</i> the result of this comparison chain has not already been
174    * determined.
175    */
compare(long left, long right)176   public abstract ComparisonChain compare(long left, long right);
177 
178   /**
179    * Compares two {@code float} values as specified by {@link
180    * Float#compare}, <i>if</i> the result of this comparison chain has not
181    * already been determined.
182    */
compare(float left, float right)183   public abstract ComparisonChain compare(float left, float right);
184 
185   /**
186    * Compares two {@code double} values as specified by {@link
187    * Double#compare}, <i>if</i> the result of this comparison chain has not
188    * already been determined.
189    */
compare(double left, double right)190   public abstract ComparisonChain compare(double left, double right);
191 
192   /**
193    * Compares two {@code boolean} values, considering {@code true} to be less
194    * than {@code false}, <i>if</i> the result of this comparison chain has not
195    * already been determined.
196    *
197    * @since 12.0
198    */
compareTrueFirst(boolean left, boolean right)199   public abstract ComparisonChain compareTrueFirst(boolean left, boolean right);
200 
201   /**
202    * Compares two {@code boolean} values, considering {@code false} to be less
203    * than {@code true}, <i>if</i> the result of this comparison chain has not
204    * already been determined.
205    *
206    * @since 12.0 (present as {@code compare} since 2.0)
207    */
compareFalseFirst(boolean left, boolean right)208   public abstract ComparisonChain compareFalseFirst(boolean left, boolean right);
209 
210   /**
211    * Ends this comparison chain and returns its result: a value having the
212    * same sign as the first nonzero comparison result in the chain, or zero if
213    * every result was zero.
214    */
result()215   public abstract int result();
216 }
217