com.facebook.infrastructure.io.DataInputBuffer.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.infrastructure.io.DataInputBuffer.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.facebook.infrastructure.io;

import org.apache.commons.lang.ArrayUtils;

import java.io.*;
import java.nio.ByteBuffer;
import java.util.Random;

/**
 * An implementation of the DataInputStream interface. This instance is completely thread 
 * unsafe.
 * 
 * Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
 */

public final class DataInputBuffer extends DataInputStream {
    /*
     * This is a clone of the ByteArrayInputStream class w/o any
     * method being synchronized.
    */
    public static class FastByteArrayInputStream extends InputStream {
        /**
         * An array of bytes that was provided by the creator of the stream.
         * Elements <code>buf[0]</code> through <code>buf[count-1]</code> are
         * the only bytes that can ever be read from the stream; element
         * <code>buf[pos]</code> is the next byte to be read.
         */
        protected byte buf[];

        /**
         * The index of the next character to read from the input stream buffer.
         * This value should always be nonnegative and not larger than the value of
         * <code>count</code>. The next byte to be read from the input stream
         * buffer will be <code>buf[pos]</code>.
         */
        protected int pos;

        /**
         * The currently marked position in the stream. ByteArrayInputStream objects
         * are marked at position zero by default when constructed. They may be
         * marked at another position within the buffer by the <code>mark()</code>
         * method. The current buffer position is set to this point by the
         * <code>reset()</code> method.
         * <p>
         * If no mark has been set, then the value of mark is the offset passed to
         * the constructor (or 0 if the offset was not supplied).
         * 
         * @since JDK1.1
         */
        protected int mark = 0;

        /**
         * The index one greater than the last valid character in the input stream
         * buffer. This value should always be nonnegative and not larger than the
         * length of <code>buf</code>. It is one greater than the position of the
         * last byte within <code>buf</code> that can ever be read from the input
         * stream buffer.
         */
        protected int count;

        public FastByteArrayInputStream() {
            buf = ArrayUtils.EMPTY_BYTE_ARRAY;
        }

        /**
         * Creates a <code>ByteArrayInputStream</code> so that it uses
         * <code>buf</code> as its buffer array. The buffer array is not copied.
         * The initial value of <code>pos</code> is <code>0</code> and the
         * initial value of <code>count</code> is the length of <code>buf</code>.
         * 
         * @param buf
         *            the input buffer.
         */
        public FastByteArrayInputStream(byte buf[]) {
            this.buf = buf;
            this.pos = 0;
            this.count = buf.length;
        }

        /**
         * Creates <code>ByteArrayInputStream</code> that uses <code>buf</code>
         * as its buffer array. The initial value of <code>pos</code> is
         * <code>offset</code> and the initial value of <code>count</code> is
         * the minimum of <code>offset+length</code> and <code>buf.length</code>.
         * The buffer array is not copied. The buffer's mark is set to the specified
         * offset.
         * 
         * @param buf
         *            the input buffer.
         * @param offset
         *            the offset in the buffer of the first byte to read.
         * @param length
         *            the maximum number of bytes to read from the buffer.
         */
        public FastByteArrayInputStream(byte buf[], int offset, int length) {
            this.buf = buf;
            this.pos = offset;
            this.count = Math.min(offset + length, buf.length);
            this.mark = offset;
        }

        public final void setBytes(byte[] bytes) {
            buf = bytes;
            pos = 0;
            count = bytes.length;
        }

        /**
         * Reads the next byte of data from this input stream. The value byte is
         * returned as an <code>int</code> in the range <code>0</code> to
         * <code>255</code>. If no byte is available because the end of the
         * stream has been reached, the value <code>-1</code> is returned.
         * <p>
         * This <code>read</code> method cannot block.
         * 
         * @return the next byte of data, or <code>-1</code> if the end of the
         *         stream has been reached.
         */
        public final int read() {
            return (pos < count) ? (buf[pos++] & 0xFF) : -1;
        }

