DataBuffer.java


import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;




/**
 * DataBuffer is to store misc types of data into a byte array. This is to replace
 * JDK's ByteBufer class.
 */
public class DataBuffer implements DataOutput, DataInput {


    public static Charset UTF8_CHARSET = Charset.forName("UTF-8");


    /**
     * Index to store data.
     */
    protected int byteIndex;


    /**
     * Backing bytes to store data.
     */
    protected byte[] bytes;
    
    private static final byte BYTE_ONE = (byte) 1;
    private static final byte BYTE_ZERO = (byte) 0;
    
    public static final byte BYTE_ASCII = (byte) 0;
    public static final byte SHORT_ASCII = (byte) 1;
    public static final byte INT_ASCII = (byte) 2;
    public static final byte BYTE_NASCII = (byte) 4;
    public static final byte SHORT_NASCII = (byte) 5;
    public static final byte INT_NASCII = (byte) 6;
        




    public DataBuffer() {
        this(32);
    }


    /**
     * Create a DataBuffer with a given capacity.
     *
     * @param capacity
     */
    public DataBuffer(int capacity) {
        this.bytes = new byte[capacity];
    }
    
    public DataBuffer copy() {
        int length = bytes.length - byteIndex;
        byte[] copyBytes = new byte[length];
        System.arraycopy(bytes, byteIndex, copyBytes, 0, length);
        return wrap(copyBytes);        
    }


    public void setBackingBytes(byte[] bytes, int startIndex) {
        this.bytes = bytes;
        this.byteIndex = startIndex;
    }


    /**
     * Wrap around a byte array to create a DataBuffer.
     *
     * @param bytes
     * @return
     */
    public static DataBuffer wrap(byte[] bytes) {
        DataBuffer dataBuffer = new DataBuffer();
        dataBuffer.bytes = bytes;
        dataBuffer.byteIndex = 0;
        return dataBuffer;
    }


    public static DataBuffer wrap(byte[] bytes, int startIndex) {
        DataBuffer dataBuffer = new DataBuffer();
        dataBuffer.bytes = bytes;
        dataBuffer.byteIndex = startIndex;
        return dataBuffer;
    }


    public byte[] getBackingBytes() {
        return bytes;
    }


    public int getByteIndex() {
        return byteIndex;
    }


    public int getCapacity() {
        return bytes.length;
    }


    public void setByteIndex(int byteIndex) {
        this.byteIndex = byteIndex;
    }


    public void reset() {
        byteIndex = 0;
    }


