I'm committing this on behalf of Ingo. He implemented a caching
mechanism in InputStreamReader to avoid allocation of new byte[] on
every call of read(byte[],int,int).
2006-08-21 Ingo Proetel <[EMAIL PROTECTED]>
* java/io/InputStreamReader.java
(bytesCache): New field.
(cacheLock): New field.
(read(byte[],int,int): Avoid allocations of new byte
array on every call and reuse cached byte array if possible.
/Roman
Index: java/io/InputStreamReader.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/io/InputStreamReader.java,v
retrieving revision 1.29
diff -u -1 -2 -r1.29 InputStreamReader.java
--- java/io/InputStreamReader.java 12 Feb 2006 09:36:21 -0000 1.29
+++ java/io/InputStreamReader.java 21 Aug 2006 10:00:34 -0000
@@ -126,24 +126,34 @@
* java.io canonical name of the encoding.
*/
private String encoding;
/**
* We might decode to a 2-char UTF-16 surrogate, which won't fit in the
* output buffer. In this case we need to save the surrogate char.
*/
private char savedSurrogate;
private boolean hasSavedSurrogate = false;
/**
+ * A byte array to be reused in read(byte[], int, int).
+ */
+ private byte[] bytesCache;
+
+ /**
+ * Locks the bytesCache above in read(byte[], int, int).
+ */
+ private Object cacheLock = new Object();
+
+ /**
* This method initializes a new instance of <code>InputStreamReader</code>
* to read from the specified stream using the default encoding.
*
* @param in The <code>InputStream</code> to read from
*/
public InputStreamReader(InputStream in)
{
if (in == null)
throw new NullPointerException();
this.in = in;
try
{
@@ -346,27 +356,37 @@
* @param length The requested number of characters to read.
*
* @return The actual number of characters read, or -1 if end of stream.
*
* @exception IOException If an error occurs
*/
public int read(char[] buf, int offset, int length) throws IOException
{
if (in == null)
throw new IOException("Reader has been closed");
if (isDone)
return -1;
- if(decoder != null){
- int totalBytes = (int)((double)length * maxBytesPerChar);
- byte[] bytes = new byte[totalBytes];
+ if(decoder != null)
+ {
+ int totalBytes = (int)((double) length * maxBytesPerChar);
+ byte[] bytes;
+ // Fetch cached bytes array if available and big enough.
+ synchronized(cacheLock)
+ {
+ bytes = bytesCache;
+ if (bytes == null || bytes.length < totalBytes)
+ bytes = new byte[totalBytes];
+ else
+ bytesCache = null;
+ }
int remaining = 0;
if(byteBuffer != null)
{
remaining = byteBuffer.remaining();
byteBuffer.get(bytes, 0, remaining);
}
int read;
if(totalBytes - remaining > 0)
{
read = in.read(bytes, remaining, totalBytes - remaining);
if(read == -1){
@@ -401,30 +421,58 @@
isDone = false;
}
}
if(byteBuffer.hasRemaining()) {
byteBuffer.compact();
byteBuffer.flip();
isDone = false;
} else
byteBuffer = null;
read = cb.position() - startPos;
- return (read <= 0) ? -1 : read;
- } else {
- byte[] bytes = new byte[length];
+
+ // Put cached bytes array back if we are finished and the cache
+ // is null or smaller than the used bytes array.
+ synchronized (cacheLock)
+ {
+ if (byteBuffer == null
+ && (bytesCache == null || bytesCache.length < bytes.length))
+ bytesCache = bytes;
+ }
+ return (read <= 0) ? -1 : read;
+ }
+ else
+ {
+ byte[] bytes;
+ // Fetch cached bytes array if available and big enough.
+ synchronized (cacheLock)
+ {
+ bytes = bytesCache;
+ if (bytes == null || length < bytes.length)
+ bytes = new byte[length];
+ else
+ bytesCache = null;
+ }
+
int read = in.read(bytes);
for(int i=0;i<read;i++)
buf[offset+i] = (char)(bytes[i]&0xFF);
+
+ // Put back byte array into cache if appropriate.
+ synchronized (cacheLock)
+ {
+ if (bytesCache == null || bytesCache.length < bytes.length)
+ bytesCache = bytes;
+ }
return read;
}
}
/**
* Reads an char from the input stream and returns it
* as an int in the range of 0-65535. This method also will return -1 if
* the end of the stream has been reached.
* <p>
* This method will block until the char can be read.
*
* @return The char read or -1 if end of stream