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 017package com.google.common.collect; 018 019import com.google.common.annotations.GwtCompatible; 020import com.google.common.primitives.Booleans; 021import com.google.common.primitives.Ints; 022import com.google.common.primitives.Longs; 023import java.util.Comparator; 024import javax.annotation.Nullable; 025 026/** 027 * A utility for performing a chained comparison statement. For example: 028 * <pre> {@code 029 * 030 * public int compareTo(Foo that) { 031 * return ComparisonChain.start() 032 * .compare(this.aString, that.aString) 033 * .compare(this.anInt, that.anInt) 034 * .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast()) 035 * .result(); 036 * }}</pre> 037 * 038 * <p>The value of this expression will have the same sign as the <i>first 039 * nonzero</i> comparison result in the chain, or will be zero if every 040 * comparison result was zero. 041 * 042 * <p><b>Note:</b> {@code ComparisonChain} instances are <b>immutable</b>. For 043 * this utility to work correctly, calls must be chained as illustrated above. 044 * 045 * <p>Performance note: Even though the {@code ComparisonChain} caller always 046 * invokes its {@code compare} methods unconditionally, the {@code 047 * ComparisonChain} implementation stops calling its inputs' {@link 048 * Comparable#compareTo compareTo} and {@link Comparator#compare compare} 049 * methods as soon as one of them returns a nonzero result. This optimization is 050 * typically important only in the presence of expensive {@code compareTo} and 051 * {@code compare} implementations. 052 * 053 * <p>See the Guava User Guide article on <a href= 054 * "https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained#comparecompareto"> 055 * {@code ComparisonChain}</a>. 056 * 057 * @author Mark Davis 058 * @author Kevin Bourrillion 059 * @since 2.0 060 */ 061@GwtCompatible 062public abstract class ComparisonChain { 063 private ComparisonChain() {} 064 065 /** 066 * Begins a new chained comparison statement. See example in the class 067 * documentation. 068 */ 069 public static ComparisonChain start() { 070 return ACTIVE; 071 } 072 073 private static final ComparisonChain ACTIVE = 074 new ComparisonChain() { 075 @SuppressWarnings("unchecked") 076 @Override 077 public ComparisonChain compare(Comparable left, Comparable right) { 078 return classify(left.compareTo(right)); 079 } 080 081 @Override 082 public <T> ComparisonChain compare( 083 @Nullable T left, @Nullable T right, Comparator<T> comparator) { 084 return classify(comparator.compare(left, right)); 085 } 086 087 @Override 088 public ComparisonChain compare(int left, int right) { 089 return classify(Ints.compare(left, right)); 090 } 091 092 @Override 093 public ComparisonChain compare(long left, long right) { 094 return classify(Longs.compare(left, right)); 095 } 096 097 @Override 098 public ComparisonChain compare(float left, float right) { 099 return classify(Float.compare(left, right)); 100 } 101 102 @Override 103 public ComparisonChain compare(double left, double right) { 104 return classify(Double.compare(left, right)); 105 } 106 107 @Override 108 public ComparisonChain compareTrueFirst(boolean left, boolean right) { 109 return classify(Booleans.compare(right, left)); // reversed 110 } 111 112 @Override 113 public ComparisonChain compareFalseFirst(boolean left, boolean right) { 114 return classify(Booleans.compare(left, right)); 115 } 116 117 ComparisonChain classify(int result) { 118 return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE; 119 } 120 121 @Override 122 public int result() { 123 return 0; 124 } 125 }; 126 127 private static final ComparisonChain LESS = new InactiveComparisonChain(-1); 128 129 private static final ComparisonChain GREATER = new InactiveComparisonChain(1); 130 131 private static final class InactiveComparisonChain extends ComparisonChain { 132 final int result; 133 134 InactiveComparisonChain(int result) { 135 this.result = result; 136 } 137 138 @Override 139 public ComparisonChain compare(@Nullable Comparable left, @Nullable Comparable right) { 140 return this; 141 } 142 143 @Override 144 public <T> ComparisonChain compare( 145 @Nullable T left, @Nullable T right, @Nullable Comparator<T> comparator) { 146 return this; 147 } 148 149 @Override 150 public ComparisonChain compare(int left, int right) { 151 return this; 152 } 153 154 @Override 155 public ComparisonChain compare(long left, long right) { 156 return this; 157 } 158 159 @Override 160 public ComparisonChain compare(float left, float right) { 161 return this; 162 } 163 164 @Override 165 public ComparisonChain compare(double left, double right) { 166 return this; 167 } 168 169 @Override 170 public ComparisonChain compareTrueFirst(boolean left, boolean right) { 171 return this; 172 } 173 174 @Override 175 public ComparisonChain compareFalseFirst(boolean left, boolean right) { 176 return this; 177 } 178 179 @Override 180 public int result() { 181 return result; 182 } 183 } 184 185 /** 186 * Compares two comparable objects as specified by {@link 187 * Comparable#compareTo}, <i>if</i> the result of this comparison chain 188 * has not already been determined. 189 */ 190 public abstract ComparisonChain compare(Comparable<?> left, Comparable<?> right); 191 192 /** 193 * Compares two objects using a comparator, <i>if</i> the result of this 194 * comparison chain has not already been determined. 195 */ 196 public abstract <T> ComparisonChain compare( 197 @Nullable T left, @Nullable T right, Comparator<T> comparator); 198 199 /** 200 * Compares two {@code int} values as specified by {@link Ints#compare}, 201 * <i>if</i> the result of this comparison chain has not already been 202 * determined. 203 */ 204 public abstract ComparisonChain compare(int left, int right); 205 206 /** 207 * Compares two {@code long} values as specified by {@link Longs#compare}, 208 * <i>if</i> the result of this comparison chain has not already been 209 * determined. 210 */ 211 public abstract ComparisonChain compare(long left, long right); 212 213 /** 214 * Compares two {@code float} values as specified by {@link 215 * Float#compare}, <i>if</i> the result of this comparison chain has not 216 * already been determined. 217 */ 218 public abstract ComparisonChain compare(float left, float right); 219 220 /** 221 * Compares two {@code double} values as specified by {@link 222 * Double#compare}, <i>if</i> the result of this comparison chain has not 223 * already been determined. 224 */ 225 public abstract ComparisonChain compare(double left, double right); 226 227 /** 228 * Discouraged synonym for {@link #compareFalseFirst}. 229 * 230 * @deprecated Use {@link #compareFalseFirst}; or, if the parameters passed 231 * are being either negated or reversed, undo the negation or reversal and 232 * use {@link #compareTrueFirst}. 233 * @since 19.0 234 */ 235 @Deprecated 236 public final ComparisonChain compare(Boolean left, Boolean right) { 237 return compareFalseFirst(left, right); 238 } 239 240 /** 241 * Compares two {@code boolean} values, considering {@code true} to be less 242 * than {@code false}, <i>if</i> the result of this comparison chain has not 243 * already been determined. 244 * 245 * @since 12.0 246 */ 247 public abstract ComparisonChain compareTrueFirst(boolean left, boolean right); 248 249 /** 250 * Compares two {@code boolean} values, considering {@code false} to be less 251 * than {@code true}, <i>if</i> the result of this comparison chain has not 252 * already been determined. 253 * 254 * @since 12.0 (present as {@code compare} since 2.0) 255 */ 256 public abstract ComparisonChain compareFalseFirst(boolean left, boolean right); 257 258 /** 259 * Ends this comparison chain and returns its result: a value having the 260 * same sign as the first nonzero comparison result in the chain, or zero if 261 * every result was zero. 262 */ 263 public abstract int result(); 264}