| package org.checkerframework.checker.signedness.util; |
| |
| import java.io.IOException; |
| import java.io.RandomAccessFile; |
| import java.math.BigInteger; |
| import java.nio.ByteBuffer; |
| import java.nio.IntBuffer; |
| import org.checkerframework.checker.signedness.qual.Unsigned; |
| import org.checkerframework.framework.qual.AnnotatedFor; |
| |
| /** |
| * Provides static utility methods for unsigned values, beyond what is available in the JDK's |
| * Unsigned Integer API. The JDK's Unsigned Integer API is methods in primitive wrapper classes and |
| * in classes {@code Arrays}, {@code RandomAccessFile}, {@code ObjectInputStream}, and {@code |
| * DataInputStream}. |
| * |
| * <p>{@link SignednessUtilExtra} has more methods that reference packages that Android does not |
| * provide. That is, {@code SignednessUtil} can be used anywhere, and {@link SignednessUtilExtra} |
| * can be used anywhere except on Android. |
| * |
| * @checker_framework.manual #signedness-utilities Utility routines for manipulating unsigned values |
| */ |
| @AnnotatedFor("nullness") |
| public final class SignednessUtil { |
| |
| private SignednessUtil() { |
| throw new Error("Do not instantiate"); |
| } |
| |
| /** |
| * Wraps an unsigned byte array into a ByteBuffer. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#wrap(byte[]) wrap(byte[])}, but assumes that the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer wrapUnsigned(@Unsigned byte[] array) { |
| return ByteBuffer.wrap(array); |
| } |
| |
| /** |
| * Wraps an unsigned byte array into a ByteBuffer. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#wrap(byte[], int, int) wrap(byte[], int, int)}, but assumes that the input |
| * should be interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer wrapUnsigned(@Unsigned byte[] array, int offset, int length) { |
| return ByteBuffer.wrap(array, offset, length); |
| } |
| |
| /** |
| * Gets an unsigned int from the ByteBuffer b. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#getInt() getInt()}, but assumes that the result should be interpreted as |
| * unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned int getUnsignedInt(ByteBuffer b) { |
| return b.getInt(); |
| } |
| |
| /** |
| * Gets an unsigned short from the ByteBuffer b. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#getShort() getShort()}, but assumes that the result should be interpreted |
| * as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned short getUnsignedShort(ByteBuffer b) { |
| return b.getShort(); |
| } |
| |
| /** |
| * Gets an unsigned byte from the ByteBuffer b. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#get() get()}, but assumes that the result should be interpreted as |
| * unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned byte getUnsigned(ByteBuffer b) { |
| return b.get(); |
| } |
| |
| /** |
| * Gets an unsigned byte from the ByteBuffer b at i. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#get(int) get(int)}, but assumes that the result should be interpreted as |
| * unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned byte getUnsigned(ByteBuffer b, int i) { |
| return b.get(i); |
| } |
| |
| /** |
| * Populates an unsigned byte array from the ByteBuffer b at i with l bytes. This method is a |
| * wrapper around {@link java.nio.ByteBuffer#get(byte[] bs, int, int) get(byte[], int, int)}, but |
| * assumes that the bytes should be interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer getUnsigned(ByteBuffer b, byte[] bs, int i, int l) { |
| return b.get(bs, i, l); |
| } |
| |
| /** |
| * Places an unsigned byte into the ByteBuffer b. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#put(byte) put(byte)}, but assumes that the input should be interpreted as |
| * unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer putUnsigned(ByteBuffer b, @Unsigned byte ubyte) { |
| return b.put(ubyte); |
| } |
| |
| /** |
| * Places an unsigned byte into the ByteBuffer b at i. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#put(int, byte) put(int, byte)}, but assumes that the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer putUnsigned(ByteBuffer b, int i, @Unsigned byte ubyte) { |
| return b.put(i, ubyte); |
| } |
| |
| /** |
| * Places an unsigned int into the IntBuffer b. This method is a wrapper around {@link |
| * java.nio.IntBuffer#put(int) put(int)}, but assumes that the input should be interpreted as |
| * unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static IntBuffer putUnsigned(IntBuffer b, @Unsigned int uint) { |
| return b.put(uint); |
| } |
| |
| /** |
| * Places an unsigned int into the IntBuffer b at i. This method is a wrapper around {@link |
| * java.nio.IntBuffer#put(int, int) put(int, int)}, but assumes that the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static IntBuffer putUnsigned(IntBuffer b, int i, @Unsigned int uint) { |
| return b.put(i, uint); |
| } |
| |
| /** |
| * Places an unsigned int array into the IntBuffer b. This method is a wrapper around {@link |
| * java.nio.IntBuffer#put(int[]) put(int[])}, but assumes that the input should be interpreted as |
| * unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static IntBuffer putUnsigned(IntBuffer b, @Unsigned int[] uints) { |
| return b.put(uints); |
| } |
| |
| /** |
| * Places an unsigned int array into the IntBuffer b at i with length l. This method is a wrapper |
| * around {@link java.nio.IntBuffer#put(int[], int, int) put(int[], int, int)}, but assumes that |
| * the input should be interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static IntBuffer putUnsigned(IntBuffer b, @Unsigned int[] uints, int i, int l) { |
| return b.put(uints, i, l); |
| } |
| |
| /** |
| * Gets an unsigned int from the IntBuffer b at i. This method is a wrapper around {@link |
| * java.nio.IntBuffer#get(int) get(int)}, but assumes that the output should be interpreted as |
| * unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned int getUnsigned(IntBuffer b, int i) { |
| return b.get(i); |
| } |
| |
| /** |
| * Places an unsigned short into the ByteBuffer b. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#putShort(short) putShort(short)}, but assumes that the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer putUnsignedShort(ByteBuffer b, @Unsigned short ushort) { |
| return b.putShort(ushort); |
| } |
| |
| /** |
| * Places an unsigned short into the ByteBuffer b at i. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#putShort(int, short) putShort(int, short)}, but assumes that the input |
| * should be interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer putUnsignedShort(ByteBuffer b, int i, @Unsigned short ushort) { |
| return b.putShort(i, ushort); |
| } |
| |
| /** |
| * Places an unsigned int into the ByteBuffer b. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#putInt(int) putInt(int)}, but assumes that the input should be interpreted |
| * as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer putUnsignedInt(ByteBuffer b, @Unsigned int uint) { |
| return b.putInt(uint); |
| } |
| |
| /** |
| * Places an unsigned int into the ByteBuffer b at i. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#putInt(int, int) putInt(int, int)}, but assumes that the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer putUnsignedInt(ByteBuffer b, int i, @Unsigned int uint) { |
| return b.putInt(i, uint); |
| } |
| |
| /** |
| * Places an unsigned long into the ByteBuffer b at i. This method is a wrapper around {@link |
| * java.nio.ByteBuffer#putLong(int, long) putLong(int, long)}, but assumes that the input should |
| * be interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static ByteBuffer putUnsignedLong(ByteBuffer b, int i, @Unsigned long ulong) { |
| return b.putLong(i, ulong); |
| } |
| |
| /** |
| * Reads an unsigned char from the RandomAccessFile f. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#readChar() readChar()}, but assumes the output should be interpreted |
| * as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned char readUnsignedChar(RandomAccessFile f) throws IOException { |
| return f.readChar(); |
| } |
| |
| /** |
| * Reads an unsigned int from the RandomAccessFile f. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#readInt() readInt()}, but assumes the output should be interpreted as |
| * unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned int readUnsignedInt(RandomAccessFile f) throws IOException { |
| return f.readInt(); |
| } |
| |
| /** |
| * Reads an unsigned long from the RandomAccessFile f. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#readLong() readLong()}, but assumes the output should be interpreted |
| * as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned long readUnsignedLong(RandomAccessFile f) throws IOException { |
| return f.readLong(); |
| } |
| |
| /** |
| * Reads up to {@code len} bytes of data from this file into an unsigned array of bytes. This |
| * method is a wrapper around {@link java.io.RandomAccessFile#read(byte[], int, int) read(byte[], |
| * int, int)}, but assumes the output should be interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static int readUnsigned(RandomAccessFile f, @Unsigned byte b[], int off, int len) |
| throws IOException { |
| return f.read(b, off, len); |
| } |
| |
| /** |
| * Reads a file fully into an unsigned byte array. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#readFully(byte[]) readFully(byte[])}, but assumes the output should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static void readFullyUnsigned(RandomAccessFile f, @Unsigned byte b[]) throws IOException { |
| f.readFully(b); |
| } |
| |
| /** |
| * Writes len unsigned bytes to the RandomAccessFile f at offset off. This method is a wrapper |
| * around {@link java.io.RandomAccessFile#write(byte[], int, int) write(byte[], int, int)}, but |
| * assumes the input should be interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static void writeUnsigned(RandomAccessFile f, @Unsigned byte[] bs, int off, int len) |
| throws IOException { |
| f.write(bs, off, len); |
| } |
| |
| /** |
| * Writes an unsigned byte to the RandomAccessFile f. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#writeByte(int) writeByte(int)}, but assumes the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static void writeUnsignedByte(RandomAccessFile f, @Unsigned byte b) throws IOException { |
| f.writeByte(Byte.toUnsignedInt(b)); |
| } |
| |
| /** |
| * Writes an unsigned char to the RandomAccessFile f. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#writeChar(int) writeChar(int)}, but assumes the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static void writeUnsignedChar(RandomAccessFile f, @Unsigned char c) throws IOException { |
| f.writeChar(toUnsignedInt(c)); |
| } |
| |
| /** |
| * Writes an unsigned short to the RandomAccessFile f. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#writeShort(int) writeShort(int)}, but assumes the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static void writeUnsignedShort(RandomAccessFile f, @Unsigned short s) throws IOException { |
| f.writeShort(Short.toUnsignedInt(s)); |
| } |
| |
| /** |
| * Writes an unsigned byte to the RandomAccessFile f. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#writeInt(int) writeInt(int)}, but assumes the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static void writeUnsignedInt(RandomAccessFile f, @Unsigned int i) throws IOException { |
| f.writeInt(i); |
| } |
| |
| /** |
| * Writes an unsigned byte to the RandomAccessFile f. This method is a wrapper around {@link |
| * java.io.RandomAccessFile#writeLong(long) writeLong(long)}, but assumes the input should be |
| * interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static void writeUnsignedLong(RandomAccessFile f, @Unsigned long l) throws IOException { |
| f.writeLong(l); |
| } |
| |
| /** |
| * Gets an array of unsigned bytes from the ByteBuffer b and stores them in the array bs. This |
| * method is a wrapper around {@link java.nio.ByteBuffer#get(byte[]) get(byte[])}, but assumes |
| * that the array of bytes should be interpreted as unsigned. |
| */ |
| @SuppressWarnings("signedness") |
| public static void getUnsigned(ByteBuffer b, @Unsigned byte[] bs) { |
| b.get(bs); |
| } |
| |
| /** |
| * Compares two unsigned shorts x and y. |
| * |
| * <p>In Java 11 or later, use Short.compareUnsigned. |
| * |
| * @param x the first value to compare |
| * @param y the second value to compare |
| * @return a negative number iff x {@literal <} y, a positive number iff x {@literal >} y, and |
| * zero iff x == y. |
| */ |
| // TODO: deprecate when we require Java 9, which defines Short.compareUnsigned() |
| // * @deprecated use Short.compareUnsigned |
| // @Deprecated // use Short.compareUnsigned |
| @SuppressWarnings("signedness") |
| public static int compareUnsigned(@Unsigned short x, @Unsigned short y) { |
| return Integer.compareUnsigned(Short.toUnsignedInt(x), Short.toUnsignedInt(y)); |
| } |
| |
| /** |
| * Compares two unsigned bytes x and y. |
| * |
| * <p>In Java 11 or later, use Byte.compareUnsigned. |
| * |
| * @param x the first value to compare |
| * @param y the second value to compare |
| * @return a negative number iff x {@literal <} y, a positive number iff x {@literal >} y, and |
| * zero iff x == y. |
| */ |
| // TODO: deprecate when we require Java 9, which defines Byte.compareUnsigned() |
| // * @deprecated use Byte.compareUnsigned |
| // @Deprecated // use Byte.compareUnsigned |
| @SuppressWarnings("signedness") |
| public static int compareUnsigned(@Unsigned byte x, @Unsigned byte y) { |
| return Integer.compareUnsigned(Byte.toUnsignedInt(x), Byte.toUnsignedInt(y)); |
| } |
| |
| /** Produces a string representation of the unsigned short s. */ |
| @SuppressWarnings("signedness") |
| public static String toUnsignedString(@Unsigned short s) { |
| return Long.toString(Short.toUnsignedLong(s)); |
| } |
| |
| /** Produces a string representation of the unsigned short s in base radix. */ |
| @SuppressWarnings("signedness") |
| public static String toUnsignedString(@Unsigned short s, int radix) { |
| return Integer.toUnsignedString(Short.toUnsignedInt(s), radix); |
| } |
| |
| /** Produces a string representation of the unsigned byte b. */ |
| @SuppressWarnings("signedness") |
| public static String toUnsignedString(@Unsigned byte b) { |
| return Integer.toUnsignedString(Byte.toUnsignedInt(b)); |
| } |
| |
| /** Produces a string representation of the unsigned byte b in base radix. */ |
| @SuppressWarnings("signedness") |
| public static String toUnsignedString(@Unsigned byte b, int radix) { |
| return Integer.toUnsignedString(Byte.toUnsignedInt(b), radix); |
| } |
| |
| /* |
| * Creates a BigInteger representing the same value as unsigned long. |
| * |
| * This is a reimplementation of Java 8's |
| * {@link Long.toUnsignedBigInteger(long)}. |
| */ |
| @SuppressWarnings("signedness") |
| private static @Unsigned BigInteger toUnsignedBigInteger(@Unsigned long l) { |
| // Java 8 version: return Long.toUnsignedBigInteger(l); |
| if (l >= 0L) { |
| return BigInteger.valueOf(l); |
| } else { |
| int upper = (int) (l >>> 32); |
| int lower = (int) l; |
| |
| // return (upper << 32) + lower |
| return BigInteger.valueOf(Integer.toUnsignedLong(upper)) |
| .shiftLeft(32) |
| .add(BigInteger.valueOf(Integer.toUnsignedLong(lower))); |
| } |
| } |
| |
| /** Returns an unsigned short representing the same value as an unsigned byte. */ |
| public static @Unsigned short toUnsignedShort(@Unsigned byte b) { |
| return (short) (((int) b) & 0xff); |
| } |
| |
| /** Returns an unsigned long representing the same value as an unsigned char. */ |
| public static @Unsigned long toUnsignedLong(@Unsigned char c) { |
| return ((long) c) & 0xffL; |
| } |
| |
| /** Returns an unsigned int representing the same value as an unsigned char. */ |
| public static @Unsigned int toUnsignedInt(@Unsigned char c) { |
| return ((int) c) & 0xff; |
| } |
| |
| /** Returns an unsigned short representing the same value as an unsigned char. */ |
| public static @Unsigned short toUnsignedShort(@Unsigned char c) { |
| return (short) (((int) c) & 0xff); |
| } |
| |
| /** Returns a float representing the same value as the unsigned byte. */ |
| public static float toFloat(@Unsigned byte b) { |
| return toUnsignedBigInteger(Byte.toUnsignedLong(b)).floatValue(); |
| } |
| |
| /** Returns a float representing the same value as the unsigned short. */ |
| public static float toFloat(@Unsigned short s) { |
| return toUnsignedBigInteger(Short.toUnsignedLong(s)).floatValue(); |
| } |
| |
| /** Returns a float representing the same value as the unsigned int. */ |
| public static float toFloat(@Unsigned int i) { |
| return toUnsignedBigInteger(Integer.toUnsignedLong(i)).floatValue(); |
| } |
| |
| /** Returns a float representing the same value as the unsigned long. */ |
| public static float toFloat(@Unsigned long l) { |
| return toUnsignedBigInteger(l).floatValue(); |
| } |
| |
| /** Returns a double representing the same value as the unsigned byte. */ |
| public static double toDouble(@Unsigned byte b) { |
| return toUnsignedBigInteger(Byte.toUnsignedLong(b)).doubleValue(); |
| } |
| |
| /** Returns a double representing the same value as the unsigned short. */ |
| public static double toDouble(@Unsigned short s) { |
| return toUnsignedBigInteger(Short.toUnsignedLong(s)).doubleValue(); |
| } |
| |
| /** Returns a double representing the same value as the unsigned int. */ |
| public static double toDouble(@Unsigned int i) { |
| return toUnsignedBigInteger(Integer.toUnsignedLong(i)).doubleValue(); |
| } |
| |
| /** Returns a double representing the same value as the unsigned long. */ |
| public static double toDouble(@Unsigned long l) { |
| return toUnsignedBigInteger(l).doubleValue(); |
| } |
| |
| /** Returns an unsigned byte representing the same value as the float. */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned byte byteFromFloat(float f) { |
| assert f >= 0; |
| return (byte) f; |
| } |
| |
| /** Returns an unsigned short representing the same value as the float. */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned short shortFromFloat(float f) { |
| assert f >= 0; |
| return (short) f; |
| } |
| |
| /** Returns an unsigned int representing the same value as the float. */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned int intFromFloat(float f) { |
| assert f >= 0; |
| return (int) f; |
| } |
| |
| /** Returns an unsigned long representing the same value as the float. */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned long longFromFloat(float f) { |
| assert f >= 0; |
| return (long) f; |
| } |
| |
| /** Returns an unsigned byte representing the same value as the double. */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned byte byteFromDouble(double d) { |
| assert d >= 0; |
| return (byte) d; |
| } |
| |
| /** Returns an unsigned short representing the same value as the double. */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned short shortFromDouble(double d) { |
| assert d >= 0; |
| return (short) d; |
| } |
| |
| /** Returns an unsigned int representing the same value as the double. */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned int intFromDouble(double d) { |
| assert d >= 0; |
| return (int) d; |
| } |
| |
| /** Returns an unsigned long representing the same value as the double. */ |
| @SuppressWarnings("signedness") |
| public static @Unsigned long longFromDouble(double d) { |
| assert d >= 0; |
| return (long) d; |
| } |
| } |