1 /*
  2  * Copyright (c) 2024, 2025, 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 java.lang.runtime;
 26 
 27 /**
 28  * A testing conversion of a value is exact if it yields a result without loss
 29  * of information or throwing an exception. Otherwise, it is inexact. Some
 30  * conversions are always exact regardless of the value. These conversions are
 31  * said to be unconditionally exact.
 32  * <p>
 33  * For example, a conversion from {@code int} to {@code byte} for the value 10
 34  * is exact because the result, 10, is the same as the original value. In
 35  * contrast, if the {@code int} variable {@code i} stores the value 1000 then a
 36  * narrowing primitive conversion to {@code byte} will yield the result -24.
 37  * Loss of information has occurred: both the magnitude and the sign of the
 38  * result are different than those of the original value. As such, a conversion
 39  * from {@code int} to {@code byte} for the value 1000 is inexact. Finally a
 40  * widening primitive conversion from {@code byte} to {@code int} is
 41  * unconditionally exact because it will always succeed with no loss of
 42  * information about the magnitude of the numeric value.
 43  * <p>
 44  * The methods in this class provide the run-time support for the exactness
 45  * checks of testing conversions from a primitive type to primitive type. These
 46  * methods may be used, for example, by Java compiler implementations to
 47  * implement checks for {@code instanceof} and pattern matching runtime
 48  * implementations. Unconditionally exact testing conversions do not require a
 49  * corresponding action at run time and, for this reason, methods corresponding
 50  * to these exactness checks are omitted here.
 51  * <p>
 52  * The run time conversion checks examine whether loss of information would
 53  * occur if a testing conversion would be to be applied. In those cases where a
 54  * floating-point primitive type is involved, and the value of the testing
 55  * conversion is either signed zero, signed infinity or {@code NaN}, these
 56  * methods comply with the following:
 57  *
 58  * <ul>
 59  * <li>Converting a floating-point negative zero to an integer type is considered
 60  *   inexact.</li>
 61  * <li>Converting a floating-point {@code NaN} or infinity to an integer type is
 62  *   considered inexact.</li>
 63  * <li>Converting a floating-point {@code NaN} or infinity or signed zero to another
 64  *   floating-point type is considered exact.</li>
 65  * </ul>
 66  *
 67  * @see <a href="../../../../../specs/primitive-types-in-patterns-instanceof-switch-jls.html#jls-5.7.1">
 68  * JLS 5.7.1 Exact Testing Conversions</a>
 69  * @see <a href="../../../../../specs/primitive-types-in-patterns-instanceof-switch-jls.html#jls-5.7.2">
 70  * JLS 5.7.2 Unconditionally Exact Testing Conversions</a>
 71  * @see <a href="../../../../../specs/primitive-types-in-patterns-instanceof-switch-jls.html#jls-15.20.2">
 72  * JLS 15.20.2 The instanceof Operator</a>
 73  *
 74  * @implNote Some exactness checks describe a test which can be redirected
 75  * safely through one of the existing methods. Those are omitted too (i.e.,
 76  * {@code byte} to {@code char} can be redirected  to
 77  * {@link ExactConversionsSupport#isIntToCharExact(int)}, {@code short} to
 78  * {@code byte} can be redirected to
 79  * {@link ExactConversionsSupport#isIntToByteExact(int)} and similarly for
 80  * {@code short} to {@code char}, {@code char} to {@code byte} and {@code char}
 81  * to {@code short} to the corresponding methods that take an {@code int}).
 82  *
 83  * @since 23
 84  */
 85 public final class ExactConversionsSupport {
 86 
 87     private ExactConversionsSupport() { }
 88 
 89     /**
 90      * Exactness method from int to byte
 91      * @param n value
 92      * @return true if and only if the passed value can be converted exactly to the target type
 93      */
 94     public static boolean isIntToByteExact(int n)      {return n == (int)(byte)n;}
 95 
 96     /**
 97      * Exactness method from int to short
 98      * @param n value
 99      * @return true if and only if the passed value can be converted exactly to the target type
100      */
101     public static boolean isIntToShortExact(int n)     {return n == (int)(short)n;}
102 
103     /**
104      * Exactness method from int to char
105      * @param n value
106      * @return true if and only if the passed value can be converted exactly to the target type
107      */
108     public static boolean isIntToCharExact(int n)      {return n == (int)(char)n;}
109 
110     /**
111      * Exactness method from int to float
112      * @param n value
113      * @return true if and only if the passed value can be converted exactly to the target type
114      *
115      * @implSpec relies on the notion of representation equivalence defined in the
116      * specification of the {@linkplain Double} class.
117      */
118     public static boolean isIntToFloatExact(int n) {
119         return n == (int)(float)n && n != Integer.MAX_VALUE;
120     }
121     /**
122      * Exactness method from long to byte
123      * @param n value
124      * @return true if and only if the passed value can be converted exactly to the target type
125      */
126     public static boolean isLongToByteExact(long n)    {return n == (long)(byte)n;}
127 
128     /**
129      * Exactness method from long to short
130      * @param n value
131      * @return true if and only if the passed value can be converted exactly to the target type
132      */
133     public static boolean isLongToShortExact(long n)   {return n == (long)(short)n;}
134 
135     /**
136      * Exactness method from long to char
137      * @param n value
138      * @return true if and only if the passed value can be converted exactly to the target type
139      */
140     public static boolean isLongToCharExact(long n)    {return n == (long)(char)n;}
141 
142     /**
143      * Exactness method from long to int
144      * @param n value
145      * @return true if and only if the passed value can be converted exactly to the target type
146      */
147     public static boolean isLongToIntExact(long n)     {return n == (long)(int)n;}
148 
149     /**
150      * Exactness method from long to float
151      * @param n value
152      * @return true if and only if the passed value can be converted exactly to the target type
153      * @implSpec relies on the notion of representation equivalence defined in the
154      * specification of the {@linkplain Double} class.
155      */
156     public static boolean isLongToFloatExact(long n) {
157         return n == (long)(float)n && n != Long.MAX_VALUE;
158     }
159 
160     /**
161      * Exactness method from long to double
162      * @param n value
163      * @return true if and only if the passed value can be converted exactly to the target type
164      * @implSpec relies on the notion of representation equivalence defined in the
165      * specification of the {@linkplain Double} class.
166      */
167     public static boolean isLongToDoubleExact(long n) {
168         return n == (long)(double)n && n != Long.MAX_VALUE;
169     }
170 
171     /**
172      * Exactness method from float to byte
173      * @param n value
174      * @return true if and only if the passed value can be converted exactly to the target type
175      * @implSpec relies on the notion of representation equivalence defined in the
176      * specification of the {@linkplain Double} class.
177      */
178     public static boolean isFloatToByteExact(float n)  {
179         return n == (float)(byte)n && !isNegativeZero(n);
180     }
181 
182     /**
183      * Exactness method from float to short
184      * @param n value
185      * @return true if and only if the passed value can be converted exactly to the target type
186      * @implSpec relies on the notion of representation equivalence defined in the
187      * specification of the {@linkplain Double} class.
188      */
189     public static boolean isFloatToShortExact(float n) {
190         return n == (float)(short)n && !isNegativeZero(n);
191     }
192 
193     /**
194      * Exactness method from float to char
195      * @param n value
196      * @return true if and only if the passed value can be converted exactly to the target type
197      * @implSpec relies on the notion of representation equivalence defined in the
198      * specification of the {@linkplain Double} class.
199      */
200     public static boolean isFloatToCharExact(float n)  {
201         return n == (float)(char)n && !isNegativeZero(n);
202     }
203 
204     /**
205      * Exactness method from float to int
206      * @param n value
207      * @return true if and only if the passed value can be converted exactly to the target type
208      * @implSpec relies on the notion of representation equivalence defined in the
209      * specification of the {@linkplain Double} class.
210      */
211     public static boolean isFloatToIntExact(float n) {
212         return n == (float)(int)n && n != 0x1p31f && !isNegativeZero(n);
213     }
214 
215     /**
216      * Exactness method from float to long
217      * @param n value
218      * @return true if and only if the passed value can be converted exactly to the target type
219      * @implSpec relies on the notion of representation equivalence defined in the
220      * specification of the {@linkplain Double} class.
221      */
222     public static boolean isFloatToLongExact(float n) {
223         return n == (float)(long)n && n != 0x1p63f && !isNegativeZero(n);
224     }
225 
226     /**
227      * Exactness method from double to byte
228      * @param n value
229      * @return true if and only if the passed value can be converted exactly to the target type
230      * @implSpec relies on the notion of representation equivalence defined in the
231      * specification of the {@linkplain Double} class.
232      */
233     public static boolean isDoubleToByteExact(double n) {
234         return n == (double)(byte)n && !isNegativeZero(n);
235     }
236 
237     /**
238      * Exactness method from double to short
239      * @param n value
240      * @return true if and only if the passed value can be converted exactly to the target type
241      * @implSpec relies on the notion of representation equivalence defined in the
242      * specification of the {@linkplain Double} class.
243      */
244     public static boolean isDoubleToShortExact(double n){
245         return n == (double)(short)n && !isNegativeZero(n);
246     }
247 
248     /**
249      * Exactness method from double to char
250      * @param n value
251      * @return true if and only if the passed value can be converted exactly to the target type
252      * @implSpec relies on the notion of representation equivalence defined in the
253      * specification of the {@linkplain Double} class.
254      */
255     public static boolean isDoubleToCharExact(double n) {
256         return n == (double)(char)n && !isNegativeZero(n);
257     }
258 
259     /**
260      * Exactness method from double to int
261      * @param n value
262      * @return true if and only if the passed value can be converted exactly to the target type
263      * @implSpec relies on the notion of representation equivalence defined in the
264      * specification of the {@linkplain Double} class.
265      */
266     public static boolean isDoubleToIntExact(double n)  {
267         return n == (double)(int)n && !isNegativeZero(n);
268     }
269 
270     /**
271      * Exactness method from double to long
272      * @param n value
273      * @return true if and only if the passed value can be converted exactly to the target type
274      * @implSpec relies on the notion of representation equivalence defined in the
275      * specification of the {@linkplain Double} class.
276      */
277     public static boolean isDoubleToLongExact(double n) {
278         return n == (double)(long)n && n != 0x1p63 && !isNegativeZero(n);
279     }
280 
281     /**
282      * Exactness method from double to float
283      * @param n value
284      * @return true if and only if the passed value can be converted exactly to the target type
285      * @implSpec relies on the notion of representation equivalence defined in the
286      * specification of the {@linkplain Double} class.
287      */
288     public static boolean isDoubleToFloatExact(double n) {
289         return n == (double)(float)n || n != n;
290     }
291 
292     private static boolean isNegativeZero(float n) {
293         return Float.floatToRawIntBits(n) == Integer.MIN_VALUE;
294     }
295 
296     private static boolean isNegativeZero(double n) {
297         return Double.doubleToRawLongBits(n) == Long.MIN_VALUE;
298     }
299 }