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