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