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 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 @SuppressWarnings("unchecked") 108 @Override public ComparisonChain compare( 109 @Nullable Comparable left, @Nullable Comparable right) { 110 return this; 111 } 112 @Override public <T> ComparisonChain compare(@Nullable T left, 113 @Nullable T right, @Nullable Comparator<T> comparator) { 114 return this; 115 } 116 @Override public ComparisonChain compare(int left, int right) { 117 return this; 118 } 119 @Override public ComparisonChain compare(long left, long right) { 120 return this; 121 } 122 @Override public ComparisonChain compare(float left, float right) { 123 return this; 124 } 125 @Override public ComparisonChain compare(double left, double right) { 126 return this; 127 } 128 @Override public ComparisonChain compare(boolean left, boolean right) { 129 return this; 130 } 131 @Override public int result() { 132 return result; 133 } 134 } 135 136 /** 137 * Compares two comparable objects as specified by {@link 138 * Comparable#compareTo}, <i>if</i> the result of this comparison chain 139 * has not already been determined. 140 */ 141 public abstract ComparisonChain compare( 142 Comparable<?> left, Comparable<?> right); 143 144 /** 145 * Compares two objects using a comparator, <i>if</i> the result of this 146 * comparison chain has not already been determined. 147 */ 148 public abstract <T> ComparisonChain compare( 149 @Nullable T left, @Nullable T right, Comparator<T> comparator); 150 151 /** 152 * Compares two {@code int} values as specified by {@link Ints#compare}, 153 * <i>if</i> the result of this comparison chain has not already been 154 * determined. 155 */ 156 public abstract ComparisonChain compare(int left, int right); 157 158 /** 159 * Compares two {@code long} values as specified by {@link Longs#compare}, 160 * <i>if</i> the result of this comparison chain has not already been 161 * determined. 162 */ 163 public abstract ComparisonChain compare(long left, long right); 164 165 /** 166 * Compares two {@code float} values as specified by {@link 167 * Float#compare}, <i>if</i> the result of this comparison chain has not 168 * already been determined. 169 */ 170 public abstract ComparisonChain compare(float left, float right); 171 172 /** 173 * Compares two {@code double} values as specified by {@link 174 * Double#compare}, <i>if</i> the result of this comparison chain has not 175 * already been determined. 176 */ 177 public abstract ComparisonChain compare(double left, double right); 178 179 /** 180 * Compares two {@code boolean} values as specified by {@link 181 * Booleans#compare}, <i>if</i> the result of this comparison chain has not 182 * already been determined. 183 */ 184 public abstract ComparisonChain compare(boolean left, boolean right); 185 186 /** 187 * Ends this comparison chain and returns its result: a value having the 188 * same sign as the first nonzero comparison result in the chain, or zero if 189 * every result was zero. 190 */ 191 public abstract int result(); 192 }