diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java index d6d506e4c..1171babb1 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java @@ -83,6 +83,9 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug case "voidClass": context.getWriter().append("$rt_cls($rt_voidcls())"); break; + case "charClass": + context.getWriter().append("$rt_cls($rt_charcls())"); + break; case "wrap": context.writeExpr(context.getArgument(0)); break; @@ -172,6 +175,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug switch (graph.getReference().getName()) { case "booleanClass": case "intClass": + case "charClass": case "wrap": case "getSuperclass": case "getComponentType0": diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java index 3ace9acf6..bfe0e1845 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TCharacter.java @@ -28,8 +28,73 @@ import org.teavm.javascript.ni.Rename; public class TCharacter extends TObject { public static final int MIN_RADIX = 2; public static final int MAX_RADIX = 36; + public static final char MIN_VALUE = '\0'; + public static final char MAX_VALUE = '\uFFFF'; + public static final TClass TYPE = TClass.charClass(); + public static final byte UNASSIGNED = 0; + public static final byte UPPERCASE_LETTER = 1; + public static final byte LOWERCASE_LETTER = 2; + public static final byte TITLECASE_LETTER = 3; + public static final byte MODIFIER_LETTER = 4; + public static final byte OTHER_LETTER = 5; + public static final byte NON_SPACING_MARK = 6; + public static final byte ENCLOSING_MARK = 7; + public static final byte COMBINING_SPACING_MARK = 8; + public static final byte DECIMAL_DIGIT_NUMBER = 9; + public static final byte LETTER_NUMBER = 10; + public static final byte OTHER_NUMBER = 11; + public static final byte SPACE_SEPARATOR = 12; + public static final byte LINE_SEPARATOR = 13; + public static final byte PARAGRAPH_SEPARATOR = 14; + public static final byte CONTROL = 15; + public static final byte FORMAT = 16; + public static final byte PRIVATE_USE = 17; + public static final byte SURROGATE = 19; + public static final byte DASH_PUNCTUATION = 20; + public static final byte START_PUNCTUATION = 21; + public static final byte END_PUNCTUATION = 22; + public static final byte CONNECTOR_PUNCTUATION = 23; + public static final byte OTHER_PUNCTUATION = 24; + public static final byte MATH_SYMBOL = 25; + public static final byte CURRENCY_SYMBOL = 26; + public static final byte MODIFIER_SYMBOL = 27; + public static final byte OTHER_SYMBOL = 28; + public static final byte INITIAL_QUOTE_PUNCTUATION = 29; + public static final byte FINAL_QUOTE_PUNCTUATION = 30; + public static final byte DIRECTIONALITY_UNDEFINED = -1; + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = 0; + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = 1; + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2; + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = 3; + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4; + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5; + public static final byte DIRECTIONALITY_ARABIC_NUMBER = 6; + public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7; + public static final byte DIRECTIONALITY_NONSPACING_MARK = 8; + public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 9; + public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10; + public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = 11; + public static final byte DIRECTIONALITY_WHITESPACE = 12; + public static final byte DIRECTIONALITY_OTHER_NEUTRALS = 13; + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14; + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15; + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16; + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17; + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18; + public static final char MIN_HIGH_SURROGATE = '\uD800'; + public static final char MAX_HIGH_SURROGATE = '\uDBFF'; + public static final char MIN_LOW_SURROGATE = '\uDC00'; + public static final char MAX_LOW_SURROGATE = '\uDFFF'; + public static final char MIN_SURROGATE = MIN_HIGH_SURROGATE; + public static final char MAX_SURROGATE = MAX_LOW_SURROGATE; + public static final int MIN_SUPPLEMENTARY_CODE_POINT = 0x010000; + public static final int MIN_CODE_POINT = 0x000000; + public static final int MAX_CODE_POINT = 0X10FFFF; + public static final int SIZE = 16; + static final int ERROR = 0xFFFFFFFF; private static int[] digitMapping; private char value; + private static TCharacter[] characterCache = new TCharacter[128]; public TCharacter(char value) { this.value = value; @@ -40,13 +105,21 @@ public class TCharacter extends TObject { } public static TCharacter valueOf(char value) { + if (value < characterCache.length) { + TCharacter result = characterCache[value]; + if (result == null) { + result = new TCharacter(value); + characterCache[value] = result; + } + return result; + } return new TCharacter(value); } @Override @Rename("toString") public TString toString0() { - return new TString(new char[] { value }); + return toString(value); } @Override @@ -57,6 +130,100 @@ public class TCharacter extends TObject { return other instanceof TCharacter && ((TCharacter)other).value == value; } + @Override + public int hashCode() { + return value; + } + + public static TString toString(char c) { + return new TString(new char[] { c }); + } + + public static boolean isValidCodePoint(int codePoint) { + return codePoint >= 0 && codePoint <= MAX_CODE_POINT; + } + + public static boolean isBmpCodePoint(int codePoint) { + return codePoint > 0 && codePoint <= MAX_VALUE; + } + + public static boolean isSupplementaryCodePoint(int codePoint) { + return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT && codePoint <= MAX_CODE_POINT; + } + + public static boolean isHighSurrogate(char ch) { + return UTF16Helper.isHighSurrogate(ch); + } + + public static boolean isLowSurrogate(char ch) { + return UTF16Helper.isLowSurrogate(ch); + } + + public static boolean isSurrogate(char ch) { + return isHighSurrogate(ch) || isLowSurrogate(ch); + } + + public static boolean isSurrogatePair(char high, char low) { + return isHighSurrogate(high) && isLowSurrogate(low); + } + + public static int charCount(int codePoint) { + return isSupplementaryCodePoint(codePoint) ? 2 : 1; + } + + public static int toCodePoint(char high, char low) { + return UTF16Helper.buildCodePoint(high, low); + } + + public static int codePointAt(TCharSequence seq, int index) { + if (index >= seq.length() - 1 || !isHighSurrogate(seq.charAt(index)) || + !isLowSurrogate(seq.charAt(index + 1))) { + return seq.charAt(index); + } else { + return toCodePoint(seq.charAt(index), seq.charAt(index + 1)); + } + } + + public static int codePointAt(char[] a, int index) { + return codePointAt(a, index, a.length); + } + + public static int codePointAt(char[] a, int index, int limit) { + if (index >= limit - 1 || !isHighSurrogate(a[index]) || !isLowSurrogate(a[index + 1])) { + return a[index]; + } else { + return toCodePoint(a[index], a[index + 1]); + } + } + + public static int codePointBefore(TCharSequence seq, int index) { + if (index == 0 || !isLowSurrogate(seq.charAt(index)) || !isHighSurrogate(seq.charAt(index - 1))) { + return seq.charAt(index); + } else { + return toCodePoint(seq.charAt(index - 1), seq.charAt(index)); + } + } + + public static int codePointBefore(char[] a, int index) { + return codePointBefore(a, index, 0); + } + + public static int codePointBefore(char[] a, int index, int start) { + if (index <= start || !isLowSurrogate(a[index]) || !isHighSurrogate(a[index - 1])) { + return a[index]; + } else { + return toCodePoint(a[index - 1], a[index]); + } + } + + public static char highSurrogate(int codePoint) { + return UTF16Helper.highSurrogate(codePoint); + } + + public static char lowSurrogate(int codePoint) { + return UTF16Helper.lowSurrogate(codePoint); + } + @GeneratedBy(CharacterNativeGenerator.class) public static native char toLowerCase(char ch); @@ -138,6 +305,54 @@ public class TCharacter extends TObject { } } + public static int codePointCount(TCharSequence seq, int beginIndex, int endIndex) { + int count = endIndex; + --endIndex; + for (int i = beginIndex; i < endIndex; ++i) { + if (UTF16Helper.isHighSurrogate(seq.charAt(i)) && UTF16Helper.isLowSurrogate(seq.charAt(i + 1))) { + --count; + ++i; + } + } + return count; + } + + public static int codePointCount(char[] a, int offset, int count) { + int r = count; + --count; + for (int i = 0; i < count; ++i) { + if (UTF16Helper.isHighSurrogate(a[offset]) && UTF16Helper.isLowSurrogate(a[offset + i + 1])) { + --r; + ++i; + } + } + return r; + } + + public static int offsetByCodePoints(TCharSequence seq, int index, int codePointOffset) { + for (int i = 0; i < codePointOffset; ++i) { + if (index < seq.length() - 1 && UTF16Helper.isHighSurrogate(seq.charAt(index)) && + UTF16Helper.isLowSurrogate(seq.charAt(index + 1))) { + index += 2; + } else { + index++; + } + } + return index; + } + + public static int offsetByCodePoints(char[] a, int start, int count, int index, int codePointOffset) { + for (int i = 0; i < codePointOffset; ++i) { + if (index < count - 1 && UTF16Helper.isHighSurrogate(a[index + start]) && + UTF16Helper.isLowSurrogate(a[index + start + 1])) { + index += 2; + } else { + index++; + } + } + return index; + } + public static boolean isISOControl(char ch) { return isISOControl((int)ch); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 94139507b..e26b9dcbc 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -73,6 +73,10 @@ public class TClass extends TObject { @PluggableDependency(ClassNativeGenerator.class) static native TClass booleanClass(); + @InjectedBy(ClassNativeGenerator.class) + @PluggableDependency(ClassNativeGenerator.class) + static native TClass charClass(); + @InjectedBy(ClassNativeGenerator.class) @PluggableDependency(ClassNativeGenerator.class) static native TClass intClass(); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java index 664075ae6..0f4320526 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java @@ -118,42 +118,19 @@ public class TString extends TObject implements TSerializable, TComparable