    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    }