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

edu.illinois.ncsa.BCGSS.CircularByteBuffer Maven / Gradle / Ivy

The newest version!
///*
// *
// * 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 edu.illinois.ncsa.BCGSS;
///*
// * Circular Byte Buffer
// * Copyright (C) 2002 Stephen Ostermiller
// * http://ostermiller.org/contact.pl?regarding=Java+Utilities
// *
// * This program is free software; you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation; either version 2 of the License, or
// * (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU General Public License for more details.
// *
// * See COPYING.TXT for details.
// */
//
//
//import java.io.*;
//import java.nio.*;
//
///**
// * Implements the Circular Buffer producer/consumer model for bytes.
// * More information about this class is available from ostermiller.org.
// * 

// * Using this class is a simpler alternative to using a PipedInputStream // * and a PipedOutputStream. PipedInputStreams and PipedOutputStreams don't support the // * mark operation, don't allow you to control buffer sizes that they use, // * and have a more complicated API that requires instantiating two // * classes and connecting them. // *

// * This class is thread safe. // * // */ //public class CircularByteBuffer { // // /** // * The default size for a circular byte buffer. // * // * @since ostermillerutils 1.00.00 // */ // private final static int DEFAULT_SIZE = 1024; // // /** // * A buffer that will grow as things are added. // * // * @since ostermillerutils 1.00.00 // */ // public final static int INFINITE_SIZE = -1; // // /** // * The circular buffer. // *

// * The actual capacity of the buffer is one less than the actual length // * of the buffer so that an empty and a full buffer can be // * distinguished. An empty buffer will have the markPostion and the // * writePosition equal to each other. A full buffer will have // * the writePosition one less than the markPostion. // *

// * There are three important indexes into the buffer: // * The readPosition, the writePosition, and the markPosition. // * If the InputStream has never been marked, the readPosition and // * the markPosition should always be the same. The bytes // * available to be read go from the readPosition to the writePosition, // * wrapping around the end of the buffer. The space available for writing // * goes from the write position to one less than the markPosition, // * wrapping around the end of the buffer. The bytes that have // * been saved to support a reset() of the InputStream go from markPosition // * to readPosition, wrapping around the end of the buffer. // * // * @since ostermillerutils 1.00.00 // */ // protected byte[] buffer; // /** // * Index of the first byte available to be read. // * // * @since ostermillerutils 1.00.00 // */ // protected volatile int readPosition = 0; // /** // * Index of the first byte available to be written. // * // * @since ostermillerutils 1.00.00 // */ // protected volatile int writePosition = 0; // /** // * Index of the first saved byte. (To support stream marking.) // * // * @since ostermillerutils 1.00.00 // */ // protected volatile int markPosition = 0; // /** // * Number of bytes that have to be saved // * to support mark() and reset() on the InputStream. // * // * @since ostermillerutils 1.00.00 // */ // protected volatile int markSize = 0; // /** // * If this buffer is infinite (should resize itself when full) // * // * @since ostermillerutils 1.00.00 // */ // protected volatile boolean infinite = false; // /** // * True if a write to a full buffer should block until the buffer // * has room, false if the write method should throw an IOException // * // * @since ostermillerutils 1.00.00 // */ // protected boolean blockingWrite = true; // /** // * The InputStream that can empty this buffer. // * // * @since ostermillerutils 1.00.00 // */ // protected InputStream in = new CircularByteBufferInputStream(); // /** // * true if the close() method has been called on the InputStream // * // * @since ostermillerutils 1.00.00 // */ // protected boolean inputStreamClosed = false; // /** // * The OutputStream that can fill this buffer. // * // * @since ostermillerutils 1.00.00 // */ // protected OutputStream out = new CircularByteBufferOutputStream(); // /** // * true if the close() method has been called on the OutputStream // * // * @since ostermillerutils 1.00.00 // */ // protected boolean outputStreamClosed = false; // // /** // * Make this buffer ready for reuse. The contents of the buffer // * will be cleared and the streams associated with this buffer // * will be reopened if they had been closed. // * // * @since ostermillerutils 1.00.00 // */ // public void clear(){ // synchronized (this){ // readPosition = 0; // writePosition = 0; // markPosition = 0; // outputStreamClosed = false; // inputStreamClosed = false; // } // } // // /** // * Retrieve a OutputStream that can be used to fill // * this buffer. // *

