Reduce byte[] allocations in SerialInputStream and SerialOutputStream

* use a shared, re-usable buffer for single byte reads and writes
* implement read(byte[]) directly instead of delegating to
read(byte[], int, int), which makes an unnecessary copy.
* implement write(byte[]) directly instead of delegating to
write(byte[], int, int), which makes an unnecessary copy.
* avoid a corner case unnecessary copy in write(byte[], int, int)
This commit is contained in:
Kevin Herron 2017-04-30 06:47:38 -07:00
parent 46790676e6
commit 6edf6f9396
1 changed files with 46 additions and 17 deletions

View File

@ -27,12 +27,12 @@ package com.fazecast.jSerialComm;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Date; import java.util.Date;
@ -1022,6 +1022,11 @@ public final class SerialPort
// InputStream interface class // InputStream interface class
private final class SerialPortInputStream extends InputStream private final class SerialPortInputStream extends InputStream
{ {
// a shared, re-usable, single-byte scratch buffer to avoid allocating
// a new byte[] when reading a single byte. not thread safe, but neither
// SerialPort nor its Input/Output streams are to begin with.
private final byte[] singleByteBuffer = new byte[1];
public SerialPortInputStream() {} public SerialPortInputStream() {}
@Override @Override
@ -1036,23 +1041,30 @@ public final class SerialPort
@Override @Override
public final int read() throws IOException public final int read() throws IOException
{ {
byte[] buffer = new byte[1];
int bytesRead; int bytesRead;
while (isOpened) while (isOpened)
{ {
bytesRead = readBytes(portHandle, buffer, 1l); bytesRead = readBytes(portHandle, singleByteBuffer, 1L);
if (bytesRead > 0) if (bytesRead > 0)
return ((int)buffer[0] & 0x000000FF); return ((int) singleByteBuffer[0] & 0xFF);
try { Thread.sleep(1); } catch (Exception e) {}
sleep1();
} }
throw new IOException("This port appears to have been shutdown or disconnected."); throw new IOException("This port appears to have been shutdown or disconnected.");
} }
@Override @Override
public final int read(byte[] b) throws IOException public final int read(byte[] b) throws IOException
{ {
return read(b, 0, b.length); if (!isOpened)
throw new IOException("This port appears to have been shutdown or disconnected.");
if (b.length == 0)
return 0;
return readBytes(portHandle, b, b.length);
} }
@Override @Override
@ -1085,6 +1097,11 @@ public final class SerialPort
// OutputStream interface class // OutputStream interface class
private final class SerialPortOutputStream extends OutputStream private final class SerialPortOutputStream extends OutputStream
{ {
// a shared, re-usable, single-byte scratch buffer to avoid allocating
// a new byte[] when writing a single byte. not thread safe, but neither
// SerialPort nor its Input/Output streams are to begin with.
private final byte[] singleByteBuffer = new byte[1];
public SerialPortOutputStream() {} public SerialPortOutputStream() {}
@Override @Override
@ -1093,28 +1110,40 @@ public final class SerialPort
if (!isOpened) if (!isOpened)
throw new IOException("This port appears to have been shutdown or disconnected."); throw new IOException("This port appears to have been shutdown or disconnected.");
byte[] buffer = new byte[1]; singleByteBuffer[0] = (byte) (b & 0xFF);
buffer[0] = (byte)(b & 0x000000FF);
if (writeBytes(portHandle, buffer, 1l) < 0) if (writeBytes(portHandle, singleByteBuffer, 1L) < 0)
throw new IOException("This port appears to have been shutdown or disconnected."); throw new IOException("This port appears to have been shutdown or disconnected.");
} }
@Override @Override
public final void write(byte[] b) throws IOException public final void write(byte[] b) throws IOException
{ {
write(b, 0, b.length); if (!isOpened)
throw new IOException("This port appears to have been shutdown or disconnected.");
if (writeBytes(portHandle, b, b.length) < 0)
throw new IOException("This port appears to have been shutdown or disconnected.");
} }
@Override @Override
public final void write(byte[] b, int off, int len) throws IOException public final void write(byte[] b, int off, int len) throws IOException
{ {
if (!isOpened) if (off == 0 && len == b.length)
throw new IOException("This port appears to have been shutdown or disconnected."); {
write(b);
}
else
{
byte[] buffer = new byte[len]; byte[] buffer = new byte[len];
System.arraycopy(b, off, buffer, 0, len); System.arraycopy(b, off, buffer, 0, len);
if (writeBytes(portHandle, buffer, len) < 0) write(buffer);
throw new IOException("This port appears to have been shutdown or disconnected.");
} }
} }
} }
private static void sleep1() {
try { Thread.sleep(1); } catch (Exception ignored) {}
}
}