View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.functor.range;
18  
19  import java.util.Iterator;
20  
21  import org.apache.commons.functor.BinaryFunction;
22  import org.apache.commons.lang3.Validate;
23  
24  /**
25   * A range of longs.
26   *
27   * @since 1.0
28   * @version $Revision: 1385335 $ $Date: 2012-09-16 15:08:31 -0300 (Sun, 16 Sep 2012) $
29   */
30  public final class LongRange extends NumericRange<Long> {
31      // attributes
32      //---------------------------------------------------------------
33  
34      /**
35       * Calculate default step.
36       */
37      public static final BinaryFunction<Long, Long, Long> DEFAULT_STEP = new BinaryFunction<Long, Long, Long>() {
38  
39          public Long evaluate(Long left, Long right) {
40              return left > right ? -1L : 1L;
41          }
42      };
43  
44      // constructors
45      // ---------------------------------------------------------------
46      /**
47       * Create a new LongRange.
48       *
49       * @param from start
50       * @param to end
51       */
52      public LongRange(Number from, Number to) {
53          this(from.longValue(), to.longValue());
54      }
55  
56      /**
57       * Create a new LongRange.
58       *
59       * @param from start
60       * @param to end
61       * @param step increment
62       */
63      public LongRange(Number from, Number to, Number step) {
64          this(from.longValue(), to.longValue(), step.longValue());
65      }
66  
67      /**
68       * Create a new LongRange.
69       *
70       * @param from start
71       * @param to end
72       */
73      public LongRange(long from, long to) {
74          this(from, to, DEFAULT_STEP.evaluate(from, to).longValue());
75      }
76  
77      /**
78       * Create a new LongRange.
79       *
80       * @param from start
81       * @param to end
82       * @param step increment
83       */
84      public LongRange(long from, long to, long step) {
85          this(from, DEFAULT_LEFT_BOUND_TYPE, to, DEFAULT_RIGHT_BOUND_TYPE, step);
86      }
87  
88      /**
89       * Create a new LongRange.
90       *
91       * @param from start
92       * @param to end
93       * @throws NullPointerException if either {@link Endpoint} is {@code null}
94       */
95      public LongRange(Endpoint<Long> from, Endpoint<Long> to) {
96          this(from, to, DEFAULT_STEP.evaluate(from.getValue(), to.getValue()));
97      }
98  
99      /**
100      * Create a new LongRange.
101      *
102      * @param from start
103      * @param to end
104      * @param step increment
105      * @throws NullPointerException if either {@link Endpoint} is {@code null}
106      */
107     public LongRange(Endpoint<Long> from, Endpoint<Long> to, int step) {
108         this(from, to, (long) step);
109     }
110 
111     /**
112      * Create a new LongRange.
113      *
114      * @param from start
115      * @param leftBoundType type of left bound
116      * @param to end
117      * @param rightBoundType type of right bound
118      * @throws NullPointerException if either {@link BoundType} is {@code null}
119      */
120     public LongRange(long from, BoundType leftBoundType, long to, BoundType rightBoundType) {
121         this(from, leftBoundType, to, rightBoundType, DEFAULT_STEP.evaluate(from, to));
122     }
123 
124     /**
125      * Create a new LongRange.
126      *
127      * @param from start
128      * @param to end
129      * @param step increment
130      * @throws NullPointerException if either {@link Endpoint} is {@code null}
131      */
132     public LongRange(Endpoint<Long> from, Endpoint<Long> to, long step) {
133         super(from, to, Long.valueOf(step), new BinaryFunction<Long, Long, Long>() {
134 
135             public Long evaluate(Long left, Long right) {
136                 return Long.valueOf(left.longValue() + right.longValue());
137             }
138         });
139 
140         final long f = from.getValue();
141         final long t = to.getValue();
142 
143         Validate.isTrue(f == t || Long.signum(step) == Long.signum(t - f),
144             "Will never reach '%s' from '%s' using step %s", t, f, step);
145     }
146 
147     /**
148      * Create a new LongRange.
149      *
150      * @param from start
151      * @param leftBoundType type of left bound
152      * @param to end
153      * @param rightBoundType type of right bound
154      * @param step increment
155      * @throws NullPointerException if either {@link BoundType} is {@code null}
156      */
157     public LongRange(long from, BoundType leftBoundType, long to,
158                      BoundType rightBoundType, long step) {
159         this(new Endpoint<Long>(from, leftBoundType), new Endpoint<Long>(to, rightBoundType), step);
160     }
161 
162     // iterable
163     // ---------------------------------------------------------------
164 
165     /**
166      * {@inheritDoc}
167      */
168     protected Iterator<Long> createIterator() {
169         return new Iterator<Long>() {
170             private long currentValue;
171 
172             {
173                 currentValue = leftEndpoint.getValue();
174 
175                 if (leftEndpoint.getBoundType() == BoundType.OPEN) {
176                     this.currentValue += step;
177                 }
178             }
179 
180             public void remove() {
181                 throw new UnsupportedOperationException();
182             }
183 
184             public Long next() {
185                 final long step = getStep();
186                 final long r = currentValue;
187                 currentValue += step;
188                 return Long.valueOf(r);
189             }
190 
191             public boolean hasNext() {
192                 final int cmp = Long.valueOf(currentValue).compareTo(rightEndpoint.getValue());
193 
194                 if (cmp == 0) {
195                     return rightEndpoint.getBoundType() == BoundType.CLOSED;
196                 }
197                 if (step > 0L) {
198                     return cmp < 0;
199                 }
200                 return cmp > 0;
201             }
202         };
203     }
204 
205 }