All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.util.Bits Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
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))); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy