package org.checkerframework.checker.signedness; import java.math.BigInteger; import java.nio.ByteBuffer; import org.checkerframework.checker.signedness.qual.Unsigned; /** * Provides static utility methods for unsigned values. Some re-implement functionality in JDK 8, * making it available in earlier versions of Java. Others provide new functionality. */ public final class SignednessUtil { private SignednessUtil() { throw new Error("Do not instantiate"); } /** * Gets an unsigned int from the ByteBuffer b. Wraps {@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. Wraps {@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. Wraps {@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 array of unsigned bytes from the ByteBuffer b and stores them in the array bs. Wraps * {@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 longs x and y. * * <p>This is a reimplementation of Java 8's {@code Long.compareUnsigned(long, long)}. * * @return a negative number iff x {@literal <} y, a positive number iff x {@literal >} y, and * zero iff x == y. */ @SuppressWarnings("signedness") public static int compareUnsigned(@Unsigned long x, @Unsigned long y) { // Java 8 version: return Long.compareUnsigned(x, y); return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE); } /** * Compares two unsigned ints x and y. * * <p>This is a reimplementation of Java 8's {@code Integer.compareUnsigned(int, int)}. * * @return a negative number iff x {@literal <} y, a positive number iff x {@literal >} y, and * zero iff x == y. */ @SuppressWarnings("signedness") public static int compareUnsigned(@Unsigned int x, @Unsigned int y) { // Java 8 version: return Integer.compareUnsigned(x, y); return Integer.compare(x + Integer.MIN_VALUE, y + Integer.MIN_VALUE); } /** * Compares two unsigned shorts x and y. * * @return a negative number iff x {@literal <} y, a positive number iff x {@literal >} y, and * zero iff x == y. */ @SuppressWarnings("signedness") public static int compareUnsigned(@Unsigned short x, @Unsigned short y) { // Java 8 version: return Integer.compareUnsigned(Short.toUnsignedInt(x), Short.toUnsignedInt(y)); return compareUnsigned(toUnsignedInt(x), toUnsignedInt(y)); } /** * Compares two unsigned bytes x and y. * * @return a negative number iff x {@literal <} y, a positive number iff x {@literal >} y, and * zero iff x == y. */ @SuppressWarnings("signedness") public static int compareUnsigned(@Unsigned byte x, @Unsigned byte y) { // Java 8 version: return Integer.compareUnsigned(Byte.toUnsignedInt(x), Byte.toUnsignedInt(y)); return compareUnsigned(toUnsignedInt(x), toUnsignedInt(y)); } /** * Produces a string representation of the unsigned long l. * * <p>This is a reimplementation of Java 8's {@code Long.toUnsignedString(long)}. */ @SuppressWarnings("signedness") public static String toUnsignedString(@Unsigned long l) { // Java 8 version: return Long.toUnsignedString(l); return toUnsignedBigInteger(l).toString(); } /** * Produces a string representation of the unsigned long l in base radix. * * <p>This is a reimplementation of Java 8's {@code Long.toUnsignedString(long, int)}. */ @SuppressWarnings("signedness") public static String toUnsignedString(@Unsigned long l, int radix) { // Java 8 version: return Long.toUnsignedString(l, radix); return toUnsignedBigInteger(l).toString(radix); } /** * Produces a string representation of the unsigned int i. * * <p>This is a reimplementation of Java 8's {@code Integer.toUnsignedString(int)}. */ @SuppressWarnings("signedness") public static String toUnsignedString(@Unsigned int i) { // Java 8 version: return Integer.toUnsignedString(i); return Long.toString(toUnsignedLong(i)); } /** * Produces a string representation of the unsigned int i in base radix. * * <p>This is a reimplementation of Java 8's {@code Integer.toUnsignedString(int, int)}. */ @SuppressWarnings("signedness") public static String toUnsignedString(@Unsigned int i, int radix) { // Java 8 version: return Integer.toUnsignedString(i, radix); return Long.toString(toUnsignedLong(i), radix); } /** Produces a string representation of the unsigned short s. */ @SuppressWarnings("signedness") public static String toUnsignedString(@Unsigned short s) { // Java 8 version: return Integer.toUnsignedString(Short.toUnsignedInt(s)); return Long.toString(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) { // Java 8 version: return Integer.toUnsignedString(Short.toUnsignedInt(s), radix); return Long.toString(toUnsignedLong(s), radix); } /** Produces a string representation of the unsigned byte b. */ @SuppressWarnings("signedness") public static String toUnsignedString(@Unsigned byte b) { // Java 8 version: return Integer.toUnsignedString(Byte.toUnsignedInt(b)); return Long.toString(toUnsignedLong(b)); } /** Produces a string representation of the unsigned byte b in base radix. */ @SuppressWarnings("signedness") public static String toUnsignedString(@Unsigned byte b, int radix) { // Java 8 version: return Integer.toUnsignedString(Byte.toUnsignedInt(b), radix); return Long.toString(toUnsignedLong(b), radix); } /* * Creates a BigInteger representing the same value as unsigned long. * * This is a reimplementation of Java 8's * {@code 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(toUnsignedLong(upper))) .shiftLeft(32) .add(BigInteger.valueOf(toUnsignedLong(lower))); } } /** * Returns an unsigned long representing the same value as an unsigned int. * * <p>This is a reimplementation of Java 8's {@code Integer.toUnsignedLong(int)}. */ public static @Unsigned long toUnsignedLong(@Unsigned int i) { // Java 8 version: Integer.toUnsignedLong(i) return ((long) i) & 0xffffffffL; } /** Returns an unsigned long representing the same value as an unsigned short. */ public static @Unsigned long toUnsignedLong(@Unsigned short s) { return ((long) s) & 0xffffL; } /** Returns an unsigned int representing the same value as an unsigned short. */ public static @Unsigned int toUnsignedInt(@Unsigned short s) { return ((int) s) & 0xffff; } /** Returns an unsigned long representing the same value as an unsigned byte. */ public static @Unsigned long toUnsignedLong(@Unsigned byte b) { return ((long) b) & 0xffL; } /** Returns an unsigned int representing the same value as an unsigned byte. */ public static @Unsigned int toUnsignedInt(@Unsigned byte b) { return ((int) b) & 0xff; } /** 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); } }