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.math3.util;
018    
019    import org.apache.commons.math3.exception.MaxCountExceededException;
020    import 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     * @version $Id: Incrementor.java 1364389 2012-07-22 18:19:26Z tn $
032     */
033    public class Incrementor {
034        /**
035         * Upper limit for the counter.
036         */
037        private int maximalCount;
038        /**
039         * Current count.
040         */
041        private int count = 0;
042        /**
043         * Function called at counter exhaustion.
044         */
045        private final MaxCountExceededCallback maxCountCallback;
046    
047        /**
048         * Default constructor.
049         * For the new instance to be useful, the maximal count must be set
050         * by calling {@link #setMaximalCount(int) setMaximalCount}.
051         */
052        public Incrementor() {
053            this(0);
054        }
055    
056        /**
057         * Defines a maximal count.
058         *
059         * @param max Maximal count.
060         */
061        public Incrementor(int max) {
062            this(max,
063                 new MaxCountExceededCallback() {
064                     /** {@inheritDoc} */
065                     public void trigger(int max) {
066                         throw new MaxCountExceededException(max);
067                     }
068                 });
069        }
070    
071        /**
072         * Defines a maximal count and a callback method to be triggered at
073         * counter exhaustion.
074         *
075         * @param max Maximal count.
076         * @param cb Function to be called when the maximal count has been reached.
077         * @throws NullArgumentException if {@code cb} is {@code null}
078         */
079        public Incrementor(int max,
080                           MaxCountExceededCallback cb) {
081            if (cb == null){
082                throw new NullArgumentException();
083            }
084            maximalCount = max;
085            maxCountCallback = cb;
086        }
087    
088        /**
089         * Sets the upper limit for the counter.
090         * This does not automatically reset the current count to zero (see
091         * {@link #resetCount()}).
092         *
093         * @param max Upper limit of the counter.
094         */
095        public void setMaximalCount(int max) {
096            maximalCount = max;
097        }
098    
099        /**
100         * Gets the upper limit of the counter.
101         *
102         * @return the counter upper limit.
103         */
104        public int getMaximalCount() {
105            return maximalCount;
106        }
107    
108        /**
109         * Gets the current count.
110         *
111         * @return the current count.
112         */
113        public int getCount() {
114            return count;
115        }
116    
117        /**
118         * Checks whether a single increment is allowed.
119         *
120         * @return {@code false} if the next call to {@link #incrementCount(int)
121         * incrementCount} will trigger a {@code MaxCountExceededException},
122         * {@code true} otherwise.
123         */
124        public boolean canIncrement() {
125            return count < maximalCount;
126        }
127    
128        /**
129         * Performs multiple increments.
130         * See the other {@link #incrementCount() incrementCount} method).
131         *
132         * @param value Number of increments.
133         * @throws MaxCountExceededException at counter exhaustion.
134         */
135        public void incrementCount(int value) {
136            for (int i = 0; i < value; i++) {
137                incrementCount();
138            }
139        }
140    
141        /**
142         * Adds one to the current iteration count.
143         * At counter exhaustion, this method will call the
144         * {@link MaxCountExceededCallback#trigger(int) trigger} method of the
145         * callback object passed to the
146         * {@link #Incrementor(int,MaxCountExceededCallback) constructor}.
147         * If not explictly set, a default callback is used that will throw
148         * a {@code MaxCountExceededException}.
149         *
150         * @throws MaxCountExceededException at counter exhaustion, unless a
151         * custom {@link MaxCountExceededCallback callback} has been set at
152         * construction.
153         */
154        public void incrementCount() {
155            if (++count > maximalCount) {
156                maxCountCallback.trigger(maximalCount);
157            }
158        }
159    
160        /**
161         * Resets the counter to 0.
162         */
163        public void resetCount() {
164            count = 0;
165        }
166    
167        /**
168         * Defines a method to be called at counter exhaustion.
169         * The {@link #trigger(int) trigger} method should usually throw an exception.
170         */
171        public interface MaxCountExceededCallback {
172            /**
173             * Function called when the maximal count has been reached.
174             *
175             * @param maximalCount Maximal count.
176             */
177            void trigger(int maximalCount);
178        }
179    }