Skip to content

Commit 97ac36f

Browse files
committed
Reimpl byte[] stream without synchronization
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.
1 parent b11e4f2 commit 97ac36f

File tree

1 file changed

+44
-4
lines changed

1 file changed

+44
-4
lines changed

java/src/json/ext/ByteListDirectOutputStream.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,54 @@
33
import org.jcodings.Encoding;
44
import org.jruby.util.ByteList;
55

6-
import java.io.ByteArrayOutputStream;
6+
import java.io.IOException;
7+
import java.io.OutputStream;
8+
import java.util.Arrays;
9+
10+
public class ByteListDirectOutputStream extends OutputStream {
11+
private byte[] buffer;
12+
private int length;
713

8-
public class ByteListDirectOutputStream extends ByteArrayOutputStream {
914
ByteListDirectOutputStream(int size) {
10-
super(size);
15+
buffer = new byte[size];
1116
}
1217

1318
public ByteList toByteListDirect(Encoding encoding) {
14-
return new ByteList(buf, 0, count, encoding, false);
19+
return new ByteList(buffer, 0, length, encoding, false);
20+
}
21+
22+
@Override
23+
public void write(int b) throws IOException {
24+
int myLength = this.length;
25+
grow(this, buffer, myLength, 1);
26+
buffer[length++] = (byte) b;
27+
}
28+
29+
@Override
30+
public void write(byte[] bytes, int start, int length) throws IOException {
31+
int myLength = this.length;
32+
grow(this, buffer, myLength, length);
33+
System.arraycopy(bytes, start, buffer, myLength, length);
34+
this.length = myLength + length;
35+
}
36+
37+
@Override
38+
public void write(byte[] bytes) throws IOException {
39+
int myLength = this.length;
40+
int moreLength = bytes.length;
41+
grow(this, buffer, myLength, moreLength);
42+
System.arraycopy(bytes, 0, buffer, myLength, moreLength);
43+
this.length = myLength + moreLength;
44+
}
45+
46+
private static void grow(ByteListDirectOutputStream self, byte[] buffer, int myLength, int more) {
47+
int newLength = myLength + more;
48+
int myCapacity = buffer.length;
49+
int diff = newLength - myCapacity;
50+
if (diff > 0) {
51+
// grow to double current length or capacity + diff, whichever is greater
52+
int growBy = Math.max(myLength, diff);
53+
self.buffer = Arrays.copyOf(self.buffer, myCapacity + growBy);
54+
}
1555
}
1656
}

0 commit comments

Comments
 (0)