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

org.fuzzydb.util.ReadAheadInputStream Maven / Gradle / Ivy

Go to download

Contains classes not specific to fuzzydb implementation which could be used in any implementation of fuzzy matching, or as general utility classes such as those in the geo package.

The newest version!
/******************************************************************************
 * WARNING: NEED TO SORT OUT SOURCE OF THIS.
 * OpenJDK7 is GPL2, so the file below could be a contribution to OpenJDK.
 * http://www.docjar.com/html/api/java/io/BufferedInputStream.java.html
 *****************************************************************************/
package org.fuzzydb.util;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * Derived from Sun's BufferedInputStream, as they suggest we do in the source for that file :O)
 *
 */
public class ReadAheadInputStream extends FilterInputStream {

	private static int defaultBufferSize = 65536;
	private int readThruThreshold;
	private Adler64 checksum = new Adler64();
	private long byteCount = 0;
	
	/**
	 * Internal buffer
	 */
	protected volatile byte buf[];

	/**
	 * Atomic updater to provide compareAndSet for buf. This is
	 * necessary because closes can be asynchronous. We use nullness
	 * of buf[] as primary indicator that this stream is closed. (The
	 * "in" field is also nulled out on close.)
	 */
	private static final AtomicReferenceFieldUpdater bufUpdater = AtomicReferenceFieldUpdater
			.newUpdater(ReadAheadInputStream.class, byte[].class, "buf");

	/**
	 * The index one greater than the index of the last valid byte in 
	 * the buffer. 
	 * This value is always
	 * in the range 0 through buf.length;
	 * elements buf[0]  through buf[count-1]
	 * contain buffered input data obtained
	 * from the underlying  input stream.
	 */
	protected int count;

