001 /* 002 * Copyright (C) 2009 Google Inc. 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 * 032 * <pre class="code"> {@code 033 * 034 * public int compareTo(Foo that) { 035 * return ComparisonChain.start() 036 * .compare(this.aString, that.aString) 037 * .compare(this.anInt, that.anInt) 038 * .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast()) 039 * .result(); 040 * }}</pre> 041 * 042 * The value of this expression will have the same sign as the <i>first 043 * nonzero</i> comparison result in the chain, or will be zero if every 044 * comparison result was zero. 045 * 046 * <p>Once any comparison returns a nonzero value, remaining comparisons are 047 * "short-circuited". 048 * 049 * @author Mark Davis 050 * @author Kevin Bourrillion 051 * @since 2 052 */ 053 @GwtCompatible 054 public abstract class ComparisonChain { 055 private ComparisonChain() {} 056 057 /** 058 * Begins a new chained comparison statement. See example in the class 059 * documentation. 060 */ 061 public static ComparisonChain start() { 062 return ACTIVE; 063 } 064 065 private static final ComparisonChain ACTIVE = new ComparisonChain() { 066 @SuppressWarnings("unchecked") 067 @Override public ComparisonChain compare( 068 Comparable left, Comparable right) { 069 return classify(left.compareTo(right)); 070 } 071 @Override public <T> ComparisonChain compare( 072 @Nullable T left, @Nullable T right, Comparator<T> comparator) { 073 return classify(comparator.compare(left, right)); 074 } 075 @Override public ComparisonChain compare(int left, int right) { 076 return classify(Ints.compare(left, right)); 077 } 078 @Override public ComparisonChain compare(long left, long right) { 079 return classify(Longs.compare(left, right)); 080 } 081 @Override public ComparisonChain compare(float left, float right) { 082 return classify(Float.compare(left, right)); 083 } 084 @Override public ComparisonChain compare(double left, double right) { 085 return classify(Double.compare(left, right)); 086 } 087 @Override public ComparisonChain compare(boolean left, boolean right) { 088 return classify(Booleans.compare(left, right)); 089 } 090 ComparisonChain classify(int result) { 091 return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE; 092 } 093 @Override public int result() { 094 return 0; 095 } 096 }; 097 098 private static final ComparisonChain LESS = new InactiveComparisonChain(-1); 099 100 private static final ComparisonChain GREATER = new InactiveComparisonChain(1); 101 102 private static final class InactiveComparisonChain extends ComparisonChain { 103 final int result; 104 105 InactiveComparisonChain(int result) { 106 this.result = result; 107 } 108 @SuppressWarnings("unchecked") 109 @Override public ComparisonChain compare( 110 @Nullable Comparable left, @Nullable Comparable right) { 111 return this; 112 } 113 @Override public <T> ComparisonChain compare(@Nullable T left, 114 @Nullable T right, @Nullable Comparator<T> comparator) { 115 return this; 116 } 117 @Override public ComparisonChain compare(int left, int right) { 118 return this; 119 } 120 @Override public ComparisonChain compare(long left, long right) { 121 return this; 122 } 123 @Override public ComparisonChain compare(float left, float right) { 124 return this; 125 } 126 @Override public ComparisonChain compare(double left, double right) { 127 return this; 128 } 129 @Override public ComparisonChain compare(boolean left, boolean right) { 130 return this; 131 } 132 @Override public int result() { 133 return result; 134 } 135 } 136 137 /** 138 * Compares two comparable objects as specified by {@link 139 * Comparable#compareTo}, <i>if</i> the result of this comparison chain 140 * has not already been determined. 141 */ 142 public abstract ComparisonChain compare( 143 Comparable<?> left, Comparable<?> right); 144 145 /** 146 * Compares two objects using a comparator, <i>if</i> the result of this 147 * comparison chain has not already been determined. 148 */ 149 public abstract <T> ComparisonChain compare( 150 @Nullable T left, @Nullable T right, Comparator<T> comparator); 151 152 /** 153 * Compares two {@code int} values as specified by {@link Ints#compare}, 154 * <i>if</i> the result of this comparison chain has not already been 155 * determined. 156 */ 157 public abstract ComparisonChain compare(int left, int right); 158 159 /** 160 * Compares two {@code long} values as specified by {@link Longs#compare}, 161 * <i>if</i> the result of this comparison chain has not already been 162 * determined. 163 */ 164 public abstract ComparisonChain compare(long left, long right); 165 166 /** 167 * Compares two {@code float} values as specified by {@link 168 * Float#compare}, <i>if</i> the result of this comparison chain has not 169 * already been determined. 170 */ 171 public abstract ComparisonChain compare(float left, float right); 172 173 /** 174 * Compares two {@code double} values as specified by {@link 175 * Double#compare}, <i>if</i> the result of this comparison chain has not 176 * already been determined. 177 */ 178 public abstract ComparisonChain compare(double left, double right); 179 180 /** 181 * Compares two {@code boolean} values as specified by {@link 182 * Booleans#compare}, <i>if</i> the result of this comparison chain has not 183 * already been determined. 184 */ 185 public abstract ComparisonChain compare(boolean left, boolean right); 186 187 /** 188 * Ends this comparison chain and returns its result: a value having the 189 * same sign as the first nonzero comparison result in the chain, or zero if 190 * every result was zero. 191 */ 192 public abstract int result(); 193 }