1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.internal.util; 26 27 import java.util.List; 28 import java.util.function.BiFunction; 29 import java.util.function.Function; 30 31 /** 32 * Utility methods to check if state or arguments are correct. 33 * 34 */ 35 public class Preconditions { 36 37 /** 38 * Maps out-of-bounds values to a runtime exception. 39 * 40 * @param checkKind the kind of bounds check, whose name may correspond 41 * to the name of one of the range check methods, checkIndex, 42 * checkFromToIndex, checkFromIndexSize 43 * @param args the out-of-bounds arguments that failed the range check. 44 * If the checkKind corresponds a the name of a range check method 45 * then the bounds arguments are those that can be passed in order 46 * to the method. 47 * @param oobef the exception formatter that when applied with a checkKind 48 * and a list out-of-bounds arguments returns a runtime exception. 49 * If {@code null} then, it is as if an exception formatter was 50 * supplied that returns {@link IndexOutOfBoundsException} for any 51 * given arguments. 52 * @return the runtime exception 53 */ outOfBounds( BiFunction<String, List<Integer>, ? extends RuntimeException> oobef, String checkKind, Integer... args)54 private static RuntimeException outOfBounds( 55 BiFunction<String, List<Integer>, ? extends RuntimeException> oobef, 56 String checkKind, 57 Integer... args) { 58 List<Integer> largs = List.of(args); 59 RuntimeException e = oobef == null 60 ? null : oobef.apply(checkKind, largs); 61 return e == null 62 ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e; 63 } 64 outOfBoundsCheckIndex( BiFunction<String, List<Integer>, ? extends RuntimeException> oobe, int index, int length)65 private static RuntimeException outOfBoundsCheckIndex( 66 BiFunction<String, List<Integer>, ? extends RuntimeException> oobe, 67 int index, int length) { 68 return outOfBounds(oobe, "checkIndex", index, length); 69 } 70 outOfBoundsCheckFromToIndex( BiFunction<String, List<Integer>, ? extends RuntimeException> oobe, int fromIndex, int toIndex, int length)71 private static RuntimeException outOfBoundsCheckFromToIndex( 72 BiFunction<String, List<Integer>, ? extends RuntimeException> oobe, 73 int fromIndex, int toIndex, int length) { 74 return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length); 75 } 76 outOfBoundsCheckFromIndexSize( BiFunction<String, List<Integer>, ? extends RuntimeException> oobe, int fromIndex, int size, int length)77 private static RuntimeException outOfBoundsCheckFromIndexSize( 78 BiFunction<String, List<Integer>, ? extends RuntimeException> oobe, 79 int fromIndex, int size, int length) { 80 return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length); 81 } 82 83 /** 84 * Returns an out-of-bounds exception formatter from an given exception 85 * factory. The exception formatter is a function that formats an 86 * out-of-bounds message from its arguments and applies that message to the 87 * given exception factory to produce and relay an exception. 88 * 89 * <p>The exception formatter accepts two arguments: a {@code String} 90 * describing the out-of-bounds range check that failed, referred to as the 91 * <em>check kind</em>; and a {@code List<Integer>} containing the 92 * out-of-bound integer values that failed the check. The list of 93 * out-of-bound values is not modified. 94 * 95 * <p>Three check kinds are supported {@code checkIndex}, 96 * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding 97 * respectively to the specified application of an exception formatter as an 98 * argument to the out-of-bounds range check methods 99 * {@link #checkIndex(int, int, BiFunction) checkIndex}, 100 * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and 101 * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}. 102 * Thus a supported check kind corresponds to a method name and the 103 * out-of-bound integer values correspond to method argument values, in 104 * order, preceding the exception formatter argument (similar in many 105 * respects to the form of arguments required for a reflective invocation of 106 * such a range check method). 107 * 108 * <p>Formatter arguments conforming to such supported check kinds will 109 * produce specific exception messages describing failed out-of-bounds 110 * checks. Otherwise, more generic exception messages will be produced in 111 * any of the following cases: the check kind is supported but fewer 112 * or more out-of-bounds values are supplied, the check kind is not 113 * supported, the check kind is {@code null}, or the list of out-of-bound 114 * values is {@code null}. 115 * 116 * @apiNote 117 * This method produces an out-of-bounds exception formatter that can be 118 * passed as an argument to any of the supported out-of-bounds range check 119 * methods declared by {@code Objects}. For example, a formatter producing 120 * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a 121 * {@code static final} field as follows: 122 * <pre>{@code 123 * static final 124 * BiFunction<String, List<Integer>, ArrayIndexOutOfBoundsException> AIOOBEF = 125 * outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new); 126 * }</pre> 127 * The formatter instance {@code AIOOBEF} may be passed as an argument to an 128 * out-of-bounds range check method, such as checking if an {@code index} 129 * is within the bounds of a {@code limit}: 130 * <pre>{@code 131 * checkIndex(index, limit, AIOOBEF); 132 * }</pre> 133 * If the bounds check fails then the range check method will throw an 134 * {@code ArrayIndexOutOfBoundsException} with an appropriate exception 135 * message that is a produced from {@code AIOOBEF} as follows: 136 * <pre>{@code 137 * AIOOBEF.apply("checkIndex", List.of(index, limit)); 138 * }</pre> 139 * 140 * @param f the exception factory, that produces an exception from a message 141 * where the message is produced and formatted by the returned 142 * exception formatter. If this factory is stateless and side-effect 143 * free then so is the returned formatter. 144 * Exceptions thrown by the factory are relayed to the caller 145 * of the returned formatter. 146 * @param <X> the type of runtime exception to be returned by the given 147 * exception factory and relayed by the exception formatter 148 * @return the out-of-bounds exception formatter 149 */ 150 public static <X extends RuntimeException> outOfBoundsExceptionFormatter(Function<String, X> f)151 BiFunction<String, List<Integer>, X> outOfBoundsExceptionFormatter(Function<String, X> f) { 152 // Use anonymous class to avoid bootstrap issues if this method is 153 // used early in startup 154 return new BiFunction<String, List<Integer>, X>() { 155 @Override 156 public X apply(String checkKind, List<Integer> args) { 157 return f.apply(outOfBoundsMessage(checkKind, args)); 158 } 159 }; 160 } 161 162 private static String outOfBoundsMessage(String checkKind, List<Integer> args) { 163 if (checkKind == null && args == null) { 164 return String.format("Range check failed"); 165 } else if (checkKind == null) { 166 return String.format("Range check failed: %s", args); 167 } else if (args == null) { 168 return String.format("Range check failed: %s", checkKind); 169 } 170 171 int argSize = 0; 172 switch (checkKind) { 173 case "checkIndex": 174 argSize = 2; 175 break; 176 case "checkFromToIndex": 177 case "checkFromIndexSize": 178 argSize = 3; 179 break; 180 default: 181 } 182 183 // Switch to default if fewer or more arguments than required are supplied 184 switch ((args.size() != argSize) ? "" : checkKind) { 185 case "checkIndex": 186 return String.format("Index %d out-of-bounds for length %d", 187 args.get(0), args.get(1)); 188 case "checkFromToIndex": 189 return String.format("Range [%d, %d) out-of-bounds for length %d", 190 args.get(0), args.get(1), args.get(2)); 191 case "checkFromIndexSize": 192 return String.format("Range [%d, %<d + %d) out-of-bounds for length %d", 193 args.get(0), args.get(1), args.get(2)); 194 default: 195 return String.format("Range check failed: %s %s", checkKind, args); 196 } 197 } 198 199 /** 200 * Checks if the {@code index} is within the bounds of the range from 201 * {@code 0} (inclusive) to {@code length} (exclusive). 202 * 203 * <p>The {@code index} is defined to be out-of-bounds if any of the 204 * following inequalities is true: 205 * <ul> 206 * <li>{@code index < 0}</li> 207 * <li>{@code index >= length}</li> 208 * <li>{@code length < 0}, which is implied from the former inequalities</li> 209 * </ul> 210 * 211 * <p>If the {@code index} is out-of-bounds, then a runtime exception is 212 * thrown that is the result of applying the following arguments to the 213 * exception formatter: the name of this method, {@code checkIndex}; 214 * and an unmodifiable list integers whose values are, in order, the 215 * out-of-bounds arguments {@code index} and {@code length}. 216 * 217 * @param <X> the type of runtime exception to throw if the arguments are 218 * out-of-bounds 219 * @param index the index 220 * @param length the upper-bound (exclusive) of the range 221 * @param oobef the exception formatter that when applied with this 222 * method name and out-of-bounds arguments returns a runtime 223 * exception. If {@code null} or returns {@code null} then, it is as 224 * if an exception formatter produced from an invocation of 225 * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used 226 * instead (though it may be more efficient). 227 * Exceptions thrown by the formatter are relayed to the caller. 228 * @return {@code index} if it is within bounds of the range 229 * @throws X if the {@code index} is out-of-bounds and the exception 230 * formatter is non-{@code null} 231 * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds 232 * and the exception formatter is {@code null} 233 * @since 9 234 * 235 * @implNote 236 * This method is made intrinsic in optimizing compilers to guide them to 237 * perform unsigned comparisons of the index and length when it is known the 238 * length is a non-negative value (such as that of an array length or from 239 * the upper bound of a loop) 240 */ 241 // Android-removed: @HotSpotIntrinsicCandidate not present on Android yet (could reconsider). 242 // @HotSpotIntrinsicCandidate 243 public static <X extends RuntimeException> 244 int checkIndex(int index, int length, 245 BiFunction<String, List<Integer>, X> oobef) { 246 if (index < 0 || index >= length) 247 throw outOfBoundsCheckIndex(oobef, index, length); 248 return index; 249 } 250 251 /** 252 * Checks if the sub-range from {@code fromIndex} (inclusive) to 253 * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} 254 * (inclusive) to {@code length} (exclusive). 255 * 256 * <p>The sub-range is defined to be out-of-bounds if any of the following 257 * inequalities is true: 258 * <ul> 259 * <li>{@code fromIndex < 0}</li> 260 * <li>{@code fromIndex > toIndex}</li> 261 * <li>{@code toIndex > length}</li> 262 * <li>{@code length < 0}, which is implied from the former inequalities</li> 263 * </ul> 264 * 265 * <p>If the sub-range is out-of-bounds, then a runtime exception is 266 * thrown that is the result of applying the following arguments to the 267 * exception formatter: the name of this method, {@code checkFromToIndex}; 268 * and an unmodifiable list integers whose values are, in order, the 269 * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. 270 * 271 * @param <X> the type of runtime exception to throw if the arguments are 272 * out-of-bounds 273 * @param fromIndex the lower-bound (inclusive) of the sub-range 274 * @param toIndex the upper-bound (exclusive) of the sub-range 275 * @param length the upper-bound (exclusive) the range 276 * @param oobef the exception formatter that when applied with this 277 * method name and out-of-bounds arguments returns a runtime 278 * exception. If {@code null} or returns {@code null} then, it is as 279 * if an exception formatter produced from an invocation of 280 * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used 281 * instead (though it may be more efficient). 282 * Exceptions thrown by the formatter are relayed to the caller. 283 * @return {@code fromIndex} if the sub-range within bounds of the range 284 * @throws X if the sub-range is out-of-bounds and the exception factory 285 * function is non-{@code null} 286 * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and 287 * the exception factory function is {@code null} 288 * @since 9 289 */ 290 public static <X extends RuntimeException> 291 int checkFromToIndex(int fromIndex, int toIndex, int length, 292 BiFunction<String, List<Integer>, X> oobef) { 293 if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) 294 throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); 295 return fromIndex; 296 } 297 298 /** 299 * Checks if the sub-range from {@code fromIndex} (inclusive) to 300 * {@code fromIndex + size} (exclusive) is within the bounds of range from 301 * {@code 0} (inclusive) to {@code length} (exclusive). 302 * 303 * <p>The sub-range is defined to be out-of-bounds if any of the following 304 * inequalities is true: 305 * <ul> 306 * <li>{@code fromIndex < 0}</li> 307 * <li>{@code size < 0}</li> 308 * <li>{@code fromIndex + size > length}, taking into account integer overflow</li> 309 * <li>{@code length < 0}, which is implied from the former inequalities</li> 310 * </ul> 311 * 312 * <p>If the sub-range is out-of-bounds, then a runtime exception is 313 * thrown that is the result of applying the following arguments to the 314 * exception formatter: the name of this method, {@code checkFromIndexSize}; 315 * and an unmodifiable list integers whose values are, in order, the 316 * out-of-bounds arguments {@code fromIndex}, {@code size}, and 317 * {@code length}. 318 * 319 * @param <X> the type of runtime exception to throw if the arguments are 320 * out-of-bounds 321 * @param fromIndex the lower-bound (inclusive) of the sub-interval 322 * @param size the size of the sub-range 323 * @param length the upper-bound (exclusive) of the range 324 * @param oobef the exception formatter that when applied with this 325 * method name and out-of-bounds arguments returns a runtime 326 * exception. If {@code null} or returns {@code null} then, it is as 327 * if an exception formatter produced from an invocation of 328 * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used 329 * instead (though it may be more efficient). 330 * Exceptions thrown by the formatter are relayed to the caller. 331 * @return {@code fromIndex} if the sub-range within bounds of the range 332 * @throws X if the sub-range is out-of-bounds and the exception factory 333 * function is non-{@code null} 334 * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and 335 * the exception factory function is {@code null} 336 * @since 9 337 */ 338 public static <X extends RuntimeException> 339 int checkFromIndexSize(int fromIndex, int size, int length, 340 BiFunction<String, List<Integer>, X> oobef) { 341 if ((length | fromIndex | size) < 0 || size > length - fromIndex) 342 throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); 343 return fromIndex; 344 } 345 } 346