| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.math4.legacy.core; |
| |
| import java.util.Iterator; |
| import java.util.NoSuchElementException; |
| import org.apache.commons.math4.legacy.exception.MaxCountExceededException; |
| import org.apache.commons.math4.legacy.exception.NullArgumentException; |
| import org.apache.commons.math4.legacy.exception.MathUnsupportedOperationException; |
| import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; |
| import org.apache.commons.math4.legacy.exception.ZeroException; |
| |
| /** |
| * Provides a sequence of integers. |
| * |
| * @since 3.6 |
| */ |
| public final class IntegerSequence { |
| /** |
| * Utility class contains only static methods. |
| */ |
| private IntegerSequence() {} |
| |
| /** |
| * Creates a sequence {@code [start .. end]}. |
| * It calls {@link #range(int,int,int) range(start, end, 1)}. |
| * |
| * @param start First value of the range. |
| * @param end Last value of the range. |
| * @return a range. |
| */ |
| public static Range range(int start, |
| int end) { |
| return range(start, end, 1); |
| } |
| |
| /** |
| * Creates a sequence <code>a<sub>i</sub>, i < 0 < n</code> |
| * where <code>a<sub>i</sub> = start + i * step</code> |
| * and {@code n} is such that <code>a<sub>n</sub> <= max</code> |
| * and <code>a<sub>n+1</sub> > max</code>. |
| * |
| * @param start First value of the range. |
| * @param max Last value of the range that satisfies the above |
| * construction rule. |
| * @param step Increment. |
| * @return a range. |
| */ |
| public static Range range(final int start, |
| final int max, |
| final int step) { |
| return new Range(start, max, step); |
| } |
| |
| /** |
| * Generates a sequence of integers. |
| */ |
| public static class Range implements Iterable<Integer> { |
| /** Number of integers contained in this range. */ |
| private final int size; |
| /** First value. */ |
| private final int start; |
| /** Final value. */ |
| private final int max; |
| /** Increment. */ |
| private final int step; |
| |
| /** |
| * Creates a sequence <code>a<sub>i</sub>, i < 0 < n</code> |
| * where <code>a<sub>i</sub> = start + i * step</code> |
| * and {@code n} is such that <code>a<sub>n</sub> <= max</code> |
| * and <code>a<sub>n+1</sub> > max</code>. |
| * |
| * @param start First value of the range. |
| * @param max Last value of the range that satisfies the above |
| * construction rule. |
| * @param step Increment. |
| */ |
| public Range(int start, |
| int max, |
| int step) { |
| this.start = start; |
| this.max = max; |
| this.step = step; |
| |
| final int s = (max - start) / step + 1; |
| this.size = s < 0 ? 0 : s; |
| } |
| |
| /** |
| * Gets the number of elements contained in the range. |
| * |
| * @return the size of the range. |
| */ |
| public int size() { |
| return size; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Iterator<Integer> iterator() { |
| return Incrementor.create() |
| .withStart(start) |
| .withMaximalCount(max + (step > 0 ? 1 : -1)) |
| .withIncrement(step); |
| } |
| } |
| |
| /** |
| * Utility that increments a counter until a maximum is reached, at |
| * which point, the instance will by default throw a |
| * {@link MaxCountExceededException}. |
| * However, the user is able to override this behaviour by defining a |
| * custom {@link MaxCountExceededCallback callback}, in order to e.g. |
| * select which exception must be thrown. |
| */ |
| public static final class Incrementor implements Iterator<Integer> { |
| /** Default callback. */ |
| private static final MaxCountExceededCallback CALLBACK |
| = new MaxCountExceededCallback() { |
| /** {@inheritDoc} */ |
| @Override |
| public void trigger(int max) throws MaxCountExceededException { |
| throw new MaxCountExceededException(max); |
| } |
| }; |
| |
| /** Initial value the counter. */ |
| private final int init; |
| /** Upper limit for the counter. */ |
| private final int maximalCount; |
| /** Increment. */ |
| private final int increment; |
| /** Function called at counter exhaustion. */ |
| private final MaxCountExceededCallback maxCountCallback; |
| /** Current count. */ |
| private int count; |
| |
| /** |
| * Defines a method to be called at counter exhaustion. |
| * The {@link #trigger(int) trigger} method should usually throw an exception. |
| */ |
| public interface MaxCountExceededCallback { |
| /** |
| * Function called when the maximal count has been reached. |
| * |
| * @param maximalCount Maximal count. |
| * @throws MaxCountExceededException at counter exhaustion |
| */ |
| void trigger(int maximalCount) throws MaxCountExceededException; |
| } |
| |
| /** |
| * Creates an incrementor. |
| * The counter will be exhausted either when {@code max} is reached |
| * or when {@code nTimes} increments have been performed. |
| * |
| * @param start Initial value. |
| * @param max Maximal count. |
| * @param step Increment. |
| * @param cb Function to be called when the maximal count has been reached. |
| * @throws NullArgumentException if {@code cb} is {@code null}. |
| */ |
| private Incrementor(int start, |
| int max, |
| int step, |
| MaxCountExceededCallback cb) |
| throws NullArgumentException { |
| if (cb == null) { |
| throw new NullArgumentException(); |
| } |
| this.init = start; |
| this.maximalCount = max; |
| this.increment = step; |
| this.maxCountCallback = cb; |
| this.count = start; |
| } |
| |
| /** |
| * Factory method that creates a default instance. |
| * The initial and maximal values are set to 0. |
| * For the new instance to be useful, the maximal count must be set |
| * by calling {@link #withMaximalCount(int) withMaximalCount}. |
| * |
| * @return an new instance. |
| */ |
| public static Incrementor create() { |
| return new Incrementor(0, 0, 1, CALLBACK); |
| } |
| |
| /** |
| * Creates a new instance with a given initial value. |
| * The counter is reset to the initial value. |
| * |
| * @param start Initial value of the counter. |
| * @return a new instance. |
| */ |
| public Incrementor withStart(int start) { |
| return new Incrementor(start, |
| this.maximalCount, |
| this.increment, |
| this.maxCountCallback); |
| } |
| |
| /** |
| * Creates a new instance with a given maximal count. |
| * The counter is reset to the initial value. |
| * |
| * @param max Maximal count. |
| * @return a new instance. |
| */ |
| public Incrementor withMaximalCount(int max) { |
| return new Incrementor(this.init, |
| max, |
| this.increment, |
| this.maxCountCallback); |
| } |
| |
| /** |
| * Creates a new instance with a given increment. |
| * The counter is reset to the initial value. |
| * |
| * @param step Increment. |
| * @return a new instance. |
| */ |
| public Incrementor withIncrement(int step) { |
| if (step == 0) { |
| throw new ZeroException(); |
| } |
| return new Incrementor(this.init, |
| this.maximalCount, |
| step, |
| this.maxCountCallback); |
| } |
| |
| /** |
| * Creates a new instance with a given callback. |
| * The counter is reset to the initial value. |
| * |
| * @param cb Callback to be called at counter exhaustion. |
| * @return a new instance. |
| */ |
| public Incrementor withCallback(MaxCountExceededCallback cb) { |
| return new Incrementor(this.init, |
| this.maximalCount, |
| this.increment, |
| cb); |
| } |
| |
| /** |
| * Gets the upper limit of the counter. |
| * |
| * @return the counter upper limit. |
| */ |
| public int getMaximalCount() { |
| return maximalCount; |
| } |
| |
| /** |
| * Gets the current count. |
| * |
| * @return the current count. |
| */ |
| public int getCount() { |
| return count; |
| } |
| |
| /** |
| * Checks whether incrementing the counter {@code nTimes} is allowed. |
| * |
| * @return {@code false} if calling {@link #increment()} |
| * will trigger a {@code MaxCountExceededException}, |
| * {@code true} otherwise. |
| */ |
| public boolean canIncrement() { |
| return canIncrement(1); |
| } |
| |
| /** |
| * Checks whether incrementing the counter several times is allowed. |
| * |
| * @param nTimes Number of increments. |
| * @return {@code false} if calling {@link #increment(int) |
| * increment(nTimes)} would call the {@link MaxCountExceededCallback callback} |
| * {@code true} otherwise. |
| */ |
| public boolean canIncrement(int nTimes) { |
| final int finalCount = count + nTimes * increment; |
| return increment < 0 ? |
| finalCount > maximalCount : |
| finalCount < maximalCount; |
| } |
| |
| /** |
| * Performs multiple increments. |
| * |
| * @param nTimes Number of increments. |
| * @throws MaxCountExceededException at counter exhaustion. |
| * @throws NotStrictlyPositiveException if {@code nTimes <= 0}. |
| * |
| * @see #increment() |
| */ |
| public void increment(int nTimes) throws MaxCountExceededException { |
| if (nTimes <= 0) { |
| throw new NotStrictlyPositiveException(nTimes); |
| } |
| |
| count += nTimes * increment; |
| |
| if (!canIncrement(0)) { |
| maxCountCallback.trigger(maximalCount); |
| } |
| } |
| |
| /** |
| * Adds the increment value to the current iteration count. |
| * At counter exhaustion, this method will call the |
| * {@link MaxCountExceededCallback#trigger(int) trigger} method of the |
| * callback object passed to the |
| * {@link #withCallback(MaxCountExceededCallback)} method. |
| * If not explicitly set, a default callback is used that will throw |
| * a {@code MaxCountExceededException}. |
| * |
| * @throws MaxCountExceededException at counter exhaustion, unless a |
| * custom {@link MaxCountExceededCallback callback} has been set. |
| * |
| * @see #increment(int) |
| */ |
| public void increment() throws MaxCountExceededException { |
| increment(1); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public boolean hasNext() { |
| return canIncrement(0); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Integer next() { |
| if (canIncrement(0)) { |
| final int value = count; |
| count += increment; |
| return value; |
| } else { |
| // Contract for "Iterator". |
| throw new NoSuchElementException(); |
| } |
| } |
| |
| /** |
| * Not applicable. |
| * |
| * @throws MathUnsupportedOperationException always |
| */ |
| @Override |
| public void remove() { |
| throw new MathUnsupportedOperationException(); |
| } |
| } |
| } |