Skip to content

Commit d6c6d25

Browse files
lukesandbergcpovirk
authored andcommitted
Optimize CharSource.wrap(CharSequence) for when the CharSequence is a String
StringReader should be faster than CharSequenceReader in this case since it can use the String.getChars() method. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161843629
1 parent 2453d95 commit d6c6d25

File tree

2 files changed

+106
-6
lines changed

2 files changed

+106
-6
lines changed

android/guava/src/com/google/common/io/CharSource.java

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.io.IOException;
3030
import java.io.InputStream;
3131
import java.io.Reader;
32+
import java.io.StringReader;
3233
import java.io.Writer;
3334
import java.nio.charset.Charset;
3435
import java.util.Iterator;
@@ -408,7 +409,9 @@ public static CharSource concat(CharSource... sources) {
408409
* @since 15.0 (since 14.0 as {@code CharStreams.asCharSource(String)})
409410
*/
410411
public static CharSource wrap(CharSequence charSequence) {
411-
return new CharSequenceCharSource(charSequence);
412+
return charSequence instanceof String
413+
? new StringCharSource((String) charSequence)
414+
: new CharSequenceCharSource(charSequence);
412415
}
413416

414417
/**
@@ -454,7 +457,7 @@ private static class CharSequenceCharSource extends CharSource {
454457

455458
private static final Splitter LINE_SPLITTER = Splitter.onPattern("\r\n|\n|\r");
456459

457-
private final CharSequence seq;
460+
protected final CharSequence seq;
458461

459462
protected CharSequenceCharSource(CharSequence seq) {
460463
this.seq = checkNotNull(seq);
@@ -535,7 +538,54 @@ public String toString() {
535538
}
536539
}
537540

538-
private static final class EmptyCharSource extends CharSequenceCharSource {
541+
/**
542+
* Subclass specialized for string instances.
543+
*
544+
* <p>Since Strings are immutable and built into the jdk we can optimize some operations
545+
*
546+
* <ul>
547+
* <li>use {@link StringReader} instead of {@link CharSequenceReader}. It is faster since it can
548+
* use {@link String#getChars(int, int, char[], int)} instead of copying characters one by
549+
* one with {@link CharSequence#charAt(int)}.
550+
* <li>use {@link Appendable#append(CharSequence)} in {@link #copyTo(Appendable)} and {@link
551+
* #copyTo(CharSink)}. We know this is correct since strings are immutable and so the length
552+
* can't change, and it is faster because many writers and appendables are optimized for
553+
* appending string instances.
554+
* </ul>
555+
*/
556+
private static class StringCharSource extends CharSequenceCharSource {
557+
protected StringCharSource(String seq) {
558+
super(seq);
559+
}
560+
561+
@Override
562+
public Reader openStream() {
563+
return new StringReader((String) seq);
564+
}
565+
566+
@Override
567+
public long copyTo(Appendable appendable) throws IOException {
568+
appendable.append(seq);
569+
return seq.length();
570+
}
571+
572+
@Override
573+
public long copyTo(CharSink sink) throws IOException {
574+
checkNotNull(sink);
575+
Closer closer = Closer.create();
576+
try {
577+
Writer writer = closer.register(sink.openStream());
578+
writer.write((String) seq);
579+
return seq.length();
580+
} catch (Throwable e) {
581+
throw closer.rethrow(e);
582+
} finally {
583+
closer.close();
584+
}
585+
}
586+
}
587+
588+
private static final class EmptyCharSource extends StringCharSource {
539589

540590
private static final EmptyCharSource INSTANCE = new EmptyCharSource();
541591

guava/src/com/google/common/io/CharSource.java

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.io.IOException;
3232
import java.io.InputStream;
3333
import java.io.Reader;
34+
import java.io.StringReader;
3435
import java.io.UncheckedIOException;
3536
import java.io.Writer;
3637
import java.nio.charset.Charset;
@@ -475,7 +476,9 @@ public static CharSource concat(CharSource... sources) {
475476
* @since 15.0 (since 14.0 as {@code CharStreams.asCharSource(String)})
476477
*/
477478
public static CharSource wrap(CharSequence charSequence) {
478-
return new CharSequenceCharSource(charSequence);
479+
return charSequence instanceof String
480+
? new StringCharSource((String) charSequence)
481+
: new CharSequenceCharSource(charSequence);
479482
}
480483

481484
/**
@@ -521,7 +524,7 @@ private static class CharSequenceCharSource extends CharSource {
521524

522525
private static final Splitter LINE_SPLITTER = Splitter.onPattern("\r\n|\n|\r");
523526

524-
private final CharSequence seq;
527+
protected final CharSequence seq;
525528

526529
protected CharSequenceCharSource(CharSequence seq) {
527530
this.seq = checkNotNull(seq);
@@ -607,7 +610,54 @@ public String toString() {
607610
}
608611
}
609612

610-
private static final class EmptyCharSource extends CharSequenceCharSource {
613+
/**
614+
* Subclass specialized for string instances.
615+
*
616+
* <p>Since Strings are immutable and built into the jdk we can optimize some operations
617+
*
618+
* <ul>
619+
* <li>use {@link StringReader} instead of {@link CharSequenceReader}. It is faster since it can
620+
* use {@link String#getChars(int, int, char[], int)} instead of copying characters one by
621+
* one with {@link CharSequence#charAt(int)}.
622+
* <li>use {@link Appendable#append(CharSequence)} in {@link #copyTo(Appendable)} and {@link
623+
* #copyTo(CharSink)}. We know this is correct since strings are immutable and so the length
624+
* can't change, and it is faster because many writers and appendables are optimized for
625+
* appending string instances.
626+
* </ul>
627+
*/
628+
private static class StringCharSource extends CharSequenceCharSource {
629+
protected StringCharSource(String seq) {
630+
super(seq);
631+
}
632+
633+
@Override
634+
public Reader openStream() {
635+
return new StringReader((String) seq);
636+
}
637+
638+
@Override
639+
public long copyTo(Appendable appendable) throws IOException {
640+
appendable.append(seq);
641+
return seq.length();
642+
}
643+
644+
@Override
645+
public long copyTo(CharSink sink) throws IOException {
646+
checkNotNull(sink);
647+
Closer closer = Closer.create();
648+
try {
649+
Writer writer = closer.register(sink.openStream());
650+
writer.write((String) seq);
651+
return seq.length();
652+
} catch (Throwable e) {
653+
throw closer.rethrow(e);
654+
} finally {
655+
closer.close();
656+
}
657+
}
658+
}
659+
660+
private static final class EmptyCharSource extends StringCharSource {
611661

612662
private static final EmptyCharSource INSTANCE = new EmptyCharSource();
613663

0 commit comments

Comments
 (0)