Skip to content

Commit 73ef811

Browse files
committed
#68 serialize without copy
1 parent 5d61fd1 commit 73ef811

5 files changed

Lines changed: 122 additions & 50 deletions

File tree

src/main/java/com/jsoniter/output/JsonStream.java

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
import com.jsoniter.any.Any;
44
import com.jsoniter.spi.*;
55

6-
import java.io.ByteArrayOutputStream;
76
import java.io.IOException;
87
import java.io.OutputStream;
9-
import java.io.UnsupportedEncodingException;
108
import java.lang.reflect.Type;
119

1210
public class JsonStream extends OutputStream {
@@ -30,44 +28,54 @@ public void reset(OutputStream out) {
3028
this.count = 0;
3129
}
3230

33-
public final void write(int b) throws IOException {
34-
if (count == buf.length) {
35-
flushBuffer();
31+
final void ensure(int minimal) throws IOException {
32+
int available = buf.length - count;
33+
if (available < minimal) {
34+
if (count > 1024) {
35+
flushBuffer();
36+
}
37+
growAtLeast(minimal);
3638
}
39+
}
40+
41+
private final void growAtLeast(int minimal) {
42+
int toGrow = buf.length;
43+
if (toGrow < minimal) {
44+
toGrow = minimal;
45+
}
46+
byte[] newBuf = new byte[buf.length + toGrow];
47+
System.arraycopy(buf, 0, newBuf, 0, buf.length);
48+
buf = newBuf;
49+
}
50+
51+
public final void write(int b) throws IOException {
52+
ensure(1);
3753
buf[count++] = (byte) b;
3854
}
3955

4056
public final void write(byte b1, byte b2) throws IOException {
41-
if (count >= buf.length - 1) {
42-
flushBuffer();
43-
}
57+
ensure(2);
4458
buf[count++] = b1;
4559
buf[count++] = b2;
4660
}
4761

4862
public final void write(byte b1, byte b2, byte b3) throws IOException {
49-
if (count >= buf.length - 2) {
50-
flushBuffer();
51-
}
63+
ensure(3);
5264
buf[count++] = b1;
5365
buf[count++] = b2;
5466
buf[count++] = b3;
5567
}
5668

5769
public final void write(byte b1, byte b2, byte b3, byte b4) throws IOException {
58-
if (count >= buf.length - 3) {
59-
flushBuffer();
60-
}
70+
ensure(4);
6171
buf[count++] = b1;
6272
buf[count++] = b2;
6373
buf[count++] = b3;
6474
buf[count++] = b4;
6575
}
6676

6777
public final void write(byte b1, byte b2, byte b3, byte b4, byte b5) throws IOException {
68-
if (count >= buf.length - 4) {
69-
flushBuffer();
70-
}
78+
ensure(5);
7179
buf[count++] = b1;
7280
buf[count++] = b2;
7381
buf[count++] = b3;
@@ -76,9 +84,7 @@ public final void write(byte b1, byte b2, byte b3, byte b4, byte b5) throws IOEx
7684
}
7785

7886
public final void write(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6) throws IOException {
79-
if (count >= buf.length - 5) {
80-
flushBuffer();
81-
}
87+
ensure(6);
8288
buf[count++] = b1;
8389
buf[count++] = b2;
8490
buf[count++] = b3;
@@ -88,16 +94,20 @@ public final void write(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6) th
8894
}
8995

9096
public final void write(byte b[], int off, int len) throws IOException {
91-
if (len >= buf.length - count) {
92-
if (len >= buf.length) {
97+
if (out == null) {
98+
ensure(len);
99+
} else {
100+
if (len >= buf.length - count) {
101+
if (len >= buf.length) {
93102
/* If the request length exceeds the size of the output buffer,
94103
flush the output buffer and then write the data directly.
95104
In this way buffered streams will cascade harmlessly. */
105+
flushBuffer();
106+
out.write(b, off, len);
107+
return;
108+
}
96109
flushBuffer();
97-
out.write(b, off, len);
98-
return;
99110
}
100-
flushBuffer();
101111
}
102112
System.arraycopy(b, off, buf, count, len);
103113
count += len;
@@ -142,6 +152,12 @@ public final void writeRaw(String val) throws IOException {
142152
}
143153

144154
public final void writeRaw(String val, int remaining) throws IOException {
155+
if (out == null) {
156+
ensure(remaining);
157+
val.getBytes(0, remaining, buf, count);
158+
count += remaining;
159+
return;
160+
}
145161
int i = 0;
146162
for (; ; ) {
147163
int available = buf.length - count;
@@ -288,16 +304,9 @@ private void writeIndention(int delta) throws IOException {
288304
}
289305
write('\n');
290306
int toWrite = indention - delta;
291-
int i = 0;
292-
for (; ; ) {
293-
for (; i < toWrite && count < buf.length; i++) {
294-
buf[count++] = ' ';
295-
}
296-
if (i == toWrite) {
297-
break;
298-
} else {
299-
flushBuffer();
300-
}
307+
ensure(toWrite);
308+
for (int i = 0; i < toWrite && count < buf.length; i++) {
309+
buf[count++] = ' ';
301310
}
302311
}
303312

@@ -496,4 +505,7 @@ public static void registerNativeEncoder(Class clazz, Encoder.ReflectionEncoder
496505
CodegenImplNative.NATIVE_ENCODERS.put(clazz, encoder);
497506
}
498507

508+
public Slice buffer() {
509+
return new Slice(buf, 0, count);
510+
}
499511
}

src/main/java/com/jsoniter/output/StreamImplNumber.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ class StreamImplNumber {
4949
private static final byte[] MIN_INT = "-2147483648".getBytes();
5050

5151
public static final void writeInt(final JsonStream stream, int value) throws IOException {
52-
if (stream.buf.length - stream.count < 11) {
53-
stream.flushBuffer();
54-
}
52+
stream.ensure(12);
5553
byte[] buf = stream.buf;
5654
int pos = stream.count;
5755
if (value < 0) {
@@ -117,9 +115,7 @@ private static void writeBuf(final byte[] buf, final int v, int pos) {
117115
private static final byte[] MIN_LONG = "-9223372036854775808".getBytes();
118116

119117
public static final void writeLong(final JsonStream stream, long value) throws IOException {
120-
if (stream.buf.length - stream.count < 21) {
121-
stream.flushBuffer();
122-
}
118+
stream.ensure(22);
123119
byte[] buf = stream.buf;
124120
int pos = stream.count;
125121
if (value < 0) {
@@ -232,9 +228,7 @@ public static final void writeFloat(JsonStream stream, float val) throws IOExcep
232228
return;
233229
}
234230
stream.write('.');
235-
if (stream.buf.length - stream.count < 10) {
236-
stream.flushBuffer();
237-
}
231+
stream.ensure(11);
238232
for (int p = precision - 1; p > 0 && fval < POW10[p]; p--) {
239233
stream.buf[stream.count++] = '0';
240234
}
@@ -262,9 +256,7 @@ public static final void writeDouble(JsonStream stream, double val) throws IOExc
262256
return;
263257
}
264258
stream.write('.');
265-
if (stream.buf.length - stream.count < 10) {
266-
stream.flushBuffer();
267-
}
259+
stream.ensure(11);
268260
for (int p = precision - 1; p > 0 && fval < POW10[p]; p--) {
269261
stream.buf[stream.count++] = '0';
270262
}

src/main/java/com/jsoniter/output/StreamImplString.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public static final void writeString(final JsonStream stream, final String val)
6363
toWriteLen = bufLengthMinusTwo - stream.count;
6464
}
6565
if (toWriteLen < 0) {
66-
stream.flushBuffer();
66+
stream.ensure(32);
6767
if (stream.count + toWriteLen > bufLengthMinusTwo) {
6868
toWriteLen = bufLengthMinusTwo - stream.count;
6969
}
@@ -103,7 +103,7 @@ public static final void writeStringWithoutQuote(final JsonStream stream, final
103103
toWriteLen = bufLen - stream.count;
104104
}
105105
if (toWriteLen < 0) {
106-
stream.flushBuffer();
106+
stream.ensure(32);
107107
if (stream.count + toWriteLen > bufLen) {
108108
toWriteLen = bufLen - stream.count;
109109
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.jsoniter.output;
2+
3+
import com.jsoniter.spi.Config;
4+
import com.jsoniter.spi.JsoniterSpi;
5+
import junit.framework.TestCase;
6+
7+
import java.io.IOException;
8+
9+
public class TestStreamBuffer extends TestCase {
10+
11+
public void test_write_string() throws IOException {
12+
JsonStream jsonStream = new JsonStream(null, 32);
13+
jsonStream.writeVal("01234567");
14+
jsonStream.writeVal("01234567");
15+
jsonStream.writeVal("012345678");
16+
jsonStream.writeVal("");
17+
assertEquals(33, jsonStream.buffer().len());
18+
}
19+
20+
public void test_write_raw() throws IOException {
21+
JsonStream jsonStream = new JsonStream(null, 32);
22+
jsonStream.writeRaw("0123456789");
23+
jsonStream.writeRaw("0123456789");
24+
jsonStream.writeRaw("0123456789");
25+
jsonStream.writeRaw("0123456789");
26+
assertEquals(40, jsonStream.buffer().len());
27+
}
28+
29+
public void test_write_bytes() throws IOException {
30+
JsonStream jsonStream = new JsonStream(null, 32);
31+
jsonStream.write("0123456789".getBytes());
32+
jsonStream.write("0123456789".getBytes());
33+
jsonStream.write("0123456789".getBytes());
34+
jsonStream.write("0123456789".getBytes());
35+
assertEquals(40, jsonStream.buffer().len());
36+
}
37+
38+
public void test_write_indention() throws IOException {
39+
Config oldConfig = JsoniterSpi.getCurrentConfig();
40+
try {
41+
JsoniterSpi.setCurrentConfig(new Config.Builder().indentionStep(32).build());
42+
JsonStream jsonStream = new JsonStream(null, 32);
43+
jsonStream.writeArrayStart();
44+
assertEquals(34, jsonStream.buffer().len());
45+
} finally {
46+
JsoniterSpi.setCurrentConfig(oldConfig);
47+
}
48+
}
49+
50+
public void test_write_int() throws IOException {
51+
JsonStream jsonStream = new JsonStream(null, 32);
52+
jsonStream.writeVal(123456789);
53+
jsonStream.writeVal(123456789);
54+
jsonStream.writeVal(123456789);
55+
jsonStream.writeVal(123456789);
56+
assertEquals(36, jsonStream.buffer().len());
57+
}
58+
59+
public void test_write_long() throws IOException {
60+
JsonStream jsonStream = new JsonStream(null, 32);
61+
jsonStream.writeVal(123456789L);
62+
jsonStream.writeVal(123456789L);
63+
jsonStream.writeVal(123456789L);
64+
jsonStream.writeVal(123456789L);
65+
assertEquals(36, jsonStream.buffer().len());
66+
}
67+
}

src/test/java/com/jsoniter/suite/AllTestCases.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
TestSpiTypeDecoder.class,
4848
TestSpiPropertyDecoder.class,
4949
TestGson.class,
50-
com.jsoniter.output.TestGson.class})
50+
com.jsoniter.output.TestGson.class,
51+
TestStreamBuffer.class})
5152
public abstract class AllTestCases {
5253
}

0 commit comments

Comments
 (0)