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 */
017package org.apache.commons.math3.util;
018
019import org.apache.commons.math3.exception.MaxCountExceededException;
020import org.apache.commons.math3.exception.NullArgumentException;
021
022/**
023 * Utility that increments a counter until a maximum is reached, at
024 * which point, the instance will by default throw a
025 * {@link MaxCountExceededException}.
026 * However, the user is able to override this behaviour by defining a
027 * custom {@link MaxCountExceededCallback callback}, in order to e.g.
028 * select which exception must be thrown.
029 *
030 * @since 3.0
031 * @deprecated Use {@link IntegerSequence.Incrementor} instead.
032 */
033@Deprecated
034public class Incrementor {
035    /**
036     * Upper limit for the counter.
037     */
038    private int maximalCount;
039    /**
040     * Current count.
041     */
042    private int count = 0;
043    /**
044     * Function called at counter exhaustion.
045     */
046    private final MaxCountExceededCallback maxCountCallback;
047
048    /**
049     * Default constructor.
050     * For the new instance to be useful, the maximal count must be set
051     * by calling {@link #setMaximalCount(int) setMaximalCount}.
052     */
053    public Incrementor() {
054        this(0);
055    }
056
057    /**
058     * Defines a maximal count.
059     *
060     * @param max Maximal count.
061     */
062    public Incrementor(int max) {
063        this(max,
064             new MaxCountExceededCallback() {
065                 /** {@inheritDoc} */
066                 public void trigger(int max) throws MaxCountExceededException {
067                     throw new MaxCountExceededException(max);
068                 }
069             });
070    }
071
072    /**
073     * Defines a maximal count and a callback method to be triggered at
074     * counter exhaustion.
075     *
076     * @param max Maximal count.
077     * @param cb Function to be called when the maximal count has been reached.
078     * @throws NullArgumentException if {@code cb} is {@code null}
079     */
080    public Incrementor(int max, MaxCountExceededCallback cb)
081        throws NullArgumentException {
082        if (cb == null){
083            throw new NullArgumentException();
084        }
085        maximalCount = max;
086        maxCountCallback = cb;
087    }
088
089    /**
090     * Sets the upper limit for the counter.
091     * This does not automatically reset the current count to zero (see
092     * {@link #resetCount()}).
093     *
094     * @param max Upper limit of the counter.
095     */
096    public void setMaximalCount(int max) {
097        maximalCount = max;
098    }
099
100    /**
101     * Gets the upper limit of the counter.
102     *
103     * @return the counter upper limit.
104     */
105    public int getMaximalCount() {
106        return maximalCount;
107    }
108
109    /**
110     * Gets the current count.
111     *
112     * @return the current count.
113     */
114    public int getCount() {
115        return count;
116    }
117
118    /**
119     * Checks whether a single increment is allowed.
120     *
121     * @return {@code false} if the next call to {@link #incrementCount(int)
122     * incrementCount} will trigger a {@code MaxCountExceededException},
123     * {@code true} otherwise.
124     */
125    public boolean canIncrement() {
126        return count < maximalCount;
127    }
128
129    /**
130     * Performs multiple increments.
131     * See the other {@link #incrementCount() incrementCount} method).
132     *
133     * @param value Number of increments.
134     * @throws MaxCountExceededException at counter exhaustion.
135     */
136    public void incrementCount(int value) throws MaxCountExceededException {
137        for (int i = 0; i < value; i++) {
138            incrementCount();
139        }
140    }
141
142    /**
143     * Adds one to the current iteration count.
144     * At counter exhaustion, this method will call the
145     * {@link MaxCountExceededCallback#trigger(int) trigger} method of the
146     * callback object passed to the
147     * {@link #Incrementor(int,MaxCountExceededCallback) constructor}.
148     * If not explictly set, a default callback is used that will throw
149     * a {@code MaxCountExceededException}.
150     *
151     * @throws MaxCountExceededException at counter exhaustion, unless a
152     * custom {@link MaxCountExceededCallback callback} has been set at
153     * construction.
154     */
155    public void incrementCount() throws MaxCountExceededException {
156        if (++count > maximalCount) {
157            maxCountCallback.trigger(maximalCount);
158        }
159    }
160
161    /**
162     * Resets the counter to 0.
163     */
164    public void resetCount() {
165        count = 0;
166    }
167
168    /**
169     * Defines a method to be called at counter exhaustion.
170     * The {@link #trigger(int) trigger} method should usually throw an exception.
171     */
172    public interface MaxCountExceededCallback {
173        /**
174         * Function called when the maximal count has been reached.
175         *
176         * @param maximalCount Maximal count.
177         * @throws MaxCountExceededException at counter exhaustion
178         */
179        void trigger(int maximalCount) throws MaxCountExceededException;
180    }
181
182    /** Create an instance that delegates everything to a {@link IntegerSequence.Incrementor}.
183     * <p>
184     * This factory method is intended only as a temporary hack for internal use in
185     * Apache Commons Math 3.X series, when {@code Incrementor} is required in
186     * interface (as a return value or in protected fields). It should <em>not</em>
187     * be used in other cases. The {@link IntegerSequence.Incrementor} class should
188     * be used instead of {@code Incrementor}.
189     * </p>
190     * <p>
191     * All methods are mirrored to the underlying {@link IntegerSequence.Incrementor},
192     * as long as neither {@link #setMaximalCount(int)} nor {@link #resetCount()} are called.
193     * If one of these two methods is called, the created instance becomes independent
194     * of the {@link IntegerSequence.Incrementor} used at creation. The rationale is that
195     * {@link IntegerSequence.Incrementor} cannot change their maximal count and cannot be reset.
196     * </p>
197     * @param incrementor wrapped {@link IntegerSequence.Incrementor}
198     * @return an incrementor wrapping an {@link IntegerSequence.Incrementor}
199     * @since 3.6
200     */
201    public static Incrementor wrap(final IntegerSequence.Incrementor incrementor) {
202        return new Incrementor() {
203
204            /** Underlying incrementor. */
205            private IntegerSequence.Incrementor delegate;
206
207            {
208                // set up matching values at initialization
209                delegate = incrementor;
210                super.setMaximalCount(delegate.getMaximalCount());
211                super.incrementCount(delegate.getCount());
212            }
213
214            /** {@inheritDoc} */
215            @Override
216            public void setMaximalCount(int max) {
217                super.setMaximalCount(max);
218                delegate = delegate.withMaximalCount(max);
219            }
220
221            /** {@inheritDoc} */
222            @Override
223            public void resetCount() {
224                super.resetCount();
225                delegate = delegate.withStart(0);
226            }
227
228            /** {@inheritDoc} */
229            @Override
230            public void incrementCount() {
231                super.incrementCount();
232                delegate.increment();
233            }
234
235        };
236    }
237
238}