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