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

Reply via email to