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