From: Shane Carr Date: Wed, 28 Feb 2018 05:42:11 +0000 (+0000) Subject: ICU-13613 Move Java StringSegment to com.ibm.icu.impl. X-Git-Tag: release-61-rc~44 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f616fca69b31793a1fe2eaa44ed38ca6ce9397ce;p=icu ICU-13613 Move Java StringSegment to com.ibm.icu.impl. X-SVN-Rev: 41003 --- diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/StringSegment.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java similarity index 66% rename from icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/StringSegment.java rename to icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java index eb2b27bc8ee..138abe82392 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/StringSegment.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java @@ -1,13 +1,17 @@ // © 2017 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html#License -package com.ibm.icu.impl.number.parse; +package com.ibm.icu.impl; import com.ibm.icu.lang.UCharacter; import com.ibm.icu.text.UnicodeSet; /** - * A mutable class allowing for a String with a variable offset and length. The charAt, length, and - * subSequence methods all operate relative to the fixed offset into the String. + * A mutable String wrapper with a variable offset and length and support for case folding. + *

+ * The charAt, length, and subSequence methods all operate relative to the fixed offset into the String. + *

+ * CAUTION: Since this class is mutable, it must not be used anywhere that an immutable object is + * required, like in a cache or as the key of a hash map. * * @author sffc */ @@ -17,11 +21,11 @@ public class StringSegment implements CharSequence { private int end; private boolean foldCase; - public StringSegment(String str, int parseFlags) { + public StringSegment(String str, boolean foldCase) { this.str = str; this.start = 0; this.end = str.length(); - this.foldCase = 0 != (parseFlags & ParsingUtils.PARSE_FLAG_IGNORE_CASE); + this.foldCase = foldCase; } public int getOffset() { @@ -37,9 +41,10 @@ public class StringSegment implements CharSequence { * Equivalent to setOffset(getOffset()+delta). * *

- * This method is usually called by a Matcher to register that a char was consumed. If the char is - * strong (it usually is, except for things like whitespace), follow this with a call to - * {@link ParsedNumber#setCharsConsumed}. For more information on strong chars, see that method. + * Number parsing note: This method is usually called by a Matcher to register that a char was + * consumed. If the char is strong (it usually is, except for things like whitespace), follow this + * with a call to ParsedNumber#setCharsConsumed(). For more information on strong chars, see that + * method. */ public void adjustOffset(int delta) { assert start + delta >= 0; @@ -48,7 +53,7 @@ public class StringSegment implements CharSequence { } /** - * Adjusts the offset by the width of the current code point, either 1 or 2 chars. + * Adjusts the offset by the width of the current lead code point, either 1 or 2 chars. */ public void adjustOffsetByCodePoint() { start += Character.charCount(getCodePoint()); @@ -86,8 +91,8 @@ public class StringSegment implements CharSequence { * code point. * *

- * Important: Most of the time, you should use {@link #matches}, which handles case - * folding logic, instead of this method. + * Important: Most of the time, you should use {@link #startsWith}, which handles + * case folding logic, instead of this method. */ public int getCodePoint() { assert start < end; @@ -107,14 +112,14 @@ public class StringSegment implements CharSequence { *

* This method will perform case folding if case folding is enabled for the parser. */ - public boolean matches(int otherCp) { + public boolean startsWith(int otherCp) { return codePointsEqual(getCodePoint(), otherCp, foldCase); } /** * Returns true if the first code point of this StringSegment is in the given UnicodeSet. */ - public boolean matches(UnicodeSet uniset) { + public boolean startsWith(UnicodeSet uniset) { // TODO: Move UnicodeSet case-folding logic here. // TODO: Handle string matches here instead of separately. int cp = getCodePoint(); @@ -130,15 +135,18 @@ public class StringSegment implements CharSequence { * since the first 2 characters are the same. * *

- * This method will perform case folding if case folding is enabled for the parser. + * This method only returns offsets along code point boundaries. + * + *

+ * This method will perform case folding if case folding was enabled in the constructor. */ public int getCommonPrefixLength(CharSequence other) { return getPrefixLengthInternal(other, foldCase); } /** - * Like {@link #getCommonPrefixLength}, but never performs case folding, even if case folding is - * enabled for the parser. + * Like {@link #getCommonPrefixLength}, but never performs case folding, even if case folding was + * enabled in the constructor. */ public int getCaseSensitivePrefixLength(CharSequence other) { return getPrefixLengthInternal(other, false); @@ -147,29 +155,16 @@ public class StringSegment implements CharSequence { private int getPrefixLengthInternal(CharSequence other, boolean foldCase) { int offset = 0; for (; offset < Math.min(length(), other.length());) { - // TODO: case-fold code points, not chars - char c1 = charAt(offset); - char c2 = other.charAt(offset); - if (!codePointsEqual(c1, c2, foldCase)) { + int cp1 = Character.codePointAt(this, offset); + int cp2 = Character.codePointAt(other, offset); + if (!codePointsEqual(cp1, cp2, foldCase)) { break; } - offset++; + offset += Character.charCount(cp1); } return offset; } - // /** - // * Case-folds the string if IGNORE_CASE flag is set; otherwise, returns the same string. - // */ - // public static String maybeFold(String input, int parseFlags) { - // UnicodeSet cwcf = UnicodeSetStaticCache.get(UnicodeSetStaticCache.Key.CWCF); - // if (0 != (parseFlags & ParsingUtils.PARSE_FLAG_IGNORE_CASE) && cwcf.containsSome(input)) { - // return UCharacter.foldCase(input, true); - // } else { - // return input; - // } - // } - private static final boolean codePointsEqual(int cp1, int cp2, boolean foldCase) { if (cp1 == cp2) { return true; @@ -182,6 +177,26 @@ public class StringSegment implements CharSequence { return cp1 == cp2; } + /** + * Equals any CharSequence with the same chars as this segment. + * + *

+ * This method does not perform case folding; if you want case-insensitive equality, use + * {@link #getCommonPrefixLength}. + */ + @Override + public boolean equals(Object other) { + if (!(other instanceof CharSequence)) + return false; + return Utility.charSequenceEquals(this, (CharSequence) other); + } + + /** Returns a hash code equivalent to calling .toString().hashCode() */ + @Override + public int hashCode() { + return Utility.charSequenceHashCode(this); + } + @Override public String toString() { return str.substring(0, start) + "[" + str.substring(start, end) + "]" + str.substring(end); diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/Utility.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/Utility.java index 111e898152a..db10b2569d1 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/Utility.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/Utility.java @@ -1863,4 +1863,36 @@ public final class Utility { } return r; } + + /** + * Returns whether the chars in the two CharSequences are equal. + */ + public static boolean charSequenceEquals(CharSequence a, CharSequence b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a.length() != b.length()) { + return false; + } + for (int i = 0; i < a.length(); i++) { + if (a.charAt(i) != b.charAt(i)) + return false; + } + return true; + } + + /** + * Returns a hash code for a CharSequence that is equivalent to calling + * charSequence.toString().hashCode() + */ + public static int charSequenceHashCode(CharSequence value) { + int hash = 0; + for (int i = 0; i < value.length(); i++) { + hash = hash * 31 + value.charAt(i); + } + return hash; + } } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AffixMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AffixMatcher.java index 58bf69ac7d2..87446367132 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AffixMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AffixMatcher.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.Comparator; import com.ibm.icu.impl.StandardPlural; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.impl.Utility; import com.ibm.icu.impl.number.AffixPatternProvider; import com.ibm.icu.impl.number.AffixUtils; diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AnyMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AnyMatcher.java index 3470fa22b73..005f8cc9b5f 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AnyMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AnyMatcher.java @@ -5,6 +5,7 @@ package com.ibm.icu.impl.number.parse; import java.util.ArrayList; import java.util.List; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CodePointMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CodePointMatcher.java index 8a0b7b9beb4..afa6f68a661 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CodePointMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CodePointMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; /** @@ -24,7 +25,7 @@ public class CodePointMatcher implements NumberParseMatcher { @Override public boolean match(StringSegment segment, ParsedNumber result) { - if (segment.matches(cp)) { + if (segment.startsWith(cp)) { segment.adjustOffsetByCodePoint(); result.setCharsConsumed(segment); } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CurrencyMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CurrencyMatcher.java index d81c2e9f81a..f3c01e4e2a4 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CurrencyMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CurrencyMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; import com.ibm.icu.util.Currency; import com.ibm.icu.util.ULocale; diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CurrencyTrieMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CurrencyTrieMatcher.java index 239949ec13d..3763059f55c 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CurrencyTrieMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CurrencyTrieMatcher.java @@ -4,6 +4,7 @@ package com.ibm.icu.impl.number.parse; import java.util.Iterator; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.impl.TextTrieMap; import com.ibm.icu.text.UnicodeSet; import com.ibm.icu.util.Currency; diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/DecimalMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/DecimalMatcher.java index b965263af1a..6eea11ed849 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/DecimalMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/DecimalMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD; import com.ibm.icu.impl.number.Grouper; import com.ibm.icu.impl.number.parse.UnicodeSetStaticCache.Key; diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/IgnorablesMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/IgnorablesMatcher.java index 125dd1078fe..190396bd128 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/IgnorablesMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/IgnorablesMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/InfinityMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/InfinityMatcher.java index 843a1c7db1f..ecf816a53e6 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/InfinityMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/InfinityMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.DecimalFormatSymbols; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/MinusSignMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/MinusSignMatcher.java index d011986aa40..08e9d1a9ecc 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/MinusSignMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/MinusSignMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.DecimalFormatSymbols; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NanMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NanMatcher.java index c5b01255e98..f78d0e80d1b 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NanMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NanMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.DecimalFormatSymbols; import com.ibm.icu.text.UnicodeSet; diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParseMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParseMatcher.java index 1d576cee2cc..bd772cace22 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParseMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParseMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java index 3db8b782aec..451044c670a 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java @@ -8,6 +8,7 @@ import java.util.Collection; import java.util.Comparator; import java.util.List; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.impl.number.AffixPatternProvider; import com.ibm.icu.impl.number.CustomSymbolCurrency; import com.ibm.icu.impl.number.DecimalFormatProperties; @@ -380,7 +381,8 @@ public class NumberParserImpl { public void parse(String input, int start, boolean greedy, ParsedNumber result) { assert frozen; assert start >= 0 && start < input.length(); - StringSegment segment = new StringSegment(input, parseFlags); + StringSegment segment = new StringSegment(input, + 0 != (parseFlags & ParsingUtils.PARSE_FLAG_IGNORE_CASE)); segment.adjustOffset(start); if (greedy) { parseGreedyRecursive(segment, result); diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PaddingMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PaddingMatcher.java index 64c17d79b6a..51c36b1fe35 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PaddingMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PaddingMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java index 27ce15df1f6..e968e6c3473 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java @@ -5,6 +5,7 @@ package com.ibm.icu.impl.number.parse; import java.math.BigDecimal; import java.util.Comparator; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PercentMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PercentMatcher.java index 624363b2442..afac0a6f721 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PercentMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PercentMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.DecimalFormatSymbols; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PermilleMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PermilleMatcher.java index 64d297d029b..d28e96b8e48 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PermilleMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PermilleMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.DecimalFormatSymbols; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PlusSignMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PlusSignMatcher.java index 598bd159804..d7b94110612 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PlusSignMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PlusSignMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.DecimalFormatSymbols; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ScientificMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ScientificMatcher.java index 329ee12ba6f..a6656542baa 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ScientificMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ScientificMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.impl.number.Grouper; import com.ibm.icu.text.DecimalFormatSymbols; import com.ibm.icu.text.UnicodeSet; @@ -47,10 +48,10 @@ public class ScientificMatcher implements NumberParseMatcher { // Allow a sign, and then try to match digits. boolean minusSign = false; - if (segment.matches(UnicodeSetStaticCache.get(UnicodeSetStaticCache.Key.MINUS_SIGN))) { + if (segment.startsWith(UnicodeSetStaticCache.get(UnicodeSetStaticCache.Key.MINUS_SIGN))) { minusSign = true; segment.adjustOffsetByCodePoint(); - } else if (segment.matches(UnicodeSetStaticCache.get(UnicodeSetStaticCache.Key.PLUS_SIGN))) { + } else if (segment.startsWith(UnicodeSetStaticCache.get(UnicodeSetStaticCache.Key.PLUS_SIGN))) { segment.adjustOffsetByCodePoint(); } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/SeriesMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/SeriesMatcher.java index 7f8f6704b07..8c8c67f573c 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/SeriesMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/SeriesMatcher.java @@ -5,6 +5,7 @@ package com.ibm.icu.impl.number.parse; import java.util.ArrayList; import java.util.List; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/SymbolMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/SymbolMatcher.java index bf15d726b7a..77a5f8fedbd 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/SymbolMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/SymbolMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; /** @@ -47,7 +48,7 @@ public abstract class SymbolMatcher implements NumberParseMatcher { } } - if (segment.matches(uniSet)) { + if (segment.startsWith(uniSet)) { segment.adjustOffsetByCodePoint(); accept(segment, result); return false; diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ValidationMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ValidationMatcher.java index bfe5a6b5491..913dcf83a1c 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ValidationMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ValidationMatcher.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number.parse; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.text.UnicodeSet; /** diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/StringSegmentTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/impl/StringSegmentTest.java similarity index 88% rename from icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/StringSegmentTest.java rename to icu4j/main/tests/core/src/com/ibm/icu/dev/test/impl/StringSegmentTest.java index 833df6537e9..3434f6454a3 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/StringSegmentTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/impl/StringSegmentTest.java @@ -1,12 +1,12 @@ // © 2017 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html#License -package com.ibm.icu.dev.test.number; +package com.ibm.icu.dev.test.impl; import static org.junit.Assert.assertEquals; import org.junit.Test; -import com.ibm.icu.impl.number.parse.StringSegment; +import com.ibm.icu.impl.StringSegment; /** * @author sffc @@ -17,9 +17,11 @@ public class StringSegmentTest { @Test public void testOffset() { - StringSegment segment = new StringSegment(SAMPLE_STRING, 0); + StringSegment segment = new StringSegment(SAMPLE_STRING, false); assertEquals(0, segment.getOffset()); - segment.adjustOffset(3); + segment.adjustOffsetByCodePoint(); + assertEquals(2, segment.getOffset()); + segment.adjustOffset(1); assertEquals(3, segment.getOffset()); segment.adjustOffset(2); assertEquals(5, segment.getOffset()); @@ -29,7 +31,7 @@ public class StringSegmentTest { @Test public void testLength() { - StringSegment segment = new StringSegment(SAMPLE_STRING, 0); + StringSegment segment = new StringSegment(SAMPLE_STRING, false); assertEquals(11, segment.length()); segment.adjustOffset(3); assertEquals(8, segment.length()); @@ -43,7 +45,7 @@ public class StringSegmentTest { @Test public void testCharAt() { - StringSegment segment = new StringSegment(SAMPLE_STRING, 0); + StringSegment segment = new StringSegment(SAMPLE_STRING, false); assertCharSequenceEquals(SAMPLE_STRING, segment); segment.adjustOffset(3); assertCharSequenceEquals("radio 📻", segment); @@ -53,7 +55,7 @@ public class StringSegmentTest { @Test public void testGetCodePoint() { - StringSegment segment = new StringSegment(SAMPLE_STRING, 0); + StringSegment segment = new StringSegment(SAMPLE_STRING, false); assertEquals(0x1F4FB, segment.getCodePoint()); segment.setLength(1); assertEquals(0xD83D, segment.getCodePoint()); @@ -66,18 +68,20 @@ public class StringSegmentTest { @Test public void testCommonPrefixLength() { - StringSegment segment = new StringSegment(SAMPLE_STRING, 0); + StringSegment segment = new StringSegment(SAMPLE_STRING, true); assertEquals(11, segment.getCommonPrefixLength(SAMPLE_STRING)); assertEquals(4, segment.getCommonPrefixLength("📻 r")); assertEquals(3, segment.getCommonPrefixLength("📻 x")); assertEquals(0, segment.getCommonPrefixLength("x")); assertEquals(0, segment.getCommonPrefixLength("")); segment.adjustOffset(3); - assertEquals(0, segment.getCommonPrefixLength("RADiO")); + assertEquals(5, segment.getCommonPrefixLength("raDio")); assertEquals(5, segment.getCommonPrefixLength("radio")); assertEquals(2, segment.getCommonPrefixLength("rafio")); assertEquals(0, segment.getCommonPrefixLength("fadio")); assertEquals(0, segment.getCommonPrefixLength("")); + assertEquals(5, segment.getCaseSensitivePrefixLength("radio")); + assertEquals(2, segment.getCaseSensitivePrefixLength("raDio")); segment.setLength(3); assertEquals(3, segment.getCommonPrefixLength("radio")); assertEquals(2, segment.getCommonPrefixLength("rafio")); diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberParserTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberParserTest.java index 70513ce5f1a..04b3d7c5abc 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberParserTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberParserTest.java @@ -8,6 +8,7 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; +import com.ibm.icu.impl.StringSegment; import com.ibm.icu.impl.number.DecimalFormatProperties; import com.ibm.icu.impl.number.parse.IgnorablesMatcher; import com.ibm.icu.impl.number.parse.MinusSignMatcher; @@ -17,7 +18,6 @@ import com.ibm.icu.impl.number.parse.ParsingUtils; import com.ibm.icu.impl.number.parse.PercentMatcher; import com.ibm.icu.impl.number.parse.PlusSignMatcher; import com.ibm.icu.impl.number.parse.SeriesMatcher; -import com.ibm.icu.impl.number.parse.StringSegment; import com.ibm.icu.impl.number.parse.UnicodeSetStaticCache; import com.ibm.icu.impl.number.parse.UnicodeSetStaticCache.Key; import com.ibm.icu.text.DecimalFormatSymbols; @@ -192,7 +192,7 @@ public class NumberParserTest { int expectedOffset = (Integer) cas[1]; boolean expectedMaybeMore = (Boolean) cas[2]; - StringSegment segment = new StringSegment(input, 0); + StringSegment segment = new StringSegment(input, false); ParsedNumber result = new ParsedNumber(); boolean actualMaybeMore = series.match(segment, result); int actualOffset = segment.getOffset(); diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/UtilityTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/UtilityTest.java index 708c61103be..7cfc9815e6c 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/UtilityTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/UtilityTest.java @@ -15,6 +15,7 @@ package com.ibm.icu.dev.test.util; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Random; import java.util.Set; import org.junit.Test; @@ -249,4 +250,45 @@ public class UtilityTest extends TestFmwk { public String CheckSourceLocale() { return TestFmwk.sourceLocation(); } + + static final String RANDOM_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + static final Random RANDOM = new Random(2018); + + @Test + public void TestCharSequenceEqualsAndHashCode() { + for (int t=0; t<1000; t++) { + int length = RANDOM.nextInt(5); + CharSequence a = randomCharSequence(length); + CharSequence b = randomCharSequence(length); + CharSequence c = randomCharSequence(length + 3); + String message = "a=" + a + "; b=" + b + "; c=" + c; + + assertTrue(message, Utility.charSequenceEquals(a, a)); + assertFalse(message, Utility.charSequenceEquals(a, c)); + assertTrue(message, Utility.charSequenceEquals(b, b)); + assertFalse(message, Utility.charSequenceEquals(b, c)); + assertFalse(message, Utility.charSequenceEquals(c, a)); + assertFalse(message, Utility.charSequenceEquals(c, b)); + assertTrue(message, Utility.charSequenceEquals(c, c)); + if (length == 0 || a.toString().equals(b.toString())) { + assertTrue(message, Utility.charSequenceEquals(a, b)); + assertTrue(message, Utility.charSequenceEquals(b, a)); + } else { + assertFalse(message, Utility.charSequenceEquals(a, b)); + assertFalse(message, Utility.charSequenceEquals(b, a)); + } + + assertEquals(message, Utility.charSequenceHashCode(a), a.toString().hashCode()); + assertEquals(message, Utility.charSequenceHashCode(b), b.toString().hashCode()); + assertEquals(message, Utility.charSequenceHashCode(c), c.toString().hashCode()); + } + } + + private CharSequence randomCharSequence(int length) { + StringBuilder sb = new StringBuilder(); + for (int i=0; i