class DecimalMatcher : public NumberParseMatcher, public UMemory {
public:
+ DecimalMatcher() = default; // WARNING: Leaves the object in an unusable state
+
DecimalMatcher(const DecimalFormatSymbols& symbols, const Grouper& grouper,
parse_flags_t parseFlags);
auto* parser = new NumberParserImpl(parseFlags, true);
DecimalFormatSymbols symbols(locale, status);
- IgnorablesMatcher* ignorables = new IgnorablesMatcher(unisets::DEFAULT_IGNORABLES);
+ parser->fLocalMatchers.ignorables = {unisets::DEFAULT_IGNORABLES};
// MatcherFactory factory = new MatcherFactory();
// factory.currency = Currency.getInstance("USD");
Grouper grouper = Grouper::forStrategy(UNUM_GROUPING_AUTO);
grouper.setLocaleData(patternInfo, locale);
- parser->addAndAdoptMatcher(ignorables);
- parser->addAndAdoptMatcher(new DecimalMatcher(symbols, grouper, parseFlags));
- parser->addAndAdoptMatcher(new MinusSignMatcher(symbols, false));
- parser->addAndAdoptMatcher(new PlusSignMatcher(symbols, false));
- parser->addAndAdoptMatcher(new PercentMatcher(symbols));
- parser->addAndAdoptMatcher(new PermilleMatcher(symbols));
- parser->addAndAdoptMatcher(new NanMatcher(symbols));
+ parser->addMatcher(parser->fLocalMatchers.ignorables);
+ parser->addMatcher(parser->fLocalMatchers.decimal = {symbols, grouper, parseFlags});
+ parser->addMatcher(parser->fLocalMatchers.minusSign = {symbols, false});
+ parser->addMatcher(parser->fLocalMatchers.plusSign = {symbols, false});
+ parser->addMatcher(parser->fLocalMatchers.percent = {symbols});
+ parser->addMatcher(parser->fLocalMatchers.permille = {symbols});
+ parser->addMatcher(parser->fLocalMatchers.nan = {symbols});
// parser.addMatcher(ScientificMatcher.getInstance(symbols, grouper, parseFlags));
// parser.addMatcher(CurrencyTrieMatcher.getInstance(locale));
// parser.addMatcher(new RequireNumberMatcher());
}
NumberParserImpl::~NumberParserImpl() {
- for (int32_t i = 0; i < fNumMatchers; i++) {
- delete (fMatchers[i]);
- if (fComputeLeads) {
+ if (fComputeLeads) {
+ for (int32_t i = 0; i < fNumMatchers; i++) {
delete (fLeads[i]);
}
}
fNumMatchers = 0;
}
-void NumberParserImpl::addAndAdoptMatcher(const NumberParseMatcher* matcher) {
+void NumberParserImpl::addMatcher(const NumberParseMatcher& matcher) {
if (fNumMatchers + 1 > fMatchers.getCapacity()) {
fMatchers.resize(fNumMatchers * 2, fNumMatchers);
if (fComputeLeads) {
}
}
- fMatchers[fNumMatchers] = matcher;
+ fMatchers[fNumMatchers] = &matcher;
if (fComputeLeads) {
- fLeads[fNumMatchers] = matcher->getLeadCodePoints();
+ fLeads[fNumMatchers] = matcher.getLeadCodePoints();
}
fNumMatchers++;
return parse(input, 0, greedy, result, status);
}
-void
-NumberParserImpl::parse(const UnicodeString& input, int32_t start, bool greedy, ParsedNumber& result,
- UErrorCode& status) const {
+void NumberParserImpl::parse(const UnicodeString& input, int32_t start, bool greedy, ParsedNumber& result,
+ UErrorCode& status) const {
U_ASSERT(fFrozen);
// TODO: Check start >= 0 and start < input.length()
StringSegment segment(input, fParseFlags);
#define __NUMPARSE_IMPL_H__
#include "numparse_types.h"
+#include "numparse_decimal.h"
+#include "numparse_symbols.h"
#include "unicode/uniset.h"
U_NAMESPACE_BEGIN namespace numparse {
class NumberParserImpl {
public:
+ ~NumberParserImpl();
+
static NumberParserImpl* createSimpleParser(const Locale& locale, const UnicodeString& patternString,
parse_flags_t parseFlags, UErrorCode& status);
- void addAndAdoptMatcher(const NumberParseMatcher* matcher);
+ void addMatcher(const NumberParseMatcher& matcher);
void freeze();
bool fComputeLeads;
bool fFrozen = false;
- NumberParserImpl(parse_flags_t parseFlags, bool computeLeads);
+ // WARNING: All of these matchers start in an uninitialized state.
+ // You must use an assignment operator on them before using.
+ struct {
+ IgnorablesMatcher ignorables;
+ MinusSignMatcher minusSign;
+ NanMatcher nan;
+ PercentMatcher percent;
+ PermilleMatcher permille;
+ PlusSignMatcher plusSign;
+ DecimalMatcher decimal;
+ } fLocalMatchers;
- ~NumberParserImpl();
+ NumberParserImpl(parse_flags_t parseFlags, bool computeLeads);
void parseGreedyRecursive(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const;
class SymbolMatcher : public NumberParseMatcher, public UMemory {
public:
+ SymbolMatcher() = default; // WARNING: Leaves the object in an unusable state
+
const UnicodeSet* getSet();
bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override;
class IgnorablesMatcher : public SymbolMatcher {
public:
- explicit IgnorablesMatcher(unisets::Key key);
+ IgnorablesMatcher() = default; // WARNING: Leaves the object in an unusable state
+
+ IgnorablesMatcher(unisets::Key key);
bool isFlexible() const override;
class MinusSignMatcher : public SymbolMatcher {
public:
+ MinusSignMatcher() = default; // WARNING: Leaves the object in an unusable state
+
MinusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing);
protected:
class NanMatcher : public SymbolMatcher {
public:
- explicit NanMatcher(const DecimalFormatSymbols& dfs);
+ NanMatcher() = default; // WARNING: Leaves the object in an unusable state
+
+ NanMatcher(const DecimalFormatSymbols& dfs);
const UnicodeSet* getLeadCodePoints() const override;
class PercentMatcher : public SymbolMatcher {
public:
- explicit PercentMatcher(const DecimalFormatSymbols& dfs);
+ PercentMatcher() = default; // WARNING: Leaves the object in an unusable state
+
+ PercentMatcher(const DecimalFormatSymbols& dfs);
void postProcess(ParsedNumber& result) const override;
class PermilleMatcher : public SymbolMatcher {
public:
- explicit PermilleMatcher(const DecimalFormatSymbols& dfs);
+ PermilleMatcher() = default; // WARNING: Leaves the object in an unusable state
+
+ PermilleMatcher(const DecimalFormatSymbols& dfs);
void postProcess(ParsedNumber& result) const override;
class PlusSignMatcher : public SymbolMatcher {
public:
+ PlusSignMatcher() = default; // WARNING: Leaves the object in an unusable state
+
PlusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing);
protected:
namespace {
-UnicodeSet* gUnicodeSets[COUNT] = {};
+static UnicodeSet* gUnicodeSets[COUNT] = {};
UnicodeSet* computeUnion(Key k1, Key k2) {
UnicodeSet* result = new UnicodeSet();
icu::UInitOnce gNumberParseUniSetsInitOnce = U_INITONCE_INITIALIZER;
-UBool U_CALLCONV cleanupNumberParseUnitSets() {
+UBool U_CALLCONV cleanupNumberParseUniSets() {
for (int32_t i = 0; i < COUNT; i++) {
delete gUnicodeSets[i];
gUnicodeSets[i] = nullptr;
return TRUE;
}
-void U_CALLCONV initNumberParseUniSets(UErrorCode &status) {
- ucln_i18n_registerCleanup(UCLN_I18N_NUMPARSE_UNISETS, cleanupNumberParseUnitSets);
+void U_CALLCONV initNumberParseUniSets(UErrorCode& status) {
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMPARSE_UNISETS, cleanupNumberParseUniSets);
#define NEW_UNISET(pattern, status) new UnicodeSet(UnicodeString(pattern), status)
gUnicodeSets[EMPTY] = new UnicodeSet();
gUnicodeSets[WHITESPACE] = NEW_UNISET(u"[[:Zs:][\\u0009]]", status);
gUnicodeSets[DEFAULT_IGNORABLES] = computeUnion(BIDI, WHITESPACE);
- gUnicodeSets[STRICT_IGNORABLES] = gUnicodeSets[BIDI];
+ gUnicodeSets[STRICT_IGNORABLES] = new UnicodeSet(*gUnicodeSets[BIDI]);
// TODO: Re-generate these sets from the UCD. They probably haven't been updated in a while.
gUnicodeSets[COMMA] = NEW_UNISET(u"[,،٫、︐︑﹐﹑,、]", status);
gUnicodeSets[PERIOD] = NEW_UNISET(u"[.․。︒﹒.。]", status);
gUnicodeSets[STRICT_PERIOD] = NEW_UNISET(u"[.․﹒.。]", status);
gUnicodeSets[OTHER_GROUPING_SEPARATORS] = NEW_UNISET(
- u"['٬‘’'\\u0020\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]", status);
+ u"['٬‘’'\\u0020\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]",
+ status);
gUnicodeSets[ALL_SEPARATORS] = computeUnion(COMMA, PERIOD, OTHER_GROUPING_SEPARATORS);
gUnicodeSets[STRICT_ALL_SEPARATORS] = computeUnion(
STRICT_COMMA, STRICT_PERIOD, OTHER_GROUPING_SEPARATORS);
gUnicodeSets[INFINITY] = NEW_UNISET(u"[∞]", status);
gUnicodeSets[DIGITS] = NEW_UNISET(u"[:digit:]", status);
- gUnicodeSets[NAN_LEAD] = NEW_UNISET(
- u"[NnТтmeՈոс¤НнчTtsҳ\u975e\u1002\u0e9a\u10d0\u0f68\u0644\u0646]", status);
+ gUnicodeSets[NAN_LEAD] = NEW_UNISET(u"[NnТтmeՈոс¤НнчTtsҳ\u975e\u1002\u0e9a\u10d0\u0f68\u0644\u0646]",
+ status);
gUnicodeSets[SCIENTIFIC_LEAD] = NEW_UNISET(u"[Ee×·е\u0627]", status);
gUnicodeSets[CWCF] = NEW_UNISET(u"[:CWCF:]", status);
for (auto cas : cases) {
UnicodeString inputString(cas.inputString);
UnicodeString patternString(cas.patternString);
- const NumberParserImpl* parser = NumberParserImpl::createSimpleParser(
- Locale("en"), patternString, parseFlags, status);
+ LocalPointer<const NumberParserImpl> parser(
+ NumberParserImpl::createSimpleParser(
+ Locale("en"), patternString, parseFlags, status));
UnicodeString message =
UnicodeString("Input <") + inputString + UnicodeString("> Parser ") + parser->toString();
assertEquals(
"Greedy Parse failed: " + message, cas.expectedCharsConsumed, resultObject.charEnd);
assertEquals(
- "Greedy Parse failed: " + message,
- cas.expectedResultDouble,
- resultObject.getDouble());
+ "Greedy Parse failed: " + message, cas.expectedResultDouble, resultObject.getDouble());
}
if (0 != (cas.flags & 0x02)) {
if (0 != (cas.flags & 0x04)) {
// Test with strict separators
- parser = NumberParserImpl::createSimpleParser(
- Locale("en"), patternString, parseFlags | PARSE_FLAG_STRICT_GROUPING_SIZE, status);
+ parser.adoptInstead(
+ NumberParserImpl::createSimpleParser(
+ Locale("en"),
+ patternString,
+ parseFlags | PARSE_FLAG_STRICT_GROUPING_SIZE,
+ status));
ParsedNumber resultObject;
parser->parse(inputString, true, resultObject, status);
assertTrue("Strict Parse failed: " + message, resultObject.success());
assertEquals(
"Strict Parse failed: " + message, cas.expectedCharsConsumed, resultObject.charEnd);
assertEquals(
- "Strict Parse failed: " + message,
- cas.expectedResultDouble,
- resultObject.getDouble());
+ "Strict Parse failed: " + message, cas.expectedResultDouble, resultObject.getDouble());
}
}
}