From 0dd10899a06f5b19842de33c5059f6b943c66c07 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 29 Apr 2024 19:15:08 +0200 Subject: [PATCH] classlib: implement CharSequence chars and codePoints --- .../classlib/java/lang/TCharSequence.java | 12 ++++ .../org/teavm/classlib/java/lang/TString.java | 7 +++ .../intimpl/TCharSequenceCharsStream.java | 48 +++++++++++++++ .../TCharSequenceCodePointsStream.java | 60 +++++++++++++++++++ .../stream/intimpl/TStringCharsStream.java | 3 +- .../intimpl/TStringCodePointsStream.java | 60 +++++++++++++++++++ .../classlib/java/lang/StringBuilderTest.java | 19 ++++++ .../teavm/classlib/java/lang/StringTest.java | 12 ++++ 8 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TCharSequenceCharsStream.java create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TCharSequenceCodePointsStream.java create mode 100644 classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TStringCodePointsStream.java diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TCharSequence.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TCharSequence.java index 11f4c705f3..2e24aee75c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TCharSequence.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TCharSequence.java @@ -15,6 +15,10 @@ */ package org.teavm.classlib.java.lang; +import org.teavm.classlib.java.util.stream.TIntStream; +import org.teavm.classlib.java.util.stream.intimpl.TCharSequenceCharsStream; +import org.teavm.classlib.java.util.stream.intimpl.TCharSequenceCodePointsStream; + public interface TCharSequence { int length(); @@ -24,6 +28,14 @@ public interface TCharSequence { TCharSequence subSequence(int start, int end); + default TIntStream chars() { + return new TCharSequenceCharsStream(this); + } + + default TIntStream codePoints() { + return new TCharSequenceCodePointsStream(this); + } + @Override String toString(); } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java index 7e368cb201..6488165fb0 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TString.java @@ -33,6 +33,7 @@ import org.teavm.classlib.java.util.regex.TPattern; import org.teavm.classlib.java.util.stream.TIntStream; import org.teavm.classlib.java.util.stream.intimpl.TStringCharsStream; +import org.teavm.classlib.java.util.stream.intimpl.TStringCodePointsStream; import org.teavm.dependency.PluggableDependency; import org.teavm.interop.NoSideEffects; @@ -589,10 +590,16 @@ public char[] toCharArray() { return array; } + @Override public TIntStream chars() { return new TStringCharsStream(this); } + @Override + public TIntStream codePoints() { + return new TStringCodePointsStream(this); + } + public static String valueOf(Object obj) { return obj != null ? obj.toString() : "null"; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TCharSequenceCharsStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TCharSequenceCharsStream.java new file mode 100644 index 0000000000..842053d9ea --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TCharSequenceCharsStream.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023 JFronny. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.util.stream.intimpl; + +import java.util.function.IntPredicate; +import org.teavm.classlib.java.lang.TCharSequence; + +public class TCharSequenceCharsStream extends TSimpleIntStreamImpl { + private final TCharSequence csq; + private int index; + + public TCharSequenceCharsStream(TCharSequence csq) { + this.csq = csq; + } + + @Override + public boolean next(IntPredicate consumer) { + while (index < csq.length()) { + if (!consumer.test(csq.charAt(index++))) { + break; + } + } + return index < csq.length(); + } + + @Override + protected int estimateSize() { + return csq.length(); + } + + @Override + public long count() { + return csq.length(); + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TCharSequenceCodePointsStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TCharSequenceCodePointsStream.java new file mode 100644 index 0000000000..3708f86cbe --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TCharSequenceCodePointsStream.java @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.util.stream.intimpl; + +import java.util.function.IntPredicate; +import org.teavm.classlib.java.lang.TCharSequence; +import org.teavm.classlib.java.lang.TCharacter; + +public class TCharSequenceCodePointsStream extends TSimpleIntStreamImpl { + private final TCharSequence csq; + private int index; + + public TCharSequenceCodePointsStream(TCharSequence csq) { + this.csq = csq; + } + + @Override + public boolean next(IntPredicate consumer) { + while (index < csq.length()) { + var hi = csq.charAt(index++); + if (TCharacter.isHighSurrogate(hi) && index < csq.length()) { + var lo = csq.charAt(index); + if (TCharacter.isLowSurrogate(lo)) { + ++index; + if (!consumer.test(TCharacter.toCodePoint(hi, lo))) { + break; + } + continue; + } + } + if (!consumer.test(hi)) { + break; + } + } + return index < csq.length(); + } + + @Override + protected int estimateSize() { + return csq.length(); + } + + @Override + public long count() { + return csq.length(); + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TStringCharsStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TStringCharsStream.java index 64debb2319..93ab8763f5 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TStringCharsStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TStringCharsStream.java @@ -15,7 +15,6 @@ */ package org.teavm.classlib.java.util.stream.intimpl; -import java.util.Objects; import java.util.function.IntPredicate; import org.teavm.classlib.java.lang.TString; @@ -24,7 +23,7 @@ public class TStringCharsStream extends TSimpleIntStreamImpl { private int index; public TStringCharsStream(TString string) { - this.string = Objects.requireNonNull(string); + this.string = string; } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TStringCodePointsStream.java b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TStringCodePointsStream.java new file mode 100644 index 0000000000..6ae2f78fd0 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/stream/intimpl/TStringCodePointsStream.java @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.util.stream.intimpl; + +import java.util.function.IntPredicate; +import org.teavm.classlib.java.lang.TCharacter; +import org.teavm.classlib.java.lang.TString; + +public class TStringCodePointsStream extends TSimpleIntStreamImpl { + private final TString string; + private int index; + + public TStringCodePointsStream(TString string) { + this.string = string; + } + + @Override + public boolean next(IntPredicate consumer) { + while (index < string.length()) { + var hi = string.charAt(index++); + if (TCharacter.isHighSurrogate(hi) && index < string.length()) { + var lo = string.charAt(index); + if (TCharacter.isLowSurrogate(lo)) { + ++index; + if (!consumer.test(TCharacter.toCodePoint(hi, lo))) { + break; + } + continue; + } + } + if (!consumer.test(hi)) { + break; + } + } + return index < string.length(); + } + + @Override + protected int estimateSize() { + return string.length(); + } + + @Override + public long count() { + return string.length(); + } +} diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java index 12e7a2d586..da81544c74 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java @@ -15,6 +15,7 @@ */ package org.teavm.classlib.java.lang; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import org.junit.Test; @@ -265,4 +266,22 @@ public void replace() { sb.replace(1, 1, "bc"); assertEquals("abcgh", sb.toString()); } + + @Test + public void charStream() { + assertEquals(0, new StringBuilder().chars().toArray().length); + assertArrayEquals(new int[] {'A', 'B', 'C', '1', '2', '3'}, new StringBuilder("ABC123").chars().toArray()); + } + + @Test + public void codePointsStream() { + assertEquals(0, "".codePoints().toArray().length); + assertArrayEquals(new int[] {'A', 'B', 'C', '1', '2', '3'}, new StringBuilder("ABC123").chars().toArray()); + + assertArrayEquals(new int[] { 969356 }, new StringBuilder().append(new char[] { (char) 56178, (char) 56972 }) + .codePoints().toArray()); + assertArrayEquals(new int[] { 56972, 56178 }, new StringBuilder().append( + new char[] { (char) 56972, (char) 56178 }).codePoints().toArray()); + assertArrayEquals(new int[] { 56178 }, new StringBuilder().append((char) 56178).codePoints().toArray()); + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/StringTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/StringTest.java index 5be2168a93..e62ae11ef7 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/StringTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/StringTest.java @@ -378,4 +378,16 @@ public void testChars() { assertEquals(0, "".chars().toArray().length); assertArrayEquals(new int[] {'A', 'B', 'C', '1', '2', '3'}, "ABC123".chars().toArray()); } + + @Test + public void codePointsStream() { + assertEquals(0, "".codePoints().toArray().length); + assertArrayEquals(new int[] {'A', 'B', 'C', '1', '2', '3'}, "ABC123".chars().toArray()); + + assertArrayEquals(new int[] { 969356 }, new String(new char[] { (char) 56178, (char) 56972 }) + .codePoints().toArray()); + assertArrayEquals(new int[] { 56972, 56178 }, new String(new char[] { (char) 56972, (char) 56178 }) + .codePoints().toArray()); + assertArrayEquals(new int[] { 56178 }, String.valueOf((char) 56178).codePoints().toArray()); + } }