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