Skip to content

Commit 0a96e61

Browse files
committed
add Unsynchronized version of UnsynchronizedBufferedInputStream and UnsynchronizedBufferedInputStream, and performance tests.
1 parent 4b92e65 commit 0a96e61

File tree

6 files changed

+964
-0
lines changed

6 files changed

+964
-0
lines changed

pom.xml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,18 @@ file comparators, endian transformation classes, and much more.
242242
</dependencyManagement>
243243

244244
<dependencies>
245+
<dependency>
246+
<groupId>org.openjdk.jmh</groupId>
247+
<artifactId>jmh-core</artifactId>
248+
<version>${jmh.version}</version>
249+
<scope>test</scope>
250+
</dependency>
251+
<dependency>
252+
<groupId>org.openjdk.jmh</groupId>
253+
<artifactId>jmh-generator-annprocess</artifactId>
254+
<version>${jmh.version}</version>
255+
<scope>test</scope>
256+
</dependency>
245257
<dependency>
246258
<groupId>org.junit.jupiter</groupId>
247259
<artifactId>junit-jupiter</artifactId>
@@ -312,6 +324,7 @@ file comparators, endian transformation classes, and much more.
312324
<commons.release.isDistModule>true</commons.release.isDistModule>
313325
<commons.releaseManagerName>Gary Gregory</commons.releaseManagerName>
314326
<commons.releaseManagerKey>86fdc7e2a11262cb</commons.releaseManagerKey>
327+
<jmh.version>1.27</jmh.version>
315328
</properties>
316329

