All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jdk.internal.util.Preconditions Maven / Gradle / Ivy

There is a newer version: 17.alpha.0.57
Show newest version
/*
 * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package jdk.internal.util;

import jdk.internal.vm.annotation.IntrinsicCandidate;

import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * Utility methods to check if state or arguments are correct.
 *
 */
public class Preconditions {

    /**
     * Maps out-of-bounds values to a runtime exception.
     *
     * @param checkKind the kind of bounds check, whose name may correspond
     *        to the name of one of the range check methods, checkIndex,
     *        checkFromToIndex, checkFromIndexSize
     * @param args the out-of-bounds arguments that failed the range check.
     *        If the checkKind corresponds a the name of a range check method
     *        then the bounds arguments are those that can be passed in order
     *        to the method.
     * @param oobef the exception formatter that when applied with a checkKind
     *        and a list out-of-bounds arguments returns a runtime exception.
     *        If {@code null} then, it is as if an exception formatter was
     *        supplied that returns {@link IndexOutOfBoundsException} for any
     *        given arguments.
     * @return the runtime exception
     */
    private static RuntimeException outOfBounds(
            BiFunction, ? extends RuntimeException> oobef,
            String checkKind,
            Number... args) {
        List largs = List.of(args);
        RuntimeException e = oobef == null
                             ? null : oobef.apply(checkKind, largs);
        return e == null
               ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e;
    }

    private static RuntimeException outOfBoundsCheckIndex(
            BiFunction, ? extends RuntimeException> oobe,
            int index, int length) {
        return outOfBounds(oobe, "checkIndex", index, length);
    }

