![JAR search and dependency download from the Maven repository](/logo.png)
com.bigdata.btree.keys.SuccessorUtil Maven / Gradle / Ivy
/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
This program 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; version 2 of the License.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Feb 3, 2007
*/
package com.bigdata.btree.keys;
/**
* Utility methods for computing the successor of a value for various data
* types.
*
* @author Bryan Thompson
* @version $Id$
*
* @todo reconcile with the GOM SuccessorUtil.
*
* @todo There is no successor method for UUID. This should be treated as a
* special case of a fixed length field. Handle as two longs. add 1 to the
* low order bits. on overflow add one to the high order bits. on overflow
* of the high order bits there is no successor.
*
* @see BytesUtil#successor(byte[]), which computes the successor of a variable
* length unsigned byte[].
*/
public class SuccessorUtil {
/*
* useful single precision values.
*/
/**
* Positive zero (+0f).
*
* Note: +0f and -0f will compare as _equal_ in the language. This means
* that you can not write tests that directly distinguish positive and
* negative zero using >, <, or ==.
*/
final public static float FPOS_ZERO = Float.intBitsToFloat(0x00000000);
/**
* Negative zero (-0f).
*
* Note: +0f and -0f will compare as _equal_ in the language. This means
* that you can not write tests that directly distinguish positive and
* negative zero using >, <, or ==.
*/
final public static float FNEG_ZERO = Float.intBitsToFloat(0x80000000);
/**
* Smallest non-zero positive value.
*/
final public static float FPOS_MIN = Float.intBitsToFloat(0x00000001);
/**
* Smallest non-zero negative value.
*/
final public static float FNEG_MIN = Float.intBitsToFloat(0x80000001);
/**
* Positive one (1f).
*/
final public static float FPOS_ONE = 1f;
/**
* Negative one (-1f).
*/
final public static float FNEG_ONE = -1f;
/**
* Largest positive float.
*/
final public static float FPOS_MAX = Float.MAX_VALUE;
/**
* Largest negative float.
*/
final public static float FNEG_MAX = Float.intBitsToFloat(0xFF7FFFFF);
/*
* useful double precision values.
*/
/**
* Positive zero (+0d).
*
* Note: +0d and -0d will compare as _equal_ in the language. This means
* that you can not write tests that directly distinguish positive and
* negative zero using >, <, or ==.
*/
final public static double DPOS_ZERO = Double.longBitsToDouble(0x0000000000000000L);
/**
* Negative zero (-0d).
*
* Note: +0d and -0d will compare as _equal_ in the language. This means
* that you can not write tests that directly distinguish positive and
* negative zero using >, <, or ==.
*/
final public static double DNEG_ZERO = Double.longBitsToDouble(0x8000000000000000L);
/**
* Smallest non-zero positive value.
*/
final public static double DPOS_MIN = Double.longBitsToDouble(0x0000000000000001L);
/**
* Smallest non-zero negative value.
*/
final public static double DNEG_MIN = Double.longBitsToDouble(0x8000000000000001L);
/**
* Positive one (1d).
*/
final public static double DPOS_ONE = 1d;
/**
* Negative one (-1d).
*/
final public static double DNEG_ONE = -1d;
/**
* Largest positive double.
*/
final public static double DPOS_MAX = Double.MAX_VALUE;
/**
* Largest negative double.
*/
final public static double DNEG_MAX = Double.longBitsToDouble(0xFFEFFFFFFFFFFFFFL);
/*
* successor methods.
*/
/**
* Computes the successor of a byte
value.
*
* @param n
* A value
*
* @return The successor of that value.
*
* @exception NoSuccessorException
* if there is no successor for that value.
*/
public static byte successor(final byte n) throws NoSuccessorException {
if (Byte.MAX_VALUE == n) {
throw new NoSuccessorException();
} else {
return (byte) (n + 1);
}
}
/**
* Computes the successor of a char
value.
*
* @param n
* A value
*
* @return The successor of that value.
*
* @exception NoSuccessorException
* if there is no successor for that value.
*/
public static char successor(final char n) throws NoSuccessorException {
if (Character.MAX_VALUE == n) {
throw new NoSuccessorException();
} else {
return (char) (n + 1);
}
}
/**
* Computes the successor of a short
value.
*
* @param n
* A value
*
* @return The successor of that value.
*
* @exception NoSuccessorException
* if there is no successor for that value.
*/
public static short successor(final short n) throws NoSuccessorException {
if (Short.MAX_VALUE == n) {
throw new NoSuccessorException();
} else {
return (short) (n + 1);
}
}
/**
* Computes the successor of an int
value.
*
* @param n
* A value
*
* @return The successor of that value.
*
* @exception NoSuccessorException
* if there is no successor for that value.
*/
public static int successor(final int n) throws NoSuccessorException {
if (Integer.MAX_VALUE == n) {
throw new NoSuccessorException();
} else {
return n + 1;
}
}
/**
* Computes the successor of a long
value.
*
* @param n
* A value
*
* @return The successor of that value.
*
* @exception NoSuccessorException
* if there is no successor for that value.
*/
public static long successor(final long n) throws NoSuccessorException {
if (Long.MAX_VALUE == n) {
throw new NoSuccessorException();
} else {
return n + 1L;
}
}
/**
*
* Computes the successor of a float
value.
*
*
* The IEEE floating point standard provides a means for computing the next
* larger or smaller floating point value using a bit manipulation trick.
* See
* Comparing floating point numbers by Bruce Dawson. The Java
* {@link Float} and {@link Double} classes provide the static methods
* required to convert a float or double into its IEEE 754 floating point
* bit layout, which can be treated as an int (for floats) or a long (for
* doubles). By testing for the sign, you can just add (or subtract) one (1)
* to get the bit pattern of the successor (see the above referenced
* article). Special exceptions must be made for NaNs, negative infinity and
* positive infinity.
*
*
* @param f
* The float value.
*
* @return The next value in the value space for float
.
*
* @exception NoSuccessorException
* if there is no next value in the value space.
*/
static public float successor(final float f) throws NoSuccessorException {
if (f == Float.MAX_VALUE) {
return Float.POSITIVE_INFINITY;
}
if (Float.isNaN(f)) {
throw new NoSuccessorException("NaN");
}
if (Float.isInfinite(f)) {
if (f > 0) {
throw new NoSuccessorException("Positive Infinity");
} else {
/* no successor for negative infinity (could be the largest
* negative value).
*/
throw new NoSuccessorException("Negative Infinity");
}
}
int bits = Float.floatToIntBits(f);
if (bits == 0x80000000) {
/*
* the successor of -0.0f is +0.0f
*
* @todo Java defines the successor of floating point zeros as the
* first non-zero value so maybe we should change this.
*/
return +0.0f;
}
if (f >= +0.0f) {
bits += 1;
} else {
bits -= 1;
}
float nxt = Float.intBitsToFloat(bits);
return nxt;
}
/**
*
* Computes the successor of a double
value.
*
*
* The IEEE floating point standard provides a means for computing the next
* larger or smaller floating point value using a bit manipulation trick.
* See
* Comparing floating point numbers by Bruce Dawson. The Java
* {@link Float} and {@link Double} classes provide the static methods
* required to convert a float or double into its IEEE 754 floating point
* bit layout, which can be treated as an int (for floats) or a long (for
* doubles). By testing for the sign, you can just add (or subtract) one (1)
* to get the bit pattern of the successor (see the above referenced
* article). Special exceptions must be made for NaNs, negative infinity and
* positive infinity.
*
*
* @param d The double value.
*
* @return The next value in the value space for double
.
*
* @exception NoSuccessorException
* if there is no next value in the value space.
*/
public static double successor(final double d) throws NoSuccessorException {
if (d == Double.MAX_VALUE) {
return Double.POSITIVE_INFINITY;
}
if (Double.isNaN(d)) {
throw new NoSuccessorException("Nan");
}
if (Double.isInfinite(d)) {
if (d > 0) {
throw new NoSuccessorException("Positive Infinity");
} else {
// The successor of negative infinity.
return Double.MIN_VALUE;
}
}
long bits = Double.doubleToLongBits(d);
if (bits == 0x8000000000000000L) {
/* the successor of -0.0d is +0.0d
*
* @todo Java defines the successor of floating point zeros as the
* first non-zero value so maybe we should change this.
*/
return +0.0d;
}
// if (f >= +0.0f) {
if (d >= +0.0) {
bits += 1;
} else {
bits -= 1;
}
double nxt = Double.longBitsToDouble(bits);
return nxt;
}
/**
* The successor of a string value is formed by appending a nul
.
* The successor of a null
string reference is an empty
* string. The successor of a string value is defined unless the string is
* too long.
*
* @param s
* The string reference or null
.
*
* @return The successor and never null
*/
public static String successor(final String s) {
if (s == null)
return "\0";
return s + "\0";
}
/**
* Modifies a byte[] as a side-effect so that it represents its successor
* when interpreted as a fixed length bit string. The successor is formed by
* adding ONE (1) to the low byte and handling overflow.
*
* @param b
*
* @return b, which has been modified as a side-effect.
*
* @throws NoSuccessorException
* If all bytes overflow.
* @throws NoSuccessorException
* If the byte[] has zero length.
*/
static public byte[] successor(final byte[] b) {
return successor(b, 0, b.length);
}
/**
* Modifies a byte[] as a side-effect so that it represents its successor
* when interpreted as a fixed length bit string. The successor is formed by
* adding ONE (1) to the low byte and handling overflow.
*
* @param b
* The byte[].
* @param off
* The offset of the start of the bitstring in the byte[].
* @param len
* The #of bytes in the bit string within the byte[].
*
* @return b, which has been modified as a side-effect.
*
* @throws NoSuccessorException
* If all bytes overflow.
* @throws NoSuccessorException
* If the byte[] has zero length.
*
* @todo unit tests when offset is non-zero.
*/
static public byte[] successor(final byte[] b, final int off, final int len) {
if (len == 0) {
throw new NoSuccessorException("Empty byte[]");
}
boolean overflow = false;
for (int i = off+len - 1; i >= off; i--) {
// overflow = b[i] == Byte.MAX_VALUE;
overflow = b[i] == (byte)-1; // Note: largest 8-bit value == 1111 1111
b[i]++;
if(!overflow) return b;
// int tmp = ((int)b[i]) + 1;
//
// /*
// * Negative integers will be sign extended so we onlyStrip off the sign bit when checking overflow so that the sign
// * bit does not get extended to a large negative integer.
// */
// overflow = b[i] > 0 && tmp > Byte.MAX_VALUE;
// b[i] = (byte)(tmp & 0xff);
}
// overflow for the entire bit string.
throw new NoSuccessorException("Overflow");
}
}