src.it.unimi.dsi.Util Maven / Gradle / Ivy
package it.unimi.dsi;
/*
* DSI utilities
*
* Copyright (C) 2002-2017 Sebastiano Vigna
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see .
*
*/
import it.unimi.dsi.fastutil.BigArrays;
import it.unimi.dsi.fastutil.longs.LongBigArrays;
import it.unimi.dsi.util.XoRoShiRo128PlusRandomGenerator;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.util.Locale;
/** All-purpose static-method container class.
*
* @author Sebastiano Vigna
* @since 0.1
*/
public final class Util {
private Util() {}
/** A reasonable format for real numbers. Shared by all format methods. */
private static final NumberFormat FORMAT_DOUBLE = NumberFormat.getInstance(Locale.US);
static {
if (FORMAT_DOUBLE instanceof DecimalFormat) ((DecimalFormat)FORMAT_DOUBLE).applyPattern("#,##0.00");
}
/** A reasonable format for integers. Shared by all format methods. */
private static final NumberFormat FORMAT_LONG = NumberFormat.getInstance(Locale.US);
static {
if (FORMAT_DOUBLE instanceof DecimalFormat) ((DecimalFormat)FORMAT_LONG).applyPattern("#,###");
}
private static final FieldPosition UNUSED_FIELD_POSITION = new java.text.FieldPosition(0);
/** Formats a number.
*
* This method formats a double separating thousands and printing just two fractional digits.
*
Note that the method is synchronized, as it uses a static {@link NumberFormat}.
* @param d a number.
* @return a string containing a pretty print of the number.
*/
public synchronized static String format(final double d) {
return FORMAT_DOUBLE.format(d, new StringBuffer(), UNUSED_FIELD_POSITION).toString();
}
/** Formats a number.
*
*
This method formats a long separating thousands.
*
Note that the method is synchronized, as it uses a static {@link NumberFormat}.
* @param l a number.
* @return a string containing a pretty print of the number.
*/
public synchronized static String format(final long l) {
return FORMAT_LONG.format(l, new StringBuffer(), UNUSED_FIELD_POSITION).toString();
}
/** Formats a number using a specified {@link NumberFormat}.
*
* @param d a number.
* @param format a format.
* @return a string containing a pretty print of the number.
*/
public static String format(final double d, final NumberFormat format) {
final StringBuffer s = new StringBuffer();
return format.format(d, s, UNUSED_FIELD_POSITION).toString();
}
/** Formats a number using a specified {@link NumberFormat}.
*
* @param l a number.
* @param format a format.
* @return a string containing a pretty print of the number.
*/
public static String format(final long l, final NumberFormat format) {
final StringBuffer s = new StringBuffer();
return format.format(l, s, UNUSED_FIELD_POSITION).toString();
}
/** Formats a size.
*
*
This method formats a long using suitable unit multipliers (e.g., K
, M
, G
, and T
)
* and printing just two fractional digits.
*
Note that the method is synchronized, as it uses a static {@link NumberFormat}.
* @param l a number, representing a size (e.g., memory).
* @return a string containing a pretty print of the number using unit multipliers.
*/
public static String formatSize(final long l) {
if (l >= 1000000000000L) return format(l / 1000000000000.0) + "T";
if (l >= 1000000000L) return format(l / 1000000000.0) + "G";
if (l >= 1000000L) return format(l / 1000000.0) + "M";
if (l >= 1000L) return format(l / 1000.0) + "K";
return Long.toString(l);
}
/** Formats a binary size.
*
*
This method formats a long using suitable unit binary multipliers (e.g., Ki
, Mi
, Gi
, and Ti
)
* and printing no fractional digits. The argument must be a power of 2.
*
Note that the method is synchronized, as it uses a static {@link NumberFormat}.
* @param l a number, representing a binary size (e.g., memory); must be a power of 2.
* @return a string containing a pretty print of the number using binary unit multipliers.
*/
public static String formatBinarySize(final long l) {
if ((l & -l) != l) throw new IllegalArgumentException("Not a power of 2: " + l);
if (l >= (1L << 40)) return format(l >> 40) + "Ti";
if (l >= (1L << 30)) return format(l >> 30) + "Gi";
if (l >= (1L << 20)) return format(l >> 20) + "Mi";
if (l >= (1L << 10)) return format(l >> 10) + "Ki";
return Long.toString(l);
}
/** Formats a size.
*
*
This method formats a long using suitable binary
* unit multipliers (e.g., Ki
, Mi
, Gi
, and Ti
)
* and printing just two fractional digits.
*
Note that the method is synchronized, as it uses a static {@link NumberFormat}.
* @param l a number, representing a size (e.g., memory).
* @return a string containing a pretty print of the number using binary unit multipliers.
*/
public static String formatSize2(final long l) {
if (l >= 1L << 40) return format((double)l / (1L << 40)) + "Ti";
if (l >= 1L << 30) return format((double)l / (1L << 30)) + "Gi";
if (l >= 1L << 20) return format((double)l / (1L << 20)) + "Mi";
if (l >= 1L << 10) return format((double)l / (1L << 10)) + "Ki";
return Long.toString(l);
}
/** Formats a size using a specified {@link NumberFormat}.
*
*
This method formats a long using suitable unit multipliers (e.g., K
, M
, G
, and T
)
* and the given {@link NumberFormat} for the digits.
* @param l a number, representing a size (e.g., memory).
* @param format a format.
* @return a string containing a pretty print of the number using unit multipliers.
*/
public static String formatSize(final long l, final NumberFormat format) {
if (l >= 1000000000000L) return format(l / 1000000000000.0) + "T";
if (l >= 1000000000L) return format(l / 1000000000.0) + "G";
if (l >= 1000000L) return format(l / 1000000.0) + "M";
if (l >= 1000L) return format(l / 1000.0) + "K";
return Long.toString(l);
}
/** Formats a size using a specified {@link NumberFormat}.
*
*
This method formats a long using suitable unit binary multipliers (e.g., Ki
, Mi
, Gi
, and Ti
)
* and the given {@link NumberFormat} for the digits. The argument must be a power of 2.
* @param l a number, representing a binary size (e.g., memory); must be a power of 2.
* @param format a format.
* @return a string containing a pretty print of the number using binary unit multipliers.
*/
public static String formatBinarySize(final long l, final NumberFormat format) {
if ((l & -l) != l) throw new IllegalArgumentException("Not a power of 2: " + l);
if (l >= (1L << 40)) return format(l >> 40) + "Ti";
if (l >= (1L << 30)) return format(l >> 30) + "Gi";
if (l >= (1L << 20)) return format(l >> 20) + "Mi";
if (l >= (1L << 10)) return format(l >> 10) + "Ki";
return Long.toString(l);
}
/** Formats a size using a specified {@link NumberFormat} and binary unit multipliers.
*
*
This method formats a long using suitable binary
* unit multipliers (e.g., Ki
, Mi
, Gi
, and Ti
)
* and the given {@link NumberFormat} for the digits.
* @param l a number, representing a size (e.g., memory).
* @param format a format.
* @return a string containing a pretty print of the number using binary unit multipliers.
*/
public static String formatSize2(final long l, final NumberFormat format) {
if (l >= 1L << 40) return format((double)l / (1L << 40)) + "Ti";
if (l >= 1L << 30) return format((double)l / (1L << 30)) + "Gi";
if (l >= 1L << 20) return format((double)l / (1L << 20)) + "Mi";
if (l >= 1L << 10) return format((double)l / (1L << 10)) + "Ki";
return Long.toString(l);
}
/** A static reference to {@link Runtime#getRuntime()}. */
public final static Runtime RUNTIME = Runtime.getRuntime();
/** Returns true if less then 5% of the available memory is free.
*
* @return true if less then 5% of the available memory is free.
*/
public static boolean memoryIsLow() {
return availableMemory() * 100 < RUNTIME.totalMemory() * 5;
}
/** Returns the amount of available memory (free memory plus never allocated memory).
*
* @return the amount of available memory, in bytes.
*/
public static long availableMemory() {
return RUNTIME.freeMemory() + (RUNTIME.maxMemory() - RUNTIME.totalMemory());
}
/** Returns the percentage of available memory (free memory plus never allocated memory).
*
* @return the percentage of available memory.
*/
public static int percAvailableMemory() {
return (int)((Util.availableMemory() * 100) / Runtime.getRuntime().maxMemory());
}
/** Tries to compact memory as much as possible by forcing garbage collection.
*/
public static void compactMemory() {
try {
final byte[][] unused = new byte[128][];
for(int i = unused.length; i-- != 0;) unused[i] = new byte[2000000000];
}
catch (OutOfMemoryError itsWhatWeWanted) {}
System.gc();
}
private static final XoRoShiRo128PlusRandomGenerator seedUniquifier = new XoRoShiRo128PlusRandomGenerator(System.nanoTime());
/** Returns a random seed generated by taking the output of a {@link XoRoShiRo128PlusRandomGenerator}
* (seeded at startup with {@link System#nanoTime()}) and xoring it with {@link System#nanoTime()}.
*
* @return a reasonably good random seed.
*/
public static long randomSeed() {
final long x;
synchronized(seedUniquifier) {
x = seedUniquifier.nextLong();
}
return x ^ System.nanoTime();
}
/** Returns a random seed generated by {@link #randomSeed()} under the form of an array of eight bytes.
*
* @return a reasonably good random seed.
*/
public static byte[] randomSeedBytes() {
final long seed = Util.randomSeed();
final byte[] s = new byte[8];
for(int i = Long.SIZE / Byte.SIZE; i-- != 0;) s[i] = (byte)(seed >>> i);
return s;
}
/** Computes in place the inverse of a permutation expressed
* as an array of n distinct integers in [0 .. n).
*
*
Warning: if perm
is not a permutation,
* essentially anything can happen.
*
* @param perm the permutation to be inverted.
* @return perm
.
*/
public static int[] invertPermutationInPlace(int[] perm) {
for(int n = perm.length; n-- != 0;) {
int i = perm[n];
if (i < 0) perm[n] = -i - 1;
else if (i != n) {
int j, k = n;
for(;;) {
j = perm[i];
perm[i] = -k - 1;
if (j == n) {
perm[n] = i;
break;
}
k = i;
i = j;
}
}
}
return perm;
}
/** Computes the inverse of a permutation expressed
* as an array of n distinct integers in [0 .. n).
*
*
Warning: if perm
is not a permutation,
* essentially anything can happen.
*
* @param perm the permutation to be inverted.
* @param inv the array storing the inverse.
* @return inv
.
*/
public static int[] invertPermutation(int[] perm, int[] inv) {
for(int i = perm.length; i-- != 0;) inv[perm[i]] = i;
return inv;
}
/** Computes the inverse of a permutation expressed
* as an array of n distinct integers in [0 .. n)
* and stores the result in a new array.
*
*
Warning: if perm
is not a permutation,
* essentially anything can happen.
*
* @param perm the permutation to be inverted.
* @return a new array containing the inverse permutation.
*/
public static int[] invertPermutation(int[] perm) {
return invertPermutation(perm, new int[perm.length]);
}
/** Stores the identity permutation in an array.
*
* @param perm an array of integers.
* @return perm
, filled with the identity permutation.
*/
public static int[] identity(int[] perm) {
for(int i = perm.length; i-- != 0;) perm[i] = i;
return perm;
}
/** Stores the identity permutation in a new array of given length.
*
* @param n the size of the array.
* @return a new array of length n
, filled with the identity permutation.
*/
public static int[] identity(int n) {
return identity(new int[n]);
}
/** Computes in place the inverse of a permutation expressed
* as a {@linkplain BigArrays big array} of n distinct long integers in [0 .. n).
*
*
Warning: if perm
is not a permutation,
* essentially anything can happen.
*
* @param perm the permutation to be inverted.
* @return perm
.
*/
public static long[][] invertPermutationInPlace(long[][] perm) {
for(long n = LongBigArrays.length(perm); n-- != 0;) {
long i = LongBigArrays.get(perm, n);
if (i < 0) LongBigArrays.set(perm, n, -i - 1);
else if (i != n) {
long j, k = n;
for(;;) {
j = LongBigArrays.get(perm, i);
LongBigArrays.set(perm, i, -k - 1);
if (j == n) {
LongBigArrays.set(perm, n, i);
break;
}
k = i;
i = j;
}
}
}
return perm;
}
/** Computes the inverse of a permutation expressed
* as a {@linkplain BigArrays big array} of n distinct long integers in [0 .. n).
*
*
Warning: if perm
is not a permutation,
* essentially anything can happen.
*
* @param perm the permutation to be inverted.
* @param inv the big array storing the inverse.
* @return inv
.
*/
public static long[][] invertPermutation(long[][] perm, long[][] inv) {
for(int i = perm.length; i-- != 0;) {
final long t[] = perm[i];
for(int d = t.length; d-- != 0;) LongBigArrays.set(inv, t[d], BigArrays.index(i, d));
}
return inv;
}
/** Computes the inverse of a permutation expressed
* as a {@linkplain BigArrays big array} of n distinct long integers in [0 .. n)
* and stores the result in a new big array.
*
*
Warning: if perm
is not a permutation,
* essentially anything can happen.
*
* @param perm the permutation to be inverted.
* @return a new big array containing the inverse permutation.
*/
public static long[][] invertPermutation(long[][] perm) {
return invertPermutation(perm, LongBigArrays.newBigArray(LongBigArrays.length(perm)));
}
/** Stores the identity permutation in a {@linkplain BigArrays big array}.
*
* @param perm a big array.
* @return perm
, filled with the identity permutation.
*/
public static long[][] identity(long[][] perm) {
for(int i = perm.length; i-- != 0;) {
final long[] t = perm[i];
for(int d = t.length; d-- != 0;) t[d] = BigArrays.index(i, d);
}
return perm;
}
/** Stores the identity permutation in a new big array of given length.
*
* @param n the size of the array.
* @return a new array of length n
, filled with the identity permutation.
*/
public static long[][] identity(long n) {
return identity(LongBigArrays.newBigArray(n));
}
}