    private static RuntimeException outOfBoundsCheckFromToIndex(
            BiFunction, ? extends RuntimeException> oobe,
            int fromIndex, int toIndex, int length) {
        return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length);
    }

    private static RuntimeException outOfBoundsCheckFromIndexSize(
            BiFunction, ? extends RuntimeException> oobe,
            int fromIndex, int size, int length) {
        return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length);
    }

    private static RuntimeException outOfBoundsCheckIndex(
            BiFunction, ? extends RuntimeException> oobe,
            long index, long length) {
        return outOfBounds(oobe, "checkIndex", index, length);
    }

    private static RuntimeException outOfBoundsCheckFromToIndex(
            BiFunction, ? extends RuntimeException> oobe,
            long fromIndex, long toIndex, long length) {
        return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length);
    }

    private static RuntimeException outOfBoundsCheckFromIndexSize(
            BiFunction, ? extends RuntimeException> oobe,
            long fromIndex, long size, long length) {
        return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length);
    }

    /**
     * Returns an out-of-bounds exception formatter from an given exception
     * factory.  The exception formatter is a function that formats an
     * out-of-bounds message from its arguments and applies that message to the
     * given exception factory to produce and relay an exception.
     *
     * 

The exception formatter accepts two arguments: a {@code String} * describing the out-of-bounds range check that failed, referred to as the * check kind; and a {@code List} containing the * out-of-bound integral values that failed the check. The list of * out-of-bound values is not modified. * *

Three check kinds are supported {@code checkIndex}, * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding * respectively to the specified application of an exception formatter as an * argument to the out-of-bounds range check methods * {@link #checkIndex(int, int, BiFunction) checkIndex}, * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}. * Thus a supported check kind corresponds to a method name and the * out-of-bound integral values correspond to method argument values, in * order, preceding the exception formatter argument (similar in many * respects to the form of arguments required for a reflective invocation of * such a range check method). * *

Formatter arguments conforming to such supported check kinds will * produce specific exception messages describing failed out-of-bounds * checks. Otherwise, more generic exception messages will be produced in * any of the following cases: the check kind is supported but fewer * or more out-of-bounds values are supplied, the check kind is not * supported, the check kind is {@code null}, or the list of out-of-bound * values is {@code null}. * * @apiNote * This method produces an out-of-bounds exception formatter that can be * passed as an argument to any of the supported out-of-bounds range check * methods declared by {@code Objects}. For example, a formatter producing * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a * {@code static final} field as follows: *

{@code
     * static final
     * BiFunction, ArrayIndexOutOfBoundsException> AIOOBEF =
     *     outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
     * }
* The formatter instance {@code AIOOBEF} may be passed as an argument to an * out-of-bounds range check method, such as checking if an {@code index} * is within the bounds of a {@code limit}: *
{@code
     * checkIndex(index, limit, AIOOBEF);
     * }
* If the bounds check fails then the range check method will throw an * {@code ArrayIndexOutOfBoundsException} with an appropriate exception * message that is a produced from {@code AIOOBEF} as follows: *
{@code
     * AIOOBEF.apply("checkIndex", List.of(index, limit));
     * }
* * @param f the exception factory, that produces an exception from a message * where the message is produced and formatted by the returned * exception formatter. If this factory is stateless and side-effect * free then so is the returned formatter. * Exceptions thrown by the factory are relayed to the caller * of the returned formatter. * @param the type of runtime exception to be returned by the given * exception factory and relayed by the exception formatter * @return the out-of-bounds exception formatter */ public static BiFunction, X> outOfBoundsExceptionFormatter(Function f) { // Use anonymous class to avoid bootstrap issues if this method is // used early in startup return new BiFunction, X>() { @Override public X apply(String checkKind, List args) { return f.apply(outOfBoundsMessage(checkKind, args)); } }; } private static String outOfBoundsMessage(String checkKind, List args) { if (checkKind == null && args == null) { return String.format("Range check failed"); } else if (checkKind == null) { return String.format("Range check failed: %s", args); } else if (args == null) { return String.format("Range check failed: %s", checkKind); } int argSize = 0; switch (checkKind) { case "checkIndex": argSize = 2; break; case "checkFromToIndex": case "checkFromIndexSize": argSize = 3; break; default: } // Switch to default if fewer or more arguments than required are supplied switch ((args.size() != argSize) ? "" : checkKind) { case "checkIndex": return String.format("Index %s out of bounds for length %s", args.get(0), args.get(1)); case "checkFromToIndex": return String.format("Range [%s, %s) out of bounds for length %s", args.get(0), args.get(1), args.get(2)); case "checkFromIndexSize": return String.format("Range [%s, %The {@code index} is defined to be out of bounds if any of the * following inequalities is true: *
    *
  • {@code index < 0}
  • *
  • {@code index >= length}
  • *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* *

If the {@code index} is out of bounds, then a runtime exception is * thrown that is the result of applying the following arguments to the * exception formatter: the name of this method, {@code checkIndex}; * and an unmodifiable list of integers whose values are, in order, the * out-of-bounds arguments {@code index} and {@code length}. * * @param the type of runtime exception to throw if the arguments are * out of bounds * @param index the index * @param length the upper-bound (exclusive) of the range * @param oobef the exception formatter that when applied with this * method name and out-of-bounds arguments returns a runtime * exception. If {@code null} or returns {@code null} then, it is as * if an exception formatter produced from an invocation of * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used * instead (though it may be more efficient). * Exceptions thrown by the formatter are relayed to the caller. * @return {@code index} if it is within bounds of the range * @throws X if the {@code index} is out of bounds and the exception * formatter is non-{@code null} * @throws IndexOutOfBoundsException if the {@code index} is out of bounds * and the exception formatter is {@code null} * @since 9 * * @implNote * This method is made intrinsic in optimizing compilers to guide them to * perform unsigned comparisons of the index and length when it is known the * length is a non-negative value (such as that of an array length or from * the upper bound of a loop) */ @IntrinsicCandidate public static int checkIndex(int index, int length, BiFunction, X> oobef) { if (index < 0 || index >= length) throw outOfBoundsCheckIndex(oobef, index, length); return index; } /** * Checks if the sub-range from {@code fromIndex} (inclusive) to * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} * (inclusive) to {@code length} (exclusive). * *

The sub-range is defined to be out of bounds if any of the following * inequalities is true: *

    *
  • {@code fromIndex < 0}
  • *
  • {@code fromIndex > toIndex}
  • *
  • {@code toIndex > length}
  • *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* *

If the sub-range is out of bounds, then a runtime exception is * thrown that is the result of applying the following arguments to the * exception formatter: the name of this method, {@code checkFromToIndex}; * and an unmodifiable list of integers whose values are, in order, the * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. * * @param the type of runtime exception to throw if the arguments are * out of bounds * @param fromIndex the lower-bound (inclusive) of the sub-range * @param toIndex the upper-bound (exclusive) of the sub-range * @param length the upper-bound (exclusive) the range * @param oobef the exception formatter that when applied with this * method name and out-of-bounds arguments returns a runtime * exception. If {@code null} or returns {@code null} then, it is as * if an exception formatter produced from an invocation of * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used * instead (though it may be more efficient). * Exceptions thrown by the formatter are relayed to the caller. * @return {@code fromIndex} if the sub-range within bounds of the range * @throws X if the sub-range is out of bounds and the exception factory * function is non-{@code null} * @throws IndexOutOfBoundsException if the sub-range is out of bounds and * the exception factory function is {@code null} * @since 9 */ public static int checkFromToIndex(int fromIndex, int toIndex, int length, BiFunction, X> oobef) { if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); return fromIndex; } /** * Checks if the sub-range from {@code fromIndex} (inclusive) to * {@code fromIndex + size} (exclusive) is within the bounds of range from * {@code 0} (inclusive) to {@code length} (exclusive). * *

The sub-range is defined to be out of bounds if any of the following * inequalities is true: *

    *
  • {@code fromIndex < 0}
  • *
  • {@code size < 0}
  • *
  • {@code fromIndex + size > length}, taking into account integer overflow
  • *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* *

If the sub-range is out of bounds, then a runtime exception is * thrown that is the result of applying the following arguments to the * exception formatter: the name of this method, {@code checkFromIndexSize}; * and an unmodifiable list of integers whose values are, in order, the * out-of-bounds arguments {@code fromIndex}, {@code size}, and * {@code length}. * * @param the type of runtime exception to throw if the arguments are * out of bounds * @param fromIndex the lower-bound (inclusive) of the sub-interval * @param size the size of the sub-range * @param length the upper-bound (exclusive) of the range * @param oobef the exception formatter that when applied with this * method name and out-of-bounds arguments returns a runtime * exception. If {@code null} or returns {@code null} then, it is as * if an exception formatter produced from an invocation of * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used * instead (though it may be more efficient). * Exceptions thrown by the formatter are relayed to the caller. * @return {@code fromIndex} if the sub-range within bounds of the range * @throws X if the sub-range is out of bounds and the exception factory * function is non-{@code null} * @throws IndexOutOfBoundsException if the sub-range is out of bounds and * the exception factory function is {@code null} * @since 9 */ public static int checkFromIndexSize(int fromIndex, int size, int length, BiFunction, X> oobef) { if ((length | fromIndex | size) < 0 || size > length - fromIndex) throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); return fromIndex; } /** * Checks if the {@code index} is within the bounds of the range from * {@code 0} (inclusive) to {@code length} (exclusive). * *

The {@code index} is defined to be out of bounds if any of the * following inequalities is true: *

    *
  • {@code index < 0}
  • *
  • {@code index >= length}
  • *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* *

If the {@code index} is out of bounds, then a runtime exception is * thrown that is the result of applying the following arguments to the * exception formatter: the name of this method, {@code checkIndex}; * and an unmodifiable list of longs whose values are, in order, the * out-of-bounds arguments {@code index} and {@code length}. * * @param the type of runtime exception to throw if the arguments are * out of bounds * @param index the index * @param length the upper-bound (exclusive) of the range * @param oobef the exception formatter that when applied with this * method name and out-of-bounds arguments returns a runtime * exception. If {@code null} or returns {@code null} then, it is as * if an exception formatter produced from an invocation of * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used * instead (though it may be more efficient). * Exceptions thrown by the formatter are relayed to the caller. * @return {@code index} if it is within bounds of the range * @throws X if the {@code index} is out of bounds and the exception * formatter is non-{@code null} * @throws IndexOutOfBoundsException if the {@code index} is out of bounds * and the exception formatter is {@code null} * @since 16 * * @implNote * This method is made intrinsic in optimizing compilers to guide them to * perform unsigned comparisons of the index and length when it is known the * length is a non-negative value (such as that of an array length or from * the upper bound of a loop) */ @IntrinsicCandidate public static long checkIndex(long index, long length, BiFunction, X> oobef) { if (index < 0 || index >= length) throw outOfBoundsCheckIndex(oobef, index, length); return index; } /** * Checks if the sub-range from {@code fromIndex} (inclusive) to * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} * (inclusive) to {@code length} (exclusive). * *

The sub-range is defined to be out of bounds if any of the following * inequalities is true: *

    *
  • {@code fromIndex < 0}
  • *
  • {@code fromIndex > toIndex}
  • *
  • {@code toIndex > length}
  • *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* *

If the sub-range is out of bounds, then a runtime exception is * thrown that is the result of applying the following arguments to the * exception formatter: the name of this method, {@code checkFromToIndex}; * and an unmodifiable list of longs whose values are, in order, the * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. * * @param the type of runtime exception to throw if the arguments are * out of bounds * @param fromIndex the lower-bound (inclusive) of the sub-range * @param toIndex the upper-bound (exclusive) of the sub-range * @param length the upper-bound (exclusive) the range * @param oobef the exception formatter that when applied with this * method name and out-of-bounds arguments returns a runtime * exception. If {@code null} or returns {@code null} then, it is as * if an exception formatter produced from an invocation of * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used * instead (though it may be more efficient). * Exceptions thrown by the formatter are relayed to the caller. * @return {@code fromIndex} if the sub-range within bounds of the range * @throws X if the sub-range is out of bounds and the exception factory * function is non-{@code null} * @throws IndexOutOfBoundsException if the sub-range is out of bounds and * the exception factory function is {@code null} * @since 16 */ public static long checkFromToIndex(long fromIndex, long toIndex, long length, BiFunction, X> oobef) { if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); return fromIndex; } /** * Checks if the sub-range from {@code fromIndex} (inclusive) to * {@code fromIndex + size} (exclusive) is within the bounds of range from * {@code 0} (inclusive) to {@code length} (exclusive). * *

The sub-range is defined to be out of bounds if any of the following * inequalities is true: *

    *
  • {@code fromIndex < 0}
  • *
  • {@code size < 0}
  • *
  • {@code fromIndex + size > length}, taking into account integer overflow
  • *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* *

If the sub-range is out of bounds, then a runtime exception is * thrown that is the result of applying the following arguments to the * exception formatter: the name of this method, {@code checkFromIndexSize}; * and an unmodifiable list of longs whose values are, in order, the * out-of-bounds arguments {@code fromIndex}, {@code size}, and * {@code length}. * * @param the type of runtime exception to throw if the arguments are * out of bounds * @param fromIndex the lower-bound (inclusive) of the sub-interval * @param size the size of the sub-range * @param length the upper-bound (exclusive) of the range * @param oobef the exception formatter that when applied with this * method name and out-of-bounds arguments returns a runtime * exception. If {@code null} or returns {@code null} then, it is as * if an exception formatter produced from an invocation of * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used * instead (though it may be more efficient). * Exceptions thrown by the formatter are relayed to the caller. * @return {@code fromIndex} if the sub-range within bounds of the range * @throws X if the sub-range is out of bounds and the exception factory * function is non-{@code null} * @throws IndexOutOfBoundsException if the sub-range is out of bounds and * the exception factory function is {@code null} * @since 16 */ public static long checkFromIndexSize(long fromIndex, long size, long length, BiFunction, X> oobef) { if ((length | fromIndex | size) < 0 || size > length - fromIndex) throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); return fromIndex; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy