Skip to content

Commit

Permalink
Reimpl byte[] stream without synchronization
Browse files Browse the repository at this point in the history
The byte[] output stream used here extended ByteArrayOutputStream
from the JDK, which sychronizes all mutation operations (like
writes). Since this is only going to be used once within a given
call stack, it needs no synchronization.

This change more than triples the performance of a benchmark of
dumping an array of empty arrays and should increase performance
of all dump forms.
  • Loading branch information
headius committed Jan 15, 2025
1 parent b11e4f2 commit a128bfa
Showing 1 changed file with 44 additions and 4 deletions.
48 changes: 44 additions & 4 deletions java/src/json/ext/ByteListDirectOutputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,54 @@
import org.jcodings.Encoding;
import org.jruby.util.ByteList;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;

public class ByteListDirectOutputStream extends OutputStream {
private byte[] buffer;
private int length;

public class ByteListDirectOutputStream extends ByteArrayOutputStream {
ByteListDirectOutputStream(int size) {
super(size);
buffer = new byte[size];
}

public ByteList toByteListDirect(Encoding encoding) {
return new ByteList(buf, 0, count, encoding, false);
return new ByteList(buffer, 0, length, encoding, false);
}

@Override
public void write(int b) throws IOException {
int myLength = this.length;
grow(buffer, myLength, 1);
buffer[length++] = (byte) b;
}

@Override
public void write(byte[] bytes, int start, int length) throws IOException {
int myLength = this.length;
grow(buffer, myLength, length);
System.arraycopy(bytes, start, buffer, myLength, length);
this.length = myLength + length;
}

@Override
public void write(byte[] bytes) throws IOException {
int myLength = this.length;
int moreLength = bytes.length;
grow(buffer, myLength, moreLength);
System.arraycopy(bytes, 0, buffer, myLength, moreLength);
this.length = myLength + moreLength;
}

private static void grow(ByteListDirectOutputStream self, byte[] buffer, int myLength, int more) {
int newLength = myLength + more;
int myCapacity = buffer.length;
int diff = newLength - myCapacity;
if (diff > 0) {
// grow to double current length or capacity + diff, whichever is greater
int growBy = Math.max(myLength, diff);
self.buffer = Arrays.copyOf(self.buffer, myCapacity + growBy);
}
}
}

0 comments on commit a128bfa

Please sign in to comment.