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