• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Google Inc.
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.primitives.Booleans;
20 import com.google.common.primitives.Ints;
21 import com.google.common.primitives.Longs;
22 
23 import java.util.Comparator;
24 
25 import javax.annotation.Nullable;
26 
27 /**
28  * A utility for performing a "lazy" chained comparison statement, which
29  * performs comparisons only until it finds a nonzero result. For example:
30  *
31  * <pre class="code">   {@code
32  *
33  *   public int compareTo(Foo that) {
34  *     return ComparisonChain.start()
35  *         .compare(this.aString, that.aString)
36  *         .compare(this.anInt, that.anInt)
37  *         .compare(this.anEnum, that.anEnum, Ordering.nullsLast())
38  *         .result();
39  *   }}</pre>
40  *
41  * The value of this expression will have the same sign as the <i>first
42  * nonzero</i> comparison result in the chain, or will be zero if every
43  * comparison result was zero.
44  *
45  * <p>Once any comparison returns a nonzero value, remaining comparisons are
46  * "short-circuited".
47  *
48  * @author Mark Davis
49  * @author Kevin Bourrillion
50  * @since 2010.01.04 <b>tentative</b>
51  */
52 public abstract class ComparisonChain {
ComparisonChain()53   private ComparisonChain() {}
54 
55   /**
56    * Begins a new chained comparison statement. See example in the class
57    * documentation.
58    */
start()59   public static ComparisonChain start() {
60     return ACTIVE;
61   }
62 
63   private static final ComparisonChain ACTIVE = new ComparisonChain() {
64     @SuppressWarnings("unchecked")
65     @Override public ComparisonChain compare(
66         Comparable left, Comparable right) {
67       return classify(left.compareTo(right));
68     }
69     @Override public <T> ComparisonChain compare(
70         @Nullable T left, @Nullable T right, Comparator<T> comparator) {
71       return classify(comparator.compare(left, right));
72     }
73     @Override public ComparisonChain compare(int left, int right) {
74       return classify(Ints.compare(left, right));
75     }
76     @Override public ComparisonChain compare(long left, long right) {
77       return classify(Longs.compare(left, right));
78     }
79     @Override public ComparisonChain compare(float left, float right) {
80       return classify(Float.compare(left, right));
81     }
82     @Override public ComparisonChain compare(double left, double right) {
83       return classify(Double.compare(left, right));
84     }
85     @Override public ComparisonChain compare(boolean left, boolean right) {
86       return classify(Booleans.compare(left, right));
87     }
88     ComparisonChain classify(int result) {
89       return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
90     }
91     @Override public int result() {
92       return 0;
93     }
94   };
95 
96   private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
97 
98   private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
99 
100   private static final class InactiveComparisonChain extends ComparisonChain {
101     final int result;
102 
InactiveComparisonChain(int result)103     InactiveComparisonChain(int result) {
104       this.result = result;
105     }
106     @SuppressWarnings("unchecked")
compare( @ullable Comparable left, @Nullable Comparable right)107     @Override public ComparisonChain compare(
108         @Nullable Comparable left, @Nullable Comparable right) {
109       return this;
110     }
compare(@ullable T left, @Nullable T right, @Nullable Comparator<T> comparator)111     @Override public <T> ComparisonChain compare(@Nullable T left,
112         @Nullable T right, @Nullable Comparator<T> comparator) {
113       return this;
114     }
compare(int left, int right)115     @Override public ComparisonChain compare(int left, int right) {
116       return this;
117     }
compare(long left, long right)118     @Override public ComparisonChain compare(long left, long right) {
119       return this;
120     }
compare(float left, float right)121     @Override public ComparisonChain compare(float left, float right) {
122       return this;
123     }
compare(double left, double right)124     @Override public ComparisonChain compare(double left, double right) {
125       return this;
126     }
compare(boolean left, boolean right)127     @Override public ComparisonChain compare(boolean left, boolean right) {
128       return this;
129     }
result()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    */
compare( Comparable<?> left, Comparable<?> right)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    */
compare( @ullable T left, @Nullable T right, Comparator<T> comparator)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    */
compare(int left, int right)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    */
compare(long left, long right)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    */
compare(float left, float right)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    */
compare(double left, double right)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    */
compare(boolean left, boolean right)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    */
result()190   public abstract int result();
191 }
192