/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.util;
import java.nio.ByteOrder;
/**
* Examples for BIG endianness (default for Java and computer network).
* <pre>
* 0=>0100 0001
* 1=>1110 1011
* 2=>...
* </pre> LITTLE endianness is default for GraphHopper and most microprocessors.
*
* @author Peter Karich
*/
public abstract class BitUtil {
/**
* Default for GraphHopper
*/
public static final BitUtil LITTLE = new BitUtilLittle();
/**
* BIG endianness. Little is the default for GraphHopper.
*/
public static final BitUtil BIG = new BitUtilBig();
public static BitUtil get(ByteOrder order) {
if (order.equals(ByteOrder.BIG_ENDIAN))
return BitUtil.BIG;
else
return BitUtil.LITTLE;
}
public final double toDouble(byte[] bytes) {
return toDouble(bytes, 0);
}
public final double toDouble(byte[] bytes, int offset) {
return Double.longBitsToDouble(toLong(bytes, offset));
}
public final byte[] fromDouble(double value) {
byte[] bytes = new byte[8];
fromDouble(bytes, value, 0);
return bytes;
}
public final void fromDouble(byte[] bytes, double value) {
fromDouble(bytes, value, 0);
}
public final void fromDouble(byte[] bytes, double value, int offset) {
fromLong(bytes, Double.doubleToRawLongBits(value), offset);
}
public final float toFloat(byte[] bytes) {
return toFloat(bytes, 0);
}
public final float toFloat(byte[] bytes, int offset) {
return Float.intBitsToFloat(toInt(bytes, offset));
}
public final byte[] fromFloat(float value) {
byte[] bytes = new byte[4];
fromFloat(bytes, value, 0);
return bytes;
}
public final void fromFloat(byte[] bytes, float value) {
fromFloat(bytes, value, 0);
}
public final void fromFloat(byte[] bytes, float value, int offset) {
fromInt(bytes, Float.floatToRawIntBits(value), offset);
}
public final short toShort(byte[] b) {
return toShort(b, 0);
}
public abstract short toShort(byte[] b, int offset);
public final int toInt(byte[] b) {
return toInt(b, 0);
}
public abstract int toInt(byte[] b, int offset);
public final byte[] fromInt(int value) {
byte[] bytes = new byte[4];
fromInt(bytes, value, 0);
return bytes;
}
public final void fromInt(byte[] bytes, int value) {
fromInt(bytes, value, 0);
}
public final byte[] fromShort(short value) {
byte[] bytes = new byte[4];
fromShort(bytes, value, 0);
return bytes;
}
public final void fromShort(byte[] bytes, short value) {
fromShort(bytes, value, 0);
}
public abstract void fromShort(byte[] bytes, short value, int offset);
public abstract void fromInt(byte[] bytes, int value, int offset);
public final long toLong(byte[] b) {
return toLong(b, 0);
}
public abstract long toLong(int high, int low);
public abstract long toLong(byte[] b, int offset);
public final byte[] fromLong(long value) {
byte[] bytes = new byte[8];
fromLong(bytes, value, 0);
return bytes;
}
public final void fromLong(byte[] bytes, long value) {
fromLong(bytes, value, 0);
}
public abstract void fromLong(byte[] bytes, long value, int offset);
/**
* The only purpose of this method is to test 'reverse'. toBitString is the reverse and both are
* independent of the endianness.
*/
public final long fromBitString2Long(String str) {
if (str.length() > 64)
throw new UnsupportedOperationException("Strings needs to fit into a 'long' but length was " + str.length());
long res = 0;
int strLen = str.length();
for (int charIndex = 0; charIndex < strLen; charIndex++) {
res <<= 1;
if (str.charAt(charIndex) != '0')
res |= 1;
}
res <<= (64 - strLen);
return res;
}
public abstract byte[] fromBitString(String str);
/**
* Similar to Long.toBinaryString
*/
public final String toBitString(long value) {
return toBitString(value, 64);
}
public String toLastBitString(long value, int bits) {
StringBuilder sb = new StringBuilder(bits);
long lastBit = 1L << bits - 1;
for (int i = 0; i < bits; i++) {
if ((value & lastBit) == 0)
sb.append('0');
else
sb.append('1');
value <<= 1;
}
return sb.toString();
}
/**
* Higher order bits comes first in the returned string.
* <p>
*
* @param bits how many bits should be returned.
*/
public String toBitString(long value, int bits) {
StringBuilder sb = new StringBuilder(bits);
long lastBit = 1L << 63;
for (int i = 0; i < bits; i++) {
if ((value & lastBit) == 0)
sb.append('0');
else
sb.append('1');
value <<= 1;
}
return sb.toString();
}
/**
* Higher order bits comes first in the returned string.
*/
public abstract String toBitString(byte[] bytes);
/**
* Reverses the bits in the specified long value and it removes the remaining higher bits. See
* also http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious
* <p>
*
* @param maxBits the maximum number of recognized bits for reversal
*/
public final long reverse(long value, int maxBits) {
long res = 0;
for (; maxBits > 0; value >>>= 1) {
res <<= 1;
res |= value & 1;
maxBits--;
if (value == 0) {
res <<= maxBits;
break;
}
}
return res;
}
public final int getIntLow(long longValue) {
return (int) (longValue & 0xFFFFFFFFL);
}
public final int getIntHigh(long longValue) {
return (int) (longValue >> 32);
}
public final long combineIntsToLong(int intLow, int intHigh) {
return ((long) intHigh << 32) | (intLow & 0xFFFFFFFFL);
}
public final long reverseLeft(long value, int maxBits) {
long res = 0;
int delta = 64 - maxBits;
long maxBit = 1L << delta;
for (; maxBits > 0; res <<= 1) {
if ((value & maxBit) != 0)
res |= 1;
maxBit <<= 1;
maxBits--;
if (maxBit == 0) {
res <<= delta;
break;
}
}
return res;
}
}