using namespace icu::number::impl;
+namespace {
+
+/**
+ * Helper method to return whether the given AffixPatternMatcher equals the given pattern string.
+ * Either both arguments must be null or the pattern string inside the AffixPatternMatcher must equal
+ * the given pattern string.
+ */
+static bool matched(const AffixPatternMatcher* affix, const UnicodeString& patternString) {
+ return (affix == nullptr && patternString.isBogus()) ||
+ (affix != nullptr && affix->getPattern() == patternString);
+}
+
+/**
+ * Helper method to return the length of the given AffixPatternMatcher. Returns 0 for null.
+ */
+static int32_t length(const AffixPatternMatcher* matcher) {
+ return matcher == nullptr ? 0 : matcher->getPattern().length();
+}
+
+/**
+ * Helper method to return whether (1) both lhs and rhs are null/invalid, or (2) if they are both
+ * valid, whether they are equal according to operator==. Similar to Java Objects.equals()
+ */
+static bool equals(const AffixPatternMatcher* lhs, const AffixPatternMatcher* rhs) {
+ if (lhs == nullptr && rhs == nullptr) {
+ return true;
+ }
+ if (lhs == nullptr || rhs == nullptr) {
+ return false;
+ }
+ return *lhs == *rhs;
+}
+
+}
+
+
AffixPatternMatcherBuilder::AffixPatternMatcherBuilder(const UnicodeString& pattern,
AffixTokenMatcherWarehouse& warehouse,
IgnorablesMatcher* ignorables)
utils::copyCurrencyCode(this->currencyCode, currencyCode);
}
+AffixTokenMatcherWarehouse::AffixTokenMatcherWarehouse(
+ AffixTokenMatcherWarehouse&& src) U_NOEXCEPT = default;
+
AffixTokenMatcherWarehouse::~AffixTokenMatcherWarehouse() {
// Delete the variable number of batches of code point matchers
for (int32_t i = 0; i < codePointNumBatches; i++) {
}
-AffixMatcherWarehouse::AffixMatcherWarehouse(const AffixPatternProvider& patternInfo,
- NumberParserImpl& output,
- AffixTokenMatcherWarehouse& warehouse,
- const IgnorablesMatcher& ignorables, parse_flags_t parseFlags,
- UErrorCode& status)
- : fAffixTokenMatcherWarehouse(std::move(warehouse)) {
+AffixMatcherWarehouse::AffixMatcherWarehouse(AffixTokenMatcherWarehouse& warehouse)
+ : fAffixTokenMatcherWarehouse(std::move(warehouse)) {}
+
+AffixMatcherWarehouse& AffixMatcherWarehouse::operator=(AffixMatcherWarehouse&& src) = default;
+
+bool AffixMatcherWarehouse::isInteresting(const AffixPatternProvider& patternInfo,
+ const IgnorablesMatcher& ignorables, parse_flags_t parseFlags,
+ UErrorCode& status) {
+ UnicodeStringCharSequence posPrefixString(patternInfo.getString(AffixPatternProvider::AFFIX_POS_PREFIX));
+ UnicodeStringCharSequence posSuffixString(patternInfo.getString(AffixPatternProvider::AFFIX_POS_SUFFIX));
+ UnicodeStringCharSequence negPrefixString(UnicodeString(u""));
+ UnicodeStringCharSequence negSuffixString(UnicodeString(u""));
+ if (patternInfo.hasNegativeSubpattern()) {
+ negPrefixString = UnicodeStringCharSequence(patternInfo.getString(AffixPatternProvider::AFFIX_NEG_PREFIX));
+ negSuffixString = UnicodeStringCharSequence(patternInfo.getString(AffixPatternProvider::AFFIX_NEG_SUFFIX));
+ }
+
+ if (0 == (parseFlags & PARSE_FLAG_USE_FULL_AFFIXES) &&
+ AffixUtils::containsOnlySymbolsAndIgnorables(posPrefixString, *ignorables.getSet(), status) &&
+ AffixUtils::containsOnlySymbolsAndIgnorables(posSuffixString, *ignorables.getSet(), status) &&
+ AffixUtils::containsOnlySymbolsAndIgnorables(negPrefixString, *ignorables.getSet(), status) &&
+ AffixUtils::containsOnlySymbolsAndIgnorables(negSuffixString, *ignorables.getSet(), status)
+ // HACK: Plus and minus sign are a special case: we accept them trailing only if they are
+ // trailing in the pattern string.
+ && !AffixUtils::containsType(posSuffixString, TYPE_PLUS_SIGN, status) &&
+ !AffixUtils::containsType(posSuffixString, TYPE_MINUS_SIGN, status) &&
+ !AffixUtils::containsType(negSuffixString, TYPE_PLUS_SIGN, status) &&
+ !AffixUtils::containsType(negSuffixString, TYPE_MINUS_SIGN, status)) {
+ // The affixes contain only symbols and ignorables.
+ // No need to generate affix matchers.
+ return false;
+ }
+ return true;
+}
+
+AffixMatcherWarehouse AffixMatcherWarehouse::createAffixMatchers(const AffixPatternProvider& patternInfo,
+ MutableMatcherCollection& output,
+ AffixTokenMatcherWarehouse tokenWarehouse,
+ const IgnorablesMatcher& ignorables,
+ parse_flags_t parseFlags,
+ UErrorCode& status) {
if (!isInteresting(patternInfo, ignorables, parseFlags, status)) {
- return;
+ return {};
}
+ AffixMatcherWarehouse warehouse(tokenWarehouse);
+
// The affixes have interesting characters, or we are in strict mode.
// Use initial capacity of 6, the highest possible number of AffixMatchers.
UnicodeString sb;
bool hasPrefix = false;
PatternStringUtils::patternInfoToStringBuilder(
patternInfo, true, signum, signDisplay, StandardPlural::OTHER, false, sb);
- fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern(
- sb, warehouse, parseFlags, &hasPrefix, status);
- AffixPatternMatcher* prefix = hasPrefix ? &fAffixPatternMatchers[numAffixPatternMatchers++]
- : nullptr;
+ warehouse.fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern(
+ sb, tokenWarehouse, parseFlags, &hasPrefix, status);
+ AffixPatternMatcher* prefix = hasPrefix
+ ? &warehouse.fAffixPatternMatchers[numAffixPatternMatchers++]
+ : nullptr;
// Generate Suffix
bool hasSuffix = false;
PatternStringUtils::patternInfoToStringBuilder(
patternInfo, false, signum, signDisplay, StandardPlural::OTHER, false, sb);
- fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern(
- sb, warehouse, parseFlags, &hasSuffix, status);
- AffixPatternMatcher* suffix = hasSuffix ? &fAffixPatternMatchers[numAffixPatternMatchers++]
- : nullptr;
+ warehouse.fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern(
+ sb, tokenWarehouse, parseFlags, &hasSuffix, status);
+ AffixPatternMatcher* suffix = hasSuffix
+ ? &warehouse.fAffixPatternMatchers[numAffixPatternMatchers++]
+ : nullptr;
if (signum == 1) {
posPrefix = prefix;
// Note: it is indeed possible for posPrefix and posSuffix to both be null.
// We still need to add that matcher for strict mode to work.
- fAffixMatchers[numAffixMatchers++] = {prefix, suffix, flags};
+ warehouse.fAffixMatchers[numAffixMatchers++] = {prefix, suffix, flags};
if (includeUnpaired && prefix != nullptr && suffix != nullptr) {
// The following if statements are designed to prevent adding two identical matchers.
if (signum == 1 || equals(prefix, posPrefix)) {
- fAffixMatchers[numAffixMatchers++] = {prefix, nullptr, flags};
+ warehouse.fAffixMatchers[numAffixMatchers++] = {prefix, nullptr, flags};
}
if (signum == 1 || equals(suffix, posSuffix)) {
- fAffixMatchers[numAffixMatchers++] = {nullptr, suffix, flags};
+ warehouse.fAffixMatchers[numAffixMatchers++] = {nullptr, suffix, flags};
}
}
}
// Put the AffixMatchers in order, and then add them to the output.
- // TODO
-// Collections.sort(matchers, COMPARATOR);
-// output.addMatchers(matchers);
-}
-
-bool AffixMatcherWarehouse::isInteresting(const AffixPatternProvider& patternInfo,
- const IgnorablesMatcher& ignorables, parse_flags_t parseFlags,
- UErrorCode& status) {
- UnicodeStringCharSequence posPrefixString(patternInfo.getString(AffixPatternProvider::AFFIX_POS_PREFIX));
- UnicodeStringCharSequence posSuffixString(patternInfo.getString(AffixPatternProvider::AFFIX_POS_SUFFIX));
- UnicodeStringCharSequence negPrefixString(UnicodeString(u""));
- UnicodeStringCharSequence negSuffixString(UnicodeString(u""));
- if (patternInfo.hasNegativeSubpattern()) {
- negPrefixString = UnicodeStringCharSequence(patternInfo.getString(AffixPatternProvider::AFFIX_NEG_PREFIX));
- negSuffixString = UnicodeStringCharSequence(patternInfo.getString(AffixPatternProvider::AFFIX_NEG_SUFFIX));
- }
-
- if (0 == (parseFlags & PARSE_FLAG_USE_FULL_AFFIXES) &&
- AffixUtils::containsOnlySymbolsAndIgnorables(posPrefixString, *ignorables.getSet(), status) &&
- AffixUtils::containsOnlySymbolsAndIgnorables(posSuffixString, *ignorables.getSet(), status) &&
- AffixUtils::containsOnlySymbolsAndIgnorables(negPrefixString, *ignorables.getSet(), status) &&
- AffixUtils::containsOnlySymbolsAndIgnorables(negSuffixString, *ignorables.getSet(), status)
- // HACK: Plus and minus sign are a special case: we accept them trailing only if they are
- // trailing in the pattern string.
- && !AffixUtils::containsType(posSuffixString, TYPE_PLUS_SIGN, status) &&
- !AffixUtils::containsType(posSuffixString, TYPE_MINUS_SIGN, status) &&
- !AffixUtils::containsType(negSuffixString, TYPE_PLUS_SIGN, status) &&
- !AffixUtils::containsType(negSuffixString, TYPE_MINUS_SIGN, status)) {
- // The affixes contain only symbols and ignorables.
- // No need to generate affix matchers.
- return false;
+ // Since there are at most 9 elements, do a simple-to-implement bubble sort.
+ bool madeChanges;
+ do {
+ madeChanges = false;
+ for (int32_t i = 1; i < numAffixMatchers; i++) {
+ if (warehouse.fAffixMatchers[i - 1].compareTo(warehouse.fAffixMatchers[i]) > 0) {
+ madeChanges = true;
+ AffixMatcher temp = std::move(warehouse.fAffixMatchers[i - 1]);
+ warehouse.fAffixMatchers[i - 1] = std::move(warehouse.fAffixMatchers[i]);
+ warehouse.fAffixMatchers[i] = std::move(temp);
+ }
+ }
+ } while (madeChanges);
+ for (int32_t i = 0; i < numAffixMatchers; i++) {
+ output.addMatcher(warehouse.fAffixMatchers[i]);
}
- return true;
-}
-bool AffixMatcherWarehouse::equals(const AffixPatternMatcher* lhs, const AffixPatternMatcher* rhs) {
- if (lhs == nullptr && rhs == nullptr) {
- return true;
- }
- if (lhs == nullptr || rhs == nullptr) {
- return false;
- }
- return *lhs == *rhs;
+ return warehouse;
}
}
}
-bool AffixMatcher::matched(const AffixPatternMatcher* affix, const UnicodeString& patternString) {
- return (affix == nullptr && patternString.isBogus()) ||
- (affix != nullptr && affix->getPattern() == patternString);
+int8_t AffixMatcher::compareTo(const AffixMatcher& rhs) const {
+ const AffixMatcher& lhs = *this;
+ if (length(lhs.fPrefix) != length(rhs.fPrefix)) {
+ return length(lhs.fPrefix) > length(rhs.fPrefix) ? -1 : 1;
+ } else if (length(lhs.fSuffix) != length(rhs.fSuffix)) {
+ return length(lhs.fSuffix) > length(rhs.fSuffix) ? -1 : 1;
+ } else {
+ return 0;
+ }
}
const UnicodeString* currency2, const DecimalFormatSymbols* dfs,
IgnorablesMatcher* ignorables, const Locale* locale);
- AffixTokenMatcherWarehouse(AffixTokenMatcherWarehouse&& src) = default;
+ AffixTokenMatcherWarehouse(AffixTokenMatcherWarehouse&& src) U_NOEXCEPT;
~AffixTokenMatcherWarehouse();
};
-class AffixPatternMatcherBuilder : public TokenConsumer {
+class AffixPatternMatcherBuilder : public TokenConsumer, public MutableMatcherCollection {
public:
AffixPatternMatcherBuilder(const UnicodeString& pattern, AffixTokenMatcherWarehouse& warehouse,
IgnorablesMatcher* ignorables);
AffixTokenMatcherWarehouse& fWarehouse;
IgnorablesMatcher* fIgnorables;
- void addMatcher(NumberParseMatcher& matcher);
+ void addMatcher(NumberParseMatcher& matcher) override;
};
AffixMatcher(AffixPatternMatcher* prefix, AffixPatternMatcher* suffix, result_flags_t flags);
- // static void createMatchers() is the constructor for AffixMatcherWarehouse in C++
-
bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override;
void postProcess(ParsedNumber& result) const override;
const UnicodeSet& getLeadCodePoints() override;
+ int8_t compareTo(const AffixMatcher& rhs) const;
+
private:
AffixPatternMatcher* fPrefix;
AffixPatternMatcher* fSuffix;
result_flags_t fFlags;
-
- /**
- * Helper method to return whether the given AffixPatternMatcher equals the given pattern string.
- * Either both arguments must be null or the pattern string inside the AffixPatternMatcher must equal
- * the given pattern string.
- */
- static bool matched(const AffixPatternMatcher* affix, const UnicodeString& patternString);
};
public:
AffixMatcherWarehouse() = default; // WARNING: Leaves the object in an unusable state
- // in Java, this is AffixMatcher#createMatchers()
- AffixMatcherWarehouse(const AffixPatternProvider& patternInfo, NumberParserImpl& output,
- AffixTokenMatcherWarehouse& warehouse, const IgnorablesMatcher& ignorables,
- parse_flags_t parseFlags, UErrorCode& status);
+ AffixMatcherWarehouse(AffixTokenMatcherWarehouse& warehouse);
+
+ AffixMatcherWarehouse& operator=(AffixMatcherWarehouse&& src);
+
+ static AffixMatcherWarehouse createAffixMatchers(const AffixPatternProvider& patternInfo,
+ MutableMatcherCollection& output,
+ AffixTokenMatcherWarehouse tokenWarehouse,
+ const IgnorablesMatcher& ignorables,
+ parse_flags_t parseFlags, UErrorCode& status);
private:
// 9 is the limit: positive, zero, and negative, each with prefix, suffix, and prefix+suffix
// Store all the tokens used by the AffixPatternMatchers
AffixTokenMatcherWarehouse fAffixTokenMatcherWarehouse;
+ friend class AffixMatcher;
+
static bool isInteresting(const AffixPatternProvider& patternInfo, const IgnorablesMatcher& ignorables,
parse_flags_t parseFlags, UErrorCode& status);
-
- /**
- * Helper method to return whether (1) both lhs and rhs are null/invalid, or (2) if they are both
- * valid, whether they are equal according to operator==. Similar to Java Objects.equals()
- */
- static bool equals(const AffixPatternMatcher* lhs, const AffixPatternMatcher* rhs);
};