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 "lazy" chained comparison statement, which 30 * performs comparisons only until it finds a nonzero result. For example: 31 * <pre> {@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.natural().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 2.0 51 */ 52 @GwtCompatible 53 public abstract class ComparisonChain { 54 private ComparisonChain() {} 55 56 /** 57 * Begins a new chained comparison statement. See example in the class 58 * documentation. 59 */ 60 public static ComparisonChain start() { 61 return ACTIVE; 62 } 63 64 private static final ComparisonChain ACTIVE = new ComparisonChain() { 65 @SuppressWarnings("unchecked") 66 @Override public ComparisonChain compare( 67 Comparable left, Comparable right) { 68 return classify(left.compareTo(right)); 69 } 70 @Override public <T> ComparisonChain compare( 71 @Nullable T left, @Nullable T right, Comparator<T> comparator) { 72 return classify(comparator.compare(left, right)); 73 } 74 @Override public ComparisonChain compare(int left, int right) { 75 return classify(Ints.compare(left, right)); 76 } 77 @Override public ComparisonChain compare(long left, long right) { 78 return classify(Longs.compare(left, right)); 79 } 80 @Override public ComparisonChain compare(float left, float right) { 81 return classify(Float.compare(left, right)); 82 } 83 @Override public ComparisonChain compare(double left, double right) { 84 return classify(Double.compare(left, right)); 85 } 86 @Override public ComparisonChain compare(boolean left, boolean right) { 87 return classify(Booleans.compare(left, right)); 88 } 89 ComparisonChain classify(int result) { 90 return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE; 91 } 92 @Override public int result() { 93 return 0; 94 } 95 }; 96 97 private static final ComparisonChain LESS = new InactiveComparisonChain(-1); 98 99 private static final ComparisonChain GREATER = new InactiveComparisonChain(1); 100 101 private static final class InactiveComparisonChain extends ComparisonChain { 102 final int result; 103 104 InactiveComparisonChain(int result) { 105 this.result = result; 106 } 107 @Override public ComparisonChain compare( 108 @Nullable Comparable left, @Nullable Comparable right) { 109 return this; 110 } 111 @Override public <T> ComparisonChain compare(@Nullable T left, 112 @Nullable T right, @Nullable Comparator<T> comparator) { 113 return this; 114 } 115 @Override public ComparisonChain compare(int left, int right) { 116 return this; 117 } 118 @Override public ComparisonChain compare(long left, long right) { 119 return this; 120 } 121 @Override public ComparisonChain compare(float left, float right) { 122 return this; 123 } 124 @Override public ComparisonChain compare(double left, double right) { 125 return this; 126 } 127 @Override public ComparisonChain compare(boolean left, boolean right) { 128 return this; 129 } 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 190 public abstract int result(); 191 } 192