317330
<build>
@@ -549,5 +562,44 @@ file comparators, endian transformation classes, and much more.
549562
<coveralls.skip>true</coveralls.skip>
550563
</properties>
551564
</profile>
565+
<profile>
566+
<id>benchmark</id>
567+
<properties>
568+
<skipTests>true</skipTests>
569+
<benchmark>org.apache</benchmark>
570+
</properties>
571+
<build>
572+
<plugins>
573+
<plugin>
574+
<groupId>org.codehaus.mojo</groupId>
575+
<artifactId>exec-maven-plugin</artifactId>
576+
<version>1.6.0</version>
577+
<executions>
578+
<execution>
579+
<id>benchmark</id>
580+
<phase>test</phase>
581+
<goals>
582+
<goal>exec</goal>
583+
</goals>
584+
<configuration>
585+
<classpathScope>test</classpathScope>
586+
<executable>java</executable>
587+
<arguments>
588+
<argument>-classpath</argument>
589+
<classpath/>
590+
<argument>org.openjdk.jmh.Main</argument>
591+
<argument>-rf</argument>
592+
<argument>json</argument>
593+
<argument>-rff</argument>
594+
<argument>target/jmh-result.${benchmark}.json</argument>
595+
<argument>${benchmark}</argument>
596+
</arguments>
597+
</configuration>
598+
</execution>
599+
</executions>
600+
</plugin>
601+
</plugins>
602+
</build>
603+
</profile>
552604
</profiles>
553605
</project>
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.io.input.buffer;
18+
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import org.apache.commons.io.IOUtils;
22+
import static org.apache.commons.io.IOUtils.EOF;
23+
24+
/**
25+
* A BufferedReader class who does not care about thread safety, but very much faster.
26+
*
27+
* Should be able to replace java.io.BufferedReader in nearly every use-cases when you
28+
* need the Reader be buffered, but do not need it have thread safety.
29+
*/
30+
public class UnsynchronizedBufferedInputStream extends InputStream {
31+
private final InputStream inputStream;
32+
private final byte[] byteBuffer;
33+
34+
private int nowIndex = 0;
35+
private int nowLimit = 0;
36+
37+
/**
38+
* Creates a new instance, which filters the given input stream, and
39+
* uses the given buffer size.
40+
*
41+
* @param inputStream The original input stream, which is being buffered.
42+
* @param charBufferSize size of the buffer.
43+
*/
44+
public UnsynchronizedBufferedInputStream(InputStream inputStream, int charBufferSize) {
45+
this(inputStream, new byte[charBufferSize]);
46+
}
47+
48+
/**
49+
* Creates a new instance, which filters the given input stream, and
50+
* uses IOUtils.DEFAULT_BUFFER_SIZE.
51+
*
52+
* @param inputStream The original input stream, which is being buffered.
53+
* @see IOUtils#DEFAULT_BUFFER_SIZE
54+
*/
55+
public UnsynchronizedBufferedInputStream(InputStream inputStream) {
56+
this(inputStream, IOUtils.DEFAULT_BUFFER_SIZE);
57+
}
58+
59+
/**
60+
* Creates a new instance, which filters the given reader, and
61+
* uses the given buffer.
62+
*
63+
* @param inputStream The original inputStream, which is being buffered.
64+
* @param byteBuffer buffer used.
65+
*/
66+
public UnsynchronizedBufferedInputStream(InputStream inputStream, byte[] byteBuffer) {
67+
this.inputStream = inputStream;
68+
this.byteBuffer = byteBuffer;
69+
}
70+
71+
/**
72+
* {@inheritDoc}
73+
*/
74+
@Override
75+
public int read(byte[] cbuf, int off, int len) throws IOException {
76+
if (len <= 0) {
77+
return 0;
78+
}
79+
int currentBufferSize = this.nowLimit - this.nowIndex;
80+
if (currentBufferSize == 0) {
81+
int readLength;
82+
do {
83+
readLength = this.inputStream.read(this.byteBuffer, 0, this.byteBuffer.length);
84+
} while (readLength == 0);
85+
if (readLength == EOF) {
86+
return EOF;
87+
}
88+
this.nowLimit = readLength;
89+
this.nowIndex = 0;
90+
currentBufferSize = this.nowLimit - this.nowIndex;
91+
}
92+
if (currentBufferSize <= len) {
93+
System.arraycopy(this.byteBuffer, this.nowIndex, cbuf, off, currentBufferSize);
94+
this.nowLimit = this.nowIndex = 0;
95+
return currentBufferSize;
96+
} else {
97+
System.arraycopy(this.byteBuffer, this.nowIndex, cbuf, off, len);
98+
this.nowIndex += len;
99+
return len;
100+
}
101+
}
102+
103+
/**
104+
* {@inheritDoc}
105+
*/
106+
@Override
107+
public int read() throws IOException {
108+
int res = this.peek();
109+
if (res != EOF) {
110+
eat();
111+
}
112+
return res;
113+
}
114+
115+
/**
116+
* see the next byte, but not mark it as read.
117+
*
118+
* @return the next byte
119+
* @throws IOException by inputStream.read()
120+
* @see #read()
121+
*/
122+
public int peek() throws IOException {
123+
int currentBufferSize = this.nowLimit - this.nowIndex;
124+
if (currentBufferSize == 0) {
125+
int readLength;
126+
do {
127+
readLength = this.inputStream.read(this.byteBuffer, 0, this.byteBuffer.length);
128+
} while (readLength == 0);
129+
if (readLength == EOF) {
130+
return EOF;
131+
}
132+
this.nowLimit = readLength;
133+
this.nowIndex = 0;
134+
return this.byteBuffer[0];
135+
}
136+
return this.byteBuffer[this.nowIndex];
137+
}
138+
139+
/**
140+
* mark the current char as read.
141+
* must be used after invoke peek.
142+
*
143+
* @see #read()
144+
* @see #peek()
145+
*/
146+
public void eat() {
147+
this.nowIndex++;
148+
}
149+
150+
/**
151+
* {@inheritDoc}
152+
*/
153+
@Override
154+
public void close() throws IOException {
155+
if (this.inputStream != null) {
156+
this.inputStream.close();
157+
}
158+
}
159+
160+
/**
161+
* getter for this.inputStream
162+
* @return this.inputStream
163+
*/
164+
public InputStream getInputStream() {
165+
return this.inputStream;
166+
}
167+
168+
/**
169+
* getter for this.byteBuffer
170+
* @return this.byteBuffer
171+
*/
172+
public byte[] getByteBuffer() {
173+
return this.byteBuffer;
174+
}
175+
176+
/**
177+
* getter for this.nowIndex
178+
* @return this.nowIndex
179+
*/
180+
public int getNowIndex() {
181+
return this.nowIndex;
182+
}
183+
184+
/**
185+
* setter for this.nowIndex
186+
* @param nowIndex this.nowIndex
187+
*/
188+
public void setNowIndex(int nowIndex) {
189+
this.nowIndex = nowIndex;
190+
}
191+
192+
/**
193+
* getter for this.nowLimit
194+
* @return this.nowLimit
195+
*/
196+
public int getNowLimit() {
197+
return this.nowLimit;
198+
}
199+
200+
/**
201+
* setter for this.nowLimit
202+
* @param nowLimit this.nowLimit
203+
*/
204+
public void setNowLimit(int nowLimit) {
205+
this.nowLimit = nowLimit;
206+
}
207+
}

0 commit comments

Comments
 (0)