001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.lang.math; 018 019 import org.apache.commons.lang.text.StrBuilder; 020 021 /** 022 * <p><code>Range</code> represents a range of numbers of the same type.</p> 023 * 024 * <p>Specific subclasses hold the range values as different types. Each 025 * subclass should be immutable and {@link java.io.Serializable Serializable} 026 * if possible.</p> 027 * 028 * @author Apache Software Foundation 029 * @since 2.0 030 * @version $Id: Range.java 1057072 2011-01-10 01:55:57Z niallp $ 031 */ 032 public abstract class Range { 033 034 /** 035 * <p>Constructs a new range.</p> 036 */ 037 public Range() { 038 super(); 039 } 040 041 // Accessors 042 //-------------------------------------------------------------------- 043 044 /** 045 * <p>Gets the minimum number in this range.</p> 046 * 047 * @return the minimum number in this range 048 */ 049 public abstract Number getMinimumNumber(); 050 051 /** 052 * <p>Gets the minimum number in this range as a <code>long</code>.</p> 053 * 054 * <p>This implementation uses the {@link #getMinimumNumber()} method. 055 * Subclasses may be able to optimise this.</p> 056 * 057 * @return the minimum number in this range 058 */ 059 public long getMinimumLong() { 060 return getMinimumNumber().longValue(); 061 } 062 063 /** 064 * <p>Gets the minimum number in this range as a <code>int</code>.</p> 065 * 066 * <p>This implementation uses the {@link #getMinimumNumber()} method. 067 * Subclasses may be able to optimise this.</p> 068 * 069 * @return the minimum number in this range 070 */ 071 public int getMinimumInteger() { 072 return getMinimumNumber().intValue(); 073 } 074 075 /** 076 * <p>Gets the minimum number in this range as a <code>double</code>.</p> 077 * 078 * <p>This implementation uses the {@link #getMinimumNumber()} method. 079 * Subclasses may be able to optimise this.</p> 080 * 081 * @return the minimum number in this range 082 */ 083 public double getMinimumDouble() { 084 return getMinimumNumber().doubleValue(); 085 } 086 087 /** 088 * <p>Gets the minimum number in this range as a <code>float</code>.</p> 089 * 090 * <p>This implementation uses the {@link #getMinimumNumber()} method. 091 * Subclasses may be able to optimise this.</p> 092 * 093 * @return the minimum number in this range 094 */ 095 public float getMinimumFloat() { 096 return getMinimumNumber().floatValue(); 097 } 098 099 /** 100 * <p>Gets the maximum number in this range.</p> 101 * 102 * @return the maximum number in this range 103 */ 104 public abstract Number getMaximumNumber(); 105 106 /** 107 * <p>Gets the maximum number in this range as a <code>long</code>.</p> 108 * 109 * <p>This implementation uses the {@link #getMaximumNumber()} method. 110 * Subclasses may be able to optimise this.</p> 111 * 112 * @return the maximum number in this range 113 */ 114 public long getMaximumLong() { 115 return getMaximumNumber().longValue(); 116 } 117 118 /** 119 * <p>Gets the maximum number in this range as a <code>int</code>.</p> 120 * 121 * <p>This implementation uses the {@link #getMaximumNumber()} method. 122 * Subclasses may be able to optimise this.</p> 123 * 124 * @return the maximum number in this range 125 */ 126 public int getMaximumInteger() { 127 return getMaximumNumber().intValue(); 128 } 129 130 /** 131 * <p>Gets the maximum number in this range as a <code>double</code>.</p> 132 * 133 * <p>This implementation uses the {@link #getMaximumNumber()} method. 134 * Subclasses may be able to optimise this.</p> 135 * 136 * @return the maximum number in this range 137 */ 138 public double getMaximumDouble() { 139 return getMaximumNumber().doubleValue(); 140 } 141 142 /** 143 * <p>Gets the maximum number in this range as a <code>float</code>.</p> 144 * 145 * <p>This implementation uses the {@link #getMaximumNumber()} method. 146 * Subclasses may be able to optimise this.</p> 147 * 148 * @return the maximum number in this range 149 */ 150 public float getMaximumFloat() { 151 return getMaximumNumber().floatValue(); 152 } 153 154 // Include tests 155 //-------------------------------------------------------------------- 156 157 /** 158 * <p>Tests whether the specified <code>Number</code> occurs within 159 * this range.</p> 160 * 161 * <p>The exact comparison implementation varies by subclass. It is 162 * intended that an <code>int</code> specific subclass will compare using 163 * <code>int</code> comparison.</p> 164 * 165 * <p><code>null</code> is handled and returns <code>false</code>.</p> 166 * 167 * @param number the number to test, may be <code>null</code> 168 * @return <code>true</code> if the specified number occurs within this range 169 * @throws IllegalArgumentException if the <code>Number</code> cannot be compared 170 */ 171 public abstract boolean containsNumber(Number number); 172 173 /** 174 * <p>Tests whether the specified <code>Number</code> occurs within 175 * this range using <code>long</code> comparison..</p> 176 * 177 * <p><code>null</code> is handled and returns <code>false</code>.</p> 178 * 179 * <p>This implementation forwards to the {@link #containsLong(long)} method.</p> 180 * 181 * @param value the long to test, may be <code>null</code> 182 * @return <code>true</code> if the specified number occurs within this 183 * range by <code>long</code> comparison 184 */ 185 public boolean containsLong(Number value) { 186 if (value == null) { 187 return false; 188 } 189 return containsLong(value.longValue()); 190 } 191 192 /** 193 * <p>Tests whether the specified <code>long</code> occurs within 194 * this range using <code>long</code> comparison.</p> 195 * 196 * <p>This implementation uses the {@link #getMinimumLong()} and 197 * {@link #getMaximumLong()} methods and should be good for most uses.</p> 198 * 199 * @param value the long to test 200 * @return <code>true</code> if the specified number occurs within this 201 * range by <code>long</code> comparison 202 */ 203 public boolean containsLong(long value) { 204 return value >= getMinimumLong() && value <= getMaximumLong(); 205 } 206 207 /** 208 * <p>Tests whether the specified <code>Number</code> occurs within 209 * this range using <code>int</code> comparison..</p> 210 * 211 * <p><code>null</code> is handled and returns <code>false</code>.</p> 212 * 213 * <p>This implementation forwards to the {@link #containsInteger(int)} method.</p> 214 * 215 * @param value the integer to test, may be <code>null</code> 216 * @return <code>true</code> if the specified number occurs within this 217 * range by <code>int</code> comparison 218 */ 219 public boolean containsInteger(Number value) { 220 if (value == null) { 221 return false; 222 } 223 return containsInteger(value.intValue()); 224 } 225 226 /** 227 * <p>Tests whether the specified <code>int</code> occurs within 228 * this range using <code>int</code> comparison.</p> 229 * 230 * <p>This implementation uses the {@link #getMinimumInteger()} and 231 * {@link #getMaximumInteger()} methods and should be good for most uses.</p> 232 * 233 * @param value the int to test 234 * @return <code>true</code> if the specified number occurs within this 235 * range by <code>int</code> comparison 236 */ 237 public boolean containsInteger(int value) { 238 return value >= getMinimumInteger() && value <= getMaximumInteger(); 239 } 240 241 /** 242 * <p>Tests whether the specified <code>Number</code> occurs within 243 * this range using <code>double</code> comparison..</p> 244 * 245 * <p><code>null</code> is handled and returns <code>false</code>.</p> 246 * 247 * <p>This implementation forwards to the {@link #containsDouble(double)} method.</p> 248 * 249 * @param value the double to test, may be <code>null</code> 250 * @return <code>true</code> if the specified number occurs within this 251 * range by <code>double</code> comparison 252 */ 253 public boolean containsDouble(Number value) { 254 if (value == null) { 255 return false; 256 } 257 return containsDouble(value.doubleValue()); 258 } 259 260 /** 261 * <p>Tests whether the specified <code>double</code> occurs within 262 * this range using <code>double</code> comparison.</p> 263 * 264 * <p>This implementation uses the {@link #getMinimumDouble()} and 265 * {@link #getMaximumDouble()} methods and should be good for most uses.</p> 266 * 267 * @param value the double to test 268 * @return <code>true</code> if the specified number occurs within this 269 * range by <code>double</code> comparison 270 */ 271 public boolean containsDouble(double value) { 272 int compareMin = NumberUtils.compare(getMinimumDouble(), value); 273 int compareMax = NumberUtils.compare(getMaximumDouble(), value); 274 return compareMin <= 0 && compareMax >= 0; 275 } 276 277 /** 278 * <p>Tests whether the specified <code>Number</code> occurs within 279 * this range using <code>float</code> comparison.</p> 280 * 281 * <p><code>null</code> is handled and returns <code>false</code>.</p> 282 * 283 * <p>This implementation forwards to the {@link #containsFloat(float)} method.</p> 284 * 285 * @param value the float to test, may be <code>null</code> 286 * @return <code>true</code> if the specified number occurs within this 287 * range by <code>float</code> comparison 288 */ 289 public boolean containsFloat(Number value) { 290 if (value == null) { 291 return false; 292 } 293 return containsFloat(value.floatValue()); 294 } 295 296 /** 297 * <p>Tests whether the specified <code>float</code> occurs within 298 * this range using <code>float</code> comparison.</p> 299 * 300 * <p>This implementation uses the {@link #getMinimumFloat()} and 301 * {@link #getMaximumFloat()} methods and should be good for most uses.</p> 302 * 303 * @param value the float to test 304 * @return <code>true</code> if the specified number occurs within this 305 * range by <code>float</code> comparison 306 */ 307 public boolean containsFloat(float value) { 308 int compareMin = NumberUtils.compare(getMinimumFloat(), value); 309 int compareMax = NumberUtils.compare(getMaximumFloat(), value); 310 return compareMin <= 0 && compareMax >= 0; 311 } 312 313 // Range tests 314 //-------------------------------------------------------------------- 315 316 /** 317 * <p>Tests whether the specified range occurs entirely within this range.</p> 318 * 319 * <p>The exact comparison implementation varies by subclass. It is 320 * intended that an <code>int</code> specific subclass will compare using 321 * <code>int</code> comparison.</p> 322 * 323 * <p><code>null</code> is handled and returns <code>false</code>.</p> 324 * 325 * <p>This implementation uses the {@link #containsNumber(Number)} method. 326 * Subclasses may be able to optimise this.</p> 327 * 328 * @param range the range to test, may be <code>null</code> 329 * @return <code>true</code> if the specified range occurs entirely within 330 * this range; otherwise, <code>false</code> 331 * @throws IllegalArgumentException if the <code>Range</code> cannot be compared 332 */ 333 public boolean containsRange(Range range) { 334 if (range == null) { 335 return false; 336 } 337 return containsNumber(range.getMinimumNumber()) 338 && containsNumber(range.getMaximumNumber()); 339 } 340 341 /** 342 * <p>Tests whether the specified range overlaps with this range.</p> 343 * 344 * <p>The exact comparison implementation varies by subclass. It is 345 * intended that an <code>int</code> specific subclass will compare using 346 * <code>int</code> comparison.</p> 347 * 348 * <p><code>null</code> is handled and returns <code>false</code>.</p> 349 * 350 * <p>This implementation uses the {@link #containsNumber(Number)} and 351 * {@link #containsRange(Range)} methods. 352 * Subclasses may be able to optimise this.</p> 353 * 354 * @param range the range to test, may be <code>null</code> 355 * @return <code>true</code> if the specified range overlaps with this 356 * range; otherwise, <code>false</code> 357 * @throws IllegalArgumentException if the <code>Range</code> cannot be compared 358 */ 359 public boolean overlapsRange(Range range) { 360 if (range == null) { 361 return false; 362 } 363 return range.containsNumber(getMinimumNumber()) 364 || range.containsNumber(getMaximumNumber()) 365 || containsNumber(range.getMinimumNumber()); 366 } 367 368 // Basics 369 //-------------------------------------------------------------------- 370 371 /** 372 * <p>Compares this range to another object to test if they are equal.</p>. 373 * 374 * <p>To be equal, the class, minimum and maximum must be equal.</p> 375 * 376 * <p>This implementation uses the {@link #getMinimumNumber()} and 377 * {@link #getMaximumNumber()} methods. 378 * Subclasses may be able to optimise this.</p> 379 * 380 * @param obj the reference object with which to compare 381 * @return <code>true</code> if this object is equal 382 */ 383 public boolean equals(Object obj) { 384 if (obj == this) { 385 return true; 386 } else if (obj == null || obj.getClass() != getClass()) { 387 return false; 388 } else { 389 Range range = (Range) obj; 390 return getMinimumNumber().equals(range.getMinimumNumber()) && 391 getMaximumNumber().equals(range.getMaximumNumber()); 392 } 393 } 394 395 /** 396 * <p>Gets a hashCode for the range.</p> 397 * 398 * <p>This implementation uses the {@link #getMinimumNumber()} and 399 * {@link #getMaximumNumber()} methods. 400 * Subclasses may be able to optimise this.</p> 401 * 402 * @return a hash code value for this object 403 */ 404 public int hashCode() { 405 int result = 17; 406 result = 37 * result + getClass().hashCode(); 407 result = 37 * result + getMinimumNumber().hashCode(); 408 result = 37 * result + getMaximumNumber().hashCode(); 409 return result; 410 } 411 412 /** 413 * <p>Gets the range as a <code>String</code>.</p> 414 * 415 * <p>The format of the String is 'Range[<i>min</i>,<i>max</i>]'.</p> 416 * 417 * <p>This implementation uses the {@link #getMinimumNumber()} and 418 * {@link #getMaximumNumber()} methods. 419 * Subclasses may be able to optimise this.</p> 420 * 421 * @return the <code>String</code> representation of this range 422 */ 423 public String toString() { 424 StrBuilder buf = new StrBuilder(32); 425 buf.append("Range["); 426 buf.append(getMinimumNumber()); 427 buf.append(','); 428 buf.append(getMaximumNumber()); 429 buf.append(']'); 430 return buf.toString(); 431 } 432 433 }