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