--- a/src/java.base/share/classes/java/lang/String.java Thu Mar 01 18:27:39 2018 +0000
+++ b/src/java.base/share/classes/java/lang/String.java Thu Mar 01 15:45:51 2018 -0400
@@ -2963,6 +2963,56 @@
*/
public native String intern();
+ /**
+ * Returns a string whose value is the concatenation of this
+ * string repeated {@code count} times.
+ * <p>
+ * If this string is empty or count is zero then the empty
+ * string is returned.
+ *
+ * @param count number of times to repeat
+ *
+ * @return A string composed of this string repeated
+ * {@code count} times or the empty string if this
+ * string is empty or count is zero
+ *
+ * @throws IllegalArgumentException if the {@code count} is
+ * negative.
+ *
+ * @since 11
+ */
+ public String repeat(int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException("count is negative: " + count);
+ }
+ if (count == 1) {
+ return this;
+ }
+ final int len = value.length;
+ if (len == 0 || count == 0) {
+ return "";
+ }
+ if (len == 1) {
+ final byte[] single = new byte[count];
+ Arrays.fill(single, value[0]);
+ return new String(single, coder);
+ }
+ if (Integer.MAX_VALUE / count < len) {
+ throw new OutOfMemoryError("Repeating " + len + " bytes String " + count +
+ " times will produce a String exceeding maximum size.");
+ }
+ final int limit = len * count;
+ final byte[] multiple = new byte[limit];
+ System.arraycopy(value, 0, multiple, 0, len);
+ int copied = len;
+ for (int next = copied << 1; next < limit && 0 < next; next = next << 1) {
+ System.arraycopy(multiple, 0, multiple, copied, copied);
+ copied = next;
+ }
+ System.arraycopy(multiple, 0, multiple, copied, limit - copied);
+ return new String(multiple, coder);
+ }
+
////////////////////////////////////////////////////////////////
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/String/StringRepeat.java Thu Mar 01 15:45:51 2018 -0400
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary This exercises String#repeat patterns and limits.
+ * @run main/othervm -Xmx4G StringRepeat
+ */
+
+import java.nio.CharBuffer;
+
+public class StringRepeat {
+ public static void main(String... arg) {
+ test1();
+ test2();
+ }
+
+ /*
+ * Varitions of repeat count.
+ */
+ static int[] REPEATS = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 32, 64, 128, 256, 512, 1024, 64 * 1024, 1024 * 1024,
+ 16 * 1024 * 1024
+ };
+
+ /*
+ * Varitions of Strings.
+ */
+ static String[] STRINGS = new String[] {
+ "", "\0", " ", "a", "$", "\u2022",
+ "ab", "abc", "abcd", "abcde",
+ "The quick brown fox jumps over the lazy dog."
+ };
+
+ /*
+ * Repeat String function tests.
+ */
+ static void test1() {
+ for (int repeat : REPEATS) {
+ for (String string : STRINGS) {
+ long limit = (long)string.length() * (long)repeat;
+
+ if ((long)(Integer.MAX_VALUE >> 1) <= limit) {
+ break;
+ }
+
+ verify(string.repeat(repeat), string, repeat);
+ }
+ }
+ }
+
+ /*
+ * Repeat String exception tests.
+ */
+ static void test2() {
+ try {
+ "abc".repeat(-1);
+ throw new RuntimeException("No exception for negative repeat count");
+ } catch (IllegalArgumentException ex) {
+ // Correct
+ }
+
+ try {
+ "abc".repeat(Integer.MAX_VALUE - 1);
+ throw new RuntimeException("No exception for large repeat count");
+ } catch (OutOfMemoryError ex) {
+ // Correct
+ }
+ }
+
+ static String truncate(String string) {
+ if (string.length() < 80) {
+ return string;
+ }
+ return string.substring(0, 80) + "...";
+ }
+
+ /*
+ * Verify string repeat patterns.
+ */
+ static void verify(String result, String string, int repeat) {
+ if (string.isEmpty() || repeat == 0) {
+ if (!result.isEmpty()) {
+ System.err.format("\"%s\".repeat(%d)%n", truncate(string), repeat);
+ System.err.format("Result \"%s\"%n", truncate(result));
+ System.err.format("Result expected to be empty, found string of length %d%n", result.length());
+ throw new RuntimeException();
+ }
+ } else {
+ int expected = 0;
+ int count = 0;
+ for (int offset = result.indexOf(string, expected);
+ 0 <= offset;
+ offset = result.indexOf(string, expected)) {
+ count++;
+ if (offset != expected) {
+ System.err.format("\"%s\".repeat(%d)%n", truncate(string), repeat);
+ System.err.format("Result \"%s\"%n", truncate(result));
+ System.err.format("Repeat expected at %d, found at = %d%n", expected, offset);
+ throw new RuntimeException();
+ }
+ expected += string.length();
+ }
+ if (count != repeat) {
+ System.err.format("\"%s\".repeat(%d)%n", truncate(string), repeat);
+ System.err.format("Result \"%s\"%n", truncate(result));
+ System.err.format("Repeat count expected to be %d, found %d%n", repeat, count);
+ throw new RuntimeException();
+ }
+ }
+ }
+}