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 Stephen Colebourne
027: * @since 2.0
028: * @version $Id: Range.java 437554 2006-08-28 06:21:41Z bayard $
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()
237: && value <= getMaximumInteger();
238: }
239:
240: /**
241: * <p>Tests whether the specified <code>Number</code> occurs within
242: * this range using <code>double</code> comparison..</p>
243: *
244: * <p><code>null</code> is handled and returns <code>false</code>.</p>
245: *
246: * <p>This implementation forwards to the {@link #containsDouble(double)} method.</p>
247: *
248: * @param value the double to test, may be <code>null</code>
249: * @return <code>true</code> if the specified number occurs within this
250: * range by <code>double</code> comparison
251: */
252: public boolean containsDouble(Number value) {
253: if (value == null) {
254: return false;
255: }
256: return containsDouble(value.doubleValue());
257: }
258:
259: /**
260: * <p>Tests whether the specified <code>double</code> occurs within
261: * this range using <code>double</code> comparison.</p>
262: *
263: * <p>This implementation uses the {@link #getMinimumDouble()} and
264: * {@link #getMaximumDouble()} methods and should be good for most uses.</p>
265: *
266: * @param value the double to test
267: * @return <code>true</code> if the specified number occurs within this
268: * range by <code>double</code> comparison
269: */
270: public boolean containsDouble(double value) {
271: int compareMin = NumberUtils.compare(getMinimumDouble(), value);
272: int compareMax = NumberUtils.compare(getMaximumDouble(), value);
273: return compareMin <= 0 && compareMax >= 0;
274: }
275:
276: /**
277: * <p>Tests whether the specified <code>Number</code> occurs within
278: * this range using <code>float</code> comparison.</p>
279: *
280: * <p><code>null</code> is handled and returns <code>false</code>.</p>
281: *
282: * <p>This implementation forwards to the {@link #containsFloat(float)} method.</p>
283: *
284: * @param value the float to test, may be <code>null</code>
285: * @return <code>true</code> if the specified number occurs within this
286: * range by <code>float</code> comparison
287: */
288: public boolean containsFloat(Number value) {
289: if (value == null) {
290: return false;
291: }
292: return containsFloat(value.floatValue());
293: }
294:
295: /**
296: * <p>Tests whether the specified <code>float</code> occurs within
297: * this range using <code>float</code> comparison.</p>
298: *
299: * <p>This implementation uses the {@link #getMinimumFloat()} and
300: * {@link #getMaximumFloat()} methods and should be good for most uses.</p>
301: *
302: * @param value the float to test
303: * @return <code>true</code> if the specified number occurs within this
304: * range by <code>float</code> comparison
305: */
306: public boolean containsFloat(float value) {
307: int compareMin = NumberUtils.compare(getMinimumFloat(), value);
308: int compareMax = NumberUtils.compare(getMaximumFloat(), value);
309: return compareMin <= 0 && compareMax >= 0;
310: }
311:
312: // Range tests
313: //--------------------------------------------------------------------
314:
315: /**
316: * <p>Tests whether the specified range occurs entirely within this range.</p>
317: *
318: * <p>The exact comparison implementation varies by subclass. It is
319: * intended that an <code>int</code> specific subclass will compare using
320: * <code>int</code> comparison.</p>
321: *
322: * <p><code>null</code> is handled and returns <code>false</code>.</p>
323: *
324: * <p>This implementation uses the {@link #containsNumber(Number)} method.
325: * Subclasses may be able to optimise this.</p>
326: *
327: * @param range the range to test, may be <code>null</code>
328: * @return <code>true</code> if the specified range occurs entirely within
329: * this range; otherwise, <code>false</code>
330: * @throws IllegalArgumentException if the <code>Range</code> cannot be compared
331: */
332: public boolean containsRange(Range range) {
333: if (range == null) {
334: return false;
335: }
336: return containsNumber(range.getMinimumNumber())
337: && containsNumber(range.getMaximumNumber());
338: }
339:
340: /**
341: * <p>Tests whether the specified range overlaps with this range.</p>
342: *
343: * <p>The exact comparison implementation varies by subclass. It is
344: * intended that an <code>int</code> specific subclass will compare using
345: * <code>int</code> comparison.</p>
346: *
347: * <p><code>null</code> is handled and returns <code>false</code>.</p>
348: *
349: * <p>This implementation uses the {@link #containsNumber(Number)} and
350: * {@link #containsRange(Range)} methods.
351: * Subclasses may be able to optimise this.</p>
352: *
353: * @param range the range to test, may be <code>null</code>
354: * @return <code>true</code> if the specified range overlaps with this
355: * range; otherwise, <code>false</code>
356: * @throws IllegalArgumentException if the <code>Range</code> cannot be compared
357: */
358: public boolean overlapsRange(Range range) {
359: if (range == null) {
360: return false;
361: }
362: return range.containsNumber(getMinimumNumber())
363: || range.containsNumber(getMaximumNumber())
364: || containsNumber(range.getMinimumNumber());
365: }
366:
367: // Basics
368: //--------------------------------------------------------------------
369:
370: /**
371: * <p>Compares this range to another object to test if they are equal.</p>.
372: *
373: * <p>To be equal, the class, minimum and maximum must be equal.</p>
374: *
375: * <p>This implementation uses the {@link #getMinimumNumber()} and
376: * {@link #getMaximumNumber()} methods.
377: * Subclasses may be able to optimise this.</p>
378: *
379: * @param obj the reference object with which to compare
380: * @return <code>true</code> if this object is equal
381: */
382: public boolean equals(Object obj) {
383: if (obj == this ) {
384: return true;
385: } else if (obj == null || obj.getClass() != getClass()) {
386: return false;
387: } else {
388: Range range = (Range) obj;
389: return getMinimumNumber().equals(range.getMinimumNumber())
390: && getMaximumNumber().equals(
391: 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: StringBuffer buf = new StringBuffer(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: }
|