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