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 agents.anac.y2019.harddealer.math3.util;
|
---|
18 |
|
---|
19 | import java.util.Iterator;
|
---|
20 | import agents.anac.y2019.harddealer.math3.exception.MaxCountExceededException;
|
---|
21 | import agents.anac.y2019.harddealer.math3.exception.NullArgumentException;
|
---|
22 | import agents.anac.y2019.harddealer.math3.exception.MathUnsupportedOperationException;
|
---|
23 | import agents.anac.y2019.harddealer.math3.exception.NotStrictlyPositiveException;
|
---|
24 | import agents.anac.y2019.harddealer.math3.exception.ZeroException;
|
---|
25 |
|
---|
26 | /**
|
---|
27 | * Provides a sequence of integers.
|
---|
28 | *
|
---|
29 | * @since 3.6
|
---|
30 | */
|
---|
31 | public class IntegerSequence {
|
---|
32 | /**
|
---|
33 | * Utility class contains only static methods.
|
---|
34 | */
|
---|
35 | private IntegerSequence() {}
|
---|
36 |
|
---|
37 | /**
|
---|
38 | * Creates a sequence {@code [start .. end]}.
|
---|
39 | * It calls {@link #range(int,int,int) range(start, end, 1)}.
|
---|
40 | *
|
---|
41 | * @param start First value of the range.
|
---|
42 | * @param end Last value of the range.
|
---|
43 | * @return a range.
|
---|
44 | */
|
---|
45 | public static Range range(int start,
|
---|
46 | int end) {
|
---|
47 | return range(start, end, 1);
|
---|
48 | }
|
---|
49 |
|
---|
50 | /**
|
---|
51 | * Creates a sequence \( a_i, i < 0 <= n \)
|
---|
52 | * where \( a_i = start + i * step \)
|
---|
53 | * and \( n \) is such that \( a_n <= max \) and \( a_{n+1} > max \).
|
---|
54 | *
|
---|
55 | * @param start First value of the range.
|
---|
56 | * @param max Last value of the range that satisfies the above
|
---|
57 | * construction rule.
|
---|
58 | * @param step Increment.
|
---|
59 | * @return a range.
|
---|
60 | */
|
---|
61 | public static Range range(final int start,
|
---|
62 | final int max,
|
---|
63 | final int step) {
|
---|
64 | return new Range(start, max, step);
|
---|
65 | }
|
---|
66 |
|
---|
67 | /**
|
---|
68 | * Generates a sequence of integers.
|
---|
69 | */
|
---|
70 | public static class Range implements Iterable<Integer> {
|
---|
71 | /** Number of integers contained in this range. */
|
---|
72 | private final int size;
|
---|
73 | /** First value. */
|
---|
74 | private final int start;
|
---|
75 | /** Final value. */
|
---|
76 | private final int max;
|
---|
77 | /** Increment. */
|
---|
78 | private final int step;
|
---|
79 |
|
---|
80 | /**
|
---|
81 | * Creates a sequence \( a_i, i < 0 <= n \)
|
---|
82 | * where \( a_i = start + i * step \)
|
---|
83 | * and \( n \) is such that \( a_n <= max \) and \( a_{n+1} > max \).
|
---|
84 | *
|
---|
85 | * @param start First value of the range.
|
---|
86 | * @param max Last value of the range that satisfies the above
|
---|
87 | * construction rule.
|
---|
88 | * @param step Increment.
|
---|
89 | */
|
---|
90 | public Range(int start,
|
---|
91 | int max,
|
---|
92 | int step) {
|
---|
93 | this.start = start;
|
---|
94 | this.max = max;
|
---|
95 | this.step = step;
|
---|
96 |
|
---|
97 | final int s = (max - start) / step + 1;
|
---|
98 | this.size = s < 0 ? 0 : s;
|
---|
99 | }
|
---|
100 |
|
---|
101 | /**
|
---|
102 | * Gets the number of elements contained in the range.
|
---|
103 | *
|
---|
104 | * @return the size of the range.
|
---|
105 | */
|
---|
106 | public int size() {
|
---|
107 | return size;
|
---|
108 | }
|
---|
109 |
|
---|
110 | /** {@inheritDoc} */
|
---|
111 | public Iterator<Integer> iterator() {
|
---|
112 | return Incrementor.create()
|
---|
113 | .withStart(start)
|
---|
114 | .withMaximalCount(max + (step > 0 ? 1 : -1))
|
---|
115 | .withIncrement(step);
|
---|
116 | }
|
---|
117 | }
|
---|
118 |
|
---|
119 | /**
|
---|
120 | * Utility that increments a counter until a maximum is reached, at
|
---|
121 | * which point, the instance will by default throw a
|
---|
122 | * {@link MaxCountExceededException}.
|
---|
123 | * However, the user is able to override this behaviour by defining a
|
---|
124 | * custom {@link MaxCountExceededCallback callback}, in order to e.g.
|
---|
125 | * select which exception must be thrown.
|
---|
126 | */
|
---|
127 | public static class Incrementor implements Iterator<Integer> {
|
---|
128 | /** Default callback. */
|
---|
129 | private static final MaxCountExceededCallback CALLBACK
|
---|
130 | = new MaxCountExceededCallback() {
|
---|
131 | /** {@inheritDoc} */
|
---|
132 | public void trigger(int max) throws MaxCountExceededException {
|
---|
133 | throw new MaxCountExceededException(max);
|
---|
134 | }
|
---|
135 | };
|
---|
136 |
|
---|
137 | /** Initial value the counter. */
|
---|
138 | private final int init;
|
---|
139 | /** Upper limit for the counter. */
|
---|
140 | private final int maximalCount;
|
---|
141 | /** Increment. */
|
---|
142 | private final int increment;
|
---|
143 | /** Function called at counter exhaustion. */
|
---|
144 | private final MaxCountExceededCallback maxCountCallback;
|
---|
145 | /** Current count. */
|
---|
146 | private int count = 0;
|
---|
147 |
|
---|
148 | /**
|
---|
149 | * Defines a method to be called at counter exhaustion.
|
---|
150 | * The {@link #trigger(int) trigger} method should usually throw an exception.
|
---|
151 | */
|
---|
152 | public interface MaxCountExceededCallback {
|
---|
153 | /**
|
---|
154 | * Function called when the maximal count has been reached.
|
---|
155 | *
|
---|
156 | * @param maximalCount Maximal count.
|
---|
157 | * @throws MaxCountExceededException at counter exhaustion
|
---|
158 | */
|
---|
159 | void trigger(int maximalCount) throws MaxCountExceededException;
|
---|
160 | }
|
---|
161 |
|
---|
162 | /**
|
---|
163 | * Creates an incrementor.
|
---|
164 | * The counter will be exhausted either when {@code max} is reached
|
---|
165 | * or when {@code nTimes} increments have been performed.
|
---|
166 | *
|
---|
167 | * @param start Initial value.
|
---|
168 | * @param max Maximal count.
|
---|
169 | * @param step Increment.
|
---|
170 | * @param cb Function to be called when the maximal count has been reached.
|
---|
171 | * @throws NullArgumentException if {@code cb} is {@code null}.
|
---|
172 | */
|
---|
173 | private Incrementor(int start,
|
---|
174 | int max,
|
---|
175 | int step,
|
---|
176 | MaxCountExceededCallback cb)
|
---|
177 | throws NullArgumentException {
|
---|
178 | if (cb == null) {
|
---|
179 | throw new NullArgumentException();
|
---|
180 | }
|
---|
181 | this.init = start;
|
---|
182 | this.maximalCount = max;
|
---|
183 | this.increment = step;
|
---|
184 | this.maxCountCallback = cb;
|
---|
185 | this.count = start;
|
---|
186 | }
|
---|
187 |
|
---|
188 | /**
|
---|
189 | * Factory method that creates a default instance.
|
---|
190 | * The initial and maximal values are set to 0.
|
---|
191 | * For the new instance to be useful, the maximal count must be set
|
---|
192 | * by calling {@link #withMaximalCount(int) withMaximalCount}.
|
---|
193 | *
|
---|
194 | * @return an new instance.
|
---|
195 | */
|
---|
196 | public static Incrementor create() {
|
---|
197 | return new Incrementor(0, 0, 1, CALLBACK);
|
---|
198 | }
|
---|
199 |
|
---|
200 | /**
|
---|
201 | * Creates a new instance with a given initial value.
|
---|
202 | * The counter is reset to the initial value.
|
---|
203 | *
|
---|
204 | * @param start Initial value of the counter.
|
---|
205 | * @return a new instance.
|
---|
206 | */
|
---|
207 | public Incrementor withStart(int start) {
|
---|
208 | return new Incrementor(start,
|
---|
209 | this.maximalCount,
|
---|
210 | this.increment,
|
---|
211 | this.maxCountCallback);
|
---|
212 | }
|
---|
213 |
|
---|
214 | /**
|
---|
215 | * Creates a new instance with a given maximal count.
|
---|
216 | * The counter is reset to the initial value.
|
---|
217 | *
|
---|
218 | * @param max Maximal count.
|
---|
219 | * @return a new instance.
|
---|
220 | */
|
---|
221 | public Incrementor withMaximalCount(int max) {
|
---|
222 | return new Incrementor(this.init,
|
---|
223 | max,
|
---|
224 | this.increment,
|
---|
225 | this.maxCountCallback);
|
---|
226 | }
|
---|
227 |
|
---|
228 | /**
|
---|
229 | * Creates a new instance with a given increment.
|
---|
230 | * The counter is reset to the initial value.
|
---|
231 | *
|
---|
232 | * @param step Increment.
|
---|
233 | * @return a new instance.
|
---|
234 | */
|
---|
235 | public Incrementor withIncrement(int step) {
|
---|
236 | if (step == 0) {
|
---|
237 | throw new ZeroException();
|
---|
238 | }
|
---|
239 | return new Incrementor(this.init,
|
---|
240 | this.maximalCount,
|
---|
241 | step,
|
---|
242 | this.maxCountCallback);
|
---|
243 | }
|
---|
244 |
|
---|
245 | /**
|
---|
246 | * Creates a new instance with a given callback.
|
---|
247 | * The counter is reset to the initial value.
|
---|
248 | *
|
---|
249 | * @param cb Callback to be called at counter exhaustion.
|
---|
250 | * @return a new instance.
|
---|
251 | */
|
---|
252 | public Incrementor withCallback(MaxCountExceededCallback cb) {
|
---|
253 | return new Incrementor(this.init,
|
---|
254 | this.maximalCount,
|
---|
255 | this.increment,
|
---|
256 | cb);
|
---|
257 | }
|
---|
258 |
|
---|
259 | /**
|
---|
260 | * Gets the upper limit of the counter.
|
---|
261 | *
|
---|
262 | * @return the counter upper limit.
|
---|
263 | */
|
---|
264 | public int getMaximalCount() {
|
---|
265 | return maximalCount;
|
---|
266 | }
|
---|
267 |
|
---|
268 | /**
|
---|
269 | * Gets the current count.
|
---|
270 | *
|
---|
271 | * @return the current count.
|
---|
272 | */
|
---|
273 | public int getCount() {
|
---|
274 | return count;
|
---|
275 | }
|
---|
276 |
|
---|
277 | /**
|
---|
278 | * Checks whether incrementing the counter {@code nTimes} is allowed.
|
---|
279 | *
|
---|
280 | * @return {@code false} if calling {@link #increment()}
|
---|
281 | * will trigger a {@code MaxCountExceededException},
|
---|
282 | * {@code true} otherwise.
|
---|
283 | */
|
---|
284 | public boolean canIncrement() {
|
---|
285 | return canIncrement(1);
|
---|
286 | }
|
---|
287 |
|
---|
288 | /**
|
---|
289 | * Checks whether incrementing the counter several times is allowed.
|
---|
290 | *
|
---|
291 | * @param nTimes Number of increments.
|
---|
292 | * @return {@code false} if calling {@link #increment(int)
|
---|
293 | * increment(nTimes)} would call the {@link MaxCountExceededCallback callback}
|
---|
294 | * {@code true} otherwise.
|
---|
295 | */
|
---|
296 | public boolean canIncrement(int nTimes) {
|
---|
297 | final int finalCount = count + nTimes * increment;
|
---|
298 | return increment < 0 ?
|
---|
299 | finalCount > maximalCount :
|
---|
300 | finalCount < maximalCount;
|
---|
301 | }
|
---|
302 |
|
---|
303 | /**
|
---|
304 | * Performs multiple increments.
|
---|
305 | *
|
---|
306 | * @param nTimes Number of increments.
|
---|
307 | * @throws MaxCountExceededException at counter exhaustion.
|
---|
308 | * @throws NotStrictlyPositiveException if {@code nTimes <= 0}.
|
---|
309 | *
|
---|
310 | * @see #increment()
|
---|
311 | */
|
---|
312 | public void increment(int nTimes) throws MaxCountExceededException {
|
---|
313 | if (nTimes <= 0) {
|
---|
314 | throw new NotStrictlyPositiveException(nTimes);
|
---|
315 | }
|
---|
316 |
|
---|
317 | if (!canIncrement(0)) {
|
---|
318 | maxCountCallback.trigger(maximalCount);
|
---|
319 | }
|
---|
320 | count += nTimes * increment;
|
---|
321 | }
|
---|
322 |
|
---|
323 | /**
|
---|
324 | * Adds the increment value to the current iteration count.
|
---|
325 | * At counter exhaustion, this method will call the
|
---|
326 | * {@link MaxCountExceededCallback#trigger(int) trigger} method of the
|
---|
327 | * callback object passed to the
|
---|
328 | * {@link #withCallback(MaxCountExceededCallback)} method.
|
---|
329 | * If not explicitly set, a default callback is used that will throw
|
---|
330 | * a {@code MaxCountExceededException}.
|
---|
331 | *
|
---|
332 | * @throws MaxCountExceededException at counter exhaustion, unless a
|
---|
333 | * custom {@link MaxCountExceededCallback callback} has been set.
|
---|
334 | *
|
---|
335 | * @see #increment(int)
|
---|
336 | */
|
---|
337 | public void increment() throws MaxCountExceededException {
|
---|
338 | increment(1);
|
---|
339 | }
|
---|
340 |
|
---|
341 | /** {@inheritDoc} */
|
---|
342 | public boolean hasNext() {
|
---|
343 | return canIncrement(0);
|
---|
344 | }
|
---|
345 |
|
---|
346 | /** {@inheritDoc} */
|
---|
347 | public Integer next() {
|
---|
348 | final int value = count;
|
---|
349 | increment();
|
---|
350 | return value;
|
---|
351 | }
|
---|
352 |
|
---|
353 | /**
|
---|
354 | * Not applicable.
|
---|
355 | *
|
---|
356 | * @throws MathUnsupportedOperationException
|
---|
357 | */
|
---|
358 | public void remove() {
|
---|
359 | throw new MathUnsupportedOperationException();
|
---|
360 | }
|
---|
361 | }
|
---|
362 | }
|
---|