content: package edu.berkeley.cs.succinct.util.stream;
  
  import org.apache.hadoop.fs.FSDataInputStream;
  
  import java.io.IOException;
  
  /**
   * ByteBuffer like wrapper for FSDataInputStream
   */
  
  public class RandomAccessByteStream {
    private FSDataInputStream stream;
    private long startPos;
    private long limit;
  
    public RandomAccessByteStream(FSDataInputStream stream, long startPos, long limit)
      throws IOException {
      this.stream = stream;
      this.startPos = startPos;
      this.limit = limit;
      stream.seek(startPos);
    }
  
    public byte get() throws IOException {
      if (stream.getPos() >= startPos + limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit);
      }
      return stream.readByte();
    }
  
    public byte get(int index) throws IOException {
      if (index >= limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit + " index = " + index);
      }
      long currentPos = stream.getPos();
      stream.seek(startPos + index);
      byte returnValue = stream.readByte();
      stream.seek(currentPos);
      return returnValue;
    }
  
    public short getShort() throws IOException {
      if (stream.getPos() >= startPos + limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit);
      }
      return stream.readShort();
    }
  
    public short getShort(int index) throws IOException {
      if (index >= limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit + " index = " + index);
      }
      long currentPos = stream.getPos();
      stream.seek(startPos + index);
      short returnValue = stream.readShort();
      stream.seek(currentPos);
      return returnValue;
    }
  
    public int getInt() throws IOException {
      if (stream.getPos() >= startPos + limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit + " currentPos = "
            + stream.getPos());
      }
      return stream.readInt();
    }
  
    public int getInt(int index) throws IOException {
      if (index >= limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit + " index = " + index);
      }
      long currentPos = stream.getPos();
      stream.seek(startPos + index);
      int returnValue = stream.readInt();
      stream.seek(currentPos);
      return returnValue;
    }
  
    public long getLong() throws IOException {
      if (stream.getPos() >= startPos + limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit);
      }
      return stream.readLong();
    }
  
    public long getLong(int index) throws IOException {
      if (index >= limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit + " index = " + index);
      }
      long currentPos = stream.getPos();
      stream.seek(startPos + index);
      long returnValue = stream.readLong();
      stream.seek(currentPos);
      return returnValue;
    }
  
    public long position() throws IOException {
      return stream.getPos() - startPos;
    }
  
    public RandomAccessByteStream position(long pos) throws IOException {
      if (pos >= limit) {
        throw new ArrayIndexOutOfBoundsException(
          "Stream out of bounds: startPos = " + startPos + " limit = " + limit + " position = "
            + pos);
      }
      stream.seek(startPos + pos);
      return this;
    }
  
    public RandomAccessIntStream asIntStream() throws IOException {
      return new RandomAccessIntStream(stream, stream.getPos(),
        (limit - (stream.getPos() - startPos)) / 4);
    }
  
    public RandomAccessLongStream asLongStream() throws IOException {
      return new RandomAccessLongStream(stream, stream.getPos(),
        (limit - (stream.getPos() - startPos)) / 8);
    }
  
    public RandomAccessByteStream rewind() throws IOException {
      return position(0);
    }
  
    public void close() throws IOException {
      stream.close();
    }
  }
  