// * Write methods may throw a BufferOverflowException if // * the buffer is not large enough. A large enough buffer // * size must be chosen so that this does not happen or // * the caller must be prepared to catch the exception and // * try again once part of the buffer has been consumed. // * // * // * @return the producer for this buffer. // * // * @since ostermillerutils 1.00.00 // */ // public OutputStream getOutputStream(){ // return out; // } // // /** // * Retrieve a InputStream that can be used to empty // * this buffer. // *

// * This InputStream supports marks at the expense // * of the buffer size. // * // * @return the consumer for this buffer. // * // * @since ostermillerutils 1.00.00 // */ // public InputStream getInputStream(){ // return in; // } // // /** // * Get number of bytes that are available to be read. // *

// * Note that the number of bytes available plus // * the number of bytes free may not add up to the // * capacity of this buffer, as the buffer may reserve some // * space for other purposes. // * // * @return the size in bytes of this buffer // * // * @since ostermillerutils 1.00.00 // */ // public int getAvailable(){ // synchronized (this){ // return available(); // } // } // // /** // * Get the number of bytes this buffer has free for // * writing. // *

// * Note that the number of bytes available plus // * the number of bytes free may not add up to the // * capacity of this buffer, as the buffer may reserve some // * space for other purposes. // * // * @return the available space in bytes of this buffer // * // * @since ostermillerutils 1.00.00 // */ // public int getSpaceLeft(){ // synchronized (this){ // return spaceLeft(); // } // } // // /** // * Get the capacity of this buffer. // *

// * Note that the number of bytes available plus // * the number of bytes free may not add up to the // * capacity of this buffer, as the buffer may reserve some // * space for other purposes. // * // * @return the size in bytes of this buffer // * // * @since ostermillerutils 1.00.00 // */ // public int getSize(){ // synchronized (this){ // return buffer.length; // } // } // // /** // * double the size of the buffer // * // * @since ostermillerutils 1.00.00 // */ // private void resize(){ // byte[] newBuffer = new byte[buffer.length * 2]; // int marked = marked(); // int available = available(); // if (markPosition <= writePosition){ // // any space between the mark and // // the first write needs to be saved. // // In this case it is all in one piece. // int length = writePosition - markPosition; // System.arraycopy(buffer, markPosition, newBuffer, 0, length); // } else { // int length1 = buffer.length - markPosition; // System.arraycopy(buffer, markPosition, newBuffer, 0, length1); // int length2 = writePosition; // System.arraycopy(buffer, 0, newBuffer, length1, length2); // } // buffer = newBuffer; // markPosition = 0; // readPosition = marked; // writePosition = marked + available; // } // // /** // * Space available in the buffer which can be written. // * // * @since ostermillerutils 1.00.00 // */ // private int spaceLeft(){ // if (writePosition < markPosition){ // // any space between the first write and // // the mark except one byte is available. // // In this case it is all in one piece. // return (markPosition - writePosition - 1); // } // // space at the beginning and end. // return ((buffer.length - 1) - (writePosition - markPosition)); // } // // /** // * Bytes available for reading. // * // * @since ostermillerutils 1.00.00 // */ // private int available(){ // if (readPosition <= writePosition){ // // any space between the first read and // // the first write is available. In this case i // // is all in one piece. // return (writePosition - readPosition); // } // // space at the beginning and end. // return (buffer.length - (readPosition - writePosition)); // } // // /** // * Bytes saved for supporting marks. // * // * @since ostermillerutils 1.00.00 // */ // private int marked(){ // if (markPosition <= readPosition){ // // any space between the markPosition and // // the first write is marked. In this case i // // is all in one piece. // return (readPosition - markPosition); // } // // space at the beginning and end. // return (buffer.length - (markPosition - readPosition)); // } // // /** // * If we have passed the markSize reset the // * mark so that the space can be used. // * // * @since ostermillerutils 1.00.00 // */ // private void ensureMark(){ // if (marked() >= markSize){ // markPosition = readPosition; // markSize = 0; // } // } // // /** // * Create a new buffer with a default capacity. // * Writing to a full buffer will block until space // * is available rather than throw an exception. // * // * @since ostermillerutils 1.00.00 // */ // public CircularByteBuffer(){ // this (DEFAULT_SIZE, true); // } // // /** // * Create a new buffer with given capacity. // * Writing to a full buffer will block until space // * is available rather than throw an exception. // *

