--- old/src/java.base/share/classes/java/lang/AbstractStringBuilder.java 2016-12-09 08:31:41.461375054 +0100 +++ new/src/java.base/share/classes/java/lang/AbstractStringBuilder.java 2016-12-09 08:31:41.358375828 +0100 @@ -547,6 +547,10 @@ if (s instanceof AbstractStringBuilder) { return this.append((AbstractStringBuilder)s); } + if (s instanceof CharRepetitions) { + CharRepetitions cr = (CharRepetitions) s; + return this.appendN(cr.getChar(), cr.length()); + } return this.append(s, 0, s.length()); } @@ -741,6 +745,53 @@ } return this; } + + /** + * Appends {@code n} copies of the string representation of + * the {@code char} argument to this sequence. + *

+ * The first argument is appended to the contents of this + * sequence specified amount of times. + * The length of this sequence increases by {@code n}. + *

+ * The overall effect is exactly as if the first argument + * were converted to a string by the method + * {@link String#valueOf(char)}, and the character in that + * string were then {@link #append(String) appended} to this + * character sequence {@code n} times. + * + * @param c a {@code char}. + * @param n a number of copies to append. + * @return a reference to this object. + * @throws IllegalArgumentException if {@code n < 0}. + */ + @Override + public AbstractStringBuilder appendN(char c, int n) { + if (n <= 0) { + if (n < 0) { + throw new IllegalArgumentException( + "Negative number of copies: " + n); + } + } else { + int count = this.count; + ensureCapacityInternal(count + n); + if (isLatin1() && StringLatin1.canEncode(c)) { + byte b = (byte)c; + do { + value[count++] = b; + } while (--n > 0); + } else { + if (isLatin1()) { + inflate(); + } + do { + StringUTF16.putCharSB(value, count++, c); + } while (--n > 0); + } + this.count = count; + } + return this; + } /** * Appends the string representation of the {@code int} --- old/src/java.base/share/classes/java/lang/Appendable.java 2016-12-09 08:31:41.810372432 +0100 +++ new/src/java.base/share/classes/java/lang/Appendable.java 2016-12-09 08:31:41.671373476 +0100 @@ -118,4 +118,29 @@ * If an I/O error occurs */ Appendable append(char c) throws IOException; + + /** + * Appends {@code n} copies of the specified character to this + * {@code Appendable}. + * + * @param c + * The character to append + * @param n + * The number of copies + * + * @return A reference to this {@code Appendable} + * + * @throws IOException + * If an I/O error occurs + * @throws IllegalArgumentException + * If {@code n} is negative + */ + default Appendable appendN(char c, int n) throws IOException { + if (n < 0) { + throw new IllegalArgumentException("Negative number of" + + " copies: " + n); + } + StringBuilder sb = new StringBuilder(n); + return append(sb.appendN(c, n)); + } } --- old/src/java.base/share/classes/java/lang/CharSequence.java 2016-12-09 08:31:42.142369937 +0100 +++ new/src/java.base/share/classes/java/lang/CharSequence.java 2016-12-09 08:31:42.019370861 +0100 @@ -237,4 +237,19 @@ Spliterator.ORDERED, false); } + + /** + * Returns a {@code CharSequence} of specified length representing repetitions + * of the same character. + * + * @param c the character to be repeated + * @param length the length of resulting {@code CharSequence} + * @return a {@code CharSequence} of {@code length} repetitions of + * character {@code c}. + * @throws IllegalArgumentException if given {@code length} is negative + * @since 10 + */ + static CharSequence repetitions(char c, int length) { + return new CharRepetitions(c, length); + } } --- old/src/java.base/share/classes/java/lang/StringBuffer.java 2016-12-09 08:31:42.489367329 +0100 +++ new/src/java.base/share/classes/java/lang/StringBuffer.java 2016-12-09 08:31:42.347368396 +0100 @@ -427,6 +427,13 @@ return this; } + @Override + public synchronized StringBuffer appendN(char c, int n) { + toStringCache = null; + super.appendN(c, n); + return this; + } + /** * @throws StringIndexOutOfBoundsException {@inheritDoc} * @since 1.2 --- old/src/java.base/share/classes/java/lang/StringBuilder.java 2016-12-09 08:31:42.793365045 +0100 +++ new/src/java.base/share/classes/java/lang/StringBuilder.java 2016-12-09 08:31:42.700365744 +0100 @@ -234,6 +234,12 @@ return this; } + @Override + public StringBuilder appendN(char c, int n) { + super.appendN(c, n); + return this; + } + /** * @since 1.5 */ --- /dev/null 2016-12-09 08:02:56.857125237 +0100 +++ new/src/java.base/share/classes/java/lang/CharRepetitions.java 2016-12-09 08:31:43.030363264 +0100 @@ -0,0 +1,73 @@ +package java.lang; + +import java.util.Arrays; +import java.util.Objects; + +/** + * A {@link CharSequence} implementation that represents repetitions + * of the same character. + */ +final class CharRepetitions implements CharSequence { + private final char c; + private final int len; + + CharRepetitions(char c, int len) { + if (len < 0) { + throw new IllegalArgumentException("Length should not be negative"); + } + this.c = c; + this.len = len; + } + + char getChar() { + return c; + } + + @Override + public int length() { + return len; + } + + @Override + public char charAt(int index) { + Objects.checkIndex(index, len); + return c; + } + + @Override + public CharSequence subSequence(int start, int end) { + Objects.checkFromToIndex(start, end, len); + return new CharRepetitions(c, end - start); + } + + @Override + public int hashCode() { + return len * (c + 1); + } + + @Override + public boolean equals(Object obj) { + CharRepetitions o; + return obj instanceof CharRepetitions && + (o = (CharRepetitions) obj).len == len && + (o.c == c | len == 0); + } + + @Override + public String toString() { + byte[] val; + byte coder; + if (c > 0xFF & len > 0) { + val = StringUTF16.newBytesFor(len); + for (int i = 0; i < len; i++) { + StringUTF16.putChar(val, i, c); + } + coder = String.UTF16; + } else { + val = new byte[len]; + Arrays.fill(val, (byte) c); + coder = String.LATIN1; + } + return new String(val, coder); + } +}