	/**
	 * The current position in the buffer. This is the index of the next 
	 * character to be read from the buf array. 
	 * 

* This value is always in the range 0 * through count. If it is less * than count, then buf[pos] * is the next byte to be supplied as input; * if it is equal to count, then * the next read or skip * operation will require more bytes to be * read from the contained input stream. * * @see java.io.BufferedInputStream#buf */ protected int pos; /** * Check to make sure that underlying input stream has not been * nulled out due to close; if not return it; */ private InputStream getInIfOpen() throws IOException { InputStream input = in; if (input == null) throw new IOException("Stream closed"); return input; } /** * Check to make sure that buffer has not been nulled out due to * close; if not return it; */ private byte[] getBufIfOpen() throws IOException { byte[] buffer = buf; if (buffer == null) throw new IOException("Stream closed"); return buffer; } /** * Creates a BufferedInputStream * and saves its argument, the input stream * in, for later use. An internal * buffer array is created and stored in buf. * * @param in the underlying input stream. */ public ReadAheadInputStream(InputStream in) { this(in, defaultBufferSize); } /** * Creates a BufferedInputStream * with the specified buffer size, * and saves its argument, the input stream * in, for later use. An internal * buffer array of length size * is created and stored in buf. * * @param in the underlying input stream. * @param size the buffer size. * @exception IllegalArgumentException if size <= 0. */ public ReadAheadInputStream(InputStream in, int size) { super(in); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; readThruThreshold = size / 2; } /** * Entirely fill the buffer with data (or whatever the read call will give us) */ private void fill() throws IOException { // preconditions assert( pos == count ); // Should only have got here when we've exhausted the buffer byte[] buffer = getBufIfOpen(); // Reset our position pos = 0; // Attempt to read whole buffer count = getInIfOpen().read(buffer, 0, buffer.length); } /** * See * the general contract of the read * method of InputStream. * * @return the next byte of data, or -1 if the end of the * stream is reached. * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override public synchronized int read() throws IOException { if (pos >= count) { fill(); if (pos >= count) return -1; } int rval = getBufIfOpen()[pos++] & 0xff; checksum.update(rval); byteCount += 1; return rval; } /** * Read as much as is wanted (len) or available (count-pos) from our buffer into * the requested array, b. */ private int readFromBuffer(byte[] b, int off, int len) throws IOException { // preconditions assert( count > pos ); // Shouldn't be called if nowt available int avail = count - pos; // Number to read = min( avail, len ) int cnt = (avail < len) ? avail : len; System.arraycopy(getBufIfOpen(), pos, b, off, cnt); // Copy from buf[pos] to b[off] for cnt bytes pos += cnt; //postconditions assert (pos <= count ); return cnt; } /** * Reads bytes from this byte-input stream into the specified byte array, * starting at the given offset. * *

This method implements the general contract of the corresponding * {@link InputStream#read(byte[], int, int) read} method of * the {@link InputStream} class. As an additional * convenience, it attempts to read as many bytes as possible by repeatedly * invoking the read method of the underlying stream. This * iterated read continues until one of the following * conditions becomes true:

    * *
  • The specified number of bytes have been read, * *
  • The read method of the underlying stream returns * -1, indicating end-of-file, or * *
  • The available method of the underlying stream * returns zero, indicating that further input requests would block. * *
If the first read on the underlying stream returns * -1 to indicate end-of-file then this method returns * -1. Otherwise this method returns the number of bytes * actually read. * *

Subclasses of this class are encouraged, but not required, to * attempt to read as many bytes as possible in the same fashion. * * @param b destination buffer. * @param off offset at which to start storing bytes. * @param len maximum number of bytes to read. * @return the number of bytes read, or -1 if the end of * the stream has been reached. * @exception IOException if an I/O error occurs. */ @Override public synchronized int read(byte b[], int off, int len) throws IOException { getBufIfOpen(); // Check for closed stream if ((off | len | (off + len) | (b.length - (off + len))) < 0) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } // If buffer isn't empty then return what's required from what we have if ( pos < count ) { int rval = readFromBuffer( b, off, len ); if (rval > 0 ) { checksum.update(b, off, rval); byteCount += rval; } return rval; } // Buffer is empty // If len requested is >= than readThruThreshold, then passThru read if ( len >= readThruThreshold ) { int rval = getInIfOpen().read( b, off, len ); if (rval > 0 ) { checksum.update(b, off, rval); byteCount += rval; } return rval; } // Otherwise, fill buffer, and then read from buffer if (pos >= count) { fill(); if (pos >= count) return -1; } int rval = readFromBuffer( b, off, len ); if (rval > 0 ) { checksum.update(b, off, rval); byteCount += rval; } return rval; } /** * See the general contract of the skip * method of InputStream. * * @param n the number of bytes to be skipped. * @return the actual number of bytes skipped. * @exception IOException if an I/O error occurs. */ @Override public synchronized long skip(long n) { throw(new RuntimeException("ReadAheadInputStream.skip() not implemented due to checksum calculations")); // getBufIfOpen(); // Check for closed stream // if (n <= 0) { // return 0; // } // long avail = count - pos; // // // If nothing in buffer, skip on stream // if (avail <= 0) { // return getInIfOpen().skip(n); // } // // // Otherwise skip up to remainder of buffer length of what's required on buffer // long skipped = (avail < n) ? avail : n; // pos += skipped; // return skipped; } /** * Returns the number of bytes that can be read from this input * stream without blocking. *

* The available method of * BufferedInputStream returns the sum of the number * of bytes remaining to be read in the buffer * (count - pos) * and the result of calling the available method of the * underlying input stream. * * @return the number of bytes that can be read from this input * stream without blocking. * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override public synchronized int available() throws IOException { return getInIfOpen().available() + (count - pos); } /** * Closes this input stream and releases any system resources * associated with the stream. * * @exception IOException if an I/O error occurs. */ @Override public void close() throws IOException { byte[] buffer; while ((buffer = buf) != null) { if (bufUpdater.compareAndSet(this, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return; } // Else retry in case a new buf was CASed in fill() } } public long getChecksumValue() { return checksum.getValue(); } public long getByteCount() { return byteCount; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy