|
31 | 31 | import java.io.IOException;
|
32 | 32 | import java.io.InputStream;
|
33 | 33 | import java.io.Reader;
|
| 34 | +import java.io.StringReader; |
34 | 35 | import java.io.UncheckedIOException;
|
35 | 36 | import java.io.Writer;
|
36 | 37 | import java.nio.charset.Charset;
|
@@ -475,7 +476,9 @@ public static CharSource concat(CharSource... sources) {
|
475 | 476 | * @since 15.0 (since 14.0 as {@code CharStreams.asCharSource(String)})
|
476 | 477 | */
|
477 | 478 | 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); |
479 | 482 | }
|
480 | 483 |
|
481 | 484 | /**
|
@@ -521,7 +524,7 @@ private static class CharSequenceCharSource extends CharSource {
|
521 | 524 |
|
522 | 525 | private static final Splitter LINE_SPLITTER = Splitter.onPattern("\r\n|\n|\r");
|
523 | 526 |
|
524 |
| - private final CharSequence seq; |
| 527 | + protected final CharSequence seq; |
525 | 528 |
|
526 | 529 | protected CharSequenceCharSource(CharSequence seq) {
|
527 | 530 | this.seq = checkNotNull(seq);
|
@@ -607,7 +610,54 @@ public String toString() {
|
607 | 610 | }
|
608 | 611 | }
|
609 | 612 |
|
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 { |
611 | 661 |
|
612 | 662 | private static final EmptyCharSource INSTANCE = new EmptyCharSource();
|
613 | 663 |
|
|
0 commit comments