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 }