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    }