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 Stephen Colebourne
025: * @since 2.0
026: * @version $Id: LongRange.java 437554 2006-08-28 06:21:41Z bayard $
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(
087: "The number must not be null");
088: }
089: this .min = number.longValue();
090: this .max = number.longValue();
091: if (number instanceof Long) {
092: this .minObject = (Long) number;
093: this .maxObject = (Long) number;
094: }
095: }
096:
097: /**
098: * <p>Constructs a new <code>LongRange</code> with the specified
099: * minimum and maximum numbers (both inclusive).</p>
100: *
101: * <p>The arguments may be passed in the order (min,max) or (max,min). The
102: * getMinimum and getMaximum methods will return the correct values.</p>
103: *
104: * @param number1 first number that defines the edge of the range, inclusive
105: * @param number2 second number that defines the edge of the range, inclusive
106: */
107: public LongRange(long number1, long number2) {
108: super ();
109: if (number2 < number1) {
110: this .min = number2;
111: this .max = number1;
112: } else {
113: this .min = number1;
114: this .max = number2;
115: }
116: }
117:
118: /**
119: * <p>Constructs a new <code>LongRange</code> with the specified
120: * minimum and maximum numbers (both inclusive).</p>
121: *
122: * <p>The arguments may be passed in the order (min,max) or (max,min). The
123: * getMinimum and getMaximum methods will return the correct values.</p>
124: *
125: * @param number1 first number that defines the edge of the range, inclusive
126: * @param number2 second number that defines the edge of the range, inclusive
127: * @throws IllegalArgumentException if either number is <code>null</code>
128: */
129: public LongRange(Number number1, Number number2) {
130: super ();
131: if (number1 == null || number2 == null) {
132: throw new IllegalArgumentException(
133: "The numbers must not be null");
134: }
135: long number1val = number1.longValue();
136: long number2val = number2.longValue();
137: if (number2val < number1val) {
138: this .min = number2val;
139: this .max = number1val;
140: if (number2 instanceof Long) {
141: this .minObject = (Long) number2;
142: }
143: if (number1 instanceof Long) {
144: this .maxObject = (Long) number1;
145: }
146: } else {
147: this .min = number1val;
148: this .max = number2val;
149: if (number1 instanceof Long) {
150: this .minObject = (Long) number1;
151: }
152: if (number2 instanceof Long) {
153: this .maxObject = (Long) number2;
154: }
155: }
156: }
157:
158: // Accessors
159: //--------------------------------------------------------------------
160:
161: /**
162: * <p>Returns the minimum number in this range.</p>
163: *
164: * @return the minimum number in this range
165: */
166: public Number getMinimumNumber() {
167: if (minObject == null) {
168: minObject = new Long(min);
169: }
170: return minObject;
171: }
172:
173: /**
174: * <p>Gets the minimum number in this range as a <code>long</code>.</p>
175: *
176: * @return the minimum number in this range
177: */
178: public long getMinimumLong() {
179: return min;
180: }
181:
182: /**
183: * <p>Gets the minimum number in this range as a <code>int</code>.</p>
184: *
185: * <p>This conversion can lose information for large values.</p>
186: *
187: * @return the minimum number in this range
188: */
189: public int getMinimumInteger() {
190: return (int) min;
191: }
192:
193: /**
194: * <p>Gets the minimum number in this range as a <code>double</code>.</p>
195: *
196: * <p>This conversion can lose information for large values.</p>
197: *
198: * @return the minimum number in this range
199: */
200: public double getMinimumDouble() {
201: return min;
202: }
203:
204: /**
205: * <p>Gets the minimum number in this range as a <code>float</code>.</p>
206: *
207: * <p>This conversion can lose information for large values.</p>
208: *
209: * @return the minimum number in this range
210: */
211: public float getMinimumFloat() {
212: return min;
213: }
214:
215: /**
216: * <p>Returns the maximum number in this range.</p>
217: *
218: * @return the maximum number in this range
219: */
220: public Number getMaximumNumber() {
221: if (maxObject == null) {
222: maxObject = new Long(max);
223: }
224: return maxObject;
225: }
226:
227: /**
228: * <p>Gets the maximum number in this range as a <code>long</code>.</p>
229: *
230: * @return the maximum number in this range
231: */
232: public long getMaximumLong() {
233: return max;
234: }
235:
236: /**
237: * <p>Gets the maximum number in this range cast to an <code>int</code>.</p>
238: *
239: * <p>This conversion can lose information for large values.</p>
240: *
241: * @return the maximum number in this range cast to an <code>int</code>.
242: */
243: public int getMaximumInteger() {
244: return (int) max;
245: }
246:
247: /**
248: * <p>Gets the maximum number in this range as a <code>double</code>.</p>
249: *
250: * <p>This conversion can lose information for large values.</p>
251: *
252: * @return The maximum number in this range as a <code>double</code>.
253: */
254: public double getMaximumDouble() {
255: return max;
256: }
257:
258: /**
259: * <p>Gets the maximum number in this range as a <code>float</code>.</p>
260: *
261: * <p>This conversion can lose information for large values.</p>
262: *
263: * @return The maximum number in this range as a <code>float</code>.
264: */
265: public float getMaximumFloat() {
266: return max;
267: }
268:
269: // Tests
270: //--------------------------------------------------------------------
271:
272: /**
273: * <p>Tests whether the specified <code>number</code> occurs within
274: * this range using <code>long</code> comparison.</p>
275: *
276: * <p><code>null</code> is handled and returns <code>false</code>.</p>
277: *
278: * @param number the number to test, may be <code>null</code>
279: * @return <code>true</code> if the specified number occurs within this range
280: */
281: public boolean containsNumber(Number number) {
282: if (number == null) {
283: return false;
284: }
285: return containsLong(number.longValue());
286: }
287:
288: /**
289: * <p>Tests whether the specified <code>long</code> occurs within
290: * this range using <code>long</code> comparison.</p>
291: *
292: * <p>This implementation overrides the superclass for performance as it is
293: * the most common case.</p>
294: *
295: * @param value the long to test
296: * @return <code>true</code> if the specified number occurs within this
297: * range by <code>long</code> comparison
298: */
299: public boolean containsLong(long value) {
300: return value >= min && value <= max;
301: }
302:
303: // Range tests
304: //--------------------------------------------------------------------
305:
306: /**
307: * <p>Tests whether the specified range occurs entirely within this range
308: * using <code>long</code> comparison.</p>
309: *
310: * <p><code>null</code> is handled and returns <code>false</code>.</p>
311: *
312: * @param range the range to test, may be <code>null</code>
313: * @return <code>true</code> if the specified range occurs entirely within this range
314: * @throws IllegalArgumentException if the range is not of this type
315: */
316: public boolean containsRange(Range range) {
317: if (range == null) {
318: return false;
319: }
320: return containsLong(range.getMinimumLong())
321: && containsLong(range.getMaximumLong());
322: }
323:
324: /**
325: * <p>Tests whether the specified range overlaps with this range
326: * using <code>long</code> comparison.</p>
327: *
328: * <p><code>null</code> is handled and returns <code>false</code>.</p>
329: *
330: * @param range the range to test, may be <code>null</code>
331: * @return <code>true</code> if the specified range overlaps with this range
332: */
333: public boolean overlapsRange(Range range) {
334: if (range == null) {
335: return false;
336: }
337: return range.containsLong(min) || range.containsLong(max)
338: || containsLong(range.getMinimumLong());
339: }
340:
341: // Basics
342: //--------------------------------------------------------------------
343:
344: /**
345: * <p>Compares this range to another object to test if they are equal.</p>.
346: *
347: * <p>To be equal, the class, minimum and maximum must be equal.</p>
348: *
349: * @param obj the reference object with which to compare
350: * @return <code>true</code> if this object is equal
351: */
352: public boolean equals(Object obj) {
353: if (obj == this ) {
354: return true;
355: }
356: if (obj instanceof LongRange == false) {
357: return false;
358: }
359: LongRange range = (LongRange) obj;
360: return min == range.min && max == range.max;
361: }
362:
363: /**
364: * <p>Gets a hashCode for the range.</p>
365: *
366: * @return a hash code value for this object
367: */
368: public int hashCode() {
369: if (hashCode == 0) {
370: hashCode = 17;
371: hashCode = 37 * hashCode + getClass().hashCode();
372: hashCode = 37 * hashCode + ((int) (min ^ (min >> 32)));
373: hashCode = 37 * hashCode + ((int) (max ^ (max >> 32)));
374: }
375: return hashCode;
376: }
377:
378: /**
379: * <p>Gets the range as a <code>String</code>.</p>
380: *
381: * <p>The format of the String is 'Range[<i>min</i>,<i>max</i>]'.</p>
382: *
383: * @return the <code>String</code> representation of this range
384: */
385: public String toString() {
386: if (toString == null) {
387: StringBuffer buf = new StringBuffer(32);
388: buf.append("Range[");
389: buf.append(min);
390: buf.append(',');
391: buf.append(max);
392: buf.append(']');
393: toString = buf.toString();
394: }
395: return toString;
396: }
397:
398: }
|