Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.jgroups.util;
import org.jgroups.Global;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* Class (similar to (and partly copied from) java.nio.Bits) containing helper methods to encode variables
* (e.g. ints, long, List<Address> etc) to memory (byte buffer) or output streams and read variables
* from memory or input streams.
* The write methods write a type (e.g. an int or a char) to a buffer ({@link ByteBuffer} or output stream, using
* variable-length encoding. If
* there are not enough byte in the buffer to write a type, a {@link java.nio.BufferOverflowException} is thrown.
* If the variable cannot be written to the output stream, an IOException is thrown.
*
* The read methods read a variable-length encoded type from a buffer or input stream. If there are fewer bytes in
* the buffer than needed to read the type, a {@link java.nio.BufferUnderflowException} is thrown. If the read fails,
* an IOException is thrown.
*
* The size() methods return the number of bytes used to encode the given type with variable-length encoding.
*
* There are additional helper methods to write/read custom JGroups types, e.g. address lists, Views etc
*
* Note that methods to read/write atomic types (char, int etc) should only be used if variable-length encoding is
* desired; otherwise {@link DataOutput#writeInt(int)} or {@link ByteBuffer#putInt(int)} should be used instead.
*
* At the time of writing this (Feb 2014), most methods have not yet been implemented.
* @author Bela Ban
* @author Sanne Grinovero
* @since 3.5
*/
public final class Bits {
private Bits() {
throw new InstantiationError( "Must not instantiate this class" );
}
// -------------------- char ------------------------ //
public static void writeChar(char c, byte[] buf, int offset) {
buf[offset+1]=(byte)c;
buf[offset]=(byte)(c >>> 8);
}
public static char readChar(byte[] buf, int offset) {
return makeChar(buf[offset+1], buf[offset]);
}
public static char readChar(ByteBuffer buf) {
byte a=buf.get(), b=buf.get();
return makeChar(b, a);
}
static private char makeChar(byte b1, byte b0) {
return (char)((b1 & 0xFF) + (b0 << 8));
}
// -------------------- short ----------------------- //
public static void writeShort(short s, byte[] buf, int offset) {
buf[offset+1]=(byte)s;
buf[offset]=(byte)(s >>> 8);
}
public static short readShort(byte[] buf, int offset) {
return makeShort(buf[offset], buf[offset+1]);
}
public static short readShort(ByteBuffer buf) {
return makeShort(buf.get(), buf.get());
}
public static short makeShort(byte a, byte b) {
return (short)((a << 8) | (b & 0xff));
}
// --------------------- int ------------------------ //
public static void writeInt(int num, byte[] buf, int offset) {
buf[offset+3]=(byte)num;
buf[offset+2]=(byte)(num >>> 8);
buf[offset+1]=(byte)(num >>> 16);
buf[offset]=(byte)(num >>> 24);
}
public static int readInt(byte[] buf, int offset) {
return ((buf[offset+3] & 0xFF)) +
((buf[offset+2] & 0xFF) << 8) +
((buf[offset+1] & 0xFF) << 16) +
((buf[offset]) << 24);
}
public static int readInt(ByteBuffer buf) {
byte a=buf.get(), b=buf.get(), c=buf.get(), d=buf.get();
return (d & 0xFF) +
((c & 0xFF) << 8) +
((b & 0xFF) << 16) +
(a << 24);
}
public static void writeIntCompressed(int num, byte[] buf, int offset) {
if(num == 0) {
buf[offset]=0;
return;
}
final byte bytes_needed=bytesRequiredFor(num);
buf[offset++]=bytes_needed;
for(int i=0; i < bytes_needed; i++)
buf[offset++]=getByteAt(num, i);
}
public static int readIntCompressed(byte[] buf, int offset) {
byte len=buf[offset++];
if(len == 0)
return 0;
return makeInt(buf, offset, len);
}
public static void writeIntCompressed(int num, ByteBuffer buf) {
if(num == 0) {
buf.put((byte)0);
return;
}
final byte bytes_needed=bytesRequiredFor(num);
buf.put(bytes_needed);
for(int i=0; i < bytes_needed; i++)
buf.put(getByteAt(num, i));
}
public static int readIntCompressed(ByteBuffer buf) {
byte len=buf.get();
if(len == 0)
return 0;
return makeInt(buf, len);
}
public static void writeIntCompressed(int num, DataOutput out) throws IOException {
if(num == 0) {
out.write(0);
return;
}
final byte bytes_needed=bytesRequiredFor(num);
out.write(bytes_needed);
for(int i=0; i < bytes_needed; i++)
out.write(getByteAt(num, i));
}
public static int readIntCompressed(DataInput in) throws IOException {
byte len=in.readByte();
if(len == 0)
return 0;
return makeInt(in, len);
}
public static int makeInt(ByteBuffer buffer, int bytes_to_read) {
int retval=0;
for(int i=0; i < bytes_to_read; i++) {
byte b=buffer.get();
retval |= ((int)b & 0xff) << (i * 8);
}
return retval;
}
public static int makeInt(DataInput in, int bytes_to_read) throws IOException {
int retval=0;
for(int i=0; i < bytes_to_read; i++) {
byte b=in.readByte();
retval |= ((int)b & 0xff) << (i * 8);
}
return retval;
}
public static int makeInt(byte[] buf, int offset, int bytes_to_read) {
int retval=0;
for(int i=0; i < bytes_to_read; i++) {
byte b=buf[offset + i];
retval |= ((int)b & 0xff) << (i * 8);
}
return retval;
}
/**
* Computes the size of a variable-length encoded int
* @param num the int
* @return the number of bytes needed to variable-length encode num
*/
public static int size(int num) {
return (byte)(num == 0? 1 : bytesRequiredFor(num) +1);
}
// -------------------- long ------------------------ //
public static void writeLong(long num, byte[] buf, int offset) {
buf[offset+7]=(byte)num;
buf[offset+6]=(byte)(num >>> 8);
buf[offset+5]=(byte)(num >>> 16);
buf[offset+4]=(byte)(num >>> 24);
buf[offset+3]=(byte)(num >>> 32);
buf[offset+2]=(byte)(num >>> 40);
buf[offset+1]=(byte)(num >>> 48);
buf[offset]=(byte)(num >>> 56);
}
public static long readLong(byte[] buf, int offset) {
return ((buf[offset+7] & 0xFFL)) +
((buf[offset+6] & 0xFFL) << 8) +
((buf[offset+5] & 0xFFL) << 16) +
((buf[offset+4] & 0xFFL) << 24) +
((buf[offset+3] & 0xFFL) << 32) +
((buf[offset+2] & 0xFFL) << 40) +
((buf[offset+1] & 0xFFL) << 48) +
(((long) buf[offset]) << 56);
}
public static long readLong(ByteBuffer buf) {
byte a=buf.get(), b=buf.get(), c=buf.get(), d=buf.get(), e=buf.get(), f=buf.get(), g=buf.get(), h=buf.get();
return ((h & 0xFFL)) +
((g & 0xFFL) << 8) +
((f & 0xFFL) << 16) +
((e & 0xFFL) << 24) +
((d & 0xFFL) << 32) +
((c & 0xFFL) << 40) +
((b & 0xFFL) << 48) +
(((long)a) << 56);
}
public static void writeLongCompressed(long num, byte[] buf, int offset) {
if(num == 0) {
buf[offset]=0;
return;
}
final byte bytes_needed=bytesRequiredFor(num);
buf[offset++]=bytes_needed;
for(int i=0; i < bytes_needed; i++)
buf[offset++]=getByteAt(num, i);
}
public static long readLongCompressed(byte[] buf, int offset) {
byte len=buf[offset++];
if(len == 0)
return 0;
return makeLong(buf, offset, len);
}
public static void writeLongCompressed(long num, ByteBuffer buf) {
if(num == 0) {
buf.put((byte)0);
return;
}
final byte bytes_needed=bytesRequiredFor(num);
buf.put(bytes_needed);
for(int i=0; i < bytes_needed; i++)
buf.put(getByteAt(num, i));
}
public static long readLongCompressed(ByteBuffer buf) {
byte len=buf.get();
if(len == 0)
return 0;
return makeLong(buf, len);
}
/** Writes a long to out in variable-length encoding */
public static void writeLongCompressed(final long num, final DataOutput out) throws IOException {
if(num == 0) {
out.write(0);
return;
}
final byte bytes_needed=bytesRequiredFor(num);
out.write(bytes_needed);
for(int i=0; i < bytes_needed; i++)
out.write(getByteAt(num, i));
}
public static long readLongCompressed(DataInput in) throws IOException {
byte len=in.readByte();
if(len == 0)
return 0;
return makeLong(in, len);
}
/**
* Computes the size of a variable-length encoded long. Note that this is not currently using
* variable-length encoding (will be implemented later).
* @param num the long
* @return the number of bytes needed to variable-length encode num
*/
public static int size(long num) {
return (byte)(num == 0? 1 : bytesRequiredFor(num) +1);
}
public static long makeLong(byte[] buf, int offset, int bytes_to_read) {
long retval=0;
for(int i=0; i < bytes_to_read; i++) {
byte b=buf[offset + i];
retval |= ((long)b & 0xff) << (i * 8);
}
return retval;
}
public static long makeLong(ByteBuffer buffer, int bytes_to_read) {
long retval=0;
for(int i=0; i < bytes_to_read; i++) {
byte b=buffer.get();
retval |= ((long)b & 0xff) << (i * 8);
}
return retval;
}
public static long makeLong(DataInput in, int bytes_to_read) throws IOException {
long retval=0;
for(int i=0; i < bytes_to_read; i++) {
byte b=in.readByte();
retval |= ((long)b & 0xff) << (i * 8);
}
return retval;
}
// ------------------ long seq ---------------------- //
/**
* Writes 2 sequence numbers (seqnos) in compressed format to buf.
* The seqnos are non-negative and hr is guaranteed to be >= hd.
*
* Once variable-length encoding has been implemented, this method will probably get dropped as we can simply
* write the 2 longs individually.
* @param hd the highest delivered seqno. Guaranteed to be a positive number
* @param hr the highest received seqno. Guaranteed to be a positive number. Greater than or equal to hd
* @param buf the buffer to write to
*/
public static void writeLongSequence(long hd, long hr, ByteBuffer buf) {
if(hr < hd)
throw new IllegalArgumentException("hr (" + hr + ") has to be >= hd (" + hd + ")");
if(hd == 0 && hr == 0) {
buf.put((byte)0);
return;
}
long delta=hr - hd;
// encode highest_delivered followed by delta
byte bytes_for_hd=bytesRequiredFor(hd), bytes_for_delta=bytesRequiredFor(delta);
byte bytes_needed=encodeLength(bytes_for_hd, bytes_for_delta);
buf.put(bytes_needed);
for(int i=0; i < bytes_for_hd; i++)
buf.put(getByteAt(hd, i));
for(int i=0; i < bytes_for_delta; i++)
buf.put(getByteAt(delta, i));
}
/**
* Writes 2 sequence numbers (seqnos) in compressed format to an output stream.
* The seqnos are non-negative and hr is guaranteed to be >= hd.
*
* Once variable-length encoding has been implemented, this method will probably get dropped as we can simply
* write the 2 longs individually.
* @param hd the highest delivered seqno. Guaranteed to be a positive number
* @param hr the highest received seqno. Guaranteed to be a positive number. Greater than or equal to hd
* @param out the output stream to write to
*/
public static void writeLongSequence(long hd, long hr, DataOutput out) throws IOException {
if(hr < hd)
throw new IllegalArgumentException("hr (" + hr + ") has to be >= hd (" + hd + ")");
if(hd == 0 && hr == 0) {
out.write(0);
return;
}
long delta=hr - hd;
// encode highest_delivered followed by delta
byte bytes_for_hd=bytesRequiredFor(hd), bytes_for_delta=bytesRequiredFor(delta);
byte bytes_needed=encodeLength(bytes_for_hd, bytes_for_delta);
out.write(bytes_needed);
for(int i=0; i < bytes_for_hd; i++)
out.write(getByteAt(hd, i));
for(int i=0; i < bytes_for_delta; i++)
out.write(getByteAt(delta, i));
}
/**
* Reads 2 compressed longs from buf into seqnos
*
* Once variable-length encoding has been implemented, this method will probably get dropped as we can simply
* read the 2 longs individually.
* @param buf the buffer to read from
* @param seqnos the array to read the seqnos into, needs to have a length of 2
*/
public static void readLongSequence(ByteBuffer buf, long[] seqnos) {
byte len=buf.get();
if(len == 0) {
seqnos[0]=seqnos[1]=0;
return;
}
byte len1=firstNibble(len), len2=secondNibble(len);
seqnos[0]=makeLong(buf, len1);
seqnos[1]=makeLong(buf, len2) + seqnos[0];
}
/**
* Reads 2 compressed longs into an array of 2 longs.
*
* Once variable-length encoding has been implemented, this method will probably get dropped as we can simply
* read the 2 longs individually.
* @param in the input stream to read from
* @param seqnos the array to read the seqnos into, needs to have a length of 2
* @param index the index of the first element to be written; the seqnos are written to seqnos[index] and seqnos[index+1]
*/
public static void readLongSequence(DataInput in, long[] seqnos, int index) throws IOException {
byte len=in.readByte();
if(len == 0) {
seqnos[index]=seqnos[index+1]=0;
return;
}
byte len1=firstNibble(len), len2=secondNibble(len);
seqnos[index]=makeLong(in, len1);
seqnos[index+1]=makeLong(in, len2) + seqnos[index];
}
public static byte size(long hd, long hr) {
if(hd == 0 && hr == 0)
return 1;
byte num_bytes_for_hd=bytesRequiredFor(hd), num_bytes_for_delta=bytesRequiredFor(hr - hd);
return (byte)(num_bytes_for_hd + num_bytes_for_delta + 1);
}
// -------------------- float ----------------------- //
public static void writeFloat(float num, byte[] buf, int offset) {
writeInt(Float.floatToIntBits(num), buf, offset);
}
public static float readFloat(byte[] buf, int offset) {
return Float.intBitsToFloat(readInt(buf, offset));
}
public static void writeFloat(float num, ByteBuffer buf) {
buf.putInt(Float.floatToIntBits(num));
}
public static float readFloat(ByteBuffer buf) {
return Float.intBitsToFloat(buf.getInt());
}
public static void writeFloat(float num, DataOutput out) throws IOException {
out.writeInt(Float.floatToIntBits(num));
}
public static float readFloat(DataInput in) throws IOException {
return Float.intBitsToFloat(in.readInt());
}
public static int size(float ignored) {
return Float.BYTES;
}
// -------------------- double ---------------------- //
public static void writeDouble(double num, byte[] buf, int offset) {
writeLong(Double.doubleToLongBits(num), buf, offset);
}
public static double readDouble(byte[] buf, int offset) {
return Double.longBitsToDouble(readLong(buf, offset));
}
public static void writeDouble(double num, ByteBuffer buf) {
buf.putLong(Double.doubleToLongBits(num));
}
public static double readDouble(ByteBuffer buf) {
return Double.longBitsToDouble(buf.getLong());
}
public static void writeDouble(double num, DataOutput out) throws IOException {
out.writeLong(Double.doubleToLongBits(num));
}
public static double readDouble(DataInput in) throws IOException {
return Double.longBitsToDouble(in.readLong());
}
/**
* Computes the size of a variable-length encoded double
* @param num the double
* @return the number of bytes needed to variable-length encode num
*/
public static int size(double num) {
return Double.BYTES;
}
// -------------------- String ---------------------- //
/**
* Writes a string to buf. The length of the string is written first, followed by the chars (as single-byte values).
* Multi-byte values are truncated: only the lower byte of each multi-byte char is written, similar to
* {@link DataOutput#writeChars(String)}.
* @param s the string
* @param buf the buffer
*/
public static void writeString(String s, ByteBuffer buf) {
buf.put((byte)(s != null? 1 : 0));
if(s != null) {
byte[] bytes=s.getBytes();
Bits.writeIntCompressed(bytes.length, buf);
buf.put(bytes);
}
}
/**
* Writes a string to buf. The length of the string is written first, followed by the chars (as single-byte values).
* Multi-byte values are truncated: only the lower byte of each multi-byte char is written, similar to
* {@link DataOutput#writeChars(String)}.
* @param s the string
* @param out the output stream
*/
public static void writeString(String s, DataOutput out) throws IOException {
if(s != null) {
out.write(1);
out.writeUTF(s);
}
else
out.write(0);
}
/**
* Reads a string from buf. The length is read first, followed by the chars. Each char is a single byte
* @param buf the buffer
* @return the string read from buf
*/
public static String readString(ByteBuffer buf) {
if(buf.get() == 0)
return null;
int len=readIntCompressed(buf);
if(buf.isDirect()) {
byte[] bytes=new byte[len];
buf.get(bytes);
return new String(bytes);
}
else {
byte[] bytes=buf.array();
return new String(bytes, buf.arrayOffset() + buf.position(), len);
}
}
/**
* Reads a string from buf. The length is read first, followed by the chars. Each char is a single byte
* @param in the input stream
* @return the string read from buf
*/
public static String readString(DataInput in) throws IOException {
int b=in.readByte();
if(b == 1)
return in.readUTF();
return null;
}
/**
* Measures the number of bytes required to encode a string, taking multibyte characters into account. Measures
* strings written by {@link DataOutput#writeUTF(String)}.
* @param str the string
* @return the number of bytes required for encoding str
*/
public static int sizeUTF(String str) {
int len=str != null? str.length() : 0, utflen=2;
if(len == 0)
return utflen;
for(int i = 0; i < len; i++) {
int c=str.charAt(i);
if((c >= 0x0001) && (c <= 0x007F))
utflen++;
else if (c > 0x07FF)
utflen += 3;
else
utflen += 2;
}
return utflen;
}
public static int size(String str) {
if(str == null)
return Global.BYTE_SIZE;
byte[] bytes=str.getBytes();
return Global.BYTE_SIZE + size(bytes.length) + bytes.length;
}
// ------------------ AsciiString ------------------- //
/**
* Writes an AsciiString to buf. The length of the string is written first, followed by the chars (as single-byte values).
* @param s the string
* @param buf the buffer
*/
public static void writeAsciiString(AsciiString s, ByteBuffer buf) {
short length=(short)(s != null? s.length() : -1);
buf.putShort(length);
if(s != null)
buf.put(s.chars());
}
/**
* Writes an AsciiString to buf. The length of the string is written first, followed by the chars (as single-byte values).
* @param s the string
* @param out the output stream
*/
public static void writeAsciiString(AsciiString s, DataOutput out) throws IOException {
short length=(short)(s != null? s.length() : -1);
out.writeShort(length);
if(s != null)
out.write(s.chars());
}
/**
* Reads an AsciiString from buf. The length is read first, followed by the chars. Each char is a single byte
* @param buf the buffer
* @return the string read from buf
*/
public static AsciiString readAsciiString(ByteBuffer buf) {
short len=buf.getShort();
if(len < 0)
return null;
AsciiString retval=new AsciiString(len);
buf.get(retval.chars());
return retval;
}
/**
* Reads an AsciiString from buf. The length is read first, followed by the chars. Each char is a single byte
* @param in the input stream
* @return the string read from buf
*/
public static AsciiString readAsciiString(DataInput in) throws IOException {
short len=in.readShort();
if(len < 0)
return null;
AsciiString retval=new AsciiString(len);
in.readFully(retval.chars());
return retval;
}
/**
* Measures the number of bytes required to encode an AsciiSring.
* @param str the string
* @return the number of bytes required for encoding str
*/
public static int size(AsciiString str) {
return str == null? Global.SHORT_SIZE : Global.SHORT_SIZE + str.length();
}
/**
* Encodes the number of bytes needed into a single byte. The first number is encoded in the first nibble (the
* first 4 bits), the second number in the second nibble
* @param len1 The number of bytes needed to store a long. Must be between 0 and 8
* @param len2 The number of bytes needed to store a long. Must be between 0 and 8
* @return The byte storing the 2 numbers len1 and len2
*/
protected static byte encodeLength(byte len1, byte len2) {
byte retval=len2;
retval |= (len1 << 4);
return retval;
}
/* protected static byte[] decodeLength(byte len) {
return new byte[]{(byte)((len & 0xff) >> 4),(byte)(len & ~0xf0)}; // 0xf0 is the first nibble set (11110000)
}*/
protected static byte firstNibble(byte len) {
return (byte)((len & 0xff) >> 4); // 0xf0 is the first nibble set (11110000)
}
protected static byte secondNibble(byte len) {
return (byte)(len & ~0xf0); // 0xf0 is the first nibble set (11110000)
}
protected static byte bytesRequiredFor(long number) {
if(number >> 56 != 0) return 8;
if(number >> 48 != 0) return 7;
if(number >> 40 != 0) return 6;
if(number >> 32 != 0) return 5;
if(number >> 24 != 0) return 4;
if(number >> 16 != 0) return 3;
if(number >> 8 != 0) return 2;
return 1;
}
protected static byte bytesRequiredFor(int number) {
if(number >> 24 != 0) return 4;
if(number >> 16 != 0) return 3;
if(number >> 8 != 0) return 2;
return 1;
}
static protected byte getByteAt(long num, int index) {
return (byte)((num >> (index * 8)));
}
}