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 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 package org.hipparchus.util; 23 24 import org.hipparchus.exception.LocalizedCoreFormats; 25 import org.hipparchus.exception.MathIllegalArgumentException; 26 import org.hipparchus.exception.MathIllegalStateException; 27 import org.hipparchus.exception.NullArgumentException; 28 29 /** 30 * Utility that increments a counter until a maximum is reached, at 31 * which point, the instance will by default throw a 32 * {@link MathIllegalStateException}. 33 * However, the user is able to override this behaviour by defining a 34 * custom {@link MaxCountExceededCallback callback}, in order to e.g. 35 * select which exception must be thrown. 36 */ 37 public class Incrementor { 38 /** Default callback. */ 39 private static final MaxCountExceededCallback DEFAULT_CALLBACK = 40 (int max) -> { 41 throw new MathIllegalStateException(LocalizedCoreFormats.MAX_COUNT_EXCEEDED, max); 42 }; 43 44 /** Upper limit for the counter. */ 45 private final int maximalCount; 46 /** Function called at counter exhaustion. */ 47 private final MaxCountExceededCallback maxCountCallback; 48 /** Current count. */ 49 private int count; 50 51 /** 52 * Defines a method to be called at counter exhaustion. 53 * The {@link #trigger(int) trigger} method should usually throw an exception. 54 */ 55 public interface MaxCountExceededCallback { 56 /** 57 * Function called when the maximal count has been reached. 58 * 59 * @param maximalCount Maximal count. 60 * @throws MathIllegalStateException at counter exhaustion 61 */ 62 void trigger(int maximalCount) throws MathIllegalStateException; 63 } 64 65 /** 66 * Creates an Incrementor. 67 * <p> 68 * The maximal value will be set to {@code Integer.MAX_VALUE}. 69 */ 70 public Incrementor() { 71 this(Integer.MAX_VALUE); 72 } 73 74 /** 75 * Creates an Incrementor. 76 * 77 * @param max Maximal count. 78 * @throws MathIllegalArgumentException if {@code max} is negative. 79 */ 80 public Incrementor(int max) { 81 this(max, DEFAULT_CALLBACK); 82 } 83 84 /** 85 * Creates an Incrementor. 86 * 87 * @param max Maximal count. 88 * @param cb Function to be called when the maximal count has been reached. 89 * @throws NullArgumentException if {@code cb} is {@code null}. 90 * @throws MathIllegalArgumentException if {@code max} is negative. 91 */ 92 public Incrementor(int max, 93 MaxCountExceededCallback cb) 94 throws NullArgumentException { 95 this(0, max, cb); 96 } 97 98 /** 99 * Creates an Incrementor. 100 * 101 * @param count Initial counter value. 102 * @param max Maximal count. 103 * @param cb Function to be called when the maximal count has been reached. 104 * @throws NullArgumentException if {@code cb} is {@code null}. 105 * @throws MathIllegalArgumentException if {@code max} is negative. 106 */ 107 private Incrementor(int count, 108 int max, 109 MaxCountExceededCallback cb) 110 throws NullArgumentException { 111 if (cb == null) { 112 throw new NullArgumentException(); 113 } 114 if (max < 0) { 115 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, max, 0); 116 } 117 this.maximalCount = max; 118 this.maxCountCallback = cb; 119 this.count = count; 120 } 121 122 /** 123 * Creates a new instance and set the counter to the given value. 124 * 125 * @param value Value of the counter. 126 * @return a new instance. 127 */ 128 public Incrementor withCount(int value) { 129 return new Incrementor(value, 130 this.maximalCount, 131 this.maxCountCallback); 132 } 133 134 /** 135 * Creates a new instance with a given maximal count. 136 * The counter is reset to 0. 137 * 138 * @param max Maximal count. 139 * @return a new instance. 140 * @throws MathIllegalArgumentException if {@code max} is negative. 141 */ 142 public Incrementor withMaximalCount(int max) { 143 return new Incrementor(0, 144 max, 145 this.maxCountCallback); 146 } 147 148 /** 149 * Creates a new instance with a given callback. 150 * The counter is reset to 0. 151 * 152 * @param cb Callback to be called at counter exhaustion. 153 * @return a new instance. 154 */ 155 public Incrementor withCallback(MaxCountExceededCallback cb) { 156 return new Incrementor(0, 157 this.maximalCount, 158 cb); 159 } 160 161 /** 162 * Gets the upper limit of the counter. 163 * 164 * @return the counter upper limit. 165 */ 166 public int getMaximalCount() { 167 return maximalCount; 168 } 169 170 /** 171 * Gets the current count. 172 * 173 * @return the current count. 174 */ 175 public int getCount() { 176 return count; 177 } 178 179 /** 180 * Checks whether incrementing the counter {@code nTimes} is allowed. 181 * 182 * @return {@code false} if calling {@link #increment()} 183 * will trigger a {@code MathIllegalStateException}, 184 * {@code true} otherwise. 185 */ 186 public boolean canIncrement() { 187 return canIncrement(1); 188 } 189 190 /** 191 * Checks whether incrementing the counter several times is allowed. 192 * 193 * @param nTimes Number of increments. 194 * @return {@code false} if calling {@link #increment(int) 195 * increment(nTimes)} would call the {@link MaxCountExceededCallback callback} 196 * {@code true} otherwise. 197 * @throws MathIllegalArgumentException if {@code nTimes} is negative. 198 */ 199 public boolean canIncrement(int nTimes) { 200 if (nTimes < 0) { 201 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, 202 nTimes, 0); 203 } 204 return count <= maximalCount - nTimes; 205 } 206 207 /** 208 * Performs multiple increments. 209 * 210 * @param nTimes Number of increments. 211 * @throws MathIllegalArgumentException if {@code nTimes} is negative. 212 * 213 * @see #increment() 214 */ 215 public void increment(int nTimes) { 216 if (nTimes < 0) { 217 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, 218 nTimes, 0); 219 } 220 221 for (int i = 0; i < nTimes; i++) { 222 increment(); 223 } 224 } 225 226 /** 227 * Adds the increment value to the current iteration count. 228 * At counter exhaustion, this method will call the 229 * {@link MaxCountExceededCallback#trigger(int) trigger} method of the 230 * callback object passed to the 231 * {@link #withCallback(MaxCountExceededCallback)} method. 232 * 233 * @see #increment(int) 234 */ 235 public void increment() { 236 if (count > maximalCount - 1) { 237 maxCountCallback.trigger(maximalCount); 238 } 239 ++count; 240 } 241 242 /** 243 * Resets the counter to 0. 244 */ 245 public void reset() { 246 count = 0; 247 } 248 }