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 017 package com.google.common.collect; 018 019 import com.google.common.annotations.GwtCompatible; 020 import com.google.common.primitives.Booleans; 021 import com.google.common.primitives.Ints; 022 import com.google.common.primitives.Longs; 023 024 import java.util.Comparator; 025 026 import javax.annotation.Nullable; 027 028 /** 029 * A utility for performing a "lazy" chained comparison statement, which 030 * performs comparisons only until it finds a nonzero result. 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 * 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>Once any comparison returns a nonzero value, remaining comparisons are 046 * "short-circuited". 047 * 048 * @author Mark Davis 049 * @author Kevin Bourrillion 050 * @since 2.0 051 */ 052 @GwtCompatible 053 public abstract class ComparisonChain { 054 private ComparisonChain() {} 055 056 /** 057 * Begins a new chained comparison statement. See example in the class 058 * documentation. 059 */ 060 public static ComparisonChain start() { 061 return ACTIVE; 062 } 063 064 private static final ComparisonChain ACTIVE = new ComparisonChain() { 065 @SuppressWarnings("unchecked") 066 @Override public ComparisonChain compare( 067 Comparable left, Comparable right) { 068 return classify(left.compareTo(right)); 069 } 070 @Override public <T> ComparisonChain compare( 071 @Nullable T left, @Nullable T right, Comparator<T> comparator) { 072 return classify(comparator.compare(left, right)); 073 } 074 @Override public ComparisonChain compare(int left, int right) { 075 return classify(Ints.compare(left, right)); 076 } 077 @Override public ComparisonChain compare(long left, long right) { 078 return classify(Longs.compare(left, right)); 079 } 080 @Override public ComparisonChain compare(float left, float right) { 081 return classify(Float.compare(left, right)); 082 } 083 @Override public ComparisonChain compare(double left, double right) { 084 return classify(Double.compare(left, right)); 085 } 086 @Override public ComparisonChain compare(boolean left, boolean right) { 087 return classify(Booleans.compare(left, right)); 088 } 089 ComparisonChain classify(int result) { 090 return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE; 091 } 092 @Override public int result() { 093 return 0; 094 } 095 }; 096 097 private static final ComparisonChain LESS = new InactiveComparisonChain(-1); 098 099 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 }