< prev index next >

src/java.base/share/classes/sun/nio/cs/StreamEncoder.java

Print this page
*** 36,15 ***
  import java.nio.charset.CharsetEncoder;
  import java.nio.charset.CoderResult;
  import java.nio.charset.CodingErrorAction;
  import java.nio.charset.IllegalCharsetNameException;
  import java.nio.charset.UnsupportedCharsetException;
  
! public class StreamEncoder extends Writer
- {
  
!     private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
  
      private volatile boolean closed;
  
      private void ensureOpen() throws IOException {
          if (closed)
--- 36,16 ---
  import java.nio.charset.CharsetEncoder;
  import java.nio.charset.CoderResult;
  import java.nio.charset.CodingErrorAction;
  import java.nio.charset.IllegalCharsetNameException;
  import java.nio.charset.UnsupportedCharsetException;
+ import jdk.internal.misc.InternalLock;
  
! public final class StreamEncoder extends Writer {
  
!     private static final int INITIAL_BYTE_BUFFER_CAPACITY = 512;
+     private static final int MAX_BYTE_BUFFER_CAPACITY = 8192;
  
      private volatile boolean closed;
  
      private void ensureOpen() throws IOException {
          if (closed)

*** 104,35 ***
              return encodingName();
          return null;
      }
  
      public void flushBuffer() throws IOException {
!         synchronized (lock) {
!             if (isOpen())
!                 implFlushBuffer();
!             else
!                 throw new IOException("Stream closed");
          }
      }
  
      public void write(int c) throws IOException {
          char[] cbuf = new char[1];
          cbuf[0] = (char) c;
          write(cbuf, 0, 1);
      }
  
      public void write(char[] cbuf, int off, int len) throws IOException {
!         synchronized (lock) {
!             ensureOpen();
!             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
!                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
!                 throw new IndexOutOfBoundsException();
!             } else if (len == 0) {
-                 return;
              }
!             implWrite(cbuf, off, len);
          }
      }
  
      public void write(String str, int off, int len) throws IOException {
          /* Check the len before creating a char buffer */
          if (len < 0)
--- 105,61 ---
              return encodingName();
          return null;
      }
  
      public void flushBuffer() throws IOException {
!         if (lock instanceof InternalLock locker) {
!             locker.lock();
!             try {
!                 lockedFlushBuffer();
!             } finally {
+                 locker.unlock();
+             }
+         } else {
+             synchronized (super.lock) {
+                 lockedFlushBuffer();
+             }
          }
      }
  
+     private void lockedFlushBuffer() throws IOException {
+         if (isOpen())
+             implFlushBuffer();
+         else
+             throw new IOException("Stream closed");
+     }
+ 
      public void write(int c) throws IOException {
          char[] cbuf = new char[1];
          cbuf[0] = (char) c;
          write(cbuf, 0, 1);
      }
  
      public void write(char[] cbuf, int off, int len) throws IOException {
!         if (lock instanceof InternalLock locker) {
!             locker.lock();
!             try {
!                 lockedWrite(cbuf, off, len);
!             } finally {
!                 locker.unlock();
              }
!         } else {
+             synchronized (super.lock) {
+                 lockedWrite(cbuf, off, len);
+             }
+         }
+     }
+ 
+     private void lockedWrite(char[] cbuf, int off, int len) throws IOException {
+         ensureOpen();
+         if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
+             throw new IndexOutOfBoundsException();
+         } else if (len == 0) {
+             return;
          }
+         implWrite(cbuf, off, len);
      }
  
      public void write(String str, int off, int len) throws IOException {
          /* Check the len before creating a char buffer */
          if (len < 0)

*** 143,48 ***
      }
  
      public void write(CharBuffer cb) throws IOException {
          int position = cb.position();
          try {
!             synchronized (lock) {
!                 ensureOpen();
!                 implWrite(cb);
              }
          } finally {
              cb.position(position);
          }
      }
  
      public void flush() throws IOException {
!         synchronized (lock) {
!             ensureOpen();
!             implFlush();
          }
      }
  
      public void close() throws IOException {
!         synchronized (lock) {
!             if (closed)
-                 return;
              try {
!                 implClose();
              } finally {
!                 closed = true;
              }
          }
      }
  
      private boolean isOpen() {
          return !closed;
      }
  
  
      // -- Charset-based stream encoder impl --
  
      private final Charset cs;
      private final CharsetEncoder encoder;
!     private final ByteBuffer bb;
  
      // Exactly one of these is non-null
      private final OutputStream out;
      private final WritableByteChannel ch;
  
--- 170,88 ---
      }
  
      public void write(CharBuffer cb) throws IOException {
          int position = cb.position();
          try {
!             if (lock instanceof InternalLock locker) {
!                 locker.lock();
!                 try {
+                     lockedWrite(cb);
+                 } finally {
+                     locker.unlock();
+                 }
+             } else {
+                 synchronized (super.lock) {
+                     lockedWrite(cb);
+                 }
              }
          } finally {
              cb.position(position);
          }
      }
  
