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