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