    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    }