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    }