+     private void lockedWrite(CharBuffer cb) throws IOException {
+         ensureOpen();
+         implWrite(cb);
+     }
+ 
      public void flush() throws IOException {
!         if (lock instanceof InternalLock locker) {
!             locker.lock();
!             try {
+                 lockedFlush();
+             } finally {
+                 locker.unlock();
+             }
+         } else {
+             synchronized (lock) {
+                 lockedFlush();
+             }
          }
      }
  
+     private void lockedFlush() throws IOException {
+         ensureOpen();
+         implFlush();
+     }
+ 
      public void close() throws IOException {
!         if (lock instanceof InternalLock locker) {
!             locker.lock();
              try {
!                 lockedClose();
              } finally {
!                 locker.unlock();
+             }
+         } else {
+             synchronized (lock) {
+                 lockedClose();
              }
          }
      }
  
+     private void lockedClose() throws IOException {
+         if (closed)
+             return;
+         try {
+             implClose();
+         } finally {
+             closed = true;
+         }
+     }
+ 
      private boolean isOpen() {
          return !closed;
      }
  
  
      // -- Charset-based stream encoder impl --
  
      private final Charset cs;
      private final CharsetEncoder encoder;
!     private ByteBuffer bb;
+     private final int maxBufferCapacity;
  
      // Exactly one of these is non-null
      private final OutputStream out;
      private final WritableByteChannel ch;
  

*** 204,21 ***
          super(lock);
          this.out = out;
          this.ch = null;
          this.cs = enc.charset();
          this.encoder = enc;
!         this.bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
      }
  
      private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
          this.out = null;
          this.ch = ch;
          this.cs = enc.charset();
          this.encoder = enc;
!         this.bb = ByteBuffer.allocate(mbc < 0
!                                   ? DEFAULT_BYTE_BUFFER_SIZE
!                                   : mbc);
      }
  
      private void writeBytes() throws IOException {
          bb.flip();
          int lim = bb.limit();
--- 271,28 ---
          super(lock);
          this.out = out;
          this.ch = null;
          this.cs = enc.charset();
          this.encoder = enc;
! 
+         this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
+         this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
      }
  
      private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
          this.out = null;
          this.ch = ch;
          this.cs = enc.charset();
          this.encoder = enc;
! 
!         if (mbc > 0) {
!             this.bb = ByteBuffer.allocate(mbc);
+             this.maxBufferCapacity = mbc;
+         } else {
+             this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
+             this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
+         }
      }
  
      private void writeBytes() throws IOException {
          bb.flip();
          int lim = bb.limit();

*** 287,10 ***
--- 361,12 ---
      {
          if (haveLeftoverChar) {
              flushLeftoverChar(cb, false);
          }
  
+         growByteBufferIfNeeded(cb.remaining());
+ 
          while (cb.hasRemaining()) {
              CoderResult cr = encoder.encode(cb, bb, false);
              if (cr.isUnderflow()) {
                  assert (cb.remaining() <= 1) : cb.remaining();
                  if (cb.remaining() == 1) {

*** 306,10 ***
--- 382,25 ---
              }
              cr.throwException();
          }
      }
  
+     /**
+      * Grows bb to a capacity to allow len characters be encoded.
+      */
+     void growByteBufferIfNeeded(int len) throws IOException {
+         int cap = bb.capacity();
+         if (cap < maxBufferCapacity) {
+             int maxBytes = len * Math.round(encoder.maxBytesPerChar());
+             int newCap = Math.min(maxBytes, maxBufferCapacity);
+             if (newCap > cap) {
+                 implFlushBuffer();
+                 bb = ByteBuffer.allocate(newCap);
+             }
+         }
+     }
+ 
      void implFlushBuffer() throws IOException {
          if (bb.position() > 0) {
              writeBytes();
          }
      }
< prev index next >