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