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.DataOutputStream;
import java.io.InputStreamReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Date;
@ -1022,6 +1022,11 @@ public final class SerialPort
// InputStream interface class
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() {}
@Override
@ -1036,23 +1041,30 @@ public final class SerialPort
@Override
public final int read() throws IOException
{
byte[] buffer = new byte[1];
int bytesRead;
while (isOpened)
{
bytesRead = readBytes(portHandle, buffer, 1l);
bytesRead = readBytes(portHandle, singleByteBuffer, 1L);
if (bytesRead > 0)
return ((int)buffer[0] & 0x000000FF);
try { Thread.sleep(1); } catch (Exception e) {}
return ((int) singleByteBuffer[0] & 0xFF);
sleep1();
}
throw new IOException("This port appears to have been shutdown or disconnected.");
}
@Override
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
@ -1085,6 +1097,11 @@ public final class SerialPort
// OutputStream interface class
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() {}
@Override
@ -1093,28 +1110,40 @@ public final class SerialPort
if (!isOpened)
throw new IOException("This port appears to have been shutdown or disconnected.");
byte[] buffer = new byte[1];
buffer[0] = (byte)(b & 0x000000FF);
if (writeBytes(portHandle, buffer, 1l) < 0)
singleByteBuffer[0] = (byte) (b & 0xFF);
if (writeBytes(portHandle, singleByteBuffer, 1L) < 0)
throw new IOException("This port appears to have been shutdown or disconnected.");
}
@Override
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
public final void write(byte[] b, int off, int len) throws IOException
{
if (!isOpened)
throw new IOException("This port appears to have been shutdown or disconnected.");
byte[] buffer = new byte[len];
System.arraycopy(b, off, buffer, 0, len);
if (writeBytes(portHandle, buffer, len) < 0)
throw new IOException("This port appears to have been shutdown or disconnected.");
if (off == 0 && len == b.length)
{
write(b);
}
else
{
byte[] buffer = new byte[len];
System.arraycopy(b, off, buffer, 0, len);
write(buffer);
}
}
}
private static void sleep1() {
try { Thread.sleep(1); } catch (Exception ignored) {}
}
}