    public final void writeByte(byte v) {
int newByteIndex = byteIndex + 1;
if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
}
        bytes[byteIndex++] = v;
    }


    public final void writeBytes(byte[] values, int size) {
        writeBytes(values, 0, size);
    }


    public final void writeBytes(byte[] values, int start, int size) {
        int newByteIndex = byteIndex + size;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        System.arraycopy(values, start, bytes, byteIndex, size);
        byteIndex = newByteIndex;
    }


    public final void writeChar(char v) {
        int newByteIndex = byteIndex + 2;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        bytes[byteIndex++] = (byte) ((v >>> 8) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>> 0) & 0xFF);
    }


    public final void writeChars(char[] values, int size) {
        int newByteIndex = byteIndex + (size << 1);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            char v = values[i];
            bytes[byteIndex++] = (byte) ((v >>> 8) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 0) & 0xFF);
        }
    }


    public final void writeChars(CharSequence values, int size) {
        int newByteIndex = byteIndex + (size << 1);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            char v = values.charAt(i);
            bytes[byteIndex++] = (byte) ((v >>> 8) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 0) & 0xFF);
        }
    }


    public final void writeChars(char[] values, int startIndex, int size) {
        int newByteIndex = byteIndex + (size << 1);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            char v = values[startIndex + i];
            bytes[byteIndex++] = (byte) ((v >>> 8) & 0xFF);
            bytes[byteIndex++] = (byte) ((v) & 0xFF);
        }
    }
    
    public final void writeVChars(char[] values) {
        writeVChars(values, 0, values.length);
    }
    
    public final void writeVChars(String values) {
        writeVChars(values, 0, values.length());
    }


    public final void writeVChars(char[] values, int startIndex, int size) {
        boolean writeAscii = true;
        for (int i = 0; i < size; i++) {
            char c = values[startIndex + i];
            if (c > 255) {
                writeAscii = false;
                break;
            }
        }    
        byte writeType;
        if (writeAscii) {
            if (size <= Byte.MAX_VALUE) {
                writeType = BYTE_ASCII;
            } else if (size <= Short.MAX_VALUE) {
                writeType = SHORT_ASCII;
            } else {
                writeType = INT_ASCII;
            }
        } else {
            if (size <= Byte.MAX_VALUE) {
                writeType = BYTE_NASCII;
            } else if (size <= Short.MAX_VALUE) {
                writeType = SHORT_NASCII;
            } else {
                writeType = INT_NASCII;
            }
        }
        writeByte(writeType);
        int newByteIndex;
        switch (writeType) {
        case BYTE_ASCII:
            writeByte((byte) size);
            newByteIndex = byteIndex + (size);  
            break;
        case SHORT_ASCII:
            writeShort((short) size);
            newByteIndex = byteIndex + (size);  
            break;
        case INT_ASCII:
            writeInt(size);
            newByteIndex = byteIndex + (size);  
            break;
        case BYTE_NASCII:
            writeByte((byte) size);
            newByteIndex = byteIndex + (size << 1);  
            break;
        case SHORT_NASCII:
            writeShort((short) size);
            newByteIndex = byteIndex + (size << 1);  
            break;
        default:
        case INT_NASCII:
            writeInt(size);
            newByteIndex = byteIndex + (size << 1);  
            break;
                
        }       
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            char v = values[startIndex + i];
            if (writeAscii) {
                bytes[byteIndex++] = (byte) ((v) & 0xFF);
            } else {
                bytes[byteIndex++] = (byte) ((v >>> 8) & 0xFF);
                bytes[byteIndex++] = (byte) ((v) & 0xFF);
            }
        }        
    }
    
    public final void writeVChars(String values, int startIndex, int size) {
        boolean writeAscii = true;
        for (int i = 0; i < size; i++) {
            char c = values.charAt(startIndex + i);
            if (c > 255) {
                writeAscii = false;
                break;
            }
        }    
        byte writeType;
        if (writeAscii) {
            if (size <= Byte.MAX_VALUE) {
                writeType = BYTE_ASCII;
            } else if (size <= Short.MAX_VALUE) {
                writeType = SHORT_ASCII;
            } else {
                writeType = INT_ASCII;
            }
        } else {
            if (size <= Byte.MAX_VALUE) {
                writeType = BYTE_NASCII;
            } else if (size <= Short.MAX_VALUE) {
                writeType = SHORT_NASCII;
            } else {
                writeType = INT_NASCII;
            }
        }
        writeByte(writeType);
        int newByteIndex;
        switch (writeType) {
        case BYTE_ASCII:
            writeByte((byte) size);
            newByteIndex = byteIndex + (size);  
            break;
        case SHORT_ASCII:
            writeShort((short) size);
            newByteIndex = byteIndex + (size);  
            break;
        case INT_ASCII:
            writeInt(size);
            newByteIndex = byteIndex + (size);  
            break;
        case BYTE_NASCII:
            writeByte((byte) size);
            newByteIndex = byteIndex + (size << 1);  
            break;
        case SHORT_NASCII:
            writeShort((short) size);
            newByteIndex = byteIndex + (size << 1);  
            break;
        default:
        case INT_NASCII:
            writeInt(size);
            newByteIndex = byteIndex + (size << 1);  
            break;
                
        }       
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            char v = values.charAt(startIndex + i);
            if (writeAscii) {
                bytes[byteIndex++] = (byte) ((v) & 0xFF);
            } else {
                bytes[byteIndex++] = (byte) ((v >>> 8) & 0xFF);
                bytes[byteIndex++] = (byte) ((v) & 0xFF);
            }
        }        
    }


    public char[] readVChars() {
        byte writeType = readByte();
        int size;
        char[] chars;
        switch (writeType) {
        case BYTE_ASCII:
            size = readByte();
            chars = new char[size];
            for (int i = 0; i < size; i++) {
                chars[i] = (char)((bytes[byteIndex++] & 0xFF));            
            }
            break;
        case SHORT_ASCII:
            size = readShort();
            chars = new char[size];
            for (int i = 0; i < size; i++) {
                chars[i] = (char)((bytes[byteIndex++] & 0xFF));            
            }
            break;
        case INT_ASCII:
            size = readInt();
            chars = new char[size];
            for (int i = 0; i < size; i++) {
                chars[i] = (char)((bytes[byteIndex++] & 0xFF));            
            }
            break;
        case BYTE_NASCII:
            size = readByte();
            chars = new char[size];
            for (int i = 0; i < size; i++) {
                chars[i] = (char)((bytes[byteIndex++] << 8) | (bytes[byteIndex++] & 0xFF));        
            }
            break;
        case SHORT_NASCII:
            size = readShort();
            chars = new char[size];
            for (int i = 0; i < size; i++) {
                chars[i] = (char)((bytes[byteIndex++] << 8) | (bytes[byteIndex++] & 0xFF));            
            }
            break;
        case INT_NASCII:
        default:
            size = readInt();
            chars = new char[size];
            for (int i = 0; i < size; i++) {
                chars[i] = (char)((bytes[byteIndex++] << 8) | (bytes[byteIndex++] & 0xFF));          
            }
        }
        return chars;
    }


    public final void writeShort(short v) {
        int newByteIndex = byteIndex + 2;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        bytes[byteIndex++] = (byte) ((v >>> 8) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>> 0) & 0xFF);
    }


    public final void writeShorts(short[] values, int size) {
        int newByteIndex = byteIndex + (size << 1);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            short v = values[i];
            bytes[byteIndex++] = (byte) ((v >>> 8) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 0) & 0xFF);
        }
    }


    public final void writeInt(int v) {
        int newByteIndex = byteIndex + 4;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        bytes[byteIndex++] = (byte) ((v >>> 24) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>> 16) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>>  8) & 0xFF);
        bytes[byteIndex++] = (byte) ((v) & 0xFF);
    }


    public final void writeInts(int[] values, int size) {
        int newByteIndex = byteIndex + (size << 2);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            int v = values[i];
            bytes[byteIndex++] = (byte) ((v >>> 24) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 16) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>>  8) & 0xFF);
            bytes[byteIndex++] = (byte) ((v) & 0xFF);
        }
    }
    


    public final void writeInts(int[] values, int startIndex, int size) {
        int newByteIndex = byteIndex + (size << 2);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            int v = values[startIndex + i];
            bytes[byteIndex++] = (byte) ((v >>> 24) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 16) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>>  8) & 0xFF);
            bytes[byteIndex++] = (byte) ((v) & 0xFF);
        }
    }


    public final void writeBooleans(boolean[] values, int size) {
        int newByteIndex = byteIndex + size;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            boolean v = values[i];
            bytes[byteIndex++] = v ? BYTE_ONE : BYTE_ZERO;
        }
    }


    public final void writeLong(long v) {
        int newByteIndex = byteIndex + 8;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        
        bytes[byteIndex++] = (byte) ((v >>> 56) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>> 48) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>> 40) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>> 32) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>> 24) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>> 16) & 0xFF);
        bytes[byteIndex++] = (byte) ((v >>>  8) & 0xFF);
        bytes[byteIndex++] = (byte) ((v) & 0xFF);
    }


    public final void writeLongs(long[] values, int size) {
        int newByteIndex = byteIndex + (size << 3);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            long v = values[i];
            bytes[byteIndex++] = (byte) ((v >>> 56) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 48) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 40) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 32) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 24) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 16) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>>  8) & 0xFF);
            bytes[byteIndex++] = (byte) ((v) & 0xFF);
        }
    }


    public final void writeLongs(long[] values, int startIndex, int size) {
        int newByteIndex = byteIndex + (size << 3);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            long v = values[startIndex + i];
            bytes[byteIndex++] = (byte) ((v >>> 56) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 48) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 40) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 32) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 24) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>> 16) & 0xFF);
            bytes[byteIndex++] = (byte) ((v >>>  8) & 0xFF);
            bytes[byteIndex++] = (byte) ((v) & 0xFF);
        }
    }


    public final void writeFloat(float v) {
        int newByteIndex = byteIndex + 4;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        writeInt(Float.floatToIntBits(v));
    }


    public final void writeFloats(float[] values, int size) {
        int newByteIndex = byteIndex + (size << 2);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            float v = values[i];
            writeInt(Float.floatToIntBits(v));
        }
    }


    public final void writeDouble(double v) {
        int newByteIndex = byteIndex + 8;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        writeLong(Double.doubleToLongBits(v));
    }


    public final void writeDoubles(double[] values, int size) {
        int newByteIndex = byteIndex + (size << 3);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = 0; i < size; i++) {
            double v = values[i];
            writeLong(Double.doubleToLongBits(v));
        }
    }


    public final void write(byte[] v) {
        write(v, 0, v.length);
    }


    public final void write(byte[] v, int length) {
        write(v, 0, length);
    }


    public final void write(byte[] v, int start, int length) {
        if (length == 0) {
            return;
        }
        int newByteIndex = byteIndex + length;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        System.arraycopy(v, start, bytes, byteIndex, length);
        byteIndex += length;
    }


    public final void write(char[] chars) {
        byte[] writeBytes = CharUtil.toBytes(chars);
        write(writeBytes);
    }


    public final byte readByte() {
        return bytes[byteIndex++];
    }


    public final void loadBytes(byte[] readBytes) {
        readFully(readBytes);
    }


    public final void loadBytes(boolean[] isNulls, byte[] values) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            byteIndex++; // skip type
            values[i] = bytes[byteIndex++];
        }
    }
    
    public final char readChar() {
        return (char)((bytes[byteIndex++] << 8) | (bytes[byteIndex++] & 0xFF));
    }


    public final void loadChars(char[] chars) {
        for (int i = 0; i < chars.length; i++) {
            chars[i] = (char)((bytes[byteIndex++] << 8) | (bytes[byteIndex++] & 0xFF));
        }
    }


    public final void loadChars(boolean[] isNulls, char[] values) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            byteIndex++; // skip type
            values[i] = (char)((bytes[byteIndex++] << 8) | (bytes[byteIndex++] & 0xFF));
        }
    }


    public final short readShort() {
        return (short)((bytes[byteIndex++] << 8) | (bytes[byteIndex++] & 0xFF));
    }


    public final void loadShorts(short[] shorts) {
        for (int i = 0; i < shorts.length; i++) {
            shorts[i] = (short)((bytes[byteIndex++] << 8) | (bytes[byteIndex++] & 0xFF));
        }
    }


    public final int readInt() {
        return (((bytes[byteIndex++] & 0xFF) << 24) |
                ((bytes[byteIndex++] & 0xFF) << 16) |
                ((bytes[byteIndex++] & 0xFF) << 8)  |
                ((bytes[byteIndex++] & 0xFF)));
    }


    public final void loadInts(int[] ints) {
        for (int i = 0; i < ints.length; i++) {
            ints[i] = (((bytes[byteIndex++] & 0xFF) << 24) |
                      ((bytes[byteIndex++] & 0xFF) << 16) |
                      ((bytes[byteIndex++] & 0xFF) << 8)  |
                      ((bytes[byteIndex++] & 0xFF)));
        }
    }
    
    public final void loadInts(boolean[] isNulls, int[] values) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            byteIndex++; // skip type
            values[i] = (((bytes[byteIndex++] & 0xFF) << 24) |
                      ((bytes[byteIndex++] & 0xFF) << 16) |
                      ((bytes[byteIndex++] & 0xFF) << 8)  |
                      ((bytes[byteIndex++] & 0xFF)));
        }
    }


    public final void loadTinyDecimals(boolean[] isNulls, int[] values, byte[] scales) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            // has type and skip type
            byteIndex++; 
            values[i] = (((bytes[byteIndex++] & 0xFF) << 24) |
                      ((bytes[byteIndex++] & 0xFF) << 16) |
                      ((bytes[byteIndex++] & 0xFF) << 8)  |
                      ((bytes[byteIndex++] & 0xFF)));
            byte scale = bytes[byteIndex++];
            if (scales != null) {
                scales[i] = scale;
            }
        }
    }


    public final void loadSmallDecimals(boolean[] isNulls, long[] values, byte[] scales) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            byteIndex++; 
            values[i] = ((((long)bytes[byteIndex++] & 0xFF) << 56) |
                       (((long)bytes[byteIndex++] & 0xFF) << 48) |
      (((long)bytes[byteIndex++] & 0xFF) << 40) |
                       (((long)bytes[byteIndex++] & 0xFF) << 32) |
                       (((long)bytes[byteIndex++] & 0xFF) << 24) |
                       (((long)bytes[byteIndex++] & 0xFF) << 16) |
                       (((long)bytes[byteIndex++] & 0xFF) <<  8) |
                       (((long)bytes[byteIndex++] & 0xFF)));
            // has scale
            byte scale = bytes[byteIndex++];
            if (scales != null) {
                scales[i] = scale;
            }
        }
    }


    public final void loadBooleans(boolean[] bs) {
        for (int i = 0; i < bs.length; i++) {
            bs[i] = (bytes[byteIndex++] == BYTE_ONE);
        }
    }


    public final void loadBooleans(boolean[] isNulls, boolean[] values) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            // skip type
            byteIndex++;
            values[i] = (bytes[byteIndex++] == BYTE_ONE);
        }
    }


    public final long readLong() {
        return ((((long)bytes[byteIndex++] & 0xFF) << 56) |
                (((long)bytes[byteIndex++] & 0xFF) << 48) |
(((long)bytes[byteIndex++] & 0xFF) << 40) |
                (((long)bytes[byteIndex++] & 0xFF) << 32) |
                (((long)bytes[byteIndex++] & 0xFF) << 24) |
                (((long)bytes[byteIndex++] & 0xFF) << 16) |
                (((long)bytes[byteIndex++] & 0xFF) <<  8) |
                (((long)bytes[byteIndex++] & 0xFF)));
    }


    public final void loadLongs(long[] longs) {
        for (int i = 0; i < longs.length; i++) {
            longs[i] = ((((long)bytes[byteIndex++] & 0xFF) << 56) |
                       (((long)bytes[byteIndex++] & 0xFF) << 48) |
      (((long)bytes[byteIndex++] & 0xFF) << 40) |
                       (((long)bytes[byteIndex++] & 0xFF) << 32) |
                       (((long)bytes[byteIndex++] & 0xFF) << 24) |
                       (((long)bytes[byteIndex++] & 0xFF) << 16) |
                       (((long)bytes[byteIndex++] & 0xFF) <<  8) |
                       (((long)bytes[byteIndex++] & 0xFF)));
        }
    }


    public final void loadLongs(boolean[] isNulls, long[] values) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            // skip type
            byteIndex++;
            values[i] = ((((long)bytes[byteIndex++] & 0xFF) << 56) |
                       (((long)bytes[byteIndex++] & 0xFF) << 48) |
      (((long)bytes[byteIndex++] & 0xFF) << 40) |
                       (((long)bytes[byteIndex++] & 0xFF) << 32) |
                       (((long)bytes[byteIndex++] & 0xFF) << 24) |
                       (((long)bytes[byteIndex++] & 0xFF) << 16) |
                       (((long)bytes[byteIndex++] & 0xFF) <<  8) |
                       (((long)bytes[byteIndex++] & 0xFF)));
        }
    }


    public final float readFloat() {
return Float.intBitsToFloat(readInt());
    }


    public final void loadFloats(float[] floats) {
        for (int i = 0; i < floats.length; i++) {
            int v = (((bytes[byteIndex++] & 0xFF) << 24) |
                      ((bytes[byteIndex++] & 0xFF) << 16) |
                      ((bytes[byteIndex++] & 0xFF) << 8)  |
                      ((bytes[byteIndex++] & 0xFF)));
            floats[i] = Float.intBitsToFloat(v);
        }
    }


    public final void loadFloats(boolean[] isNulls, float[] values) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            // skip type
            byteIndex++;
            int v = (((bytes[byteIndex++] & 0xFF) << 24) |
                      ((bytes[byteIndex++] & 0xFF) << 16) |
                      ((bytes[byteIndex++] & 0xFF) << 8)  |
                      ((bytes[byteIndex++] & 0xFF)));
            values[i] = Float.intBitsToFloat(v);
        }
    }
    
    public final double readDouble() {
return Double.longBitsToDouble(readLong());
    }


    public final void loadDoubles(double[] doubles) {
        for (int i = 0; i < doubles.length; i++) {
            long l = ((((long)bytes[byteIndex++] & 0xFF) << 56) |
                       (((long)bytes[byteIndex++] & 0xFF) << 48) |
      (((long)bytes[byteIndex++] & 0xFF) << 40) |
                       (((long)bytes[byteIndex++] & 0xFF) << 32) |
                       (((long)bytes[byteIndex++] & 0xFF) << 24) |
                       (((long)bytes[byteIndex++] & 0xFF) << 16) |
                       (((long)bytes[byteIndex++] & 0xFF) <<  8) |
                       (((long)bytes[byteIndex++] & 0xFF)));
            doubles[i] = Double.longBitsToDouble(l);
        }
    }


    public final void loadDoubles(boolean[] isNulls, double[] values) {
        for (int i = 0; i < values.length; i++) {
            boolean isNull = bytes[byteIndex++] == BYTE_ONE;
            isNulls[i] = isNull;
            if (isNull) {
                continue;
            }
            // skip type
            byteIndex++;
            long l = ((((long)bytes[byteIndex++] & 0xFF) << 56) |
                       (((long)bytes[byteIndex++] & 0xFF) << 48) |
      (((long)bytes[byteIndex++] & 0xFF) << 40) |
                       (((long)bytes[byteIndex++] & 0xFF) << 32) |
                       (((long)bytes[byteIndex++] & 0xFF) << 24) |
                       (((long)bytes[byteIndex++] & 0xFF) << 16) |
                       (((long)bytes[byteIndex++] & 0xFF) <<  8) |
                       (((long)bytes[byteIndex++] & 0xFF)));
            values[i] = Double.longBitsToDouble(l);
        }
    }


    public final byte[] read(int length) {
        byte[] readBytes = new byte[length];
        System.arraycopy(bytes, byteIndex, readBytes, 0, length);
        byteIndex += length;
        return readBytes;
    }


    public void write(int b) {
        writeByte((byte) b);
    }


    public void writeBoolean(boolean v) {
        write(v ? BYTE_ONE : BYTE_ZERO);
    }


    public void writeByte(int v) {
        writeByte((byte) v);
    }


    public void writeShort(int v) {
        write((short) v);
    }


    public void writeChar(int v) {
        writeChar((char) v);
    }


    public void writeBytes(String s) {
        byte[] values = s.getBytes();;
        writeBytes(values, values.length);
    }


    public void writeChars(String s) {
        char[] values = s.toCharArray();
        writeChars(values, values.length);
    }


    public void writeUTF(String s) {
        byte[] values = s.getBytes(UTF8_CHARSET);
        writeInt(values.length);
        write(values, values.length);
    }


    @Override
    public void readFully(byte[] b) {
        if (b.length == 0) {
            return;
        }
        System.arraycopy(bytes, byteIndex, b, 0, b.length);
        byteIndex += b.length;
    }


    public void readFully(byte[] b, int off, int len) {
        if (len > 0) {
            System.arraycopy(bytes, byteIndex, b, off, len);
            byteIndex += len;
        }
    }


    public int skipBytes(int n) {
        byteIndex += n;
        return byteIndex;
    }


    public boolean readBoolean() {
        return bytes[byteIndex++] == BYTE_ONE;
    }


    public int readUnsignedByte() throws IOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }


    public int readUnsignedShort() throws IOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }


    public String readLine() throws IOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }


    public String readUTF() throws IOException {
        int length = readInt();
        byte[] values = new byte[length];
        readFully(values);
        return new String(values, UTF8_CHARSET);
    }


    public byte[] toByteArray() {
        return Arrays.copyOf(bytes, byteIndex);
    }
    
    public void writeVInt(int value) throws IOException {
        int newByteIndex = byteIndex + 9;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        if (value >= -112 && value <= 127) {
            bytes[byteIndex++] = ((byte)value);
            return;
        }


        int len = -112;
        if (value < 0) {
            value ^= -1L; // take one's complement'
            len = -120;
        }


        long tmp = value;
        while (tmp != 0) {
            tmp = tmp >> 8;
            len--;
        }


        bytes[byteIndex++] = ((byte)len);


        len = (len < -120) ? -(len + 120) : -(len + 112);


        for (int idx = len; idx != 0; idx--) {
            int shiftbits = (idx - 1) * 8;
            long mask = 0xFFL << shiftbits;
            bytes[byteIndex++] = ((byte)((value & mask) >> shiftbits));
        }
    }


    public final int readVInt() throws IOException {
        byte firstByte = bytes[byteIndex++];
        int len = firstByte >= -112 ? 1                 
                                    : ((firstByte < -120) ? (-119 - firstByte) 
                                                          : (-111 - firstByte));
        if (len == 1) {
            return firstByte;
        }
        long i = 0;
        for (int idx = 0; idx < len-1; idx++) {
            byte b = bytes[byteIndex++];
            i = i << 8;
            i = i | (b & 0xFF);
        }
        return (int) ((firstByte < -120 || (firstByte >= -112 && firstByte < 0)) ? (i ^ -1L) 
                                                                                 : i);        
    }
    
    public final void readRLE(int[] values) throws IOException {
        int size = values.length;
        int index = 0;
        // loop until reach last
        while (index < size) {
            // read byte value
            int fileIndex = readVInt();
            // read count
            int count = readVInt();
            // expand
            for (int i = 0; i < count; i++) {
                values[index] = fileIndex;
                index++;
            }
        }        
    }
    
    
    public void writeVLong(long value) throws IOException {
        int newByteIndex = byteIndex + 9;
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        if (value >= -112 && value <= 127) {
            bytes[byteIndex++] = ((byte)value);
            return;
        }


        int len = -112;
        if (value < 0) {
            value ^= -1L; // take one's complement'
            len = -120;
        }


        long tmp = value;
        while (tmp != 0) {
            tmp = tmp >> 8;
            len--;
        }


        bytes[byteIndex++] = ((byte)len);


        len = (len < -120) ? -(len + 120) : -(len + 112);


        for (int idx = len; idx != 0; idx--) {
            int shiftbits = (idx - 1) * 8;
            long mask = 0xFFL << shiftbits;
            bytes[byteIndex++] = ((byte)((value & mask) >> shiftbits));
        }
    }
    
    public void writeVLongs(long[] values, int startIndex, int size) throws IOException {
        int newByteIndex = byteIndex + (size * 9);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = startIndex; i < size; i++) {
            long value = values[i];
            if (value >= -112 && value <= 127) {
                bytes[byteIndex++] = ((byte)value);
                continue;
            }


            int len = -112;
            if (value < 0) {
                value ^= -1L; // take one's complement'
                len = -120;
            }


            long tmp = value;
            while (tmp != 0) {
                tmp = tmp >> 8;
                len--;
            }


            bytes[byteIndex++] = ((byte)len);


            len = (len < -120) ? -(len + 120) : -(len + 112);


            for (int idx = len; idx != 0; idx--) {
                int shiftbits = (idx - 1) * 8;
                long mask = 0xFFL << shiftbits;
                bytes[byteIndex++] = ((byte)((value & mask) >> shiftbits));
            }
        }
    }
    
    public void loadVLongs(long[] values) throws IOException {
        for (int k = 0; k < values.length; k++) {
            byte firstByte = bytes[byteIndex++];
            int len = firstByte >= -112 ? 1                 
                                        : ((firstByte < -120) ? (-119 - firstByte) 
                                                              : (-111 - firstByte));
            if (len == 1) {
                values[k] = firstByte;
                continue;
            }
            long i = 0;
            for (int idx = 0; idx < len-1; idx++) {
                byte b = bytes[byteIndex++];
                i = i << 8;
                i = i | (b & 0xFF);
            }
            values[k] = ((firstByte < -120 || (firstByte >= -112 && firstByte < 0)) ? (i ^ -1L) 
                                                                                          : i);        
        }
    }


    public void writeVInts(int[] values, int startIndex, int size) throws IOException {
        int newByteIndex = byteIndex + (size * 9);
        if (newByteIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, Math.max(bytes.length << 1, newByteIndex));
        }
        for (int i = startIndex; i < size; i++) {
            long value = values[i];
            if (value >= -112 && value <= 127) {
                bytes[byteIndex++] = ((byte)value);
                continue;
            }


            int len = -112;
            if (value < 0) {
                value ^= -1L; // take one's complement'
                len = -120;
            }


            long tmp = value;
            while (tmp != 0) {
                tmp = tmp >> 8;
                len--;
            }


            bytes[byteIndex++] = ((byte)len);


            len = (len < -120) ? -(len + 120) : -(len + 112);


            for (int idx = len; idx != 0; idx--) {
                int shiftbits = (idx - 1) * 8;
                long mask = 0xFFL << shiftbits;
                bytes[byteIndex++] = ((byte)((value & mask) >> shiftbits));
            }
        }
    }
    
    public void loadVInts(int[] values) throws IOException {
        for (int k = 0; k < values.length; k++) {
            byte firstByte = bytes[byteIndex++];
            // int len = decodeVIntSize(firstByte);
            int len = firstByte >= -112 ? 1                 
                                        : ((firstByte < -120) ? (-119 - firstByte) 
                                                              : (-111 - firstByte));
            if (len == 1) {
                values[k] = firstByte;
                continue;
            }
            long i = 0;
            for (int idx = 0; idx < len-1; idx++) {
                byte b = bytes[byteIndex++];
                i = i << 8;
                i = i | (b & 0xFF);
            }
            values[k] = (int) ((firstByte < -120 || (firstByte >= -112 && firstByte < 0)) ? (i ^ -1L) 
                                                                                          : i);        
        }
    }
    
    /**
    * Reads a zero-compressed encoded long from input stream and returns it.
    * @param stream Binary input stream
    * @throws java.io.IOException 
    * @return deserialized long from stream.
    */
    public final long readVLong() throws IOException {
        byte firstByte = bytes[byteIndex++];
        int len = firstByte >= -112 ? 1                 
                                    : ((firstByte < -120) ? (-119 - firstByte) 
                                                          : (-111 - firstByte));
        if (len == 1) {
            return firstByte;
        }
        long i = 0;
        for (int idx = 0; idx < len-1; idx++) {
            byte b = bytes[byteIndex++];
            i = i << 8;
            i = i | (b & 0xFF);
        }
        return (firstByte < -120 || (firstByte >= -112 && firstByte < 0))  ? (i ^ -1L) 
                                                                           : i;
    }
    
    /**
    * Given the first byte of a vint/vlong, determine the sign
    * @param value the first byte
    * @return is the value negative
    */
    public static boolean isNegativeVInt(byte value) {
        return value < -120 || (value >= -112 && value < 0);
    }


    /**
    * Parse the first byte of a vint/vlong to determine the number of bytes
    * @param value the first byte of the vint/vlong
    * @return the total number of bytes (1 to 9)
    */
    public static int decodeVIntSize(byte value) {
        if (value >= -112) {
            return 1;
        } else if (value < -120) {
            return -119 - value;
        }
        return -111 - value;
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FocusOneThread

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值