Incrementor.java

  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.  *      https://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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.util;

  22. import org.hipparchus.exception.LocalizedCoreFormats;
  23. import org.hipparchus.exception.MathIllegalArgumentException;
  24. import org.hipparchus.exception.MathIllegalStateException;
  25. import org.hipparchus.exception.NullArgumentException;

  26. /**
  27.  * Utility that increments a counter until a maximum is reached, at
  28.  * which point, the instance will by default throw a
  29.  * {@link MathIllegalStateException}.
  30.  * However, the user is able to override this behaviour by defining a
  31.  * custom {@link MaxCountExceededCallback callback}, in order to e.g.
  32.  * select which exception must be thrown.
  33.  */
  34. public class Incrementor {
  35.     /** Default callback. */
  36.     private static final MaxCountExceededCallback DEFAULT_CALLBACK =
  37.         (int max) -> {
  38.             throw new MathIllegalStateException(LocalizedCoreFormats.MAX_COUNT_EXCEEDED, max);
  39.         };

  40.     /** Upper limit for the counter. */
  41.     private final int maximalCount;
  42.     /** Function called at counter exhaustion. */
  43.     private final MaxCountExceededCallback maxCountCallback;
  44.     /** Current count. */
  45.     private int count;

  46.     /**
  47.      * Defines a method to be called at counter exhaustion.
  48.      * The {@link #trigger(int) trigger} method should usually throw an exception.
  49.      */
  50.     public interface MaxCountExceededCallback {
  51.         /**
  52.          * Function called when the maximal count has been reached.
  53.          *
  54.          * @param maximalCount Maximal count.
  55.          * @throws MathIllegalStateException at counter exhaustion
  56.          */
  57.         void trigger(int maximalCount) throws MathIllegalStateException;
  58.     }

  59.     /**
  60.      * Creates an Incrementor.
  61.      * <p>
  62.      * The maximal value will be set to {@code Integer.MAX_VALUE}.
  63.      */
  64.     public Incrementor() {
  65.         this(Integer.MAX_VALUE);
  66.     }

  67.     /**
  68.      * Creates an Incrementor.
  69.      *
  70.      * @param max Maximal count.
  71.      * @throws MathIllegalArgumentException if {@code max} is negative.
  72.      */
  73.     public Incrementor(int max) {
  74.         this(max, DEFAULT_CALLBACK);
  75.     }

  76.     /**
  77.      * Creates an Incrementor.
  78.      *
  79.      * @param max Maximal count.
  80.      * @param cb Function to be called when the maximal count has been reached.
  81.      * @throws NullArgumentException if {@code cb} is {@code null}.
  82.      * @throws MathIllegalArgumentException if {@code max} is negative.
  83.      */
  84.     public Incrementor(int max,
  85.                         MaxCountExceededCallback cb)
  86.         throws NullArgumentException {
  87.         this(0, max, cb);
  88.     }

  89.     /**
  90.      * Creates an Incrementor.
  91.      *
  92.      * @param count Initial counter value.
  93.      * @param max Maximal count.
  94.      * @param cb Function to be called when the maximal count has been reached.
  95.      * @throws NullArgumentException if {@code cb} is {@code null}.
  96.      * @throws MathIllegalArgumentException if {@code max} is negative.
  97.      */
  98.     private Incrementor(int count,
  99.                         int max,
  100.                         MaxCountExceededCallback cb)
  101.         throws NullArgumentException {
  102.         if (cb == null) {
  103.             throw new NullArgumentException();
  104.         }
  105.         if (max < 0) {
  106.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, max, 0);
  107.         }
  108.         this.maximalCount = max;
  109.         this.maxCountCallback = cb;
  110.         this.count = count;
  111.     }

  112.     /**
  113.      * Creates a new instance and set the counter to the given value.
  114.      *
  115.      * @param value Value of the counter.
  116.      * @return a new instance.
  117.      */
  118.     public Incrementor withCount(int value) {
  119.         return new Incrementor(value,
  120.                                this.maximalCount,
  121.                                this.maxCountCallback);
  122.     }

  123.     /**
  124.      * Creates a new instance with a given maximal count.
  125.      * The counter is reset to 0.
  126.      *
  127.      * @param max Maximal count.
  128.      * @return a new instance.
  129.      * @throws MathIllegalArgumentException if {@code max} is negative.
  130.      */
  131.     public Incrementor withMaximalCount(int max) {
  132.         return new Incrementor(0,
  133.                                max,
  134.                                this.maxCountCallback);
  135.     }

  136.     /**
  137.      * Creates a new instance with a given callback.
  138.      * The counter is reset to 0.
  139.      *
  140.      * @param cb Callback to be called at counter exhaustion.
  141.      * @return a new instance.
  142.      */
  143.     public Incrementor withCallback(MaxCountExceededCallback cb) {
  144.         return new Incrementor(0,
  145.                                this.maximalCount,
  146.                                cb);
  147.     }

  148.     /**
  149.      * Gets the upper limit of the counter.
  150.      *
  151.      * @return the counter upper limit.
  152.      */
  153.     public int getMaximalCount() {
  154.         return maximalCount;
  155.     }

  156.     /**
  157.      * Gets the current count.
  158.      *
  159.      * @return the current count.
  160.      */
  161.     public int getCount() {
  162.         return count;
  163.     }

  164.     /**
  165.      * Checks whether incrementing the counter {@code nTimes} is allowed.
  166.      *
  167.      * @return {@code false} if calling {@link #increment()}
  168.      * will trigger a {@code MathIllegalStateException},
  169.      * {@code true} otherwise.
  170.      */
  171.     public boolean canIncrement() {
  172.         return canIncrement(1);
  173.     }

  174.     /**
  175.      * Checks whether incrementing the counter several times is allowed.
  176.      *
  177.      * @param nTimes Number of increments.
  178.      * @return {@code false} if calling {@link #increment(int)
  179.      * increment(nTimes)} would call the {@link MaxCountExceededCallback callback}
  180.      * {@code true} otherwise.
  181.      * @throws MathIllegalArgumentException if {@code nTimes} is negative.
  182.      */
  183.     public boolean canIncrement(int nTimes) {
  184.         if (nTimes < 0) {
  185.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL,
  186.                                                    nTimes, 0);
  187.         }
  188.         return count <= maximalCount - nTimes;
  189.     }

  190.     /**
  191.      * Performs multiple increments.
  192.      *
  193.      * @param nTimes Number of increments.
  194.      * @throws MathIllegalArgumentException if {@code nTimes} is negative.
  195.      *
  196.      * @see #increment()
  197.      */
  198.     public void increment(int nTimes) {
  199.         if (nTimes < 0) {
  200.             throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL,
  201.                                                    nTimes, 0);
  202.         }

  203.         for (int i = 0; i < nTimes; i++) {
  204.             increment();
  205.         }
  206.     }

  207.     /**
  208.      * Adds the increment value to the current iteration count.
  209.      * At counter exhaustion, this method will call the
  210.      * {@link MaxCountExceededCallback#trigger(int) trigger} method of the
  211.      * callback object passed to the
  212.      * {@link #withCallback(MaxCountExceededCallback)} method.
  213.      *
  214.      * @see #increment(int)
  215.      */
  216.     public void increment() {
  217.         if (count > maximalCount - 1) {
  218.             maxCountCallback.trigger(maximalCount);
  219.         }
  220.         ++count;
  221.     }

  222.     /**
  223.      * Resets the counter to 0.
  224.      */
  225.     public void reset() {
  226.         count = 0;
  227.     }
  228. }