// * Note that the buffer may reserve some bytes for // * special purposes and capacity number of bytes may // * not be able to be written to the buffer. // *

// * Note that if the buffer is of INFINITE_SIZE it will // * neither block or throw exceptions, but rather grow // * without bound. // * // * @param size desired capacity of the buffer in bytes or CircularByteBuffer.INFINITE_SIZE. // * // * @since ostermillerutils 1.00.00 // */ // public CircularByteBuffer(int size){ // this (size, true); // } // // /** // * Create a new buffer with a default capacity and // * given blocking behavior. // * // * @param blockingWrite true writing to a full buffer should block // * until space is available, false if an exception should // * be thrown instead. // * // * @since ostermillerutils 1.00.00 // */ // public CircularByteBuffer(boolean blockingWrite){ // this (DEFAULT_SIZE, blockingWrite); // } // // /** // * Create a new buffer with the given capacity and // * blocking behavior. // *

// * Note that the buffer may reserve some bytes for // * special purposes and capacity number of bytes may // * not be able to be written to the buffer. // *

// * Note that if the buffer is of INFINITE_SIZE it will // * neither block or throw exceptions, but rather grow // * without bound. // * // * @param size desired capacity of the buffer in bytes or CircularByteBuffer.INFINITE_SIZE. // * @param blockingWrite true writing to a full buffer should block // * until space is available, false if an exception should // * be thrown instead. // * // * @since ostermillerutils 1.00.00 // */ // public CircularByteBuffer(int size, boolean blockingWrite){ // if (size == INFINITE_SIZE){ // buffer = new byte[DEFAULT_SIZE]; // infinite = true; // } else { // buffer = new byte[size]; // infinite = false; // } // this.blockingWrite = blockingWrite; // } // // /** // * Class for reading from a circular byte buffer. // * // * @since ostermillerutils 1.00.00 // */ // protected class CircularByteBufferInputStream extends InputStream { // // /** // * Returns the number of bytes that can be read (or skipped over) from this // * input stream without blocking by the next caller of a method for this input // * stream. The next caller might be the same thread or or another thread. // * // * @return the number of bytes that can be read from this input stream without blocking. // * @throws IOException if the stream is closed. // * // * @since ostermillerutils 1.00.00 // */ // @Override public int available() throws IOException { // synchronized (CircularByteBuffer.this){ // if (inputStreamClosed) throw new IOException("InputStream has been closed, it is not ready."); // return (CircularByteBuffer.this.available()); // } // } // // /** // * Close the stream. Once a stream has been closed, further read(), available(), // * mark(), or reset() invocations will throw an IOException. Closing a // * previously-closed stream, however, has no effect. // * // * @throws IOException never. // * // * @since ostermillerutils 1.00.00 // */ // @Override public void close() throws IOException { // synchronized (CircularByteBuffer.this){ // inputStreamClosed = true; // } // } // // /** // * Mark the present position in the stream. Subsequent calls to reset() will // * attempt to reposition the stream to this point. // *

