Clover coverage report - PLT Utilities Test Coverage (plt-20120304-r5436)
Coverage timestamp: Sat Mar 3 2012 22:01:56 CST
file stats: LOC: 304   Methods: 30
NCLOC: 197   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ExpandingCharBuffer.java 0% 0% 0% 0%
coverage
 1    /*BEGIN_COPYRIGHT_BLOCK*
 2   
 3    PLT Utilities BSD License
 4   
 5    Copyright (c) 2007-2010 JavaPLT group at Rice University
 6    All rights reserved.
 7   
 8    Developed by: Java Programming Languages Team
 9    Rice University
 10    http://www.cs.rice.edu/~javaplt/
 11   
 12    Redistribution and use in source and binary forms, with or without modification, are permitted
 13    provided that the following conditions are met:
 14   
 15    - Redistributions of source code must retain the above copyright notice, this list of conditions
 16    and the following disclaimer.
 17    - Redistributions in binary form must reproduce the above copyright notice, this list of
 18    conditions and the following disclaimer in the documentation and/or other materials provided
 19    with the distribution.
 20    - Neither the name of the JavaPLT group, Rice University, nor the names of the library's
 21    contributors may be used to endorse or promote products derived from this software without
 22    specific prior written permission.
 23   
 24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 25    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 26    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND
 27    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 28    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 29    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 30    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 31    OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 32   
 33    *END_COPYRIGHT_BLOCK*/
 34   
 35    package edu.rice.cs.plt.io;
 36   
 37    import java.io.Reader;
 38    import java.io.Writer;
 39    import java.io.IOException;
 40    import java.io.InterruptedIOException;
 41   
 42    /**
 43    * <p>A character buffer of arbitrary size to be used with Readers and Writers. The
 44    * buffer is a FIFO queue of characters. It provides a {@link DirectWriter} for adding
 45    * characters to the end and a {@link DirectReader} for pulling characters from the front.
 46    * This allows behavior similar to that of a {@link java.io.PipedWriter} and {@link java.io.PipedReader},
 47    * but without any assumptions about access from different threads, without any restrictions on
 48    * the size of the buffer (so writing will never block), and <em>with</em> support for multiple
 49    * readers or writers connected to the same source. (If access is restricted to a single thread,
 50    * care must be taken to never read when the buffer is empty.)</p>
 51    *
 52    * <p>While an attempt at thread safety has been made, at least one exception is evident:
 53    * if the result of {@code writer()} attempts to write from the result of {@code reader()},
 54    * and the reader blocks, a write from another thread will be necessary to unblock the reader.
 55    * At that point, the original {@code write()} will have already instructed the reader to copy
 56    * its data into an incorrect location. In general, connecting a reader and a writer from the same
 57    * buffer is not recommended.</p>
 58    */
 59    public class ExpandingCharBuffer extends ExpandingBuffer<char[]> {
 60   
 61    /** True iff {@link #end()} has been invoked */
 62    private boolean _eof;
 63   
 64  0 public ExpandingCharBuffer() {
 65  0 super();
 66  0 _eof = false;
 67    }
 68   
 69    /**
 70    * Place an "end of file" at the end of the buffer. No further writes will be allowed,
 71    * and when the buffer is emptied, reads will see an end of file.
 72    */
 73  0 public synchronized void end() { _eof = true; notifyAll(); }
 74   
 75  0 public synchronized boolean isEnded() { return _eof; }
 76   
 77  0 protected char[] allocateBuffer(int size) { return new char[size]; }
 78   
 79    /**
 80    * Create a writer providing write access to the buffer. Invocations of {@code write} will atomically
 81    * add characters directly to the buffer. {@link Writer#close()} will have no effect.
 82    */
 83  0 public DirectWriter writer() {
 84  0 return new DirectWriter() {
 85  0 @Override public void close() {}
 86   
 87  0 @Override public void flush() {}
 88   
 89  0 @Override public void write(int c) throws IOException {
 90  0 synchronized (ExpandingCharBuffer.this) {
 91  0 if (_eof) { throw new IOException("Buffer has been ended"); }
 92  0 allocate();
 93  0 lastBuffer()[lastIndex()] = (char) c;
 94  0 recordWrite(1);
 95  0 ExpandingCharBuffer.this.notifyAll();
 96    }
 97    }
 98   
 99  0 @Override public void write(char[] cbuf) throws IOException { write(cbuf, 0, cbuf.length); }
 100   
 101  0 @Override public void write(char[] cbuf, int off, int chars) throws IOException {
 102  0 if (chars == 0) { return; }
 103  0 synchronized (ExpandingCharBuffer.this) {
 104  0 if (_eof) { throw new IOException("Buffer has been ended"); }
 105  0 while (chars > 0) {
 106  0 int space = allocate();
 107  0 int toWrite = (space > chars) ? chars : space;
 108  0 System.arraycopy(cbuf, off, lastBuffer(), lastIndex(), toWrite);
 109  0 recordWrite(toWrite);
 110  0 chars -= toWrite;
 111    }
 112  0 ExpandingCharBuffer.this.notifyAll();
 113    }
 114    }
 115   
 116  0 @Override public int write(Reader r, int chars) throws IOException {
 117  0 if (chars == 0) { return 0; }
 118  0 synchronized (ExpandingCharBuffer.this) {
 119  0 if (_eof) { throw new IOException("Buffer has been ended"); }
 120  0 int charsRead = 0;
 121  0 int totalRead = 0;
 122  0 while (chars > 0 && charsRead >= 0) {
 123  0 int space = allocate();
 124  0 charsRead = r.read(lastBuffer(), lastIndex(), space);
 125  0 if (charsRead >= 0) {
 126  0 recordWrite(charsRead);
 127  0 chars -= charsRead;
 128  0 totalRead += charsRead;
 129    }
 130    }
 131  0 ExpandingCharBuffer.this.notifyAll();
 132  0 if (totalRead == 0) { return -1; }
 133  0 else { return totalRead; }
 134    }
 135    }
 136   
 137  0 @Override public int write(Reader r, int chars, int bufferSize) throws IOException {
 138  0 return write(r, chars);
 139    }
 140   
 141  0 @Override public int write(Reader r, int chars, char[] buffer) throws IOException {
 142  0 return write(r, chars);
 143    }
 144   
 145  0 @Override public int writeAll(Reader r) throws IOException {
 146  0 synchronized (ExpandingCharBuffer.this) {
 147  0 int charsRead;
 148  0 long totalRead = 0;
 149  0 do {
 150  0 int space = allocate();
 151  0 charsRead = r.read(lastBuffer(), lastIndex(), space);
 152  0 if (charsRead >= 0) {
 153  0 recordWrite(charsRead);
 154  0 totalRead += charsRead;
 155    }
 156  0 } while (charsRead >= 0);
 157  0 ExpandingCharBuffer.this.notifyAll();
 158   
 159  0 if (totalRead == 0) { return -1; }
 160  0 else if (totalRead > Integer.MAX_VALUE) { return Integer.MAX_VALUE; }
 161  0 else { return (int) totalRead; }
 162    }
 163    }
 164   
 165  0 @Override public int writeAll(Reader r, int bufferSize) throws IOException {
 166  0 return writeAll(r);
 167    }
 168   
 169  0 @Override public int writeAll(Reader r, char[] buffer) throws IOException {
 170  0 return writeAll(r);
 171    }
 172   
 173    };
 174    }
 175   
 176   
 177    /**
 178    * Create a reader providing read access to the buffer. Invocations of {@code read} will atomically
 179    * remove characters from the buffer. {@link Reader#close()} will have no effect.
 180    */
 181  0 public DirectReader reader() {
 182  0 return new DirectReader() {
 183  0 @Override public void close() {}
 184   
 185  0 @Override public boolean ready() { return !isEmpty(); }
 186   
 187  0 @Override public int read() throws IOException {
 188  0 synchronized (ExpandingCharBuffer.this) {
 189  0 waitForInput();
 190  0 if (isEmpty()) { return -1; }
 191    else {
 192  0 char result = firstBuffer()[firstIndex()];
 193  0 recordRead(1);
 194  0 deallocate();
 195  0 return result;
 196    }
 197    }
 198    }
 199   
 200  0 @Override public int read(char[] cbuf) throws IOException { return read(cbuf, 0, cbuf.length); }
 201   
 202  0 @Override public int read(char[] cbuf, int offset, int chars) throws IOException {
 203  0 if (chars <= 0) { return 0; }
 204  0 synchronized (ExpandingCharBuffer.this) {
 205  0 waitForInput();
 206  0 if (isEmpty()) { return -1; }
 207    else {
 208  0 int totalRead = 0;
 209  0 while (chars > 0 && !isEmpty()) {
 210  0 int inFirstBuffer = elementsInFirstBuffer();
 211  0 int toRead = (inFirstBuffer > chars) ? chars : inFirstBuffer;
 212  0 System.arraycopy(firstBuffer(), firstIndex(), cbuf, offset, toRead);
 213  0 recordRead(toRead);
 214  0 chars -= toRead;
 215  0 totalRead += toRead;
 216  0 deallocate();
 217    }
 218  0 return totalRead;
 219    }
 220    }
 221    }
 222   
 223  0 @Override public int read(Writer w, int chars) throws IOException {
 224  0 if (chars <= 0) { return 0; }
 225  0 synchronized (ExpandingCharBuffer.this) {
 226  0 waitForInput();
 227  0 if (isEmpty()) { return -1; }
 228    else {
 229  0 int totalRead = 0;
 230  0 while (chars > 0 && !isEmpty()) {
 231  0 int inFirstBuffer = elementsInFirstBuffer();
 232  0 int toRead = (inFirstBuffer > chars) ? chars : inFirstBuffer;
 233  0 w.write(firstBuffer(), firstIndex(), toRead);
 234  0 recordRead(toRead);
 235  0 chars -= toRead;
 236  0 totalRead += toRead;
 237  0 deallocate();
 238    }
 239  0 return totalRead;
 240    }
 241    }
 242    }
 243   
 244  0 @Override public int read(Writer w, int chars, int bufferSize) throws IOException {
 245  0 return read(w, chars);
 246    }
 247   
 248  0 @Override public int read(Writer w, int chars, char[] buffer) throws IOException {
 249  0 return read(w, chars);
 250    }
 251   
 252  0 @Override public int readAll(Writer w) throws IOException {
 253  0 synchronized (ExpandingCharBuffer.this) {
 254  0 long totalRead = 0;
 255  0 do {
 256  0 waitForInput();
 257  0 while (!isEmpty()) {
 258  0 int toRead = elementsInFirstBuffer();
 259  0 w.write(firstBuffer(), firstIndex(), toRead);
 260  0 recordRead(toRead);
 261  0 totalRead += toRead;
 262  0 deallocate();
 263    }
 264  0 } while (!_eof);
 265   
 266  0 if (totalRead == 0) { return -1; }
 267  0 else if (totalRead > Integer.MAX_VALUE) { return Integer.MAX_VALUE; }
 268  0 else { return (int) totalRead; }
 269    }
 270    }
 271   
 272  0 @Override public int readAll(Writer w, int bufferSize) throws IOException { return readAll(w); }
 273   
 274  0 @Override public int readAll(Writer w, char[] buffer) throws IOException { return readAll(w); }
 275   
 276  0 @Override public long skip(long chars) throws IOException {
 277  0 if (chars <= 0) { return 0; }
 278  0 synchronized (ExpandingCharBuffer.this) {
 279  0 waitForInput();
 280  0 long size = size();
 281  0 if (chars > size) { chars = size; }
 282  0 recordRead(chars);
 283  0 while (deallocate()) {}
 284  0 return chars;
 285    }
 286    }
 287   
 288    /**
 289    * Guarantees that either {@code !isEmpty()} or {@code _eof} (or both) holds. If
 290    * neither is true, the thread will wait until it becomes true. Assumes that calling code
 291    * is synchronized on the {@code ExpandingCharBuffer} object.
 292    * @throws InterruptedIOException If this thread is interrupted while waiting for input
 293    */
 294  0 private void waitForInput() throws InterruptedIOException {
 295  0 while (!_eof && isEmpty()) {
 296  0 try { ExpandingCharBuffer.this.wait(); }
 297  0 catch (InterruptedException e) { throw new InterruptedIOException(); }
 298    }
 299    }
 300   
 301    };
 302    }
 303   
 304    }