        /**
         * Reads up to <code>len</code> bytes of data into an array of bytes from
         * this input stream. If <code>pos</code> equals <code>count</code>,
         * then <code>-1</code> is returned to indicate end of file. Otherwise,
         * the number <code>k</code> of bytes read is equal to the smaller of
         * <code>len</code> and <code>count-pos</code>. If <code>k</code> is
         * positive, then bytes <code>buf[pos]</code> through
         * <code>buf[pos+k-1]</code> are copied into <code>b[off]</code> through
         * <code>b[off+k-1]</code> in the manner performed by
         * <code>System.arraycopy</code>. The value <code>k</code> is added
         * into <code>pos</code> and <code>k</code> is returned.
         * <p>
         * This <code>read</code> method cannot block.
         * 
         * @param b
         *            the buffer into which the data is read.
         * @param off
         *            the start offset in the destination array <code>b</code>
         * @param len
         *            the maximum number of bytes read.
         * @return the total number of bytes read into the buffer, or
         *         <code>-1</code> if there is no more data because the end of the
         *         stream has been reached.
         * @exception NullPointerException
         *                If <code>b</code> is <code>null</code>.
         * @exception IndexOutOfBoundsException
         *                If <code>off</code> is negative, <code>len</code> is
         *                negative, or <code>len</code> is greater than
         *                <code>b.length - off</code>
         */
        public final int read(byte b[], int off, int len) {
            if (b == null) {
                throw new NullPointerException();
            } else if (off < 0 || len < 0 || len > b.length - off) {
                throw new IndexOutOfBoundsException();
            }
            if (pos >= count) {
                return -1;
            }
            if (pos + len > count) {
                len = count - pos;
            }
            if (len <= 0) {
                return 0;
            }
            System.arraycopy(buf, pos, b, off, len);
            pos += len;
            return len;
        }

        /**
         * Skips <code>n</code> bytes of input from this input stream. Fewer bytes
         * might be skipped if the end of the input stream is reached. The actual
         * number <code>k</code> of bytes to be skipped is equal to the smaller of
         * <code>n</code> and <code>count-pos</code>. The value <code>k</code>
         * is added into <code>pos</code> and <code>k</code> is returned.
         * 
         * @param n
         *            the number of bytes to be skipped.
         * @return the actual number of bytes skipped.
         */
        public final long skip(long n) {
            if (pos + n > count) {
                n = count - pos;
            }
            if (n < 0) {
                return 0;
            }
            pos += n;
            return n;
        }

        /**
         * Returns the number of remaining bytes that can be read (or skipped over)
         * from this input stream.
         * <p>
         * The value returned is <code>count&nbsp;- pos</code>, which is the
         * number of bytes remaining to be read from the input buffer.
         * 
         * @return the number of remaining bytes that can be read (or skipped over)
         *         from this input stream without blocking.
         */
        public final int available() {
            return count - pos;
        }

        /**
         * Tests if this <code>InputStream</code> supports mark/reset. The
         * <code>markSupported</code> method of <code>ByteArrayInputStream</code>
         * always returns <code>true</code>.
         * 
         * @since JDK1.1
         */
        public final boolean markSupported() {
            return true;
        }

        /**
         * Set the current marked position in the stream. ByteArrayInputStream
         * objects are marked at position zero by default when constructed. They may
         * be marked at another position within the buffer by this method.
         * <p>
         * If no mark has been set, then the value of the mark is the offset passed
         * to the constructor (or 0 if the offset was not supplied).
         * 
         * <p>
         * Note: The <code>readAheadLimit</code> for this class has no meaning.
         * 
         * @since JDK1.1
         */
        public final void mark(int readAheadLimit) {
            mark = pos;
        }

        /**
         * Resets the buffer to the marked position. The marked position is 0 unless
         * another position was marked or an offset was specified in the
         * constructor.
         */
        public final void reset() {
            pos = mark;
        }

        /**
         * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
         * this class can be called after the stream has been closed without
         * generating an <tt>IOException</tt>.
         * <p>
         */
        public final void close() throws IOException {
        }
    }

    private static class Buffer extends FastByteArrayInputStream {
        public Buffer() {
            super(new byte[] {});
        }

        public void reset(byte[] input, int start, int length) {
            this.buf = input;
            this.count = start + length;
            this.mark = start;
            this.pos = start;
        }

        public int getPosition() {
            return pos;
        }

        public int getLength() {
            return count;
        }
    }

    private Buffer buffer;

    /** Constructs a new empty buffer. */
    public DataInputBuffer() {
        this(new Buffer());
    }

    private DataInputBuffer(Buffer buffer) {
        super(buffer);
        this.buffer = buffer;
    }

    /** Resets the data that the buffer reads. */
    public void reset(byte[] input, int length) {
        buffer.reset(input, 0, length);
    }

    /** Resets the data that the buffer reads. */
    public void reset(byte[] input, int start, int length) {
        buffer.reset(input, start, length);
    }

    /** Returns the current position in the input. */
    public int getPosition() {
        return buffer.getPosition();
    }

    /** Returns the length of the input. */
    public int getLength() {
        return buffer.getLength();
    }
}