// * The readAheadLimit must be less than the size of circular buffer, otherwise // * this method has no effect. // * // * @param readAheadLimit Limit on the number of bytes that may be read while // * still preserving the mark. After reading this many bytes, attempting to // * reset the stream will fail. // * // * @since ostermillerutils 1.00.00 // */ // @Override public void mark(int readAheadLimit) { // synchronized (CircularByteBuffer.this){ // //if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot mark a closed InputStream."); // if (buffer.length - 1 > readAheadLimit) { // markSize = readAheadLimit; // markPosition = readPosition; // } // } // } // // /** // * Tell whether this stream supports the mark() operation. // * // * @return true, mark is supported. // * // * @since ostermillerutils 1.00.00 // */ // @Override public boolean markSupported() { // return true; // } // // /** // * Read a single byte. // * This method will block until a byte is available, an I/O error occurs, // * or the end of the stream is reached. // * // * @return The byte read, as an integer in the range 0 to 255 (0x00-0xff), // * or -1 if the end of the stream has been reached // * @throws IOException if the stream is closed. // * // * @since ostermillerutils 1.00.00 // */ // @Override public int read() throws IOException { // while (true){ // synchronized (CircularByteBuffer.this){ // if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream."); // int available = CircularByteBuffer.this.available(); // if (available > 0){ // int result = buffer[readPosition] & 0xff; // readPosition++; // if (readPosition == buffer.length){ // readPosition = 0; // } // ensureMark(); // return result; // } else if (outputStreamClosed){ // return -1; // } // } // try { // Thread.sleep(100); // } catch(Exception x){ // throw new IOException("Blocking read operation interrupted."); // } // } // } // // /** // * Read bytes into an array. // * This method will block until some input is available, // * an I/O error occurs, or the end of the stream is reached. // * // * @param cbuf Destination buffer. // * @return The number of bytes read, or -1 if the end of // * the stream has been reached // * @throws IOException if the stream is closed. // * // * @since ostermillerutils 1.00.00 // */ // @Override public int read(byte[] cbuf) throws IOException { // return read(cbuf, 0, cbuf.length); // } // // /** // * Read bytes into a portion of an array. // * This method will block until some input is available, // * an I/O error occurs, or the end of the stream is reached. // * // * @param cbuf 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 // * @throws IOException if the stream is closed. // * // * @since ostermillerutils 1.00.00 // */ // @Override public int read(byte[] cbuf, int off, int len) throws IOException { // while (true){ // synchronized (CircularByteBuffer.this){ // if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream."); // int available = CircularByteBuffer.this.available(); // if (available > 0){ // int length = Math.min(len, available); // int firstLen = Math.min(length, buffer.length - readPosition); // int secondLen = length - firstLen; // System.arraycopy(buffer, readPosition, cbuf, off, firstLen); // if (secondLen > 0){ // System.arraycopy(buffer, 0, cbuf, off+firstLen, secondLen); // readPosition = secondLen; // } else { // readPosition += length; // } // if (readPosition == buffer.length) { // readPosition = 0; // } // ensureMark(); // return length; // } else if (outputStreamClosed){ // return -1; // } // } // try { // Thread.sleep(100); // } catch(Exception x){ // throw new IOException("Blocking read operation interrupted."); // } // } // } // // /** // * Reset the stream. // * If the stream has been marked, then attempt to reposition i // * at the mark. If the stream has not been marked, or more bytes // * than the readAheadLimit have been read, this method has no effect. // * // * @throws IOException if the stream is closed. // * // * @since ostermillerutils 1.00.00 // */ // @Override public void reset() throws IOException { // synchronized (CircularByteBuffer.this){ // if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot reset a closed InputStream."); // readPosition = markPosition; // } // } // // /** // * Skip bytes. // * This method will block until some bytes are available, // * an I/O error occurs, or the end of the stream is reached. // * // * @param n The number of bytes to skip // * @return The number of bytes actually skipped // * @throws IllegalArgumentException if n is negative. // * @throws IOException if the stream is closed. // * // * @since ostermillerutils 1.00.00 // */ // @Override public long skip(long n) throws IOException, IllegalArgumentException { // while (true){ // synchronized (CircularByteBuffer.this){ // if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot skip bytes on a closed InputStream."); // int available = CircularByteBuffer.this.available(); // if (available > 0){ // int length = Math.min((int)n, available); // int firstLen = Math.min(length, buffer.length - readPosition); // int secondLen = length - firstLen; // if (secondLen > 0){ // readPosition = secondLen; // } else { // readPosition += length; // } // if (readPosition == buffer.length) { // readPosition = 0; // } // ensureMark(); // return length; // } else if (outputStreamClosed){ // return 0; // } // } // try { // Thread.sleep(100); // } catch(Exception x){ // throw new IOException("Blocking read operation interrupted."); // } // } // } // } // // /** // * Class for writing to a circular byte buffer. // * If the buffer is full, the writes will either block // * until there is some space available or throw an IOException // * based on the CircularByteBuffer's preference. // * // * @since ostermillerutils 1.00.00 // */ // protected class CircularByteBufferOutputStream extends OutputStream { // // /** // * Close the stream, flushing it first. // * This will cause the InputStream associated with this circular buffer // * to read its last bytes once it empties the buffer. // * Once a stream has been closed, further write() or flush() invocations // * will cause an IOException to be thrown. Closing a previously-closed stream, // * however, has no effect. // * // * @throws IOException never. // * // * @since ostermillerutils 1.00.00 // */ // @Override public void close() throws IOException { // synchronized (CircularByteBuffer.this){ // if (!outputStreamClosed){ // flush(); // } // outputStreamClosed = true; // } // } // // /** // * Flush the stream. // * // * @throws IOException if the stream is closed. // * // * @since ostermillerutils 1.00.00 // */ // @Override public void flush() throws IOException { // if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot flush a closed OutputStream."); // if (inputStreamClosed) throw new IOException("Buffer closed by inputStream; cannot flush."); // // this method needs to do nothing // } // // /** // * Write an array of bytes. // * If the buffer allows blocking writes, this method will block until // * all the data has been written rather than throw an IOException. // * // * @param cbuf Array of bytes to be written // * @throws BufferOverflowException if buffer does not allow blocking writes // * and the buffer is full. If the exception is thrown, no data // * will have been written since the buffer was set to be non-blocking. // * @throws IOException if the stream is closed, or the write is interrupted. // * // * @since ostermillerutils 1.00.00 // */ // @Override public void write(byte[] cbuf) throws IOException { // write(cbuf, 0, cbuf.length); // } // // /** // * Write a portion of an array of bytes. // * If the buffer allows blocking writes, this method will block until // * all the data has been written rather than throw an IOException. // * // * @param cbuf Array of bytes // * @param off Offset from which to start writing bytes // * @param len - Number of bytes to write // * @throws BufferOverflowException if buffer does not allow blocking writes // * and the buffer is full. If the exception is thrown, no data // * will have been written since the buffer was set to be non-blocking. // * @throws IOException if the stream is closed, or the write is interrupted. // * // * @since ostermillerutils 1.00.00 // */ // @Override public void write(byte[] cbuf, int off, int len) throws IOException { // while (len > 0){ // synchronized (CircularByteBuffer.this){ // if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot write to a closed OutputStream."); // if (inputStreamClosed) throw new IOException("Buffer closed by InputStream; cannot write to a closed buffer."); // int spaceLeft = spaceLeft(); // while (infinite && spaceLeft < len){ // resize(); // spaceLeft = spaceLeft(); // } // if (!blockingWrite && spaceLeft < len) throw new BufferOverflowException(); // int realLen = Math.min(len, spaceLeft); // int firstLen = Math.min(realLen, buffer.length - writePosition); // int secondLen = Math.min(realLen - firstLen, buffer.length - markPosition - 1); // int written = firstLen + secondLen; // if (firstLen > 0){ // System.arraycopy(cbuf, off, buffer, writePosition, firstLen); // } // if (secondLen > 0){ // System.arraycopy(cbuf, off+firstLen, buffer, 0, secondLen); // writePosition = secondLen; // } else { // writePosition += written; // } // if (writePosition == buffer.length) { // writePosition = 0; // } // off += written; // len -= written; // } // if (len > 0){ // try { // Thread.sleep(100); // } catch(Exception x){ // throw new IOException("Waiting for available space in buffer interrupted."); // } // } // } // } // // /** // * Write a single byte. // * The byte to be written is contained in the 8 low-order bits of the // * given integer value; the 24 high-order bits are ignored. // * If the buffer allows blocking writes, this method will block until // * all the data has been written rather than throw an IOException. // * // * @param c number of bytes to be written // * @throws BufferOverflowException if buffer does not allow blocking writes // * and the buffer is full. // * @throws IOException if the stream is closed, or the write is interrupted. // * // * @since ostermillerutils 1.00.00 // */ // @Override public void write(int c) throws IOException { // boolean written = false; // while (!written){ // synchronized (CircularByteBuffer.this){ // if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot write to a closed OutputStream."); // if (inputStreamClosed) throw new IOException("Buffer closed by InputStream; cannot write to a closed buffer."); // int spaceLeft = spaceLeft(); // while (infinite && spaceLeft < 1){ // resize(); // spaceLeft = spaceLeft(); // } // if (!blockingWrite && spaceLeft < 1) throw new BufferOverflowException(); // if (spaceLeft > 0){ // buffer[writePosition] = (byte)(c & 0xff); // writePosition++; // if (writePosition == buffer.length) { // writePosition = 0; // } // written = true; // } // } // if (!written){ // try { // Thread.sleep(100); // } catch(Exception x){ // throw new IOException("Waiting for available space in buffer interrupted."); // } // } // } // } // } //}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy