Coverage Report - org.galagosearch.tupleflow.BufferedFileDataStream
 
Classes in this File Line Coverage Branch Coverage Complexity
BufferedFileDataStream
0%
0/103
0%
0/34
1.37
 
 1  
 // BSD License (http://www.galagosearch.org/license)
 2  
 package org.galagosearch.tupleflow;
 3  
 
 4  
 import java.io.EOFException;
 5  
 import java.io.IOException;
 6  
 import java.io.RandomAccessFile;
 7  
 
 8  
 /**
 9  
  *
 10  
  * @author trevor
 11  
  */
 12  0
 public class BufferedFileDataStream implements DataStream {
 13  
     RandomAccessFile stream;
 14  
     long stopPosition;
 15  
     long startPosition;
 16  
     final static int cacheLength = 32768;
 17  
     long bufferStart;
 18  
     int bufferPosition;
 19  
     byte[] cacheBuffer;
 20  
 
 21  
     /** Creates a new instance of BufferedFileDataStream */
 22  
     public BufferedFileDataStream(RandomAccessFile stream, long stopPosition) throws IOException {
 23  0
         this(stream, stream.getFilePointer(), stopPosition);
 24  0
     }
 25  
 
 26  0
     public BufferedFileDataStream(RandomAccessFile stream, long start, long end) {
 27  0
         assert start <= end;
 28  
 
 29  0
         this.stream = stream;
 30  0
         this.stopPosition = end;
 31  0
         this.cacheBuffer = new byte[0];
 32  0
         this.bufferPosition = 0;
 33  0
         this.bufferStart = start;
 34  0
         this.startPosition = start;
 35  0
     }
 36  
     
 37  
     public BufferedFileDataStream subStream(long start, long length) {
 38  0
         assert start < length();
 39  0
         assert start + length <= length();
 40  0
         return new BufferedFileDataStream(
 41  
                 stream, bufferStart + start,
 42  
                 bufferStart + start + length);
 43  
     }
 44  
 
 45  
     public boolean isDone() {
 46  0
         return stopPosition <= bufferStart + bufferPosition;
 47  
     }
 48  
 
 49  
     public long length() {
 50  0
         return stopPosition - startPosition;
 51  
     }
 52  
 
 53  
     public long getPosition() {
 54  0
         return getAbsolutePosition() - startPosition;
 55  
     }
 56  
 
 57  
     public long getAbsolutePosition() {
 58  0
         return bufferStart + bufferPosition;
 59  
     }
 60  
 
 61  
     /**
 62  
      * Seeks forward into the stream to a particular byte offset (reverse
 63  
      * seeks are not allowed).  The offset is relative to the start position of
 64  
      * this data stream, not the beginning of the file.
 65  
      */
 66  
     public void seek(long offset) {
 67  0
         seekAbsolute(offset + startPosition);
 68  0
     }
 69  
 
 70  
     /**
 71  
      * Seeks forward into the stream to a particular byte offset (reverse
 72  
      * seeks are not allowed).  The offset is relative to the start of the file.
 73  
      */
 74  
     public void seekAbsolute(long offset) {
 75  0
         assert bufferStart + bufferPosition <= offset;
 76  
 
 77  
         // is any of this data cached?
 78  0
         if (offset - bufferStart < cacheBuffer.length) {
 79  
             // this cast is safe because we know it's smaller than cacheBuffer.length
 80  0
             bufferPosition = (int) (offset - bufferStart);
 81  
         } else {
 82  
             // this sets the stream position to the appropriate point,
 83  
             // and effectively invalidates the current cache contents.
 84  0
             bufferStart = offset - cacheBuffer.length;
 85  0
             bufferPosition = cacheBuffer.length;
 86  
         }
 87  0
     }
 88  
 
 89  
     public void readFully(byte[] buffer, int start, int length) throws IOException {
 90  0
         cache(length);
 91  0
         System.arraycopy(cacheBuffer, bufferPosition, buffer, start, length);
 92  0
         update(length);
 93  0
     }
 94  
 
 95  
     public void readFully(byte[] buffer) throws IOException {
 96  0
         cache(buffer.length);
 97  0
         System.arraycopy(cacheBuffer, bufferPosition, buffer, 0, buffer.length);
 98  0
         update(buffer.length);
 99  0
     }
 100  
 
 101  
     public int skipBytes(int n) throws IOException {
 102  0
         update(n);
 103  0
         return n;
 104  
     }
 105  
 
 106  
     public int readUnsignedShort() throws IOException {
 107  0
         cache(2);
 108  
 
 109  0
         byte a = cacheByte(0);
 110  0
         byte b = cacheByte(1);
 111  
 
 112  0
         int result = (((a << 8) | (b & 0xff)) & 0xffff);
 113  
 
 114  0
         update(2);
 115  0
         return result;
 116  
     }
 117  
 
 118  
     public boolean readBoolean() throws IOException {
 119  0
         cache(1);
 120  0
         boolean result = (cacheByte(0) != 0) ? true : false;
 121  0
         update(1);
 122  0
         return result;
 123  
     }
 124  
 
 125  
     public byte readByte() throws IOException {
 126  0
         cache(1);
 127  0
         byte result = cacheByte(0);
 128  0
         update(1);
 129  0
         return result;
 130  
     }
 131  
 
 132  
     public char readChar() throws IOException {
 133  0
         return (char) readShort();
 134  
     }
 135  
 
 136  
     public short readShort() throws IOException {
 137  0
         cache(2);
 138  0
         byte a = cacheByte(0);
 139  0
         byte b = cacheByte(1);
 140  0
         short result = (short) ((a << 8) | (b & 0xff));
 141  0
         update(2);
 142  0
         return result;
 143  
     }
 144  
 
 145  
     public double readDouble() throws IOException {
 146  0
         long result = readLong();
 147  0
         return Double.longBitsToDouble(result);
 148  
     }
 149  
 
 150  
     public float readFloat() throws IOException {
 151  0
         int result = readInt();
 152  0
         return Float.intBitsToFloat(result);
 153  
     }
 154  
 
 155  
     public int readInt() throws IOException {
 156  0
         cache(4);
 157  
 
 158  0
         int a = cacheByte(0);
 159  0
         int b = cacheByte(1);
 160  0
         int c = cacheByte(2);
 161  0
         int d = cacheByte(3);
 162  
 
 163  0
         int result = ((a & 0xff) << 24) |
 164  
                 ((b & 0xff) << 16) |
 165  
                 ((c & 0xff) << 8) |
 166  
                 (d & 0xff);
 167  
 
 168  0
         update(4);
 169  0
         return result;
 170  
     }
 171  
 
 172  
     public String readLine() throws IOException {
 173  0
         throw new IOException("readLine is unimplemented and deprecated");
 174  
     }
 175  
 
 176  
     public long readLong() throws IOException {
 177  0
         long a = readInt();
 178  0
         long b = readInt();
 179  
 
 180  
         // shift a to high word
 181  0
         a <<= 32;
 182  
         // mask b
 183  0
         b &= (0xFFFFFFFFL);
 184  
 
 185  0
         return a | b;
 186  
     }
 187  
 
 188  
     public String readUTF() throws IOException {
 189  0
         throw new IOException("readUTF is unimplemented");
 190  
     }
 191  
 
 192  
     // inlining here for performance
 193  
     public int readUnsignedByte() throws IOException {
 194  0
         if (cacheBuffer.length - bufferPosition >= 1) {
 195  0
             int result = 0xff & (int) cacheBuffer[bufferPosition];
 196  0
             bufferPosition += 1;
 197  0
             return result;
 198  
         } else {
 199  0
             cache(1);
 200  0
             int b = cacheByte(0);
 201  0
             update(1);
 202  0
             return b & 0xff;
 203  
         }
 204  
     }
 205  
     
 206  
     private void cache(int length) throws IOException {
 207  
         assert length >= 0 : "Length can't be negative: " + length + " " +
 208  0
                 bufferStart + bufferPosition + " " + stopPosition;
 209  
 
 210  
         // quick check to see if it's already buffered
 211  0
         if (cacheBuffer.length - bufferPosition >= length) {
 212  0
             return;        // if it's not buffered, is there enough room left in the
 213  
                            // file to cache this much data?
 214  
         }
 215  0
         if (bufferStart + bufferPosition + length > stopPosition) {
 216  0
             throw new EOFException("Tried to read off the end of the file.");
 217  
         }
 218  0
         long current = bufferStart + bufferPosition;
 219  0
         int readLength = (int) Math.min(stopPosition - current, cacheLength);
 220  0
         readLength = Math.max(readLength, length);
 221  
 
 222  0
         if (readLength != cacheBuffer.length) {
 223  0
             cacheBuffer = new byte[readLength];
 224  
         }
 225  0
         stream.seek(current);
 226  0
         stream.readFully(cacheBuffer);
 227  0
         bufferStart = current;
 228  0
         bufferPosition = 0;
 229  0
     }
 230  
     
 231  
     private void update(int length) {
 232  0
         bufferPosition += length;
 233  0
     }
 234  
 
 235  
     private byte cacheByte(int i) {
 236  0
         return cacheBuffer[bufferPosition + i];
 237  
     }
 238  
 }