Skip to content

Commit

Permalink
Implement String#repeat(int) which was introduced in JDK 11
Browse files Browse the repository at this point in the history
We can delegate the work directly to JS as the APIs are neraly indentical.

The only quirk is that we we are re-checking that the provided count is
non-negative to ensure that we always throw an IllegalArgumentException.

PiperOrigin-RevId: 585966573
  • Loading branch information
kevinoconnor7 authored and copybara-github committed Nov 28, 2023
1 parent 83a4aac commit e2042d0
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 2 deletions.
8 changes: 8 additions & 0 deletions jre/java/java/lang/String.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package java.lang;

import static javaemul.internal.InternalPreconditions.checkArgument;
import static javaemul.internal.InternalPreconditions.checkCriticalStringBounds;
import static javaemul.internal.InternalPreconditions.checkNotNull;
import static javaemul.internal.InternalPreconditions.checkPositionIndexes;
Expand Down Expand Up @@ -467,6 +468,11 @@ public boolean regionMatches(int toffset, String other, int ooffset, int len) {
return regionMatches(false, toffset, other, ooffset, len);
}

public String repeat(int count) {
checkArgument(count >= 0);
return asNativeString().repeat(count);
}

public String replace(char from, char to) {
return StringUtil.replace(this, from, to, /* ignoreCase= */ false);
}
Expand Down Expand Up @@ -678,6 +684,8 @@ private static class NativeString {

public native int lastIndexOf(String str, int start);

public native String repeat(int count);

public native String replace(NativeRegExp regex, String replace);

public native String substr(int beginIndex);
Expand Down
8 changes: 8 additions & 0 deletions jre/java/super-wasm-alt/java/lang/String.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package java.lang;

import static javaemul.internal.InternalPreconditions.checkArgument;
import static javaemul.internal.InternalPreconditions.checkCriticalStringBounds;
import static javaemul.internal.InternalPreconditions.checkNotNull;
import static javaemul.internal.InternalPreconditions.checkPositionIndexes;
Expand Down Expand Up @@ -597,6 +598,11 @@ public boolean regionMatches(
: isRegionEqual(value, offset + thisStart, string.value, string.offset + start, length);
}

public String repeat(int count) {
checkArgument(count >= 0);
return fromJsString(toJsString().repeat(count));
}

public String replace(char oldChar, char newChar) {
char[] buffer = value;
int thisOffset = offset;
Expand Down Expand Up @@ -1006,6 +1012,8 @@ interface NativeString {

NativeString toUpperCase();

NativeString repeat(int count);

NativeString toLocaleLowerCase();

NativeString toLocaleUpperCase();
Expand Down
12 changes: 10 additions & 2 deletions jre/java/super-wasm/java/lang/String.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package java.lang;

import static javaemul.internal.InternalPreconditions.checkArgument;
import static javaemul.internal.InternalPreconditions.checkCriticalStringBounds;
import static javaemul.internal.InternalPreconditions.checkNotNull;
import static javaemul.internal.InternalPreconditions.checkPositionIndexes;
Expand Down Expand Up @@ -539,8 +540,13 @@ public boolean regionMatches(
return ignoreCase ? left.equalsIgnoreCase(right) : left.equals(right);
}

public boolean regionMatches(int toffset, String other, int ooffset, int len) {
return regionMatches(false, toffset, other, ooffset, len);
public boolean regionMatches(int toffset, String other, int offset, int len) {
return regionMatches(false, toffset, other, offset, len);
}

public String repeat(int count) {
checkArgument(count >= 0);
return new String(value.repeat(count));
}

public String replace(char from, char to) {
Expand Down Expand Up @@ -762,6 +768,8 @@ interface NativeString {

int lastIndexOf(NativeString str, int start);

NativeString repeat(int count);

NativeString replace(NativeRegExp regex, NativeString replace);

NativeString toLocaleLowerCase();
Expand Down
20 changes: 20 additions & 0 deletions jre/javatests/com/google/j2cl/jre/java/lang/StringTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,26 @@ public void testRegionMatches() {
}
}

public void testRepeat() {
// Empty results
assertEquals("", "a".repeat(0));
assertEquals("", "".repeat(0));
assertEquals("", "".repeat(10));

// Normal cases
assertEquals("aaaaaaaaaa", "a".repeat(10));
assertEquals("abc", "abc".repeat(1));
assertEquals("abcabc", "abc".repeat(2));

// Invalid calls
try {
String unused = "abc".repeat(-1);
fail("Repeating a negative count should throw an exception.");
} catch (IllegalArgumentException ex) {
// expected.
}
}

public void testReplace() {
String axax = String.valueOf(new char[] {'a', 'x', 'a', 'x'});
String aaaa = String.valueOf(new char[] {'a', 'a', 'a', 'a'});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ function getImports() {
'string.indexOf$2': (/** string */ $instance, /** string */ str, /** number */ startIndex, ) => $instance.indexOf(str, startIndex, ),
'string.lastIndexOf$1': (/** string */ $instance, /** string */ str, ) => $instance.lastIndexOf(str, ),
'string.lastIndexOf$2': (/** string */ $instance, /** string */ str, /** number */ start, ) => $instance.lastIndexOf(str, start, ),
'string.repeat$1': (/** string */ $instance, /** number */ count, ) => $instance.repeat(count, ),
'string.replace$2': (/** string */ $instance, /** !RegExp */ regex, /** string */ replace, ) => $instance.replace(regex, replace, ),
'string.toLocaleLowerCase': (/** string */ $instance, ) => $instance.toLocaleLowerCase(),
'string.toLocaleUpperCase': (/** string */ $instance, ) => $instance.toLocaleUpperCase(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ function getImports() {
'string.indexOf$2': (/** string */ $instance, /** string */ str, /** number */ startIndex, ) => $instance.indexOf(str, startIndex, ),
'string.lastIndexOf$1': (/** string */ $instance, /** string */ str, ) => $instance.lastIndexOf(str, ),
'string.lastIndexOf$2': (/** string */ $instance, /** string */ str, /** number */ start, ) => $instance.lastIndexOf(str, start, ),
'string.repeat$1': (/** string */ $instance, /** number */ count, ) => $instance.repeat(count, ),
'string.replace$2': (/** string */ $instance, /** !RegExp */ regex, /** string */ replace, ) => $instance.replace(regex, replace, ),
'string.toLocaleLowerCase': (/** string */ $instance, ) => $instance.toLocaleLowerCase(),
'string.toLocaleUpperCase': (/** string */ $instance, ) => $instance.toLocaleUpperCase(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ function getImports() {
'string.indexOf$2': (/** string */ $instance, /** string */ str, /** number */ startIndex, ) => $instance.indexOf(str, startIndex, ),
'string.lastIndexOf$1': (/** string */ $instance, /** string */ str, ) => $instance.lastIndexOf(str, ),
'string.lastIndexOf$2': (/** string */ $instance, /** string */ str, /** number */ start, ) => $instance.lastIndexOf(str, start, ),
'string.repeat$1': (/** string */ $instance, /** number */ count, ) => $instance.repeat(count, ),
'string.replace$2': (/** string */ $instance, /** !RegExp */ regex, /** string */ replace, ) => $instance.replace(regex, replace, ),
'string.toLocaleLowerCase': (/** string */ $instance, ) => $instance.toLocaleLowerCase(),
'string.toLocaleUpperCase': (/** string */ $instance, ) => $instance.toLocaleUpperCase(),
Expand Down

0 comments on commit e2042d0

Please sign in to comment.