net.freeutils.util.Utils Maven / Gradle / Ivy
Show all versions of jelementary Show documentation
/*
* Copyright © 2003-2024 Amichai Rothman
*
* This file is part of JElementary - the Java Elementary Utilities package.
*
* JElementary is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* JElementary 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with JElementary. If not, see .
*
* For additional info see https://www.freeutils.net/source/jelementary/
*/
package net.freeutils.util;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
/**
* The {@code Utils} class contains general utility methods.
*/
public class Utils {
/**
* A publicly available Random instance, for generating random
* data (thread-safe and unique within the JVM process).
*/
public static final Random rand = new Random();
/**
* An AtomicLong used for generating JVM-unique sequence numbers.
*/
private static final AtomicLong sequence = new AtomicLong();
/**
* Private constructor to avoid external instantiation.
*/
private Utils() {}
/**
* Returns whether the two given objects are equal.
*
* Equality is determined by first making the reference comparison {@code a == b},
* and if it fails and the first object is not null, by calling {@code a.equals(b)}.
* This provides several advantages over a regular call to {@code a.equals(b)}:
*
* - increased efficiency for objects whose {@code equals} method does not
* include the optimization of using reference comparison
*
- null safety in that the {@code equals} method is never invoked on a null reference
*
- two null references can be safely checked for equality
*
*
* @param a the first object
* @param b the second object
* @return true if the objects are equal, false otherwise
*/
public static boolean equals(Object a, Object b) {
return a == b || a != null && a.equals(b);
}
/**
* Returns the given object if it is not null, otherwise the second object.
*
* @param the object's type
* @param obj the object
* @param def the alternate (default) object
* @return obj if it is not null, otherwise def
*/
public static T def(T obj, T def) {
return obj != null ? obj : def;
}
/**
* Returns an increasing sequence number, starting with {@code 1}.
* The sequence overflows after reaching {@code Long.MAX_VALUE}.
*
* This method can be used to return up to 264 values
* which are unique within the JVM instance.
*
* @return the next sequence number
*/
public static long nextSequence() {
return sequence.incrementAndGet();
}
/**
* Returns the given object if it is not null.
*
* @param the object type
* @param obj an object
* @return the object if it is not null
* @throws NullPointerException if the object is null
*/
public static T notNull(T obj) {
if (obj == null)
throw new NullPointerException("invalid object (null)");
return obj;
}
/**
* Parses an unsigned long value. This method behaves the same as calling
* {@link Long#parseLong(String, int)}, but considers the string invalid
* if it starts with an ASCII minus sign ('-') or plus sign ('+').
*
* @param s the String containing the long representation to be parsed
* @param radix the radix to be used while parsing s
* @return the long represented by s in the specified radix
* @throws NumberFormatException if the string does not contain a parsable
* long, or if it starts with an ASCII minus sign or plus sign
*/
public static long parseULong(String s, int radix)
throws NumberFormatException {
long val = Long.parseLong(s, radix); // throws NumberFormatException
if (s.charAt(0) == '-' || s.charAt(0) == '+')
throw new NumberFormatException("invalid digit: " + s.charAt(0));
return val;
}
/**
* Parses a long value in the given range.
*
* @param s the String containing the long representation to be parsed
* @param radix the radix to be used while parsing s
* @param min the minimum allowed value (inclusive)
* @param max the maximum allowed value (inclusive)
* @return the long represented by s in the specified radix
* @throws NumberFormatException if the string does not contain a parsable
* long, or it is outside the given range
*/
public static long parseLong(String s, int radix, long min, long max) throws NumberFormatException {
long i = Long.parseLong(s, radix); // throws NumberFormatException
if (i < min || i > max)
throw new NumberFormatException("number out of range (" + s + " not in [" + min + "," + max + "])");
return i;
}
/**
* Parses an array of ints.
*
* @param arr the array to parse
* @return the parsed array of ints
* @throws NumberFormatException if one of the strings does not contain a parsable integer
*/
public static int[] parseInts(String... arr) {
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++)
res[i] = Integer.parseInt(arr[i]);
return res;
}
/**
* Parses an array of unsigned decimal byte values.
*
* @param arr the array to parse
* @return the parsed array of bytes
* @throws NumberFormatException if one of the strings does not contain a parsable unsigned byte
*/
public static byte[] parseUBytes(String... arr) {
byte[] res = new byte[arr.length];
for (int i = 0; i < arr.length; i++) {
int b = Integer.parseInt(arr[i]);
if (b < 0 || b > 255)
throw new NumberFormatException("invalid unsigned byte value: " + arr[i]);
res[i] = (byte)b;
}
return res;
}
/**
* Parses an int value using {@link Integer#parseInt}. If the given string
* is null or empty, the given default is returned. If the string cannot
* be parsed as an integer, an exception is thrown.
*
* @param s a String
containing the int
* representation to be parsed
* @param def the default value to return if s is null or empty
* @return the parsed integer value, or the default value if the string is null or empty
* @throws NumberFormatException if the string does not contain a parsable integer
*/
public static int parseInt(String s, int def) throws NumberFormatException {
return s == null || s.isEmpty() ? def : Integer.parseInt(s);
}
/**
* Parses a boolean value using {@link Boolean#parseBoolean}. If the given string
* is null or empty, the given default is returned. If the string cannot
* be parsed as a boolean, an exception is thrown.
*
* @param s a String
containing the boolean
* representation to be parsed
* @param def the default value to return if s is null or empty
* @return the parsed boolean value, or the default value if the string is null or empty
*/
public static boolean parseBoolean(String s, boolean def) {
return s == null || s.isEmpty() ? def : Boolean.parseBoolean(s);
}
/**
* Returns an unsigned 8-bit value from a byte array.
*
* @param buf a byte array from which byte value is taken
* @param offset the offset within buf from which byte value is taken
* @return an unsigned 8-bit value as an int
*/
public static int getU8(byte[] buf, int offset) {
return buf[offset] & 0xFF;
}
/**
* Returns an unsigned 16-bit value from its constituent bytes.
*
* @param b1 first byte value
* @param b2 second byte value
* @param lsb specifies if the bytes are interpreted in LSB or MSB order
* @return an unsigned 16-bit value as an int
*/
public static int getU16(int b1, int b2, boolean lsb) {
return lsb
? ((b1 & 0xFF) | ((b2 & 0xFF) << 8)) & 0xFFFF
: ((b2 & 0xFF) | ((b1 & 0xFF) << 8)) & 0xFFFF;
}
/**
* Returns an unsigned 16-bit value read from a byte array.
*
* @param buf a byte array from which byte values are taken
* @param offset the offset within buf from which byte values are taken
* @param lsb specifies if the bytes are interpreted in LSB or MSB order
* @return an unsigned 16-bit value as an int
*/
public static int getU16(byte[] buf, int offset, boolean lsb) {
return lsb
? ((buf[offset] & 0xFF) | ((buf[offset + 1] & 0xFF) << 8)) & 0xFFFF
: ((buf[offset + 1] & 0xFF) | ((buf[offset] & 0xFF) << 8)) & 0xFFFF;
}
/**
* Returns an unsigned 32-bit value from its constituent bytes.
*
* @param b1 first byte value
* @param b2 second byte value
* @param b3 third byte value
* @param b4 fourth byte value
* @param lsb specifies if the bytes are interpreted in LSB or MSB order
* @return an unsigned 32-bit value as a long
*/
public static long getU32(int b1, int b2, int b3, int b4, boolean lsb) {
return lsb
? ((b1 & 0xFF) | ((b2 & 0xFF) << 8) | ((b3 & 0xFF) << 16) | ((b4 & 0xFF) << 24)) & 0x00000000FFFFFFFFL
: ((b4 & 0xFF) | ((b3 & 0xFF) << 8) | ((b2 & 0xFF) << 16) | ((b1 & 0xFF) << 24)) & 0x00000000FFFFFFFFL;
}
/**
* Returns an unsigned 32-bit value read from a byte array.
*
* @param buf a byte array from which byte values are taken
* @param offset the offset within buf from which byte values are taken
* @param lsb specifies if the bytes are interpreted in LSB or MSB order
* @return an unsigned 32-bit value as a long
*/
public static long getU32(byte[] buf, int offset, boolean lsb) {
return lsb
? ((buf[offset] & 0xFF) | ((buf[offset + 1] & 0xFF) << 8) |
((buf[offset + 2] & 0xFF) << 16) | ((buf[offset + 3] & 0xFF) << 24)) & 0x00000000FFFFFFFFL
: ((buf[offset + 3] & 0xFF) | ((buf[offset + 2] & 0xFF) << 8) |
((buf[offset + 1] & 0xFF) << 16) | ((buf[offset] & 0xFF) << 24)) & 0x00000000FFFFFFFFL;
}
/**
* Returns a 64-bit value read from a byte array.
*
* @param buf a byte array from which byte values are taken
* @param offset the offset within buf from which byte values are taken
* @param lsb specifies if the bytes are interpreted in LSB or MSB order
* @return a 64-bit value as a long
*/
public static long getU64(byte[] buf, int offset, boolean lsb) {
return lsb
? ((getU32(buf, offset + 4, true) & 0x00000000FFFFFFFFL) << 32) |
(getU32(buf, offset, true) & 0x00000000FFFFFFFFL)
: ((getU32(buf, offset, false) & 0x00000000FFFFFFFFL) << 32) |
(getU32(buf, offset + 4, false) & 0x00000000FFFFFFFFL);
}
/**
* Returns the signum function of the argument; zero if the argument
* is zero, 1 if the argument is greater than zero, -1 if the
* argument is less than zero.
*
* @param i the value whose signum is to be returned
* @return the signum function of the argument
*/
public static int signum(long i) {
return i < 0 ? -1 : i > 0 ? 1 : 0;
}
/**
* Returns the bytes of the given value as a byte array.
*
* @param value the value
* @param lsb specifies if the bytes are returned in LSB or MSB order
* @param b the byte array into which the bytes are written
* @param offset the offset in the byte array where the bytes are written
* @param len the number of byte to write (always taken from the lower-order bytes of the value)
* @return the b array containing the value bytes
*/
public static byte[] getBytes(long value, boolean lsb, byte[] b, int offset, int len) {
if (lsb) {
for (int i = offset, max = offset + len; i < max; i++) {
b[i] = (byte)value;
value >>>= 8;
}
} else {
for (int i = offset + len - 1; i >= offset; i--) {
b[i] = (byte)value;
value >>>= 8;
}
}
return b;
}
/**
* Returns the bytes of the given value as a byte array.
*
* @param value the value
* @param lsb specifies if the bytes are returned in LSB or MSB order
* @param b the byte array into which the bytes are written, starting
* at offset zero; the number of written bytes n depends on the size
* of the array (always taken from the lower-order n bytes of the value)
* @return the b array containing the value bytes
*/
public static byte[] getBytes(long value, boolean lsb, byte[] b) {
return getBytes(value, lsb, b, 0, b.length);
}
/**
* Returns the bytes of the given value as a byte array.
*
* @param value the value
* @param lsb specifies if the bytes are returned in LSB or MSB order
* @param len the number of bytes to return (bytes are always taken
* from the lower-order bytes of the value)
* @return an array containing the value bytes
*/
public static byte[] getBytes(long value, boolean lsb, int len) {
return getBytes(value, lsb, new byte[len]);
}
/**
* Returns the bytes of the given long value as a byte array.
*
* @param value the value
* @param lsb specifies if the bytes are returned in LSB or MSB order
* @return an array containing the 8 long value bytes
*/
public static byte[] getBytes(long value, boolean lsb) {
return getBytes(value, lsb, 8);
}
/**
* Returns the bytes of the given int value as a byte array.
*
* @param value the value
* @param lsb specifies if the bytes are returned in LSB or MSB order
* @return an array containing the 4 int value bytes
*/
public static byte[] getBytes(int value, boolean lsb) {
return getBytes(value, lsb, 4);
}
/**
* Returns a bitmask with given number of high-order bits set.
*
* @param bits the number of high-order bits to set in the bitmask
* @return the bitmask with the given number of high-order bits set
* @throws IllegalArgumentException if given number of bits is
* negative or greater than 32
*/
public static byte[] getMask32(int bits) {
if (bits < 0 || bits > 32)
throw new IllegalArgumentException("invalid bitmask " + bits);
int mask = -(1 << (32 - bits));
return new byte[] {
(byte)((mask >> 24) & 0xFF), (byte)((mask >> 16) & 0xFF),
(byte)((mask >> 8) & 0xFF), (byte)(mask & 0xFF)
};
}
/**
* Returns the result of an AND operation between the corresponding bytes
* in the two given arrays.
*
* @param bytes an array of bytes
* @param mask an array of bytes
* @return a new array which is the result of performing the AND operation
* between the corresponding bytes in the two arrays
* @throws IllegalArgumentException if the arrays have different lengths
*/
public static byte[] and(byte[] bytes, byte[] mask) {
int len = bytes.length;
if (mask.length != len)
throw new IllegalArgumentException("mismatched number of bytes");
byte[] res = new byte[len];
for (int i = 0; i < len; i++)
res[i] = (byte)(bytes[i] & mask[i]);
return res;
}
}