LANG-993: Add zero copy write method to StrBuilder; LANG-994: Add zero copy read method to StrBuilder. Thanks to Mikhail Mazursky.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1590224 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benedikt Ritter 2014-04-26 10:39:03 +00:00
parent d13a40266f
commit 6125951060
3 changed files with 199 additions and 0 deletions

View File

@ -22,6 +22,8 @@
<body>
<release version="3.4" date="tba" description="tba">
<action issue="LANG-994" type="add" dev="britter" due-to="Mikhail Mazursky">Add zero copy read method to StrBuilder</action>
<action issue="LANG-993" type="add" dev="britter" due-to="Mikhail Mazursky">Add zero copy write method to StrBuilder</action>
<action issue="LANG-998" type="update" dev="chas">Javadoc is not clear on preferred pattern to instantiate FastDateParser / FastDatePrinter</action>
<action issue="LANG-996" type="fix" dev="chas">FastDateParser should be case insensitive</action>
<action issue="LANG-995" type="fix" dev="britter" due-to="Andrey Khobnya">Fix bug with stripping spaces on last line in WordUtils.wrap()</action>

View File

@ -16,9 +16,11 @@
*/
package org.apache.commons.lang3.text;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.io.Writer;
import java.nio.CharBuffer;
import java.util.Iterator;
import java.util.List;
@ -421,6 +423,48 @@ public class StrBuilder implements CharSequence, Appendable, Serializable, Build
System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
}
//-----------------------------------------------------------------------
/**
* If possible, reads chars from the provided {@link Readable} directly into underlying
* character buffer without making extra copies.
*
* @param readable object to read from
* @return the number of characters read
* @throws IOException if an I/O error occurs
*
* @since 3.4
* @see #appendTo(Appendable)
*/
public int readFrom(final Readable readable) throws IOException {
final int oldSize = size;
if (readable instanceof Reader) {
final Reader r = (Reader) readable;
ensureCapacity(size + 1);
int read;
while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
size += read;
ensureCapacity(size + 1);
}
} else if (readable instanceof CharBuffer) {
final CharBuffer cb = (CharBuffer) readable;
final int remaining = cb.remaining();
ensureCapacity(size + remaining);
cb.get(buffer, size, remaining);
size += remaining;
} else {
while (true) {
ensureCapacity(size + 1);
final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
final int read = readable.read(buf);
if (read == -1) {
break;
}
size += read;
}
}
return size - oldSize;
}
//-----------------------------------------------------------------------
/**
* Appends the new line string to this string builder.
@ -2610,6 +2654,32 @@ public class StrBuilder implements CharSequence, Appendable, Serializable, Build
return new StrBuilderWriter();
}
/**
* Appends current contents of this <code>StrBuilder</code> to the
* provided {@link Appendable}.
* <p>
* This method tries to avoid doing any extra copies of contents.
*
* @param appendable the appendable to append data to
* @throws IOException if an I/O error occurs
*
* @since 3.4
* @see #readFrom(Readable)
*/
public void appendTo(final Appendable appendable) throws IOException {
if (appendable instanceof Writer) {
((Writer) appendable).write(buffer, 0, size);
} else if (appendable instanceof StringBuilder) {
((StringBuilder) appendable).append(buffer, 0, size);
} else if (appendable instanceof StringBuffer) {
((StringBuffer) appendable).append(buffer, 0, size);
} else if (appendable instanceof CharBuffer) {
((CharBuffer) appendable).put(buffer, 0, size);
} else {
appendable.append(this);
}
}
//-----------------------------------------------------------------------
// /**
// * Gets a String version of the string builder by calling the internal

View File

@ -19,8 +19,13 @@ package org.apache.commons.lang3.text;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.CharBuffer;
import java.util.Arrays;
import org.apache.commons.lang3.ArrayUtils;
@ -91,6 +96,84 @@ public class StrBuilderTest {
assertSame(sb, sb.trim());
}
//-----------------------------------------------------------------------
@Test
public void testReadFromReader() throws Exception {
String s = "";
for (int i = 0; i < 100; ++i) {
StrBuilder sb = new StrBuilder();
int len = sb.readFrom(new StringReader(s));
assertEquals(s.length(), len);
assertEquals(s, sb.toString());
s += Integer.toString(i);
}
}
@Test
public void testReadFromReaderAppendsToEnd() throws Exception {
StrBuilder sb = new StrBuilder("Test");
sb.readFrom(new StringReader(" 123"));
assertEquals("Test 123", sb.toString());
}
@Test
public void testReadFromCharBuffer() throws Exception {
String s = "";
for (int i = 0; i < 100; ++i) {
StrBuilder sb = new StrBuilder();
int len = sb.readFrom(CharBuffer.wrap(s));
assertEquals(s.length(), len);
assertEquals(s, sb.toString());
s += Integer.toString(i);
}
}
@Test
public void testReadFromCharBufferAppendsToEnd() throws Exception {
StrBuilder sb = new StrBuilder("Test");
sb.readFrom(CharBuffer.wrap(" 123"));
assertEquals("Test 123", sb.toString());
}
@Test
public void testReadFromReadable() throws Exception {
String s = "";
for (int i = 0; i < 100; ++i) {
StrBuilder sb = new StrBuilder();
int len = sb.readFrom(new MockReadable(s));
assertEquals(s.length(), len);
assertEquals(s, sb.toString());
s += Integer.toString(i);
}
}
@Test
public void testReadFromReadableAppendsToEnd() throws Exception {
StrBuilder sb = new StrBuilder("Test");
sb.readFrom(new MockReadable(" 123"));
assertEquals("Test 123", sb.toString());
}
private static class MockReadable implements Readable {
private final CharBuffer src;
public MockReadable(final String src) {
this.src = CharBuffer.wrap(src);
}
@Override
public int read(final CharBuffer cb) throws IOException {
return src.read(cb);
}
}
//-----------------------------------------------------------------------
@Test
public void testGetSetNewLineText() {
@ -1855,4 +1938,48 @@ public class StrBuilderTest {
assertEquals(sb.toString(), sb.build());
}
//-----------------------------------------------------------------------
@Test
public void testAppendToWriter() throws Exception {
final StrBuilder sb = new StrBuilder("1234567890");
final StringWriter writer = new StringWriter();
writer.append("Test ");
sb.appendTo(writer);
assertEquals("Test 1234567890", writer.toString());
}
@Test
public void testAppendToStringBuilder() throws Exception {
final StrBuilder sb = new StrBuilder("1234567890");
final StringBuilder builder = new StringBuilder("Test ");
sb.appendTo(builder);
assertEquals("Test 1234567890", builder.toString());
}
@Test
public void testAppendToStringBuffer() throws Exception {
final StrBuilder sb = new StrBuilder("1234567890");
final StringBuffer buffer = new StringBuffer("Test ");
sb.appendTo(buffer);
assertEquals("Test 1234567890", buffer.toString());
}
@Test
public void testAppendToCharBuffer() throws Exception {
final StrBuilder sb = new StrBuilder("1234567890");
final String text = "Test ";
final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
buffer.put(text);
sb.appendTo(buffer);
buffer.flip();
assertEquals("Test 1234567890", buffer.toString());
}
}