From 538acead6670d711ddb71c0b852089b792c996e3 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Mon, 9 Jul 2018 13:46:16 -0700 Subject: deps: icu 62.1 bump (Unicode 11, CLDR 33.1) - Full release notes: http://site.icu-project.org/download/62 Fixes: https://github.com/nodejs/node/issues/21452 PR-URL: https://github.com/nodejs/node/pull/21728 Reviewed-By: James M Snell Reviewed-By: Bradley Farias Reviewed-By: Gus Caplan Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Richard Lau --- deps/icu-small/README-SMALL-ICU.txt | 4 +- deps/icu-small/source/common/charstr.cpp | 12 + deps/icu-small/source/common/charstr.h | 12 + deps/icu-small/source/common/cmemory.h | 45 +- deps/icu-small/source/common/edits.cpp | 29 +- deps/icu-small/source/common/locmap.cpp | 2 +- deps/icu-small/source/common/norm2_nfc_data.h | 1219 ++-- deps/icu-small/source/common/propname_data.h | 1744 +++--- deps/icu-small/source/common/putil.cpp | 22 + deps/icu-small/source/common/putilimp.h | 26 + deps/icu-small/source/common/rbbi.cpp | 112 +- deps/icu-small/source/common/rbbi_cache.cpp | 49 +- deps/icu-small/source/common/rbbidata.cpp | 41 - deps/icu-small/source/common/rbbidata.h | 8 +- deps/icu-small/source/common/rbbirb.cpp | 194 +- deps/icu-small/source/common/rbbirb.h | 23 +- deps/icu-small/source/common/rbbiscan.cpp | 18 +- deps/icu-small/source/common/rbbisetb.cpp | 12 +- deps/icu-small/source/common/rbbisetb.h | 8 +- deps/icu-small/source/common/rbbitblb.cpp | 345 +- deps/icu-small/source/common/rbbitblb.h | 77 +- deps/icu-small/source/common/serv.cpp | 3 +- .../source/common/static_unicode_sets.cpp | 222 + deps/icu-small/source/common/static_unicode_sets.h | 119 + deps/icu-small/source/common/ubidi_props_data.h | 1315 +++-- deps/icu-small/source/common/ucase.cpp | 53 +- deps/icu-small/source/common/ucase.h | 18 +- deps/icu-small/source/common/ucase_props_data.h | 1503 ++--- deps/icu-small/source/common/uchar_props_data.h | 6193 ++++++++++---------- deps/icu-small/source/common/ucln_cmn.h | 1 + deps/icu-small/source/common/ucnv_bld.cpp | 11 +- deps/icu-small/source/common/ucnv_bld.h | 3 + deps/icu-small/source/common/ucurr.cpp | 189 +- deps/icu-small/source/common/ucurrimp.h | 17 + deps/icu-small/source/common/unicode/brkiter.h | 2 +- .../source/common/unicode/bytestriebuilder.h | 2 +- deps/icu-small/source/common/unicode/caniter.h | 4 +- deps/icu-small/source/common/unicode/docmain.h | 2 +- deps/icu-small/source/common/unicode/edits.h | 150 +- deps/icu-small/source/common/unicode/platform.h | 14 - deps/icu-small/source/common/unicode/rbbi.h | 24 +- deps/icu-small/source/common/unicode/uchar.h | 45 +- deps/icu-small/source/common/unicode/unistr.h | 6 +- deps/icu-small/source/common/unicode/urename.h | 13 + deps/icu-small/source/common/unicode/uscript.h | 17 +- deps/icu-small/source/common/unicode/utypes.h | 5 +- deps/icu-small/source/common/unicode/uvernum.h | 10 +- deps/icu-small/source/common/uprops.cpp | 1 + deps/icu-small/source/common/uprops.h | 6 +- deps/icu-small/source/common/uscript_props.cpp | 9 +- deps/icu-small/source/common/ustr_cnv.cpp | 3 +- deps/icu-small/source/common/util.h | 7 + deps/icu-small/source/common/utypes.cpp | 3 +- deps/icu-small/source/common/wintz.cpp | 28 +- deps/icu-small/source/data/in/icudt61l.dat | Bin 2795984 -> 0 bytes deps/icu-small/source/data/in/icudt62l.dat | Bin 0 -> 2808160 bytes deps/icu-small/source/i18n/affixpatternparser.cpp | 698 --- deps/icu-small/source/i18n/affixpatternparser.h | 402 -- deps/icu-small/source/i18n/collationfcd.cpp | 98 +- .../icu-small/source/i18n/compactdecimalformat.cpp | 1018 +--- deps/icu-small/source/i18n/currpinf.cpp | 3 + deps/icu-small/source/i18n/currunit.cpp | 33 +- deps/icu-small/source/i18n/dcfmtimp.h | 54 - deps/icu-small/source/i18n/dcfmtsym.cpp | 10 +- deps/icu-small/source/i18n/decfmtst.cpp | 251 - deps/icu-small/source/i18n/decfmtst.h | 69 - .../icu-small/source/i18n/decimalformatpattern.cpp | 656 --- deps/icu-small/source/i18n/decimalformatpattern.h | 106 - .../source/i18n/decimalformatpatternimpl.h | 35 - deps/icu-small/source/i18n/decimfmt.cpp | 4030 ++++--------- deps/icu-small/source/i18n/decimfmtimpl.cpp | 1596 ----- deps/icu-small/source/i18n/decimfmtimpl.h | 549 -- deps/icu-small/source/i18n/digitaffix.cpp | 109 - deps/icu-small/source/i18n/digitaffix.h | 104 - .../source/i18n/digitaffixesandpadding.cpp | 175 - .../icu-small/source/i18n/digitaffixesandpadding.h | 179 - deps/icu-small/source/i18n/digitformatter.cpp | 417 -- deps/icu-small/source/i18n/digitformatter.h | 288 - deps/icu-small/source/i18n/digitgrouping.cpp | 58 - deps/icu-small/source/i18n/digitgrouping.h | 112 - deps/icu-small/source/i18n/digitinterval.cpp | 55 - deps/icu-small/source/i18n/digitinterval.h | 159 - deps/icu-small/source/i18n/digitlst.cpp | 1143 ---- deps/icu-small/source/i18n/digitlst.h | 529 -- .../source/i18n/double-conversion-strtod.cpp | 574 ++ .../source/i18n/double-conversion-strtod.h | 63 + .../source/i18n/double-conversion-utils.h | 4 +- deps/icu-small/source/i18n/double-conversion.cpp | 7 +- deps/icu-small/source/i18n/double-conversion.h | 2 +- deps/icu-small/source/i18n/fmtable.cpp | 160 +- deps/icu-small/source/i18n/fmtableimp.h | 12 +- deps/icu-small/source/i18n/fphdlimp.cpp | 21 +- deps/icu-small/source/i18n/fphdlimp.h | 23 +- deps/icu-small/source/i18n/measunit.cpp | 87 +- deps/icu-small/source/i18n/msgfmt.cpp | 32 +- deps/icu-small/source/i18n/nfsubs.cpp | 25 +- deps/icu-small/source/i18n/number_affixutils.cpp | 62 +- deps/icu-small/source/i18n/number_affixutils.h | 65 +- deps/icu-small/source/i18n/number_asformat.cpp | 105 + deps/icu-small/source/i18n/number_asformat.h | 107 + deps/icu-small/source/i18n/number_capi.cpp | 213 + deps/icu-small/source/i18n/number_compact.cpp | 15 +- deps/icu-small/source/i18n/number_compact.h | 2 +- .../source/i18n/number_currencysymbols.cpp | 123 + .../icu-small/source/i18n/number_currencysymbols.h | 65 + .../source/i18n/number_decimalquantity.cpp | 414 +- .../icu-small/source/i18n/number_decimalquantity.h | 92 +- .../icu-small/source/i18n/number_decimfmtprops.cpp | 80 +- deps/icu-small/source/i18n/number_decimfmtprops.h | 79 +- deps/icu-small/source/i18n/number_decnum.h | 77 + deps/icu-small/source/i18n/number_fluent.cpp | 625 +- deps/icu-small/source/i18n/number_formatimpl.cpp | 262 +- deps/icu-small/source/i18n/number_formatimpl.h | 33 +- deps/icu-small/source/i18n/number_grouping.cpp | 33 +- deps/icu-small/source/i18n/number_integerwidth.cpp | 28 +- deps/icu-small/source/i18n/number_longnames.cpp | 7 +- deps/icu-small/source/i18n/number_longnames.h | 2 +- deps/icu-small/source/i18n/number_mapper.cpp | 502 ++ deps/icu-small/source/i18n/number_mapper.h | 206 + deps/icu-small/source/i18n/number_microprops.h | 82 + deps/icu-small/source/i18n/number_modifiers.cpp | 6 +- deps/icu-small/source/i18n/number_modifiers.h | 2 +- deps/icu-small/source/i18n/number_multiplier.cpp | 156 + deps/icu-small/source/i18n/number_multiplier.h | 57 + deps/icu-small/source/i18n/number_notation.cpp | 15 +- deps/icu-small/source/i18n/number_padding.cpp | 14 +- .../source/i18n/number_patternmodifier.cpp | 243 +- .../icu-small/source/i18n/number_patternmodifier.h | 52 +- .../icu-small/source/i18n/number_patternstring.cpp | 323 +- deps/icu-small/source/i18n/number_patternstring.h | 117 +- deps/icu-small/source/i18n/number_rounding.cpp | 195 +- deps/icu-small/source/i18n/number_roundingutils.h | 57 +- deps/icu-small/source/i18n/number_scientific.cpp | 23 +- deps/icu-small/source/i18n/number_scientific.h | 2 +- deps/icu-small/source/i18n/number_skeletons.cpp | 1510 +++++ deps/icu-small/source/i18n/number_skeletons.h | 327 ++ .../icu-small/source/i18n/number_stringbuilder.cpp | 59 +- deps/icu-small/source/i18n/number_stringbuilder.h | 16 +- deps/icu-small/source/i18n/number_types.h | 92 +- deps/icu-small/source/i18n/number_utils.cpp | 253 + deps/icu-small/source/i18n/number_utils.h | 144 +- deps/icu-small/source/i18n/number_utypes.h | 79 + deps/icu-small/source/i18n/numfmt.cpp | 92 +- deps/icu-small/source/i18n/numparse_affixes.cpp | 470 ++ deps/icu-small/source/i18n/numparse_affixes.h | 255 + .../source/i18n/numparse_compositions.cpp | 107 + deps/icu-small/source/i18n/numparse_compositions.h | 124 + deps/icu-small/source/i18n/numparse_currency.cpp | 186 + deps/icu-small/source/i18n/numparse_currency.h | 74 + deps/icu-small/source/i18n/numparse_decimal.cpp | 458 ++ deps/icu-small/source/i18n/numparse_decimal.h | 76 + deps/icu-small/source/i18n/numparse_impl.cpp | 361 ++ deps/icu-small/source/i18n/numparse_impl.h | 109 + .../source/i18n/numparse_parsednumber.cpp | 122 + deps/icu-small/source/i18n/numparse_scientific.cpp | 133 + deps/icu-small/source/i18n/numparse_scientific.h | 45 + .../source/i18n/numparse_stringsegment.cpp | 146 + .../icu-small/source/i18n/numparse_stringsegment.h | 24 + deps/icu-small/source/i18n/numparse_symbols.cpp | 193 + deps/icu-small/source/i18n/numparse_symbols.h | 173 + deps/icu-small/source/i18n/numparse_types.h | 377 ++ deps/icu-small/source/i18n/numparse_utils.h | 43 + deps/icu-small/source/i18n/numparse_validators.cpp | 85 + deps/icu-small/source/i18n/numparse_validators.h | 95 + deps/icu-small/source/i18n/pluralaffix.cpp | 104 - deps/icu-small/source/i18n/pluralaffix.h | 177 - deps/icu-small/source/i18n/plurfmt.cpp | 59 +- deps/icu-small/source/i18n/plurrule.cpp | 63 +- deps/icu-small/source/i18n/plurrule_impl.h | 135 +- deps/icu-small/source/i18n/precision.cpp | 444 -- deps/icu-small/source/i18n/precision.h | 323 - deps/icu-small/source/i18n/quantityformatter.cpp | 10 +- deps/icu-small/source/i18n/rbnf.cpp | 54 +- deps/icu-small/source/i18n/reldatefmt.cpp | 3 +- .../source/i18n/scientificnumberformatter.cpp | 17 +- .../source/i18n/significantdigitinterval.h | 92 - deps/icu-small/source/i18n/smallintformatter.cpp | 2622 --------- deps/icu-small/source/i18n/smallintformatter.h | 90 - deps/icu-small/source/i18n/smpdtfmt.cpp | 356 +- deps/icu-small/source/i18n/timezone.cpp | 5 +- deps/icu-small/source/i18n/ucln_in.h | 1 + .../source/i18n/unicode/compactdecimalformat.h | 267 +- deps/icu-small/source/i18n/unicode/currunit.h | 5 +- deps/icu-small/source/i18n/unicode/dcfmtsym.h | 9 +- deps/icu-small/source/i18n/unicode/decimfmt.h | 740 +-- deps/icu-small/source/i18n/unicode/fmtable.h | 35 +- deps/icu-small/source/i18n/unicode/fpositer.h | 8 - deps/icu-small/source/i18n/unicode/measunit.h | 8 - deps/icu-small/source/i18n/unicode/nounit.h | 12 +- .../source/i18n/unicode/numberformatter.h | 1558 +++-- deps/icu-small/source/i18n/unicode/numfmt.h | 18 +- deps/icu-small/source/i18n/unicode/plurrule.h | 21 - deps/icu-small/source/i18n/unicode/rbnf.h | 4 +- .../i18n/unicode/scientificnumberformatter.h | 5 - deps/icu-small/source/i18n/unicode/smpdtfmt.h | 39 +- deps/icu-small/source/i18n/unicode/timezone.h | 2 + deps/icu-small/source/i18n/unicode/unum.h | 31 +- .../source/i18n/unicode/unumberformatter.h | 666 +++ deps/icu-small/source/i18n/unicode/uspoof.h | 25 +- deps/icu-small/source/i18n/upluralrules.cpp | 37 +- deps/icu-small/source/i18n/uspoof.cpp | 193 +- deps/icu-small/source/i18n/uspoof_build.cpp | 21 + deps/icu-small/source/i18n/uspoof_conf.cpp | 37 +- deps/icu-small/source/i18n/uspoof_impl.cpp | 50 +- deps/icu-small/source/i18n/uspoof_impl.h | 3 + deps/icu-small/source/i18n/valueformatter.cpp | 223 - deps/icu-small/source/i18n/valueformatter.h | 161 - deps/icu-small/source/i18n/visibledigits.cpp | 186 - deps/icu-small/source/i18n/visibledigits.h | 162 - deps/icu-small/source/i18n/windtfmt.cpp | 3 +- deps/icu-small/source/i18n/zonemeta.cpp | 1 + deps/icu-small/source/tools/toolutil/swapimpl.cpp | 2 +- deps/icu-small/source/tools/toolutil/udbgutil.cpp | 1 - 213 files changed, 22041 insertions(+), 25762 deletions(-) create mode 100644 deps/icu-small/source/common/static_unicode_sets.cpp create mode 100644 deps/icu-small/source/common/static_unicode_sets.h delete mode 100644 deps/icu-small/source/data/in/icudt61l.dat create mode 100644 deps/icu-small/source/data/in/icudt62l.dat delete mode 100644 deps/icu-small/source/i18n/affixpatternparser.cpp delete mode 100644 deps/icu-small/source/i18n/affixpatternparser.h delete mode 100644 deps/icu-small/source/i18n/dcfmtimp.h delete mode 100644 deps/icu-small/source/i18n/decfmtst.cpp delete mode 100644 deps/icu-small/source/i18n/decfmtst.h delete mode 100644 deps/icu-small/source/i18n/decimalformatpattern.cpp delete mode 100644 deps/icu-small/source/i18n/decimalformatpattern.h delete mode 100644 deps/icu-small/source/i18n/decimalformatpatternimpl.h delete mode 100644 deps/icu-small/source/i18n/decimfmtimpl.cpp delete mode 100644 deps/icu-small/source/i18n/decimfmtimpl.h delete mode 100644 deps/icu-small/source/i18n/digitaffix.cpp delete mode 100644 deps/icu-small/source/i18n/digitaffix.h delete mode 100644 deps/icu-small/source/i18n/digitaffixesandpadding.cpp delete mode 100644 deps/icu-small/source/i18n/digitaffixesandpadding.h delete mode 100644 deps/icu-small/source/i18n/digitformatter.cpp delete mode 100644 deps/icu-small/source/i18n/digitformatter.h delete mode 100644 deps/icu-small/source/i18n/digitgrouping.cpp delete mode 100644 deps/icu-small/source/i18n/digitgrouping.h delete mode 100644 deps/icu-small/source/i18n/digitinterval.cpp delete mode 100644 deps/icu-small/source/i18n/digitinterval.h delete mode 100644 deps/icu-small/source/i18n/digitlst.cpp delete mode 100644 deps/icu-small/source/i18n/digitlst.h create mode 100644 deps/icu-small/source/i18n/double-conversion-strtod.cpp create mode 100644 deps/icu-small/source/i18n/double-conversion-strtod.h create mode 100644 deps/icu-small/source/i18n/number_asformat.cpp create mode 100644 deps/icu-small/source/i18n/number_asformat.h create mode 100644 deps/icu-small/source/i18n/number_capi.cpp create mode 100644 deps/icu-small/source/i18n/number_currencysymbols.cpp create mode 100644 deps/icu-small/source/i18n/number_currencysymbols.h create mode 100644 deps/icu-small/source/i18n/number_decnum.h create mode 100644 deps/icu-small/source/i18n/number_mapper.cpp create mode 100644 deps/icu-small/source/i18n/number_mapper.h create mode 100644 deps/icu-small/source/i18n/number_microprops.h create mode 100644 deps/icu-small/source/i18n/number_multiplier.cpp create mode 100644 deps/icu-small/source/i18n/number_multiplier.h create mode 100644 deps/icu-small/source/i18n/number_skeletons.cpp create mode 100644 deps/icu-small/source/i18n/number_skeletons.h create mode 100644 deps/icu-small/source/i18n/number_utils.cpp create mode 100644 deps/icu-small/source/i18n/number_utypes.h create mode 100644 deps/icu-small/source/i18n/numparse_affixes.cpp create mode 100644 deps/icu-small/source/i18n/numparse_affixes.h create mode 100644 deps/icu-small/source/i18n/numparse_compositions.cpp create mode 100644 deps/icu-small/source/i18n/numparse_compositions.h create mode 100644 deps/icu-small/source/i18n/numparse_currency.cpp create mode 100644 deps/icu-small/source/i18n/numparse_currency.h create mode 100644 deps/icu-small/source/i18n/numparse_decimal.cpp create mode 100644 deps/icu-small/source/i18n/numparse_decimal.h create mode 100644 deps/icu-small/source/i18n/numparse_impl.cpp create mode 100644 deps/icu-small/source/i18n/numparse_impl.h create mode 100644 deps/icu-small/source/i18n/numparse_parsednumber.cpp create mode 100644 deps/icu-small/source/i18n/numparse_scientific.cpp create mode 100644 deps/icu-small/source/i18n/numparse_scientific.h create mode 100644 deps/icu-small/source/i18n/numparse_stringsegment.cpp create mode 100644 deps/icu-small/source/i18n/numparse_stringsegment.h create mode 100644 deps/icu-small/source/i18n/numparse_symbols.cpp create mode 100644 deps/icu-small/source/i18n/numparse_symbols.h create mode 100644 deps/icu-small/source/i18n/numparse_types.h create mode 100644 deps/icu-small/source/i18n/numparse_utils.h create mode 100644 deps/icu-small/source/i18n/numparse_validators.cpp create mode 100644 deps/icu-small/source/i18n/numparse_validators.h delete mode 100644 deps/icu-small/source/i18n/pluralaffix.cpp delete mode 100644 deps/icu-small/source/i18n/pluralaffix.h delete mode 100644 deps/icu-small/source/i18n/precision.cpp delete mode 100644 deps/icu-small/source/i18n/precision.h delete mode 100644 deps/icu-small/source/i18n/significantdigitinterval.h delete mode 100644 deps/icu-small/source/i18n/smallintformatter.cpp delete mode 100644 deps/icu-small/source/i18n/smallintformatter.h create mode 100644 deps/icu-small/source/i18n/unicode/unumberformatter.h delete mode 100644 deps/icu-small/source/i18n/valueformatter.cpp delete mode 100644 deps/icu-small/source/i18n/valueformatter.h delete mode 100644 deps/icu-small/source/i18n/visibledigits.cpp delete mode 100644 deps/icu-small/source/i18n/visibledigits.h (limited to 'deps/icu-small') diff --git a/deps/icu-small/README-SMALL-ICU.txt b/deps/icu-small/README-SMALL-ICU.txt index b3919ec52b..b98a528485 100644 --- a/deps/icu-small/README-SMALL-ICU.txt +++ b/deps/icu-small/README-SMALL-ICU.txt @@ -1,8 +1,8 @@ Small ICU sources - auto generated by shrink-icu-src.py This directory contains the ICU subset used by --with-intl=small-icu (the default) -It is a strict subset of ICU 61 source files with the following exception(s): -* deps/icu-small/source/data/in/icudt61l.dat : Reduced-size data file +It is a strict subset of ICU 62 source files with the following exception(s): +* deps/icu-small/source/data/in/icudt62l.dat : Reduced-size data file To rebuild this directory, see ../../tools/icu/README.md diff --git a/deps/icu-small/source/common/charstr.cpp b/deps/icu-small/source/common/charstr.cpp index 8bacd20ddc..353f1d5254 100644 --- a/deps/icu-small/source/common/charstr.cpp +++ b/deps/icu-small/source/common/charstr.cpp @@ -23,6 +23,18 @@ U_NAMESPACE_BEGIN +CharString::CharString(CharString&& src) U_NOEXCEPT + : buffer(std::move(src.buffer)), len(src.len) { + src.len = 0; // not strictly necessary because we make no guarantees on the source string +} + +CharString& CharString::operator=(CharString&& src) U_NOEXCEPT { + buffer = std::move(src.buffer); + len = src.len; + src.len = 0; // not strictly necessary because we make no guarantees on the source string + return *this; +} + CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) { if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) { len=s.len; diff --git a/deps/icu-small/source/common/charstr.h b/deps/icu-small/source/common/charstr.h index 3cfdf6a897..86f69c383a 100644 --- a/deps/icu-small/source/common/charstr.h +++ b/deps/icu-small/source/common/charstr.h @@ -55,6 +55,18 @@ public: } ~CharString() {} + /** + * Move constructor; might leave src in an undefined state. + * This string will have the same contents and state that the source string had. + */ + CharString(CharString &&src) U_NOEXCEPT; + /** + * Move assignment operator; might leave src in an undefined state. + * This string will have the same contents and state that the source string had. + * The behavior is undefined if *this and src are the same object. + */ + CharString &operator=(CharString &&src) U_NOEXCEPT; + /** * Replaces this string's contents with the other string's contents. * CharString does not support the standard copy constructor nor diff --git a/deps/icu-small/source/common/cmemory.h b/deps/icu-small/source/common/cmemory.h index a44f9a1902..f98e13efc0 100644 --- a/deps/icu-small/source/common/cmemory.h +++ b/deps/icu-small/source/common/cmemory.h @@ -299,6 +299,14 @@ public: * Destructor deletes the array (if owned). */ ~MaybeStackArray() { releaseArray(); } + /** + * Move constructor: transfers ownership or copies the stack array. + */ + MaybeStackArray(MaybeStackArray &&src) U_NOEXCEPT; + /** + * Move assignment: transfers ownership or copies the stack array. + */ + MaybeStackArray &operator=(MaybeStackArray &&src) U_NOEXCEPT; /** * Returns the array capacity (number of T items). * @return array capacity @@ -376,6 +384,11 @@ private: uprv_free(ptr); } } + void resetToStackArray() { + ptr=stackArray; + capacity=stackCapacity; + needToRelease=FALSE; + } /* No comparison operators with other MaybeStackArray's. */ bool operator==(const MaybeStackArray & /*other*/) {return FALSE;} bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;} @@ -398,6 +411,34 @@ private: #endif }; +template +icu::MaybeStackArray::MaybeStackArray( + MaybeStackArray && src) U_NOEXCEPT + : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) { + if (src.ptr == src.stackArray) { + ptr = stackArray; + uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity); + } else { + src.resetToStackArray(); // take ownership away from src + } +} + +template +inline MaybeStackArray & +MaybeStackArray::operator=(MaybeStackArray && src) U_NOEXCEPT { + releaseArray(); // in case this instance had its own memory allocated + capacity = src.capacity; + needToRelease = src.needToRelease; + if (src.ptr == src.stackArray) { + ptr = stackArray; + uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity); + } else { + ptr = src.ptr; + src.resetToStackArray(); // take ownership away from src + } + return *this; +} + template inline T *MaybeStackArray::resize(int32_t newCapacity, int32_t length) { if(newCapacity>0) { @@ -447,9 +488,7 @@ inline T *MaybeStackArray::orphanOrClone(int32_t length, int32 uprv_memcpy(p, ptr, (size_t)length*sizeof(T)); } resultCapacity=length; - ptr=stackArray; - capacity=stackCapacity; - needToRelease=FALSE; + resetToStackArray(); return p; } diff --git a/deps/icu-small/source/common/edits.cpp b/deps/icu-small/source/common/edits.cpp index 9ec005624f..3b3611fcf8 100644 --- a/deps/icu-small/source/common/edits.cpp +++ b/deps/icu-small/source/common/edits.cpp @@ -4,10 +4,12 @@ // edits.cpp // created: 2017feb08 Markus W. Scherer -#include "unicode/utypes.h" #include "unicode/edits.h" +#include "unicode/unistr.h" +#include "unicode/utypes.h" #include "cmemory.h" #include "uassert.h" +#include "util.h" U_NAMESPACE_BEGIN @@ -773,4 +775,29 @@ int32_t Edits::Iterator::sourceIndexFromDestinationIndex(int32_t i, UErrorCode & } } +UnicodeString& Edits::Iterator::toString(UnicodeString& sb) const { + sb.append(u"{ src[", -1); + ICU_Utility::appendNumber(sb, srcIndex); + sb.append(u"..", -1); + ICU_Utility::appendNumber(sb, srcIndex + oldLength_); + if (changed) { + sb.append(u"] ⇝ dest[", -1); + } else { + sb.append(u"] ≡ dest[", -1); + } + ICU_Utility::appendNumber(sb, destIndex); + sb.append(u"..", -1); + ICU_Utility::appendNumber(sb, destIndex + newLength_); + if (changed) { + sb.append(u"], repl[", -1); + ICU_Utility::appendNumber(sb, replIndex); + sb.append(u"..", -1); + ICU_Utility::appendNumber(sb, replIndex + newLength_); + sb.append(u"] }", -1); + } else { + sb.append(u"] (no-change) }", -1); + } + return sb; +} + U_NAMESPACE_END diff --git a/deps/icu-small/source/common/locmap.cpp b/deps/icu-small/source/common/locmap.cpp index 029c1edf03..a3cf2d5eb2 100644 --- a/deps/icu-small/source/common/locmap.cpp +++ b/deps/icu-small/source/common/locmap.cpp @@ -1015,7 +1015,7 @@ static const char* getPosixID(const ILcidPosixMap *this_0, uint32_t hostID) { uint32_t i; - for (i = 0; i <= this_0->numRegions; i++) + for (i = 0; i < this_0->numRegions; i++) { if (this_0->regionMaps[i].hostID == hostID) { diff --git a/deps/icu-small/source/common/norm2_nfc_data.h b/deps/icu-small/source/common/norm2_nfc_data.h index 8f5c4346db..c8bf440ae1 100644 --- a/deps/icu-small/source/common/norm2_nfc_data.h +++ b/deps/icu-small/source/common/norm2_nfc_data.h @@ -12,625 +12,638 @@ #ifdef INCLUDED_FROM_NORMALIZER2_CPP static const UVersionInfo norm2_nfc_data_formatVersion={3,0,0,0}; -static const UVersionInfo norm2_nfc_data_dataVersion={0xa,0,0,0}; +static const UVersionInfo norm2_nfc_data_dataVersion={0xb,0,0,0}; static const int32_t norm2_nfc_data_indexes[Normalizer2Impl::IX_COUNT]={ -0x50,0x4cc0,0x8918,0x8a18,0x8a18,0x8a18,0x8a18,0x8a18,0xc0,0x300,0xadc,0x29d0,0x3c56,0xfc00,0x1282,0x3b8c, +0x50,0x4e50,0x8aa8,0x8ba8,0x8ba8,0x8ba8,0x8ba8,0x8ba8,0xc0,0x300,0xadc,0x29d0,0x3c56,0xfc00,0x1282,0x3b8c, 0x3c24,0x3c56,0x300,0 }; -static const uint16_t norm2_nfc_data_trieIndex[9776]={ -0x2a8,0x2b0,0x2b8,0x2c0,0x2ce,0x2d6,0x2de,0x2e6,0x2ee,0x2f6,0x2fe,0x306,0x30e,0x316,0x31c,0x324, -0x32c,0x334,0x2c7,0x2cf,0x339,0x341,0x2c7,0x2cf,0x349,0x351,0x359,0x361,0x369,0x371,0x379,0x381, -0x389,0x391,0x399,0x3a1,0x3a9,0x3b1,0x3b9,0x3c1,0x2c7,0x2cf,0x2c7,0x2cf,0x3c8,0x3d0,0x3d8,0x3e0, -0x3e4,0x3ec,0x3f2,0x3fa,0x2c7,0x2cf,0x402,0x40a,0x40e,0x416,0x41e,0x426,0x2c7,0x2cf,0x424,0x42c, -0x431,0x438,0x43c,0x2c7,0x2c7,0x2c7,0x443,0x44b,0x2c7,0x453,0x45b,0x2c7,0x2c7,0x463,0x46b,0x2c7, -0x2c7,0x473,0x47b,0x2c7,0x2c7,0x483,0x48b,0x2c7,0x2c7,0x463,0x492,0x2c7,0x49a,0x4a0,0x4a8,0x2c7, -0x2c7,0x2c7,0x4af,0x2c7,0x2c7,0x4b5,0x4bd,0x2c7,0x2c7,0x4c3,0x4cb,0x2c7,0x2c7,0x2c7,0x4d1,0x2c7, -0x2c7,0x4d9,0x4e0,0x2c7,0x2c7,0x4e3,0x4ea,0x2c7,0x4ed,0x4f4,0x4fc,0x504,0x50c,0x514,0x51b,0x2c7, -0x2c7,0x522,0x2c7,0x2c7,0x529,0x2c7,0x2c7,0x2c7,0x93b,0x2c7,0x2c7,0x943,0x2c7,0x949,0x951,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x52d,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x535,0x535,0x2c7,0x2c7,0x2c7,0x2c7,0x53b,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x543,0x2c7,0x2c7,0x2c7,0x546,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x54d,0x2c7,0x2c7,0x555,0x2c7,0x55d,0x2c7,0x2c7,0x565,0x56a,0x572,0x578,0x2c7,0x57e,0x2c7,0x585, -0x2c7,0x58a,0x2c7,0x2c7,0x2c7,0x2c7,0x590,0x598,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x5a0,0x5a5, -0x5ad,0x5b5,0x5bd,0x5c5,0x5cd,0x5d5,0x5dd,0x5e5,0x5ed,0x5f5,0x5fd,0x605,0x60d,0x615,0x61d,0x625, -0x62d,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x631,0x639,0x2c7,0x640,0x2c7,0x2c7,0x644,0x64b,0x650,0x2c7, -0x658,0x660,0x668,0x670,0x678,0x680,0x2c7,0x688,0x2c7,0x68e,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x691,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x699,0x2c7,0x2c7,0x2c7,0x69e,0x2c7,0x2c7,0x2c7,0x6a6, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x6ae,0x6b5,0x6bd,0x6c5,0x6cd,0x6d5,0x6dd,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x6e5,0x6ed,0x2c7,0x2c7,0x6f5,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x6fc,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x703,0x70b,0x2c7,0x711,0x715,0x2c7,0x2c7,0x58b,0x71d,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x721,0x729,0x72c,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x48b, -0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a, -0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c, -0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e, -0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959, -0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b, -0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d, -0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d, -0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a, -0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c, -0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e, -0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959, -0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b, -0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d, -0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d, -0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a, -0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c, -0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e, -0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959, -0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b, -0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d, -0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d, -0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x96d,0x959,0x95a,0x95b,0x95c,0x95d,0x95e,0x965,0x2c7,0x2c7, -0x975,0x97c,0x2a8,0x983,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8, -0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8,0x2a8, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x734,0x73c,0x744,0x74c,0x754,0x75c,0x764,0x76c, -0x774,0x77c,0x784,0x78c,0x794,0x79c,0x7a4,0x2c7,0x7ab,0x7b3,0x7bb,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x7c3,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0xb20,0xb20,0xb38,0xb78,0xbb8,0xbf8,0xc38,0xc70,0xcb0,0xb1c,0xce4,0xb1c,0xd24,0xd64,0xda4,0xde4, -0xe24,0xe64,0xea4,0xee4,0xb1c,0xb1c,0xf20,0xf60,0xf90,0xfc8,0xb1c,0x1008,0x1038,0x1078,0xb1c,0x1090, -0x880,0x8b0,0x8ee,0x928,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x953,0x188,0x188, -0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x96f,0x188,0x188,0x9a5,0x188,0x9e5,0xa1f,0x188,0x188, +static const uint16_t norm2_nfc_data_trieIndex[9976]={ +0x2aa,0x2b2,0x2ba,0x2c2,0x2d0,0x2d8,0x2e0,0x2e8,0x2f0,0x2f8,0x300,0x308,0x310,0x318,0x31e,0x326, +0x32e,0x336,0x2c9,0x2d1,0x33b,0x343,0x2c9,0x2d1,0x34b,0x353,0x35b,0x363,0x36b,0x373,0x37b,0x383, +0x38b,0x393,0x39b,0x3a3,0x3ab,0x3b3,0x3bb,0x3c3,0x2c9,0x2d1,0x2c9,0x2d1,0x3ca,0x3d2,0x3da,0x3e2, +0x3e6,0x3ee,0x3f4,0x3fc,0x2c9,0x2d1,0x404,0x40c,0x410,0x418,0x420,0x428,0x2c9,0x2d1,0x426,0x42e, +0x436,0x43d,0x441,0x2c9,0x2c9,0x2c9,0x448,0x450,0x2c9,0x458,0x460,0x2c9,0x2c9,0x468,0x470,0x478, +0x2c9,0x480,0x488,0x2c9,0x2c9,0x490,0x498,0x2c9,0x2c9,0x468,0x49f,0x2c9,0x4a7,0x4ad,0x4b5,0x2c9, +0x2c9,0x2c9,0x4bc,0x2c9,0x2c9,0x4c2,0x4ca,0x2c9,0x2c9,0x4d0,0x4d8,0x2c9,0x2c9,0x2c9,0x4de,0x2c9, +0x2c9,0x4e6,0x4ed,0x2c9,0x2c9,0x4f0,0x4f7,0x2c9,0x4fa,0x501,0x509,0x511,0x519,0x521,0x528,0x2c9, +0x2c9,0x52f,0x2c9,0x2c9,0x536,0x2c9,0x2c9,0x2c9,0x96d,0x2c9,0x2c9,0x975,0x2c9,0x97b,0x983,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x53a,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x542,0x542,0x2c9,0x2c9,0x2c9,0x2c9,0x548,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x550,0x2c9,0x2c9,0x2c9,0x553,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x55a,0x2c9,0x2c9,0x562,0x2c9,0x56a,0x2c9,0x2c9,0x572,0x577,0x57f,0x585,0x2c9,0x58b,0x2c9,0x592, +0x2c9,0x597,0x2c9,0x2c9,0x2c9,0x2c9,0x59d,0x5a5,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x5ad,0x5b2, +0x5ba,0x5c2,0x5ca,0x5d2,0x5da,0x5e2,0x5ea,0x5f2,0x5fa,0x602,0x60a,0x612,0x61a,0x622,0x62a,0x632, +0x63a,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x63e,0x646,0x2c9,0x64d,0x2c9,0x2c9,0x651,0x658,0x65d,0x2c9, +0x665,0x66d,0x675,0x67d,0x685,0x68d,0x2c9,0x695,0x2c9,0x69b,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x69e,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x6a6,0x2c9,0x2c9,0x2c9,0x6ab,0x2c9,0x2c9,0x2c9,0x6b3, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x6bb,0x6c2,0x6ca,0x6d2,0x6da,0x6e2,0x6ea,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x6f2,0x6fa,0x2c9,0x2c9,0x702,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x709,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x710,0x718,0x2c9,0x71e,0x722,0x2c9,0x2c9,0x598,0x72a,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x72e,0x736,0x739,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x498, +0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c, +0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e, +0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990, +0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b, +0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d, +0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f, +0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f, +0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c, +0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e, +0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990, +0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b, +0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d, +0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f, +0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f, +0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c, +0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e, +0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990, +0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b, +0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d, +0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f, +0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f, +0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x99f,0x98b,0x98c,0x98d,0x98e,0x98f,0x990,0x997,0x2c9,0x2c9, +0x9a7,0x9ae,0x2aa,0x9b5,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa, +0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa,0x2aa, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x741,0x749,0x751,0x759,0x761,0x769,0x771,0x779, +0x781,0x789,0x791,0x799,0x7a1,0x7a9,0x7b1,0x2c9,0x7b8,0x7c0,0x7c8,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x7d0,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0xb28,0xb28,0xb40,0xb80,0xbc0,0xc00,0xc40,0xc78,0xcb8,0xb24,0xcec,0xb24,0xd2c,0xd6c,0xdac,0xdec, +0xe2c,0xe6c,0xeac,0xeec,0xb24,0xb24,0xf28,0xf68,0xf98,0xfd0,0xb24,0x1010,0x1040,0x1080,0xb24,0x1098, +0x880,0x8b0,0x8ee,0x92d,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x95a,0x188,0x188, +0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x976,0x188,0x188,0x9ac,0x188,0x9ec,0xa26,0x188,0x188, 0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188, -0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0xa5f, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x7c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x7cf,0x2c7,0x2c7,0x2c7,0x7d2,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x7d9,0x7dd,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x7e5,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x6fc,0x69e,0x7e7,0x7ef,0x2c7,0x2c7,0x7f7,0x7fe,0x2c7,0x58b,0x2c7,0x2c7,0x806,0x2c7,0x2c7,0x809, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x80f,0x2c7,0x463,0x816,0x81d,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x825,0x2c7,0x2c7,0x829,0x831,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x836,0x83e,0x2c7,0x2c7,0x69e, -0x2c7,0x2c7,0x2c7,0x841,0x2c7,0x2c7,0x2c7,0x847,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x535,0x848,0x2c7,0x84a,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x69e,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x852,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x856,0x2c7,0x85c,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x862,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x86a, -0x872,0x87a,0x880,0x888,0x2c7,0x2c7,0x2c7,0x890,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x898,0x8a0,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x8a4,0x2c7,0x2c7,0x2c7,0x8ab,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x8b3, -0x8bb,0x8c3,0x8cb,0x8d3,0x8db,0x8e3,0x8eb,0x8f3,0x8fb,0x903,0x90b,0x913,0x91b,0x923,0x92b,0x933, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7, -0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2a7, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,4,8,0xc,1, -1,0x10,0x50,0x5c,0x70,0x88,0xcc,0xd0,0xec,0x108,0x144,0x148,0x15c,0x174,0x180,0x1a4, -0x1e4,1,0x1ec,0x20c,0x228,0x244,0x290,0x298,0x2b0,0x2b8,0x2dc,1,1,1,1,1, -1,0x2f4,0x334,0x340,0x354,0x36c,0x3b0,0x3b4,0x3d0,0x3f0,0x428,0x430,0x444,0x45c,0x468,0x48c, -0x4cc,1,0x4d4,0x4f4,0x510,0x530,0x57c,0x584,0x5a0,0x5a8,0x5d0,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0x5e8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0x1284,0x128a,0xade,0x1290,0xaf4,0xafe,0x5f4,0xb08, -0x1296,0x129c,0xb12,0x12a2,0x12a8,0x12ae,0x12b4,0xb28,1,0x12ba,0x12c0,0x12c6,0xb32,0xb48,0xb5a,1, -0x5fc,0x12cc,0x12d2,0x12d8,0xb64,0x12de,1,1,0x12e4,0x12ea,0xb7a,0x12f0,0xb90,0xb9a,0x600,0xba4, -0x12f6,0x12fc,0xbae,0x1302,0x1308,0x130e,0x1314,0xbc4,1,0x131a,0x1320,0x1326,0xbce,0xbe4,0xbf6,1, -0x608,0x132c,0x1332,0x1338,0xc00,0x133e,1,0x1344,0x134a,0x1350,0xc16,0xc2c,0x1357,0x135d,0x1362,0x1368, -0x136e,0x1374,0x137a,0x1380,0x1386,0x138c,0x1392,0x1398,1,1,0xc42,0xc50,0x139e,0x13a4,0x13aa,0x13b0, -0x13b7,0x13bd,0x13c2,0x13c8,0x13ce,0x13d4,0x13da,0x13e0,0x13e6,0x13ec,0x13f3,0x13f9,0x13fe,0x1404,1,1, -0x140a,0x1410,0x1416,0x141c,0x1422,0x1428,0x142f,0x1435,0x143a,1,1,1,0x1441,0x1447,0x144d,0x1453, -1,0x1458,0x145e,0x1465,0x146b,0x1470,0x1476,1,1,1,1,0x147c,0x1482,0x1489,0x148f,0x1494, -0x149a,1,1,1,0xc5e,0xc6c,0x14a0,0x14a6,0x14ac,0x14b2,1,1,0x14b8,0x14be,0x14c5,0x14cb, -0x14d0,0x14d6,0xc7a,0xc84,0x14dc,0x14e2,0x14e9,0x14ef,0xc8e,0xc98,0x14f5,0x14fb,0x1500,0x1506,1,1, -0xca2,0xcac,0xcb6,0xcc0,0x150c,0x1512,0x1518,0x151e,0x1524,0x152a,0x1531,0x1537,0x153c,0x1542,0x1548,0x154e, -0x1554,0x155a,0x1560,0x1566,0x156c,0x1572,0x1578,0x60c,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0xcca,0xce4,1,1,1,1,1,1, -1,1,1,1,1,1,1,0xcfe,0xd18,1,1,1,1,1,1,0x610, -1,1,1,1,1,1,1,1,1,1,1,1,1,0x157e,0x1584,0x158a, -0x1590,0x1596,0x159c,0x15a2,0x15a8,0x15b0,0x15ba,0x15c4,0x15ce,0x15d8,0x15e2,0x15ec,0x15f6,1,0x1600,0x160a, -0x1614,0x161e,0x1627,0x162d,1,1,0x1632,0x1638,0x163e,0x1644,0xd32,0xd3c,0x164d,0x1657,0x165f,0x1665, -0x166b,1,1,1,0x1670,0x1676,1,1,0x167c,0x1682,0x168a,0x1694,0x169d,0x16a3,0x16a9,0x16af, -0x16b4,0x16ba,0x16c0,0x16c6,0x16cc,0x16d2,0x16d8,0x16de,0x16e4,0x16ea,0x16f0,0x16f6,0x16fc,0x1702,0x1708,0x170e, -0x1714,0x171a,0x1720,0x1726,0x172c,0x1732,0x1738,0x173e,0x1744,0x174a,0x1750,0x1756,1,1,0x175c,0x1762, -1,1,1,1,1,1,0xd46,0xd50,0xd5a,0xd64,0x176a,0x1774,0x177e,0x1788,0xd6e,0xd78, -0x1792,0x179c,0x17a4,0x17aa,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,0x614,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xfdcc,0xfdcc,0xfdcc,0xfdcc,0xfdcc,0xffcc,0xfdcc,0xfdcc,0xfdcc,0xfdcc,0xfdcc,0xfdcc, -0xfdcc,0xffcc,0xffcc,0xfdcc,0xffcc,0xfdcc,0xffcc,0xfdcc,0xfdcc,0xffd0,0xffb8,0xffb8,0xffb8,0xffb8,0xffd0,0xfdb0, -0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xff94,0xff94,0xfdb8,0xfdb8,0xfdb8,0xfdb8,0xfd94,0xfd94,0xffb8,0xffb8,0xffb8, -0xffb8,0xfdb8,0xfdb8,0xffb8,0xfdb8,0xfdb8,0xffb8,0xffb8,0xfe02,0xfe02,0xfe02,0xfe02,0xfc02,0xffb8,0xffb8,0xffb8, -0xffb8,0xffcc,0xffcc,0xffcc,0x3c26,0x3c2c,0xfdcc,0x3c32,0x3c38,0xfde0,0xffcc,0xffb8,0xffb8,0xffb8,0xffcc,0xffcc, -0xffcc,0xffb8,0xffb8,1,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,0xffd0,0xffb8,0xffb8,0xffcc, -0xffd2,0xffd4,0xffd4,0xffd2,0xffd4,0xffd4,0xffd2,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,0x29d1,1,1,1,1,1,1,1, -1,1,0x29d5,1,1,1,1,1,1,0x17b1,0x17b7,0x29d9,0x17bd,0x17c3,0x17c9,1, -0x17cf,1,0x17d5,0x17db,0x17e3,0x618,1,1,1,0x634,1,0x644,1,0x658,1,1, -1,1,1,0x674,1,0x684,1,1,1,0x688,1,1,1,0x6a0,0x17eb,0x17f1, -0xd82,0x17f7,0xd8c,0x17fd,0x1805,0x6b4,1,1,1,0x6d4,1,0x6e4,1,0x6fc,1,1, -1,1,1,0x71c,1,0x72c,1,1,1,0x734,1,1,1,0x754,0xd96,0xda8, -0x180d,0x1813,0xdba,1,1,1,0x76c,0x1819,0x181f,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0x1825,0x182b,1,0x1831,1,1,0x774,0x1837,1,1,1,1, -0x183d,0x1843,0x1849,1,0x778,1,1,0x780,1,0x784,0x790,0x798,0x79c,0x184f,0x7ac,1, -1,1,0x7b0,1,1,1,1,0x7b4,1,1,1,0x7c4,1,1,1,0x7c8, -1,0x7cc,1,1,0x7d0,1,1,0x7d8,1,0x7dc,0x7e8,0x7f0,0x7f4,0x1855,0x804,1, -1,1,0x808,1,1,1,1,0x80c,1,1,1,0x81c,1,1,1,0x820, -1,0x824,1,1,0x185b,0x1861,1,0x1867,1,1,0x828,0x186d,1,1,1,1, -0x1873,0x1879,0x187f,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0x82c,0x830,0x1885,0x188b,1,1,1,1, -1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,0x1891,0x1897,1,1,1,1,1,1,1,1,1, -1,1,1,1,0x189d,0x18a3,0x18a9,0x18af,1,1,0x18b5,0x18bb,0x834,0x838,0x18c1,0x18c7, -0x18cd,0x18d3,0x18d9,0x18df,1,1,0x18e5,0x18eb,0x18f1,0x18f7,0x18fd,0x1903,0x83c,0x840,0x1909,0x190f, -0x1915,0x191b,0x1921,0x1927,0x192d,0x1933,0x1939,0x193f,0x1945,0x194b,1,1,0x1951,0x1957,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffcc,0xffbc,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffbc,0xffc8,0xffcc, -0xfe14,0xfe16,0xfe18,0xfe1a,0xfe1c,0xfe1e,0xfe20,0xfe22,0xfe24,0xfe26,0xfe26,0xfe28,0xfe2a,0xfe2c,1,0xfe2e, -1,0xfe30,0xfe32,1,0xffcc,0xffb8,1,0xfe24,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xfe3c,0xfe3e,0xfe40,1,1,1,1,1, -1,1,0x195c,0x1962,0x1969,0x196f,0x1975,0x844,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0x850,1,0x854,0xfe36,0xfe38,0xfe3a,0xfe3c,0xfe3e,0xfe40,0xfe42,0xfe44,0xfdcc,0xfdcc,0xfdb8,0xffb8,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0xfe46,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0x197b,0x858,0x1981,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0x85c,0x1987,1,0x860,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,1,1,0xffcc, -0xffcc,1,0xffb8,0xffcc,0xffcc,0xffb8,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0xfe48,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8, -0xffb8,0xffb8,0xffcc,0xffb8,0xffb8,0xffcc,0xffb8,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,0xffb8,0xffcc,0xffb8,0xffcc, -0xffb8,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffb8,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,1,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,1,0xffcc,0xffcc,0xffcc,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0xffb8,0xffb8,0xffb8,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,0xffb8, -0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xfe36,0xfe38,0xfe3a,0xffcc, -0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1, -1,1,1,1,0x864,0x198d,1,1,1,1,1,1,0x868,0x1993,1,0x86c, -0x1999,1,1,1,1,1,1,1,0xfc0e,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0xfe12,1,1,1,0xffcc,0xffb8,0xffcc, -0xffcc,1,1,1,0x29dc,0x29e2,0x29e8,0x29ee,0x29f4,0x29fa,0x2a00,0x2a06,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0xfe0e,1,0xfc00,1,1,1,1,1, -1,1,1,0x870,1,1,1,0x199f,0x19a5,0xfe12,1,1,1,1,1,1, -1,1,1,0xfc00,1,1,1,1,0x2a0c,0x2a12,1,0x2a18,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x2a1e, -1,1,0x2a24,1,1,1,1,1,0xfe0e,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0xfe12,1,1,1,1,1,1, -1,1,1,1,1,0x2a2a,0x2a30,0x2a36,1,1,0x2a3c,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0xfe0e,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0xfe12,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x878, -0x19ab,1,1,0x19b1,0x19b7,0xfe12,1,1,1,1,1,1,1,1,0xfc00,0xfc00, -1,1,1,1,0x2a42,0x2a48,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0x884,1,0x19bd,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfc00,1, -1,1,1,1,1,1,0x888,0x890,1,1,0x19c3,0x19c9,0x19cf,0xfe12,1,1, -1,1,1,1,1,1,1,0xfc00,1,1,1,1,1,1,1,1, -1,1,0x894,1,0x19d5,1,1,1,1,0xfe12,1,1,1,1,1,1, -1,0xfea8,0xfcb6,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xfe0e,1,1,0x898,0x19db,1,0xfc00,1,1,1,0x89c,0x19e1,0x19e7,1,0xdc4,0x19ef, -1,0xfe12,1,1,1,1,1,1,1,0xfc00,0xfc00,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,0xfe12,0xfe12,1,0xfc00,1,1,1,1,1, -1,1,0x8a8,0x8b0,1,1,0x19f7,0x19fd,0x1a03,0xfe12,1,1,1,1,1,1, -1,1,1,0xfc00,1,1,1,1,1,1,1,1,1,1,0xfc12,1, -1,1,1,0xfc00,1,1,1,1,1,1,1,1,1,0x8b4,0x1a09,1, -0xdce,0x1a11,0x1a19,0xfc00,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0xfece,0xfece,0xfe12,1, -1,1,1,1,1,1,1,1,0xfed6,0xfed6,0xfed6,0xfed6,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xfeec,0xfeec,1,1,1,1,1,1,1,1,1,1, -0xfef4,0xfef4,0xfef4,0xfef4,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0xffb8,0xffb8,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,0xffb8,1,0xffb8,1,0xffb0,1,1,1,1,1,1, -1,1,1,0x2a4f,1,1,1,1,1,1,1,1,1,0x2a55,1,1, -1,1,0x2a5b,1,1,1,1,0x2a61,1,1,1,1,0x2a67,1,1,1, -1,1,1,1,1,1,1,1,1,0x2a6d,1,1,1,1,1,1, -1,0xff02,0xff04,0x3c40,0xff08,0x3c48,0x2a72,1,0x2a78,1,0xff04,0xff04,0xff04,0xff04,1,1, -0xff04,0x3c50,0xffcc,0xffcc,0xfe12,1,0xffcc,0xffcc,1,1,1,1,1,1,1,1, -1,1,1,0x2a7f,1,1,1,1,1,1,1,1,1,0x2a85,1,1, -1,1,0x2a8b,1,1,1,1,0x2a91,1,1,1,1,0x2a97,1,1,1, -1,1,1,1,1,1,1,1,1,0x2a9d,1,1,1,1,1,1, -1,1,0xffb8,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,0x8c0,0x1a1f,1, -1,1,1,1,1,1,0xfc00,1,1,1,1,1,1,1,1,0xfe0e, -1,0xfe12,0xfe12,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,0xffb8,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0xfe12,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe12,1, -1,1,1,1,1,1,1,1,1,0xffcc,1,1,1,1,1,1, -1,1,1,1,1,0xffc8,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,0xffbc,0xffcc,0xffb8,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,0xffcc,0xffb8,1,1,1, -1,1,1,1,0xfe12,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,1,1,0xffb8,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc, -0xffcc,0xffb8,1,1,1,1,1,1,1,0x8c4,0x1a25,0x8c8,0x1a2b,0x8cc,0x1a31,0x8d0, -0x1a37,0x8d4,0x1a3d,1,1,0x8d8,0x1a43,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0xfe0e,0xfc00,1,1, -1,1,0x8dc,0x1a49,0x8e0,0x1a4f,0x8e4,0x8e8,0x1a55,0x1a5b,0x8ec,0x1a61,0xfe12,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,0xffcc,0xffb8,0xffcc,0xffcc,0xffcc, +0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0xa66, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x7d4, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x7dc,0x2c9,0x2c9,0x2c9,0x7df,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x7e6,0x7ea,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x7f2,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x7f9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x800,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x709,0x6ab,0x805,0x80d,0x2c9,0x2c9,0x815,0x81c,0x2c9,0x598,0x2c9,0x2c9,0x824,0x2c9,0x2c9,0x827, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x82d,0x2c9,0x830,0x838,0x83f,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x847,0x2c9,0x2c9,0x84f,0x857,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x85c,0x864,0x2c9,0x2c9,0x6ab, +0x2c9,0x2c9,0x2c9,0x867,0x2c9,0x2c9,0x2c9,0x86d,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x870,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x542,0x86e, +0x2c9,0x877,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x6ab,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x87f,0x2c9,0x882,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x888,0x2c9,0x88e,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x894,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x89c,0x8a4,0x8ac,0x8b2,0x8ba,0x2c9,0x2c9,0x2c9,0x8c2,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x8ca,0x8d2,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x8d6,0x2c9,0x2c9,0x2c9, +0x8dd,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x8e5,0x8ed,0x8f5,0x8fd,0x905,0x90d,0x915,0x91d,0x925,0x92d, +0x935,0x93d,0x945,0x94d,0x955,0x95d,0x965,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9, +0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2c9,0x2a9,0x2a9,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,4,8,0xc,1,1,0x10,0x50,0x5c,0x70,0x88,0xcc,0xd0, +0xec,0x108,0x144,0x148,0x15c,0x174,0x180,0x1a4,0x1e4,1,0x1ec,0x20c,0x228,0x244,0x290,0x298, +0x2b0,0x2b8,0x2dc,1,1,1,1,1,1,0x2f4,0x334,0x340,0x354,0x36c,0x3b0,0x3b4, +0x3d0,0x3f0,0x428,0x430,0x444,0x45c,0x468,0x48c,0x4cc,1,0x4d4,0x4f4,0x510,0x530,0x57c,0x584, +0x5a0,0x5a8,0x5d0,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0x5e8,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0x1284,0x128a,0xade,0x1290,0xaf4,0xafe,0x5f4,0xb08,0x1296,0x129c,0xb12,0x12a2,0x12a8,0x12ae,0x12b4,0xb28, +1,0x12ba,0x12c0,0x12c6,0xb32,0xb48,0xb5a,1,0x5fc,0x12cc,0x12d2,0x12d8,0xb64,0x12de,1,1, +0x12e4,0x12ea,0xb7a,0x12f0,0xb90,0xb9a,0x600,0xba4,0x12f6,0x12fc,0xbae,0x1302,0x1308,0x130e,0x1314,0xbc4, +1,0x131a,0x1320,0x1326,0xbce,0xbe4,0xbf6,1,0x608,0x132c,0x1332,0x1338,0xc00,0x133e,1,0x1344, +0x134a,0x1350,0xc16,0xc2c,0x1357,0x135d,0x1362,0x1368,0x136e,0x1374,0x137a,0x1380,0x1386,0x138c,0x1392,0x1398, +1,1,0xc42,0xc50,0x139e,0x13a4,0x13aa,0x13b0,0x13b7,0x13bd,0x13c2,0x13c8,0x13ce,0x13d4,0x13da,0x13e0, +0x13e6,0x13ec,0x13f3,0x13f9,0x13fe,0x1404,1,1,0x140a,0x1410,0x1416,0x141c,0x1422,0x1428,0x142f,0x1435, +0x143a,1,1,1,0x1441,0x1447,0x144d,0x1453,1,0x1458,0x145e,0x1465,0x146b,0x1470,0x1476,1, +1,1,1,0x147c,0x1482,0x1489,0x148f,0x1494,0x149a,1,1,1,0xc5e,0xc6c,0x14a0,0x14a6, +0x14ac,0x14b2,1,1,0x14b8,0x14be,0x14c5,0x14cb,0x14d0,0x14d6,0xc7a,0xc84,0x14dc,0x14e2,0x14e9,0x14ef, +0xc8e,0xc98,0x14f5,0x14fb,0x1500,0x1506,1,1,0xca2,0xcac,0xcb6,0xcc0,0x150c,0x1512,0x1518,0x151e, +0x1524,0x152a,0x1531,0x1537,0x153c,0x1542,0x1548,0x154e,0x1554,0x155a,0x1560,0x1566,0x156c,0x1572,0x1578,0x60c, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xcca,0xce4,1,1,1,1,1,1,1,1,1,1,1,1,1,0xcfe, +0xd18,1,1,1,1,1,1,0x610,1,1,1,1,1,1,1,1, +1,1,1,1,1,0x157e,0x1584,0x158a,0x1590,0x1596,0x159c,0x15a2,0x15a8,0x15b0,0x15ba,0x15c4, +0x15ce,0x15d8,0x15e2,0x15ec,0x15f6,1,0x1600,0x160a,0x1614,0x161e,0x1627,0x162d,1,1,0x1632,0x1638, +0x163e,0x1644,0xd32,0xd3c,0x164d,0x1657,0x165f,0x1665,0x166b,1,1,1,0x1670,0x1676,1,1, +0x167c,0x1682,0x168a,0x1694,0x169d,0x16a3,0x16a9,0x16af,0x16b4,0x16ba,0x16c0,0x16c6,0x16cc,0x16d2,0x16d8,0x16de, +0x16e4,0x16ea,0x16f0,0x16f6,0x16fc,0x1702,0x1708,0x170e,0x1714,0x171a,0x1720,0x1726,0x172c,0x1732,0x1738,0x173e, +0x1744,0x174a,0x1750,0x1756,1,1,0x175c,0x1762,1,1,1,1,1,1,0xd46,0xd50, +0xd5a,0xd64,0x176a,0x1774,0x177e,0x1788,0xd6e,0xd78,0x1792,0x179c,0x17a4,0x17aa,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x614,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0xfdcc,0xfdcc,0xfdcc,0xfdcc, +0xfdcc,0xffcc,0xfdcc,0xfdcc,0xfdcc,0xfdcc,0xfdcc,0xfdcc,0xfdcc,0xffcc,0xffcc,0xfdcc,0xffcc,0xfdcc,0xffcc,0xfdcc, +0xfdcc,0xffd0,0xffb8,0xffb8,0xffb8,0xffb8,0xffd0,0xfdb0,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xff94,0xff94,0xfdb8, +0xfdb8,0xfdb8,0xfdb8,0xfd94,0xfd94,0xffb8,0xffb8,0xffb8,0xffb8,0xfdb8,0xfdb8,0xffb8,0xfdb8,0xfdb8,0xffb8,0xffb8, +0xfe02,0xfe02,0xfe02,0xfe02,0xfc02,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,0xffcc,0xffcc,0x3c26,0x3c2c,0xfdcc,0x3c32, +0x3c38,0xfde0,0xffcc,0xffb8,0xffb8,0xffb8,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,1,0xffcc,0xffcc,0xffcc,0xffb8, +0xffb8,0xffb8,0xffb8,0xffcc,0xffd0,0xffb8,0xffb8,0xffcc,0xffd2,0xffd4,0xffd4,0xffd2,0xffd4,0xffd4,0xffd2,0xffcc, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1, +0x29d1,1,1,1,1,1,1,1,1,1,0x29d5,1,1,1,1,1, +1,0x17b1,0x17b7,0x29d9,0x17bd,0x17c3,0x17c9,1,0x17cf,1,0x17d5,0x17db,0x17e3,0x618,1,1, +1,0x634,1,0x644,1,0x658,1,1,1,1,1,0x674,1,0x684,1,1, +1,0x688,1,1,1,0x6a0,0x17eb,0x17f1,0xd82,0x17f7,0xd8c,0x17fd,0x1805,0x6b4,1,1, +1,0x6d4,1,0x6e4,1,0x6fc,1,1,1,1,1,0x71c,1,0x72c,1,1, +1,0x734,1,1,1,0x754,0xd96,0xda8,0x180d,0x1813,0xdba,1,1,1,0x76c,0x1819, +0x181f,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0x1825,0x182b,1,0x1831, +1,1,0x774,0x1837,1,1,1,1,0x183d,0x1843,0x1849,1,0x778,1,1,0x780, +1,0x784,0x790,0x798,0x79c,0x184f,0x7ac,1,1,1,0x7b0,1,1,1,1,0x7b4, +1,1,1,0x7c4,1,1,1,0x7c8,1,0x7cc,1,1,0x7d0,1,1,0x7d8, +1,0x7dc,0x7e8,0x7f0,0x7f4,0x1855,0x804,1,1,1,0x808,1,1,1,1,0x80c, +1,1,1,0x81c,1,1,1,0x820,1,0x824,1,1,0x185b,0x1861,1,0x1867, +1,1,0x828,0x186d,1,1,1,1,0x1873,0x1879,0x187f,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0x82c,0x830,0x1885,0x188b,1,1,1,1,1,1,1,1,1,1,1,0xffcc, 0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,0xfe12,0xfe12,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0xfe0e,1,1,1,1,1, -1,1,1,1,1,1,0xfe12,0xfe12,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe0e, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xffcc,0xffcc,0xffcc,1,0xfe02,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xffb8, -0xffcc,1,0xfe02,0xfe02,0xfe02,0xfe02,0xfe02,0xfe02,0xfe02,1,1,1,1,0xffb8,1,1, -1,1,1,1,0xffcc,1,1,1,0xffcc,0xffcc,1,1,1,1,1,1, -0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffd4,0xffac,0xffb8, -0xff94,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffd0,0xffc8,0xffc8,0xffb8,1,0xffcc, -0xffd2,0xffb8,0xffcc,0xffb8,0x1a66,0x1a6c,0x1a72,0x1a78,0x1a7f,0x1a85,0x1a8b,0x1a91,0x1a99,0x1aa3,0x1aaa,0x1ab0, -0x1ab6,0x1abc,0x1ac2,0x1ac8,0x1acf,0x1ad5,0x1ada,0x1ae0,0x1ae8,0x1af2,0x1afc,0x1b06,0x1b0e,0x1b14,0x1b1a,0x1b20, -0x1b29,0x1b33,0x1b3b,0x1b41,0x1b46,0x1b4c,0x1b52,0x1b58,0x1b5e,0x1b64,0x1b6a,0x1b70,0x1b77,0x1b7d,0x1b82,0x1b88, -0x1b8e,0x1b94,0x1b9c,0x1ba6,0x1bae,0x1bb4,0x1bba,0x1bc0,0x1bc6,0x1bcc,0xdd8,0xde2,0x1bd4,0x1bde,0x1be6,0x1bec, -0x1bf2,0x1bf8,0x1bfe,0x1c04,0x1c0a,0x1c10,0x1c17,0x1c1d,0x1c22,0x1c28,0x1c2e,0x1c34,0x1c3a,0x1c40,0x1c46,0x1c4c, -0x1c54,0x1c5e,0x1c68,0x1c72,0x1c7c,0x1c86,0x1c90,0x1c9a,0x1ca3,0x1ca9,0x1caf,0x1cb5,0x1cba,0x1cc0,0xdec,0xdf6, -0x1cc8,0x1cd2,0x1cda,0x1ce0,0x1ce6,0x1cec,0xe00,0xe0a,0x1cf4,0x1cfe,0x1d08,0x1d12,0x1d1c,0x1d26,0x1d2e,0x1d34, -0x1d3a,0x1d40,0x1d46,0x1d4c,0x1d52,0x1d58,0x1d5e,0x1d64,0x1d6a,0x1d70,0x1d76,0x1d7c,0x1d84,0x1d8e,0x1d98,0x1da2, -0x1daa,0x1db0,0x1db7,0x1dbd,0x1dc2,0x1dc8,0x1dce,0x1dd4,0x1dda,0x1de0,0x1de6,0x1dec,0x1df3,0x1df9,0x1dff,0x1e05, -0x1e0b,0x1e11,0x1e16,0x1e1c,0x1e22,0x1e28,0x1e2f,0x1e35,0x1e3b,0x1e41,0x1e46,0x1e4c,0x1e52,0x1e58,1,0x1e5f, -1,1,1,1,0xe14,0xe22,0x1e64,0x1e6a,0x1e72,0x1e7c,0x1e86,0x1e90,0x1e9a,0x1ea4,0x1eae,0x1eb8, -0x1ec2,0x1ecc,0x1ed6,0x1ee0,0x1eea,0x1ef4,0x1efe,0x1f08,0x1f12,0x1f1c,0x1f26,0x1f30,0xe30,0xe3a,0x1f38,0x1f3e, -0x1f44,0x1f4a,0x1f52,0x1f5c,0x1f66,0x1f70,0x1f7a,0x1f84,0x1f8e,0x1f98,0x1fa2,0x1fac,0x1fb4,0x1fba,0x1fc0,0x1fc6, -0xe44,0xe4e,0x1fcc,0x1fd2,0x1fda,0x1fe4,0x1fee,0x1ff8,0x2002,0x200c,0x2016,0x2020,0x202a,0x2034,0x203e,0x2048, -0x2052,0x205c,0x2066,0x2070,0x207a,0x2084,0x208e,0x2098,0x20a0,0x20a6,0x20ac,0x20b2,0x20ba,0x20c4,0x20ce,0x20d8, -0x20e2,0x20ec,0x20f6,0x2100,0x210a,0x2114,0x211c,0x2122,0x2129,0x212f,0x2134,0x213a,0x2140,0x2146,1,1, -1,1,1,1,0xe58,0xe6e,0xe86,0xe94,0xea2,0xeb0,0xebe,0xecc,0xed8,0xeee,0xf06,0xf14, -0xf22,0xf30,0xf3e,0xf4c,0xf58,0xf66,0x214f,0x2159,0x2163,0x216d,1,1,0xf74,0xf82,0x2177,0x2181, -0x218b,0x2195,1,1,0xf90,0xfa6,0xfbe,0xfcc,0xfda,0xfe8,0xff6,0x1004,0x1010,0x1026,0x103e,0x104c, -0x105a,0x1068,0x1076,0x1084,0x1090,0x10a2,0x219f,0x21a9,0x21b3,0x21bd,0x21c7,0x21d1,0x10b4,0x10c6,0x21db,0x21e5, -0x21ef,0x21f9,0x2203,0x220d,0x10d8,0x10e6,0x2217,0x2221,0x222b,0x2235,1,1,0x10f4,0x1102,0x223f,0x2249, -0x2253,0x225d,1,1,0x1110,0x1122,0x2267,0x2271,0x227b,0x2285,0x228f,0x2299,1,0x1134,1,0x22a3, -1,0x22ad,1,0x22b7,0x1146,0x115c,0x1174,0x1182,0x1190,0x119e,0x11ac,0x11ba,0x11c6,0x11dc,0x11f4,0x1202, -0x1210,0x121e,0x122c,0x123a,0x1246,0x3b8e,0x22bf,0x3b96,0x1250,0x3b9e,0x22c5,0x3ba6,0x22cb,0x3bae,0x22d1,0x3bb6, -0x125a,0x3bbe,1,1,0x22d8,0x22e2,0x22f1,0x2301,0x2311,0x2321,0x2331,0x2341,0x234c,0x2356,0x2365,0x2375, -0x2385,0x2395,0x23a5,0x23b5,0x23c0,0x23ca,0x23d9,0x23e9,0x23f9,0x2409,0x2419,0x2429,0x2434,0x243e,0x244d,0x245d, -0x246d,0x247d,0x248d,0x249d,0x24a8,0x24b2,0x24c1,0x24d1,0x24e1,0x24f1,0x2501,0x2511,0x251c,0x2526,0x2535,0x2545, -0x2555,0x2565,0x2575,0x2585,0x258f,0x2595,0x259d,0x25a4,0x25ad,1,0x1264,0x25b7,0x25bf,0x25c5,0x25cb,0x3bc6, -0x25d0,1,0x2aa2,0x8f0,1,0x25d7,0x25df,0x25e6,0x25ef,1,0x126e,0x25f9,0x2601,0x3bce,0x2607,0x3bd6, -0x260c,0x2613,0x2619,0x261f,0x2625,0x262b,0x2633,0x3be0,1,1,0x263b,0x2643,0x264b,0x2651,0x2657,0x3bea, -1,0x265d,0x2663,0x2669,0x266f,0x2675,0x267d,0x3bf4,0x2685,0x268b,0x2691,0x2699,0x26a1,0x26a7,0x26ad,0x3bfe, -0x26b3,0x26b9,0x3c06,0x2aa7,1,1,0x26c1,0x26c8,0x26d1,1,0x1278,0x26db,0x26e3,0x3c0e,0x26e9,0x3c16, -0x26ee,0x2aab,0x8fc,1,0xfa09,0xfa09,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xffcc,0xffcc,0xfe02,0xfe02,0xffcc,0xffcc,0xffcc,0xffcc,0xfe02,0xfe02,0xfe02,0xffcc, -0xffcc,1,1,1,1,0xffcc,1,1,1,0xfe02,0xfe02,0xffcc,0xffb8,0xffcc,0xfe02,0xfe02, -0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,0x2aae,1,1,1,0x2ab2,0x3c1e,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0x908,1,0x90c,1,0x910,1,1,1,1,1,0x26f5,0x26fb,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0x2701,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,0x2707,0x270d,0x2713, -0x914,1,0x918,1,0x91c,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,0x920,0x2719,1,1,1,0x924,0x271f,1,0x928,0x2725,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,0x92c,0x272b,0x930,0x2731,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0x934,1,1,1, -1,0x2737,1,0x938,0x273d,0x93c,1,0x2743,0x940,0x2749,1,1,1,0x944,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0x274f,0x948,0x2755,1,0x94c,0x950,1,1,1,1,1,1,1,0x275b,0x2761,0x2767, -0x276d,0x2773,0x954,0x958,0x2779,0x277f,0x95c,0x960,0x2785,0x278b,0x964,0x968,0x96c,0x970,1,1, -0x2791,0x2797,0x974,0x978,0x279d,0x27a3,0x97c,0x980,0x27a9,0x27af,1,1,1,1,1,1, -1,0x984,0x988,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,0x98c,1,1,1,1,1,0x990,0x994,1,0x998,0x27b5,0x27bb,0x27c1,0x27c7, -1,1,0x99c,0x9a0,0x9a4,0x9a8,1,1,1,1,1,1,1,1,1,1, -0x27cd,0x27d3,0x27d9,0x27df,1,1,1,1,1,1,0x27e5,0x27eb,0x27f1,0x27f7,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,0x2ab7,0x2abb,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0x2abf,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,0xfe12,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1, -1,1,0xffb4,0xffc8,0xffd0,0xffbc,0xffc0,0xffc0,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0x9ac,1,1,1,1,0x9b0, -0x27fd,0x9b4,0x2803,0x9b8,0x2809,0x9bc,0x280f,0x9c0,0x2815,0x9c4,0x281b,0x9c8,0x2821,0x9cc,0x2827,0x9d0, -0x282d,0x9d4,0x2833,0x9d8,0x2839,0x9dc,0x283f,1,0x9e0,0x2845,0x9e4,0x284b,0x9e8,0x2851,1,1, -1,1,1,0x9ec,0x2857,0x285d,0x9f4,0x2863,0x2869,0x9fc,0x286f,0x2875,0xa04,0x287b,0x2881,0xa0c, -0x2887,0x288d,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0x2893,1,1,1,1,0xfc10,0xfc10,1, -1,0xa14,0x2899,1,1,1,1,1,1,1,0xa18,1,1,1,1,0xa1c, -0x289f,0xa20,0x28a5,0xa24,0x28ab,0xa28,0x28b1,0xa2c,0x28b7,0xa30,0x28bd,0xa34,0x28c3,0xa38,0x28c9,0xa3c, -0x28cf,0xa40,0x28d5,0xa44,0x28db,0xa48,0x28e1,1,0xa4c,0x28e7,0xa50,0x28ed,0xa54,0x28f3,1,1, -1,1,1,0xa58,0x28f9,0x28ff,0xa60,0x2905,0x290b,0xa68,0x2911,0x2917,0xa70,0x291d,0x2923,0xa78, -0x2929,0x292f,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,0xa80,0xa84,0xa88,0xa8c,1,0x2935,1,1,0x293b,0x2941,0x2947,0x294d,1, -1,0xa90,0x2953,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,0xffcc,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,0xfe12,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xfe12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xffb8, -0xffb8,0xffb8,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,0xfe12,1,1,1,1,1,1,1,1, -1,1,1,1,0xfe12,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0x1891,0x1897,1, +1,1,1,1,1,1,1,1,1,1,1,1,0x189d,0x18a3,0x18a9,0x18af, +1,1,0x18b5,0x18bb,0x834,0x838,0x18c1,0x18c7,0x18cd,0x18d3,0x18d9,0x18df,1,1,0x18e5,0x18eb, +0x18f1,0x18f7,0x18fd,0x1903,0x83c,0x840,0x1909,0x190f,0x1915,0x191b,0x1921,0x1927,0x192d,0x1933,0x1939,0x193f, +0x1945,0x194b,1,1,0x1951,0x1957,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc, +0xffcc,0xffcc,0xffbc,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8, +0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffbc,0xffc8,0xffcc,0xfe14,0xfe16,0xfe18,0xfe1a,0xfe1c,0xfe1e,0xfe20,0xfe22, +0xfe24,0xfe26,0xfe26,0xfe28,0xfe2a,0xfe2c,1,0xfe2e,1,0xfe30,0xfe32,1,0xffcc,0xffb8,1,0xfe24, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, +0xfe3c,0xfe3e,0xfe40,1,1,1,1,1,1,1,0x195c,0x1962,0x1969,0x196f,0x1975,0x844, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0x850,1,0x854,0xfe36,0xfe38,0xfe3a,0xfe3c,0xfe3e, +0xfe40,0xfe42,0xfe44,0xfdcc,0xfdcc,0xfdb8,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xfe46,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0x197b,0x858,0x1981,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,0x85c,0x1987,1,0x860,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,0xffcc, +0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,1,1,0xffcc,0xffcc,1,0xffb8,0xffcc,0xffcc,0xffb8,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xffcc,1,0xffcc,0xffcc,0xffb8,1,1,0xffcc,0xffcc,1,1,1, -1,1,0xffcc,0xffcc,1,0xffcc,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,0xfe12,1,1,1,1,1,1,1,1,1, -0x2ac5,0x2ac9,0x2acd,0x2ad1,0x2ad5,0x2ad9,0x2add,0x2ae1,0x2ae1,0x2ae5,0x2ae9,0x2aed,0x2af1,0x2af5,0x2af9,0x2afd, -0x2b01,0x2b05,0x2b09,0x2b0d,0x2b11,0x2b15,0x2b19,0x2b1d,0x2b21,0x2b25,0x2b29,0x2b2d,0x2b31,0x2b35,0x2b39,0x2b3d, -0x2b41,0x2b45,0x2b49,0x2b4d,0x2b51,0x2b55,0x2b59,0x2b5d,0x2b61,0x2b65,0x2b69,0x2b6d,0x2b71,0x2b75,0x2b79,0x2b7d, -0x2b81,0x2b85,0x2b89,0x2b8d,0x2b91,0x2b95,0x2b99,0x2b9d,0x2ba1,0x2ba5,0x2ba9,0x2bad,0x2bb1,0x2bb5,0x2bb9,0x2bbd, -0x2bc1,0x2bc5,0x2bc9,0x2bcd,0x2bd1,0x2bd5,0x2bd9,0x2bdd,0x2be1,0x2be5,0x2be9,0x2bed,0x2bf1,0x2bf5,0x2bf9,0x2bfd, -0x2c01,0x2c05,0x2c09,0x2c0d,0x2c11,0x2c15,0x2c19,0x2c1d,0x2c21,0x2c25,0x2c29,0x2c2d,0x2b11,0x2c31,0x2c35,0x2c39, -0x2c3d,0x2c41,0x2c45,0x2c49,0x2c4d,0x2c51,0x2c55,0x2c59,0x2c5d,0x2c61,0x2c65,0x2c69,0x2c6d,0x2c71,0x2c75,0x2c79, -0x2c7d,0x2c81,0x2c85,0x2c89,0x2c8d,0x2c91,0x2c95,0x2c99,0x2c9d,0x2ca1,0x2ca5,0x2ca9,0x2cad,0x2cb1,0x2cb5,0x2cb9, -0x2cbd,0x2cc1,0x2cc5,0x2cc9,0x2ccd,0x2cd1,0x2cd5,0x2cd9,0x2cdd,0x2ce1,0x2ce5,0x2ce9,0x2ced,0x2cf1,0x2cf5,0x2cf9, -0x2cfd,0x2d01,0x2d05,0x2d09,0x2d0d,0x2d11,0x2d15,0x2d19,0x2d1d,0x2d21,0x2d25,0x2d29,0x2d2d,0x2d31,0x2d35,0x2d39, -0x2d3d,0x2c79,0x2d41,0x2d45,0x2d49,0x2d4d,0x2d51,0x2d55,0x2d59,0x2d5d,0x2c39,0x2d61,0x2d65,0x2d69,0x2d6d,0x2d71, -0x2d75,0x2d79,0x2d7d,0x2d81,0x2d85,0x2d89,0x2d8d,0x2d91,0x2d95,0x2d99,0x2d9d,0x2da1,0x2da5,0x2da9,0x2dad,0x2b11, -0x2db1,0x2db5,0x2db9,0x2dbd,0x2dc1,0x2dc5,0x2dc9,0x2dcd,0x2dd1,0x2dd5,0x2dd9,0x2ddd,0x2de1,0x2de5,0x2de9,0x2ded, -0x2df1,0x2df5,0x2df9,0x2dfd,0x2e01,0x2e05,0x2e09,0x2e0d,0x2e11,0x2e15,0x2e19,0x2c41,0x2e1d,0x2e21,0x2e25,0x2e29, -0x2e2d,0x2e31,0x2e35,0x2e39,0x2e3d,0x2e41,0x2e45,0x2e49,0x2e4d,0x2e51,0x2e55,0x2e59,0x2e5d,0x2e61,0x2e65,0x2e69, -0x2e6d,0x2e71,0x2e75,0x2e79,0x2e7d,0x2e81,0x2e85,0x2e89,0x2e8d,0x2e91,0x2e95,0x2e99,0x2e9d,0x2ea1,0x2ea5,0x2ea9, -0x2ead,0x2eb1,0x2eb5,0x2eb9,0x2ebd,0x2ec1,0x2ec5,0x2ec9,0x2ecd,0x2ed1,0x2ed5,0x2ed9,0x2edd,0x2ee1,1,1, -0x2ee5,1,0x2ee9,1,1,0x2eed,0x2ef1,0x2ef5,0x2ef9,0x2efd,0x2f01,0x2f05,0x2f09,0x2f0d,0x2f11,1, -0x2f15,1,0x2f19,1,1,0x2f1d,0x2f21,1,1,1,0x2f25,0x2f29,0x2f2d,0x2f31,0x2f35,0x2f39, -0x2f3d,0x2f41,0x2f45,0x2f49,0x2f4d,0x2f51,0x2f55,0x2f59,0x2f5d,0x2f61,0x2f65,0x2f69,0x2f6d,0x2f71,0x2f75,0x2f79, -0x2f7d,0x2f81,0x2f85,0x2f89,0x2f8d,0x2f91,0x2f95,0x2f99,0x2f9d,0x2fa1,0x2fa5,0x2fa9,0x2fad,0x2fb1,0x2fb5,0x2fb9, -0x2fbd,0x2fc1,0x2fc5,0x2fc9,0x2fcd,0x2fd1,0x2fd5,0x2d15,0x2fd9,0x2fdd,0x2fe1,0x2fe5,0x2fe9,0x2fed,0x2fed,0x2ff1, -0x2ff5,0x2ff9,0x2ffd,0x3001,0x3005,0x3009,0x300d,0x2f1d,0x3011,0x3015,0x3019,0x301d,0x3021,0x3027,1,1, -0x302b,0x302f,0x3033,0x3037,0x303b,0x303f,0x3043,0x3047,0x2f55,0x304b,0x304f,0x3053,0x2ee5,0x3057,0x305b,0x305f, -0x3063,0x3067,0x306b,0x306f,0x3073,0x3077,0x307b,0x307f,0x3083,0x2f79,0x3087,0x2f7d,0x308b,0x308f,0x3093,0x3097, -0x309b,0x2ee9,0x2b65,0x309f,0x30a3,0x30a7,0x2c7d,0x2dd9,0x30ab,0x30af,0x2f99,0x30b3,0x2f9d,0x30b7,0x30bb,0x30bf, -0x2ef1,0x30c3,0x30c7,0x30cb,0x30cf,0x30d3,0x2ef5,0x30d7,0x30db,0x30df,0x30e3,0x30e7,0x30eb,0x2fd5,0x30ef,0x30f3, -0x2d15,0x30f7,0x2fe5,0x30fb,0x30ff,0x3103,0x3107,0x310b,0x2ff9,0x310f,0x2f19,0x3113,0x2ffd,0x2c31,0x3117,0x3001, -0x311b,0x3009,0x311f,0x3123,0x3127,0x312b,0x312f,0x3011,0x2f09,0x3133,0x3015,0x3137,0x3019,0x313b,0x2ae1,0x313f, -0x3145,0x314b,0x3151,0x3155,0x3159,0x315d,0x3163,0x3169,0x316f,0x3173,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0x3176,0xfe34,0x317c,1,1,1,1, -1,1,1,1,1,1,0x3182,0x3188,0x3190,0x319a,0x31a2,0x31a8,0x31ae,0x31b4,0x31ba,0x31c0, -0x31c6,0x31cc,0x31d2,1,0x31d8,0x31de,0x31e4,0x31ea,0x31f0,1,0x31f6,1,0x31fc,0x3202,1,0x3208, -0x320e,1,0x3214,0x321a,0x3220,0x3226,0x322c,0x3232,0x3238,0x323e,0x3244,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,0xffcc,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0xffb8,1,1,0xffb8,1,1,1, +1,0xfe48,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xffcc,0xffb8,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xffcc,0xffb8,0xffb8,0xffcc,0xffb8,0xffcc, +0xffcc,0xffcc,0xffb8,0xffcc,0xffb8,0xffcc,0xffb8,0xffcc,0xffb8,0xffcc,0xffcc,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,1,1,1,1, +1,1,1,1,1,0xffb8,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,0xffb8,1,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0xffcc,0xfe02,0xffb8,1, -1,1,1,0xfe12,1,1,1,1,1,0xffcc,0xffb8,1,1,1,1,1, +0xffcc,0xffcc,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,0xffcc,0xffcc,0xffcc,1,0xffcc,0xffcc,0xffcc, +0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0xffb8,0xffb8,0xffb8, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,0xa94,0x2959,0xa9a,0x2963,1,1,1,1,1,1,1, -1,0xaa0,1,1,1,1,1,0x296d,1,1,1,1,1,1,1,1, -1,1,1,1,1,0xfe12,0xfc0e,1,1,1,1,1,0xffcc,0xffcc,0xffcc,1, +1,1,1,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, +0xffcc,0xffcc,1,0xffb8,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8, +0xfe36,0xfe38,0xfe3a,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffb8,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, +1,1,1,1,1,1,1,1,0x864,0x198d,1,1,1,1,1,1, +0x868,0x1993,1,0x86c,0x1999,1,1,1,1,1,1,1,0xfc0e,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe12,1,1, +1,0xffcc,0xffb8,0xffcc,0xffcc,1,1,1,0x29dc,0x29e2,0x29e8,0x29ee,0x29f4,0x29fa,0x2a00,0x2a06, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfc00, -1,1,1,1,1,1,0x2977,0x2981,1,0xaa6,0xaac,0xfe12,0xfe12,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0xfe0e,1,0xfc00,1, +1,1,1,1,1,1,1,0x870,1,1,1,0x199f,0x19a5,0xfe12,1,1, +1,1,1,1,1,1,1,0xfc00,1,1,1,1,0x2a0c,0x2a12,1,0x2a18, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xffcc,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,0x2a1e,1,1,0x2a24,1,1,1,1,1,0xfe0e,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe12,1,1, +1,1,1,1,1,1,1,1,1,0x2a2a,0x2a30,0x2a36,1,1,0x2a3c,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0xfe0e,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe12,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,0x878,0x19ab,1,1,0x19b1,0x19b7,0xfe12,1,1,1,1,1,1, +1,1,0xfc00,0xfc00,1,1,1,1,0x2a42,0x2a48,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x884,1, +0x19bd,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,0xfc00,1,1,1,1,1,1,1,0x888,0x890,1,1,0x19c3,0x19c9, +0x19cf,0xfe12,1,1,1,1,1,1,1,1,1,0xfc00,1,1,1,1, +1,1,1,1,1,1,0x894,1,0x19d5,1,1,1,1,0xfe12,1,1, +1,1,1,1,1,0xfea8,0xfcb6,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0xfe0e,1,1,0x898,0x19db,1,0xfc00,1,1,1,0x89c,0x19e1, +0x19e7,1,0xdc4,0x19ef,1,0xfe12,1,1,1,1,1,1,1,0xfc00,0xfc00,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0xfe12,0xfe12,1,0xfc00,1, +1,1,1,1,1,1,0x8a8,0x8b0,1,1,0x19f7,0x19fd,0x1a03,0xfe12,1,1, +1,1,1,1,1,1,1,0xfc00,1,1,1,1,1,1,1,1, +1,1,0xfc12,1,1,1,1,0xfc00,1,1,1,1,1,1,1,1, +1,0x8b4,0x1a09,1,0xdce,0x1a11,0x1a19,0xfc00,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xfece,0xfece,0xfe12,1,1,1,1,1,1,1,1,1,0xfed6,0xfed6,0xfed6,0xfed6, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xfeec,0xfeec,1,1,1,1,1,1, +1,1,1,1,0xfef4,0xfef4,0xfef4,0xfef4,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xffb8,0xffb8,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,0xffb8,1,0xffb8,1,0xffb0,1,1, +1,1,1,1,1,1,1,0x2a4f,1,1,1,1,1,1,1,1, +1,0x2a55,1,1,1,1,0x2a5b,1,1,1,1,0x2a61,1,1,1,1, +0x2a67,1,1,1,1,1,1,1,1,1,1,1,1,0x2a6d,1,1, +1,1,1,1,1,0xff02,0xff04,0x3c40,0xff08,0x3c48,0x2a72,1,0x2a78,1,0xff04,0xff04, +0xff04,0xff04,1,1,0xff04,0x3c50,0xffcc,0xffcc,0xfe12,1,0xffcc,0xffcc,1,1,1,1, +1,1,1,1,1,1,1,0x2a7f,1,1,1,1,1,1,1,1, +1,0x2a85,1,1,1,1,0x2a8b,1,1,1,1,0x2a91,1,1,1,1, +0x2a97,1,1,1,1,1,1,1,1,1,1,1,1,0x2a9d,1,1, +1,1,1,1,1,1,0xffb8,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,0x8c0,0x1a1f,1,1,1,1,1,1,1,0xfc00,1,1,1,1,1, +1,1,1,0xfe0e,1,0xfe12,0xfe12,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,0xffb8,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0xfe12,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,0xfe12,1,1,1,1,1,1,1,1,1,1,0xffcc,1,1, +1,1,1,1,1,1,1,1,1,0xffc8,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,0xffbc,0xffcc,0xffb8,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xffcc, +0xffb8,1,1,1,1,1,1,1,0xfe12,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,0xffb8,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8, +0xffb8,0xffb8,0xffb8,0xffcc,0xffcc,0xffb8,1,1,1,1,1,1,1,0x8c4,0x1a25,0x8c8, +0x1a2b,0x8cc,0x1a31,0x8d0,0x1a37,0x8d4,0x1a3d,1,1,0x8d8,0x1a43,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xfe0e,0xfc00,1,1,1,1,0x8dc,0x1a49,0x8e0,0x1a4f,0x8e4,0x8e8,0x1a55,0x1a5b,0x8ec,0x1a61, +0xfe12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xffcc, +0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,0xfe12,0xfe12,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe0e,1, +1,1,1,1,1,1,1,1,1,1,0xfe12,0xfe12,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,0xfe0e,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0xffcc,0xffcc,0xffcc,1,0xfe02,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,0xffcc, +0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,1,0xfe02,0xfe02,0xfe02,0xfe02,0xfe02,0xfe02,0xfe02,1,1,1, +1,0xffb8,1,1,1,1,1,1,0xffcc,1,1,1,0xffcc,0xffcc,1,1, +1,1,1,1,0xffcc,0xffcc,0xffb8,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc, +0xffcc,0xffd4,0xffac,0xffb8,0xff94,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffd0,0xffc8, +0xffc8,0xffb8,1,0xffcc,0xffd2,0xffb8,0xffcc,0xffb8,0x1a66,0x1a6c,0x1a72,0x1a78,0x1a7f,0x1a85,0x1a8b,0x1a91, +0x1a99,0x1aa3,0x1aaa,0x1ab0,0x1ab6,0x1abc,0x1ac2,0x1ac8,0x1acf,0x1ad5,0x1ada,0x1ae0,0x1ae8,0x1af2,0x1afc,0x1b06, +0x1b0e,0x1b14,0x1b1a,0x1b20,0x1b29,0x1b33,0x1b3b,0x1b41,0x1b46,0x1b4c,0x1b52,0x1b58,0x1b5e,0x1b64,0x1b6a,0x1b70, +0x1b77,0x1b7d,0x1b82,0x1b88,0x1b8e,0x1b94,0x1b9c,0x1ba6,0x1bae,0x1bb4,0x1bba,0x1bc0,0x1bc6,0x1bcc,0xdd8,0xde2, +0x1bd4,0x1bde,0x1be6,0x1bec,0x1bf2,0x1bf8,0x1bfe,0x1c04,0x1c0a,0x1c10,0x1c17,0x1c1d,0x1c22,0x1c28,0x1c2e,0x1c34, +0x1c3a,0x1c40,0x1c46,0x1c4c,0x1c54,0x1c5e,0x1c68,0x1c72,0x1c7c,0x1c86,0x1c90,0x1c9a,0x1ca3,0x1ca9,0x1caf,0x1cb5, +0x1cba,0x1cc0,0xdec,0xdf6,0x1cc8,0x1cd2,0x1cda,0x1ce0,0x1ce6,0x1cec,0xe00,0xe0a,0x1cf4,0x1cfe,0x1d08,0x1d12, +0x1d1c,0x1d26,0x1d2e,0x1d34,0x1d3a,0x1d40,0x1d46,0x1d4c,0x1d52,0x1d58,0x1d5e,0x1d64,0x1d6a,0x1d70,0x1d76,0x1d7c, +0x1d84,0x1d8e,0x1d98,0x1da2,0x1daa,0x1db0,0x1db7,0x1dbd,0x1dc2,0x1dc8,0x1dce,0x1dd4,0x1dda,0x1de0,0x1de6,0x1dec, +0x1df3,0x1df9,0x1dff,0x1e05,0x1e0b,0x1e11,0x1e16,0x1e1c,0x1e22,0x1e28,0x1e2f,0x1e35,0x1e3b,0x1e41,0x1e46,0x1e4c, +0x1e52,0x1e58,1,0x1e5f,1,1,1,1,0xe14,0xe22,0x1e64,0x1e6a,0x1e72,0x1e7c,0x1e86,0x1e90, +0x1e9a,0x1ea4,0x1eae,0x1eb8,0x1ec2,0x1ecc,0x1ed6,0x1ee0,0x1eea,0x1ef4,0x1efe,0x1f08,0x1f12,0x1f1c,0x1f26,0x1f30, +0xe30,0xe3a,0x1f38,0x1f3e,0x1f44,0x1f4a,0x1f52,0x1f5c,0x1f66,0x1f70,0x1f7a,0x1f84,0x1f8e,0x1f98,0x1fa2,0x1fac, +0x1fb4,0x1fba,0x1fc0,0x1fc6,0xe44,0xe4e,0x1fcc,0x1fd2,0x1fda,0x1fe4,0x1fee,0x1ff8,0x2002,0x200c,0x2016,0x2020, +0x202a,0x2034,0x203e,0x2048,0x2052,0x205c,0x2066,0x2070,0x207a,0x2084,0x208e,0x2098,0x20a0,0x20a6,0x20ac,0x20b2, +0x20ba,0x20c4,0x20ce,0x20d8,0x20e2,0x20ec,0x20f6,0x2100,0x210a,0x2114,0x211c,0x2122,0x2129,0x212f,0x2134,0x213a, +0x2140,0x2146,1,1,1,1,1,1,0xe58,0xe6e,0xe86,0xe94,0xea2,0xeb0,0xebe,0xecc, +0xed8,0xeee,0xf06,0xf14,0xf22,0xf30,0xf3e,0xf4c,0xf58,0xf66,0x214f,0x2159,0x2163,0x216d,1,1, +0xf74,0xf82,0x2177,0x2181,0x218b,0x2195,1,1,0xf90,0xfa6,0xfbe,0xfcc,0xfda,0xfe8,0xff6,0x1004, +0x1010,0x1026,0x103e,0x104c,0x105a,0x1068,0x1076,0x1084,0x1090,0x10a2,0x219f,0x21a9,0x21b3,0x21bd,0x21c7,0x21d1, +0x10b4,0x10c6,0x21db,0x21e5,0x21ef,0x21f9,0x2203,0x220d,0x10d8,0x10e6,0x2217,0x2221,0x222b,0x2235,1,1, +0x10f4,0x1102,0x223f,0x2249,0x2253,0x225d,1,1,0x1110,0x1122,0x2267,0x2271,0x227b,0x2285,0x228f,0x2299, +1,0x1134,1,0x22a3,1,0x22ad,1,0x22b7,0x1146,0x115c,0x1174,0x1182,0x1190,0x119e,0x11ac,0x11ba, +0x11c6,0x11dc,0x11f4,0x1202,0x1210,0x121e,0x122c,0x123a,0x1246,0x3b8e,0x22bf,0x3b96,0x1250,0x3b9e,0x22c5,0x3ba6, +0x22cb,0x3bae,0x22d1,0x3bb6,0x125a,0x3bbe,1,1,0x22d8,0x22e2,0x22f1,0x2301,0x2311,0x2321,0x2331,0x2341, +0x234c,0x2356,0x2365,0x2375,0x2385,0x2395,0x23a5,0x23b5,0x23c0,0x23ca,0x23d9,0x23e9,0x23f9,0x2409,0x2419,0x2429, +0x2434,0x243e,0x244d,0x245d,0x246d,0x247d,0x248d,0x249d,0x24a8,0x24b2,0x24c1,0x24d1,0x24e1,0x24f1,0x2501,0x2511, +0x251c,0x2526,0x2535,0x2545,0x2555,0x2565,0x2575,0x2585,0x258f,0x2595,0x259d,0x25a4,0x25ad,1,0x1264,0x25b7, +0x25bf,0x25c5,0x25cb,0x3bc6,0x25d0,1,0x2aa2,0x8f0,1,0x25d7,0x25df,0x25e6,0x25ef,1,0x126e,0x25f9, +0x2601,0x3bce,0x2607,0x3bd6,0x260c,0x2613,0x2619,0x261f,0x2625,0x262b,0x2633,0x3be0,1,1,0x263b,0x2643, +0x264b,0x2651,0x2657,0x3bea,1,0x265d,0x2663,0x2669,0x266f,0x2675,0x267d,0x3bf4,0x2685,0x268b,0x2691,0x2699, +0x26a1,0x26a7,0x26ad,0x3bfe,0x26b3,0x26b9,0x3c06,0x2aa7,1,1,0x26c1,0x26c8,0x26d1,1,0x1278,0x26db, +0x26e3,0x3c0e,0x26e9,0x3c16,0x26ee,0x2aab,0x8fc,1,0xfa09,0xfa09,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xfe02,0xfe02,0xffcc,0xffcc,0xffcc,0xffcc, +0xfe02,0xfe02,0xfe02,0xffcc,0xffcc,1,1,1,1,0xffcc,1,1,1,0xfe02,0xfe02,0xffcc, +0xffb8,0xffcc,0xfe02,0xfe02,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,0x2aae,1,1,1,0x2ab2,0x3c1e, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0x908,1,0x90c,1,0x910,1,1,1,1,1,0x26f5,0x26fb, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x2701,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,0x2707,0x270d,0x2713,0x914,1,0x918,1,0x91c,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0x920,0x2719,1,1,1,0x924,0x271f,1,0x928, +0x2725,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0x92c,0x272b,0x930,0x2731,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0x934,1,1,1,1,0x2737,1,0x938,0x273d,0x93c,1,0x2743,0x940,0x2749,1,1, +1,0x944,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0x274f,0x948,0x2755,1,0x94c,0x950,1,1,1,1,1,1, +1,0x275b,0x2761,0x2767,0x276d,0x2773,0x954,0x958,0x2779,0x277f,0x95c,0x960,0x2785,0x278b,0x964,0x968, +0x96c,0x970,1,1,0x2791,0x2797,0x974,0x978,0x279d,0x27a3,0x97c,0x980,0x27a9,0x27af,1,1, +1,1,1,1,1,0x984,0x988,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,0x98c,1,1,1,1,1,0x990,0x994,1,0x998, +0x27b5,0x27bb,0x27c1,0x27c7,1,1,0x99c,0x9a0,0x9a4,0x9a8,1,1,1,1,1,1, +1,1,1,1,0x27cd,0x27d3,0x27d9,0x27df,1,1,1,1,1,1,0x27e5,0x27eb, +0x27f1,0x27f7,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,0x2ab7,0x2abb,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0x2abf,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0xfe12,0xffcc,0xffcc,0xffcc,0xffcc, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1, +1,1,1,1,1,1,0xffb4,0xffc8,0xffd0,0xffbc,0xffc0,0xffc0,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x9ac,1, +1,1,1,0x9b0,0x27fd,0x9b4,0x2803,0x9b8,0x2809,0x9bc,0x280f,0x9c0,0x2815,0x9c4,0x281b,0x9c8, +0x2821,0x9cc,0x2827,0x9d0,0x282d,0x9d4,0x2833,0x9d8,0x2839,0x9dc,0x283f,1,0x9e0,0x2845,0x9e4,0x284b, +0x9e8,0x2851,1,1,1,1,1,0x9ec,0x2857,0x285d,0x9f4,0x2863,0x2869,0x9fc,0x286f,0x2875, +0xa04,0x287b,0x2881,0xa0c,0x2887,0x288d,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0x2893,1,1,1, +1,0xfc10,0xfc10,1,1,0xa14,0x2899,1,1,1,1,1,1,1,0xa18,1, +1,1,1,0xa1c,0x289f,0xa20,0x28a5,0xa24,0x28ab,0xa28,0x28b1,0xa2c,0x28b7,0xa30,0x28bd,0xa34, +0x28c3,0xa38,0x28c9,0xa3c,0x28cf,0xa40,0x28d5,0xa44,0x28db,0xa48,0x28e1,1,0xa4c,0x28e7,0xa50,0x28ed, +0xa54,0x28f3,1,1,1,1,1,0xa58,0x28f9,0x28ff,0xa60,0x2905,0x290b,0xa68,0x2911,0x2917, +0xa70,0x291d,0x2923,0xa78,0x2929,0x292f,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0xa80,0xa84,0xa88,0xa8c,1,0x2935,1,1,0x293b, +0x2941,0x2947,0x294d,1,1,0xa90,0x2953,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0xffcc,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,0xffcc,0xffcc,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffcc,0xffcc,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,0xfe12,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0xfe12,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, +0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,0xffb8,0xffb8,0xffb8,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0xfe12,1,1,1,1, 1,1,1,1,1,1,1,1,0xfe12,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffcc,1,0xffcc,0xffcc,0xffb8,1,1,0xffcc, +0xffcc,1,1,1,1,1,0xffcc,0xffcc,1,0xffcc,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,0xfe12,1,1,1,1,1, +1,1,1,1,0x2ac5,0x2ac9,0x2acd,0x2ad1,0x2ad5,0x2ad9,0x2add,0x2ae1,0x2ae1,0x2ae5,0x2ae9,0x2aed, +0x2af1,0x2af5,0x2af9,0x2afd,0x2b01,0x2b05,0x2b09,0x2b0d,0x2b11,0x2b15,0x2b19,0x2b1d,0x2b21,0x2b25,0x2b29,0x2b2d, +0x2b31,0x2b35,0x2b39,0x2b3d,0x2b41,0x2b45,0x2b49,0x2b4d,0x2b51,0x2b55,0x2b59,0x2b5d,0x2b61,0x2b65,0x2b69,0x2b6d, +0x2b71,0x2b75,0x2b79,0x2b7d,0x2b81,0x2b85,0x2b89,0x2b8d,0x2b91,0x2b95,0x2b99,0x2b9d,0x2ba1,0x2ba5,0x2ba9,0x2bad, +0x2bb1,0x2bb5,0x2bb9,0x2bbd,0x2bc1,0x2bc5,0x2bc9,0x2bcd,0x2bd1,0x2bd5,0x2bd9,0x2bdd,0x2be1,0x2be5,0x2be9,0x2bed, +0x2bf1,0x2bf5,0x2bf9,0x2bfd,0x2c01,0x2c05,0x2c09,0x2c0d,0x2c11,0x2c15,0x2c19,0x2c1d,0x2c21,0x2c25,0x2c29,0x2c2d, +0x2b11,0x2c31,0x2c35,0x2c39,0x2c3d,0x2c41,0x2c45,0x2c49,0x2c4d,0x2c51,0x2c55,0x2c59,0x2c5d,0x2c61,0x2c65,0x2c69, +0x2c6d,0x2c71,0x2c75,0x2c79,0x2c7d,0x2c81,0x2c85,0x2c89,0x2c8d,0x2c91,0x2c95,0x2c99,0x2c9d,0x2ca1,0x2ca5,0x2ca9, +0x2cad,0x2cb1,0x2cb5,0x2cb9,0x2cbd,0x2cc1,0x2cc5,0x2cc9,0x2ccd,0x2cd1,0x2cd5,0x2cd9,0x2cdd,0x2ce1,0x2ce5,0x2ce9, +0x2ced,0x2cf1,0x2cf5,0x2cf9,0x2cfd,0x2d01,0x2d05,0x2d09,0x2d0d,0x2d11,0x2d15,0x2d19,0x2d1d,0x2d21,0x2d25,0x2d29, +0x2d2d,0x2d31,0x2d35,0x2d39,0x2d3d,0x2c79,0x2d41,0x2d45,0x2d49,0x2d4d,0x2d51,0x2d55,0x2d59,0x2d5d,0x2c39,0x2d61, +0x2d65,0x2d69,0x2d6d,0x2d71,0x2d75,0x2d79,0x2d7d,0x2d81,0x2d85,0x2d89,0x2d8d,0x2d91,0x2d95,0x2d99,0x2d9d,0x2da1, +0x2da5,0x2da9,0x2dad,0x2b11,0x2db1,0x2db5,0x2db9,0x2dbd,0x2dc1,0x2dc5,0x2dc9,0x2dcd,0x2dd1,0x2dd5,0x2dd9,0x2ddd, +0x2de1,0x2de5,0x2de9,0x2ded,0x2df1,0x2df5,0x2df9,0x2dfd,0x2e01,0x2e05,0x2e09,0x2e0d,0x2e11,0x2e15,0x2e19,0x2c41, +0x2e1d,0x2e21,0x2e25,0x2e29,0x2e2d,0x2e31,0x2e35,0x2e39,0x2e3d,0x2e41,0x2e45,0x2e49,0x2e4d,0x2e51,0x2e55,0x2e59, +0x2e5d,0x2e61,0x2e65,0x2e69,0x2e6d,0x2e71,0x2e75,0x2e79,0x2e7d,0x2e81,0x2e85,0x2e89,0x2e8d,0x2e91,0x2e95,0x2e99, +0x2e9d,0x2ea1,0x2ea5,0x2ea9,0x2ead,0x2eb1,0x2eb5,0x2eb9,0x2ebd,0x2ec1,0x2ec5,0x2ec9,0x2ecd,0x2ed1,0x2ed5,0x2ed9, +0x2edd,0x2ee1,1,1,0x2ee5,1,0x2ee9,1,1,0x2eed,0x2ef1,0x2ef5,0x2ef9,0x2efd,0x2f01,0x2f05, +0x2f09,0x2f0d,0x2f11,1,0x2f15,1,0x2f19,1,1,0x2f1d,0x2f21,1,1,1,0x2f25,0x2f29, +0x2f2d,0x2f31,0x2f35,0x2f39,0x2f3d,0x2f41,0x2f45,0x2f49,0x2f4d,0x2f51,0x2f55,0x2f59,0x2f5d,0x2f61,0x2f65,0x2f69, +0x2f6d,0x2f71,0x2f75,0x2f79,0x2f7d,0x2f81,0x2f85,0x2f89,0x2f8d,0x2f91,0x2f95,0x2f99,0x2f9d,0x2fa1,0x2fa5,0x2fa9, +0x2fad,0x2fb1,0x2fb5,0x2fb9,0x2fbd,0x2fc1,0x2fc5,0x2fc9,0x2fcd,0x2fd1,0x2fd5,0x2d15,0x2fd9,0x2fdd,0x2fe1,0x2fe5, +0x2fe9,0x2fed,0x2fed,0x2ff1,0x2ff5,0x2ff9,0x2ffd,0x3001,0x3005,0x3009,0x300d,0x2f1d,0x3011,0x3015,0x3019,0x301d, +0x3021,0x3027,1,1,0x302b,0x302f,0x3033,0x3037,0x303b,0x303f,0x3043,0x3047,0x2f55,0x304b,0x304f,0x3053, +0x2ee5,0x3057,0x305b,0x305f,0x3063,0x3067,0x306b,0x306f,0x3073,0x3077,0x307b,0x307f,0x3083,0x2f79,0x3087,0x2f7d, +0x308b,0x308f,0x3093,0x3097,0x309b,0x2ee9,0x2b65,0x309f,0x30a3,0x30a7,0x2c7d,0x2dd9,0x30ab,0x30af,0x2f99,0x30b3, +0x2f9d,0x30b7,0x30bb,0x30bf,0x2ef1,0x30c3,0x30c7,0x30cb,0x30cf,0x30d3,0x2ef5,0x30d7,0x30db,0x30df,0x30e3,0x30e7, +0x30eb,0x2fd5,0x30ef,0x30f3,0x2d15,0x30f7,0x2fe5,0x30fb,0x30ff,0x3103,0x3107,0x310b,0x2ff9,0x310f,0x2f19,0x3113, +0x2ffd,0x2c31,0x3117,0x3001,0x311b,0x3009,0x311f,0x3123,0x3127,0x312b,0x312f,0x3011,0x2f09,0x3133,0x3015,0x3137, +0x3019,0x313b,0x2ae1,0x313f,0x3145,0x314b,0x3151,0x3155,0x3159,0x315d,0x3163,0x3169,0x316f,0x3173,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0x3176,0xfe34,0x317c, +1,1,1,1,1,1,1,1,1,1,0x3182,0x3188,0x3190,0x319a,0x31a2,0x31a8, +0x31ae,0x31b4,0x31ba,0x31c0,0x31c6,0x31cc,0x31d2,1,0x31d8,0x31de,0x31e4,0x31ea,0x31f0,1,0x31f6,1, +0x31fc,0x3202,1,0x3208,0x320e,1,0x3214,0x321a,0x3220,0x3226,0x322c,0x3232,0x3238,0x323e,0x3244,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffcc,0xffcc, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0xffb8,1,1, +0xffb8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,0xffb8,1,0xffcc,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xffcc,0xfe02,0xffb8,1,1,1,1,0xfe12,1,1,1,1,1,0xffcc,0xffb8,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,0xffb8,0xffb8,0xffcc,0xffcc,0xffcc,0xffb8,0xffcc,0xffb8,0xffb8,0xffb8, +0xffb8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0xa94,0x2959,0xa9a, +0x2963,1,1,1,1,1,1,1,1,0xaa0,1,1,1,1,1,0x296d, +1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe12,0xfc0e,1, +1,1,1,1,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0xfc00,1,1,1,1,1,1,0x2977,0x2981, +1,0xaa6,0xaac,0xfe12,0xfe12,1,1,1,1,1,1,1,1,1,1,1, +0xfe12,1,1,1,1,1,1,1,1,1,0xfe0e,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,0xfe12,0xfe0e,1,1,1,1,1,1,1,1,1,1,0xfe0e,0xfe12,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0xfe0e,0xfe0e,1,0xfc00,1, +1,1,1,1,1,1,1,0xab2,1,1,1,0x298b,0x2995,0xfe12,1,1, +1,1,1,1,1,1,1,0xfc00,1,1,1,1,1,1,1,1, +1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc, +0xffcc,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe12,1, 1,1,0xfe0e,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,0xffcc,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0xfc00,1,1,1, +1,1,1,1,1,0xabe,0xfc00,0x299f,0x29a9,0xfc00,0x29b3,1,1,1,0xfe12,0xfe0e, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfc00, +1,1,1,1,1,1,1,1,0xad0,0xad6,0x29bd,0x29c7,1,1,1,0xfe12, +0xfe0e,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,0xfe12,0xfe0e,1,1,1,1,1,1,1,1,1,1,1,0xfe12, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,0xfe12,0xfe0e,1,1,1,1,1, -1,1,1,1,1,0xfe0e,0xfe12,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xab2, -1,1,1,0x298b,0x2995,0xfe12,1,1,1,1,1,1,1,1,1,0xfc00, -1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1, -1,1,1,1,1,1,0xfe12,1,1,1,0xfe0e,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xfc00,1,1,1,1,1,1,1,1,0xabe,0xfc00,0x299f, -0x29a9,0xfc00,0x29b3,1,1,1,0xfe12,0xfe0e,1,1,1,1,1,1,1,1, +1,1,1,1,1,0xfe12,1,1,1,1,1,1,1,1,0xfe0e,1, +0xfe12,0xfe12,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe12, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,0xfc00,1,1,1,1,1,1,1,1, -0xad0,0xad6,0x29bd,0x29c7,1,1,1,0xfe12,0xfe0e,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0xfe12,0xfe0e,1,1,1,1, -1,1,1,1,1,1,1,0xfe12,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,0xfe12,1,1,1,1,1,1,1,1,0xfe0e,1,0xfe12,0xfe12,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0xfe02,0xfe02,0xfe02,0xfe02,0xfe02,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,0xfe02,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,0x324a,0x3254,0x3268,0x3280,0x3298,0x32b0,0x32c8,0xffb0,0xffb0,0xfe02, -0xfe02,0xfe02,1,1,1,0xffc4,0xffb0,0xffb0,0xffb0,0xffb0,0xffb0,1,1,1,1,1, -1,1,1,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,1,1,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffb8,0xffb8,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,1,1, -1,1,1,1,1,1,1,1,1,1,1,0x32d6,0x32e0,0x32f4,0x330c,0x3324, -0x333c,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, -0xffcc,0xffcc,1,0xffcc,0xffcc,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,1,1,1,1,1,1,1,1,1, -0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xfe0e,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0x334b,0x334f,0x3353,0x3357, -0x335d,0x2f3d,0x3361,0x3365,0x3369,0x336d,0x2f41,0x3371,0x3375,0x3379,0x2f45,0x337f,0x3383,0x3387,0x338b,0x3391, -0x3395,0x3399,0x339d,0x33a3,0x33a7,0x33ab,0x33af,0x302f,0x33b3,0x33b9,0x33bd,0x33c1,0x33c5,0x33c9,0x33cd,0x33d1, -0x33d5,0x3043,0x2f49,0x2f4d,0x3047,0x33d9,0x33dd,0x2c49,0x33e1,0x2f51,0x33e5,0x33e9,0x33ed,0x33f1,0x33f1,0x33f1, -0x33f5,0x33fb,0x33ff,0x3403,0x3407,0x340d,0x3411,0x3415,0x3419,0x341d,0x3421,0x3425,0x3429,0x342d,0x3431,0x3435, -0x3439,0x343d,0x343d,0x304f,0x3441,0x3445,0x3449,0x344d,0x2f59,0x3451,0x3455,0x3459,0x2ead,0x345d,0x3461,0x3465, -0x3469,0x346d,0x3471,0x3475,0x3479,0x347d,0x3483,0x3487,0x348b,0x348f,0x3493,0x3497,0x349b,0x34a1,0x34a7,0x34ab, -0x34af,0x34b3,0x34b7,0x34bb,0x34bf,0x34c3,0x34c7,0x34c7,0x34cb,0x34d1,0x34d5,0x2c39,0x34d9,0x34dd,0x34e3,0x34e7, -0x34eb,0x34ef,0x34f3,0x34f7,0x2f6d,0x34fb,0x34ff,0x3503,0x3509,0x350d,0x3513,0x3517,0x351b,0x351f,0x3523,0x3527, -0x352b,0x352f,0x3533,0x3537,0x353b,0x353f,0x3545,0x3549,0x354d,0x3551,0x2b61,0x3555,0x355b,0x355f,0x355f,0x3565, -0x3569,0x3569,0x356d,0x3571,0x3577,0x357d,0x3581,0x3585,0x3589,0x358d,0x3591,0x3595,0x3599,0x359d,0x35a1,0x2f71, -0x35a5,0x35ab,0x35af,0x35b3,0x307f,0x35b3,0x35b7,0x2f79,0x35bb,0x35bf,0x35c3,0x35c7,0x2f7d,0x2af5,0x35cb,0x35cf, -0x35d3,0x35d7,0x35db,0x35df,0x35e3,0x35e9,0x35ed,0x35f1,0x35f5,0x35f9,0x35fd,0x3603,0x3607,0x360b,0x360f,0x3613, -0x3617,0x361b,0x361f,0x3623,0x2f81,0x3627,0x362b,0x3631,0x3635,0x3639,0x363d,0x2f89,0x3641,0x3645,0x3649,0x364d, -0x3651,0x3655,0x3659,0x365d,0x2b65,0x309f,0x3661,0x3665,0x3669,0x366d,0x3673,0x3677,0x367b,0x367f,0x2f8d,0x3683, -0x3689,0x368d,0x3691,0x3151,0x3695,0x3699,0x369d,0x36a1,0x36a5,0x36ab,0x36af,0x36b3,0x36b7,0x36bd,0x36c1,0x36c5, -0x36c9,0x2c7d,0x36cd,0x36d1,0x36d7,0x36dd,0x36e3,0x36e7,0x36ed,0x36f1,0x36f5,0x36f9,0x36fd,0x2f91,0x2dd9,0x3701, -0x3705,0x3709,0x370d,0x3713,0x3717,0x371b,0x371f,0x30af,0x3723,0x3727,0x372d,0x3731,0x3735,0x373b,0x3741,0x3745, -0x30b3,0x3749,0x374d,0x3751,0x3755,0x3759,0x375d,0x3761,0x3767,0x376b,0x3771,0x3775,0x377b,0x30bb,0x377f,0x3783, -0x3789,0x378d,0x3791,0x3797,0x379d,0x37a1,0x37a5,0x37a9,0x37ad,0x37ad,0x37b1,0x37b5,0x30c3,0x37b9,0x37bd,0x37c1, -0x37c5,0x37c9,0x37cf,0x37d3,0x2c45,0x37d9,0x37df,0x37e3,0x37e9,0x37ef,0x37f5,0x37f9,0x30db,0x37fd,0x3803,0x3809, -0x380f,0x3815,0x3819,0x3819,0x30df,0x3159,0x381d,0x3821,0x3825,0x3829,0x382f,0x2bad,0x30e7,0x3833,0x3837,0x2fbd, -0x383d,0x3843,0x2f05,0x3849,0x384d,0x2fcd,0x3851,0x3855,0x3859,0x385f,0x385f,0x3865,0x3869,0x386d,0x3873,0x3877, -0x387b,0x387f,0x3885,0x3889,0x388d,0x3891,0x3895,0x3899,0x389f,0x38a3,0x38a7,0x38ab,0x38af,0x38b3,0x38b7,0x38bd, -0x38c3,0x38c7,0x38cd,0x38d1,0x38d7,0x38db,0x2fe5,0x38df,0x38e5,0x38eb,0x38ef,0x38f5,0x38f9,0x38ff,0x3903,0x3907, -0x390b,0x390f,0x3913,0x3917,0x391d,0x3923,0x3929,0x3565,0x392f,0x3933,0x3937,0x393b,0x393f,0x3943,0x3947,0x394b, -0x394f,0x3953,0x3957,0x395b,0x2c8d,0x3961,0x3965,0x3969,0x396d,0x3971,0x3975,0x2ff1,0x3979,0x397d,0x3981,0x3985, -0x3989,0x398f,0x3995,0x399b,0x399f,0x39a3,0x39a7,0x39ab,0x39b1,0x39b5,0x39bb,0x39bf,0x39c3,0x39c9,0x39cf,0x39d3, -0x2b99,0x39d7,0x39db,0x39df,0x39e3,0x39e7,0x39eb,0x3103,0x39ef,0x39f3,0x39f7,0x39fb,0x39ff,0x3a03,0x3a07,0x3a0b, -0x3a0f,0x3a13,0x3a19,0x3a1d,0x3a21,0x3a25,0x3a29,0x3a2d,0x3a33,0x3a39,0x3a3d,0x3a41,0x3117,0x311b,0x3a45,0x3a49, -0x3a4f,0x3a53,0x3a57,0x3a5b,0x3a5f,0x3a65,0x3a6b,0x3a6f,0x3a73,0x3a77,0x3a7d,0x311f,0x3a81,0x3a87,0x3a8d,0x3a91, -0x3a95,0x3a99,0x3a9f,0x3aa3,0x3aa7,0x3aab,0x3aaf,0x3ab3,0x3ab7,0x3abb,0x3ac1,0x3ac5,0x3ac9,0x3acd,0x3ad3,0x3ad7, -0x3adb,0x3adf,0x3ae3,0x3ae9,0x3aef,0x3af3,0x3af7,0x3afb,0x3b01,0x3b05,0x3137,0x3137,0x3b0b,0x3b0f,0x3b15,0x3b19, -0x3b1d,0x3b21,0x3b25,0x3b29,0x3b2d,0x3b31,0x313b,0x3b37,0x3b3b,0x3b3f,0x3b43,0x3b47,0x3b4b,0x3b51,0x3b55,0x3b5b, -0x3b61,0x3b67,0x3b6b,0x3b6f,0x3b73,0x3b77,0x3b7b,0x3b7f,0x3b83,0x3b87,1,1,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe00,0xfe00,0xfe00, -0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00, -0xfe00,0xfe00,1,1,1,1,1,1,1,1,1,1,0xfe00,0xfe00,0xfe00,0xfe00, -0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00, -0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xadc,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283, -0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283, -0xadc,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283, -0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,1,1,1,1,1,1,1,1, +0xfe02,0xfe02,0xfe02,0xfe02,0xfe02,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xfe02,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x324a,0x3254, +0x3268,0x3280,0x3298,0x32b0,0x32c8,0xffb0,0xffb0,0xfe02,0xfe02,0xfe02,1,1,1,0xffc4,0xffb0,0xffb0, +0xffb0,0xffb0,0xffb0,1,1,1,1,1,1,1,1,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8, +0xffb8,0xffb8,0xffb8,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffb8,0xffb8,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0x1283,0x1283,0x1283,0x1283,0xadc,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283, +1,1,0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1, +1,1,1,0x32d6,0x32e0,0x32f4,0x330c,0x3324,0x333c,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1, +0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc, +0xffcc,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,0xffcc,0xffcc,1,0xffcc,0xffcc, +0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,1, +1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xfe0e,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0x334b,0x334f,0x3353,0x3357,0x335d,0x2f3d,0x3361,0x3365,0x3369,0x336d,0x2f41,0x3371, +0x3375,0x3379,0x2f45,0x337f,0x3383,0x3387,0x338b,0x3391,0x3395,0x3399,0x339d,0x33a3,0x33a7,0x33ab,0x33af,0x302f, +0x33b3,0x33b9,0x33bd,0x33c1,0x33c5,0x33c9,0x33cd,0x33d1,0x33d5,0x3043,0x2f49,0x2f4d,0x3047,0x33d9,0x33dd,0x2c49, +0x33e1,0x2f51,0x33e5,0x33e9,0x33ed,0x33f1,0x33f1,0x33f1,0x33f5,0x33fb,0x33ff,0x3403,0x3407,0x340d,0x3411,0x3415, +0x3419,0x341d,0x3421,0x3425,0x3429,0x342d,0x3431,0x3435,0x3439,0x343d,0x343d,0x304f,0x3441,0x3445,0x3449,0x344d, +0x2f59,0x3451,0x3455,0x3459,0x2ead,0x345d,0x3461,0x3465,0x3469,0x346d,0x3471,0x3475,0x3479,0x347d,0x3483,0x3487, +0x348b,0x348f,0x3493,0x3497,0x349b,0x34a1,0x34a7,0x34ab,0x34af,0x34b3,0x34b7,0x34bb,0x34bf,0x34c3,0x34c7,0x34c7, +0x34cb,0x34d1,0x34d5,0x2c39,0x34d9,0x34dd,0x34e3,0x34e7,0x34eb,0x34ef,0x34f3,0x34f7,0x2f6d,0x34fb,0x34ff,0x3503, +0x3509,0x350d,0x3513,0x3517,0x351b,0x351f,0x3523,0x3527,0x352b,0x352f,0x3533,0x3537,0x353b,0x353f,0x3545,0x3549, +0x354d,0x3551,0x2b61,0x3555,0x355b,0x355f,0x355f,0x3565,0x3569,0x3569,0x356d,0x3571,0x3577,0x357d,0x3581,0x3585, +0x3589,0x358d,0x3591,0x3595,0x3599,0x359d,0x35a1,0x2f71,0x35a5,0x35ab,0x35af,0x35b3,0x307f,0x35b3,0x35b7,0x2f79, +0x35bb,0x35bf,0x35c3,0x35c7,0x2f7d,0x2af5,0x35cb,0x35cf,0x35d3,0x35d7,0x35db,0x35df,0x35e3,0x35e9,0x35ed,0x35f1, +0x35f5,0x35f9,0x35fd,0x3603,0x3607,0x360b,0x360f,0x3613,0x3617,0x361b,0x361f,0x3623,0x2f81,0x3627,0x362b,0x3631, +0x3635,0x3639,0x363d,0x2f89,0x3641,0x3645,0x3649,0x364d,0x3651,0x3655,0x3659,0x365d,0x2b65,0x309f,0x3661,0x3665, +0x3669,0x366d,0x3673,0x3677,0x367b,0x367f,0x2f8d,0x3683,0x3689,0x368d,0x3691,0x3151,0x3695,0x3699,0x369d,0x36a1, +0x36a5,0x36ab,0x36af,0x36b3,0x36b7,0x36bd,0x36c1,0x36c5,0x36c9,0x2c7d,0x36cd,0x36d1,0x36d7,0x36dd,0x36e3,0x36e7, +0x36ed,0x36f1,0x36f5,0x36f9,0x36fd,0x2f91,0x2dd9,0x3701,0x3705,0x3709,0x370d,0x3713,0x3717,0x371b,0x371f,0x30af, +0x3723,0x3727,0x372d,0x3731,0x3735,0x373b,0x3741,0x3745,0x30b3,0x3749,0x374d,0x3751,0x3755,0x3759,0x375d,0x3761, +0x3767,0x376b,0x3771,0x3775,0x377b,0x30bb,0x377f,0x3783,0x3789,0x378d,0x3791,0x3797,0x379d,0x37a1,0x37a5,0x37a9, +0x37ad,0x37ad,0x37b1,0x37b5,0x30c3,0x37b9,0x37bd,0x37c1,0x37c5,0x37c9,0x37cf,0x37d3,0x2c45,0x37d9,0x37df,0x37e3, +0x37e9,0x37ef,0x37f5,0x37f9,0x30db,0x37fd,0x3803,0x3809,0x380f,0x3815,0x3819,0x3819,0x30df,0x3159,0x381d,0x3821, +0x3825,0x3829,0x382f,0x2bad,0x30e7,0x3833,0x3837,0x2fbd,0x383d,0x3843,0x2f05,0x3849,0x384d,0x2fcd,0x3851,0x3855, +0x3859,0x385f,0x385f,0x3865,0x3869,0x386d,0x3873,0x3877,0x387b,0x387f,0x3885,0x3889,0x388d,0x3891,0x3895,0x3899, +0x389f,0x38a3,0x38a7,0x38ab,0x38af,0x38b3,0x38b7,0x38bd,0x38c3,0x38c7,0x38cd,0x38d1,0x38d7,0x38db,0x2fe5,0x38df, +0x38e5,0x38eb,0x38ef,0x38f5,0x38f9,0x38ff,0x3903,0x3907,0x390b,0x390f,0x3913,0x3917,0x391d,0x3923,0x3929,0x3565, +0x392f,0x3933,0x3937,0x393b,0x393f,0x3943,0x3947,0x394b,0x394f,0x3953,0x3957,0x395b,0x2c8d,0x3961,0x3965,0x3969, +0x396d,0x3971,0x3975,0x2ff1,0x3979,0x397d,0x3981,0x3985,0x3989,0x398f,0x3995,0x399b,0x399f,0x39a3,0x39a7,0x39ab, +0x39b1,0x39b5,0x39bb,0x39bf,0x39c3,0x39c9,0x39cf,0x39d3,0x2b99,0x39d7,0x39db,0x39df,0x39e3,0x39e7,0x39eb,0x3103, +0x39ef,0x39f3,0x39f7,0x39fb,0x39ff,0x3a03,0x3a07,0x3a0b,0x3a0f,0x3a13,0x3a19,0x3a1d,0x3a21,0x3a25,0x3a29,0x3a2d, +0x3a33,0x3a39,0x3a3d,0x3a41,0x3117,0x311b,0x3a45,0x3a49,0x3a4f,0x3a53,0x3a57,0x3a5b,0x3a5f,0x3a65,0x3a6b,0x3a6f, +0x3a73,0x3a77,0x3a7d,0x311f,0x3a81,0x3a87,0x3a8d,0x3a91,0x3a95,0x3a99,0x3a9f,0x3aa3,0x3aa7,0x3aab,0x3aaf,0x3ab3, +0x3ab7,0x3abb,0x3ac1,0x3ac5,0x3ac9,0x3acd,0x3ad3,0x3ad7,0x3adb,0x3adf,0x3ae3,0x3ae9,0x3aef,0x3af3,0x3af7,0x3afb, +0x3b01,0x3b05,0x3137,0x3137,0x3b0b,0x3b0f,0x3b15,0x3b19,0x3b1d,0x3b21,0x3b25,0x3b29,0x3b2d,0x3b31,0x313b,0x3b37, +0x3b3b,0x3b3f,0x3b43,0x3b47,0x3b4b,0x3b51,0x3b55,0x3b5b,0x3b61,0x3b67,0x3b6b,0x3b6f,0x3b73,0x3b77,0x3b7b,0x3b7f, +0x3b83,0x3b87,1,1,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00, +0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,1,1,1,1,1,1, +1,1,1,1,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00, +0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,0xfe00,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0xadc,0x1283,0x1283,0x1283, 0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283, -0x1283,0x1283,0x1283,0x1283,0x3c54,1,0x3c54,1,0x3c54,0x3c54,0x3c54,0x3c54,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x3c54,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x3c54, -1,1,1,1,0x3c54,1,1,1,0x3c54,1,0x3c54,1,1,1,1,1, +0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0xadc,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283, +0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0x1283,0x1283,0x1283,0x1283, +0xadc,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283, +0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x1283,0x3c54,1,0x3c54,0x3c54, +0x3c54,0x3c54,0x3c54,0x3c54,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,0x3c54,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0x3c54,1,1,1,1,0x3c54,1,1,1, +0x3c54,1,0x3c54,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0x3b87,1,1,1,1,1 +1,1,0x3b87,1,1,1,1,1 }; static const uint16_t norm2_nfc_data_extraData[7724]={ @@ -1120,7 +1133,7 @@ static const uint16_t norm2_nfc_data_extraData[7724]={ }; static const uint8_t norm2_nfc_data_smallFCD[256]={ -0xc0,0xef,3,0x7f,0xdf,0x70,0xcf,0x87,0xc7,0x66,0x66,0x46,0x64,0x46,0x66,0x5b, +0xc0,0xef,3,0x7f,0xdf,0x70,0xcf,0x87,0xc7,0xe6,0x66,0x46,0x64,0x46,0x66,0x5b, 0x12,0,0,4,0,0,0,0x43,0x20,2,0x29,0xae,0xc2,0xc0,0xff,0xff, 0xc0,0x72,0xbf,0,0,0,0,0,0,0,0x40,0,0x80,0x88,0,0, 0xfe,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -1140,16 +1153,16 @@ static const uint8_t norm2_nfc_data_smallFCD[256]={ static const UTrie2 norm2_nfc_data_trie={ norm2_nfc_data_trieIndex, - norm2_nfc_data_trieIndex+2720, + norm2_nfc_data_trieIndex+2728, NULL, - 2720, - 7056, + 2728, + 7248, 0x188, - 0xb1c, + 0xb24, 0x1, 0x1, 0x30000, - 0x262c, + 0x26f4, NULL, 0, FALSE, FALSE, 0, NULL }; diff --git a/deps/icu-small/source/common/propname_data.h b/deps/icu-small/source/common/propname_data.h index 5876fc7073..afa876c0fa 100644 --- a/deps/icu-small/source/common/propname_data.h +++ b/deps/icu-small/source/common/propname_data.h @@ -13,91 +13,93 @@ U_NAMESPACE_BEGIN -const int32_t PropNameData::indexes[8]={0x20,0x13c8,0x4831,0x92bb,0x92bb,0x92bb,0x2f,0}; +const int32_t PropNameData::indexes[8]={0x20,0x1424,0x49e9,0x966c,0x966c,0x966c,0x2f,0}; -const int32_t PropNameData::valueMaps[1258]={ -6,0,0x40,0,0xdb,0x356,0xdb,0x36c,0xdb,0x381,0xdb,0x397,0xdb,0x3a2,0xdb,0x3c3, -0xdb,0x3d3,0xdb,0x3e2,0xdb,0x3f0,0xdb,0x414,0xdb,0x42b,0xdb,0x443,0xdb,0x45a,0xdb,0x469, -0xdb,0x478,0xdb,0x489,0xdb,0x497,0xdb,0x4a9,0xdb,0x4c3,0xdb,0x4de,0xdb,0x4f3,0xdb,0x510, -0xdb,0x521,0xdb,0x52c,0xdb,0x54b,0xdb,0x561,0xdb,0x572,0xdb,0x582,0xdb,0x59d,0xdb,0x5b6, -0xdb,0x5c7,0xdb,0x5e1,0xdb,0x5f4,0xdb,0x604,0xdb,0x61e,0xdb,0x637,0xdb,0x64e,0xdb,0x662, -0xdb,0x678,0xdb,0x68c,0xdb,0x6a2,0xdb,0x6bc,0xdb,0x6d4,0xdb,0x6f0,0xdb,0x6f8,0xdb,0x700, -0xdb,0x708,0xdb,0x710,0xdb,0x719,0xdb,0x726,0xdb,0x739,0xdb,0x756,0xdb,0x773,0xdb,0x790, -0xdb,0x7ae,0xdb,0x7cc,0xdb,0x7f0,0xdb,0x7fd,0xdb,0x824,0xdb,0x843,0xdb,0x86c,0xdb,0x88d, -0xdb,0x8a4,0xdb,0x1000,0x1016,0x8c6,0x155,0xae6,0x170,0x2b81,0xe1,0x2ba0,0x28d,0x2cde,0x2a3,0x2d38, -0x2ad,0x2f95,0x2cf,0x3836,0x337,0x38a6,0x341,0x3b40,0x370,0x3b7e,0x378,0x4567,0x42e,0x45e5,0x438,0x460a, -0x43e,0x4624,0x444,0x4645,0x44b,0x465f,0xe1,0x4684,0xe1,0x46aa,0x452,0x4754,0x468,0x47cd,0x47b,0x486a, -0x495,0x2000,0x2001,0x48a1,0x49c,0x3000,0x3001,0x492d,0,0x4000,0x400e,0x493f,0,0x4948,0,0x4962, -0,0x4973,0,0x4984,0,0x499a,0,0x49a3,0,0x49c0,0,0x49de,0,0x49fc,0,0x4a1a, -0,0x4a30,0,0x4a44,0,0x4a5a,0,0x7000,0x7001,0x4a73,0,0x748,0x12,0,1,0x12, -0x20,0x766,0x49,0,1,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11, -0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21, -0x22,0x23,0x24,0x54,0x5b,0x67,0x6b,0x76,0x7a,0x81,0x82,0x84,0x85,0xc8,0xca,0xd6, -0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xe9,0xea,0xf0,0x2e,0x40,0x4c,0x56, -0x67,0x72,0x7f,0x8c,0x99,0xa6,0xb3,0xc0,0xcd,0xda,0xe7,0xf4,0x101,0x10e,0x11b,0x128, -0x135,0x142,0x14f,0x15c,0x169,0x176,0x183,0x190,0x19d,0x1aa,0x1b7,0x1c4,0x1d1,0x1de,0x1eb,0x1fa, -0x209,0x218,0x227,0x236,0x245,0x254,0x263,0x27d,0x291,0x2a5,0x2c0,0x2cf,0x2d8,0x2e8,0x2f0,0x2f9, -0x308,0x311,0x321,0x332,0x343,0x8f8,1,0,0x17,0x8d5,0x8e6,0x8f7,0x90b,0x922,0x93a,0x94c, -0x961,0x978,0x98d,0x99d,0x9af,0x9cc,0x9e8,0x9fa,0xa17,0xa33,0xa4f,0xa64,0xa79,0xa93,0xaae,0xac9, -0xa9a,1,0,0x119,0xaf1,0xafe,0xb11,0xb39,0xb57,0xb75,0xb8d,0xbb8,0xbe2,0xbfa,0xc0d,0xc20, -0xc2f,0xc3e,0xc4d,0xc5c,0xc73,0xc84,0xc97,0xcaa,0xcb7,0xcc4,0xcd3,0xce4,0xcf9,0xd0a,0xd15,0xd1e, -0xd2f,0xd40,0xd53,0xd65,0xd78,0xd8b,0xdca,0xdd7,0xde4,0xdf1,0xe06,0xe36,0xe50,0xe71,0xe9c,0xebf, -0xf1d,0xf44,0xf5f,0xf6e,0xf95,0xfbd,0xfe0,0x1003,0x102d,0x1046,0x1065,0x1088,0x10ac,0x10bf,0x10d9,0x1103, -0x111b,0x1143,0x116c,0x117f,0x1192,0x11a5,0x11cc,0x11db,0x11fb,0x1229,0x1247,0x1275,0x1291,0x12ac,0x12c5,0x12de, -0x12ff,0x132f,0x134e,0x1370,0x13a4,0x13d1,0x1416,0x1437,0x1461,0x1482,0x14ab,0x14be,0x14f1,0x1508,0x1517,0x1528, -0x1553,0x156a,0x159b,0x15c9,0x160c,0x1617,0x1650,0x1661,0x1672,0x167f,0x1692,0x16cc,0x16f0,0x1714,0x174e,0x1786, -0x17b1,0x17c9,0x17f5,0x1821,0x182e,0x183d,0x185a,0x187c,0x18aa,0x18ca,0x18f1,0x1918,0x1937,0x194a,0x195b,0x196c, -0x1991,0x19b6,0x19dd,0x1a11,0x1a3e,0x1a5c,0x1a6f,0x1a88,0x1ac1,0x1ad0,0x1af0,0x1b12,0x1b34,0x1b4b,0x1b62,0x1b8f, -0x1ba8,0x1bc1,0x1bf2,0x1c1c,0x1c37,0x1c4a,0x1c69,0x1c72,0x1c85,0x1ca3,0x1cc1,0x1cd4,0x1ceb,0x1d00,0x1d35,0x1d59, -0x1d6e,0x1d7d,0x1d90,0x1db4,0x1dbd,0x1de1,0x1df8,0x1e0b,0x1e1a,0x1e25,0x1e46,0x1e5e,0x1e6d,0x1e7c,0x1e8b,0x1ea2, -0x1eb7,0x1ecc,0x1f05,0x1f18,0x1f34,0x1f3f,0x1f4c,0x1f7a,0x1f9e,0x1fc1,0x1fd4,0x1ff6,0x2009,0x2024,0x2047,0x206a, -0x208f,0x20a0,0x20cf,0x20fc,0x2113,0x212e,0x213d,0x2168,0x21a0,0x21da,0x2208,0x2219,0x2226,0x224a,0x2259,0x2275, -0x228f,0x22ac,0x22e4,0x22f9,0x2326,0x2345,0x2373,0x2393,0x23c7,0x23d6,0x2400,0x2423,0x244e,0x2459,0x246a,0x2485, -0x24a9,0x24b6,0x24cb,0x24f2,0x251d,0x2554,0x2567,0x2578,0x25a8,0x25b9,0x25c8,0x25dd,0x25fb,0x260e,0x2621,0x2638, -0x2655,0x2660,0x2669,0x268b,0x26a0,0x26c5,0x26dc,0x2705,0x2720,0x2735,0x274e,0x276f,0x27a4,0x27b5,0x27e6,0x280a, -0x281b,0x2834,0x283f,0x286c,0x288e,0x28bc,0x28ef,0x28fe,0x290f,0x292c,0x296e,0x2995,0x29a2,0x29b7,0x29db,0x2a01, -0x2a3a,0x2a4b,0x2a6f,0x2a7a,0x2a87,0x2a96,0x2abb,0x2ae9,0x2b05,0x2b22,0x2b2f,0x2b40,0x2b5e,0x1c30,1,0, -0x12,0x2bb7,0x2bc7,0x2bda,0x2bea,0x2bfa,0x2c09,0x2c19,0x2c2b,0x2c3e,0x2c50,0x2c60,0x2c70,0x2c7f,0x2c8e,0x2c9e, -0x2cab,0x2cba,0x2cce,0x1cee,1,0,6,0x2cf3,0x2cfe,0x2d0b,0x2d18,0x2d25,0x2d30,0x1d32,1,0, -0x1e,0x2d4d,0x2d5c,0x2d71,0x2d86,0x2d9b,0x2daf,0x2dc0,0x2dd4,0x2de7,0x2df8,0x2e11,0x2e23,0x2e34,0x2e48,0x2e5b, -0x2e73,0x2e85,0x2e90,0x2ea0,0x2eae,0x2ec3,0x2ed8,0x2eee,0x2f08,0x2f1e,0x2f2e,0x2f42,0x2f56,0x2f67,0x2f7f,0x1f5d, -1,0,0x64,0x2fa7,0x2fca,0x2fd3,0x2fe0,0x2feb,0x2ff4,0x2fff,0x3008,0x3021,0x3026,0x302f,0x304c,0x3055, -0x3062,0x306b,0x308f,0x3096,0x309f,0x30b2,0x30bd,0x30c6,0x30d1,0x30ea,0x30f3,0x3102,0x310d,0x3116,0x3121,0x312a, -0x3131,0x313a,0x3145,0x314e,0x3167,0x3170,0x317d,0x3188,0x3199,0x31a4,0x31b9,0x31d0,0x31d9,0x31e2,0x31fb,0x3206, -0x320f,0x3218,0x322f,0x324c,0x3257,0x3268,0x3273,0x327a,0x3287,0x3294,0x32c1,0x32d6,0x32df,0x32fa,0x331d,0x333e, -0x335f,0x3384,0x33ab,0x33cc,0x33ef,0x3410,0x3437,0x3458,0x347d,0x349c,0x34bb,0x34da,0x34f7,0x3518,0x3539,0x355c, -0x3581,0x35a0,0x35bf,0x35e0,0x3607,0x362c,0x364b,0x366c,0x368f,0x36aa,0x36c3,0x36de,0x36f7,0x3714,0x372f,0x374c, -0x376b,0x3788,0x37a5,0x37c4,0x37e1,0x37fc,0x3819,0x2283,1,0,6,0x3847,0x3856,0x3866,0x3876,0x3886, -0x3897,0x22e1,1,0,0x2b,0x38b5,0x38c1,0x38cf,0x38de,0x38ed,0x38fd,0x390e,0x3922,0x3937,0x394d,0x3960, -0x3974,0x3984,0x398d,0x3998,0x39a8,0x39c4,0x39d6,0x39e4,0x39f3,0x39ff,0x3a14,0x3a28,0x3a3b,0x3a49,0x3a5d,0x3a6b, -0x3a75,0x3a87,0x3a93,0x3aa1,0x3ab1,0x3ab8,0x3abf,0x3ac6,0x3acd,0x3ad4,0x3aea,0x3b0b,0x88d,0x3b1d,0x3b28,0x3b37, -0x253a,1,0,4,0x3b51,0x3b5c,0x3b68,0x3b72,0x2560,1,0,0xb2,0x3b89,0x3b96,0x3bab,0x3bb8, -0x3bc7,0x3bd5,0x3be4,0x3bf3,0x3c05,0x3c14,0x3c22,0x3c33,0x3c42,0x3c51,0x3c5e,0x3c6a,0x3c79,0x3c88,0x3c92,0x3c9f, -0x3cac,0x3cbb,0x3cc9,0x3cd8,0x3ce4,0x3cee,0x3cfa,0x3d0a,0x3d1a,0x3d28,0x3d34,0x3d45,0x3d51,0x3d5d,0x3d6b,0x3d78, -0x3d84,0x3d91,0xd0a,0x3d9e,0x3dac,0x3dc6,0x3dcf,0x3ddd,0x3deb,0x3df7,0x3e06,0x3e14,0x3e22,0x3e2e,0x3e3d,0x3e4b, -0x3e59,0x3e66,0x3e75,0x3e90,0x3e9f,0x3eb0,0x3ec1,0x3ed4,0x3ee6,0x3ef5,0x3f07,0x3f16,0x3f22,0x3f2d,0x1e1a,0x3f3a, -0x3f45,0x3f50,0x3f5b,0x3f66,0x3f81,0x3f8c,0x3f97,0x3fa2,0x3fb5,0x3fc9,0x3fd4,0x3fe3,0x3ff2,0x3ffd,0x4008,0x4015, -0x4024,0x4032,0x403d,0x4058,0x4062,0x4073,0x4084,0x4093,0x40a4,0x40af,0x40ba,0x40c5,0x40d0,0x40db,0x40e6,0x40f1, -0x40fb,0x4106,0x4116,0x4121,0x412f,0x413c,0x4147,0x4156,0x4163,0x4170,0x417f,0x418c,0x419d,0x41af,0x41bf,0x41ca, -0x41dd,0x41f4,0x4202,0x420f,0x421a,0x4227,0x4238,0x4254,0x426a,0x4275,0x4292,0x42a2,0x42b1,0x42bc,0x42c7,0x1f34, -0x42d3,0x42de,0x42f6,0x4306,0x4315,0x4323,0x4331,0x433c,0x4347,0x435b,0x4372,0x438a,0x439a,0x43aa,0x43ba,0x43cc, -0x43d7,0x43e2,0x43ec,0x43f8,0x4406,0x4419,0x4425,0x4432,0x443d,0x4459,0x4466,0x4474,0x448d,0x2834,0x449c,0x2655, -0x44a9,0x44b7,0x44c9,0x44d7,0x44e3,0x44f3,0x2a6f,0x4501,0x450d,0x4518,0x4523,0x452e,0x4542,0x4550,0x2e57,1, -0,6,0x4581,0x4594,0x45a4,0x45b2,0x45c3,0x45d3,0x2eb3,0x12,0,1,0x45fd,0x4603,0x2ec0,0x12, -0,1,0x45fd,0x4603,0x2ecd,1,0,3,0x45fd,0x4603,0x463c,0x2ee3,1,0,3,0x45fd, -0x4603,0x463c,0x2ef9,1,0,0x12,0x46c6,0x46d0,0x46dc,0x46e3,0x46ee,0x46f3,0x46fa,0x4701,0x470a,0x470f, -0x4714,0x4724,0x88d,0x3b1d,0x4730,0x3b28,0x4740,0x3b37,0x2fa2,1,0,0xf,0x46c6,0x4767,0x4771,0x477b, -0x4786,0x39f3,0x4790,0x479c,0x47a4,0x47ab,0x47b5,0x46dc,0x46e3,0x46f3,0x47bf,0x3029,1,0,0x16,0x46c6, -0x47dc,0x477b,0x47e8,0x47f5,0x4803,0x39f3,0x480e,0x46dc,0x481f,0x46f3,0x482e,0x483c,0x88d,0x3b0b,0x4848,0x4859, -0x3b1d,0x4730,0x3b28,0x4740,0x3b37,0x3139,1,0,3,0x4888,0x4890,0x4898,0x3152,0x36,1,2, -4,8,0xe,0x10,0x20,0x3e,0x40,0x80,0x100,0x1c0,0x200,0x400,0x800,0xe00,0x1000,0x2000, -0x4000,0x7000,0x8000,0x10000,0x20000,0x40000,0x78001,0x80000,0x100000,0x200000,0x400000,0x800000,0x1000000,0x2000000,0x4000000,0x8000000, -0xf000000,0x10000000,0x20000000,0x30f80000,0x2d4d,0x2d5c,0x2d71,0x2d86,0x48cf,0x2d9b,0x2daf,0x48c5,0x2dc0,0x2dd4,0x2de7,0x48e0, -0x2df8,0x2e11,0x2e23,0x48f7,0x2e34,0x2e48,0x2e5b,0x4920,0x2e73,0x2e85,0x2e90,0x2ea0,0x48bc,0x2eae,0x2ec3,0x2ed8, -0x2eee,0x2f08,0x2f1e,0x2f2e,0x2f42,0x2f56,0x4916,0x2f67,0x2f7f,0x4901 +const int32_t PropNameData::valueMaps[1281]={ +6,0,0x41,0,0xdd,0x356,0xdd,0x36c,0xdd,0x381,0xdd,0x397,0xdd,0x3a2,0xdd,0x3c3, +0xdd,0x3d3,0xdd,0x3e2,0xdd,0x3f0,0xdd,0x414,0xdd,0x42b,0xdd,0x443,0xdd,0x45a,0xdd,0x469, +0xdd,0x478,0xdd,0x489,0xdd,0x497,0xdd,0x4a9,0xdd,0x4c3,0xdd,0x4de,0xdd,0x4f3,0xdd,0x510, +0xdd,0x521,0xdd,0x52c,0xdd,0x54b,0xdd,0x561,0xdd,0x572,0xdd,0x582,0xdd,0x59d,0xdd,0x5b6, +0xdd,0x5c7,0xdd,0x5e1,0xdd,0x5f4,0xdd,0x604,0xdd,0x61e,0xdd,0x637,0xdd,0x64e,0xdd,0x662, +0xdd,0x678,0xdd,0x68c,0xdd,0x6a2,0xdd,0x6bc,0xdd,0x6d4,0xdd,0x6f0,0xdd,0x6f8,0xdd,0x700, +0xdd,0x708,0xdd,0x710,0xdd,0x719,0xdd,0x726,0xdd,0x739,0xdd,0x756,0xdd,0x773,0xdd,0x790, +0xdd,0x7ae,0xdd,0x7cc,0xdd,0x7f0,0xdd,0x7fd,0xdd,0x817,0xdd,0x82c,0xdd,0x847,0xdd,0x85e, +0xdd,0x875,0xdd,0x897,0xdd,0x1000,0x1016,0x8b6,0x157,0xad6,0x172,0x2c95,0xe3,0x2cb4,0x29a,0x2df2, +0x2b0,0x2e4c,0x2ba,0x30a9,0x2dc,0x39a4,0x346,0x3a14,0x350,0x3cae,0x37f,0x3cec,0x387,0x474b,0x444,0x47c9, +0x44e,0x47ee,0x454,0x4808,0x45a,0x4829,0x461,0x4843,0xe3,0x4868,0xe3,0x488e,0x468,0x4938,0x47e,0x49b1, +0x491,0x4a63,0x4ac,0x2000,0x2001,0x4a9a,0x4b3,0x3000,0x3001,0x4b26,0,0x4000,0x400e,0x4b38,0,0x4b41, +0,0x4b5b,0,0x4b6c,0,0x4b7d,0,0x4b93,0,0x4b9c,0,0x4bb9,0,0x4bd7,0,0x4bf5, +0,0x4c13,0,0x4c29,0,0x4c3d,0,0x4c53,0,0x7000,0x7001,0x4c6c,0,0x77c,0x12,0, +1,0x12,0x20,0x79a,0x49,0,1,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, +0x20,0x21,0x22,0x23,0x24,0x54,0x5b,0x67,0x6b,0x76,0x7a,0x81,0x82,0x84,0x85,0xc8, +0xca,0xd6,0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xe9,0xea,0xf0,0x2e,0x40, +0x4c,0x56,0x67,0x72,0x7f,0x8c,0x99,0xa6,0xb3,0xc0,0xcd,0xda,0xe7,0xf4,0x101,0x10e, +0x11b,0x128,0x135,0x142,0x14f,0x15c,0x169,0x176,0x183,0x190,0x19d,0x1aa,0x1b7,0x1c4,0x1d1,0x1de, +0x1eb,0x1fa,0x209,0x218,0x227,0x236,0x245,0x254,0x263,0x27d,0x291,0x2a5,0x2c0,0x2cf,0x2d8,0x2e8, +0x2f0,0x2f9,0x308,0x311,0x321,0x332,0x343,0x92c,1,0,0x17,0x8c5,0x8d6,0x8e7,0x8fb,0x912, +0x92a,0x93c,0x951,0x968,0x97d,0x98d,0x99f,0x9bc,0x9d8,0x9ea,0xa07,0xa23,0xa3f,0xa54,0xa69,0xa83, +0xa9e,0xab9,0xace,1,0,0x124,0xae1,0xaee,0xb01,0xb29,0xb47,0xb65,0xb7d,0xba8,0xbd2,0xbea, +0xbfd,0xc10,0xc1f,0xc2e,0xc3d,0xc4c,0xc63,0xc74,0xc87,0xc9a,0xca7,0xcb4,0xcc3,0xcd4,0xce9,0xcfa, +0xd05,0xd0e,0xd1f,0xd30,0xd43,0xd55,0xd68,0xd7b,0xdba,0xdc7,0xdd4,0xde1,0xdf6,0xe26,0xe40,0xe61, +0xe8c,0xeaf,0xf0d,0xf34,0xf4f,0xf5e,0xf85,0xfad,0xfd0,0xff3,0x101d,0x1036,0x1055,0x1078,0x109c,0x10af, +0x10c9,0x10f3,0x110b,0x1133,0x115c,0x116f,0x1182,0x1195,0x11bc,0x11cb,0x11eb,0x1219,0x1237,0x1265,0x1281,0x129c, +0x12b5,0x12ce,0x12ef,0x131f,0x133e,0x1360,0x1394,0x13c1,0x1406,0x1427,0x1451,0x1472,0x149b,0x14ae,0x14e1,0x14f8, +0x1507,0x1518,0x1543,0x155a,0x158b,0x15b9,0x15fc,0x1607,0x1640,0x1651,0x1662,0x166f,0x1682,0x16bc,0x16e0,0x1704, +0x173e,0x1776,0x17a1,0x17b9,0x17e5,0x1811,0x181e,0x182d,0x184a,0x186c,0x189a,0x18ba,0x18e1,0x1908,0x1927,0x193a, +0x194b,0x195c,0x1981,0x19a6,0x19cd,0x1a01,0x1a2e,0x1a4c,0x1a5f,0x1a78,0x1ab1,0x1ac0,0x1ae0,0x1b02,0x1b24,0x1b3b, +0x1b52,0x1b7f,0x1b98,0x1bb1,0x1be2,0x1c0c,0x1c27,0x1c3a,0x1c59,0x1c62,0x1c75,0x1c93,0x1cb1,0x1cc4,0x1cdb,0x1cf0, +0x1d25,0x1d49,0x1d5e,0x1d6d,0x1d80,0x1da4,0x1dad,0x1dd1,0x1de8,0x1dfb,0x1e0a,0x1e15,0x1e36,0x1e4e,0x1e5d,0x1e6c, +0x1e7b,0x1e92,0x1ea7,0x1ebc,0x1ef5,0x1f08,0x1f24,0x1f2f,0x1f3c,0x1f6a,0x1f8e,0x1fb1,0x1fc4,0x1fe6,0x1ff9,0x2014, +0x2037,0x205a,0x207f,0x2090,0x20bf,0x20ec,0x2103,0x211e,0x212d,0x2158,0x2190,0x21ca,0x21f8,0x2209,0x2216,0x223a, +0x2249,0x2265,0x227f,0x229c,0x22d4,0x22e9,0x2316,0x2335,0x2363,0x2383,0x23b7,0x23c6,0x23f0,0x2413,0x243e,0x2449, +0x245a,0x2475,0x2499,0x24a6,0x24bb,0x24e2,0x250d,0x2544,0x2557,0x2568,0x2598,0x25a9,0x25b8,0x25cd,0x25eb,0x25fe, +0x2611,0x2628,0x2645,0x2650,0x2659,0x267b,0x2690,0x26b5,0x26cc,0x26f5,0x2710,0x2725,0x273e,0x275f,0x2794,0x27a5, +0x27d6,0x27fa,0x280b,0x2824,0x282f,0x285c,0x287e,0x28ac,0x28df,0x28ee,0x28ff,0x291c,0x295e,0x2985,0x2992,0x29a7, +0x29cb,0x29f1,0x2a2a,0x2a3b,0x2a5f,0x2a6a,0x2a77,0x2a86,0x2aab,0x2ad9,0x2af5,0x2b12,0x2b1f,0x2b30,0x2b4e,0x2b71, +0x2b8e,0x2b9b,0x2bbb,0x2bd8,0x2bf9,0x2c22,0x2c33,0x2c52,0x2c6b,0x2c84,0x1cf4,1,0,0x12,0x2ccb,0x2cdb, +0x2cee,0x2cfe,0x2d0e,0x2d1d,0x2d2d,0x2d3f,0x2d52,0x2d64,0x2d74,0x2d84,0x2d93,0x2da2,0x2db2,0x2dbf,0x2dce,0x2de2, +0x1db2,1,0,6,0x2e07,0x2e12,0x2e1f,0x2e2c,0x2e39,0x2e44,0x1df6,1,0,0x1e,0x2e61,0x2e70, +0x2e85,0x2e9a,0x2eaf,0x2ec3,0x2ed4,0x2ee8,0x2efb,0x2f0c,0x2f25,0x2f37,0x2f48,0x2f5c,0x2f6f,0x2f87,0x2f99,0x2fa4, +0x2fb4,0x2fc2,0x2fd7,0x2fec,0x3002,0x301c,0x3032,0x3042,0x3056,0x306a,0x307b,0x3093,0x2021,1,0,0x66, +0x30bb,0x30de,0x30e7,0x30f4,0x30ff,0x3108,0x3113,0x311c,0x3135,0x313a,0x3143,0x3160,0x3169,0x3176,0x317f,0x31a3, +0x31aa,0x31b3,0x31c6,0x31d1,0x31da,0x31e5,0x31fe,0x3207,0x3216,0x3221,0x322a,0x3235,0x323e,0x3245,0x324e,0x3259, +0x3262,0x327b,0x3284,0x3291,0x329c,0x32ad,0x32b8,0x32cd,0x32e4,0x32ed,0x32f6,0x330f,0x331a,0x3323,0x332c,0x3343, +0x3360,0x336b,0x337c,0x3387,0x338e,0x339b,0x33a8,0x33d5,0x33ea,0x33f3,0x340e,0x3431,0x3452,0x3473,0x3498,0x34bf, +0x34e0,0x3503,0x3524,0x354b,0x356c,0x3591,0x35b0,0x35cf,0x35ee,0x360b,0x362c,0x364d,0x3670,0x3695,0x36b4,0x36d3, +0x36f4,0x371b,0x3740,0x375f,0x3780,0x37a3,0x37be,0x37d7,0x37f2,0x380b,0x3828,0x3843,0x3860,0x387f,0x389c,0x38b9, +0x38d8,0x38f5,0x3910,0x392d,0x394a,0x397d,0x2366,1,0,6,0x39b5,0x39c4,0x39d4,0x39e4,0x39f4,0x3a05, +0x23c4,1,0,0x2b,0x3a23,0x3a2f,0x3a3d,0x3a4c,0x3a5b,0x3a6b,0x3a7c,0x3a90,0x3aa5,0x3abb,0x3ace,0x3ae2, +0x3af2,0x3afb,0x3b06,0x3b16,0x3b32,0x3b44,0x3b52,0x3b61,0x3b6d,0x3b82,0x3b96,0x3ba9,0x3bb7,0x3bcb,0x3bd9,0x3be3, +0x3bf5,0x3c01,0x3c0f,0x3c1f,0x3c26,0x3c2d,0x3c34,0x3c3b,0x3c42,0x3c58,0x3c79,0x85e,0x3c8b,0x3c96,0x3ca5,0x261d, +1,0,4,0x3cbf,0x3cca,0x3cd6,0x3ce0,0x2643,1,0,0xb9,0x3cf7,0x3d04,0x3d19,0x3d26,0x3d35, +0x3d43,0x3d52,0x3d61,0x3d73,0x3d82,0x3d90,0x3da1,0x3db0,0x3dbf,0x3dcc,0x3dd8,0x3de7,0x3df6,0x3e00,0x3e0d,0x3e1a, +0x3e29,0x3e37,0x3e46,0x3e52,0x3e5c,0x3e68,0x3e78,0x3e88,0x3e96,0x3ea2,0x3eb3,0x3ebf,0x3ecb,0x3ed9,0x3ee6,0x3ef2, +0x3eff,0xcfa,0x3f0c,0x3f1a,0x3f34,0x3f3d,0x3f4b,0x3f59,0x3f65,0x3f74,0x3f82,0x3f90,0x3f9c,0x3fab,0x3fb9,0x3fc7, +0x3fd4,0x3fe3,0x3ffe,0x400d,0x401e,0x402f,0x4042,0x4054,0x4063,0x4075,0x4084,0x4090,0x409b,0x1e0a,0x40a8,0x40b3, +0x40be,0x40c9,0x40d4,0x40ef,0x40fa,0x4105,0x4110,0x4123,0x4137,0x4142,0x4151,0x4160,0x416b,0x4176,0x4183,0x4192, +0x41a0,0x41ab,0x41c6,0x41d0,0x41e1,0x41f2,0x4201,0x4212,0x421d,0x4228,0x4233,0x423e,0x4249,0x4254,0x425f,0x4269, +0x4274,0x4284,0x428f,0x429d,0x42aa,0x42b5,0x42c4,0x42d1,0x42de,0x42ed,0x42fa,0x430b,0x431d,0x432d,0x4338,0x434b, +0x4362,0x4370,0x437d,0x4388,0x4395,0x43a6,0x43c2,0x43d8,0x43e3,0x4400,0x4410,0x441f,0x442a,0x4435,0x1f24,0x4441, +0x444c,0x4464,0x4474,0x4483,0x4491,0x449f,0x44aa,0x44b5,0x44c9,0x44e0,0x44f8,0x4508,0x4518,0x4528,0x453a,0x4545, +0x4550,0x455a,0x4566,0x4574,0x4587,0x4593,0x45a0,0x45ab,0x45c7,0x45d4,0x45e2,0x45fb,0x2824,0x460a,0x2645,0x4617, +0x4625,0x4637,0x4645,0x4651,0x4661,0x2a5f,0x466f,0x467b,0x4686,0x4691,0x469c,0x46b0,0x46be,0x46d5,0x46e1,0x46f5, +0x4703,0x4715,0x472b,0x4739,0x2fa6,1,0,6,0x4765,0x4778,0x4788,0x4796,0x47a7,0x47b7,0x3002,0x12, +0,1,0x47e1,0x47e7,0x300f,0x12,0,1,0x47e1,0x47e7,0x301c,1,0,3,0x47e1,0x47e7, +0x4820,0x3032,1,0,3,0x47e1,0x47e7,0x4820,0x3048,1,0,0x12,0x48aa,0x48b4,0x48c0,0x48c7, +0x48d2,0x48d7,0x48de,0x48e5,0x48ee,0x48f3,0x48f8,0x4908,0x85e,0x3c8b,0x4914,0x3c96,0x4924,0x3ca5,0x30f1,1, +0,0xf,0x48aa,0x494b,0x4955,0x495f,0x496a,0x3b61,0x4974,0x4980,0x4988,0x498f,0x4999,0x48c0,0x48c7,0x48d7, +0x49a3,0x3178,1,0,0x17,0x48aa,0x49c0,0x495f,0x49cc,0x49d9,0x49e7,0x3b61,0x49f2,0x48c0,0x4a03,0x48d7, +0x4a12,0x4a20,0x85e,0x3c79,0x4a2c,0x4a3d,0x3c8b,0x4914,0x3c96,0x4924,0x3ca5,0x4a4e,0x3295,1,0,3, +0x4a81,0x4a89,0x4a91,0x32ae,0x36,1,2,4,8,0xe,0x10,0x20,0x3e,0x40,0x80,0x100, +0x1c0,0x200,0x400,0x800,0xe00,0x1000,0x2000,0x4000,0x7000,0x8000,0x10000,0x20000,0x40000,0x78001,0x80000,0x100000, +0x200000,0x400000,0x800000,0x1000000,0x2000000,0x4000000,0x8000000,0xf000000,0x10000000,0x20000000,0x30f80000,0x2e61,0x2e70,0x2e85,0x2e9a,0x4ac8, +0x2eaf,0x2ec3,0x4abe,0x2ed4,0x2ee8,0x2efb,0x4ad9,0x2f0c,0x2f25,0x2f37,0x4af0,0x2f48,0x2f5c,0x2f6f,0x4b19,0x2f87, +0x2f99,0x2fa4,0x2fb4,0x4ab5,0x2fc2,0x2fd7,0x2fec,0x3002,0x301c,0x3032,0x3042,0x3056,0x306a,0x4b0f,0x307b,0x3093, +0x4afa }; -const uint8_t PropNameData::bytesTries[13417]={ +const uint8_t PropNameData::bytesTries[13765]={ 0,0x15,0x6d,0xc3,0x5d,0x73,0xc1,0xf7,0x76,0x5f,0x76,0x68,0x77,0x90,0x78,1, 0x64,0x50,0x69,0x10,0x64,1,0x63,0x30,0x73,0x62,0x13,0x74,0x61,0x72,0x74,0x63, 0x60,0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x61,0x13,0x69,0x67,0x69,0x74,0x81, @@ -180,766 +182,788 @@ const uint8_t PropNameData::bytesTries[13417]={ 0x6e,0x64,0x37,0x12,0x61,0x73,0x65,0x35,0x11,0x78,0x74,0x37,0xc2,5,1,0x62, 0xc3,0x12,0x6d,0xd9,0x20,0,0x1c,0x6e,0x65,0x72,0x61,0x6c,0x63,0x61,0x74,0x65, 0x67,0x6f,0x72,0x79,0xc2,5,0x13,0x6d,0x61,0x73,0x6b,0xd9,0x20,0,0x61,0xa2, -0x5c,0x62,0xa2,0x8a,0x63,0xa2,0xfc,0x64,0xa4,0xc9,0x65,2,0x61,0x3a,0x6d,0x58, -0x78,0x10,0x74,0x30,0x14,0x65,0x6e,0x64,0x65,0x72,0x31,0xc2,4,0x1b,0x73,0x74, -0x61,0x73,0x69,0x61,0x6e,0x77,0x69,0x64,0x74,0x68,0xc3,4,0x12,0x6f,0x6a,0x69, -0x92,2,0x63,0x40,0x6d,0x50,0x70,0x1a,0x72,0x65,0x73,0x65,0x6e,0x74,0x61,0x74, -0x69,0x6f,0x6e,0x95,0x17,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x9b,0x16,0x6f, -0x64,0x69,0x66,0x69,0x65,0x72,0x96,0x13,0x62,0x61,0x73,0x65,0x99,3,0x67,0x44, -0x68,0x4a,0x6c,0x4e,0x73,0x1a,0x63,0x69,0x69,0x68,0x65,0x78,0x64,0x69,0x67,0x69, -0x74,0x23,0x10,0x65,0xd9,0x40,0,0x11,0x65,0x78,0x23,1,0x6e,0x38,0x70,0x11, -0x68,0x61,0x20,0x14,0x62,0x65,0x74,0x69,0x63,0x21,0x11,0x75,0x6d,0x79,4,0x63, -0xc3,0,0x69,0x3e,0x6c,0xa2,0x57,0x6d,0xa2,0x64,0x70,1,0x62,0xd9,0x40,0xd, -0x74,0xc3,0x15,0x11,0x64,0x69,2,0x63,0x54,0x6d,0x74,0x70,0x1b,0x61,0x69,0x72, -0x65,0x64,0x62,0x72,0x61,0x63,0x6b,0x65,0x74,0xd8,0x40,0xd,0x13,0x74,0x79,0x70, -0x65,0xc3,0x15,0x24,1,0x6c,0x30,0x6f,0x14,0x6e,0x74,0x72,0x6f,0x6c,0x25,0x12, -0x61,0x73,0x73,0xc3,0,0x26,0x14,0x69,0x72,0x72,0x6f,0x72,1,0x65,0x38,0x69, -0x16,0x6e,0x67,0x67,0x6c,0x79,0x70,0x68,0xd9,0x40,1,0x10,0x64,0x27,2,0x61, -0x32,0x6b,0xc3,1,0x6f,0x11,0x63,0x6b,0xc3,1,0x11,0x6e,0x6b,0x7b,0x10,0x67, -0xd9,0x40,1,6,0x68,0x7c,0x68,0x54,0x69,0x85,0x6f,0xa2,0x6f,0x77,4,0x63, -0x30,0x6b,0x36,0x6c,0x87,0x74,0x8b,0x75,0x89,1,0x66,0x8d,0x6d,0x8f,0x11,0x63, -0x66,0x91,0x18,0x61,0x6e,0x67,0x65,0x73,0x77,0x68,0x65,0x6e,4,0x63,0x44,0x6c, -0x6c,0x6e,0x7e,0x74,0x98,0x75,0x18,0x70,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x64, -0x89,0x12,0x61,0x73,0x65,1,0x66,0x30,0x6d,0x14,0x61,0x70,0x70,0x65,0x64,0x8f, -0x14,0x6f,0x6c,0x64,0x65,0x64,0x8d,0x18,0x6f,0x77,0x65,0x72,0x63,0x61,0x73,0x65, -0x64,0x87,0x1c,0x66,0x6b,0x63,0x63,0x61,0x73,0x65,0x66,0x6f,0x6c,0x64,0x65,0x64, -0x91,0x18,0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x64,0x8b,0x13,0x6d,0x70,0x65, -0x78,0x33,0x61,0x2e,0x63,0xa2,0x48,0x66,0xd9,0x40,2,1,0x6e,0x72,0x73,0x10, -0x65,3,0x64,0x83,0x66,0x3a,0x69,0x4a,0x73,0x17,0x65,0x6e,0x73,0x69,0x74,0x69, -0x76,0x65,0x65,0x15,0x6f,0x6c,0x64,0x69,0x6e,0x67,0xd9,0x40,2,0x17,0x67,0x6e, -0x6f,0x72,0x61,0x62,0x6c,0x65,0x85,0x13,0x6f,0x6e,0x69,0x63,0x1f,0x61,0x6c,0x63, -0x6f,0x6d,0x62,0x69,0x6e,0x69,0x6e,0x67,0x63,0x6c,0x61,0x73,0x73,0xc3,2,0x10, -0x63,0xc3,2,3,0x61,0x30,0x65,0x34,0x69,0xa2,0x41,0x74,0xc3,3,0x11,0x73, -0x68,0x29,2,0x63,0x3a,0x66,0x58,0x70,0x2c,0x16,0x72,0x65,0x63,0x61,0x74,0x65, -0x64,0x2d,0x1d,0x6f,0x6d,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x74,0x79,0x70, -0x65,0xc3,3,0x15,0x61,0x75,0x6c,0x74,0x69,0x67,0x1f,0x6e,0x6f,0x72,0x61,0x62, -0x6c,0x65,0x63,0x6f,0x64,0x65,0x70,0x6f,0x69,0x6e,0x74,0x2b,0x2a,0x10,0x61,0x2e, -0x15,0x63,0x72,0x69,0x74,0x69,0x63,0x2f,3,0x66,0x34,0x6e,0x3e,0x74,0x42,0x79, -0x22,0x11,0x65,0x73,0x23,0x20,0x13,0x61,0x6c,0x73,0x65,0x21,0x20,0x10,0x6f,0x21, -0x22,0x12,0x72,0x75,0x65,0x23,0xa,0x6b,0x5b,0x6f,0x23,0x6f,0x3c,0x72,0x4c,0x76, -1,0x69,0x24,0x72,0x33,0x13,0x72,0x61,0x6d,0x61,0x33,0x10,0x76,0x22,0x14,0x65, -0x72,0x6c,0x61,0x79,0x23,0xa2,0xe2,0x13,0x69,0x67,0x68,0x74,0xa3,0xe2,0x6b,0x58, -0x6c,0x74,0x6e,3,0x6b,0x2f,0x6f,0x30,0x72,0x21,0x75,0x12,0x6b,0x74,0x61,0x2f, -0x19,0x74,0x72,0x65,0x6f,0x72,0x64,0x65,0x72,0x65,0x64,0x21,1,0x61,0x24,0x76, -0x31,0x18,0x6e,0x61,0x76,0x6f,0x69,0x63,0x69,0x6e,0x67,0x31,0xa2,0xe0,0x12,0x65, -0x66,0x74,0xa3,0xe0,0x61,0x5c,0x62,0xa2,0x77,0x63,0xa2,0x96,0x64,0xa4,0xa,0x69, -1,0x6f,0x26,0x73,0xa3,0xf0,0x1a,0x74,0x61,0x73,0x75,0x62,0x73,0x63,0x72,0x69, -0x70,0x74,0xa3,0xf0,0xa2,0xe6,3,0x62,0xa0,0x6c,0xa3,0xe4,0x72,0xa3,0xe8,0x74, -2,0x61,0x74,0x62,0x7c,0x74,0x14,0x61,0x63,0x68,0x65,0x64,1,0x61,0x3e,0x62, -0x13,0x65,0x6c,0x6f,0x77,0xa2,0xca,0x13,0x6c,0x65,0x66,0x74,0xa3,0xc8,0x13,0x62, -0x6f,0x76,0x65,0xa2,0xd6,0x14,0x72,0x69,0x67,0x68,0x74,0xa3,0xd8,0xa2,0xd6,0x10, -0x72,0xa3,0xd8,0xa2,0xca,0x10,0x6c,0xa3,0xc8,0x12,0x6f,0x76,0x65,0xa2,0xe6,1, -0x6c,0x30,0x72,0x13,0x69,0x67,0x68,0x74,0xa3,0xe8,0x12,0x65,0x66,0x74,0xa3,0xe4, -0xa2,0xdc,2,0x65,0x2c,0x6c,0xa3,0xda,0x72,0xa3,0xde,0x12,0x6c,0x6f,0x77,0xa2, -0xdc,1,0x6c,0x30,0x72,0x13,0x69,0x67,0x68,0x74,0xa3,0xde,0x12,0x65,0x66,0x74, -0xa3,0xda,0x11,0x63,0x63,4,0x31,0x3c,0x32,0xa2,0x42,0x33,0xa2,0x56,0x38,0xa2, -0x64,0x39,0x10,0x31,0xa3,0x5b,9,0x35,0xa,0x35,0x3f,0x36,0x41,0x37,0x43,0x38, -0x45,0x39,0x47,0x30,0x30,0x31,0x3c,0x32,0x42,0x33,0x4e,0x34,0x3d,0x34,1,0x33, -0xa3,0x67,0x37,0xa3,0x6b,0x36,0x10,0x38,0xa3,0x76,0x38,1,0x32,0xa3,0x7a,0x39, -0xa3,0x81,0x3a,2,0x30,0xa3,0x82,0x32,0xa3,0x84,0x33,0xa3,0x85,9,0x35,0xa, -0x35,0x53,0x36,0x55,0x37,0x57,0x38,0x59,0x39,0x5b,0x30,0x49,0x31,0x4b,0x32,0x4d, -0x33,0x4f,0x34,0x51,6,0x33,8,0x33,0x63,0x34,0x65,0x35,0x67,0x36,0x69,0x30, -0x5d,0x31,0x5f,0x32,0x61,0x10,0x34,0xa3,0x54,2,0x61,0xa3,0xea,0x62,0xa3,0xe9, -0x6f,0x13,0x75,0x62,0x6c,0x65,1,0x61,0x30,0x62,0x13,0x65,0x6c,0x6f,0x77,0xa3, -0xe9,0x13,0x62,0x6f,0x76,0x65,0xa3,0xea,0xb,0x6e,0xc0,0xca,0x72,0x5f,0x72,0x46, -0x73,0xa2,0x48,0x77,1,0x68,0x24,0x73,0x33,0x17,0x69,0x74,0x65,0x73,0x70,0x61, -0x63,0x65,0x33,0x22,1,0x69,0x30,0x6c,2,0x65,0x3d,0x69,0x4b,0x6f,0x3f,0x18, -0x67,0x68,0x74,0x74,0x6f,0x6c,0x65,0x66,0x74,0x22,2,0x65,0x38,0x69,0x48,0x6f, -0x16,0x76,0x65,0x72,0x72,0x69,0x64,0x65,0x3f,0x17,0x6d,0x62,0x65,0x64,0x64,0x69, -0x6e,0x67,0x3d,0x15,0x73,0x6f,0x6c,0x61,0x74,0x65,0x4b,0x30,0x1e,0x65,0x67,0x6d, -0x65,0x6e,0x74,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x31,0x6e,0xa2,0x41, -0x6f,0xa2,0x53,0x70,2,0x61,0x66,0x64,0x86,0x6f,0x1b,0x70,0x64,0x69,0x72,0x65, -0x63,0x74,0x69,0x6f,0x6e,0x61,0x6c,1,0x66,0x32,0x69,0x15,0x73,0x6f,0x6c,0x61, -0x74,0x65,0x4d,0x14,0x6f,0x72,0x6d,0x61,0x74,0x41,0x1f,0x72,0x61,0x67,0x72,0x61, -0x70,0x68,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x2f,1,0x66,0x41,0x69, -0x4d,1,0x6f,0x28,0x73,0x10,0x6d,0x43,0x1b,0x6e,0x73,0x70,0x61,0x63,0x69,0x6e, -0x67,0x6d,0x61,0x72,0x6b,0x43,1,0x6e,0x35,0x74,0x19,0x68,0x65,0x72,0x6e,0x65, -0x75,0x74,0x72,0x61,0x6c,0x35,0x65,0x88,0x65,0x98,0x66,0xa2,0x6a,0x6c,0x20,1, -0x65,0x30,0x72,2,0x65,0x37,0x69,0x49,0x6f,0x39,0x18,0x66,0x74,0x74,0x6f,0x72, -0x69,0x67,0x68,0x74,0x20,2,0x65,0x38,0x69,0x48,0x6f,0x16,0x76,0x65,0x72,0x72, -0x69,0x64,0x65,0x39,0x17,0x6d,0x62,0x65,0x64,0x64,0x69,0x6e,0x67,0x37,0x15,0x73, -0x6f,0x6c,0x61,0x74,0x65,0x49,3,0x6e,0x25,0x73,0x27,0x74,0x29,0x75,0x15,0x72, -0x6f,0x70,0x65,0x61,0x6e,2,0x6e,0x3c,0x73,0x46,0x74,0x18,0x65,0x72,0x6d,0x69, -0x6e,0x61,0x74,0x6f,0x72,0x29,0x14,0x75,0x6d,0x62,0x65,0x72,0x25,0x17,0x65,0x70, -0x61,0x72,0x61,0x74,0x6f,0x72,0x27,1,0x69,0x28,0x73,0x10,0x69,0x47,0x1f,0x72, -0x73,0x74,0x73,0x74,0x72,0x6f,0x6e,0x67,0x69,0x73,0x6f,0x6c,0x61,0x74,0x65,0x47, -0x61,0x4e,0x62,0x84,0x63,1,0x6f,0x24,0x73,0x2d,0x1c,0x6d,0x6d,0x6f,0x6e,0x73, -0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x2d,2,0x6c,0x3b,0x6e,0x2b,0x72,0x13, -0x61,0x62,0x69,0x63,1,0x6c,0x30,0x6e,0x14,0x75,0x6d,0x62,0x65,0x72,0x2b,0x14, -0x65,0x74,0x74,0x65,0x72,0x3b,0x2e,1,0x6e,0x45,0x6f,0x1c,0x75,0x6e,0x64,0x61, -0x72,0x79,0x6e,0x65,0x75,0x74,0x72,0x61,0x6c,0x45,0,0x16,0x6d,0xc7,0xc5,0x74, -0xc1,0xb8,0x77,0x57,0x77,0x48,0x79,0x5c,0x7a,0x1d,0x61,0x6e,0x61,0x62,0x61,0x7a, -0x61,0x72,0x73,0x71,0x75,0x61,0x72,0x65,0xa5,0x18,0x18,0x61,0x72,0x61,0x6e,0x67, -0x63,0x69,0x74,0x69,0xa3,0xfc,0x10,0x69,2,0x6a,0x3c,0x72,0x68,0x73,0x17,0x79, -0x6c,0x6c,0x61,0x62,0x6c,0x65,0x73,0xa3,0x48,0x12,0x69,0x6e,0x67,0xa2,0x74,0x1e, -0x68,0x65,0x78,0x61,0x67,0x72,0x61,0x6d,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3, -0x74,0x16,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0xa3,0x49,0x74,0xa2,0x59,0x75,0xa4, -0x12,0x76,2,0x61,0x36,0x65,0x7a,0x73,0xa2,0x6c,0x12,0x73,0x75,0x70,0xa3,0x7d, -1,0x69,0xa3,0x9f,0x72,0x1e,0x69,0x61,0x74,0x69,0x6f,0x6e,0x73,0x65,0x6c,0x65, -0x63,0x74,0x6f,0x72,0x73,0xa2,0x6c,0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65, -0x6e,0x74,0xa3,0x7d,1,0x64,0x3c,0x72,0x19,0x74,0x69,0x63,0x61,0x6c,0x66,0x6f, -0x72,0x6d,0x73,0xa3,0x91,0x14,0x69,0x63,0x65,0x78,0x74,0xa2,0xaf,0x16,0x65,0x6e, -0x73,0x69,0x6f,0x6e,0x73,0xa3,0xaf,4,0x61,0x68,0x65,0xa2,0x8a,0x68,0xa2,0x8d, -0x69,0xa2,0x95,0x72,0x1c,0x61,0x6e,0x73,0x70,0x6f,0x72,0x74,0x61,0x6e,0x64,0x6d, -0x61,0x70,0xa2,0xcf,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xcf,4,0x67, -0x58,0x69,0x7e,0x6b,0xa2,0x58,0x6d,0xa2,0x5a,0x6e,0x12,0x67,0x75,0x74,0xa4,0x10, -0x19,0x63,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0xa5,0x11,2,0x61,0x2a, -0x62,0x32,0x73,0xa3,0x60,0x12,0x6c,0x6f,0x67,0xa3,0x62,0x13,0x61,0x6e,0x77,0x61, -0xa3,0x65,3,0x6c,0x52,0x74,0x56,0x76,0x5e,0x78,0x16,0x75,0x61,0x6e,0x6a,0x69, -0x6e,0x67,0xa2,0x7c,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x7c,0x10,0x65, -0xa3,0x70,0x12,0x68,0x61,0x6d,0xa3,0xae,0x12,0x69,0x65,0x74,0xa3,0xb7,0x11,0x72, -0x69,0xa3,0xdc,0x11,0x69,0x6c,0x49,0x13,0x6c,0x75,0x67,0x75,0x4b,0x10,0x61,1, -0x61,0x24,0x69,0x53,0x11,0x6e,0x61,0x3d,2,0x62,0x34,0x66,0x3c,0x72,0x13,0x68, -0x75,0x74,0x61,0xa3,0xfb,0x13,0x65,0x74,0x61,0x6e,0x57,0x14,0x69,0x6e,0x61,0x67, -0x68,0xa3,0x90,2,0x63,0x82,0x67,0x92,0x6e,0x1f,0x69,0x66,0x69,0x65,0x64,0x63, -0x61,0x6e,0x61,0x64,0x69,0x61,0x6e,0x61,0x62,0x6f,0x1f,0x72,0x69,0x67,0x69,0x6e, -0x61,0x6c,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69,0x63,0x73,0x62,0x17,0x65,0x78,0x74, -0x65,0x6e,0x64,0x65,0x64,0xa3,0xad,0x11,0x61,0x73,0x62,0x12,0x65,0x78,0x74,0xa3, -0xad,0x15,0x61,0x72,0x69,0x74,0x69,0x63,0xa3,0x78,0x70,0xc2,0xeb,0x70,0xa6,1, -0x72,0xa6,0xbd,0x73,7,0x6f,0xc1,0x75,0x6f,0x74,0x70,0x9c,0x75,0xa2,0x5d,0x79, -1,0x6c,0x4c,0x72,0x12,0x69,0x61,0x63,0x3a,0x12,0x73,0x75,0x70,0xa4,0x17,0x16, -0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0x17,0x17,0x6f,0x74,0x69,0x6e,0x61,0x67, -0x72,0x69,0xa3,0x8f,1,0x72,0x30,0x79,0x13,0x6f,0x6d,0x62,0x6f,0xa5,0x16,0x17, -0x61,0x73,0x6f,0x6d,0x70,0x65,0x6e,0x67,0xa3,0xda,1,0x61,0x32,0x65,0x14,0x63, -0x69,0x61,0x6c,0x73,0xa3,0x56,0x12,0x63,0x69,0x6e,0x1f,0x67,0x6d,0x6f,0x64,0x69, -0x66,0x69,0x65,0x72,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x2d,2,0x6e,0x48,0x70, -0x76,0x74,0x1d,0x74,0x6f,0x6e,0x73,0x69,0x67,0x6e,0x77,0x72,0x69,0x74,0x69,0x6e, -0x67,0xa5,6,0x15,0x64,0x61,0x6e,0x65,0x73,0x65,0xa2,0x9b,0x12,0x73,0x75,0x70, -0xa2,0xdb,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xdb,4,0x61,0xa2,0xa8, -0x65,0x5c,0x6d,0x9e,0x70,0xa2,0x4b,0x73,0x13,0x79,0x6d,0x62,0x6f,0x1f,0x6c,0x73, -0x61,0x6e,0x64,0x70,0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa5,5, -0x10,0x72,1,0x61,0x4e,0x73,0x12,0x63,0x72,0x69,0x1f,0x70,0x74,0x73,0x61,0x6e, -0x64,0x73,0x75,0x62,0x73,0x63,0x72,0x69,0x70,0x74,0x73,0x73,0x14,0x6e,0x64,0x73, -0x75,0x62,0x73,0x1b,0x61,0x74,0x68,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73, -0xa3,0x6a,1,0x6c,0x40,0x75,1,0x61,0x6e,0x6e,0x17,0x63,0x74,0x75,0x61,0x74, -0x69,0x6f,0x6e,0xa3,0x8e,0x15,0x65,0x6d,0x65,0x6e,0x74,0x61,1,0x6c,0x50,0x72, -0x1e,0x79,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0x61,0x72,0x65,0x61, -1,0x61,0xa3,0x6d,0x62,0xa3,0x6e,3,0x61,0x5c,0x6d,0x78,0x70,0xa2,0x41,0x73, -0x13,0x79,0x6d,0x62,0x6f,0x1f,0x6c,0x73,0x61,0x6e,0x64,0x70,0x69,0x63,0x74,0x6f, -0x67,0x72,0x61,0x70,0x68,0x73,0xa5,5,0x14,0x72,0x72,0x6f,0x77,0x73,2,0x61, -0xa3,0x67,0x62,0xa3,0x68,0x63,0xa3,0xfa,0x13,0x61,0x74,0x68,0x65,0x1f,0x6d,0x61, -0x74,0x69,0x63,0x61,0x6c,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73,0xa3,0x6a, -0x19,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x8e,0x61,0x5a,0x68, -0x84,0x69,0xa2,0x5b,0x6d,0x16,0x61,0x6c,0x6c,0x66,0x6f,0x72,0x6d,1,0x73,0xa3, -0x54,0x76,0x16,0x61,0x72,0x69,0x61,0x6e,0x74,0x73,0xa3,0x54,1,0x6d,0x36,0x75, -0x16,0x72,0x61,0x73,0x68,0x74,0x72,0x61,0xa3,0xa1,0x15,0x61,0x72,0x69,0x74,0x61, -0x6e,0xa3,0xac,1,0x61,0x52,0x6f,0x13,0x72,0x74,0x68,0x61,0x1f,0x6e,0x64,0x66, -0x6f,0x72,0x6d,0x61,0x74,0x63,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x73,0xa3,0xf7,1, -0x72,0x2e,0x76,0x12,0x69,0x61,0x6e,0xa3,0x79,0x12,0x61,0x64,0x61,0xa3,0xd9,1, -0x64,0x50,0x6e,0x13,0x68,0x61,0x6c,0x61,0x50,0x1d,0x61,0x72,0x63,0x68,0x61,0x69, -0x63,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0xf9,0x13,0x64,0x68,0x61,0x6d,0xa3, -0xf8,5,0x72,0x35,0x72,0x44,0x73,0x64,0x75,1,0x61,0xa3,0x4e,0x6e,0x17,0x63, -0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x71,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73, -0x65,0xa2,0x4e,0x13,0x61,0x72,0x65,0x61,0xa3,0x4e,0x1b,0x61,0x6c,0x74,0x65,0x72, -0x70,0x61,0x68,0x6c,0x61,0x76,0x69,0xa3,0xf6,0x61,0x40,0x68,0x82,0x6c,0x19,0x61, -0x79,0x69,0x6e,0x67,0x63,0x61,0x72,0x64,0x73,0xa3,0xcc,2,0x68,0x38,0x6c,0x4a, -0x75,0x15,0x63,0x69,0x6e,0x68,0x61,0x75,0xa3,0xf5,0x17,0x61,0x77,0x68,0x68,0x6d, -0x6f,0x6e,0x67,0xa3,0xf3,0x15,0x6d,0x79,0x72,0x65,0x6e,0x65,0xa3,0xf4,1,0x61, -0x8e,0x6f,1,0x65,0x74,0x6e,0x16,0x65,0x74,0x69,0x63,0x65,0x78,0x74,0xa2,0x72, -1,0x65,0x2c,0x73,0x11,0x75,0x70,0xa3,0x8d,0x15,0x6e,0x73,0x69,0x6f,0x6e,0x73, -0xa2,0x72,0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x8d,0x15, -0x6e,0x69,0x63,0x69,0x61,0x6e,0xa3,0x97,1,0x67,0x3e,0x69,0x13,0x73,0x74,0x6f, -0x73,0xa2,0xa6,0x13,0x64,0x69,0x73,0x63,0xa3,0xa6,0x12,0x73,0x70,0x61,0xa3,0x96, -1,0x65,0x5c,0x75,1,0x6d,0x2a,0x6e,0x11,0x69,0x63,0x67,0x10,0x69,0xa2,0xc0, -0x1d,0x6e,0x75,0x6d,0x65,0x72,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3, -0xc0,0x13,0x6a,0x61,0x6e,0x67,0xa3,0xa3,0x6d,0xa2,0xc3,0x6e,0xa6,0xd2,0x6f,5, -0x70,0x4b,0x70,0x46,0x72,0x7a,0x73,1,0x61,0x30,0x6d,0x13,0x61,0x6e,0x79,0x61, -0xa3,0x7a,0x11,0x67,0x65,0xa5,0xf,0x18,0x74,0x69,0x63,0x61,0x6c,0x63,0x68,0x61, -0x72,0x1f,0x61,0x63,0x74,0x65,0x72,0x72,0x65,0x63,0x6f,0x67,0x6e,0x69,0x74,0x69, -0x6f,0x6e,0x85,1,0x69,0x46,0x6e,0x1e,0x61,0x6d,0x65,0x6e,0x74,0x61,0x6c,0x64, -0x69,0x6e,0x67,0x62,0x61,0x74,0x73,0xa3,0xf2,0x11,0x79,0x61,0x47,0x63,0xa2,0x66, -0x67,0xa2,0x66,0x6c,1,0x63,0xa2,0x57,0x64,5,0x70,0x2d,0x70,0x36,0x73,0x56, -0x74,0x14,0x75,0x72,0x6b,0x69,0x63,0xa3,0xbf,0x11,0x65,0x72,1,0x6d,0x2e,0x73, -0x12,0x69,0x61,0x6e,0xa3,0x8c,0x11,0x69,0x63,0xa3,0xf1,0x1a,0x6f,0x75,0x74,0x68, -0x61,0x72,0x61,0x62,0x69,0x61,0x6e,0xa3,0xbb,0x68,0x42,0x69,0x54,0x6e,0x1a,0x6f, -0x72,0x74,0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e,0xa3,0xf0,0x17,0x75,0x6e,0x67, -0x61,0x72,0x69,0x61,0x6e,0xa5,4,0x14,0x74,0x61,0x6c,0x69,0x63,0xa3,0x58,0x13, -0x68,0x69,0x6b,0x69,0xa3,0x9d,0x10,0x72,0x85,0x12,0x68,0x61,0x6d,0x65,6,0x6f, -0x86,0x6f,0x6c,0x72,0xa2,0x61,0x75,0xa2,0x62,0x79,0x14,0x61,0x6e,0x6d,0x61,0x72, -0x58,0x12,0x65,0x78,0x74,2,0x61,0xa3,0xb6,0x62,0xa3,0xee,0x65,0x13,0x6e,0x64, -0x65,0x64,1,0x61,0xa3,0xb6,0x62,0xa3,0xee,1,0x64,0x52,0x6e,0x15,0x67,0x6f, -0x6c,0x69,0x61,0x6e,0x6a,0x12,0x73,0x75,0x70,0xa4,0xd,0x16,0x70,0x6c,0x65,0x6d, -0x65,0x6e,0x74,0xa5,0xd,0x10,0x69,0xa2,0xec,0x13,0x66,0x69,0x65,0x72,1,0x6c, -0x3c,0x74,0x19,0x6f,0x6e,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0xa3,0x8a,0x15, -0x65,0x74,0x74,0x65,0x72,0x73,0x2d,0x10,0x6f,0xa3,0xed,1,0x6c,0x44,0x73,0x11, -0x69,0x63,0xa2,0x5c,0x18,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5c, -0x13,0x74,0x61,0x6e,0x69,0xa5,3,0x61,0xa2,0x9b,0x65,0xa4,0x36,0x69,1,0x61, -0xa2,0x8f,0x73,0x10,0x63,5,0x70,0x18,0x70,0xa2,0x71,0x73,0x36,0x74,0x17,0x65, -0x63,0x68,0x6e,0x69,0x63,0x61,0x6c,0x81,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x8f, -0x61,0xa2,0x66,0x65,0x46,0x6d,0x19,0x61,0x74,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c, -0x73,1,0x61,0xa3,0x66,0x62,0xa3,0x69,0x17,0x6c,0x6c,0x61,0x6e,0x65,0x6f,0x75, -0x73,2,0x6d,0x3a,0x73,0x6c,0x74,0x17,0x65,0x63,0x68,0x6e,0x69,0x63,0x61,0x6c, -0x81,0x11,0x61,0x74,0x1f,0x68,0x65,0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,0x73,0x79, -0x6d,0x62,0x6f,0x6c,0x73,1,0x61,0xa3,0x66,0x62,0xa3,0x69,0x15,0x79,0x6d,0x62, -0x6f,0x6c,0x73,0x8e,0x12,0x61,0x6e,0x64,1,0x61,0x3c,0x70,0x19,0x69,0x63,0x74, -0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa3,0xcd,0x14,0x72,0x72,0x6f,0x77,0x73,0xa3, -0x73,0x10,0x6f,0xa3,0xd8,5,0x72,0x62,0x72,0xa2,0x4c,0x73,0xa2,0x50,0x74,0x10, -0x68,2,0x61,0x3a,0x65,0x4a,0x6f,0x17,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73, -0x7f,0x16,0x6c,0x70,0x68,0x61,0x6e,0x75,0x6d,0xa3,0x5d,0x16,0x6d,0x61,0x74,0x69, -0x63,0x61,0x6c,1,0x61,0x36,0x6f,0x17,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73, -0x7f,0x11,0x6c,0x70,0x1f,0x68,0x61,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x73,0x79, -0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5d,0x13,0x63,0x68,0x65,0x6e,0xa5,0xc,0x18,0x61, -0x72,0x61,0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa5,0x14,0x68,0x4c,0x6c,0x7a,0x6e,1, -0x64,0x34,0x69,0x15,0x63,0x68,0x61,0x65,0x61,0x6e,0xa3,0xea,0x12,0x61,0x69,0x63, -0xa3,0xc6,1,0x61,0x3e,0x6a,0x12,0x6f,0x6e,0x67,0xa2,0xaa,0x14,0x74,0x69,0x6c, -0x65,0x73,0xa3,0xaa,0x13,0x6a,0x61,0x6e,0x69,0xa3,0xe9,0x15,0x61,0x79,0x61,0x6c, -0x61,0x6d,0x4f,2,0x65,0x66,0x6e,0x98,0x72,0x14,0x6f,0x69,0x74,0x69,0x63,1, -0x63,0x3c,0x68,0x19,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0xd7, -0x15,0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0xd6,0x17,0x74,0x65,0x69,0x6d,0x61,0x79, -0x65,0x6b,0xa2,0xb8,0x12,0x65,0x78,0x74,0xa2,0xd5,0x16,0x65,0x6e,0x73,0x69,0x6f, -0x6e,0x73,0xa3,0xd5,0x18,0x64,0x65,0x6b,0x69,0x6b,0x61,0x6b,0x75,0x69,0xa3,0xeb, -5,0x6b,0x23,0x6b,0x4c,0x6f,0x50,0x75,1,0x6d,0x2c,0x73,0x11,0x68,0x75,0xa5, -0x15,0x17,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0x7b,0x10,0x6f,0xa3,0x92,0x14, -0x62,0x6c,0x6f,0x63,0x6b,0x21,0x61,0x44,0x62,0x21,0x65,0x10,0x77,1,0x61,0xa5, -0xe,0x74,0x14,0x61,0x69,0x6c,0x75,0x65,0xa3,0x8b,0x16,0x62,0x61,0x74,0x61,0x65, -0x61,0x6e,0xa3,0xef,0x67,0xc3,0xcd,0x6a,0xc1,0x95,0x6a,0xa2,0xc5,0x6b,0xa2,0xde, -0x6c,4,0x61,0x54,0x65,0xa2,0x61,0x69,0xa2,0x78,0x6f,0xa2,0xa7,0x79,1,0x63, -0x2e,0x64,0x12,0x69,0x61,0x6e,0xa3,0xa9,0x12,0x69,0x61,0x6e,0xa3,0xa7,1,0x6f, -0x55,0x74,0x11,0x69,0x6e,1,0x31,0x82,0x65,0x11,0x78,0x74,4,0x61,0x5c,0x62, -0x29,0x63,0xa3,0x94,0x64,0xa3,0x95,0x65,0xa2,0xe7,0x13,0x6e,0x64,0x65,0x64,4, -0x61,0x36,0x62,0x29,0x63,0xa3,0x94,0x64,0xa3,0x95,0x65,0xa3,0xe7,0x26,0x18,0x64, -0x64,0x69,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x6d,0x24,0x12,0x73,0x75,0x70,0x24,0x16, -0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x25,1,0x70,0x42,0x74,0x1d,0x74,0x65,0x72, -0x6c,0x69,0x6b,0x65,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x79,0x12,0x63,0x68,0x61, -0xa3,0x9c,2,0x6d,0x2e,0x6e,0x34,0x73,0x10,0x75,0xa3,0xb0,0x11,0x62,0x75,0xa3, -0x6f,0x12,0x65,0x61,0x72,1,0x61,0xa3,0xe8,0x62,1,0x69,0x38,0x73,0x17,0x79, -0x6c,0x6c,0x61,0x62,0x61,0x72,0x79,0xa3,0x75,0x17,0x64,0x65,0x6f,0x67,0x72,0x61, -0x6d,0x73,0xa3,0x76,0x1a,0x77,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73, -0xa3,0x4d,0x10,0x61,1,0x6d,0x32,0x76,0x14,0x61,0x6e,0x65,0x73,0x65,0xa3,0xb5, -0x10,0x6f,0x5c,0x12,0x65,0x78,0x74,1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,1,0x61, -0x80,0x68,3,0x61,0x3c,0x6d,0x4c,0x6f,0x64,0x75,0x15,0x64,0x61,0x77,0x61,0x64, -0x69,0xa3,0xe6,0x16,0x72,0x6f,0x73,0x68,0x74,0x68,0x69,0xa3,0x89,0x11,0x65,0x72, -0x68,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x71,0x12,0x6a,0x6b,0x69,0xa3, -0xe5,3,0x69,0x3a,0x6e,0x42,0x74,0xa2,0x51,0x79,0x13,0x61,0x68,0x6c,0x69,0xa3, -0xa2,0x12,0x74,0x68,0x69,0xa3,0xc1,3,0x61,0x34,0x62,0x76,0x67,0x7c,0x6e,0x12, -0x61,0x64,0x61,0x4d,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0xcb,0x16,0x70,0x6c, -0x65,0x6d,0x65,0x6e,0x74,0xa3,0xcb,0x11,0x78,0x74,1,0x61,0xa5,0x13,0x65,0x14, -0x6e,0x64,0x65,0x64,0x61,0xa5,0x13,0x11,0x75,0x6e,0xa3,0x42,0x11,0x78,0x69,0x96, -0x17,0x72,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x97,0x14,0x61,0x6b,0x61,0x6e,0x61, -0x9e,1,0x65,0x4c,0x70,0x10,0x68,0x1f,0x6f,0x6e,0x65,0x74,0x69,0x63,0x65,0x78, -0x74,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa3,0x6b,0x11,0x78,0x74,0xa3,0x6b,0x67, -0xa2,0xa3,0x68,0xa4,0x53,0x69,3,0x64,0x4c,0x6d,0xa2,0x55,0x6e,0xa2,0x62,0x70, -0x13,0x61,0x65,0x78,0x74,0x2a,0x16,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0x2b,1, -0x63,0x99,0x65,0x17,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,1,0x64,0x56,0x73, -0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa4,0xb,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e, -0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa5,0xb,0x13,0x65,0x73,0x63,0x72,0x1f, -0x69,0x70,0x74,0x69,0x6f,0x6e,0x63,0x68,0x61,0x72,0x61,0x63,0x74,0x65,0x72,0x73, -0x99,0x1c,0x70,0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3, -0xba,1,0x64,0x62,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61,0x6c, -0x70,0x61,1,0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0xbd,0x13,0x6c, -0x61,0x76,0x69,0xa3,0xbe,0x1c,0x69,0x63,0x6e,0x75,0x6d,0x62,0x65,0x72,0x66,0x6f, -0x72,0x6d,0x73,0xa3,0xb2,4,0x65,0x58,0x6c,0xa2,0x63,0x6f,0xa2,0x7b,0x72,0xa2, -0x7f,0x75,1,0x6a,0x30,0x72,0x14,0x6d,0x75,0x6b,0x68,0x69,0x43,0x14,0x61,0x72, -0x61,0x74,0x69,0x45,1,0x6e,0x8c,0x6f,1,0x6d,0x4e,0x72,0x13,0x67,0x69,0x61, -0x6e,0x5a,0x12,0x73,0x75,0x70,0xa2,0x87,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, -0xa3,0x87,0x1a,0x65,0x74,0x72,0x69,0x63,0x73,0x68,0x61,0x70,0x65,0x73,0x8c,0x12, -0x65,0x78,0x74,0xa2,0xe3,0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0xe3,0x1e,0x65,0x72, -0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x71,0x17,0x61, -0x67,0x6f,0x6c,0x69,0x74,0x69,0x63,0xa2,0x88,0x12,0x73,0x75,0x70,0xa4,0xa,0x16, -0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0xa,0x13,0x74,0x68,0x69,0x63,0xa3,0x59, -1,0x61,0x5c,0x65,0x11,0x65,0x6b,0x30,1,0x61,0x38,0x65,0x11,0x78,0x74,0x6e, -0x14,0x65,0x6e,0x64,0x65,0x64,0x6f,0x17,0x6e,0x64,0x63,0x6f,0x70,0x74,0x69,0x63, -0x31,0x13,0x6e,0x74,0x68,0x61,0xa3,0xe4,2,0x61,0xa2,0x48,0x65,0xa2,0xcf,0x69, -1,0x67,0x30,0x72,0x14,0x61,0x67,0x61,0x6e,0x61,0x9d,0x10,0x68,1,0x70,0x3a, -0x73,0x18,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4b,1,0x72,0x3c, -0x75,0x19,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4c,0x11,0x69, -0x76,0x1f,0x61,0x74,0x65,0x75,0x73,0x65,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74, -0x65,0x73,0xa3,0x4c,2,0x6c,0x32,0x6e,0x9a,0x74,0x12,0x72,0x61,0x6e,0xa5,2, -0x10,0x66,2,0x61,0x58,0x6d,0x70,0x77,0x14,0x69,0x64,0x74,0x68,0x61,0x1f,0x6e, -0x64,0x66,0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,0x66,0x6f,0x72,0x6d,0x73,0xa3, -0x57,0x1a,0x6e,0x64,0x66,0x75,0x6c,0x6c,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x57,0x13, -0x61,0x72,0x6b,0x73,0xa3,0x52,1,0x67,0x2e,0x75,0x12,0x6e,0x6f,0x6f,0xa3,0x63, -0x11,0x75,0x6c,0xa2,0x4a,2,0x63,0x3c,0x6a,0x5e,0x73,0x17,0x79,0x6c,0x6c,0x61, -0x62,0x6c,0x65,0x73,0xa3,0x4a,0x1f,0x6f,0x6d,0x70,0x61,0x74,0x69,0x62,0x69,0x6c, -0x69,0x74,0x79,0x6a,0x61,0x6d,0x6f,0xa3,0x41,0x12,0x61,0x6d,0x6f,0x5c,0x17,0x65, -0x78,0x74,0x65,0x6e,0x64,0x65,0x64,1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,0x13,0x62, -0x72,0x65,0x77,0x37,0x61,0xa2,0xe9,0x62,0xa6,0x29,0x63,0xa6,0xfe,0x64,0xac,0x7c, -0x65,5,0x6d,0xa2,0x6d,0x86,0x6e,0x96,0x74,0x15,0x68,0x69,0x6f,0x70,0x69,0x63, -0x5e,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0x86,0x16,0x70,0x6c,0x65,0x6d,0x65, -0x6e,0x74,0xa3,0x86,0x11,0x78,0x74,0xa2,0x85,1,0x61,0xa3,0xc8,0x65,0x13,0x6e, -0x64,0x65,0x64,0xa2,0x85,0x10,0x61,0xa3,0xc8,0x16,0x6f,0x74,0x69,0x63,0x6f,0x6e, -0x73,0xa3,0xce,0x15,0x63,0x6c,0x6f,0x73,0x65,0x64,2,0x61,0x5a,0x63,0x9e,0x69, -0x1c,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x73,0x75,0x70,0xa2,0xc4, -0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc4,0x16,0x6c,0x70,0x68,0x61,0x6e, -0x75,0x6d,0x86,1,0x65,0x2c,0x73,0x11,0x75,0x70,0xa3,0xc3,0x13,0x72,0x69,0x63, -0x73,0x86,0x18,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc3,0x11,0x6a, -0x6b,0xa2,0x44,0x1f,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x61,0x6e,0x64,0x6d,0x6f, -0x6e,0x74,0x68,0x73,0xa3,0x44,0x61,0x36,0x67,0x62,0x6c,0x14,0x62,0x61,0x73,0x61, -0x6e,0xa3,0xe2,0x13,0x72,0x6c,0x79,0x64,0x1f,0x79,0x6e,0x61,0x73,0x74,0x69,0x63, -0x63,0x75,0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa5,1,0x10,0x79,0x1f,0x70,0x74, -0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0xc2, -7,0x6e,0xc0,0xe5,0x6e,0x3e,0x72,0xa2,0x5d,0x73,0xa2,0xd8,0x76,0x14,0x65,0x73, -0x74,0x61,0x6e,0xa3,0xbc,1,0x61,0x92,0x63,0x13,0x69,0x65,0x6e,0x74,1,0x67, -0x34,0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xa5,0x13,0x72,0x65,0x65,0x6b, -1,0x6d,0x34,0x6e,0x15,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0x7f,0x13,0x75,0x73, -0x69,0x63,0xa2,0x7e,0x19,0x61,0x6c,0x6e,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0xa3, -0x7e,0x10,0x74,0x1f,0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c, -0x79,0x70,0x68,0x73,0xa3,0xfe,2,0x61,0x32,0x6d,0xa2,0x71,0x72,0x12,0x6f,0x77, -0x73,0x7d,0x12,0x62,0x69,0x63,0x38,3,0x65,0x4a,0x6d,0x66,0x70,0xa2,0x43,0x73, -0x11,0x75,0x70,0xa2,0x80,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x80,0x11, -0x78,0x74,1,0x61,0xa3,0xd2,0x65,0x14,0x6e,0x64,0x65,0x64,0x61,0xa3,0xd2,0x12, -0x61,0x74,0x68,0xa2,0xd3,0x18,0x65,0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,0x61,0x1f, -0x6c,0x70,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73, -0xa3,0xd3,1,0x66,0x42,0x72,0x1e,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f, -0x6e,0x66,0x6f,0x72,0x6d,0x73,1,0x61,0xa3,0x51,0x62,0xa3,0x55,0x14,0x65,0x6e, -0x69,0x61,0x6e,0x35,0x12,0x63,0x69,0x69,0x23,0x64,0x9e,0x65,0xa2,0x42,0x68,0xa2, -0x4d,0x6c,1,0x63,0x62,0x70,0x17,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x70,1, -0x66,0xa3,0x50,0x72,0x1e,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66, -0x6f,0x72,0x6d,0x73,0xa3,0x50,0x16,0x68,0x65,0x6d,0x69,0x63,0x61,0x6c,0xa2,0xd0, -0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd0,0x12,0x6c,0x61,0x6d,0xa5,7, -0x1a,0x67,0x65,0x61,0x6e,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0x77,0x11,0x6f, -0x6d,0xa3,0xfd,7,0x6f,0x71,0x6f,0x64,0x72,0xa2,0x41,0x75,0xa2,0x58,0x79,0x1b, -0x7a,0x61,0x6e,0x74,0x69,0x6e,0x65,0x6d,0x75,0x73,0x69,0x63,0xa2,0x5b,0x18,0x61, -0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5b,1,0x70,0x34,0x78,0x16,0x64, -0x72,0x61,0x77,0x69,0x6e,0x67,0x89,0x14,0x6f,0x6d,0x6f,0x66,0x6f,0xa0,0x12,0x65, -0x78,0x74,0xa2,0x43,0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0x43,0x10,0x61,1,0x68, -0x40,0x69,0x12,0x6c,0x6c,0x65,0x92,0x17,0x70,0x61,0x74,0x74,0x65,0x72,0x6e,0x73, -0x93,0x11,0x6d,0x69,0xa3,0xc9,1,0x67,0x2c,0x68,0x11,0x69,0x64,0xa3,0x64,0x14, -0x69,0x6e,0x65,0x73,0x65,0xa3,0x81,0x61,0x48,0x65,0xa2,0x4e,0x68,0xa2,0x52,0x6c, -0x1a,0x6f,0x63,0x6b,0x65,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x73,0x8b,3,0x6c,0x34, -0x6d,0x40,0x73,0x66,0x74,0x11,0x61,0x6b,0xa3,0xc7,0x14,0x69,0x6e,0x65,0x73,0x65, -0xa3,0x93,0x11,0x75,0x6d,0xa2,0xb1,0x12,0x73,0x75,0x70,0xa2,0xca,0x16,0x70,0x6c, -0x65,0x6d,0x65,0x6e,0x74,0xa3,0xca,1,0x69,0x30,0x73,0x13,0x61,0x76,0x61,0x68, -0xa3,0xdd,0x15,0x63,0x6c,0x61,0x74,0x69,0x6e,0x23,0x14,0x6e,0x67,0x61,0x6c,0x69, -0x41,0x16,0x61,0x69,0x6b,0x73,0x75,0x6b,0x69,0xa5,8,5,0x6f,0xc1,0x4c,0x6f, -0xa2,0x55,0x75,0xa4,0x10,0x79,1,0x70,0x9c,0x72,0x14,0x69,0x6c,0x6c,0x69,0x63, -0x32,1,0x65,0x4c,0x73,0x11,0x75,0x70,0xa2,0x61,0x16,0x70,0x6c,0x65,0x6d,0x65, -0x6e,0x74,0xa2,0x61,0x12,0x61,0x72,0x79,0xa3,0x61,0x11,0x78,0x74,3,0x61,0xa3, -0x9e,0x62,0xa3,0xa0,0x63,0xa5,9,0x65,0x13,0x6e,0x64,0x65,0x64,2,0x61,0xa3, -0x9e,0x62,0xa3,0xa0,0x63,0xa5,9,0x1c,0x72,0x69,0x6f,0x74,0x73,0x79,0x6c,0x6c, -0x61,0x62,0x61,0x72,0x79,0xa3,0x7b,3,0x6d,0x5a,0x6e,0xa2,0x95,0x70,0xa2,0xa0, -0x75,0x17,0x6e,0x74,0x69,0x6e,0x67,0x72,0x6f,0x64,0xa2,0x9a,0x17,0x6e,0x75,0x6d, -0x65,0x72,0x61,0x6c,0x73,0xa3,0x9a,2,0x62,0x3a,0x6d,0xa2,0x5f,0x70,0x15,0x61, -0x74,0x6a,0x61,0x6d,0x6f,0xa3,0x41,0x14,0x69,0x6e,0x69,0x6e,0x67,2,0x64,0x46, -0x68,0x9e,0x6d,0x1d,0x61,0x72,0x6b,0x73,0x66,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f, -0x6c,0x73,0x77,0x1e,0x69,0x61,0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,0x6d,0x61, -0x72,0x6b,0x73,0x2e,2,0x65,0x40,0x66,0xa6,0x1c,0x73,0x18,0x75,0x70,0x70,0x6c, -0x65,0x6d,0x65,0x6e,0x74,0xa3,0x83,0x16,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,0xa3, -0xe0,0x17,0x61,0x6c,0x66,0x6d,0x61,0x72,0x6b,0x73,0xa3,0x52,0x11,0x6f,0x6e,0x1f, -0x69,0x6e,0x64,0x69,0x63,0x6e,0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73, -0xa3,0xb2,0x1b,0x74,0x72,0x6f,0x6c,0x70,0x69,0x63,0x74,0x75,0x72,0x65,0x73,0x83, -0x12,0x74,0x69,0x63,0xa2,0x84,0x1b,0x65,0x70,0x61,0x63,0x74,0x6e,0x75,0x6d,0x62, -0x65,0x72,0x73,0xa3,0xdf,1,0x6e,0x3e,0x72,0x1b,0x72,0x65,0x6e,0x63,0x79,0x73, -0x79,0x6d,0x62,0x6f,0x6c,0x73,0x75,0x15,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa2,0x98, -0x16,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa2,0x99,0x1d,0x61,0x6e,0x64,0x70,0x75, -0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x99,0x61,0xa2,0xdb,0x68,0xa4, -5,0x6a,0x10,0x6b,0xa2,0x47,4,0x63,0x86,0x65,0xa2,0x7d,0x72,0xa2,0x92,0x73, -0xa2,0xa4,0x75,0x1f,0x6e,0x69,0x66,0x69,0x65,0x64,0x69,0x64,0x65,0x6f,0x67,0x72, -0x61,0x70,0x68,0x73,0xa2,0x47,0x18,0x65,0x78,0x74,0x65,0x6e,0x73,0x69,0x6f,0x6e, -5,0x64,0x65,0x64,0xa3,0xd1,0x65,0xa5,0,0x66,0xa5,0x12,0x14,0x6f,0x6d,0x70, -0x61,0x74,0xa2,0x45,1,0x66,0x96,0x69,1,0x62,0x44,0x64,0x17,0x65,0x6f,0x67, -0x72,0x61,0x70,0x68,0x73,0xa2,0x4f,0x12,0x73,0x75,0x70,0xa3,0x5f,0x14,0x69,0x6c, -0x69,0x74,0x79,0xa2,0x45,1,0x66,0x54,0x69,0x18,0x64,0x65,0x6f,0x67,0x72,0x61, -0x70,0x68,0x73,0xa2,0x4f,0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, -0xa3,0x5f,0x13,0x6f,0x72,0x6d,0x73,0xa3,0x53,0x11,0x78,0x74,5,0x64,9,0x64, -0xa3,0xd1,0x65,0xa5,0,0x66,0xa5,0x12,0x61,0xa3,0x46,0x62,0xa3,0x5e,0x63,0xa3, -0xc5,0x19,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x73,0x75,0x70,0x94,0x16,0x70,0x6c, -0x65,0x6d,0x65,0x6e,0x74,0x95,1,0x74,0x50,0x79,0x14,0x6d,0x62,0x6f,0x6c,0x73, -0x9a,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e, -0x9b,0x14,0x72,0x6f,0x6b,0x65,0x73,0xa3,0x82,2,0x6e,0x48,0x72,0x64,0x75,0x1d, -0x63,0x61,0x73,0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e,0xa3,0xde, -0x1d,0x61,0x64,0x69,0x61,0x6e,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69,0x63,0x73,0x63, -0x12,0x69,0x61,0x6e,0xa3,0xa8,1,0x61,0x50,0x65,0x14,0x72,0x6f,0x6b,0x65,0x65, -0x60,0x12,0x73,0x75,0x70,0xa2,0xff,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3, -0xff,1,0x6b,0x26,0x6d,0xa3,0xa4,0x11,0x6d,0x61,0xa3,0xd4,3,0x65,0x3e,0x69, -0x7e,0x6f,0xa2,0x5d,0x75,0x15,0x70,0x6c,0x6f,0x79,0x61,0x6e,0xa3,0xe1,1,0x73, -0x50,0x76,0x16,0x61,0x6e,0x61,0x67,0x61,0x72,0x69,0x3e,0x12,0x65,0x78,0x74,0xa2, -0xb3,0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0xb3,0x13,0x65,0x72,0x65,0x74,0xa3,0x5a, -1,0x61,0x30,0x6e,0x14,0x67,0x62,0x61,0x74,0x73,0x91,0x18,0x63,0x72,0x69,0x74, -0x69,0x63,0x61,0x6c,0x73,0x2e,2,0x65,0x30,0x66,0x36,0x73,0x11,0x75,0x70,0xa3, -0x83,0x11,0x78,0x74,0xa3,0xe0,0x18,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73, -0x77,0x13,0x6d,0x69,0x6e,0x6f,0xa2,0xab,0x14,0x74,0x69,0x6c,0x65,0x73,0xa3,0xab, -8,0x6d,0x5f,0x6d,0x3a,0x6e,0x48,0x73,0x7a,0x76,0xa2,0x4b,0x77,0x12,0x69,0x64, -0x65,0x43,0x11,0x65,0x64,0x32,0x12,0x69,0x61,0x6c,0x33,2,0x61,0x40,0x62,0x37, -0x6f,1,0x62,0x28,0x6e,0x10,0x65,0x21,0x13,0x72,0x65,0x61,0x6b,0x37,0x10,0x72, -0x34,0x12,0x72,0x6f,0x77,0x35,2,0x6d,0x38,0x71,0x46,0x75,1,0x62,0x3d,0x70, -0x3e,0x11,0x65,0x72,0x3f,1,0x61,0x24,0x6c,0x39,0x11,0x6c,0x6c,0x39,1,0x72, -0x3b,0x75,0x12,0x61,0x72,0x65,0x3b,0x12,0x65,0x72,0x74,0x40,0x13,0x69,0x63,0x61, -0x6c,0x41,0x63,0x58,0x65,0x92,0x66,0x96,0x69,1,0x6e,0x36,0x73,0x10,0x6f,0x30, -0x14,0x6c,0x61,0x74,0x65,0x64,0x31,0x11,0x69,0x74,0x2e,0x12,0x69,0x61,0x6c,0x2f, -2,0x61,0x36,0x69,0x48,0x6f,0x10,0x6d,0x24,0x12,0x70,0x61,0x74,0x25,0x10,0x6e, -0x22,0x15,0x6f,0x6e,0x69,0x63,0x61,0x6c,0x23,0x13,0x72,0x63,0x6c,0x65,0x27,0x11, -0x6e,0x63,0x27,2,0x69,0x3a,0x6f,0x44,0x72,0x10,0x61,0x2c,0x14,0x63,0x74,0x69, -0x6f,0x6e,0x2d,0x10,0x6e,0x28,0x11,0x61,0x6c,0x29,0x11,0x6e,0x74,0x2b,4,0x61, -0x3a,0x66,0x4c,0x68,0x5e,0x6e,0x70,0x77,0x2a,0x12,0x69,0x64,0x65,0x2b,0x22,0x17, -0x6d,0x62,0x69,0x67,0x75,0x6f,0x75,0x73,0x23,0x26,0x17,0x75,0x6c,0x6c,0x77,0x69, -0x64,0x74,0x68,0x27,0x24,0x17,0x61,0x6c,0x66,0x77,0x69,0x64,0x74,0x68,0x25,0x20, -1,0x61,0x30,0x65,0x14,0x75,0x74,0x72,0x61,0x6c,0x21,0x28,0x13,0x72,0x72,0x6f, -0x77,0x29,0xd,0x6e,0xc0,0xfb,0x73,0x6d,0x73,0x3a,0x74,0x98,0x75,0xa2,0x49,0x7a, -2,0x6c,0x3b,0x70,0x3d,0x73,0x39,5,0x6f,0x28,0x6f,0x57,0x70,0x34,0x75,0x16, -0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x45,0x11,0x61,0x63,1,0x65,0x32,0x69,0x15, -0x6e,0x67,0x6d,0x61,0x72,0x6b,0x31,0x18,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f, -0x72,0x39,0x63,0x53,0x6b,0x55,0x6d,0x51,0x1d,0x69,0x74,0x6c,0x65,0x63,0x61,0x73, -0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x27,1,0x6e,0x40,0x70,0x1c,0x70,0x65,0x72, -0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x23,0x17,0x61,0x73,0x73,0x69, -0x67,0x6e,0x65,0x64,0x21,0x6e,0x8a,0x6f,0xa2,0x47,0x70,8,0x66,0x14,0x66,0x5b, -0x69,0x59,0x6f,0x4f,0x72,0x24,0x73,0x49,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73, -0x65,0x43,0x61,0x2c,0x63,0x4d,0x64,0x47,0x65,0x4b,0x1f,0x72,0x61,0x67,0x72,0x61, -0x70,0x68,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x3d,2,0x64,0x33,0x6c, -0x35,0x6f,0x36,0x1b,0x6e,0x73,0x70,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b, -0x2d,1,0x70,0x7c,0x74,0x12,0x68,0x65,0x72,3,0x6c,0x38,0x6e,0x42,0x70,0x4c, -0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0x57,0x14,0x65,0x74,0x74,0x65,0x72,0x2b,0x14, -0x75,0x6d,0x62,0x65,0x72,0x37,0x19,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f, -0x6e,0x4f,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e, -0x49,0x66,0x9e,0x66,0x88,0x69,0xa2,0x4b,0x6c,0xa2,0x5c,0x6d,4,0x61,0x60,0x63, -0x31,0x65,0x2f,0x6e,0x2d,0x6f,0x15,0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c,0x30, -0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0x55,0x14,0x65,0x74,0x74,0x65,0x72,0x29,0x17, -0x74,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x51,1,0x69,0x2e,0x6f,0x13,0x72,0x6d, -0x61,0x74,0x41,0x1d,0x6e,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69, -0x6f,0x6e,0x5b,0x10,0x6e,0x1f,0x69,0x74,0x69,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74, -0x75,0x61,0x74,0x69,0x6f,0x6e,0x59,6,0x6d,0x18,0x6d,0x29,0x6f,0x28,0x74,0x27, -0x75,0x23,0x2a,0x1c,0x77,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65, -0x72,0x25,0x65,0x28,0x69,0x3c,0x6c,0x25,0x19,0x74,0x74,0x65,0x72,0x6e,0x75,0x6d, -0x62,0x65,0x72,0x35,0x1a,0x6e,0x65,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72, -0x3b,0x63,0x44,0x64,0xa2,0x60,0x65,0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67, -0x6d,0x61,0x72,0x6b,0x2f,6,0x6e,0x39,0x6e,0x46,0x6f,0x4e,0x73,0x45,0x75,0x1b, -0x72,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x53,0x20,0x12,0x74, -0x72,0x6c,0x3f,0x42,0x10,0x6e,1,0x6e,0x2c,0x74,0x12,0x72,0x6f,0x6c,0x3f,0x1f, -0x65,0x63,0x74,0x6f,0x72,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e, -0x4d,0x63,0x3f,0x66,0x41,0x6c,0x1d,0x6f,0x73,0x65,0x70,0x75,0x6e,0x63,0x74,0x75, -0x61,0x74,0x69,0x6f,0x6e,0x4b,2,0x61,0x30,0x65,0x4a,0x69,0x12,0x67,0x69,0x74, -0x33,0x1c,0x73,0x68,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x47, -0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e,0x75,0x6d,0x62,0x65,0x72,0x33,0,0x12,0x6d, -0xc2,0x3f,0x73,0xa1,0x73,0x4e,0x74,0xa2,0x56,0x77,0xa2,0x72,0x79,0xa2,0x73,0x7a, -1,0x61,0x2c,0x68,0x12,0x61,0x69,0x6e,0x8b,0x11,0x69,0x6e,0x85,5,0x74,0x22, -0x74,0x38,0x77,0x4c,0x79,0x16,0x72,0x69,0x61,0x63,0x77,0x61,0x77,0x6f,0x18,0x72, -0x61,0x69,0x67,0x68,0x74,0x77,0x61,0x77,0xa3,0x55,0x15,0x61,0x73,0x68,0x6b,0x61, -0x66,0x6d,0x61,0x2e,0x65,0x38,0x68,0x11,0x69,0x6e,0x6b,0x10,0x64,0x62,0x11,0x68, -0x65,0x65,1,0x65,0x2e,0x6d,0x13,0x6b,0x61,0x74,0x68,0x69,0x10,0x6e,0x67,1, -0x61,0x4e,0x65,1,0x68,0x28,0x74,0x10,0x68,0x77,0x16,0x6d,0x61,0x72,0x62,0x75, -0x74,0x61,0x74,0x13,0x67,0x6f,0x61,0x6c,0x3d,1,0x68,0x71,0x77,0x73,0x11,0x61, -0x77,0x79,1,0x65,0x32,0x75,0x11,0x64,0x68,0x80,0x11,0x68,0x65,0x83,0x10,0x68, -0x7a,1,0x62,0x34,0x77,0x16,0x69,0x74,0x68,0x74,0x61,0x69,0x6c,0x7f,0x14,0x61, -0x72,0x72,0x65,0x65,0x7d,0x6d,0x6c,0x6e,0xa4,0x6b,0x70,0xa4,0x88,0x71,0xa4,0x88, -0x72,1,0x65,0x38,0x6f,0x18,0x68,0x69,0x6e,0x67,0x79,0x61,0x79,0x65,0x68,0x93, -1,0x68,0x5f,0x76,0x16,0x65,0x72,0x73,0x65,0x64,0x70,0x65,0x61,2,0x61,0x2e, -0x65,0xa4,0x3e,0x69,0x10,0x6d,0x53,1,0x6c,0xa2,0xe7,0x6e,0x16,0x69,0x63,0x68, -0x61,0x65,0x61,0x6e,0,0x12,0x6e,0x76,0x73,0x51,0x73,0x3e,0x74,0x5c,0x77,0xa0, -0x79,0xa2,0x42,0x7a,0x13,0x61,0x79,0x69,0x6e,0xa3,0x54,0x10,0x61,1,0x64,0x2e, -0x6d,0x12,0x65,0x6b,0x68,0xa3,0x4c,0x11,0x68,0x65,0xa3,0x4b,3,0x61,0x38,0x65, -0x3c,0x68,0x4a,0x77,0x13,0x65,0x6e,0x74,0x79,0xa3,0x51,0x10,0x77,0xa3,0x4d,1, -0x6e,0xa3,0x4e,0x74,0x10,0x68,0xa3,0x4f,0x14,0x61,0x6d,0x65,0x64,0x68,0xa3,0x50, -0x11,0x61,0x77,0xa3,0x52,0x12,0x6f,0x64,0x68,0xa3,0x53,0x6e,0x3a,0x6f,0x40,0x70, -0x46,0x71,0x4a,0x72,0x12,0x65,0x73,0x68,0xa3,0x4a,0x11,0x75,0x6e,0xa3,0x46,0x11, -0x6e,0x65,0xa3,0x47,0x10,0x65,0xa3,0x48,0x12,0x6f,0x70,0x68,0xa3,0x49,0x67,0x33, -0x67,0x38,0x68,0x40,0x6b,0x5e,0x6c,0x66,0x6d,0x11,0x65,0x6d,0xa3,0x45,0x13,0x69, -0x6d,0x65,0x6c,0xa1,1,0x65,0x32,0x75,0x14,0x6e,0x64,0x72,0x65,0x64,0xa3,0x42, -0x11,0x74,0x68,0xa3,0x41,0x12,0x61,0x70,0x68,0xa3,0x43,0x14,0x61,0x6d,0x65,0x64, -0x68,0xa3,0x44,0x61,0x34,0x62,0x4a,0x64,0x50,0x66,0x12,0x69,0x76,0x65,0x9f,1, -0x6c,0x2a,0x79,0x11,0x69,0x6e,0x97,0x12,0x65,0x70,0x68,0x95,0x12,0x65,0x74,0x68, -0x99,1,0x61,0x30,0x68,0x14,0x61,0x6d,0x65,0x64,0x68,0x9d,0x13,0x6c,0x65,0x74, -0x68,0x9b,0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,6,0x6e,0x2c,0x6e,0x34,0x72,0x5e, -0x73,0x62,0x74,0x11,0x74,0x61,0xa3,0x63,2,0x67,0x2e,0x6e,0x32,0x79,0x10,0x61, -0xa3,0x60,0x10,0x61,0xa3,0x5d,1,0x61,0xa3,0x5e,0x6e,0x10,0x61,0xa3,0x5f,0x10, -0x61,0xa3,0x61,0x11,0x73,0x61,0xa3,0x62,0x62,0x3c,0x6a,0x42,0x6c,0x10,0x6c,1, -0x61,0xa3,0x5b,0x6c,0x10,0x61,0xa3,0x5c,0x11,0x68,0x61,0xa3,0x59,0x10,0x61,0xa3, -0x5a,0x11,0x65,0x6d,0x51,2,0x6f,0x2c,0x75,0x50,0x79,0x10,0x61,0x91,1,0x6a, -0x28,0x6f,0x10,0x6e,0x55,0x1a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x67,0x72,0x6f,0x75, -0x70,0x21,0x10,0x6e,0x57,0x10,0x65,0x59,0x10,0x61,1,0x66,0x5b,0x70,0x10,0x68, -0x5d,0x66,0x7b,0x66,0x42,0x67,0x7a,0x68,0x8a,0x6b,0xa2,0x56,0x6c,0x11,0x61,0x6d, -0x4c,0x12,0x61,0x64,0x68,0x4f,2,0x61,0x3e,0x65,0x4a,0x69,0x19,0x6e,0x61,0x6c, -0x73,0x65,0x6d,0x6b,0x61,0x74,0x68,0x35,0x15,0x72,0x73,0x69,0x79,0x65,0x68,0x8f, -0x86,0x10,0x68,0x33,0x10,0x61,1,0x66,0x37,0x6d,0x11,0x61,0x6c,0x39,1,0x61, -0x40,0x65,0x3e,1,0x68,0x28,0x74,0x10,0x68,0x45,0x40,0x13,0x67,0x6f,0x61,0x6c, -0x43,1,0x68,0x3b,0x6d,0x1a,0x7a,0x61,0x6f,0x6e,0x68,0x65,0x68,0x67,0x6f,0x61, -0x6c,0x3d,2,0x61,0x3a,0x68,0x44,0x6e,0x17,0x6f,0x74,0x74,0x65,0x64,0x68,0x65, -0x68,0x4b,1,0x66,0x47,0x70,0x10,0x68,0x49,0x12,0x61,0x70,0x68,0x89,0x61,0x2e, -0x62,0x8a,0x64,0xa2,0x51,0x65,0x31,2,0x66,0x3c,0x69,0x70,0x6c,1,0x61,0x28, -0x65,0x10,0x66,0x27,0x11,0x70,0x68,0x25,0x14,0x72,0x69,0x63,0x61,0x6e,2,0x66, -0x30,0x6e,0x36,0x71,0x11,0x61,0x66,0xa3,0x58,0x11,0x65,0x68,0xa3,0x56,0x12,0x6f, -0x6f,0x6e,0xa3,0x57,0x10,0x6e,0x23,1,0x65,0x4a,0x75,0x10,0x72,0x1f,0x75,0x73, -0x68,0x61,0x73,0x6b,0x69,0x79,0x65,0x68,0x62,0x61,0x72,0x72,0x65,0x65,0x8d,1, -0x68,0x29,0x74,0x10,0x68,0x2b,0x11,0x61,0x6c,0x2c,0x16,0x61,0x74,0x68,0x72,0x69, -0x73,0x68,0x2f,7,0x6e,0x2e,0x6e,0x2c,0x72,0x3e,0x74,0x56,0x75,0x21,0x18,0x6f, -0x6e,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x21,0x28,0x1a,0x69,0x67,0x68,0x74,0x6a, -0x6f,0x69,0x6e,0x69,0x6e,0x67,0x29,0x2a,0x19,0x72,0x61,0x6e,0x73,0x70,0x61,0x72, -0x65,0x6e,0x74,0x2b,0x63,0x23,0x64,0x40,0x6a,0x56,0x6c,0x26,0x19,0x65,0x66,0x74, -0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x27,0x24,0x19,0x75,0x61,0x6c,0x6a,0x6f,0x69, -0x6e,0x69,0x6e,0x67,0x25,0x19,0x6f,0x69,0x6e,0x63,0x61,0x75,0x73,0x69,0x6e,0x67, -0x23,0,0x13,0x6e,0xc0,0xd0,0x73,0x49,0x73,0x48,0x75,0x78,0x77,0x84,0x78,0x9c, -0x7a,0x10,0x77,0x58,1,0x6a,0x75,0x73,0x13,0x70,0x61,0x63,0x65,0x59,4,0x61, -0x51,0x67,0x53,0x70,0x28,0x75,0x30,0x79,0x57,0x54,0x12,0x61,0x63,0x65,0x55,0x16, -0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x53,0x15,0x6e,0x6b,0x6e,0x6f,0x77,0x6e,0x21, -1,0x6a,0x5d,0x6f,0x17,0x72,0x64,0x6a,0x6f,0x69,0x6e,0x65,0x72,0x5d,0x10,0x78, -0x21,0x6e,0x60,0x6f,0xa2,0x41,0x70,0xa2,0x50,0x71,0xa2,0x6e,0x72,1,0x65,0x24, -0x69,0x6f,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74, -0x6f,0x72,0x6f,4,0x65,0x3e,0x6c,0x5b,0x6f,0x46,0x73,0x45,0x75,0x46,0x14,0x6d, -0x65,0x72,0x69,0x63,0x47,0x15,0x78,0x74,0x6c,0x69,0x6e,0x65,0x5b,0x17,0x6e,0x73, -0x74,0x61,0x72,0x74,0x65,0x72,0x45,0x10,0x70,0x48,0x1c,0x65,0x6e,0x70,0x75,0x6e, -0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x49,1,0x6f,0x3e,0x72,0x4c,0x1a,0x65, -0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x4d,0x4a,0x1b,0x73,0x74,0x66, -0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x4b,0x10,0x75,0x4e,0x16,0x6f,0x74, -0x61,0x74,0x69,0x6f,0x6e,0x4f,0x68,0x7b,0x68,0x50,0x69,0x86,0x6a,0xa2,0x61,0x6c, -0xa2,0x65,0x6d,0x1c,0x61,0x6e,0x64,0x61,0x74,0x6f,0x72,0x79,0x62,0x72,0x65,0x61, -0x6b,0x2d,4,0x32,0x5f,0x33,0x61,0x65,0x34,0x6c,0x6d,0x79,0x3a,0x13,0x70,0x68, -0x65,0x6e,0x3b,0x19,0x62,0x72,0x65,0x77,0x6c,0x65,0x74,0x74,0x65,0x72,0x6d,2, -0x64,0x28,0x6e,0x3c,0x73,0x41,0x3c,0x18,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x69, -0x63,0x3d,0x3e,1,0x66,0x3e,0x73,0x11,0x65,0x70,1,0x61,0x22,0x65,0x14,0x72, -0x61,0x62,0x6c,0x65,0x3f,0x18,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x41, -2,0x6c,0x63,0x74,0x65,0x76,0x67,1,0x66,0x43,0x69,0x15,0x6e,0x65,0x66,0x65, -0x65,0x64,0x43,0x61,0x40,0x62,0x70,0x63,0xa2,0x55,0x65,0xa2,0xdb,0x67,0x10,0x6c, -0x38,0x11,0x75,0x65,0x39,2,0x69,0x23,0x6c,0x34,0x6d,0x16,0x62,0x69,0x67,0x75, -0x6f,0x75,0x73,0x23,0x24,0x17,0x70,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x25,4, -0x32,0x27,0x61,0x29,0x62,0x2b,0x6b,0x2d,0x72,0x12,0x65,0x61,0x6b,2,0x61,0x36, -0x62,0x3e,0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x57,0x13,0x66,0x74,0x65,0x72, -0x29,1,0x65,0x2a,0x6f,0x11,0x74,0x68,0x27,0x13,0x66,0x6f,0x72,0x65,0x2b,7, -0x6d,0x51,0x6d,0x33,0x6f,0x28,0x70,0x69,0x72,0x35,1,0x6d,0x76,0x6e,1,0x64, -0x3c,0x74,0x1a,0x69,0x6e,0x67,0x65,0x6e,0x74,0x62,0x72,0x65,0x61,0x6b,0x2f,0x15, -0x69,0x74,0x69,0x6f,0x6e,0x61,0x1f,0x6c,0x6a,0x61,0x70,0x61,0x6e,0x65,0x73,0x65, -0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x6b,1,0x62,0x3a,0x70,0x19,0x6c,0x65,0x78, -0x63,0x6f,0x6e,0x74,0x65,0x78,0x74,0x51,0x18,0x69,0x6e,0x69,0x6e,0x67,0x6d,0x61, -0x72,0x6b,0x33,0x61,0x6a,0x62,0x2f,0x6a,0x6b,0x6c,0x30,0x13,0x6f,0x73,0x65,0x70, -1,0x61,0x38,0x75,0x18,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x31,0x18, -0x72,0x65,0x6e,0x74,0x68,0x65,0x73,0x69,0x73,0x69,0x1b,0x72,0x72,0x69,0x61,0x67, -0x65,0x72,0x65,0x74,0x75,0x72,0x6e,0x35,2,0x62,0x3e,0x6d,0x46,0x78,0x36,0x18, -0x63,0x6c,0x61,0x6d,0x61,0x74,0x69,0x6f,0x6e,0x37,0x70,0x12,0x61,0x73,0x65,0x71, -0x72,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x73,1,0x64,0x42,0x6e,1,0x6f, -0x32,0x75,0x26,0x14,0x6d,0x65,0x72,0x69,0x63,0x27,0x11,0x6e,0x65,0x21,1,0x65, -0x2e,0x69,0x24,0x12,0x67,0x69,0x74,0x25,0x22,0x14,0x63,0x69,0x6d,0x61,0x6c,0x23, -0,0x18,0x6e,0xc3,0xc4,0x74,0xc1,0x51,0x77,0x7a,0x77,0xa2,0x4c,0x78,0xa2,0x60, -0x79,0xa2,0x6a,0x7a,6,0x73,0x1e,0x73,0x34,0x78,0x42,0x79,0x48,0x7a,0x11,0x7a, -0x7a,0xa3,0x67,0x10,0x79,1,0x65,0xa3,0xae,0x6d,0xa3,0x81,0x11,0x78,0x78,0xa3, -0x66,0x11,0x79,0x79,0x21,0x61,0x30,0x69,0x58,0x6d,0x11,0x74,0x68,0xa3,0x80,0x10, -0x6e,1,0x61,0x26,0x62,0xa3,0xb1,0x1a,0x62,0x61,0x7a,0x61,0x72,0x73,0x71,0x75, -0x61,0x72,0x65,0xa3,0xb1,0x11,0x6e,0x68,0x23,1,0x61,0x2c,0x6f,0x11,0x6c,0x65, -0xa3,0x9b,0x11,0x72,0x61,0xa2,0x92,0x15,0x6e,0x67,0x63,0x69,0x74,0x69,0xa3,0x92, -1,0x70,0x2c,0x73,0x11,0x75,0x78,0xa3,0x65,0x11,0x65,0x6f,0x9b,0x10,0x69,0x72, -0x11,0x69,0x69,0x73,0x74,0x4a,0x75,0xa2,0xba,0x76,1,0x61,0x2c,0x69,0x11,0x73, -0x70,0xa3,0x64,0x10,0x69,0xa2,0x63,0x10,0x69,0xa3,0x63,5,0x67,0x36,0x67,0x68, -0x68,0x6c,0x69,2,0x62,0x3a,0x66,0x4a,0x72,0x10,0x68,0xa2,0x9e,0x12,0x75,0x74, -0x61,0xa3,0x9e,1,0x65,0x24,0x74,0x6f,0x12,0x74,0x61,0x6e,0x6f,0x14,0x69,0x6e, -0x61,0x67,0x68,0x99,0x11,0x6c,0x67,0x75,0x10,0x61,1,0x61,0x24,0x69,0x6d,0x6a, -0x11,0x6e,0x61,0x6b,0x61,0x30,0x65,0xa2,0x5b,0x66,0x11,0x6e,0x67,0x99,6,0x6c, -0x21,0x6c,0x32,0x6d,0x38,0x6e,0x44,0x76,0x10,0x74,0xa3,0x7f,1,0x65,0x89,0x75, -0x97,1,0x69,0x24,0x6c,0x67,0x10,0x6c,0x67,0x10,0x67,0xa2,0x9a,0x11,0x75,0x74, -0xa3,0x9a,0x67,0x36,0x69,0x52,0x6b,0x10,0x72,0xa2,0x99,0x10,0x69,0xa3,0x99,1, -0x61,0x30,0x62,0x7a,0x13,0x61,0x6e,0x77,0x61,0x7b,0x12,0x6c,0x6f,0x67,0x75,2, -0x6c,0x32,0x74,0x34,0x76,0x12,0x69,0x65,0x74,0xa3,0x7f,0x10,0x65,0x89,0x12,0x68, -0x61,0x6d,0xa3,0x6a,1,0x6c,0x2a,0x6e,0x10,0x67,0xa3,0x62,0x10,0x75,0x68,0x11, -0x67,0x75,0x69,1,0x67,0x32,0x6e,0x14,0x6b,0x6e,0x6f,0x77,0x6e,0xa3,0x67,0x11, -0x61,0x72,0x8a,0x13,0x69,0x74,0x69,0x63,0x8b,0x71,0xc0,0xfc,0x71,0xa2,0xce,0x72, -0xa2,0xd3,0x73,6,0x69,0x7a,0x69,0x72,0x6f,0xa2,0x4c,0x75,0xa2,0x65,0x79,1, -0x6c,0x46,0x72,4,0x63,0x65,0x65,0xa3,0x5f,0x69,0x2c,0x6a,0xa3,0x60,0x6e,0xa3, -0x61,0x11,0x61,0x63,0x65,0x10,0x6f,0x94,0x16,0x74,0x69,0x6e,0x61,0x67,0x72,0x69, -0x95,2,0x64,0x3c,0x67,0x4c,0x6e,1,0x64,0xa3,0x91,0x68,0x62,0x12,0x61,0x6c, -0x61,0x63,0x10,0x64,0xa2,0xa6,0x12,0x68,0x61,0x6d,0xa3,0xa6,0x17,0x6e,0x77,0x72, -0x69,0x74,0x69,0x6e,0x67,0xa3,0x70,1,0x72,0x36,0x79,0x10,0x6f,0xa2,0xb0,0x12, -0x6d,0x62,0x6f,0xa3,0xb0,0x10,0x61,0xa2,0x98,0x16,0x73,0x6f,0x6d,0x70,0x65,0x6e, -0x67,0xa3,0x98,0x11,0x6e,0x64,0xa2,0x71,0x14,0x61,0x6e,0x65,0x73,0x65,0xa3,0x71, -0x61,0x5c,0x67,0xa2,0x43,0x68,1,0x61,0x2a,0x72,0x10,0x64,0xa3,0x97,2,0x72, -0x28,0x76,0x30,0x77,0x87,0x12,0x61,0x64,0x61,0xa3,0x97,0x12,0x69,0x61,0x6e,0x87, -2,0x6d,0x40,0x72,0x58,0x75,0x10,0x72,0xa2,0x6f,0x15,0x61,0x73,0x68,0x74,0x72, -0x61,0xa3,0x6f,1,0x61,0x26,0x72,0xa3,0x7e,0x14,0x72,0x69,0x74,0x61,0x6e,0xa3, -0x7e,1,0x61,0xa3,0x5e,0x62,0xa3,0x85,0x11,0x6e,0x77,0xa3,0x70,0x11,0x61,0x61, -1,0x63,0x2f,0x69,0x23,3,0x65,0x3e,0x6a,0x48,0x6f,0x4e,0x75,0x10,0x6e,1, -0x69,0x24,0x72,0x61,0x10,0x63,0x61,0x13,0x6a,0x61,0x6e,0x67,0xa3,0x6e,0x11,0x6e, -0x67,0xa3,0x6e,0x11,0x72,0x6f,0xa3,0x5d,0x6e,0xa2,0x83,0x6f,0xa2,0xca,0x70,5, -0x6c,0x1e,0x6c,0x44,0x72,0x4a,0x73,0x1b,0x61,0x6c,0x74,0x65,0x72,0x70,0x61,0x68, -0x6c,0x61,0x76,0x69,0xa3,0x7b,0x11,0x72,0x64,0xa3,0x5c,0x11,0x74,0x69,0xa3,0x7d, -0x61,0x7c,0x65,0xa2,0x54,0x68,3,0x61,0x3e,0x6c,0x4e,0x6e,0x5e,0x6f,0x16,0x65, -0x6e,0x69,0x63,0x69,0x61,0x6e,0xa3,0x5b,0x10,0x67,0xa2,0x5a,0x12,0x73,0x70,0x61, -0xa3,0x5a,2,0x69,0xa3,0x7a,0x70,0xa3,0x7b,0x76,0xa3,0x7c,0x10,0x78,0xa3,0x5b, -2,0x68,0x3e,0x6c,0x50,0x75,0x10,0x63,0xa2,0xa5,0x14,0x69,0x6e,0x68,0x61,0x75, -0xa3,0xa5,0x17,0x61,0x77,0x68,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0x4b,0x10,0x6d,0xa2, -0x90,0x14,0x79,0x72,0x65,0x6e,0x65,0xa3,0x90,0x11,0x72,0x6d,0xa3,0x59,5,0x6b, -0x1e,0x6b,0x32,0x73,0x4a,0x75,0x12,0x73,0x68,0x75,0xa3,0x96,1,0x67,0x2e,0x6f, -0xa2,0x57,0x10,0x6f,0xa3,0x57,0x10,0x62,0xa3,0x84,0x11,0x68,0x75,0xa3,0x96,0x61, -0x42,0x62,0x60,0x65,0x10,0x77,1,0x61,0xa3,0xaa,0x74,0x14,0x61,0x69,0x6c,0x75, -0x65,0x97,1,0x62,0x2a,0x72,0x10,0x62,0xa3,0x8e,0x15,0x61,0x74,0x61,0x65,0x61, -0x6e,0xa3,0x8f,0x11,0x61,0x74,0xa3,0x8f,3,0x67,0x5a,0x6c,0x6c,0x72,0xa2,0x88, -0x73,2,0x61,0x36,0x67,0x3c,0x6d,0x10,0x61,0x84,0x12,0x6e,0x79,0x61,0x85,0x11, -0x67,0x65,0xa3,0xab,0x10,0x65,0xa3,0xab,1,0x61,0x2a,0x68,0x11,0x61,0x6d,0x5b, -0x10,0x6d,0x5b,1,0x63,0xa2,0x55,0x64,5,0x70,0x2c,0x70,0x36,0x73,0x54,0x74, -0x14,0x75,0x72,0x6b,0x69,0x63,0xa3,0x58,0x11,0x65,0x72,1,0x6d,0x2c,0x73,0x12, -0x69,0x61,0x6e,0x9b,0x11,0x69,0x63,0xa3,0x59,0x1a,0x6f,0x75,0x74,0x68,0x61,0x72, -0x61,0x62,0x69,0x61,0x6e,0xa3,0x85,0x68,0x42,0x69,0x54,0x6e,0x1a,0x6f,0x72,0x74, -0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e,0xa3,0x8e,0x17,0x75,0x6e,0x67,0x61,0x72, -0x69,0x61,0x6e,0xa3,0x4c,0x14,0x74,0x61,0x6c,0x69,0x63,0x5d,1,0x68,0x26,0x6b, -0xa3,0x6d,0x12,0x69,0x6b,0x69,0xa3,0x6d,2,0x69,0x2c,0x6b,0x30,0x79,0x10,0x61, -0x5f,0x11,0x79,0x61,0x5f,0x10,0x68,0xa3,0x58,0x68,0xc2,0xc2,0x6b,0xc1,0xeb,0x6b, -0xa2,0xf8,0x6c,0xa4,0x79,0x6d,8,0x6f,0x46,0x6f,0x48,0x72,0x74,0x74,0x80,0x75, -0x86,0x79,1,0x61,0x28,0x6d,0x10,0x72,0x59,0x13,0x6e,0x6d,0x61,0x72,0x59,2, -0x64,0x2e,0x6e,0x32,0x6f,0x10,0x6e,0xa3,0x72,0x10,0x69,0xa3,0xa3,0x10,0x67,0x56, -0x14,0x6f,0x6c,0x69,0x61,0x6e,0x57,0x10,0x6f,0xa2,0x95,0x10,0x6f,0xa3,0x95,0x11, -0x65,0x69,0xa3,0x73,0x11,0x6c,0x74,0xa2,0xa4,0x12,0x61,0x6e,0x69,0xa3,0xa4,0x61, -0x36,0x65,0xa2,0x5b,0x69,0xa2,0x9e,0x6c,0x11,0x79,0x6d,0x55,5,0x72,0x1f,0x72, -0x2e,0x73,0x3e,0x79,0x10,0x61,0xa3,0x55,0x10,0x63,0xa2,0xa9,0x12,0x68,0x65,0x6e, -0xa3,0xa9,0x18,0x61,0x72,0x61,0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xaf,0x68,0x54, -0x6c,0x6a,0x6e,1,0x64,0x38,0x69,0xa2,0x79,0x15,0x63,0x68,0x61,0x65,0x61,0x6e, -0xa3,0x79,0xa2,0x54,0x12,0x61,0x69,0x63,0xa3,0x54,1,0x61,0x26,0x6a,0xa3,0xa0, -0x13,0x6a,0x61,0x6e,0x69,0xa3,0xa0,0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,0x55,2, -0x65,0x72,0x6e,0x84,0x72,1,0x63,0xa3,0x8d,0x6f,0xa2,0x56,0x13,0x69,0x74,0x69, +0x90,0x62,0xa2,0xbe,0x63,0xa4,0x30,0x64,0xa4,0xfd,0x65,5,0x6d,0x63,0x6d,0x6e, +0x70,0xa2,0x59,0x78,0x10,0x74,0x30,1,0x65,0x2c,0x70,0x12,0x69,0x63,0x74,0xa1, +0x12,0x6e,0x64,0x65,1,0x64,0x24,0x72,0x31,0x1b,0x70,0x69,0x63,0x74,0x6f,0x67, +0x72,0x61,0x70,0x68,0x69,0x63,0xa1,0x10,0x6f,1,0x64,0x97,0x6a,0x10,0x69,0x92, +2,0x63,0x40,0x6d,0x50,0x70,0x1a,0x72,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69, +0x6f,0x6e,0x95,0x17,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x9b,0x16,0x6f,0x64, +0x69,0x66,0x69,0x65,0x72,0x96,0x13,0x62,0x61,0x73,0x65,0x99,0x12,0x72,0x65,0x73, +0x95,0x61,0x30,0x62,0x4e,0x63,0x12,0x6f,0x6d,0x70,0x9b,0xc2,4,0x1b,0x73,0x74, +0x61,0x73,0x69,0x61,0x6e,0x77,0x69,0x64,0x74,0x68,0xc3,4,0x12,0x61,0x73,0x65, +0x99,3,0x67,0x44,0x68,0x4a,0x6c,0x4e,0x73,0x1a,0x63,0x69,0x69,0x68,0x65,0x78, +0x64,0x69,0x67,0x69,0x74,0x23,0x10,0x65,0xd9,0x40,0,0x11,0x65,0x78,0x23,1, +0x6e,0x38,0x70,0x11,0x68,0x61,0x20,0x14,0x62,0x65,0x74,0x69,0x63,0x21,0x11,0x75, +0x6d,0x79,4,0x63,0xc3,0,0x69,0x3e,0x6c,0xa2,0x57,0x6d,0xa2,0x64,0x70,1, +0x62,0xd9,0x40,0xd,0x74,0xc3,0x15,0x11,0x64,0x69,2,0x63,0x54,0x6d,0x74,0x70, +0x1b,0x61,0x69,0x72,0x65,0x64,0x62,0x72,0x61,0x63,0x6b,0x65,0x74,0xd8,0x40,0xd, +0x13,0x74,0x79,0x70,0x65,0xc3,0x15,0x24,1,0x6c,0x30,0x6f,0x14,0x6e,0x74,0x72, +0x6f,0x6c,0x25,0x12,0x61,0x73,0x73,0xc3,0,0x26,0x14,0x69,0x72,0x72,0x6f,0x72, +1,0x65,0x38,0x69,0x16,0x6e,0x67,0x67,0x6c,0x79,0x70,0x68,0xd9,0x40,1,0x10, +0x64,0x27,2,0x61,0x32,0x6b,0xc3,1,0x6f,0x11,0x63,0x6b,0xc3,1,0x11,0x6e, +0x6b,0x7b,0x10,0x67,0xd9,0x40,1,6,0x68,0x7c,0x68,0x54,0x69,0x85,0x6f,0xa2, +0x6f,0x77,4,0x63,0x30,0x6b,0x36,0x6c,0x87,0x74,0x8b,0x75,0x89,1,0x66,0x8d, +0x6d,0x8f,0x11,0x63,0x66,0x91,0x18,0x61,0x6e,0x67,0x65,0x73,0x77,0x68,0x65,0x6e, +4,0x63,0x44,0x6c,0x6c,0x6e,0x7e,0x74,0x98,0x75,0x18,0x70,0x70,0x65,0x72,0x63, +0x61,0x73,0x65,0x64,0x89,0x12,0x61,0x73,0x65,1,0x66,0x30,0x6d,0x14,0x61,0x70, +0x70,0x65,0x64,0x8f,0x14,0x6f,0x6c,0x64,0x65,0x64,0x8d,0x18,0x6f,0x77,0x65,0x72, +0x63,0x61,0x73,0x65,0x64,0x87,0x1c,0x66,0x6b,0x63,0x63,0x61,0x73,0x65,0x66,0x6f, +0x6c,0x64,0x65,0x64,0x91,0x18,0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x64,0x8b, +0x13,0x6d,0x70,0x65,0x78,0x33,0x61,0x2e,0x63,0xa2,0x48,0x66,0xd9,0x40,2,1, +0x6e,0x72,0x73,0x10,0x65,3,0x64,0x83,0x66,0x3a,0x69,0x4a,0x73,0x17,0x65,0x6e, +0x73,0x69,0x74,0x69,0x76,0x65,0x65,0x15,0x6f,0x6c,0x64,0x69,0x6e,0x67,0xd9,0x40, +2,0x17,0x67,0x6e,0x6f,0x72,0x61,0x62,0x6c,0x65,0x85,0x13,0x6f,0x6e,0x69,0x63, +0x1f,0x61,0x6c,0x63,0x6f,0x6d,0x62,0x69,0x6e,0x69,0x6e,0x67,0x63,0x6c,0x61,0x73, +0x73,0xc3,2,0x10,0x63,0xc3,2,3,0x61,0x30,0x65,0x34,0x69,0xa2,0x41,0x74, +0xc3,3,0x11,0x73,0x68,0x29,2,0x63,0x3a,0x66,0x58,0x70,0x2c,0x16,0x72,0x65, +0x63,0x61,0x74,0x65,0x64,0x2d,0x1d,0x6f,0x6d,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, +0x6e,0x74,0x79,0x70,0x65,0xc3,3,0x15,0x61,0x75,0x6c,0x74,0x69,0x67,0x1f,0x6e, +0x6f,0x72,0x61,0x62,0x6c,0x65,0x63,0x6f,0x64,0x65,0x70,0x6f,0x69,0x6e,0x74,0x2b, +0x2a,0x10,0x61,0x2e,0x15,0x63,0x72,0x69,0x74,0x69,0x63,0x2f,3,0x66,0x34,0x6e, +0x3e,0x74,0x42,0x79,0x22,0x11,0x65,0x73,0x23,0x20,0x13,0x61,0x6c,0x73,0x65,0x21, +0x20,0x10,0x6f,0x21,0x22,0x12,0x72,0x75,0x65,0x23,0xa,0x6b,0x5b,0x6f,0x23,0x6f, +0x3c,0x72,0x4c,0x76,1,0x69,0x24,0x72,0x33,0x13,0x72,0x61,0x6d,0x61,0x33,0x10, +0x76,0x22,0x14,0x65,0x72,0x6c,0x61,0x79,0x23,0xa2,0xe2,0x13,0x69,0x67,0x68,0x74, +0xa3,0xe2,0x6b,0x58,0x6c,0x74,0x6e,3,0x6b,0x2f,0x6f,0x30,0x72,0x21,0x75,0x12, +0x6b,0x74,0x61,0x2f,0x19,0x74,0x72,0x65,0x6f,0x72,0x64,0x65,0x72,0x65,0x64,0x21, +1,0x61,0x24,0x76,0x31,0x18,0x6e,0x61,0x76,0x6f,0x69,0x63,0x69,0x6e,0x67,0x31, +0xa2,0xe0,0x12,0x65,0x66,0x74,0xa3,0xe0,0x61,0x5c,0x62,0xa2,0x77,0x63,0xa2,0x96, +0x64,0xa4,0xa,0x69,1,0x6f,0x26,0x73,0xa3,0xf0,0x1a,0x74,0x61,0x73,0x75,0x62, +0x73,0x63,0x72,0x69,0x70,0x74,0xa3,0xf0,0xa2,0xe6,3,0x62,0xa0,0x6c,0xa3,0xe4, +0x72,0xa3,0xe8,0x74,2,0x61,0x74,0x62,0x7c,0x74,0x14,0x61,0x63,0x68,0x65,0x64, +1,0x61,0x3e,0x62,0x13,0x65,0x6c,0x6f,0x77,0xa2,0xca,0x13,0x6c,0x65,0x66,0x74, +0xa3,0xc8,0x13,0x62,0x6f,0x76,0x65,0xa2,0xd6,0x14,0x72,0x69,0x67,0x68,0x74,0xa3, +0xd8,0xa2,0xd6,0x10,0x72,0xa3,0xd8,0xa2,0xca,0x10,0x6c,0xa3,0xc8,0x12,0x6f,0x76, +0x65,0xa2,0xe6,1,0x6c,0x30,0x72,0x13,0x69,0x67,0x68,0x74,0xa3,0xe8,0x12,0x65, +0x66,0x74,0xa3,0xe4,0xa2,0xdc,2,0x65,0x2c,0x6c,0xa3,0xda,0x72,0xa3,0xde,0x12, +0x6c,0x6f,0x77,0xa2,0xdc,1,0x6c,0x30,0x72,0x13,0x69,0x67,0x68,0x74,0xa3,0xde, +0x12,0x65,0x66,0x74,0xa3,0xda,0x11,0x63,0x63,4,0x31,0x3c,0x32,0xa2,0x42,0x33, +0xa2,0x56,0x38,0xa2,0x64,0x39,0x10,0x31,0xa3,0x5b,9,0x35,0xa,0x35,0x3f,0x36, +0x41,0x37,0x43,0x38,0x45,0x39,0x47,0x30,0x30,0x31,0x3c,0x32,0x42,0x33,0x4e,0x34, +0x3d,0x34,1,0x33,0xa3,0x67,0x37,0xa3,0x6b,0x36,0x10,0x38,0xa3,0x76,0x38,1, +0x32,0xa3,0x7a,0x39,0xa3,0x81,0x3a,2,0x30,0xa3,0x82,0x32,0xa3,0x84,0x33,0xa3, +0x85,9,0x35,0xa,0x35,0x53,0x36,0x55,0x37,0x57,0x38,0x59,0x39,0x5b,0x30,0x49, +0x31,0x4b,0x32,0x4d,0x33,0x4f,0x34,0x51,6,0x33,8,0x33,0x63,0x34,0x65,0x35, +0x67,0x36,0x69,0x30,0x5d,0x31,0x5f,0x32,0x61,0x10,0x34,0xa3,0x54,2,0x61,0xa3, +0xea,0x62,0xa3,0xe9,0x6f,0x13,0x75,0x62,0x6c,0x65,1,0x61,0x30,0x62,0x13,0x65, +0x6c,0x6f,0x77,0xa3,0xe9,0x13,0x62,0x6f,0x76,0x65,0xa3,0xea,0xb,0x6e,0xc0,0xca, +0x72,0x5f,0x72,0x46,0x73,0xa2,0x48,0x77,1,0x68,0x24,0x73,0x33,0x17,0x69,0x74, +0x65,0x73,0x70,0x61,0x63,0x65,0x33,0x22,1,0x69,0x30,0x6c,2,0x65,0x3d,0x69, +0x4b,0x6f,0x3f,0x18,0x67,0x68,0x74,0x74,0x6f,0x6c,0x65,0x66,0x74,0x22,2,0x65, +0x38,0x69,0x48,0x6f,0x16,0x76,0x65,0x72,0x72,0x69,0x64,0x65,0x3f,0x17,0x6d,0x62, +0x65,0x64,0x64,0x69,0x6e,0x67,0x3d,0x15,0x73,0x6f,0x6c,0x61,0x74,0x65,0x4b,0x30, +0x1e,0x65,0x67,0x6d,0x65,0x6e,0x74,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72, +0x31,0x6e,0xa2,0x41,0x6f,0xa2,0x53,0x70,2,0x61,0x66,0x64,0x86,0x6f,0x1b,0x70, +0x64,0x69,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x61,0x6c,1,0x66,0x32,0x69,0x15, +0x73,0x6f,0x6c,0x61,0x74,0x65,0x4d,0x14,0x6f,0x72,0x6d,0x61,0x74,0x41,0x1f,0x72, +0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x2f, +1,0x66,0x41,0x69,0x4d,1,0x6f,0x28,0x73,0x10,0x6d,0x43,0x1b,0x6e,0x73,0x70, +0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x43,1,0x6e,0x35,0x74,0x19,0x68, +0x65,0x72,0x6e,0x65,0x75,0x74,0x72,0x61,0x6c,0x35,0x65,0x88,0x65,0x98,0x66,0xa2, +0x6a,0x6c,0x20,1,0x65,0x30,0x72,2,0x65,0x37,0x69,0x49,0x6f,0x39,0x18,0x66, +0x74,0x74,0x6f,0x72,0x69,0x67,0x68,0x74,0x20,2,0x65,0x38,0x69,0x48,0x6f,0x16, +0x76,0x65,0x72,0x72,0x69,0x64,0x65,0x39,0x17,0x6d,0x62,0x65,0x64,0x64,0x69,0x6e, +0x67,0x37,0x15,0x73,0x6f,0x6c,0x61,0x74,0x65,0x49,3,0x6e,0x25,0x73,0x27,0x74, +0x29,0x75,0x15,0x72,0x6f,0x70,0x65,0x61,0x6e,2,0x6e,0x3c,0x73,0x46,0x74,0x18, +0x65,0x72,0x6d,0x69,0x6e,0x61,0x74,0x6f,0x72,0x29,0x14,0x75,0x6d,0x62,0x65,0x72, +0x25,0x17,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x27,1,0x69,0x28,0x73,0x10, +0x69,0x47,0x1f,0x72,0x73,0x74,0x73,0x74,0x72,0x6f,0x6e,0x67,0x69,0x73,0x6f,0x6c, +0x61,0x74,0x65,0x47,0x61,0x4e,0x62,0x84,0x63,1,0x6f,0x24,0x73,0x2d,0x1c,0x6d, +0x6d,0x6f,0x6e,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x2d,2,0x6c,0x3b, +0x6e,0x2b,0x72,0x13,0x61,0x62,0x69,0x63,1,0x6c,0x30,0x6e,0x14,0x75,0x6d,0x62, +0x65,0x72,0x2b,0x14,0x65,0x74,0x74,0x65,0x72,0x3b,0x2e,1,0x6e,0x45,0x6f,0x1c, +0x75,0x6e,0x64,0x61,0x72,0x79,0x6e,0x65,0x75,0x74,0x72,0x61,0x6c,0x45,0,0x16, +0x6d,0xc7,0xfe,0x74,0xc1,0xb8,0x77,0x57,0x77,0x48,0x79,0x5c,0x7a,0x1d,0x61,0x6e, +0x61,0x62,0x61,0x7a,0x61,0x72,0x73,0x71,0x75,0x61,0x72,0x65,0xa5,0x18,0x18,0x61, +0x72,0x61,0x6e,0x67,0x63,0x69,0x74,0x69,0xa3,0xfc,0x10,0x69,2,0x6a,0x3c,0x72, +0x68,0x73,0x17,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x73,0xa3,0x48,0x12,0x69,0x6e, +0x67,0xa2,0x74,0x1e,0x68,0x65,0x78,0x61,0x67,0x72,0x61,0x6d,0x73,0x79,0x6d,0x62, +0x6f,0x6c,0x73,0xa3,0x74,0x16,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0xa3,0x49,0x74, +0xa2,0x59,0x75,0xa4,0x12,0x76,2,0x61,0x36,0x65,0x7a,0x73,0xa2,0x6c,0x12,0x73, +0x75,0x70,0xa3,0x7d,1,0x69,0xa3,0x9f,0x72,0x1e,0x69,0x61,0x74,0x69,0x6f,0x6e, +0x73,0x65,0x6c,0x65,0x63,0x74,0x6f,0x72,0x73,0xa2,0x6c,0x19,0x73,0x75,0x70,0x70, +0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x7d,1,0x64,0x3c,0x72,0x19,0x74,0x69,0x63, +0x61,0x6c,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x91,0x14,0x69,0x63,0x65,0x78,0x74,0xa2, +0xaf,0x16,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa3,0xaf,4,0x61,0x68,0x65,0xa2, +0x8a,0x68,0xa2,0x8d,0x69,0xa2,0x95,0x72,0x1c,0x61,0x6e,0x73,0x70,0x6f,0x72,0x74, +0x61,0x6e,0x64,0x6d,0x61,0x70,0xa2,0xcf,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73, +0xa3,0xcf,4,0x67,0x58,0x69,0x7e,0x6b,0xa2,0x58,0x6d,0xa2,0x5a,0x6e,0x12,0x67, +0x75,0x74,0xa4,0x10,0x19,0x63,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0xa5, +0x11,2,0x61,0x2a,0x62,0x32,0x73,0xa3,0x60,0x12,0x6c,0x6f,0x67,0xa3,0x62,0x13, +0x61,0x6e,0x77,0x61,0xa3,0x65,3,0x6c,0x52,0x74,0x56,0x76,0x5e,0x78,0x16,0x75, +0x61,0x6e,0x6a,0x69,0x6e,0x67,0xa2,0x7c,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73, +0xa3,0x7c,0x10,0x65,0xa3,0x70,0x12,0x68,0x61,0x6d,0xa3,0xae,0x12,0x69,0x65,0x74, +0xa3,0xb7,0x11,0x72,0x69,0xa3,0xdc,0x11,0x69,0x6c,0x49,0x13,0x6c,0x75,0x67,0x75, +0x4b,0x10,0x61,1,0x61,0x24,0x69,0x53,0x11,0x6e,0x61,0x3d,2,0x62,0x34,0x66, +0x3c,0x72,0x13,0x68,0x75,0x74,0x61,0xa3,0xfb,0x13,0x65,0x74,0x61,0x6e,0x57,0x14, +0x69,0x6e,0x61,0x67,0x68,0xa3,0x90,2,0x63,0x82,0x67,0x92,0x6e,0x1f,0x69,0x66, +0x69,0x65,0x64,0x63,0x61,0x6e,0x61,0x64,0x69,0x61,0x6e,0x61,0x62,0x6f,0x1f,0x72, +0x69,0x67,0x69,0x6e,0x61,0x6c,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69,0x63,0x73,0x62, +0x17,0x65,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,0xa3,0xad,0x11,0x61,0x73,0x62,0x12, +0x65,0x78,0x74,0xa3,0xad,0x15,0x61,0x72,0x69,0x74,0x69,0x63,0xa3,0x78,0x70,0xc2, +0xf5,0x70,0xa6,0xb,0x72,0xa6,0xc7,0x73,7,0x6f,0xc1,0x7f,0x6f,0x76,0x70,0xa2, +0x47,0x75,0xa2,0x66,0x79,1,0x6c,0x4c,0x72,0x12,0x69,0x61,0x63,0x3a,0x12,0x73, +0x75,0x70,0xa4,0x17,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0x17,0x17,0x6f, +0x74,0x69,0x6e,0x61,0x67,0x72,0x69,0xa3,0x8f,2,0x67,0x34,0x72,0x3e,0x79,0x13, +0x6f,0x6d,0x62,0x6f,0xa5,0x16,0x13,0x64,0x69,0x61,0x6e,0xa5,0x23,0x17,0x61,0x73, +0x6f,0x6d,0x70,0x65,0x6e,0x67,0xa3,0xda,1,0x61,0x32,0x65,0x14,0x63,0x69,0x61, +0x6c,0x73,0xa3,0x56,0x12,0x63,0x69,0x6e,0x1f,0x67,0x6d,0x6f,0x64,0x69,0x66,0x69, +0x65,0x72,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x2d,2,0x6e,0x48,0x70,0x76,0x74, +0x1d,0x74,0x6f,0x6e,0x73,0x69,0x67,0x6e,0x77,0x72,0x69,0x74,0x69,0x6e,0x67,0xa5, +6,0x15,0x64,0x61,0x6e,0x65,0x73,0x65,0xa2,0x9b,0x12,0x73,0x75,0x70,0xa2,0xdb, +0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xdb,4,0x61,0xa2,0xa8,0x65,0x5c, +0x6d,0x9e,0x70,0xa2,0x4b,0x73,0x13,0x79,0x6d,0x62,0x6f,0x1f,0x6c,0x73,0x61,0x6e, +0x64,0x70,0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa5,5,0x10,0x72, +1,0x61,0x4e,0x73,0x12,0x63,0x72,0x69,0x1f,0x70,0x74,0x73,0x61,0x6e,0x64,0x73, +0x75,0x62,0x73,0x63,0x72,0x69,0x70,0x74,0x73,0x73,0x14,0x6e,0x64,0x73,0x75,0x62, +0x73,0x1b,0x61,0x74,0x68,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73,0xa3,0x6a, +1,0x6c,0x40,0x75,1,0x61,0x6e,0x6e,0x17,0x63,0x74,0x75,0x61,0x74,0x69,0x6f, +0x6e,0xa3,0x8e,0x15,0x65,0x6d,0x65,0x6e,0x74,0x61,1,0x6c,0x50,0x72,0x1e,0x79, +0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0x61,0x72,0x65,0x61,1,0x61, +0xa3,0x6d,0x62,0xa3,0x6e,3,0x61,0x5c,0x6d,0x78,0x70,0xa2,0x41,0x73,0x13,0x79, +0x6d,0x62,0x6f,0x1f,0x6c,0x73,0x61,0x6e,0x64,0x70,0x69,0x63,0x74,0x6f,0x67,0x72, +0x61,0x70,0x68,0x73,0xa5,5,0x14,0x72,0x72,0x6f,0x77,0x73,2,0x61,0xa3,0x67, +0x62,0xa3,0x68,0x63,0xa3,0xfa,0x13,0x61,0x74,0x68,0x65,0x1f,0x6d,0x61,0x74,0x69, +0x63,0x61,0x6c,0x6f,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73,0xa3,0x6a,0x19,0x75, +0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x8e,0x61,0x5a,0x68,0x84,0x69, +0xa2,0x5b,0x6d,0x16,0x61,0x6c,0x6c,0x66,0x6f,0x72,0x6d,1,0x73,0xa3,0x54,0x76, +0x16,0x61,0x72,0x69,0x61,0x6e,0x74,0x73,0xa3,0x54,1,0x6d,0x36,0x75,0x16,0x72, +0x61,0x73,0x68,0x74,0x72,0x61,0xa3,0xa1,0x15,0x61,0x72,0x69,0x74,0x61,0x6e,0xa3, +0xac,1,0x61,0x52,0x6f,0x13,0x72,0x74,0x68,0x61,0x1f,0x6e,0x64,0x66,0x6f,0x72, +0x6d,0x61,0x74,0x63,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x73,0xa3,0xf7,1,0x72,0x2e, +0x76,0x12,0x69,0x61,0x6e,0xa3,0x79,0x12,0x61,0x64,0x61,0xa3,0xd9,1,0x64,0x50, +0x6e,0x13,0x68,0x61,0x6c,0x61,0x50,0x1d,0x61,0x72,0x63,0x68,0x61,0x69,0x63,0x6e, +0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0xf9,0x13,0x64,0x68,0x61,0x6d,0xa3,0xf8,5, +0x72,0x35,0x72,0x44,0x73,0x64,0x75,1,0x61,0xa3,0x4e,0x6e,0x17,0x63,0x74,0x75, +0x61,0x74,0x69,0x6f,0x6e,0x71,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0xa2, +0x4e,0x13,0x61,0x72,0x65,0x61,0xa3,0x4e,0x1b,0x61,0x6c,0x74,0x65,0x72,0x70,0x61, +0x68,0x6c,0x61,0x76,0x69,0xa3,0xf6,0x61,0x40,0x68,0x82,0x6c,0x19,0x61,0x79,0x69, +0x6e,0x67,0x63,0x61,0x72,0x64,0x73,0xa3,0xcc,2,0x68,0x38,0x6c,0x4a,0x75,0x15, +0x63,0x69,0x6e,0x68,0x61,0x75,0xa3,0xf5,0x17,0x61,0x77,0x68,0x68,0x6d,0x6f,0x6e, +0x67,0xa3,0xf3,0x15,0x6d,0x79,0x72,0x65,0x6e,0x65,0xa3,0xf4,1,0x61,0x8e,0x6f, +1,0x65,0x74,0x6e,0x16,0x65,0x74,0x69,0x63,0x65,0x78,0x74,0xa2,0x72,1,0x65, +0x2c,0x73,0x11,0x75,0x70,0xa3,0x8d,0x15,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa2,0x72, +0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x8d,0x15,0x6e,0x69, +0x63,0x69,0x61,0x6e,0xa3,0x97,1,0x67,0x3e,0x69,0x13,0x73,0x74,0x6f,0x73,0xa2, +0xa6,0x13,0x64,0x69,0x73,0x63,0xa3,0xa6,0x12,0x73,0x70,0x61,0xa3,0x96,1,0x65, +0x5c,0x75,1,0x6d,0x2a,0x6e,0x11,0x69,0x63,0x67,0x10,0x69,0xa2,0xc0,0x1d,0x6e, +0x75,0x6d,0x65,0x72,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xc0,0x13, +0x6a,0x61,0x6e,0x67,0xa3,0xa3,0x6d,0xa2,0xce,0x6e,0xa8,1,0x6f,5,0x70,0x4b, +0x70,0x46,0x72,0x7a,0x73,1,0x61,0x30,0x6d,0x13,0x61,0x6e,0x79,0x61,0xa3,0x7a, +0x11,0x67,0x65,0xa5,0xf,0x18,0x74,0x69,0x63,0x61,0x6c,0x63,0x68,0x61,0x72,0x1f, +0x61,0x63,0x74,0x65,0x72,0x72,0x65,0x63,0x6f,0x67,0x6e,0x69,0x74,0x69,0x6f,0x6e, +0x85,1,0x69,0x46,0x6e,0x1e,0x61,0x6d,0x65,0x6e,0x74,0x61,0x6c,0x64,0x69,0x6e, +0x67,0x62,0x61,0x74,0x73,0xa3,0xf2,0x11,0x79,0x61,0x47,0x63,0xa2,0x71,0x67,0xa2, +0x71,0x6c,1,0x63,0xa2,0x62,0x64,5,0x70,0x38,0x70,0x36,0x73,0x56,0x74,0x14, +0x75,0x72,0x6b,0x69,0x63,0xa3,0xbf,0x11,0x65,0x72,1,0x6d,0x2e,0x73,0x12,0x69, +0x61,0x6e,0xa3,0x8c,0x11,0x69,0x63,0xa3,0xf1,0x10,0x6f,1,0x67,0x3a,0x75,0x18, +0x74,0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e,0xa3,0xbb,0x13,0x64,0x69,0x61,0x6e, +0xa5,0x22,0x68,0x42,0x69,0x54,0x6e,0x1a,0x6f,0x72,0x74,0x68,0x61,0x72,0x61,0x62, +0x69,0x61,0x6e,0xa3,0xf0,0x17,0x75,0x6e,0x67,0x61,0x72,0x69,0x61,0x6e,0xa5,4, +0x14,0x74,0x61,0x6c,0x69,0x63,0xa3,0x58,0x13,0x68,0x69,0x6b,0x69,0xa3,0x9d,0x10, +0x72,0x85,0x12,0x68,0x61,0x6d,0x65,6,0x6f,0x86,0x6f,0x6c,0x72,0xa2,0x61,0x75, +0xa2,0x62,0x79,0x14,0x61,0x6e,0x6d,0x61,0x72,0x58,0x12,0x65,0x78,0x74,2,0x61, +0xa3,0xb6,0x62,0xa3,0xee,0x65,0x13,0x6e,0x64,0x65,0x64,1,0x61,0xa3,0xb6,0x62, +0xa3,0xee,1,0x64,0x52,0x6e,0x15,0x67,0x6f,0x6c,0x69,0x61,0x6e,0x6a,0x12,0x73, +0x75,0x70,0xa4,0xd,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0xd,0x10,0x69, +0xa2,0xec,0x13,0x66,0x69,0x65,0x72,1,0x6c,0x3c,0x74,0x19,0x6f,0x6e,0x65,0x6c, +0x65,0x74,0x74,0x65,0x72,0x73,0xa3,0x8a,0x15,0x65,0x74,0x74,0x65,0x72,0x73,0x2d, +0x10,0x6f,0xa3,0xed,1,0x6c,0x44,0x73,0x11,0x69,0x63,0xa2,0x5c,0x18,0x61,0x6c, +0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5c,0x13,0x74,0x61,0x6e,0x69,0xa5,3, +0x61,0xa2,0x9b,0x65,0xa4,0x4c,0x69,1,0x61,0xa2,0x8f,0x73,0x10,0x63,5,0x70, +0x18,0x70,0xa2,0x71,0x73,0x36,0x74,0x17,0x65,0x63,0x68,0x6e,0x69,0x63,0x61,0x6c, +0x81,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x8f,0x61,0xa2,0x66,0x65,0x46,0x6d,0x19, +0x61,0x74,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,1,0x61,0xa3,0x66,0x62,0xa3, +0x69,0x17,0x6c,0x6c,0x61,0x6e,0x65,0x6f,0x75,0x73,2,0x6d,0x3a,0x73,0x6c,0x74, +0x17,0x65,0x63,0x68,0x6e,0x69,0x63,0x61,0x6c,0x81,0x11,0x61,0x74,0x1f,0x68,0x65, +0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,1,0x61, +0xa3,0x66,0x62,0xa3,0x69,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x8e,0x12,0x61,0x6e, +0x64,1,0x61,0x3c,0x70,0x19,0x69,0x63,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x73, +0xa3,0xcd,0x14,0x72,0x72,0x6f,0x77,0x73,0xa3,0x73,0x10,0x6f,0xa3,0xd8,7,0x72, +0x6f,0x72,0x44,0x73,0x4e,0x74,0x62,0x79,0x19,0x61,0x6e,0x6e,0x75,0x6d,0x65,0x72, +0x61,0x6c,0x73,0xa5,0x20,0x13,0x63,0x68,0x65,0x6e,0xa5,0xc,0x18,0x61,0x72,0x61, +0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa5,0x14,0x10,0x68,2,0x61,0x3a,0x65,0x4a,0x6f, +0x17,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73,0x7f,0x16,0x6c,0x70,0x68,0x61,0x6e, +0x75,0x6d,0xa3,0x5d,0x16,0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,1,0x61,0x36,0x6f, +0x17,0x70,0x65,0x72,0x61,0x74,0x6f,0x72,0x73,0x7f,0x11,0x6c,0x70,0x1f,0x68,0x61, +0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5d, +0x68,0x50,0x6b,0x7e,0x6c,0x88,0x6e,1,0x64,0x34,0x69,0x15,0x63,0x68,0x61,0x65, +0x61,0x6e,0xa3,0xea,0x12,0x61,0x69,0x63,0xa3,0xc6,1,0x61,0x3e,0x6a,0x12,0x6f, +0x6e,0x67,0xa2,0xaa,0x14,0x74,0x69,0x6c,0x65,0x73,0xa3,0xaa,0x13,0x6a,0x61,0x6e, +0x69,0xa3,0xe9,0x13,0x61,0x73,0x61,0x72,0xa5,0x1f,0x15,0x61,0x79,0x61,0x6c,0x61, +0x6d,0x4f,3,0x64,0x6c,0x65,0x7e,0x6e,0xa2,0x47,0x72,0x14,0x6f,0x69,0x74,0x69, 0x63,1,0x63,0x3c,0x68,0x19,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73, -0xa3,0x56,0x15,0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0x8d,0x17,0x74,0x65,0x69,0x6d, -0x61,0x79,0x65,0x6b,0xa3,0x73,0x10,0x64,0xa2,0x8c,0x17,0x65,0x6b,0x69,0x6b,0x61, -0x6b,0x75,0x69,0xa3,0x8c,0x11,0x61,0x6f,0xa3,0x5c,5,0x6f,0x14,0x6f,0x30,0x70, -0x36,0x74,0x11,0x68,0x69,0xa3,0x78,0x11,0x72,0x65,0xa3,0x77,0x11,0x65,0x6c,0xa3, -0x8a,0x61,0x2e,0x68,0x98,0x6e,0x11,0x64,0x61,0x4b,4,0x69,0x3c,0x6c,0x44,0x6e, -0x48,0x74,0x56,0x79,0x13,0x61,0x68,0x6c,0x69,0xa3,0x4f,0x12,0x74,0x68,0x69,0xa3, -0x78,0x10,0x69,0xa3,0x4f,1,0x61,0x4d,0x6e,0x12,0x61,0x64,0x61,0x4b,0x14,0x61, -0x6b,0x61,0x6e,0x61,0x4c,0x19,0x6f,0x72,0x68,0x69,0x72,0x61,0x67,0x61,0x6e,0x61, -0x8d,3,0x61,0x3c,0x6d,0x4e,0x6f,0x5a,0x75,0x15,0x64,0x61,0x77,0x61,0x64,0x69, -0xa3,0x91,0x10,0x72,0x92,0x15,0x6f,0x73,0x68,0x74,0x68,0x69,0x93,1,0x65,0x24, -0x72,0x4f,0x10,0x72,0x4f,0x10,0x6a,0xa2,0x9d,0x11,0x6b,0x69,0xa3,0x9d,4,0x61, -0x5c,0x65,0x90,0x69,0xa0,0x6f,0xa2,0x5d,0x79,1,0x63,0x34,0x64,0x10,0x69,0xa2, -0x6c,0x11,0x61,0x6e,0xa3,0x6c,0x10,0x69,0xa2,0x6b,0x11,0x61,0x6e,0xa3,0x6b,2, -0x6e,0x42,0x6f,0x46,0x74,3,0x66,0xa3,0x50,0x67,0xa3,0x51,0x69,0x24,0x6e,0x53, -0x10,0x6e,0x53,0x10,0x61,0xa3,0x6a,0x50,0x10,0x6f,0x51,0x11,0x70,0x63,0xa2,0x52, -0x11,0x68,0x61,0xa3,0x52,2,0x6d,0x2e,0x6e,0x36,0x73,0x10,0x75,0xa3,0x83,0x10, -0x62,0x80,0x10,0x75,0x81,2,0x61,0xa3,0x53,0x62,0x83,0x65,0x11,0x61,0x72,1, -0x61,0xa3,0x53,0x62,0x83,0x11,0x6d,0x61,0xa3,0x8b,0x68,0x6e,0x69,0xa2,0x83,0x6a, -2,0x61,0x30,0x70,0x52,0x75,0x11,0x72,0x63,0xa3,0x94,1,0x6d,0x38,0x76,0x10, -0x61,0xa2,0x4e,0x13,0x6e,0x65,0x73,0x65,0xa3,0x4e,0x10,0x6f,0xa3,0xad,0x11,0x61, -0x6e,0xa3,0x69,6,0x6c,0x1a,0x6c,0x34,0x6d,0x3a,0x72,0x40,0x75,0x11,0x6e,0x67, -0xa3,0x4c,0x11,0x75,0x77,0xa3,0x9c,0x11,0x6e,0x67,0xa3,0x4b,0x11,0x6b,0x74,0x8d, -0x61,0x3a,0x65,0x8c,0x69,0x11,0x72,0x61,0x48,0x13,0x67,0x61,0x6e,0x61,0x49,1, -0x6e,0x34,0x74,0x10,0x72,0xa2,0xa2,0x11,0x61,0x6e,0xa3,0xa2,0x42,6,0x6f,0xe, -0x6f,0x77,0x73,0xa3,0x49,0x74,0xa3,0x4a,0x75,0x12,0x6e,0x6f,0x6f,0x77,0x62,0xa3, -0xac,0x67,0x24,0x69,0x43,0x44,0x11,0x75,0x6c,0x45,0x11,0x62,0x72,0x46,0x11,0x65, -0x77,0x47,2,0x6d,0x2e,0x6e,0x4a,0x74,0x11,0x61,0x6c,0x5d,0x1c,0x70,0x65,0x72, -0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3,0x74,2,0x64,0x66,0x68, -0x6a,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x70,0x61,1, -0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0x7d,0x13,0x6c,0x61,0x76,0x69, -0xa3,0x7a,0x10,0x73,0xa3,0x4d,0x15,0x65,0x72,0x69,0x74,0x65,0x64,0x23,0x64,0xc0, -0xcf,0x64,0xa2,0x68,0x65,0xa2,0x90,0x67,4,0x65,0x64,0x6c,0x7c,0x6f,0x90,0x72, -0xa2,0x44,0x75,1,0x6a,0x38,0x72,1,0x6d,0x24,0x75,0x41,0x13,0x75,0x6b,0x68, -0x69,0x41,1,0x61,0x24,0x72,0x3f,0x13,0x72,0x61,0x74,0x69,0x3f,0x10,0x6f,1, -0x6b,0xa3,0x48,0x72,0x38,0x13,0x67,0x69,0x61,0x6e,0x39,0x11,0x61,0x67,0x90,0x15, -0x6f,0x6c,0x69,0x74,0x69,0x63,0x91,1,0x6e,0x30,0x74,0x10,0x68,0x3a,0x11,0x69, -0x63,0x3b,0x10,0x6d,0xa3,0xaf,1,0x61,0x32,0x65,1,0x65,0x24,0x6b,0x3d,0x10, -0x6b,0x3d,0x10,0x6e,0xa2,0x89,0x12,0x74,0x68,0x61,0xa3,0x89,2,0x65,0x3e,0x73, -0x64,0x75,0x11,0x70,0x6c,0xa2,0x87,0x13,0x6f,0x79,0x61,0x6e,0xa3,0x87,1,0x73, -0x38,0x76,0x10,0x61,0x34,0x15,0x6e,0x61,0x67,0x61,0x72,0x69,0x35,0x13,0x65,0x72, -0x65,0x74,0x33,0x11,0x72,0x74,0x33,2,0x67,0x3a,0x6c,0x72,0x74,0x11,0x68,0x69, -0x36,0x13,0x6f,0x70,0x69,0x63,0x37,0x10,0x79,2,0x64,0xa3,0x45,0x68,0xa3,0x46, -0x70,0xa2,0x47,0x1e,0x74,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79, -0x70,0x68,0x73,0xa3,0x47,0x11,0x62,0x61,0xa2,0x88,0x12,0x73,0x61,0x6e,0xa3,0x88, -0x61,0xa2,0xa2,0x62,0xa4,7,0x63,6,0x6f,0x3d,0x6f,0x5a,0x70,0x76,0x75,0x7a, -0x79,1,0x70,0x3e,0x72,2,0x69,0x2a,0x6c,0x31,0x73,0xa3,0x44,0x13,0x6c,0x6c, -0x69,0x63,0x31,0x13,0x72,0x69,0x6f,0x74,0x7f,1,0x6d,0x30,0x70,0x10,0x74,0x2e, -0x11,0x69,0x63,0x2f,0x12,0x6d,0x6f,0x6e,0x21,0x11,0x72,0x74,0x7f,0x16,0x6e,0x65, -0x69,0x66,0x6f,0x72,0x6d,0xa3,0x65,0x61,0x32,0x68,0xa2,0x41,0x69,0x11,0x72,0x74, -0xa3,0x43,3,0x6b,0x4c,0x6e,0x50,0x72,0x76,0x75,0x1d,0x63,0x61,0x73,0x69,0x61, -0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e,0xa3,0x9f,0x10,0x6d,0xa3,0x76,1, -0x61,0x24,0x73,0x71,0x1d,0x64,0x69,0x61,0x6e,0x61,0x62,0x6f,0x72,0x69,0x67,0x69, -0x6e,0x61,0x6c,0x71,0x10,0x69,0xa2,0x68,0x11,0x61,0x6e,0xa3,0x68,1,0x61,0x34, -0x65,0x10,0x72,0x2c,0x13,0x6f,0x6b,0x65,0x65,0x2d,1,0x6b,0x26,0x6d,0xa3,0x42, -0x11,0x6d,0x61,0xa3,0x76,6,0x68,0x4a,0x68,0x48,0x6e,0x4e,0x72,0x76,0x76,1, -0x65,0x2a,0x73,0x10,0x74,0xa3,0x75,0x13,0x73,0x74,0x61,0x6e,0xa3,0x75,0x11,0x6f, -0x6d,0xa3,0xa1,0x11,0x61,0x74,0x1f,0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72, -0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0x9c,1,0x61,0x3e,0x6d,2,0x65,0x2a, -0x69,0xa3,0x74,0x6e,0x27,0x13,0x6e,0x69,0x61,0x6e,0x27,0x10,0x62,0x24,0x11,0x69, -0x63,0x25,0x64,0x30,0x66,0x44,0x67,0x11,0x68,0x62,0xa3,0x9f,0x10,0x6c,1,0x61, -0x26,0x6d,0xa3,0xa7,0x10,0x6d,0xa3,0xa7,0x11,0x61,0x6b,0xa3,0x93,6,0x6c,0x3c, -0x6c,0x52,0x6f,0x56,0x72,0x66,0x75,1,0x67,0x30,0x68,1,0x64,0x79,0x69,0x10, -0x64,0x79,0x10,0x69,0x8e,0x13,0x6e,0x65,0x73,0x65,0x8f,0x11,0x69,0x73,0xa1,0x11, -0x70,0x6f,0x2a,0x13,0x6d,0x6f,0x66,0x6f,0x2b,0x10,0x61,1,0x68,0x2e,0x69,0x7c, -0x12,0x6c,0x6c,0x65,0x7d,0xa2,0x41,0x11,0x6d,0x69,0xa3,0x41,0x61,0x48,0x65,0x9c, -0x68,1,0x61,0x2a,0x6b,0x10,0x73,0xa3,0xa8,0x15,0x69,0x6b,0x73,0x75,0x6b,0x69, -0xa3,0xa8,3,0x6c,0x3a,0x6d,0x48,0x73,0x54,0x74,1,0x61,0x24,0x6b,0x9f,0x10, -0x6b,0x9f,0x10,0x69,0x9c,0x13,0x6e,0x65,0x73,0x65,0x9d,0x10,0x75,0xa2,0x82,0x10, -0x6d,0xa3,0x82,0x10,0x73,0xa2,0x86,0x13,0x61,0x76,0x61,0x68,0xa3,0x86,0x11,0x6e, -0x67,0x28,0x12,0x61,0x6c,0x69,0x29,3,0x6c,0x42,0x6e,0x90,0x74,0xa2,0x46,0x76, -0x24,0x17,0x6f,0x77,0x65,0x6c,0x6a,0x61,0x6d,0x6f,0x25,0x22,1,0x65,0x54,0x76, -0x28,1,0x73,0x38,0x74,0x2a,0x17,0x73,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x2b, -0x16,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x29,0x18,0x61,0x64,0x69,0x6e,0x67,0x6a, -0x61,0x6d,0x6f,0x23,1,0x61,0x21,0x6f,0x1a,0x74,0x61,0x70,0x70,0x6c,0x69,0x63, -0x61,0x62,0x6c,0x65,0x21,0x26,0x1a,0x72,0x61,0x69,0x6c,0x69,0x6e,0x67,0x6a,0x61, -0x6d,0x6f,0x27,1,0x6e,0x2c,0x79,0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,0x21, -1,0x6e,0x2c,0x79,0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,0x21,2,0x6d,0x30, -0x6e,0x3a,0x79,0x22,0x11,0x65,0x73,0x23,0x24,0x13,0x61,0x79,0x62,0x65,0x25,0x20, -0x10,0x6f,0x21,2,0x6d,0x30,0x6e,0x3a,0x79,0x22,0x11,0x65,0x73,0x23,0x24,0x13, -0x61,0x79,0x62,0x65,0x25,0x20,0x10,0x6f,0x21,0xb,0x72,0x39,0x76,0xc,0x76,0x33, -0x78,0x2a,0x7a,0x11,0x77,0x6a,0x43,0x10,0x78,0x21,0x72,0x28,0x73,0x50,0x74,0x31, -1,0x65,0x24,0x69,0x39,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69, -0x63,0x61,0x74,0x6f,0x72,0x39,1,0x6d,0x35,0x70,0x18,0x61,0x63,0x69,0x6e,0x67, -0x6d,0x61,0x72,0x6b,0x35,0x6c,0x1f,0x6c,0x3c,0x6f,0x4a,0x70,1,0x70,0x37,0x72, -0x14,0x65,0x70,0x65,0x6e,0x64,0x37,0x28,1,0x66,0x2b,0x76,0x2c,0x10,0x74,0x2f, -0x13,0x74,0x68,0x65,0x72,0x21,0x63,0x4c,0x65,0x64,0x67,1,0x61,0x3a,0x6c,0x19, -0x75,0x65,0x61,0x66,0x74,0x65,0x72,0x7a,0x77,0x6a,0x41,0x10,0x7a,0x41,2,0x6e, -0x23,0x6f,0x24,0x72,0x25,0x14,0x6e,0x74,0x72,0x6f,0x6c,0x23,2,0x62,0x34,0x6d, -0x4e,0x78,0x26,0x13,0x74,0x65,0x6e,0x64,0x27,0x3a,1,0x61,0x24,0x67,0x3d,0x11, -0x73,0x65,0x3a,0x12,0x67,0x61,0x7a,0x3d,0x3e,0x16,0x6f,0x64,0x69,0x66,0x69,0x65, -0x72,0x3f,9,0x6e,0x4a,0x6e,0x34,0x6f,0x44,0x73,0x60,0x75,0x94,0x78,0x10,0x78, -0x21,0x10,0x75,0x2a,0x14,0x6d,0x65,0x72,0x69,0x63,0x2b,1,0x6c,0x2c,0x74,0x12, -0x68,0x65,0x72,0x21,0x14,0x65,0x74,0x74,0x65,0x72,0x2d,3,0x63,0x36,0x65,0x46, -0x70,0x31,0x74,0x32,0x12,0x65,0x72,0x6d,0x33,0x3c,0x16,0x6f,0x6e,0x74,0x69,0x6e, -0x75,0x65,0x3d,0x2e,0x10,0x70,0x2f,0x10,0x70,0x34,0x12,0x70,0x65,0x72,0x35,0x61, -0x46,0x63,0x52,0x65,0x64,0x66,0x72,0x6c,2,0x65,0x2d,0x66,0x3b,0x6f,0x28,0x12, -0x77,0x65,0x72,0x29,0x10,0x74,0x22,0x12,0x65,0x72,0x6d,0x23,1,0x6c,0x24,0x72, -0x37,0x24,0x12,0x6f,0x73,0x65,0x25,0x10,0x78,0x38,0x13,0x74,0x65,0x6e,0x64,0x39, -0x10,0x6f,0x26,0x13,0x72,0x6d,0x61,0x74,0x27,0xf,0x6c,0x7c,0x72,0x34,0x72,0x32, -0x73,0x5a,0x78,0x76,0x7a,0x11,0x77,0x6a,0x4b,1,0x65,0x24,0x69,0x3b,0x1e,0x67, -0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x3b,1, -0x69,0x24,0x71,0x3f,0x18,0x6e,0x67,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65,0x3f,0x10, -0x78,0x21,0x6c,0x36,0x6d,0x3c,0x6e,0x76,0x6f,0x13,0x74,0x68,0x65,0x72,0x21,1, -0x65,0x23,0x66,0x35,3,0x62,0x37,0x69,0x28,0x6c,0x29,0x6e,0x2b,0x10,0x64,1, -0x6c,0x34,0x6e,0x11,0x75,0x6d,0x2a,0x12,0x6c,0x65,0x74,0x37,0x14,0x65,0x74,0x74, -0x65,0x72,0x29,2,0x65,0x36,0x6c,0x39,0x75,0x2c,0x14,0x6d,0x65,0x72,0x69,0x63, -0x2d,0x14,0x77,0x6c,0x69,0x6e,0x65,0x39,0x66,0x3f,0x66,0x40,0x67,0x4e,0x68,0x70, -0x6b,0x10,0x61,0x26,0x15,0x74,0x61,0x6b,0x61,0x6e,0x61,0x27,0x10,0x6f,0x24,0x13, -0x72,0x6d,0x61,0x74,0x25,1,0x61,0x3a,0x6c,0x19,0x75,0x65,0x61,0x66,0x74,0x65, -0x72,0x7a,0x77,0x6a,0x49,0x10,0x7a,0x49,1,0x65,0x24,0x6c,0x3d,0x19,0x62,0x72, -0x65,0x77,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,0x61,0x86,0x63,0x92,0x64,0x94,0x65, -2,0x62,0x44,0x6d,0x5e,0x78,0x2e,0x13,0x74,0x65,0x6e,0x64,0x32,0x15,0x6e,0x75, -0x6d,0x6c,0x65,0x74,0x2f,0x42,1,0x61,0x24,0x67,0x45,0x11,0x73,0x65,0x42,0x12, -0x67,0x61,0x7a,0x45,0x46,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x47,0x15,0x6c, -0x65,0x74,0x74,0x65,0x72,0x23,0x10,0x72,0x31,1,0x6f,0x24,0x71,0x41,0x18,0x75, -0x62,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65,0x41,2,0x63,0x32,0x6e,0x3c,0x6f,0x22, -0x12,0x70,0x65,0x6e,0x23,0x24,0x13,0x6c,0x6f,0x73,0x65,0x25,0x20,0x12,0x6f,0x6e, -0x65,0x21,0xd,0x6e,0xc1,0x86,0x73,0xa8,0x73,0x4c,0x74,0xa2,0x76,0x75,0xa2,0x83, -0x7a,0xd8,0x70,0,2,0x6c,0xd9,0x20,0,0x70,0xd9,0x40,0,0x73,0xc3,0, -0xfe,0xf,0,0,0,7,0x6f,0x3c,0x6f,0xff,8,0,0,0,0x70,0x3a, -0x75,0x6e,0x79,0x13,0x6d,0x62,0x6f,0x6c,0xff,0xf,0,0,0,0x11,0x61,0x63, -1,0x65,0x34,0x69,0x15,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5,0,0x18,0x73,0x65, -0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xc3,0,0x16,0x72,0x72,0x6f,0x67,0x61,0x74, -0x65,0xe1,0,0,0x63,0xff,2,0,0,0,0x65,0x38,0x6b,0xff,4,0, -0,0,0x6d,0xff,1,0,0,0,0x16,0x70,0x61,0x72,0x61,0x74,0x6f,0x72, -0xd9,0x70,0,0x1d,0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74, -0x65,0x72,0x31,1,0x6e,0x40,0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c, -0x65,0x74,0x74,0x65,0x72,0x25,0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x23, -0x6e,0xa2,0x69,0x6f,0xa2,0x89,0x70,0xfe,0x30,0xf8,0,0,9,0x69,0x33,0x69, -0xff,0x10,0,0,0,0x6f,0xfd,0x80,0,0,0x72,0x54,0x73,0xf9,0,0, -0x75,0x12,0x6e,0x63,0x74,0xfe,0x30,0xf8,0,0,0x15,0x75,0x61,0x74,0x69,0x6f, -0x6e,0xff,0x30,0xf8,0,0,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0xdd, -0,0,0x61,0x48,0x63,0xfd,0x40,0,0,0x64,0xe9,0,0,0x65,0xfd,0x20, -0,0,0x66,0xff,0x20,0,0,0,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68, -0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x40,0,0xbe,0,3,0x64, -0xa7,0,0x6c,0xab,0,0x6f,0x30,0x75,0x13,0x6d,0x62,0x65,0x72,0xbf,0,0xb2, -0,0x1b,0x6e,0x73,0x70,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa1,1, -0x70,0x92,0x74,0x12,0x68,0x65,0x72,0xe6,0x80,1,3,0x6c,0x40,0x6e,0x4a,0x70, -0x56,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0xff,8,0,0,0,0x14,0x65,0x74, -0x74,0x65,0x72,0x61,0x14,0x75,0x6d,0x62,0x65,0x72,0xb3,0,0x19,0x75,0x6e,0x63, -0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd,0x80,0,0,0x1c,0x65,0x6e,0x70,0x75, -0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xf9,0,0,0x66,0xc0,0xc4,0x66, -0xa2,0x47,0x69,0xa2,0x64,0x6c,0xa2,0x79,0x6d,0xa4,0xc0,4,0x61,0x6c,0x63,0xa5, -0,0x65,0xa3,0x80,0x6e,0xa1,0x6f,0x15,0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c, -0x38,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0xff,4,0,0,0,0x14,0x65,0x74, -0x74,0x65,0x72,0x41,1,0x72,0x3c,0x74,0x16,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c, -0xff,1,0,0,0,0x10,0x6b,0xa5,0xc0,1,0x69,0x32,0x6f,0x13,0x72,0x6d, -0x61,0x74,0xdb,0,0,0x1d,0x6e,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61, -0x74,0x69,0x6f,0x6e,0xff,0x20,0,0,0,0x10,0x6e,0x1f,0x69,0x74,0x69,0x61, -0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x10,0,0, -0,0x9c,7,0x6d,0x18,0x6d,0x41,0x6f,0x28,0x74,0x31,0x75,0x25,0x60,0x1c,0x77, -0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x29,0x63,0x3d,0x65, -0x28,0x69,0x42,0x6c,0x29,0x13,0x74,0x74,0x65,0x72,0x9c,0x15,0x6e,0x75,0x6d,0x62, -0x65,0x72,0xab,0,0x1a,0x6e,0x65,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72, -0xd9,0x20,0,0x63,0x46,0x64,0xa2,0x96,0x65,0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69, -0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa3,0x80,0xe6,0x80,1,7,0x6e,0x57,0x6e,0x52, -0x6f,0x5e,0x73,0xe1,0,0,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73,0x79, -0x6d,0x62,0x6f,0x6c,0xff,2,0,0,0,0x22,0x12,0x74,0x72,0x6c,0xd9,0x80, -0,0xdc,0,0,1,0x6d,0x62,0x6e,1,0x6e,0x30,0x74,0x12,0x72,0x6f,0x6c, -0xd9,0x80,0,0x1f,0x65,0x63,0x74,0x6f,0x72,0x70,0x75,0x6e,0x63,0x74,0x75,0x61, -0x74,0x69,0x6f,0x6e,0xfd,0x40,0,0,0x19,0x62,0x69,0x6e,0x69,0x6e,0x67,0x6d, -0x61,0x72,0x6b,0xa5,0xc0,0x61,0x58,0x63,0xd9,0x80,0,0x66,0xdb,0,0,0x6c, -0x1d,0x6f,0x73,0x65,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd, -0x20,0,0,0x18,0x73,0x65,0x64,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,2,0x61, -0x32,0x65,0x50,0x69,0x12,0x67,0x69,0x74,0xa7,0,0x1c,0x73,0x68,0x70,0x75,0x6e, -0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xe9,0,0,0x1a,0x63,0x69,0x6d,0x61, -0x6c,0x6e,0x75,0x6d,0x62,0x65,0x72,0xa7,0 +0xa3,0xd7,0x15,0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0xd6,0x17,0x65,0x66,0x61,0x69, +0x64,0x72,0x69,0x6e,0xa5,0x21,0x17,0x74,0x65,0x69,0x6d,0x61,0x79,0x65,0x6b,0xa2, +0xb8,0x12,0x65,0x78,0x74,0xa2,0xd5,0x16,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa3, +0xd5,0x18,0x64,0x65,0x6b,0x69,0x6b,0x61,0x6b,0x75,0x69,0xa3,0xeb,5,0x6b,0x23, +0x6b,0x4c,0x6f,0x50,0x75,1,0x6d,0x2c,0x73,0x11,0x68,0x75,0xa5,0x15,0x17,0x62, +0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0x7b,0x10,0x6f,0xa3,0x92,0x14,0x62,0x6c,0x6f, +0x63,0x6b,0x21,0x61,0x44,0x62,0x21,0x65,0x10,0x77,1,0x61,0xa5,0xe,0x74,0x14, +0x61,0x69,0x6c,0x75,0x65,0xa3,0x8b,0x16,0x62,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3, +0xef,0x67,0xc4,0xe,0x6a,0xc1,0x95,0x6a,0xa2,0xc5,0x6b,0xa2,0xde,0x6c,4,0x61, +0x54,0x65,0xa2,0x61,0x69,0xa2,0x78,0x6f,0xa2,0xa7,0x79,1,0x63,0x2e,0x64,0x12, +0x69,0x61,0x6e,0xa3,0xa9,0x12,0x69,0x61,0x6e,0xa3,0xa7,1,0x6f,0x55,0x74,0x11, +0x69,0x6e,1,0x31,0x82,0x65,0x11,0x78,0x74,4,0x61,0x5c,0x62,0x29,0x63,0xa3, +0x94,0x64,0xa3,0x95,0x65,0xa2,0xe7,0x13,0x6e,0x64,0x65,0x64,4,0x61,0x36,0x62, +0x29,0x63,0xa3,0x94,0x64,0xa3,0x95,0x65,0xa3,0xe7,0x26,0x18,0x64,0x64,0x69,0x74, +0x69,0x6f,0x6e,0x61,0x6c,0x6d,0x24,0x12,0x73,0x75,0x70,0x24,0x16,0x70,0x6c,0x65, +0x6d,0x65,0x6e,0x74,0x25,1,0x70,0x42,0x74,0x1d,0x74,0x65,0x72,0x6c,0x69,0x6b, +0x65,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x79,0x12,0x63,0x68,0x61,0xa3,0x9c,2, +0x6d,0x2e,0x6e,0x34,0x73,0x10,0x75,0xa3,0xb0,0x11,0x62,0x75,0xa3,0x6f,0x12,0x65, +0x61,0x72,1,0x61,0xa3,0xe8,0x62,1,0x69,0x38,0x73,0x17,0x79,0x6c,0x6c,0x61, +0x62,0x61,0x72,0x79,0xa3,0x75,0x17,0x64,0x65,0x6f,0x67,0x72,0x61,0x6d,0x73,0xa3, +0x76,0x1a,0x77,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4d,0x10, +0x61,1,0x6d,0x32,0x76,0x14,0x61,0x6e,0x65,0x73,0x65,0xa3,0xb5,0x10,0x6f,0x5c, +0x12,0x65,0x78,0x74,1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,1,0x61,0x80,0x68,3, +0x61,0x3c,0x6d,0x4c,0x6f,0x64,0x75,0x15,0x64,0x61,0x77,0x61,0x64,0x69,0xa3,0xe6, +0x16,0x72,0x6f,0x73,0x68,0x74,0x68,0x69,0xa3,0x89,0x11,0x65,0x72,0x68,0x16,0x73, +0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x71,0x12,0x6a,0x6b,0x69,0xa3,0xe5,3,0x69, +0x3a,0x6e,0x42,0x74,0xa2,0x51,0x79,0x13,0x61,0x68,0x6c,0x69,0xa3,0xa2,0x12,0x74, +0x68,0x69,0xa3,0xc1,3,0x61,0x34,0x62,0x76,0x67,0x7c,0x6e,0x12,0x61,0x64,0x61, +0x4d,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0xcb,0x16,0x70,0x6c,0x65,0x6d,0x65, +0x6e,0x74,0xa3,0xcb,0x11,0x78,0x74,1,0x61,0xa5,0x13,0x65,0x14,0x6e,0x64,0x65, +0x64,0x61,0xa5,0x13,0x11,0x75,0x6e,0xa3,0x42,0x11,0x78,0x69,0x96,0x17,0x72,0x61, +0x64,0x69,0x63,0x61,0x6c,0x73,0x97,0x14,0x61,0x6b,0x61,0x6e,0x61,0x9e,1,0x65, +0x4c,0x70,0x10,0x68,0x1f,0x6f,0x6e,0x65,0x74,0x69,0x63,0x65,0x78,0x74,0x65,0x6e, +0x73,0x69,0x6f,0x6e,0x73,0xa3,0x6b,0x11,0x78,0x74,0xa3,0x6b,0x67,0xa2,0xb5,0x68, +0xa4,0x84,0x69,3,0x64,0x4c,0x6d,0xa2,0x55,0x6e,0xa2,0x62,0x70,0x13,0x61,0x65, +0x78,0x74,0x2a,0x16,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0x2b,1,0x63,0x99,0x65, +0x17,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,1,0x64,0x56,0x73,0x15,0x79,0x6d, +0x62,0x6f,0x6c,0x73,0xa4,0xb,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75, +0x61,0x74,0x69,0x6f,0x6e,0xa5,0xb,0x13,0x65,0x73,0x63,0x72,0x1f,0x69,0x70,0x74, +0x69,0x6f,0x6e,0x63,0x68,0x61,0x72,0x61,0x63,0x74,0x65,0x72,0x73,0x99,0x1c,0x70, +0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3,0xba,1,0x64, +0x62,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x70,0x61,1, +0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0xbd,0x13,0x6c,0x61,0x76,0x69, +0xa3,0xbe,0x11,0x69,0x63,1,0x6e,0x3e,0x73,0x1a,0x69,0x79,0x61,0x71,0x6e,0x75, +0x6d,0x62,0x65,0x72,0x73,0xa5,0x1e,0x19,0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72, +0x6d,0x73,0xa3,0xb2,4,0x65,0x74,0x6c,0xa2,0x82,0x6f,0xa2,0x9a,0x72,0xa2,0x9e, +0x75,2,0x6a,0x34,0x6e,0x3e,0x72,0x14,0x6d,0x75,0x6b,0x68,0x69,0x43,0x14,0x61, +0x72,0x61,0x74,0x69,0x45,0x18,0x6a,0x61,0x6c,0x61,0x67,0x6f,0x6e,0x64,0x69,0xa5, +0x1c,1,0x6e,0xa2,0x46,0x6f,1,0x6d,0x6e,0x72,0x13,0x67,0x69,0x61,0x6e,0x5a, +1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0x87,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e, +0x74,0xa3,0x87,0x11,0x78,0x74,0xa4,0x1b,0x14,0x65,0x6e,0x64,0x65,0x64,0xa5,0x1b, +0x1a,0x65,0x74,0x72,0x69,0x63,0x73,0x68,0x61,0x70,0x65,0x73,0x8c,0x12,0x65,0x78, +0x74,0xa2,0xe3,0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0xe3,0x1e,0x65,0x72,0x61,0x6c, +0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x71,0x17,0x61,0x67,0x6f, +0x6c,0x69,0x74,0x69,0x63,0xa2,0x88,0x12,0x73,0x75,0x70,0xa4,0xa,0x16,0x70,0x6c, +0x65,0x6d,0x65,0x6e,0x74,0xa5,0xa,0x13,0x74,0x68,0x69,0x63,0xa3,0x59,1,0x61, +0x5c,0x65,0x11,0x65,0x6b,0x30,1,0x61,0x38,0x65,0x11,0x78,0x74,0x6e,0x14,0x65, +0x6e,0x64,0x65,0x64,0x6f,0x17,0x6e,0x64,0x63,0x6f,0x70,0x74,0x69,0x63,0x31,0x13, +0x6e,0x74,0x68,0x61,0xa3,0xe4,2,0x61,0xa2,0x48,0x65,0xa2,0xdf,0x69,1,0x67, +0x30,0x72,0x14,0x61,0x67,0x61,0x6e,0x61,0x9d,0x10,0x68,1,0x70,0x3a,0x73,0x18, +0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4b,1,0x72,0x3c,0x75,0x19, +0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4c,0x11,0x69,0x76,0x1f, +0x61,0x74,0x65,0x75,0x73,0x65,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73, +0xa3,0x4c,2,0x6c,0x32,0x6e,0x9a,0x74,0x12,0x72,0x61,0x6e,0xa5,2,0x10,0x66, +2,0x61,0x58,0x6d,0x70,0x77,0x14,0x69,0x64,0x74,0x68,0x61,0x1f,0x6e,0x64,0x66, +0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x57,0x1a, +0x6e,0x64,0x66,0x75,0x6c,0x6c,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x57,0x13,0x61,0x72, +0x6b,0x73,0xa3,0x52,2,0x67,0x34,0x69,0xa2,0x45,0x75,0x12,0x6e,0x6f,0x6f,0xa3, +0x63,0x11,0x75,0x6c,0xa2,0x4a,2,0x63,0x3c,0x6a,0x5e,0x73,0x17,0x79,0x6c,0x6c, +0x61,0x62,0x6c,0x65,0x73,0xa3,0x4a,0x1f,0x6f,0x6d,0x70,0x61,0x74,0x69,0x62,0x69, +0x6c,0x69,0x74,0x79,0x6a,0x61,0x6d,0x6f,0xa3,0x41,0x12,0x61,0x6d,0x6f,0x5c,0x17, +0x65,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,0x19, +0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67,0x79,0x61,0xa5,0x1d,0x13,0x62,0x72,0x65, +0x77,0x37,0x61,0xa2,0xe9,0x62,0xa6,0x29,0x63,0xa6,0xfe,0x64,0xac,0x8a,0x65,5, +0x6d,0xa2,0x6d,0x86,0x6e,0x96,0x74,0x15,0x68,0x69,0x6f,0x70,0x69,0x63,0x5e,1, +0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0x86,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, +0xa3,0x86,0x11,0x78,0x74,0xa2,0x85,1,0x61,0xa3,0xc8,0x65,0x13,0x6e,0x64,0x65, +0x64,0xa2,0x85,0x10,0x61,0xa3,0xc8,0x16,0x6f,0x74,0x69,0x63,0x6f,0x6e,0x73,0xa3, +0xce,0x15,0x63,0x6c,0x6f,0x73,0x65,0x64,2,0x61,0x5a,0x63,0x9e,0x69,0x1c,0x64, +0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x73,0x75,0x70,0xa2,0xc4,0x16,0x70, +0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc4,0x16,0x6c,0x70,0x68,0x61,0x6e,0x75,0x6d, +0x86,1,0x65,0x2c,0x73,0x11,0x75,0x70,0xa3,0xc3,0x13,0x72,0x69,0x63,0x73,0x86, +0x18,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc3,0x11,0x6a,0x6b,0xa2, +0x44,0x1f,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x61,0x6e,0x64,0x6d,0x6f,0x6e,0x74, +0x68,0x73,0xa3,0x44,0x61,0x36,0x67,0x62,0x6c,0x14,0x62,0x61,0x73,0x61,0x6e,0xa3, +0xe2,0x13,0x72,0x6c,0x79,0x64,0x1f,0x79,0x6e,0x61,0x73,0x74,0x69,0x63,0x63,0x75, +0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa5,1,0x10,0x79,0x1f,0x70,0x74,0x69,0x61, +0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0xc2,7,0x6e, +0xc0,0xe5,0x6e,0x3e,0x72,0xa2,0x5d,0x73,0xa2,0xd8,0x76,0x14,0x65,0x73,0x74,0x61, +0x6e,0xa3,0xbc,1,0x61,0x92,0x63,0x13,0x69,0x65,0x6e,0x74,1,0x67,0x34,0x73, +0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xa5,0x13,0x72,0x65,0x65,0x6b,1,0x6d, +0x34,0x6e,0x15,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0x7f,0x13,0x75,0x73,0x69,0x63, +0xa2,0x7e,0x19,0x61,0x6c,0x6e,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x7e,0x10, +0x74,0x1f,0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70, +0x68,0x73,0xa3,0xfe,2,0x61,0x32,0x6d,0xa2,0x71,0x72,0x12,0x6f,0x77,0x73,0x7d, +0x12,0x62,0x69,0x63,0x38,3,0x65,0x4a,0x6d,0x66,0x70,0xa2,0x43,0x73,0x11,0x75, +0x70,0xa2,0x80,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x80,0x11,0x78,0x74, +1,0x61,0xa3,0xd2,0x65,0x14,0x6e,0x64,0x65,0x64,0x61,0xa3,0xd2,0x12,0x61,0x74, +0x68,0xa2,0xd3,0x18,0x65,0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,0x61,0x1f,0x6c,0x70, +0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd3, +1,0x66,0x42,0x72,0x1e,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66, +0x6f,0x72,0x6d,0x73,1,0x61,0xa3,0x51,0x62,0xa3,0x55,0x14,0x65,0x6e,0x69,0x61, +0x6e,0x35,0x12,0x63,0x69,0x69,0x23,0x64,0x9e,0x65,0xa2,0x42,0x68,0xa2,0x4d,0x6c, +1,0x63,0x62,0x70,0x17,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x70,1,0x66,0xa3, +0x50,0x72,0x1e,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72, +0x6d,0x73,0xa3,0x50,0x16,0x68,0x65,0x6d,0x69,0x63,0x61,0x6c,0xa2,0xd0,0x16,0x73, +0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd0,0x12,0x6c,0x61,0x6d,0xa5,7,0x1a,0x67, +0x65,0x61,0x6e,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0x77,0x11,0x6f,0x6d,0xa3, +0xfd,7,0x6f,0x71,0x6f,0x64,0x72,0xa2,0x41,0x75,0xa2,0x58,0x79,0x1b,0x7a,0x61, +0x6e,0x74,0x69,0x6e,0x65,0x6d,0x75,0x73,0x69,0x63,0xa2,0x5b,0x18,0x61,0x6c,0x73, +0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5b,1,0x70,0x34,0x78,0x16,0x64,0x72,0x61, +0x77,0x69,0x6e,0x67,0x89,0x14,0x6f,0x6d,0x6f,0x66,0x6f,0xa0,0x12,0x65,0x78,0x74, +0xa2,0x43,0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0x43,0x10,0x61,1,0x68,0x40,0x69, +0x12,0x6c,0x6c,0x65,0x92,0x17,0x70,0x61,0x74,0x74,0x65,0x72,0x6e,0x73,0x93,0x11, +0x6d,0x69,0xa3,0xc9,1,0x67,0x2c,0x68,0x11,0x69,0x64,0xa3,0x64,0x14,0x69,0x6e, +0x65,0x73,0x65,0xa3,0x81,0x61,0x48,0x65,0xa2,0x4e,0x68,0xa2,0x52,0x6c,0x1a,0x6f, +0x63,0x6b,0x65,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x73,0x8b,3,0x6c,0x34,0x6d,0x40, +0x73,0x66,0x74,0x11,0x61,0x6b,0xa3,0xc7,0x14,0x69,0x6e,0x65,0x73,0x65,0xa3,0x93, +0x11,0x75,0x6d,0xa2,0xb1,0x12,0x73,0x75,0x70,0xa2,0xca,0x16,0x70,0x6c,0x65,0x6d, +0x65,0x6e,0x74,0xa3,0xca,1,0x69,0x30,0x73,0x13,0x61,0x76,0x61,0x68,0xa3,0xdd, +0x15,0x63,0x6c,0x61,0x74,0x69,0x6e,0x23,0x14,0x6e,0x67,0x61,0x6c,0x69,0x41,0x16, +0x61,0x69,0x6b,0x73,0x75,0x6b,0x69,0xa5,8,5,0x6f,0xc1,0x4c,0x6f,0xa2,0x55, +0x75,0xa4,0x10,0x79,1,0x70,0x9c,0x72,0x14,0x69,0x6c,0x6c,0x69,0x63,0x32,1, +0x65,0x4c,0x73,0x11,0x75,0x70,0xa2,0x61,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, +0xa2,0x61,0x12,0x61,0x72,0x79,0xa3,0x61,0x11,0x78,0x74,3,0x61,0xa3,0x9e,0x62, +0xa3,0xa0,0x63,0xa5,9,0x65,0x13,0x6e,0x64,0x65,0x64,2,0x61,0xa3,0x9e,0x62, +0xa3,0xa0,0x63,0xa5,9,0x1c,0x72,0x69,0x6f,0x74,0x73,0x79,0x6c,0x6c,0x61,0x62, +0x61,0x72,0x79,0xa3,0x7b,3,0x6d,0x5a,0x6e,0xa2,0x95,0x70,0xa2,0xa0,0x75,0x17, +0x6e,0x74,0x69,0x6e,0x67,0x72,0x6f,0x64,0xa2,0x9a,0x17,0x6e,0x75,0x6d,0x65,0x72, +0x61,0x6c,0x73,0xa3,0x9a,2,0x62,0x3a,0x6d,0xa2,0x5f,0x70,0x15,0x61,0x74,0x6a, +0x61,0x6d,0x6f,0xa3,0x41,0x14,0x69,0x6e,0x69,0x6e,0x67,2,0x64,0x46,0x68,0x9e, +0x6d,0x1d,0x61,0x72,0x6b,0x73,0x66,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73, +0x77,0x1e,0x69,0x61,0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,0x6d,0x61,0x72,0x6b, +0x73,0x2e,2,0x65,0x40,0x66,0xa6,0x2a,0x73,0x18,0x75,0x70,0x70,0x6c,0x65,0x6d, +0x65,0x6e,0x74,0xa3,0x83,0x16,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,0xa3,0xe0,0x17, +0x61,0x6c,0x66,0x6d,0x61,0x72,0x6b,0x73,0xa3,0x52,0x11,0x6f,0x6e,0x1f,0x69,0x6e, +0x64,0x69,0x63,0x6e,0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0xa3,0xb2, +0x1b,0x74,0x72,0x6f,0x6c,0x70,0x69,0x63,0x74,0x75,0x72,0x65,0x73,0x83,0x12,0x74, +0x69,0x63,0xa2,0x84,0x1b,0x65,0x70,0x61,0x63,0x74,0x6e,0x75,0x6d,0x62,0x65,0x72, +0x73,0xa3,0xdf,1,0x6e,0x3e,0x72,0x1b,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d, +0x62,0x6f,0x6c,0x73,0x75,0x15,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa2,0x98,0x16,0x6e, +0x75,0x6d,0x62,0x65,0x72,0x73,0xa2,0x99,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63, +0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x99,0x61,0xa2,0xdb,0x68,0xa4,5,0x6a, +0x10,0x6b,0xa2,0x47,4,0x63,0x86,0x65,0xa2,0x7d,0x72,0xa2,0x92,0x73,0xa2,0xa4, +0x75,0x1f,0x6e,0x69,0x66,0x69,0x65,0x64,0x69,0x64,0x65,0x6f,0x67,0x72,0x61,0x70, +0x68,0x73,0xa2,0x47,0x18,0x65,0x78,0x74,0x65,0x6e,0x73,0x69,0x6f,0x6e,5,0x64, +0x65,0x64,0xa3,0xd1,0x65,0xa5,0,0x66,0xa5,0x12,0x14,0x6f,0x6d,0x70,0x61,0x74, +0xa2,0x45,1,0x66,0x96,0x69,1,0x62,0x44,0x64,0x17,0x65,0x6f,0x67,0x72,0x61, +0x70,0x68,0x73,0xa2,0x4f,0x12,0x73,0x75,0x70,0xa3,0x5f,0x14,0x69,0x6c,0x69,0x74, +0x79,0xa2,0x45,1,0x66,0x54,0x69,0x18,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68, +0x73,0xa2,0x4f,0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x5f, +0x13,0x6f,0x72,0x6d,0x73,0xa3,0x53,0x11,0x78,0x74,5,0x64,9,0x64,0xa3,0xd1, +0x65,0xa5,0,0x66,0xa5,0x12,0x61,0xa3,0x46,0x62,0xa3,0x5e,0x63,0xa3,0xc5,0x19, +0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x73,0x75,0x70,0x94,0x16,0x70,0x6c,0x65,0x6d, +0x65,0x6e,0x74,0x95,1,0x74,0x50,0x79,0x14,0x6d,0x62,0x6f,0x6c,0x73,0x9a,0x1d, +0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x9b,0x14, +0x72,0x6f,0x6b,0x65,0x73,0xa3,0x82,2,0x6e,0x48,0x72,0x64,0x75,0x1d,0x63,0x61, +0x73,0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e,0xa3,0xde,0x1d,0x61, +0x64,0x69,0x61,0x6e,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69,0x63,0x73,0x63,0x12,0x69, +0x61,0x6e,0xa3,0xa8,1,0x61,0x6c,0x65,1,0x72,0x38,0x73,0x17,0x73,0x73,0x79, +0x6d,0x62,0x6f,0x6c,0x73,0xa5,0x19,0x13,0x6f,0x6b,0x65,0x65,0x60,0x12,0x73,0x75, +0x70,0xa2,0xff,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xff,1,0x6b,0x26, +0x6d,0xa3,0xa4,0x11,0x6d,0x61,0xa3,0xd4,3,0x65,0x3e,0x69,0x7e,0x6f,0xa2,0x5d, +0x75,0x15,0x70,0x6c,0x6f,0x79,0x61,0x6e,0xa3,0xe1,1,0x73,0x50,0x76,0x16,0x61, +0x6e,0x61,0x67,0x61,0x72,0x69,0x3e,0x12,0x65,0x78,0x74,0xa2,0xb3,0x14,0x65,0x6e, +0x64,0x65,0x64,0xa3,0xb3,0x13,0x65,0x72,0x65,0x74,0xa3,0x5a,1,0x61,0x30,0x6e, +0x14,0x67,0x62,0x61,0x74,0x73,0x91,0x18,0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c, +0x73,0x2e,2,0x65,0x30,0x66,0x36,0x73,0x11,0x75,0x70,0xa3,0x83,0x11,0x78,0x74, +0xa3,0xe0,0x18,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x77,1,0x67,0x3e, +0x6d,0x12,0x69,0x6e,0x6f,0xa2,0xab,0x14,0x74,0x69,0x6c,0x65,0x73,0xa3,0xab,0x11, +0x72,0x61,0xa5,0x1a,8,0x6d,0x5f,0x6d,0x3a,0x6e,0x48,0x73,0x7a,0x76,0xa2,0x4b, +0x77,0x12,0x69,0x64,0x65,0x43,0x11,0x65,0x64,0x32,0x12,0x69,0x61,0x6c,0x33,2, +0x61,0x40,0x62,0x37,0x6f,1,0x62,0x28,0x6e,0x10,0x65,0x21,0x13,0x72,0x65,0x61, +0x6b,0x37,0x10,0x72,0x34,0x12,0x72,0x6f,0x77,0x35,2,0x6d,0x38,0x71,0x46,0x75, +1,0x62,0x3d,0x70,0x3e,0x11,0x65,0x72,0x3f,1,0x61,0x24,0x6c,0x39,0x11,0x6c, +0x6c,0x39,1,0x72,0x3b,0x75,0x12,0x61,0x72,0x65,0x3b,0x12,0x65,0x72,0x74,0x40, +0x13,0x69,0x63,0x61,0x6c,0x41,0x63,0x58,0x65,0x92,0x66,0x96,0x69,1,0x6e,0x36, +0x73,0x10,0x6f,0x30,0x14,0x6c,0x61,0x74,0x65,0x64,0x31,0x11,0x69,0x74,0x2e,0x12, +0x69,0x61,0x6c,0x2f,2,0x61,0x36,0x69,0x48,0x6f,0x10,0x6d,0x24,0x12,0x70,0x61, +0x74,0x25,0x10,0x6e,0x22,0x15,0x6f,0x6e,0x69,0x63,0x61,0x6c,0x23,0x13,0x72,0x63, +0x6c,0x65,0x27,0x11,0x6e,0x63,0x27,2,0x69,0x3a,0x6f,0x44,0x72,0x10,0x61,0x2c, +0x14,0x63,0x74,0x69,0x6f,0x6e,0x2d,0x10,0x6e,0x28,0x11,0x61,0x6c,0x29,0x11,0x6e, +0x74,0x2b,4,0x61,0x3a,0x66,0x4c,0x68,0x5e,0x6e,0x70,0x77,0x2a,0x12,0x69,0x64, +0x65,0x2b,0x22,0x17,0x6d,0x62,0x69,0x67,0x75,0x6f,0x75,0x73,0x23,0x26,0x17,0x75, +0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,0x27,0x24,0x17,0x61,0x6c,0x66,0x77,0x69,0x64, +0x74,0x68,0x25,0x20,1,0x61,0x30,0x65,0x14,0x75,0x74,0x72,0x61,0x6c,0x21,0x28, +0x13,0x72,0x72,0x6f,0x77,0x29,0xd,0x6e,0xc0,0xfb,0x73,0x6d,0x73,0x3a,0x74,0x98, +0x75,0xa2,0x49,0x7a,2,0x6c,0x3b,0x70,0x3d,0x73,0x39,5,0x6f,0x28,0x6f,0x57, +0x70,0x34,0x75,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x45,0x11,0x61,0x63,1, +0x65,0x32,0x69,0x15,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x31,0x18,0x73,0x65,0x70,0x61, +0x72,0x61,0x74,0x6f,0x72,0x39,0x63,0x53,0x6b,0x55,0x6d,0x51,0x1d,0x69,0x74,0x6c, +0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x27,1,0x6e,0x40,0x70, +0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x23,0x17, +0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x21,0x6e,0x8a,0x6f,0xa2,0x47,0x70,8, +0x66,0x14,0x66,0x5b,0x69,0x59,0x6f,0x4f,0x72,0x24,0x73,0x49,0x17,0x69,0x76,0x61, +0x74,0x65,0x75,0x73,0x65,0x43,0x61,0x2c,0x63,0x4d,0x64,0x47,0x65,0x4b,0x1f,0x72, +0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x3d, +2,0x64,0x33,0x6c,0x35,0x6f,0x36,0x1b,0x6e,0x73,0x70,0x61,0x63,0x69,0x6e,0x67, +0x6d,0x61,0x72,0x6b,0x2d,1,0x70,0x7c,0x74,0x12,0x68,0x65,0x72,3,0x6c,0x38, +0x6e,0x42,0x70,0x4c,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0x57,0x14,0x65,0x74,0x74, +0x65,0x72,0x2b,0x14,0x75,0x6d,0x62,0x65,0x72,0x37,0x19,0x75,0x6e,0x63,0x74,0x75, +0x61,0x74,0x69,0x6f,0x6e,0x4f,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61, +0x74,0x69,0x6f,0x6e,0x49,0x66,0x9e,0x66,0x88,0x69,0xa2,0x4b,0x6c,0xa2,0x5c,0x6d, +4,0x61,0x60,0x63,0x31,0x65,0x2f,0x6e,0x2d,0x6f,0x15,0x64,0x69,0x66,0x69,0x65, +0x72,1,0x6c,0x30,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0x55,0x14,0x65,0x74,0x74, +0x65,0x72,0x29,0x17,0x74,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x51,1,0x69,0x2e, +0x6f,0x13,0x72,0x6d,0x61,0x74,0x41,0x1d,0x6e,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74, +0x75,0x61,0x74,0x69,0x6f,0x6e,0x5b,0x10,0x6e,0x1f,0x69,0x74,0x69,0x61,0x6c,0x70, +0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x59,6,0x6d,0x18,0x6d,0x29, +0x6f,0x28,0x74,0x27,0x75,0x23,0x2a,0x1c,0x77,0x65,0x72,0x63,0x61,0x73,0x65,0x6c, +0x65,0x74,0x74,0x65,0x72,0x25,0x65,0x28,0x69,0x3c,0x6c,0x25,0x19,0x74,0x74,0x65, +0x72,0x6e,0x75,0x6d,0x62,0x65,0x72,0x35,0x1a,0x6e,0x65,0x73,0x65,0x70,0x61,0x72, +0x61,0x74,0x6f,0x72,0x3b,0x63,0x44,0x64,0xa2,0x60,0x65,0x1b,0x6e,0x63,0x6c,0x6f, +0x73,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x2f,6,0x6e,0x39,0x6e,0x46,0x6f,0x4e, +0x73,0x45,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c, +0x53,0x20,0x12,0x74,0x72,0x6c,0x3f,0x42,0x10,0x6e,1,0x6e,0x2c,0x74,0x12,0x72, +0x6f,0x6c,0x3f,0x1f,0x65,0x63,0x74,0x6f,0x72,0x70,0x75,0x6e,0x63,0x74,0x75,0x61, +0x74,0x69,0x6f,0x6e,0x4d,0x63,0x3f,0x66,0x41,0x6c,0x1d,0x6f,0x73,0x65,0x70,0x75, +0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4b,2,0x61,0x30,0x65,0x4a,0x69, +0x12,0x67,0x69,0x74,0x33,0x1c,0x73,0x68,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74, +0x69,0x6f,0x6e,0x47,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e,0x75,0x6d,0x62,0x65,0x72, +0x33,0,0x12,0x6d,0xc2,0x3f,0x73,0xa1,0x73,0x4e,0x74,0xa2,0x56,0x77,0xa2,0x72, +0x79,0xa2,0x73,0x7a,1,0x61,0x2c,0x68,0x12,0x61,0x69,0x6e,0x8b,0x11,0x69,0x6e, +0x85,5,0x74,0x22,0x74,0x38,0x77,0x4c,0x79,0x16,0x72,0x69,0x61,0x63,0x77,0x61, +0x77,0x6f,0x18,0x72,0x61,0x69,0x67,0x68,0x74,0x77,0x61,0x77,0xa3,0x55,0x15,0x61, +0x73,0x68,0x6b,0x61,0x66,0x6d,0x61,0x2e,0x65,0x38,0x68,0x11,0x69,0x6e,0x6b,0x10, +0x64,0x62,0x11,0x68,0x65,0x65,1,0x65,0x2e,0x6d,0x13,0x6b,0x61,0x74,0x68,0x69, +0x10,0x6e,0x67,1,0x61,0x4e,0x65,1,0x68,0x28,0x74,0x10,0x68,0x77,0x16,0x6d, +0x61,0x72,0x62,0x75,0x74,0x61,0x74,0x13,0x67,0x6f,0x61,0x6c,0x3d,1,0x68,0x71, +0x77,0x73,0x11,0x61,0x77,0x79,1,0x65,0x32,0x75,0x11,0x64,0x68,0x80,0x11,0x68, +0x65,0x83,0x10,0x68,0x7a,1,0x62,0x34,0x77,0x16,0x69,0x74,0x68,0x74,0x61,0x69, +0x6c,0x7f,0x14,0x61,0x72,0x72,0x65,0x65,0x7d,0x6d,0x6c,0x6e,0xa4,0x6b,0x70,0xa4, +0x88,0x71,0xa4,0x88,0x72,1,0x65,0x38,0x6f,0x18,0x68,0x69,0x6e,0x67,0x79,0x61, +0x79,0x65,0x68,0x93,1,0x68,0x5f,0x76,0x16,0x65,0x72,0x73,0x65,0x64,0x70,0x65, +0x61,2,0x61,0x2e,0x65,0xa4,0x3e,0x69,0x10,0x6d,0x53,1,0x6c,0xa2,0xe7,0x6e, +0x16,0x69,0x63,0x68,0x61,0x65,0x61,0x6e,0,0x12,0x6e,0x76,0x73,0x51,0x73,0x3e, +0x74,0x5c,0x77,0xa0,0x79,0xa2,0x42,0x7a,0x13,0x61,0x79,0x69,0x6e,0xa3,0x54,0x10, +0x61,1,0x64,0x2e,0x6d,0x12,0x65,0x6b,0x68,0xa3,0x4c,0x11,0x68,0x65,0xa3,0x4b, +3,0x61,0x38,0x65,0x3c,0x68,0x4a,0x77,0x13,0x65,0x6e,0x74,0x79,0xa3,0x51,0x10, +0x77,0xa3,0x4d,1,0x6e,0xa3,0x4e,0x74,0x10,0x68,0xa3,0x4f,0x14,0x61,0x6d,0x65, +0x64,0x68,0xa3,0x50,0x11,0x61,0x77,0xa3,0x52,0x12,0x6f,0x64,0x68,0xa3,0x53,0x6e, +0x3a,0x6f,0x40,0x70,0x46,0x71,0x4a,0x72,0x12,0x65,0x73,0x68,0xa3,0x4a,0x11,0x75, +0x6e,0xa3,0x46,0x11,0x6e,0x65,0xa3,0x47,0x10,0x65,0xa3,0x48,0x12,0x6f,0x70,0x68, +0xa3,0x49,0x67,0x33,0x67,0x38,0x68,0x40,0x6b,0x5e,0x6c,0x66,0x6d,0x11,0x65,0x6d, +0xa3,0x45,0x13,0x69,0x6d,0x65,0x6c,0xa1,1,0x65,0x32,0x75,0x14,0x6e,0x64,0x72, +0x65,0x64,0xa3,0x42,0x11,0x74,0x68,0xa3,0x41,0x12,0x61,0x70,0x68,0xa3,0x43,0x14, +0x61,0x6d,0x65,0x64,0x68,0xa3,0x44,0x61,0x34,0x62,0x4a,0x64,0x50,0x66,0x12,0x69, +0x76,0x65,0x9f,1,0x6c,0x2a,0x79,0x11,0x69,0x6e,0x97,0x12,0x65,0x70,0x68,0x95, +0x12,0x65,0x74,0x68,0x99,1,0x61,0x30,0x68,0x14,0x61,0x6d,0x65,0x64,0x68,0x9d, +0x13,0x6c,0x65,0x74,0x68,0x9b,0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,6,0x6e,0x2c, +0x6e,0x34,0x72,0x5e,0x73,0x62,0x74,0x11,0x74,0x61,0xa3,0x63,2,0x67,0x2e,0x6e, +0x32,0x79,0x10,0x61,0xa3,0x60,0x10,0x61,0xa3,0x5d,1,0x61,0xa3,0x5e,0x6e,0x10, +0x61,0xa3,0x5f,0x10,0x61,0xa3,0x61,0x11,0x73,0x61,0xa3,0x62,0x62,0x3c,0x6a,0x42, +0x6c,0x10,0x6c,1,0x61,0xa3,0x5b,0x6c,0x10,0x61,0xa3,0x5c,0x11,0x68,0x61,0xa3, +0x59,0x10,0x61,0xa3,0x5a,0x11,0x65,0x6d,0x51,2,0x6f,0x2c,0x75,0x50,0x79,0x10, +0x61,0x91,1,0x6a,0x28,0x6f,0x10,0x6e,0x55,0x1a,0x6f,0x69,0x6e,0x69,0x6e,0x67, +0x67,0x72,0x6f,0x75,0x70,0x21,0x10,0x6e,0x57,0x10,0x65,0x59,0x10,0x61,1,0x66, +0x5b,0x70,0x10,0x68,0x5d,0x66,0x9a,0x66,0x42,0x67,0x7a,0x68,0x8a,0x6b,0xa2,0x75, +0x6c,0x11,0x61,0x6d,0x4c,0x12,0x61,0x64,0x68,0x4f,2,0x61,0x3e,0x65,0x4a,0x69, +0x19,0x6e,0x61,0x6c,0x73,0x65,0x6d,0x6b,0x61,0x74,0x68,0x35,0x15,0x72,0x73,0x69, +0x79,0x65,0x68,0x8f,0x86,0x10,0x68,0x33,0x10,0x61,1,0x66,0x37,0x6d,0x11,0x61, +0x6c,0x39,1,0x61,0x40,0x65,0x3e,1,0x68,0x28,0x74,0x10,0x68,0x45,0x40,0x13, +0x67,0x6f,0x61,0x6c,0x43,2,0x68,0x3b,0x6d,0x5c,0x6e,0x1a,0x69,0x66,0x69,0x72, +0x6f,0x68,0x69,0x6e,0x67,0x79,0x61,1,0x6b,0x2a,0x70,0x10,0x61,0xa3,0x65,0x15, +0x69,0x6e,0x6e,0x61,0x79,0x61,0xa3,0x64,0x1a,0x7a,0x61,0x6f,0x6e,0x68,0x65,0x68, +0x67,0x6f,0x61,0x6c,0x3d,2,0x61,0x3a,0x68,0x44,0x6e,0x17,0x6f,0x74,0x74,0x65, +0x64,0x68,0x65,0x68,0x4b,1,0x66,0x47,0x70,0x10,0x68,0x49,0x12,0x61,0x70,0x68, +0x89,0x61,0x2e,0x62,0x8a,0x64,0xa2,0x51,0x65,0x31,2,0x66,0x3c,0x69,0x70,0x6c, +1,0x61,0x28,0x65,0x10,0x66,0x27,0x11,0x70,0x68,0x25,0x14,0x72,0x69,0x63,0x61, +0x6e,2,0x66,0x30,0x6e,0x36,0x71,0x11,0x61,0x66,0xa3,0x58,0x11,0x65,0x68,0xa3, +0x56,0x12,0x6f,0x6f,0x6e,0xa3,0x57,0x10,0x6e,0x23,1,0x65,0x4a,0x75,0x10,0x72, +0x1f,0x75,0x73,0x68,0x61,0x73,0x6b,0x69,0x79,0x65,0x68,0x62,0x61,0x72,0x72,0x65, +0x65,0x8d,1,0x68,0x29,0x74,0x10,0x68,0x2b,0x11,0x61,0x6c,0x2c,0x16,0x61,0x74, +0x68,0x72,0x69,0x73,0x68,0x2f,7,0x6e,0x2e,0x6e,0x2c,0x72,0x3e,0x74,0x56,0x75, +0x21,0x18,0x6f,0x6e,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x21,0x28,0x1a,0x69,0x67, +0x68,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x29,0x2a,0x19,0x72,0x61,0x6e,0x73, +0x70,0x61,0x72,0x65,0x6e,0x74,0x2b,0x63,0x23,0x64,0x40,0x6a,0x56,0x6c,0x26,0x19, +0x65,0x66,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x27,0x24,0x19,0x75,0x61,0x6c, +0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x25,0x19,0x6f,0x69,0x6e,0x63,0x61,0x75,0x73, +0x69,0x6e,0x67,0x23,0,0x13,0x6e,0xc0,0xd0,0x73,0x49,0x73,0x48,0x75,0x78,0x77, +0x84,0x78,0x9c,0x7a,0x10,0x77,0x58,1,0x6a,0x75,0x73,0x13,0x70,0x61,0x63,0x65, +0x59,4,0x61,0x51,0x67,0x53,0x70,0x28,0x75,0x30,0x79,0x57,0x54,0x12,0x61,0x63, +0x65,0x55,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x53,0x15,0x6e,0x6b,0x6e,0x6f, +0x77,0x6e,0x21,1,0x6a,0x5d,0x6f,0x17,0x72,0x64,0x6a,0x6f,0x69,0x6e,0x65,0x72, +0x5d,0x10,0x78,0x21,0x6e,0x60,0x6f,0xa2,0x41,0x70,0xa2,0x50,0x71,0xa2,0x6e,0x72, +1,0x65,0x24,0x69,0x6f,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69, +0x63,0x61,0x74,0x6f,0x72,0x6f,4,0x65,0x3e,0x6c,0x5b,0x6f,0x46,0x73,0x45,0x75, +0x46,0x14,0x6d,0x65,0x72,0x69,0x63,0x47,0x15,0x78,0x74,0x6c,0x69,0x6e,0x65,0x5b, +0x17,0x6e,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x45,0x10,0x70,0x48,0x1c,0x65,0x6e, +0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x49,1,0x6f,0x3e,0x72, +0x4c,0x1a,0x65,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x4d,0x4a,0x1b, +0x73,0x74,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x4b,0x10,0x75,0x4e, +0x16,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x68,0x7b,0x68,0x50,0x69,0x86,0x6a, +0xa2,0x61,0x6c,0xa2,0x65,0x6d,0x1c,0x61,0x6e,0x64,0x61,0x74,0x6f,0x72,0x79,0x62, +0x72,0x65,0x61,0x6b,0x2d,4,0x32,0x5f,0x33,0x61,0x65,0x34,0x6c,0x6d,0x79,0x3a, +0x13,0x70,0x68,0x65,0x6e,0x3b,0x19,0x62,0x72,0x65,0x77,0x6c,0x65,0x74,0x74,0x65, +0x72,0x6d,2,0x64,0x28,0x6e,0x3c,0x73,0x41,0x3c,0x18,0x65,0x6f,0x67,0x72,0x61, +0x70,0x68,0x69,0x63,0x3d,0x3e,1,0x66,0x3e,0x73,0x11,0x65,0x70,1,0x61,0x22, +0x65,0x14,0x72,0x61,0x62,0x6c,0x65,0x3f,0x18,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72, +0x69,0x63,0x41,2,0x6c,0x63,0x74,0x65,0x76,0x67,1,0x66,0x43,0x69,0x15,0x6e, +0x65,0x66,0x65,0x65,0x64,0x43,0x61,0x40,0x62,0x70,0x63,0xa2,0x55,0x65,0xa2,0xdb, +0x67,0x10,0x6c,0x38,0x11,0x75,0x65,0x39,2,0x69,0x23,0x6c,0x34,0x6d,0x16,0x62, +0x69,0x67,0x75,0x6f,0x75,0x73,0x23,0x24,0x17,0x70,0x68,0x61,0x62,0x65,0x74,0x69, +0x63,0x25,4,0x32,0x27,0x61,0x29,0x62,0x2b,0x6b,0x2d,0x72,0x12,0x65,0x61,0x6b, +2,0x61,0x36,0x62,0x3e,0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x57,0x13,0x66, +0x74,0x65,0x72,0x29,1,0x65,0x2a,0x6f,0x11,0x74,0x68,0x27,0x13,0x66,0x6f,0x72, +0x65,0x2b,7,0x6d,0x51,0x6d,0x33,0x6f,0x28,0x70,0x69,0x72,0x35,1,0x6d,0x76, +0x6e,1,0x64,0x3c,0x74,0x1a,0x69,0x6e,0x67,0x65,0x6e,0x74,0x62,0x72,0x65,0x61, +0x6b,0x2f,0x15,0x69,0x74,0x69,0x6f,0x6e,0x61,0x1f,0x6c,0x6a,0x61,0x70,0x61,0x6e, +0x65,0x73,0x65,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x6b,1,0x62,0x3a,0x70,0x19, +0x6c,0x65,0x78,0x63,0x6f,0x6e,0x74,0x65,0x78,0x74,0x51,0x18,0x69,0x6e,0x69,0x6e, +0x67,0x6d,0x61,0x72,0x6b,0x33,0x61,0x6a,0x62,0x2f,0x6a,0x6b,0x6c,0x30,0x13,0x6f, +0x73,0x65,0x70,1,0x61,0x38,0x75,0x18,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f, +0x6e,0x31,0x18,0x72,0x65,0x6e,0x74,0x68,0x65,0x73,0x69,0x73,0x69,0x1b,0x72,0x72, +0x69,0x61,0x67,0x65,0x72,0x65,0x74,0x75,0x72,0x6e,0x35,2,0x62,0x3e,0x6d,0x46, +0x78,0x36,0x18,0x63,0x6c,0x61,0x6d,0x61,0x74,0x69,0x6f,0x6e,0x37,0x70,0x12,0x61, +0x73,0x65,0x71,0x72,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x73,1,0x64,0x42, +0x6e,1,0x6f,0x32,0x75,0x26,0x14,0x6d,0x65,0x72,0x69,0x63,0x27,0x11,0x6e,0x65, +0x21,1,0x65,0x2e,0x69,0x24,0x12,0x67,0x69,0x74,0x25,0x22,0x14,0x63,0x69,0x6d, +0x61,0x6c,0x23,0,0x18,0x6e,0xc3,0xe6,0x74,0xc1,0x51,0x77,0x7a,0x77,0xa2,0x4c, +0x78,0xa2,0x60,0x79,0xa2,0x6a,0x7a,6,0x73,0x1e,0x73,0x34,0x78,0x42,0x79,0x48, +0x7a,0x11,0x7a,0x7a,0xa3,0x67,0x10,0x79,1,0x65,0xa3,0xae,0x6d,0xa3,0x81,0x11, +0x78,0x78,0xa3,0x66,0x11,0x79,0x79,0x21,0x61,0x30,0x69,0x58,0x6d,0x11,0x74,0x68, +0xa3,0x80,0x10,0x6e,1,0x61,0x26,0x62,0xa3,0xb1,0x1a,0x62,0x61,0x7a,0x61,0x72, +0x73,0x71,0x75,0x61,0x72,0x65,0xa3,0xb1,0x11,0x6e,0x68,0x23,1,0x61,0x2c,0x6f, +0x11,0x6c,0x65,0xa3,0x9b,0x11,0x72,0x61,0xa2,0x92,0x15,0x6e,0x67,0x63,0x69,0x74, +0x69,0xa3,0x92,1,0x70,0x2c,0x73,0x11,0x75,0x78,0xa3,0x65,0x11,0x65,0x6f,0x9b, +0x10,0x69,0x72,0x11,0x69,0x69,0x73,0x74,0x4a,0x75,0xa2,0xba,0x76,1,0x61,0x2c, +0x69,0x11,0x73,0x70,0xa3,0x64,0x10,0x69,0xa2,0x63,0x10,0x69,0xa3,0x63,5,0x67, +0x36,0x67,0x68,0x68,0x6c,0x69,2,0x62,0x3a,0x66,0x4a,0x72,0x10,0x68,0xa2,0x9e, +0x12,0x75,0x74,0x61,0xa3,0x9e,1,0x65,0x24,0x74,0x6f,0x12,0x74,0x61,0x6e,0x6f, +0x14,0x69,0x6e,0x61,0x67,0x68,0x99,0x11,0x6c,0x67,0x75,0x10,0x61,1,0x61,0x24, +0x69,0x6d,0x6a,0x11,0x6e,0x61,0x6b,0x61,0x30,0x65,0xa2,0x5b,0x66,0x11,0x6e,0x67, +0x99,6,0x6c,0x21,0x6c,0x32,0x6d,0x38,0x6e,0x44,0x76,0x10,0x74,0xa3,0x7f,1, +0x65,0x89,0x75,0x97,1,0x69,0x24,0x6c,0x67,0x10,0x6c,0x67,0x10,0x67,0xa2,0x9a, +0x11,0x75,0x74,0xa3,0x9a,0x67,0x36,0x69,0x52,0x6b,0x10,0x72,0xa2,0x99,0x10,0x69, +0xa3,0x99,1,0x61,0x30,0x62,0x7a,0x13,0x61,0x6e,0x77,0x61,0x7b,0x12,0x6c,0x6f, +0x67,0x75,2,0x6c,0x32,0x74,0x34,0x76,0x12,0x69,0x65,0x74,0xa3,0x7f,0x10,0x65, +0x89,0x12,0x68,0x61,0x6d,0xa3,0x6a,1,0x6c,0x2a,0x6e,0x10,0x67,0xa3,0x62,0x10, +0x75,0x68,0x11,0x67,0x75,0x69,1,0x67,0x32,0x6e,0x14,0x6b,0x6e,0x6f,0x77,0x6e, +0xa3,0x67,0x11,0x61,0x72,0x8a,0x13,0x69,0x74,0x69,0x63,0x8b,0x71,0xc1,0x13,0x71, +0xa2,0xde,0x72,0xa2,0xe3,0x73,6,0x69,0x8a,0x69,0x72,0x6f,0xa2,0x4c,0x75,0xa2, +0x75,0x79,1,0x6c,0x46,0x72,4,0x63,0x65,0x65,0xa3,0x5f,0x69,0x2c,0x6a,0xa3, +0x60,0x6e,0xa3,0x61,0x11,0x61,0x63,0x65,0x10,0x6f,0x94,0x16,0x74,0x69,0x6e,0x61, +0x67,0x72,0x69,0x95,2,0x64,0x3c,0x67,0x4c,0x6e,1,0x64,0xa3,0x91,0x68,0x62, +0x12,0x61,0x6c,0x61,0x63,0x10,0x64,0xa2,0xa6,0x12,0x68,0x61,0x6d,0xa3,0xa6,0x17, +0x6e,0x77,0x72,0x69,0x74,0x69,0x6e,0x67,0xa3,0x70,2,0x67,0x3a,0x72,0x52,0x79, +0x10,0x6f,0xa2,0xb0,0x12,0x6d,0x62,0x6f,0xa3,0xb0,1,0x64,0x26,0x6f,0xa3,0xb8, +0xa2,0xb7,0x12,0x69,0x61,0x6e,0xa3,0xb7,0x10,0x61,0xa2,0x98,0x16,0x73,0x6f,0x6d, +0x70,0x65,0x6e,0x67,0xa3,0x98,0x11,0x6e,0x64,0xa2,0x71,0x14,0x61,0x6e,0x65,0x73, +0x65,0xa3,0x71,0x61,0x5c,0x67,0xa2,0x43,0x68,1,0x61,0x2a,0x72,0x10,0x64,0xa3, +0x97,2,0x72,0x28,0x76,0x30,0x77,0x87,0x12,0x61,0x64,0x61,0xa3,0x97,0x12,0x69, +0x61,0x6e,0x87,2,0x6d,0x40,0x72,0x58,0x75,0x10,0x72,0xa2,0x6f,0x15,0x61,0x73, +0x68,0x74,0x72,0x61,0xa3,0x6f,1,0x61,0x26,0x72,0xa3,0x7e,0x14,0x72,0x69,0x74, +0x61,0x6e,0xa3,0x7e,1,0x61,0xa3,0x5e,0x62,0xa3,0x85,0x11,0x6e,0x77,0xa3,0x70, +0x11,0x61,0x61,1,0x63,0x2f,0x69,0x23,3,0x65,0x3e,0x6a,0x48,0x6f,0x4e,0x75, +0x10,0x6e,1,0x69,0x24,0x72,0x61,0x10,0x63,0x61,0x13,0x6a,0x61,0x6e,0x67,0xa3, +0x6e,0x11,0x6e,0x67,0xa3,0x6e,1,0x68,0x2a,0x72,0x10,0x6f,0xa3,0x5d,0x10,0x67, +0xa3,0xb6,0x6e,0xa2,0x83,0x6f,0xa2,0xca,0x70,5,0x6c,0x1e,0x6c,0x44,0x72,0x4a, +0x73,0x1b,0x61,0x6c,0x74,0x65,0x72,0x70,0x61,0x68,0x6c,0x61,0x76,0x69,0xa3,0x7b, +0x11,0x72,0x64,0xa3,0x5c,0x11,0x74,0x69,0xa3,0x7d,0x61,0x7c,0x65,0xa2,0x54,0x68, +3,0x61,0x3e,0x6c,0x4e,0x6e,0x5e,0x6f,0x16,0x65,0x6e,0x69,0x63,0x69,0x61,0x6e, +0xa3,0x5b,0x10,0x67,0xa2,0x5a,0x12,0x73,0x70,0x61,0xa3,0x5a,2,0x69,0xa3,0x7a, +0x70,0xa3,0x7b,0x76,0xa3,0x7c,0x10,0x78,0xa3,0x5b,2,0x68,0x3e,0x6c,0x50,0x75, +0x10,0x63,0xa2,0xa5,0x14,0x69,0x6e,0x68,0x61,0x75,0xa3,0xa5,0x17,0x61,0x77,0x68, +0x68,0x6d,0x6f,0x6e,0x67,0xa3,0x4b,0x10,0x6d,0xa2,0x90,0x14,0x79,0x72,0x65,0x6e, +0x65,0xa3,0x90,0x11,0x72,0x6d,0xa3,0x59,5,0x6b,0x1e,0x6b,0x32,0x73,0x4a,0x75, +0x12,0x73,0x68,0x75,0xa3,0x96,1,0x67,0x2e,0x6f,0xa2,0x57,0x10,0x6f,0xa3,0x57, +0x10,0x62,0xa3,0x84,0x11,0x68,0x75,0xa3,0x96,0x61,0x42,0x62,0x60,0x65,0x10,0x77, +1,0x61,0xa3,0xaa,0x74,0x14,0x61,0x69,0x6c,0x75,0x65,0x97,1,0x62,0x2a,0x72, +0x10,0x62,0xa3,0x8e,0x15,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3,0x8f,0x11,0x61,0x74, +0xa3,0x8f,3,0x67,0x5a,0x6c,0x6c,0x72,0xa2,0x93,0x73,2,0x61,0x36,0x67,0x3c, +0x6d,0x10,0x61,0x84,0x12,0x6e,0x79,0x61,0x85,0x11,0x67,0x65,0xa3,0xab,0x10,0x65, +0xa3,0xab,1,0x61,0x2a,0x68,0x11,0x61,0x6d,0x5b,0x10,0x6d,0x5b,1,0x63,0xa2, +0x60,0x64,5,0x70,0x37,0x70,0x36,0x73,0x54,0x74,0x14,0x75,0x72,0x6b,0x69,0x63, +0xa3,0x58,0x11,0x65,0x72,1,0x6d,0x2c,0x73,0x12,0x69,0x61,0x6e,0x9b,0x11,0x69, +0x63,0xa3,0x59,0x10,0x6f,1,0x67,0x3a,0x75,0x18,0x74,0x68,0x61,0x72,0x61,0x62, +0x69,0x61,0x6e,0xa3,0x85,0x13,0x64,0x69,0x61,0x6e,0xa3,0xb8,0x68,0x42,0x69,0x54, +0x6e,0x1a,0x6f,0x72,0x74,0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e,0xa3,0x8e,0x17, +0x75,0x6e,0x67,0x61,0x72,0x69,0x61,0x6e,0xa3,0x4c,0x14,0x74,0x61,0x6c,0x69,0x63, +0x5d,1,0x68,0x26,0x6b,0xa3,0x6d,0x12,0x69,0x6b,0x69,0xa3,0x6d,2,0x69,0x2c, +0x6b,0x30,0x79,0x10,0x61,0x5f,0x11,0x79,0x61,0x5f,0x10,0x68,0xa3,0x58,0x68,0xc2, +0xef,0x6b,0xc2,0xa,0x6b,0xa4,0x17,0x6c,0xa4,0x98,0x6d,8,0x6f,0x46,0x6f,0x48, +0x72,0x74,0x74,0x80,0x75,0x86,0x79,1,0x61,0x28,0x6d,0x10,0x72,0x59,0x13,0x6e, +0x6d,0x61,0x72,0x59,2,0x64,0x2e,0x6e,0x32,0x6f,0x10,0x6e,0xa3,0x72,0x10,0x69, +0xa3,0xa3,0x10,0x67,0x56,0x14,0x6f,0x6c,0x69,0x61,0x6e,0x57,0x10,0x6f,0xa2,0x95, +0x10,0x6f,0xa3,0x95,0x11,0x65,0x69,0xa3,0x73,0x11,0x6c,0x74,0xa2,0xa4,0x12,0x61, +0x6e,0x69,0xa3,0xa4,0x61,0x36,0x65,0xa2,0x67,0x69,0xa2,0xbd,0x6c,0x11,0x79,0x6d, +0x55,6,0x6e,0x38,0x6e,0x32,0x72,0x5c,0x73,0x6c,0x79,0x10,0x61,0xa3,0x55,1, +0x64,0x38,0x69,0xa2,0x79,0x15,0x63,0x68,0x61,0x65,0x61,0x6e,0xa3,0x79,0xa2,0x54, +0x12,0x61,0x69,0x63,0xa3,0x54,0x10,0x63,0xa2,0xa9,0x12,0x68,0x65,0x6e,0xa3,0xa9, +0x18,0x61,0x72,0x61,0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xaf,0x68,0x36,0x6b,0x4c, +0x6c,0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,0x55,1,0x61,0x26,0x6a,0xa3,0xa0,0x13, +0x6a,0x61,0x6e,0x69,0xa3,0xa0,0x10,0x61,0xa2,0xb4,0x12,0x73,0x61,0x72,0xa3,0xb4, +3,0x64,0x78,0x65,0x94,0x6e,0xa2,0x42,0x72,1,0x63,0xa3,0x8d,0x6f,0xa2,0x56, +0x13,0x69,0x74,0x69,0x63,1,0x63,0x3c,0x68,0x19,0x69,0x65,0x72,0x6f,0x67,0x6c, +0x79,0x70,0x68,0x73,0xa3,0x56,0x15,0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0x8d,1, +0x65,0x26,0x66,0xa3,0xb5,0x16,0x66,0x61,0x69,0x64,0x72,0x69,0x6e,0xa3,0xb5,0x17, +0x74,0x65,0x69,0x6d,0x61,0x79,0x65,0x6b,0xa3,0x73,0x10,0x64,0xa2,0x8c,0x17,0x65, +0x6b,0x69,0x6b,0x61,0x6b,0x75,0x69,0xa3,0x8c,0x11,0x61,0x6f,0xa3,0x5c,5,0x6f, +0x14,0x6f,0x30,0x70,0x36,0x74,0x11,0x68,0x69,0xa3,0x78,0x11,0x72,0x65,0xa3,0x77, +0x11,0x65,0x6c,0xa3,0x8a,0x61,0x2e,0x68,0x98,0x6e,0x11,0x64,0x61,0x4b,4,0x69, +0x3c,0x6c,0x44,0x6e,0x48,0x74,0x56,0x79,0x13,0x61,0x68,0x6c,0x69,0xa3,0x4f,0x12, +0x74,0x68,0x69,0xa3,0x78,0x10,0x69,0xa3,0x4f,1,0x61,0x4d,0x6e,0x12,0x61,0x64, +0x61,0x4b,0x14,0x61,0x6b,0x61,0x6e,0x61,0x4c,0x19,0x6f,0x72,0x68,0x69,0x72,0x61, +0x67,0x61,0x6e,0x61,0x8d,3,0x61,0x3c,0x6d,0x4e,0x6f,0x5a,0x75,0x15,0x64,0x61, +0x77,0x61,0x64,0x69,0xa3,0x91,0x10,0x72,0x92,0x15,0x6f,0x73,0x68,0x74,0x68,0x69, +0x93,1,0x65,0x24,0x72,0x4f,0x10,0x72,0x4f,0x10,0x6a,0xa2,0x9d,0x11,0x6b,0x69, +0xa3,0x9d,4,0x61,0x5c,0x65,0x90,0x69,0xa0,0x6f,0xa2,0x5d,0x79,1,0x63,0x34, +0x64,0x10,0x69,0xa2,0x6c,0x11,0x61,0x6e,0xa3,0x6c,0x10,0x69,0xa2,0x6b,0x11,0x61, +0x6e,0xa3,0x6b,2,0x6e,0x42,0x6f,0x46,0x74,3,0x66,0xa3,0x50,0x67,0xa3,0x51, +0x69,0x24,0x6e,0x53,0x10,0x6e,0x53,0x10,0x61,0xa3,0x6a,0x50,0x10,0x6f,0x51,0x11, +0x70,0x63,0xa2,0x52,0x11,0x68,0x61,0xa3,0x52,2,0x6d,0x2e,0x6e,0x36,0x73,0x10, +0x75,0xa3,0x83,0x10,0x62,0x80,0x10,0x75,0x81,2,0x61,0xa3,0x53,0x62,0x83,0x65, +0x11,0x61,0x72,1,0x61,0xa3,0x53,0x62,0x83,0x11,0x6d,0x61,0xa3,0x8b,0x68,0x6e, +0x69,0xa2,0x91,0x6a,2,0x61,0x30,0x70,0x52,0x75,0x11,0x72,0x63,0xa3,0x94,1, +0x6d,0x38,0x76,0x10,0x61,0xa2,0x4e,0x13,0x6e,0x65,0x73,0x65,0xa3,0x4e,0x10,0x6f, +0xa3,0xad,0x11,0x61,0x6e,0xa3,0x69,6,0x6c,0x1a,0x6c,0x34,0x6d,0x3a,0x72,0x40, +0x75,0x11,0x6e,0x67,0xa3,0x4c,0x11,0x75,0x77,0xa3,0x9c,0x11,0x6e,0x67,0xa3,0x4b, +0x11,0x6b,0x74,0x8d,0x61,0x3c,0x65,0xa2,0x43,0x69,0x11,0x72,0x61,0x48,0x13,0x67, +0x61,0x6e,0x61,0x49,1,0x6e,0x34,0x74,0x10,0x72,0xa2,0xa2,0x11,0x61,0x6e,0xa3, +0xa2,0x42,6,0x6f,0xe,0x6f,0x77,0x73,0xa3,0x49,0x74,0xa3,0x4a,0x75,0x12,0x6e, +0x6f,0x6f,0x77,0x62,0xa3,0xac,0x67,0x3e,0x69,0x42,0x19,0x66,0x69,0x72,0x6f,0x68, +0x69,0x6e,0x67,0x79,0x61,0xa3,0xb6,0x44,0x11,0x75,0x6c,0x45,0x11,0x62,0x72,0x46, +0x11,0x65,0x77,0x47,2,0x6d,0x2e,0x6e,0x4a,0x74,0x11,0x61,0x6c,0x5d,0x1c,0x70, +0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3,0x74,2,0x64, +0x66,0x68,0x6a,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x70, +0x61,1,0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0x7d,0x13,0x6c,0x61, +0x76,0x69,0xa3,0x7a,0x10,0x73,0xa3,0x4d,0x15,0x65,0x72,0x69,0x74,0x65,0x64,0x23, +0x64,0xc0,0xec,0x64,0xa2,0x7a,0x65,0xa2,0xad,0x67,4,0x65,0x82,0x6c,0x9a,0x6f, +0xa2,0x46,0x72,0xa2,0x55,0x75,2,0x6a,0x3c,0x6e,0x4e,0x72,1,0x6d,0x24,0x75, +0x41,0x13,0x75,0x6b,0x68,0x69,0x41,1,0x61,0x24,0x72,0x3f,0x13,0x72,0x61,0x74, +0x69,0x3f,0x18,0x6a,0x61,0x6c,0x61,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xb3,0x10,0x6f, +1,0x6b,0xa3,0x48,0x72,0x38,0x13,0x67,0x69,0x61,0x6e,0x39,0x11,0x61,0x67,0x90, +0x15,0x6f,0x6c,0x69,0x74,0x69,0x63,0x91,1,0x6e,0x30,0x74,0x10,0x68,0x3a,0x11, +0x69,0x63,0x3b,1,0x67,0xa3,0xb3,0x6d,0xa3,0xaf,1,0x61,0x32,0x65,1,0x65, +0x24,0x6b,0x3d,0x10,0x6b,0x3d,0x10,0x6e,0xa2,0x89,0x12,0x74,0x68,0x61,0xa3,0x89, +3,0x65,0x42,0x6f,0x68,0x73,0x76,0x75,0x11,0x70,0x6c,0xa2,0x87,0x13,0x6f,0x79, +0x61,0x6e,0xa3,0x87,1,0x73,0x38,0x76,0x10,0x61,0x34,0x15,0x6e,0x61,0x67,0x61, +0x72,0x69,0x35,0x13,0x65,0x72,0x65,0x74,0x33,0x11,0x67,0x72,0xa2,0xb2,0x10,0x61, +0xa3,0xb2,0x11,0x72,0x74,0x33,2,0x67,0x3a,0x6c,0x72,0x74,0x11,0x68,0x69,0x36, +0x13,0x6f,0x70,0x69,0x63,0x37,0x10,0x79,2,0x64,0xa3,0x45,0x68,0xa3,0x46,0x70, +0xa2,0x47,0x1e,0x74,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70, +0x68,0x73,0xa3,0x47,0x11,0x62,0x61,0xa2,0x88,0x12,0x73,0x61,0x6e,0xa3,0x88,0x61, +0xa2,0xa2,0x62,0xa4,7,0x63,6,0x6f,0x3d,0x6f,0x5a,0x70,0x76,0x75,0x7a,0x79, +1,0x70,0x3e,0x72,2,0x69,0x2a,0x6c,0x31,0x73,0xa3,0x44,0x13,0x6c,0x6c,0x69, +0x63,0x31,0x13,0x72,0x69,0x6f,0x74,0x7f,1,0x6d,0x30,0x70,0x10,0x74,0x2e,0x11, +0x69,0x63,0x2f,0x12,0x6d,0x6f,0x6e,0x21,0x11,0x72,0x74,0x7f,0x16,0x6e,0x65,0x69, +0x66,0x6f,0x72,0x6d,0xa3,0x65,0x61,0x32,0x68,0xa2,0x41,0x69,0x11,0x72,0x74,0xa3, +0x43,3,0x6b,0x4c,0x6e,0x50,0x72,0x76,0x75,0x1d,0x63,0x61,0x73,0x69,0x61,0x6e, +0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e,0xa3,0x9f,0x10,0x6d,0xa3,0x76,1,0x61, +0x24,0x73,0x71,0x1d,0x64,0x69,0x61,0x6e,0x61,0x62,0x6f,0x72,0x69,0x67,0x69,0x6e, +0x61,0x6c,0x71,0x10,0x69,0xa2,0x68,0x11,0x61,0x6e,0xa3,0x68,1,0x61,0x34,0x65, +0x10,0x72,0x2c,0x13,0x6f,0x6b,0x65,0x65,0x2d,1,0x6b,0x26,0x6d,0xa3,0x42,0x11, +0x6d,0x61,0xa3,0x76,6,0x68,0x4a,0x68,0x48,0x6e,0x4e,0x72,0x76,0x76,1,0x65, +0x2a,0x73,0x10,0x74,0xa3,0x75,0x13,0x73,0x74,0x61,0x6e,0xa3,0x75,0x11,0x6f,0x6d, +0xa3,0xa1,0x11,0x61,0x74,0x1f,0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f, +0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0x9c,1,0x61,0x3e,0x6d,2,0x65,0x2a,0x69, +0xa3,0x74,0x6e,0x27,0x13,0x6e,0x69,0x61,0x6e,0x27,0x10,0x62,0x24,0x11,0x69,0x63, +0x25,0x64,0x30,0x66,0x44,0x67,0x11,0x68,0x62,0xa3,0x9f,0x10,0x6c,1,0x61,0x26, +0x6d,0xa3,0xa7,0x10,0x6d,0xa3,0xa7,0x11,0x61,0x6b,0xa3,0x93,6,0x6c,0x3c,0x6c, +0x52,0x6f,0x56,0x72,0x66,0x75,1,0x67,0x30,0x68,1,0x64,0x79,0x69,0x10,0x64, +0x79,0x10,0x69,0x8e,0x13,0x6e,0x65,0x73,0x65,0x8f,0x11,0x69,0x73,0xa1,0x11,0x70, +0x6f,0x2a,0x13,0x6d,0x6f,0x66,0x6f,0x2b,0x10,0x61,1,0x68,0x2e,0x69,0x7c,0x12, +0x6c,0x6c,0x65,0x7d,0xa2,0x41,0x11,0x6d,0x69,0xa3,0x41,0x61,0x48,0x65,0x9c,0x68, +1,0x61,0x2a,0x6b,0x10,0x73,0xa3,0xa8,0x15,0x69,0x6b,0x73,0x75,0x6b,0x69,0xa3, +0xa8,3,0x6c,0x3a,0x6d,0x48,0x73,0x54,0x74,1,0x61,0x24,0x6b,0x9f,0x10,0x6b, +0x9f,0x10,0x69,0x9c,0x13,0x6e,0x65,0x73,0x65,0x9d,0x10,0x75,0xa2,0x82,0x10,0x6d, +0xa3,0x82,0x10,0x73,0xa2,0x86,0x13,0x61,0x76,0x61,0x68,0xa3,0x86,0x11,0x6e,0x67, +0x28,0x12,0x61,0x6c,0x69,0x29,3,0x6c,0x42,0x6e,0x90,0x74,0xa2,0x46,0x76,0x24, +0x17,0x6f,0x77,0x65,0x6c,0x6a,0x61,0x6d,0x6f,0x25,0x22,1,0x65,0x54,0x76,0x28, +1,0x73,0x38,0x74,0x2a,0x17,0x73,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x2b,0x16, +0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x29,0x18,0x61,0x64,0x69,0x6e,0x67,0x6a,0x61, +0x6d,0x6f,0x23,1,0x61,0x21,0x6f,0x1a,0x74,0x61,0x70,0x70,0x6c,0x69,0x63,0x61, +0x62,0x6c,0x65,0x21,0x26,0x1a,0x72,0x61,0x69,0x6c,0x69,0x6e,0x67,0x6a,0x61,0x6d, +0x6f,0x27,1,0x6e,0x2c,0x79,0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,0x21,1, +0x6e,0x2c,0x79,0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,0x21,2,0x6d,0x30,0x6e, +0x3a,0x79,0x22,0x11,0x65,0x73,0x23,0x24,0x13,0x61,0x79,0x62,0x65,0x25,0x20,0x10, +0x6f,0x21,2,0x6d,0x30,0x6e,0x3a,0x79,0x22,0x11,0x65,0x73,0x23,0x24,0x13,0x61, +0x79,0x62,0x65,0x25,0x20,0x10,0x6f,0x21,0xb,0x72,0x39,0x76,0xc,0x76,0x33,0x78, +0x2a,0x7a,0x11,0x77,0x6a,0x43,0x10,0x78,0x21,0x72,0x28,0x73,0x50,0x74,0x31,1, +0x65,0x24,0x69,0x39,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,0x63, +0x61,0x74,0x6f,0x72,0x39,1,0x6d,0x35,0x70,0x18,0x61,0x63,0x69,0x6e,0x67,0x6d, +0x61,0x72,0x6b,0x35,0x6c,0x1f,0x6c,0x3c,0x6f,0x4a,0x70,1,0x70,0x37,0x72,0x14, +0x65,0x70,0x65,0x6e,0x64,0x37,0x28,1,0x66,0x2b,0x76,0x2c,0x10,0x74,0x2f,0x13, +0x74,0x68,0x65,0x72,0x21,0x63,0x4c,0x65,0x64,0x67,1,0x61,0x3a,0x6c,0x19,0x75, +0x65,0x61,0x66,0x74,0x65,0x72,0x7a,0x77,0x6a,0x41,0x10,0x7a,0x41,2,0x6e,0x23, +0x6f,0x24,0x72,0x25,0x14,0x6e,0x74,0x72,0x6f,0x6c,0x23,2,0x62,0x34,0x6d,0x4e, +0x78,0x26,0x13,0x74,0x65,0x6e,0x64,0x27,0x3a,1,0x61,0x24,0x67,0x3d,0x11,0x73, +0x65,0x3a,0x12,0x67,0x61,0x7a,0x3d,0x3e,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72, +0x3f,9,0x6e,0x4a,0x6e,0x34,0x6f,0x44,0x73,0x60,0x75,0x94,0x78,0x10,0x78,0x21, +0x10,0x75,0x2a,0x14,0x6d,0x65,0x72,0x69,0x63,0x2b,1,0x6c,0x2c,0x74,0x12,0x68, +0x65,0x72,0x21,0x14,0x65,0x74,0x74,0x65,0x72,0x2d,3,0x63,0x36,0x65,0x46,0x70, +0x31,0x74,0x32,0x12,0x65,0x72,0x6d,0x33,0x3c,0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75, +0x65,0x3d,0x2e,0x10,0x70,0x2f,0x10,0x70,0x34,0x12,0x70,0x65,0x72,0x35,0x61,0x46, +0x63,0x52,0x65,0x64,0x66,0x72,0x6c,2,0x65,0x2d,0x66,0x3b,0x6f,0x28,0x12,0x77, +0x65,0x72,0x29,0x10,0x74,0x22,0x12,0x65,0x72,0x6d,0x23,1,0x6c,0x24,0x72,0x37, +0x24,0x12,0x6f,0x73,0x65,0x25,0x10,0x78,0x38,0x13,0x74,0x65,0x6e,0x64,0x39,0x10, +0x6f,0x26,0x13,0x72,0x6d,0x61,0x74,0x27,0,0x10,0x6c,0x88,0x72,0x40,0x72,0x36, +0x73,0x5e,0x77,0x7a,0x78,0x8a,0x7a,0x11,0x77,0x6a,0x4b,1,0x65,0x24,0x69,0x3b, +0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72, +0x3b,1,0x69,0x24,0x71,0x3f,0x18,0x6e,0x67,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65, +0x3f,0x17,0x73,0x65,0x67,0x73,0x70,0x61,0x63,0x65,0x4d,0x10,0x78,0x21,0x6c,0x36, +0x6d,0x3c,0x6e,0x76,0x6f,0x13,0x74,0x68,0x65,0x72,0x21,1,0x65,0x23,0x66,0x35, +3,0x62,0x37,0x69,0x28,0x6c,0x29,0x6e,0x2b,0x10,0x64,1,0x6c,0x34,0x6e,0x11, +0x75,0x6d,0x2a,0x12,0x6c,0x65,0x74,0x37,0x14,0x65,0x74,0x74,0x65,0x72,0x29,2, +0x65,0x36,0x6c,0x39,0x75,0x2c,0x14,0x6d,0x65,0x72,0x69,0x63,0x2d,0x14,0x77,0x6c, +0x69,0x6e,0x65,0x39,0x66,0x3f,0x66,0x40,0x67,0x4e,0x68,0x70,0x6b,0x10,0x61,0x26, +0x15,0x74,0x61,0x6b,0x61,0x6e,0x61,0x27,0x10,0x6f,0x24,0x13,0x72,0x6d,0x61,0x74, +0x25,1,0x61,0x3a,0x6c,0x19,0x75,0x65,0x61,0x66,0x74,0x65,0x72,0x7a,0x77,0x6a, +0x49,0x10,0x7a,0x49,1,0x65,0x24,0x6c,0x3d,0x19,0x62,0x72,0x65,0x77,0x6c,0x65, +0x74,0x74,0x65,0x72,0x3d,0x61,0x86,0x63,0x92,0x64,0x94,0x65,2,0x62,0x44,0x6d, +0x5e,0x78,0x2e,0x13,0x74,0x65,0x6e,0x64,0x32,0x15,0x6e,0x75,0x6d,0x6c,0x65,0x74, +0x2f,0x42,1,0x61,0x24,0x67,0x45,0x11,0x73,0x65,0x42,0x12,0x67,0x61,0x7a,0x45, +0x46,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x47,0x15,0x6c,0x65,0x74,0x74,0x65, +0x72,0x23,0x10,0x72,0x31,1,0x6f,0x24,0x71,0x41,0x18,0x75,0x62,0x6c,0x65,0x71, +0x75,0x6f,0x74,0x65,0x41,2,0x63,0x32,0x6e,0x3c,0x6f,0x22,0x12,0x70,0x65,0x6e, +0x23,0x24,0x13,0x6c,0x6f,0x73,0x65,0x25,0x20,0x12,0x6f,0x6e,0x65,0x21,0xd,0x6e, +0xc1,0x86,0x73,0xa8,0x73,0x4c,0x74,0xa2,0x76,0x75,0xa2,0x83,0x7a,0xd8,0x70,0, +2,0x6c,0xd9,0x20,0,0x70,0xd9,0x40,0,0x73,0xc3,0,0xfe,0xf,0,0, +0,7,0x6f,0x3c,0x6f,0xff,8,0,0,0,0x70,0x3a,0x75,0x6e,0x79,0x13, +0x6d,0x62,0x6f,0x6c,0xff,0xf,0,0,0,0x11,0x61,0x63,1,0x65,0x34,0x69, +0x15,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5,0,0x18,0x73,0x65,0x70,0x61,0x72,0x61, +0x74,0x6f,0x72,0xc3,0,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0xe1,0,0, +0x63,0xff,2,0,0,0,0x65,0x38,0x6b,0xff,4,0,0,0,0x6d,0xff, +1,0,0,0,0x16,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x70,0,0x1d, +0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x31,1, +0x6e,0x40,0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65, +0x72,0x25,0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x23,0x6e,0xa2,0x69,0x6f, +0xa2,0x89,0x70,0xfe,0x30,0xf8,0,0,9,0x69,0x33,0x69,0xff,0x10,0,0, +0,0x6f,0xfd,0x80,0,0,0x72,0x54,0x73,0xf9,0,0,0x75,0x12,0x6e,0x63, +0x74,0xfe,0x30,0xf8,0,0,0x15,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x30,0xf8, +0,0,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0xdd,0,0,0x61,0x48, +0x63,0xfd,0x40,0,0,0x64,0xe9,0,0,0x65,0xfd,0x20,0,0,0x66,0xff, +0x20,0,0,0,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61, +0x72,0x61,0x74,0x6f,0x72,0xd9,0x40,0,0xbe,0,3,0x64,0xa7,0,0x6c,0xab, +0,0x6f,0x30,0x75,0x13,0x6d,0x62,0x65,0x72,0xbf,0,0xb2,0,0x1b,0x6e,0x73, +0x70,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa1,1,0x70,0x92,0x74,0x12, +0x68,0x65,0x72,0xe6,0x80,1,3,0x6c,0x40,0x6e,0x4a,0x70,0x56,0x73,0x14,0x79, +0x6d,0x62,0x6f,0x6c,0xff,8,0,0,0,0x14,0x65,0x74,0x74,0x65,0x72,0x61, +0x14,0x75,0x6d,0x62,0x65,0x72,0xb3,0,0x19,0x75,0x6e,0x63,0x74,0x75,0x61,0x74, +0x69,0x6f,0x6e,0xfd,0x80,0,0,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75, +0x61,0x74,0x69,0x6f,0x6e,0xf9,0,0,0x66,0xc0,0xc4,0x66,0xa2,0x47,0x69,0xa2, +0x64,0x6c,0xa2,0x79,0x6d,0xa4,0xc0,4,0x61,0x6c,0x63,0xa5,0,0x65,0xa3,0x80, +0x6e,0xa1,0x6f,0x15,0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c,0x38,0x73,0x14,0x79, +0x6d,0x62,0x6f,0x6c,0xff,4,0,0,0,0x14,0x65,0x74,0x74,0x65,0x72,0x41, +1,0x72,0x3c,0x74,0x16,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c,0xff,1,0,0, +0,0x10,0x6b,0xa5,0xc0,1,0x69,0x32,0x6f,0x13,0x72,0x6d,0x61,0x74,0xdb,0, +0,0x1d,0x6e,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e, +0xff,0x20,0,0,0,0x10,0x6e,0x1f,0x69,0x74,0x69,0x61,0x6c,0x70,0x75,0x6e, +0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x10,0,0,0,0x9c,7,0x6d, +0x18,0x6d,0x41,0x6f,0x28,0x74,0x31,0x75,0x25,0x60,0x1c,0x77,0x65,0x72,0x63,0x61, +0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x29,0x63,0x3d,0x65,0x28,0x69,0x42,0x6c, +0x29,0x13,0x74,0x74,0x65,0x72,0x9c,0x15,0x6e,0x75,0x6d,0x62,0x65,0x72,0xab,0, +0x1a,0x6e,0x65,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x20,0,0x63, +0x46,0x64,0xa2,0x96,0x65,0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67,0x6d,0x61, +0x72,0x6b,0xa3,0x80,0xe6,0x80,1,7,0x6e,0x57,0x6e,0x52,0x6f,0x5e,0x73,0xe1, +0,0,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c, +0xff,2,0,0,0,0x22,0x12,0x74,0x72,0x6c,0xd9,0x80,0,0xdc,0,0, +1,0x6d,0x62,0x6e,1,0x6e,0x30,0x74,0x12,0x72,0x6f,0x6c,0xd9,0x80,0,0x1f, +0x65,0x63,0x74,0x6f,0x72,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e, +0xfd,0x40,0,0,0x19,0x62,0x69,0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5, +0xc0,0x61,0x58,0x63,0xd9,0x80,0,0x66,0xdb,0,0,0x6c,0x1d,0x6f,0x73,0x65, +0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd,0x20,0,0,0x18, +0x73,0x65,0x64,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,2,0x61,0x32,0x65,0x50,0x69, +0x12,0x67,0x69,0x74,0xa7,0,0x1c,0x73,0x68,0x70,0x75,0x6e,0x63,0x74,0x75,0x61, +0x74,0x69,0x6f,0x6e,0xe9,0,0,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e,0x75,0x6d, +0x62,0x65,0x72,0xa7,0 }; -const char PropNameData::nameGroups[19082]={ +const char PropNameData::nameGroups[19587]={ 2,'A','l','p','h','a',0,'A','l','p','h','a','b','e','t','i','c',0, 4,'N',0,'N','o',0,'F',0,'F','a','l','s','e',0,4,'Y',0,'Y','e','s',0,'T',0,'T','r','u','e',0, 2,'N','R',0,'N','o','t','_','R','e','o','r','d','e','r','e','d',0, @@ -1025,14 +1049,14 @@ const char PropNameData::nameGroups[19082]={ 2,'C','W','C','M',0,'C','h','a','n','g','e','s','_','W','h','e','n','_','C','a','s','e','m','a','p','p','e','d',0, 2,'C','W','K','C','F',0,'C','h','a','n','g','e','s','_','W','h','e','n','_','N','F','K','C','_','C','a','s','e','f','o','l', 'd','e','d',0,2,'E','m','o','j','i',0,'E','m','o','j','i',0, -2,'E','m','o','j','i','_','P','r','e','s','e','n','t','a','t','i','o','n',0,'E','m','o','j','i','_','P','r','e','s','e','n', -'t','a','t','i','o','n',0,2,'E','m','o','j','i','_','M','o','d','i','f','i','e','r',0,'E','m','o','j','i','_','M','o','d', -'i','f','i','e','r',0,2,'E','m','o','j','i','_','M','o','d','i','f','i','e','r','_','B','a','s','e',0, -'E','m','o','j','i','_','M','o','d','i','f','i','e','r','_','B','a','s','e',0, -2,'E','m','o','j','i','_','C','o','m','p','o','n','e','n','t',0,'E','m','o','j','i','_','C','o','m','p','o','n','e','n','t', -0,2,'R','I',0,'R','e','g','i','o','n','a','l','_','I','n','d','i','c','a','t','o','r',0, +2,'E','P','r','e','s',0,'E','m','o','j','i','_','P','r','e','s','e','n','t','a','t','i','o','n',0, +2,'E','M','o','d',0,'E','m','o','j','i','_','M','o','d','i','f','i','e','r',0, +2,'E','B','a','s','e',0,'E','m','o','j','i','_','M','o','d','i','f','i','e','r','_','B','a','s','e',0, +2,'E','C','o','m','p',0,'E','m','o','j','i','_','C','o','m','p','o','n','e','n','t',0, +2,'R','I',0,'R','e','g','i','o','n','a','l','_','I','n','d','i','c','a','t','o','r',0, 2,'P','C','M',0,'P','r','e','p','e','n','d','e','d','_','C','o','n','c','a','t','e','n','a','t','i','o','n','_','M','a','r', -'k',0,2,'b','c',0,'B','i','d','i','_','C','l','a','s','s',0, +'k',0,2,'E','x','t','P','i','c','t',0,'E','x','t','e','n','d','e','d','_','P','i','c','t','o','g','r','a','p','h','i','c', +0,2,'b','c',0,'B','i','d','i','_','C','l','a','s','s',0, 2,'L',0,'L','e','f','t','_','T','o','_','R','i','g','h','t',0, 2,'R',0,'R','i','g','h','t','_','T','o','_','L','e','f','t',0, 2,'E','N',0,'E','u','r','o','p','e','a','n','_','N','u','m','b','e','r',0, @@ -1371,8 +1395,19 @@ const char PropNameData::nameGroups[19082]={ 2,'N','u','s','h','u',0,'N','u','s','h','u',0,2,'S','o','y','o','m','b','o',0,'S','o','y','o','m','b','o',0, 2,'S','y','r','i','a','c','_','S','u','p',0,'S','y','r','i','a','c','_','S','u','p','p','l','e','m','e','n','t',0, 2,'Z','a','n','a','b','a','z','a','r','_','S','q','u','a','r','e',0,'Z','a','n','a','b','a','z','a','r','_','S','q','u','a', -'r','e',0,2,'c','c','c',0,'C','a','n','o','n','i','c','a','l','_','C','o','m','b','i','n','i','n','g','_','C','l','a','s', -'s',0,2,'d','t',0,'D','e','c','o','m','p','o','s','i','t','i','o','n','_','T','y','p','e',0, +'r','e',0,2,'C','h','e','s','s','_','S','y','m','b','o','l','s',0,'C','h','e','s','s','_','S','y','m','b','o','l','s',0, +2,'D','o','g','r','a',0,'D','o','g','r','a',0,2,'G','e','o','r','g','i','a','n','_','E','x','t',0, +'G','e','o','r','g','i','a','n','_','E','x','t','e','n','d','e','d',0, +2,'G','u','n','j','a','l','a','_','G','o','n','d','i',0,'G','u','n','j','a','l','a','_','G','o','n','d','i',0, +2,'H','a','n','i','f','i','_','R','o','h','i','n','g','y','a',0,'H','a','n','i','f','i','_','R','o','h','i','n','g','y','a', +0,2,'I','n','d','i','c','_','S','i','y','a','q','_','N','u','m','b','e','r','s',0,'I','n','d','i','c','_','S','i','y','a', +'q','_','N','u','m','b','e','r','s',0,2,'M','a','k','a','s','a','r',0,'M','a','k','a','s','a','r',0, +2,'M','a','y','a','n','_','N','u','m','e','r','a','l','s',0,'M','a','y','a','n','_','N','u','m','e','r','a','l','s',0, +2,'M','e','d','e','f','a','i','d','r','i','n',0,'M','e','d','e','f','a','i','d','r','i','n',0, +2,'O','l','d','_','S','o','g','d','i','a','n',0,'O','l','d','_','S','o','g','d','i','a','n',0, +2,'S','o','g','d','i','a','n',0,'S','o','g','d','i','a','n',0, +2,'c','c','c',0,'C','a','n','o','n','i','c','a','l','_','C','o','m','b','i','n','i','n','g','_','C','l','a','s','s',0, +2,'d','t',0,'D','e','c','o','m','p','o','s','i','t','i','o','n','_','T','y','p','e',0, 3,'N','o','n','e',0,'N','o','n','e',0,'n','o','n','e',0, 3,'C','a','n',0,'C','a','n','o','n','i','c','a','l',0,'c','a','n',0, 3,'C','o','m',0,'C','o','m','p','a','t',0,'c','o','m',0, @@ -1503,7 +1538,10 @@ const char PropNameData::nameGroups[19082]={ 2,'M','a','l','a','y','a','l','a','m','_','R','a',0,'M','a','l','a','y','a','l','a','m','_','R','a',0, 2,'M','a','l','a','y','a','l','a','m','_','S','s','a',0,'M','a','l','a','y','a','l','a','m','_','S','s','a',0, 2,'M','a','l','a','y','a','l','a','m','_','T','t','a',0,'M','a','l','a','y','a','l','a','m','_','T','t','a',0, -2,'j','t',0,'J','o','i','n','i','n','g','_','T','y','p','e',0, +2,'H','a','n','i','f','i','_','R','o','h','i','n','g','y','a','_','K','i','n','n','a','_','Y','a',0, +'H','a','n','i','f','i','_','R','o','h','i','n','g','y','a','_','K','i','n','n','a','_','Y','a',0, +2,'H','a','n','i','f','i','_','R','o','h','i','n','g','y','a','_','P','a',0,'H','a','n','i','f','i','_','R','o','h','i','n', +'g','y','a','_','P','a',0,2,'j','t',0,'J','o','i','n','i','n','g','_','T','y','p','e',0, 2,'U',0,'N','o','n','_','J','o','i','n','i','n','g',0,2,'C',0,'J','o','i','n','_','C','a','u','s','i','n','g',0, 2,'D',0,'D','u','a','l','_','J','o','i','n','i','n','g',0, 2,'L',0,'L','e','f','t','_','J','o','i','n','i','n','g',0, @@ -1644,7 +1682,12 @@ const char PropNameData::nameGroups[19082]={ 2,'H','a','n','b',0,'H','a','n','b',0,2,'J','a','m','o',0,'J','a','m','o',0, 2,'Z','s','y','e',0,'Z','s','y','e',0,2,'G','o','n','m',0,'M','a','s','a','r','a','m','_','G','o','n','d','i',0, 2,'S','o','y','o',0,'S','o','y','o','m','b','o',0,2,'Z','a','n','b',0,'Z','a','n','a','b','a','z','a','r','_','S','q', -'u','a','r','e',0,2,'h','s','t',0,'H','a','n','g','u','l','_','S','y','l','l','a','b','l','e','_','T','y','p','e',0, +'u','a','r','e',0,2,'D','o','g','r',0,'D','o','g','r','a',0, +2,'G','o','n','g',0,'G','u','n','j','a','l','a','_','G','o','n','d','i',0, +2,'M','a','k','a',0,'M','a','k','a','s','a','r',0,2,'M','e','d','f',0,'M','e','d','e','f','a','i','d','r','i','n',0, +2,'R','o','h','g',0,'H','a','n','i','f','i','_','R','o','h','i','n','g','y','a',0, +2,'S','o','g','d',0,'S','o','g','d','i','a','n',0,2,'S','o','g','o',0,'O','l','d','_','S','o','g','d','i','a','n',0, +2,'h','s','t',0,'H','a','n','g','u','l','_','S','y','l','l','a','b','l','e','_','T','y','p','e',0, 2,'N','A',0,'N','o','t','_','A','p','p','l','i','c','a','b','l','e',0, 2,'L',0,'L','e','a','d','i','n','g','_','J','a','m','o',0, 2,'V',0,'V','o','w','e','l','_','J','a','m','o',0,2,'T',0,'T','r','a','i','l','i','n','g','_','J','a','m','o',0, @@ -1676,6 +1719,7 @@ const char PropNameData::nameGroups[19082]={ 2,'E','x','t','e','n','d',0,'E','x','t','e','n','d',0,2,'M','B',0,'M','i','d','N','u','m','L','e','t',0, 2,'N','L',0,'N','e','w','l','i','n','e',0,2,'S','Q',0,'S','i','n','g','l','e','_','Q','u','o','t','e',0, 2,'D','Q',0,'D','o','u','b','l','e','_','Q','u','o','t','e',0, +2,'W','S','e','g','S','p','a','c','e',0,'W','S','e','g','S','p','a','c','e',0, 2,'b','p','t',0,'B','i','d','i','_','P','a','i','r','e','d','_','B','r','a','c','k','e','t','_','T','y','p','e',0, 2,'n',0,'N','o','n','e',0,2,'o',0,'O','p','e','n',0, 2,'c',0,'C','l','o','s','e',0,2,'g','c','m',0,'G','e','n','e','r','a','l','_','C','a','t','e','g','o','r','y','_','M', diff --git a/deps/icu-small/source/common/putil.cpp b/deps/icu-small/source/common/putil.cpp index e367fa6d30..a1e16a9cd9 100644 --- a/deps/icu-small/source/common/putil.cpp +++ b/deps/icu-small/source/common/putil.cpp @@ -533,6 +533,28 @@ uprv_fmin(double x, double y) return (x > y ? y : x); } +U_CAPI UBool U_EXPORT2 +uprv_add32_overflow(int32_t a, int32_t b, int32_t* res) { + // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_add_overflow. + // This function could be optimized by calling one of those primitives. + auto a64 = static_cast(a); + auto b64 = static_cast(b); + int64_t res64 = a64 + b64; + *res = static_cast(res64); + return res64 != *res; +} + +U_CAPI UBool U_EXPORT2 +uprv_mul32_overflow(int32_t a, int32_t b, int32_t* res) { + // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_mul_overflow. + // This function could be optimized by calling one of those primitives. + auto a64 = static_cast(a); + auto b64 = static_cast(b); + int64_t res64 = a64 * b64; + *res = static_cast(res64); + return res64 != *res; +} + /** * Truncates the given double. * trunc(3.3) = 3.0, trunc (-3.3) = -3.0 diff --git a/deps/icu-small/source/common/putilimp.h b/deps/icu-small/source/common/putilimp.h index 56ea8df009..023e06879a 100644 --- a/deps/icu-small/source/common/putilimp.h +++ b/deps/icu-small/source/common/putilimp.h @@ -391,6 +391,32 @@ U_INTERNAL double U_EXPORT2 uprv_log(double d); */ U_INTERNAL double U_EXPORT2 uprv_round(double x); +/** + * Adds the signed integers a and b, storing the result in res. + * Checks for signed integer overflow. + * Similar to the GCC/Clang extension __builtin_add_overflow + * + * @param a The first operand. + * @param b The second operand. + * @param res a + b + * @return true if overflow occurred; false if no overflow occurred. + * @internal + */ +U_INTERNAL UBool U_EXPORT2 uprv_add32_overflow(int32_t a, int32_t b, int32_t* res); + +/** + * Multiplies the signed integers a and b, storing the result in res. + * Checks for signed integer overflow. + * Similar to the GCC/Clang extension __builtin_mul_overflow + * + * @param a The first multiplicand. + * @param b The second multiplicand. + * @param res a * b + * @return true if overflow occurred; false if no overflow occurred. + * @internal + */ +U_INTERNAL UBool U_EXPORT2 uprv_mul32_overflow(int32_t a, int32_t b, int32_t* res); + #if 0 /** * Returns the number of digits after the decimal point in a double number x. diff --git a/deps/icu-small/source/common/rbbi.cpp b/deps/icu-small/source/common/rbbi.cpp index 69f92d94c6..c5ea2770ba 100644 --- a/deps/icu-small/source/common/rbbi.cpp +++ b/deps/icu-small/source/common/rbbi.cpp @@ -651,7 +651,7 @@ UBool RuleBasedBreakIterator::isBoundary(int32_t offset) { } // Adjust offset to be on a code point boundary and not beyond the end of the text. - // Note that isBoundary() is always be false for offsets that are not on code point boundaries. + // Note that isBoundary() is always false for offsets that are not on code point boundaries. // But we still need the side effect of leaving iteration at the following boundary. utext_setNativeIndex(&fText, offset); @@ -937,26 +937,23 @@ int32_t RuleBasedBreakIterator::handleNext() { } - //----------------------------------------------------------------------------------- // -// handlePrevious() +// handleSafePrevious() // // Iterate backwards using the safe reverse rules. -// The logic of this function is very similar to handleNext(), above. +// The logic of this function is similar to handleNext(), but simpler +// because the safe table does not require as many options. // //----------------------------------------------------------------------------------- -int32_t RuleBasedBreakIterator::handlePrevious(int32_t fromPosition) { +int32_t RuleBasedBreakIterator::handleSafePrevious(int32_t fromPosition) { int32_t state; uint16_t category = 0; - RBBIRunMode mode; RBBIStateTableRow *row; UChar32 c; - LookAheadResults lookAheadMatches; int32_t result = 0; - int32_t initialPosition = 0; - const RBBIStateTable *stateTable = fData->fSafeRevTable; + const RBBIStateTable *stateTable = fData->fReverseTable; UTEXT_SETNATIVEINDEX(&fText, fromPosition); #ifdef RBBI_DEBUG if (gTrace) { @@ -969,54 +966,24 @@ int32_t RuleBasedBreakIterator::handlePrevious(int32_t fromPosition) { return BreakIterator::DONE; } - // Set up the starting char. - initialPosition = (int32_t)UTEXT_GETNATIVEINDEX(&fText); - result = initialPosition; - c = UTEXT_PREVIOUS32(&fText); - // Set the initial state for the state machine + c = UTEXT_PREVIOUS32(&fText); state = START_STATE; row = (RBBIStateTableRow *) (stateTable->fTableData + (stateTable->fRowLen * state)); - category = 3; - mode = RBBI_RUN; - if (stateTable->fFlags & RBBI_BOF_REQUIRED) { - category = 2; - mode = RBBI_START; - } - // loop until we reach the start of the text or transition to state 0 // - for (;;) { - if (c == U_SENTINEL) { - // Reached end of input string. - if (mode == RBBI_END) { - // We have already run the loop one last time with the - // character set to the psueudo {eof} value. Now it is time - // to unconditionally bail out. - break; - } - // Run the loop one last time with the fake end-of-input character category. - mode = RBBI_END; - category = 1; - } + for (; c != U_SENTINEL; c = UTEXT_PREVIOUS32(&fText)) { + // look up the current character's character category, which tells us + // which column in the state table to look at. + // Note: the 16 in UTRIE_GET16 refers to the size of the data being returned, + // not the size of the character going in, which is a UChar32. // - // Get the char category. An incoming category of 1 or 2 means that - // we are preset for doing the beginning or end of input, and - // that we shouldn't get a category from an actual text input character. - // - if (mode == RBBI_RUN) { - // look up the current character's character category, which tells us - // which column in the state table to look at. - // Note: the 16 in UTRIE_GET16 refers to the size of the data being returned, - // not the size of the character going in, which is a UChar32. - // - // And off the dictionary flag bit. For reverse iteration it is not used. - category = UTRIE2_GET16(fData->fTrie, c); - category &= ~0x4000; - } + // And off the dictionary flag bit. For reverse iteration it is not used. + category = UTRIE2_GET16(fData->fTrie, c); + category &= ~0x4000; #ifdef RBBI_DEBUG if (gTrace) { @@ -1032,65 +999,21 @@ int32_t RuleBasedBreakIterator::handlePrevious(int32_t fromPosition) { // State Transition - move machine to its next state // - // fNextState is a variable-length array. U_ASSERT(categoryfHeader->fCatCount); state = row->fNextState[category]; /*Not accessing beyond memory*/ row = (RBBIStateTableRow *) (stateTable->fTableData + (stateTable->fRowLen * state)); - if (row->fAccepting == -1) { - // Match found, common case. - result = (int32_t)UTEXT_GETNATIVEINDEX(&fText); - } - - int16_t completedRule = row->fAccepting; - if (completedRule > 0) { - // Lookahead match is completed. - int32_t lookaheadResult = lookAheadMatches.getPosition(completedRule); - if (lookaheadResult >= 0) { - UTEXT_SETNATIVEINDEX(&fText, lookaheadResult); - return lookaheadResult; - } - } - int16_t rule = row->fLookAhead; - if (rule != 0) { - // At the position of a '/' in a look-ahead match. Record it. - int32_t pos = (int32_t)UTEXT_GETNATIVEINDEX(&fText); - lookAheadMatches.setPosition(rule, pos); - } - if (state == STOP_STATE) { // This is the normal exit from the lookup state machine. - // We have advanced through the string until it is certain that no - // longer match is possible, no matter what characters follow. + // Transistion to state zero means we have found a safe point. break; } - - // Move (backwards) to the next character to process. - // If this is a beginning-of-input loop iteration, don't advance - // the input position. The next iteration will be processing the - // first real input character. - if (mode == RBBI_RUN) { - c = UTEXT_PREVIOUS32(&fText); - } else { - if (mode == RBBI_START) { - mode = RBBI_RUN; - } - } } // The state machine is done. Check whether it found a match... - - // If the iterator failed to advance in the match engine, force it ahead by one. - // (This really indicates a defect in the break rules. They should always match - // at least one character.) - if (result == initialPosition) { - UTEXT_SETNATIVEINDEX(&fText, initialPosition); - UTEXT_PREVIOUS32(&fText); - result = (int32_t)UTEXT_GETNATIVEINDEX(&fText); - } - + result = (int32_t)UTEXT_GETNATIVEINDEX(&fText); #ifdef RBBI_DEBUG if (gTrace) { RBBIDebugPrintf("result = %d\n\n", result); @@ -1099,7 +1022,6 @@ int32_t RuleBasedBreakIterator::handlePrevious(int32_t fromPosition) { return result; } - //------------------------------------------------------------------------------- // // getRuleStatus() Return the break rule tag associated with the current diff --git a/deps/icu-small/source/common/rbbi_cache.cpp b/deps/icu-small/source/common/rbbi_cache.cpp index ba9329d477..60316ce642 100644 --- a/deps/icu-small/source/common/rbbi_cache.cpp +++ b/deps/icu-small/source/common/rbbi_cache.cpp @@ -354,14 +354,31 @@ UBool RuleBasedBreakIterator::BreakCache::populateNear(int32_t position, UErrorC if ((position < fBoundaries[fStartBufIdx] - 15) || position > (fBoundaries[fEndBufIdx] + 15)) { int32_t aBoundary = 0; int32_t ruleStatusIndex = 0; - // TODO: check for position == length of text. Although may still need to back up to get rule status. if (position > 20) { - int32_t backupPos = fBI->handlePrevious(position); - fBI->fPosition = backupPos; - aBoundary = fBI->handleNext(); // Ignore dictionary, just finding a rule based boundary. - ruleStatusIndex = fBI->fRuleStatusIndex; + int32_t backupPos = fBI->handleSafePrevious(position); + + if (backupPos > 0) { + // Advance to the boundary following the backup position. + // There is a complication: the safe reverse rules identify pairs of code points + // that are safe. If advancing from the safe point moves forwards by less than + // two code points, we need to advance one more time to ensure that the boundary + // is good, including a correct rules status value. + // + fBI->fPosition = backupPos; + aBoundary = fBI->handleNext(); + if (aBoundary <= backupPos + 4) { + // +4 is a quick test for possibly having advanced only one codepoint. + // Four being the length of the longest potential code point, a supplementary in UTF-8 + utext_setNativeIndex(&fBI->fText, aBoundary); + if (backupPos == utext_getPreviousNativeIndex(&fBI->fText)) { + // The initial handleNext() only advanced by a single code point. Go again. + aBoundary = fBI->handleNext(); // Safe rules identify safe pairs. + } + } + ruleStatusIndex = fBI->fRuleStatusIndex; + } } - reset(aBoundary, ruleStatusIndex); // Reset cache to hold aBoundary as a single starting point. + reset(aBoundary, ruleStatusIndex); // Reset cache to hold aBoundary as a single starting point. } // Fill in boundaries between existing cache content and the new requested position. @@ -485,16 +502,30 @@ UBool RuleBasedBreakIterator::BreakCache::populatePreceding(UErrorCode &status) if (backupPosition <= 0) { backupPosition = 0; } else { - backupPosition = fBI->handlePrevious(backupPosition); + backupPosition = fBI->handleSafePrevious(backupPosition); } if (backupPosition == UBRK_DONE || backupPosition == 0) { position = 0; positionStatusIdx = 0; } else { - fBI->fPosition = backupPosition; // TODO: pass starting position in a clearer way. + // Advance to the boundary following the backup position. + // There is a complication: the safe reverse rules identify pairs of code points + // that are safe. If advancing from the safe point moves forwards by less than + // two code points, we need to advance one more time to ensure that the boundary + // is good, including a correct rules status value. + // + fBI->fPosition = backupPosition; position = fBI->handleNext(); + if (position <= backupPosition + 4) { + // +4 is a quick test for possibly having advanced only one codepoint. + // Four being the length of the longest potential code point, a supplementary in UTF-8 + utext_setNativeIndex(&fBI->fText, position); + if (backupPosition == utext_getPreviousNativeIndex(&fBI->fText)) { + // The initial handleNext() only advanced by a single code point. Go again. + position = fBI->handleNext(); // Safe rules identify safe pairs. + } + }; positionStatusIdx = fBI->fRuleStatusIndex; - } } while (position >= fromPosition); diff --git a/deps/icu-small/source/common/rbbidata.cpp b/deps/icu-small/source/common/rbbidata.cpp index 18912a6a7b..fdcb564961 100644 --- a/deps/icu-small/source/common/rbbidata.cpp +++ b/deps/icu-small/source/common/rbbidata.cpp @@ -81,8 +81,6 @@ void RBBIDataWrapper::init0() { fHeader = NULL; fForwardTable = NULL; fReverseTable = NULL; - fSafeFwdTable = NULL; - fSafeRevTable = NULL; fRuleSource = NULL; fRuleStatusTable = NULL; fTrie = NULL; @@ -111,21 +109,6 @@ void RBBIDataWrapper::init(const RBBIDataHeader *data, UErrorCode &status) { if (data->fRTableLen != 0) { fReverseTable = (RBBIStateTable *)((char *)data + fHeader->fRTable); } - if (data->fSFTableLen != 0) { - fSafeFwdTable = (RBBIStateTable *)((char *)data + fHeader->fSFTable); - } - if (data->fSRTableLen != 0) { - fSafeRevTable = (RBBIStateTable *)((char *)data + fHeader->fSRTable); - } - - // Rule Compatibility Hacks - // If a rule set includes reverse rules but does not explicitly include safe reverse rules, - // the reverse rules are to be treated as safe reverse rules. - - if (fSafeRevTable == NULL && fReverseTable != NULL) { - fSafeRevTable = fReverseTable; - fReverseTable = NULL; - } fTrie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS, (uint8_t *)data + fHeader->fTrie, @@ -277,8 +260,6 @@ void RBBIDataWrapper::printData() { printTable("Forward State Transition Table", fForwardTable); printTable("Reverse State Transition Table", fReverseTable); - printTable("Safe Forward State Transition Table", fSafeFwdTable); - printTable("Safe Reverse State Transition Table", fSafeRevTable); RBBIDebugPrintf("\nOrignal Rules source:\n"); for (int32_t c=0; fRuleSource[c] != 0; c++) { @@ -418,28 +399,6 @@ ubrk_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outD outBytes+tableStartOffset+topSize, status); } - // Safe Forward state table. Same layout as forward table, above. - tableStartOffset = ds->readUInt32(rbbiDH->fSFTable); - tableLength = ds->readUInt32(rbbiDH->fSFTableLen); - - if (tableLength > 0) { - ds->swapArray32(ds, inBytes+tableStartOffset, topSize, - outBytes+tableStartOffset, status); - ds->swapArray16(ds, inBytes+tableStartOffset+topSize, tableLength-topSize, - outBytes+tableStartOffset+topSize, status); - } - - // Safe Reverse state table. Same layout as forward table, above. - tableStartOffset = ds->readUInt32(rbbiDH->fSRTable); - tableLength = ds->readUInt32(rbbiDH->fSRTableLen); - - if (tableLength > 0) { - ds->swapArray32(ds, inBytes+tableStartOffset, topSize, - outBytes+tableStartOffset, status); - ds->swapArray16(ds, inBytes+tableStartOffset+topSize, tableLength-topSize, - outBytes+tableStartOffset+topSize, status); - } - // Trie table for character categories utrie2_swap(ds, inBytes+ds->readUInt32(rbbiDH->fTrie), ds->readUInt32(rbbiDH->fTrieLen), outBytes+ds->readUInt32(rbbiDH->fTrie), status); diff --git a/deps/icu-small/source/common/rbbidata.h b/deps/icu-small/source/common/rbbidata.h index 8b21acca30..3e573039d0 100644 --- a/deps/icu-small/source/common/rbbidata.h +++ b/deps/icu-small/source/common/rbbidata.h @@ -58,7 +58,7 @@ ubrk_swap(const UDataSwapper *ds, U_NAMESPACE_BEGIN // The current RBBI data format version. -static const uint8_t RBBI_DATA_FORMAT_VERSION[] = {4, 0, 0, 0}; +static const uint8_t RBBI_DATA_FORMAT_VERSION[] = {5, 0, 0, 0}; /* * The following structs map exactly onto the raw data from ICU common data file. @@ -81,10 +81,6 @@ struct RBBIDataHeader { uint32_t fFTableLen; uint32_t fRTable; /* Offset to the reverse state transition table. */ uint32_t fRTableLen; - uint32_t fSFTable; /* safe point forward transition table */ - uint32_t fSFTableLen; - uint32_t fSRTable; /* safe point reverse transition table */ - uint32_t fSRTableLen; uint32_t fTrie; /* Offset to Trie data for character categories */ uint32_t fTrieLen; uint32_t fRuleSource; /* Offset to the source for for the break */ @@ -174,8 +170,6 @@ public: const RBBIDataHeader *fHeader; const RBBIStateTable *fForwardTable; const RBBIStateTable *fReverseTable; - const RBBIStateTable *fSafeFwdTable; - const RBBIStateTable *fSafeRevTable; const UChar *fRuleSource; const int32_t *fRuleStatusTable; diff --git a/deps/icu-small/source/common/rbbirb.cpp b/deps/icu-small/source/common/rbbirb.cpp index 9fc8f8e814..a46f483d23 100644 --- a/deps/icu-small/source/common/rbbirb.cpp +++ b/deps/icu-small/source/common/rbbirb.cpp @@ -62,10 +62,7 @@ RBBIRuleBuilder::RBBIRuleBuilder(const UnicodeString &rules, fSafeFwdTree = NULL; fSafeRevTree = NULL; fDefaultTree = &fForwardTree; - fForwardTables = NULL; - fReverseTables = NULL; - fSafeFwdTables = NULL; - fSafeRevTables = NULL; + fForwardTable = NULL; fRuleStatusVals = NULL; fChainRules = FALSE; fLBCMNoChain = FALSE; @@ -114,11 +111,7 @@ RBBIRuleBuilder::~RBBIRuleBuilder() { delete fUSetNodes; delete fSetBuilder; - delete fForwardTables; - delete fReverseTables; - delete fSafeFwdTables; - delete fSafeRevTables; - + delete fForwardTable; delete fForwardTree; delete fReverseTree; delete fSafeFwdTree; @@ -157,21 +150,15 @@ RBBIDataHeader *RBBIRuleBuilder::flattenData() { // without the padding. // int32_t headerSize = align8(sizeof(RBBIDataHeader)); - int32_t forwardTableSize = align8(fForwardTables->getTableSize()); - int32_t reverseTableSize = align8(fReverseTables->getTableSize()); - int32_t safeFwdTableSize = align8(fSafeFwdTables->getTableSize()); - int32_t safeRevTableSize = align8(fSafeRevTables->getTableSize()); + int32_t forwardTableSize = align8(fForwardTable->getTableSize()); + int32_t reverseTableSize = align8(fForwardTable->getSafeTableSize()); int32_t trieSize = align8(fSetBuilder->getTrieSize()); int32_t statusTableSize = align8(fRuleStatusVals->size() * sizeof(int32_t)); int32_t rulesSize = align8((fStrippedRules.length()+1) * sizeof(UChar)); - (void)safeFwdTableSize; - int32_t totalSize = headerSize + forwardTableSize - + /* reverseTableSize */ 0 - + /* safeFwdTableSize */ 0 - + (safeRevTableSize ? safeRevTableSize : reverseTableSize) + + reverseTableSize + statusTableSize + trieSize + rulesSize; RBBIDataHeader *data = (RBBIDataHeader *)uprv_malloc(totalSize); @@ -190,38 +177,13 @@ RBBIDataHeader *RBBIRuleBuilder::flattenData() { data->fLength = totalSize; data->fCatCount = fSetBuilder->getNumCharCategories(); - // Only save the forward table and the safe reverse table, - // because these are the only ones used at run-time. - // - // For the moment, we still build the other tables if they are present in the rule source files, - // for backwards compatibility. Old rule files need to work, and this is the simplest approach. - // - // Additional backwards compatibility consideration: if no safe rules are provided, consider the - // reverse rules to actually be the safe reverse rules. - data->fFTable = headerSize; data->fFTableLen = forwardTableSize; - // Do not save Reverse Table. - data->fRTable = data->fFTable + forwardTableSize; - data->fRTableLen = 0; - - // Do not save the Safe Forward table. - data->fSFTable = data->fRTable + 0; - data->fSFTableLen = 0; - - data->fSRTable = data->fSFTable + 0; - if (safeRevTableSize > 0) { - data->fSRTableLen = safeRevTableSize; - } else if (reverseTableSize > 0) { - data->fSRTableLen = reverseTableSize; - } else { - U_ASSERT(FALSE); // Rule build should have failed for lack of a reverse table - // before reaching this point. - } - + data->fRTable = data->fFTable + data->fFTableLen; + data->fRTableLen = reverseTableSize; - data->fTrie = data->fSRTable + data->fSRTableLen; + data->fTrie = data->fRTable + data->fRTableLen; data->fTrieLen = fSetBuilder->getTrieSize(); data->fStatusTable = data->fTrie + trieSize; data->fStatusTableLen= statusTableSize; @@ -230,15 +192,8 @@ RBBIDataHeader *RBBIRuleBuilder::flattenData() { uprv_memset(data->fReserved, 0, sizeof(data->fReserved)); - fForwardTables->exportTable((uint8_t *)data + data->fFTable); - // fReverseTables->exportTable((uint8_t *)data + data->fRTable); - // fSafeFwdTables->exportTable((uint8_t *)data + data->fSFTable); - if (safeRevTableSize > 0) { - fSafeRevTables->exportTable((uint8_t *)data + data->fSRTable); - } else { - fReverseTables->exportTable((uint8_t *)data + data->fSRTable); - } - + fForwardTable->exportTable((uint8_t *)data + data->fFTable); + fForwardTable->exportSafeTable((uint8_t *)data + data->fRTable); fSetBuilder->serializeTrie ((uint8_t *)data + data->fTrie); int32_t *ruleStatusTable = (int32_t *)((uint8_t *)data + data->fStatusTable); @@ -252,10 +207,6 @@ RBBIDataHeader *RBBIRuleBuilder::flattenData() { } - - - - //---------------------------------------------------------------------------------------- // // createRuleBasedBreakIterator construct from source rules that are passed in @@ -267,8 +218,6 @@ RBBIRuleBuilder::createRuleBasedBreakIterator( const UnicodeString &rules, UParseError *parseError, UErrorCode &status) { - // status checked below - // // Read the input rules, generate a parse tree, symbol table, // and list of all Unicode Sets referenced by the rules. @@ -277,7 +226,38 @@ RBBIRuleBuilder::createRuleBasedBreakIterator( const UnicodeString &rules, if (U_FAILURE(status)) { // status checked here bcos build below doesn't return NULL; } - builder.fScanner->parse(); + + RBBIDataHeader *data = builder.build(status); + + if (U_FAILURE(status)) { + return nullptr; + } + + // + // Create a break iterator from the compiled rules. + // (Identical to creation from stored pre-compiled rules) + // + // status is checked after init in construction. + RuleBasedBreakIterator *This = new RuleBasedBreakIterator(data, status); + if (U_FAILURE(status)) { + delete This; + This = NULL; + } + else if(This == NULL) { // test for NULL + status = U_MEMORY_ALLOCATION_ERROR; + } + return This; +} + +RBBIDataHeader *RBBIRuleBuilder::build(UErrorCode &status) { + if (U_FAILURE(status)) { + return nullptr; + } + + fScanner->parse(); + if (U_FAILURE(status)) { + return nullptr; + } // // UnicodeSet processing. @@ -285,95 +265,55 @@ RBBIRuleBuilder::createRuleBasedBreakIterator( const UnicodeString &rules, // Generate the mapping tables (TRIE) from input code points to // the character categories. // - builder.fSetBuilder->buildRanges(); - + fSetBuilder->buildRanges(); // // Generate the DFA state transition table. // - builder.fForwardTables = new RBBITableBuilder(&builder, &builder.fForwardTree); - builder.fReverseTables = new RBBITableBuilder(&builder, &builder.fReverseTree); - builder.fSafeFwdTables = new RBBITableBuilder(&builder, &builder.fSafeFwdTree); - builder.fSafeRevTables = new RBBITableBuilder(&builder, &builder.fSafeRevTree); - if (builder.fForwardTables == NULL || builder.fReverseTables == NULL || - builder.fSafeFwdTables == NULL || builder.fSafeRevTables == NULL) - { + fForwardTable = new RBBITableBuilder(this, &fForwardTree, status); + if (fForwardTable == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; - delete builder.fForwardTables; builder.fForwardTables = NULL; - delete builder.fReverseTables; builder.fReverseTables = NULL; - delete builder.fSafeFwdTables; builder.fSafeFwdTables = NULL; - delete builder.fSafeRevTables; builder.fSafeRevTables = NULL; - return NULL; + return nullptr; } - builder.fForwardTables->build(); - builder.fReverseTables->build(); - builder.fSafeFwdTables->build(); - builder.fSafeRevTables->build(); + fForwardTable->buildForwardTable(); + optimizeTables(); + fForwardTable->buildSafeReverseTable(status); + #ifdef RBBI_DEBUG - if (builder.fDebugEnv && uprv_strstr(builder.fDebugEnv, "states")) { - builder.fForwardTables->printRuleStatusTable(); + if (fDebugEnv && uprv_strstr(fDebugEnv, "states")) { + fForwardTable->printStates(); + fForwardTable->printRuleStatusTable(); + fForwardTable->printReverseTable(); } #endif - builder.optimizeTables(); - builder.fSetBuilder->buildTrie(); - - + fSetBuilder->buildTrie(); // // Package up the compiled data into a memory image // in the run-time format. // - RBBIDataHeader *data = builder.flattenData(); // returns NULL if error - if (U_FAILURE(*builder.fStatus)) { - return NULL; - } - - - // - // Clean up the compiler related stuff - // - - - // - // Create a break iterator from the compiled rules. - // (Identical to creation from stored pre-compiled rules) - // - // status is checked after init in construction. - RuleBasedBreakIterator *This = new RuleBasedBreakIterator(data, status); + RBBIDataHeader *data = flattenData(); // returns NULL if error if (U_FAILURE(status)) { - delete This; - This = NULL; + return nullptr; } - else if(This == NULL) { // test for NULL - status = U_MEMORY_ALLOCATION_ERROR; - } - return This; + return data; } void RBBIRuleBuilder::optimizeTables() { - int32_t leftClass; - int32_t rightClass; - - leftClass = 3; - rightClass = 0; - while (fForwardTables->findDuplCharClassFrom(leftClass, rightClass)) { - fSetBuilder->mergeCategories(leftClass, rightClass); - fForwardTables->removeColumn(rightClass); - fReverseTables->removeColumn(rightClass); - fSafeFwdTables->removeColumn(rightClass); - fSafeRevTables->removeColumn(rightClass); - } - - fForwardTables->removeDuplicateStates(); - fReverseTables->removeDuplicateStates(); - fSafeFwdTables->removeDuplicateStates(); - fSafeRevTables->removeDuplicateStates(); - + // Begin looking for duplicates with char class 3. + // Classes 0, 1 and 2 are special; they are unused, {bof} and {eof} respectively, + // and should not have other categories merged into them. + IntPair duplPair = {3, 0}; + while (fForwardTable->findDuplCharClassFrom(&duplPair)) { + fSetBuilder->mergeCategories(duplPair); + fForwardTable->removeColumn(duplPair.second); + } + fForwardTable->removeDuplicateStates(); } U_NAMESPACE_END diff --git a/deps/icu-small/source/common/rbbirb.h b/deps/icu-small/source/common/rbbirb.h index 511f394b45..37992daabb 100644 --- a/deps/icu-small/source/common/rbbirb.h +++ b/deps/icu-small/source/common/rbbirb.h @@ -18,6 +18,8 @@ #if !UCONFIG_NO_BREAK_ITERATION +#include + #include "unicode/uobject.h" #include "unicode/rbbi.h" #include "unicode/uniset.h" @@ -25,8 +27,7 @@ #include "uhash.h" #include "uvector.h" #include "unicode/symtable.h"// For UnicodeSet parsing, is the interface that - // looks up references to $variables within a set. - + // looks up references to $variables within a set. U_NAMESPACE_BEGIN @@ -123,10 +124,16 @@ public: RBBIRuleBuilder(const UnicodeString &rules, UParseError *parseErr, UErrorCode &status - ); + ); virtual ~RBBIRuleBuilder(); + /** + * Build the state tables and char class Trie from the source rules. + */ + RBBIDataHeader *build(UErrorCode &status); + + /** * Fold together redundant character classes (table columns) and * redundant states (table rows). Done after initial table generation, @@ -162,10 +169,7 @@ public: RBBISetBuilder *fSetBuilder; // Set and Character Category builder. UVector *fUSetNodes; // Vector of all uset nodes. - RBBITableBuilder *fForwardTables; // State transition tables - RBBITableBuilder *fReverseTables; - RBBITableBuilder *fSafeFwdTables; - RBBITableBuilder *fSafeRevTables; + RBBITableBuilder *fForwardTable; // State transition table, build time form. UVector *fRuleStatusVals; // The values that can be returned // from getRuleStatus(). @@ -200,6 +204,11 @@ struct RBBISetTableEl { RBBINode *val; }; +/** + * A pair of ints, used to bundle pairs of states or pairs of character classes. + */ +typedef std::pair IntPair; + //---------------------------------------------------------------------------- // diff --git a/deps/icu-small/source/common/rbbiscan.cpp b/deps/icu-small/source/common/rbbiscan.cpp index e3472ed599..ecc1663d8f 100644 --- a/deps/icu-small/source/common/rbbiscan.cpp +++ b/deps/icu-small/source/common/rbbiscan.cpp @@ -372,7 +372,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action) // (forward, reverse, safe_forward, safe_reverse) // OR this rule into the appropriate group of them. // - RBBINode **destRules = (fReverseRule? &fRB->fReverseTree : fRB->fDefaultTree); + RBBINode **destRules = (fReverseRule? &fRB->fSafeRevTree : fRB->fDefaultTree); if (*destRules != NULL) { // This is not the first rule encounted. @@ -1122,22 +1122,6 @@ void RBBIRuleScanner::parse() { return; } - // - // If there were NO user specified reverse rules, set up the equivalent of ".*;" - // - if (fRB->fReverseTree == NULL) { - fRB->fReverseTree = pushNewNode(RBBINode::opStar); - RBBINode *operand = pushNewNode(RBBINode::setRef); - if (U_FAILURE(*fRB->fStatus)) { - return; - } - findSetFor(UnicodeString(TRUE, kAny, 3), operand); - fRB->fReverseTree->fLeftChild = operand; - operand->fParent = fRB->fReverseTree; - fNodeStackPtr -= 2; - } - - // // Parsing of the input RBBI rules is complete. // We now have a parse tree for the rule expressions diff --git a/deps/icu-small/source/common/rbbisetb.cpp b/deps/icu-small/source/common/rbbisetb.cpp index 4e7389b4af..e6b98cf3e2 100644 --- a/deps/icu-small/source/common/rbbisetb.cpp +++ b/deps/icu-small/source/common/rbbisetb.cpp @@ -270,15 +270,15 @@ void RBBISetBuilder::buildTrie() { } -void RBBISetBuilder::mergeCategories(int32_t left, int32_t right) { - U_ASSERT(left >= 1); - U_ASSERT(right > left); +void RBBISetBuilder::mergeCategories(IntPair categories) { + U_ASSERT(categories.first >= 1); + U_ASSERT(categories.second > categories.first); for (RangeDescriptor *rd = fRangeList; rd != nullptr; rd = rd->fNext) { int32_t rangeNum = rd->fNum & ~DICT_BIT; int32_t rangeDict = rd->fNum & DICT_BIT; - if (rangeNum == right) { - rd->fNum = left | rangeDict; - } else if (rangeNum > right) { + if (rangeNum == categories.second) { + rd->fNum = categories.first | rangeDict; + } else if (rangeNum > categories.second) { rd->fNum--; } } diff --git a/deps/icu-small/source/common/rbbisetb.h b/deps/icu-small/source/common/rbbisetb.h index a7a91b3b37..ed6a76b121 100644 --- a/deps/icu-small/source/common/rbbisetb.h +++ b/deps/icu-small/source/common/rbbisetb.h @@ -94,10 +94,12 @@ public: UChar32 getFirstChar(int32_t val) const; UBool sawBOF() const; // Indicate whether any references to the {bof} pseudo // character were encountered. - /** merge two character categories that have been identified as having equivalent behavior. - * The ranges belonging to the right category (table column) will be added to the left. + /** + * Merge two character categories that have been identified as having equivalent behavior. + * The ranges belonging to the second category (table column) will be added to the first. + * @param categories the pair of categories to be merged. */ - void mergeCategories(int32_t left, int32_t right); + void mergeCategories(IntPair categories); static constexpr int32_t DICT_BIT = 0x4000; diff --git a/deps/icu-small/source/common/rbbitblb.cpp b/deps/icu-small/source/common/rbbitblb.cpp index 61661a5442..42116b0f95 100644 --- a/deps/icu-small/source/common/rbbitblb.cpp +++ b/deps/icu-small/source/common/rbbitblb.cpp @@ -27,21 +27,19 @@ U_NAMESPACE_BEGIN -RBBITableBuilder::RBBITableBuilder(RBBIRuleBuilder *rb, RBBINode **rootNode) : - fTree(*rootNode) { - fRB = rb; - fStatus = fRB->fStatus; - UErrorCode status = U_ZERO_ERROR; - fDStates = new UVector(status); - if (U_FAILURE(*fStatus)) { - return; - } +RBBITableBuilder::RBBITableBuilder(RBBIRuleBuilder *rb, RBBINode **rootNode, UErrorCode &status) : + fRB(rb), + fTree(*rootNode), + fStatus(&status), + fDStates(nullptr), + fSafeTable(nullptr) { if (U_FAILURE(status)) { - *fStatus = status; return; } - if (fDStates == NULL) { - *fStatus = U_MEMORY_ALLOCATION_ERROR;; + // fDStates is UVector + fDStates = new UVector(status); + if (U_SUCCESS(status) && fDStates == nullptr ) { + status = U_MEMORY_ALLOCATION_ERROR; } } @@ -52,17 +50,18 @@ RBBITableBuilder::~RBBITableBuilder() { for (i=0; isize(); i++) { delete (RBBIStateDescriptor *)fDStates->elementAt(i); } - delete fDStates; + delete fDStates; + delete fSafeTable; } //----------------------------------------------------------------------------- // -// RBBITableBuilder::build - This is the main function for building the DFA state transtion -// table from the RBBI rules parse tree. +// RBBITableBuilder::buildForwardTable - This is the main function for building +// the DFA state transition table from the RBBI rules parse tree. // //----------------------------------------------------------------------------- -void RBBITableBuilder::build() { +void RBBITableBuilder::buildForwardTable() { if (U_FAILURE(*fStatus)) { return; @@ -189,8 +188,6 @@ void RBBITableBuilder::build() { // for all tables. Merge the ones from this table into the global set. // mergeRuleStatusVals(); - - if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "states")) {printStates();}; } @@ -1081,18 +1078,18 @@ void RBBITableBuilder::printPosSets(RBBINode *n) { // // findDuplCharClassFrom() // -bool RBBITableBuilder::findDuplCharClassFrom(int32_t &baseCategory, int32_t &duplCategory) { +bool RBBITableBuilder::findDuplCharClassFrom(IntPair *categories) { int32_t numStates = fDStates->size(); int32_t numCols = fRB->fSetBuilder->getNumCharCategories(); uint16_t table_base; uint16_t table_dupl; - for (; baseCategory < numCols-1; ++baseCategory) { - for (duplCategory=baseCategory+1; duplCategory < numCols; ++duplCategory) { + for (; categories->first < numCols-1; categories->first++) { + for (categories->second=categories->first+1; categories->second < numCols; categories->second++) { for (int32_t state=0; stateelementAt(state); - table_base = (uint16_t)sd->fDtran->elementAti(baseCategory); - table_dupl = (uint16_t)sd->fDtran->elementAti(duplCategory); + table_base = (uint16_t)sd->fDtran->elementAti(categories->first); + table_dupl = (uint16_t)sd->fDtran->elementAti(categories->second); if (table_base != table_dupl) { break; } @@ -1121,14 +1118,14 @@ void RBBITableBuilder::removeColumn(int32_t column) { /* * findDuplicateState */ -bool RBBITableBuilder::findDuplicateState(int32_t &firstState, int32_t &duplState) { +bool RBBITableBuilder::findDuplicateState(IntPair *states) { int32_t numStates = fDStates->size(); int32_t numCols = fRB->fSetBuilder->getNumCharCategories(); - for (; firstStateelementAt(firstState); - for (duplState=firstState+1; duplStateelementAt(duplState); + for (; states->firstfirst++) { + RBBIStateDescriptor *firstSD = (RBBIStateDescriptor *)fDStates->elementAt(states->first); + for (states->second=states->first+1; states->secondsecond++) { + RBBIStateDescriptor *duplSD = (RBBIStateDescriptor *)fDStates->elementAt(states->second); if (firstSD->fAccepting != duplSD->fAccepting || firstSD->fLookAhead != duplSD->fLookAhead || firstSD->fTagsIdx != duplSD->fTagsIdx) { @@ -1139,8 +1136,36 @@ bool RBBITableBuilder::findDuplicateState(int32_t &firstState, int32_t &duplStat int32_t firstVal = firstSD->fDtran->elementAti(col); int32_t duplVal = duplSD->fDtran->elementAti(col); if (!((firstVal == duplVal) || - ((firstVal == firstState || firstVal == duplState) && - (duplVal == firstState || duplVal == duplState)))) { + ((firstVal == states->first || firstVal == states->second) && + (duplVal == states->first || duplVal == states->second)))) { + rowsMatch = false; + break; + } + } + if (rowsMatch) { + return true; + } + } + } + return false; +} + + +bool RBBITableBuilder::findDuplicateSafeState(IntPair *states) { + int32_t numStates = fSafeTable->size(); + + for (; states->firstfirst++) { + UnicodeString *firstRow = static_cast(fSafeTable->elementAt(states->first)); + for (states->second=states->first+1; states->secondsecond++) { + UnicodeString *duplRow = static_cast(fSafeTable->elementAt(states->second)); + bool rowsMatch = true; + int32_t numCols = firstRow->length(); + for (int32_t col=0; col < numCols; ++col) { + int32_t firstVal = firstRow->charAt(col); + int32_t duplVal = duplRow->charAt(col); + if (!((firstVal == duplVal) || + ((firstVal == states->first || firstVal == states->second) && + (duplVal == states->first || duplVal == states->second)))) { rowsMatch = false; break; } @@ -1153,7 +1178,10 @@ bool RBBITableBuilder::findDuplicateState(int32_t &firstState, int32_t &duplStat return false; } -void RBBITableBuilder::removeState(int32_t keepState, int32_t duplState) { + +void RBBITableBuilder::removeState(IntPair duplStates) { + const int32_t keepState = duplStates.first; + const int32_t duplState = duplStates.second; U_ASSERT(keepState < duplState); U_ASSERT(duplState < fDStates->size()); @@ -1188,19 +1216,44 @@ void RBBITableBuilder::removeState(int32_t keepState, int32_t duplState) { } } +void RBBITableBuilder::removeSafeState(IntPair duplStates) { + const int32_t keepState = duplStates.first; + const int32_t duplState = duplStates.second; + U_ASSERT(keepState < duplState); + U_ASSERT(duplState < fSafeTable->size()); + + fSafeTable->removeElementAt(duplState); // Note that fSafeTable has a deleter function + // and will auto-delete the removed element. + int32_t numStates = fSafeTable->size(); + for (int32_t state=0; stateelementAt(state); + int32_t numCols = sd->length(); + for (int32_t col=0; colcharAt(col); + int32_t newVal = existingVal; + if (existingVal == duplState) { + newVal = keepState; + } else if (existingVal > duplState) { + newVal = existingVal - 1; + } + sd->setCharAt(col, newVal); + } + } +} + /* * RemoveDuplicateStates */ void RBBITableBuilder::removeDuplicateStates() { - int32_t firstState = 3; - int32_t duplicateState = 0; - while (findDuplicateState(firstState, duplicateState)) { - // printf("Removing duplicate states (%d, %d)\n", firstState, duplicateState); - removeState(firstState, duplicateState); + IntPair dupls = {3, 0}; + while (findDuplicateState(&dupls)) { + // printf("Removing duplicate states (%d, %d)\n", dupls.first, dupls.second); + removeState(dupls); } } + //----------------------------------------------------------------------------- // // getTableSize() Calculate the size of the runtime form of this @@ -1277,6 +1330,185 @@ void RBBITableBuilder::exportTable(void *where) { } +/** + * Synthesize a safe state table from the main state table. + */ +void RBBITableBuilder::buildSafeReverseTable(UErrorCode &status) { + // The safe table creation has three steps: + + // 1. Identifiy pairs of character classes that are "safe." Safe means that boundaries + // following the pair do not depend on context or state before the pair. To test + // whether a pair is safe, run it through the main forward state table, starting + // from each state. If the the final state is the same, no matter what the starting state, + // the pair is safe. + // + // 2. Build a state table that recognizes the safe pairs. It's similar to their + // forward table, with a column for each input character [class], and a row for + // each state. Row 1 is the start state, and row 0 is the stop state. Initially + // create an additional state for each input character category; being in + // one of these states means that the character has been seen, and is potentially + // the first of a pair. In each of these rows, the entry for the second character + // of a safe pair is set to the stop state (0), indicating that a match was found. + // All other table entries are set to the state corresponding the current input + // character, allowing that charcter to be the of a start following pair. + // + // Because the safe rules are to be run in reverse, moving backwards in the text, + // the first and second pair categories are swapped when building the table. + // + // 3. Compress the table. There are typically many rows (states) that are + // equivalent - that have zeroes (match completed) in the same columns - + // and can be folded together. + + // Each safe pair is stored as two UChars in the safePair string. + UnicodeString safePairs; + + int32_t numCharClasses = fRB->fSetBuilder->getNumCharCategories(); + int32_t numStates = fDStates->size(); + + for (int32_t c1=0; c1(fDStates->elementAt(startState)); + int32_t s2 = startStateD->fDtran->elementAti(c1); + RBBIStateDescriptor *s2StateD = static_cast(fDStates->elementAt(s2)); + endState = s2StateD->fDtran->elementAti(c2); + if (wantedEndState < 0) { + wantedEndState = endState; + } else { + if (wantedEndState != endState) { + break; + } + } + } + if (wantedEndState == endState) { + safePairs.append((char16_t)c1); + safePairs.append((char16_t)c2); + // printf("(%d, %d) ", c1, c2); + } + } + // printf("\n"); + } + + // Populate the initial safe table. + // The table as a whole is UVector + // Each row is represented by a UnicodeString, being used as a Vector. + // Row 0 is the stop state. + // Row 1 is the start sate. + // Row 2 and beyond are other states, initially one per char class, but + // after initial construction, many of the states will be combined, compacting the table. + // The String holds the nextState data only. The four leading fields of a row, fAccepting, + // fLookAhead, etc. are not needed for the safe table, and are omitted at this stage of building. + + U_ASSERT(fSafeTable == nullptr); + fSafeTable = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, numCharClasses + 2, status); + for (int32_t row=0; rowaddElement(new UnicodeString(numCharClasses, 0, numCharClasses+4), status); + } + + // From the start state, each input char class transitions to the state for that input. + UnicodeString &startState = *static_cast(fSafeTable->elementAt(1)); + for (int32_t charClass=0; charClass < numCharClasses; ++charClass) { + // Note: +2 for the start & stop state. + startState.setCharAt(charClass, charClass+2); + } + + // Initially make every other state table row look like the start state row, + for (int32_t row=2; row(fSafeTable->elementAt(row)); + rowState = startState; // UnicodeString assignment, copies contents. + } + + // Run through the safe pairs, set the next state to zero when pair has been seen. + // Zero being the stop state, meaning we found a safe point. + for (int32_t pairIdx=0; pairIdx(fSafeTable->elementAt(c2 + 2)); + rowState.setCharAt(c1, 0); + } + + // Remove duplicate or redundant rows from the table. + IntPair states = {1, 0}; + while (findDuplicateSafeState(&states)) { + // printf("Removing duplicate safe states (%d, %d)\n", states.first, states.second); + removeSafeState(states); + } +} + + +//----------------------------------------------------------------------------- +// +// getSafeTableSize() Calculate the size of the runtime form of this +// safe state table. +// +//----------------------------------------------------------------------------- +int32_t RBBITableBuilder::getSafeTableSize() const { + int32_t size = 0; + int32_t numRows; + int32_t numCols; + int32_t rowSize; + + if (fSafeTable == nullptr) { + return 0; + } + + size = offsetof(RBBIStateTable, fTableData); // The header, with no rows to the table. + + numRows = fSafeTable->size(); + numCols = fRB->fSetBuilder->getNumCharCategories(); + + rowSize = offsetof(RBBIStateTableRow, fNextState) + sizeof(uint16_t)*numCols; + size += numRows * rowSize; + return size; +} + + +//----------------------------------------------------------------------------- +// +// exportSafeTable() export the state transition table in the format required +// by the runtime engine. getTableSize() bytes of memory +// must be available at the output address "where". +// +//----------------------------------------------------------------------------- +void RBBITableBuilder::exportSafeTable(void *where) { + RBBIStateTable *table = (RBBIStateTable *)where; + uint32_t state; + int col; + + if (U_FAILURE(*fStatus) || fSafeTable == nullptr) { + return; + } + + int32_t catCount = fRB->fSetBuilder->getNumCharCategories(); + if (catCount > 0x7fff || + fSafeTable->size() > 0x7fff) { + *fStatus = U_BRK_INTERNAL_ERROR; + return; + } + + table->fRowLen = offsetof(RBBIStateTableRow, fNextState) + sizeof(uint16_t) * catCount; + table->fNumStates = fSafeTable->size(); + table->fFlags = 0; + table->fReserved = 0; + + for (state=0; statefNumStates; state++) { + UnicodeString *rowString = (UnicodeString *)fSafeTable->elementAt(state); + RBBIStateTableRow *row = (RBBIStateTableRow *)(table->fTableData + state*table->fRowLen); + row->fAccepting = 0; + row->fLookAhead = 0; + row->fTagIdx = 0; + row->fReserved = 0; + for (col=0; colfNextState[col] = rowString->charAt(col); + } + } +} + + + //----------------------------------------------------------------------------- // @@ -1331,6 +1563,47 @@ void RBBITableBuilder::printStates() { #endif +//----------------------------------------------------------------------------- +// +// printSafeTable Debug Function. Dump the fully constructed safe table. +// +//----------------------------------------------------------------------------- +#ifdef RBBI_DEBUG +void RBBITableBuilder::printReverseTable() { + int c; // input "character" + int n; // state number + + RBBIDebugPrintf(" Safe Reverse Table \n"); + if (fSafeTable == nullptr) { + RBBIDebugPrintf(" --- nullptr ---\n"); + return; + } + RBBIDebugPrintf("state | i n p u t s y m b o l s \n"); + RBBIDebugPrintf(" | Acc LA Tag"); + for (c=0; cfSetBuilder->getNumCharCategories(); c++) { + RBBIDebugPrintf(" %2d", c); + } + RBBIDebugPrintf("\n"); + RBBIDebugPrintf(" |---------------"); + for (c=0; cfSetBuilder->getNumCharCategories(); c++) { + RBBIDebugPrintf("---"); + } + RBBIDebugPrintf("\n"); + + for (n=0; nsize(); n++) { + UnicodeString *rowString = (UnicodeString *)fSafeTable->elementAt(n); + RBBIDebugPrintf(" %3d | " , n); + RBBIDebugPrintf("%3d %3d %5d ", 0, 0, 0); // Accepting, LookAhead, Tags + for (c=0; cfSetBuilder->getNumCharCategories(); c++) { + RBBIDebugPrintf(" %2d", rowString->charAt(c)); + } + RBBIDebugPrintf("\n"); + } + RBBIDebugPrintf("\n\n"); +} +#endif + + //----------------------------------------------------------------------------- // diff --git a/deps/icu-small/source/common/rbbitblb.h b/deps/icu-small/source/common/rbbitblb.h index 09b57b5cf0..eea243e4cd 100644 --- a/deps/icu-small/source/common/rbbitblb.h +++ b/deps/icu-small/source/common/rbbitblb.h @@ -17,6 +17,7 @@ #include "unicode/utypes.h" #include "unicode/uobject.h" #include "unicode/rbbi.h" +#include "rbbirb.h" #include "rbbinode.h" @@ -37,22 +38,28 @@ class UVector32; class RBBITableBuilder : public UMemory { public: - RBBITableBuilder(RBBIRuleBuilder *rb, RBBINode **rootNode); + RBBITableBuilder(RBBIRuleBuilder *rb, RBBINode **rootNode, UErrorCode &status); ~RBBITableBuilder(); - void build(); - int32_t getTableSize() const; // Return the runtime size in bytes of - // the built state table + void buildForwardTable(); + + /** Return the runtime size in bytes of the built state table. */ + int32_t getTableSize() const; /** Fill in the runtime state table. Sufficient memory must exist at the specified location. */ void exportTable(void *where); - /** Find duplicate (redundant) character classes, beginning after the specifed - * pair, within this state table. This is an iterator-like function, used to - * identify char classes (state table columns) that can be eliminated. + /** + * Find duplicate (redundant) character classes. Begin looking with categories.first. + * Duplicate, if found are returned in the categories parameter. + * This is an iterator-like function, used to identify character classes + * (state table columns) that can be eliminated. + * @param categories in/out parameter, specifies where to start looking for duplicates, + * and returns the first pair of duplicates found, if any. + * @return true if duplicate char classes were found, false otherwise. */ - bool findDuplCharClassFrom(int &baseClass, int &duplClass); + bool findDuplCharClassFrom(IntPair *categories); /** Remove a column from the state table. Used when two character categories * have been found equivalent, and merged together, to eliminate the uneeded table column. @@ -62,6 +69,16 @@ public: /** Check for, and remove dupicate states (table rows). */ void removeDuplicateStates(); + /** Build the safe reverse table from the already-constructed forward table. */ + void buildSafeReverseTable(UErrorCode &status); + + /** Return the runtime size in bytes of the built safe reverse state table. */ + int32_t getSafeTableSize() const; + + /** Fill in the runtime safe state table. Sufficient memory must exist at the specified location. + */ + void exportSafeTable(void *where); + private: void calcNullable(RBBINode *n); @@ -84,20 +101,36 @@ private: void addRuleRootNodes(UVector *dest, RBBINode *node); - /** Find the next duplicate state. An iterator function. - * @param firstState (in/out) begin looking at this state, return the first of the - * pair of duplicates. - * @param duplicateState returns the duplicate state of fistState - * @return true if a duplicate pair of states was found. + /** + * Find duplicate (redundant) states, beginning at the specified pair, + * within this state table. This is an iterator-like function, used to + * identify states (state table rows) that can be eliminated. + * @param states in/out parameter, specifies where to start looking for duplicates, + * and returns the first pair of duplicates found, if any. + * @return true if duplicate states were found, false otherwise. + */ + bool findDuplicateState(IntPair *states); + + /** Remove a duplicate state. + * @param duplStates The duplicate states. The first is kept, the second is removed. + * All references to the second in the state table are retargeted + * to the first. */ - bool findDuplicateState(int32_t &firstState, int32_t &duplicateState); + void removeState(IntPair duplStates); - /** Remove a duplicate state/ - * @param keepState First of the duplicate pair. Keep it. - * @param duplState Duplicate state. Remove it. Redirect all references to the duplicate state - * to refer to keepState instead. + /** Find the next duplicate state in the safe reverse table. An iterator function. + * @param states in/out parameter, specifies where to start looking for duplicates, + * and returns the first pair of duplicates found, if any. + * @return true if a duplicate pair of states was found. */ - void removeState(int32_t keepState, int32_t duplState); + bool findDuplicateSafeState(IntPair *states); + + /** Remove a duplicate state from the safe table. + * @param duplStates The duplicate states. The first is kept, the second is removed. + * All references to the second in the state table are retargeted + * to the first. + */ + void removeSafeState(IntPair duplStates); // Set functions for UVector. // TODO: make a USet subclass of UVector @@ -113,11 +146,13 @@ public: void printPosSets(RBBINode *n /* = NULL*/); void printStates(); void printRuleStatusTable(); + void printReverseTable(); #else #define printSet(s) #define printPosSets(n) #define printStates() #define printRuleStatusTable() + #define printReverseTable() #endif private: @@ -126,10 +161,14 @@ private: // table for. UErrorCode *fStatus; + /** State Descriptors, UVector */ UVector *fDStates; // D states (Aho's terminology) // Index is state number // Contents are RBBIStateDescriptor pointers. + /** Synthesized safe table, UVector of UnicodeString, one string per table row. */ + UVector *fSafeTable; + RBBITableBuilder(const RBBITableBuilder &other); // forbid copying of this class RBBITableBuilder &operator=(const RBBITableBuilder &other); // forbid copying of this class diff --git a/deps/icu-small/source/common/serv.cpp b/deps/icu-small/source/common/serv.cpp index 8913b21e69..35e362b71a 100644 --- a/deps/icu-small/source/common/serv.cpp +++ b/deps/icu-small/source/common/serv.cpp @@ -547,16 +547,15 @@ outerEnd: if (putInCache && cacheResult) { serviceCache->put(result->actualDescriptor, result, status); if (U_FAILURE(status)) { - delete result; return NULL; } if (cacheDescriptorList._obj != NULL) { for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) { UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i); + serviceCache->put(*desc, result, status); if (U_FAILURE(status)) { - delete result; return NULL; } diff --git a/deps/icu-small/source/common/static_unicode_sets.cpp b/deps/icu-small/source/common/static_unicode_sets.cpp new file mode 100644 index 0000000000..9e731f5781 --- /dev/null +++ b/deps/icu-small/source/common/static_unicode_sets.cpp @@ -0,0 +1,222 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "static_unicode_sets.h" +#include "umutex.h" +#include "ucln_cmn.h" +#include "unicode/uniset.h" +#include "uresimp.h" +#include "cstring.h" +#include "uassert.h" + +using namespace icu; +using namespace icu::unisets; + + +namespace { + +UnicodeSet* gUnicodeSets[COUNT] = {}; + +// Save the empty instance in static memory to have well-defined behavior if a +// regular UnicodeSet cannot be allocated. +char gEmptyUnicodeSet[sizeof(UnicodeSet)]; + +// Whether the gEmptyUnicodeSet is initialized and ready to use. +UBool gEmptyUnicodeSetInitialized = FALSE; + +inline UnicodeSet* getImpl(Key key) { + UnicodeSet* candidate = gUnicodeSets[key]; + if (candidate == nullptr) { + return reinterpret_cast(gEmptyUnicodeSet); + } + return candidate; +} + +UnicodeSet* computeUnion(Key k1, Key k2) { + UnicodeSet* result = new UnicodeSet(); + if (result == nullptr) { + return nullptr; + } + result->addAll(*getImpl(k1)); + result->addAll(*getImpl(k2)); + result->freeze(); + return result; +} + +UnicodeSet* computeUnion(Key k1, Key k2, Key k3) { + UnicodeSet* result = new UnicodeSet(); + if (result == nullptr) { + return nullptr; + } + result->addAll(*getImpl(k1)); + result->addAll(*getImpl(k2)); + result->addAll(*getImpl(k3)); + result->freeze(); + return result; +} + + +void saveSet(Key key, const UnicodeString& unicodeSetPattern, UErrorCode& status) { + // assert unicodeSets.get(key) == null; + gUnicodeSets[key] = new UnicodeSet(unicodeSetPattern, status); +} + +class ParseDataSink : public ResourceSink { + public: + void put(const char* key, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE { + ResourceTable contextsTable = value.getTable(status); + if (U_FAILURE(status)) { return; } + for (int i = 0; contextsTable.getKeyAndValue(i, key, value); i++) { + if (uprv_strcmp(key, "date") == 0) { + // ignore + } else { + ResourceTable strictnessTable = value.getTable(status); + if (U_FAILURE(status)) { return; } + for (int j = 0; strictnessTable.getKeyAndValue(j, key, value); j++) { + bool isLenient = (uprv_strcmp(key, "lenient") == 0); + ResourceArray array = value.getArray(status); + if (U_FAILURE(status)) { return; } + for (int k = 0; k < array.getSize(); k++) { + array.getValue(k, value); + UnicodeString str = value.getUnicodeString(status); + if (U_FAILURE(status)) { return; } + // There is both lenient and strict data for comma/period, + // but not for any of the other symbols. + if (str.indexOf(u'.') != -1) { + saveSet(isLenient ? PERIOD : STRICT_PERIOD, str, status); + } else if (str.indexOf(u',') != -1) { + saveSet(isLenient ? COMMA : STRICT_COMMA, str, status); + } else if (str.indexOf(u'+') != -1) { + saveSet(PLUS_SIGN, str, status); + } else if (str.indexOf(u'‒') != -1) { + saveSet(MINUS_SIGN, str, status); + } else if (str.indexOf(u'$') != -1) { + saveSet(DOLLAR_SIGN, str, status); + } else if (str.indexOf(u'£') != -1) { + saveSet(POUND_SIGN, str, status); + } else if (str.indexOf(u'₨') != -1) { + saveSet(RUPEE_SIGN, str, status); + } + if (U_FAILURE(status)) { return; } + } + } + } + } + } +}; + + +icu::UInitOnce gNumberParseUniSetsInitOnce = U_INITONCE_INITIALIZER; + +UBool U_CALLCONV cleanupNumberParseUniSets() { + if (gEmptyUnicodeSetInitialized) { + reinterpret_cast(gEmptyUnicodeSet)->~UnicodeSet(); + gEmptyUnicodeSetInitialized = FALSE; + } + for (int32_t i = 0; i < COUNT; i++) { + delete gUnicodeSets[i]; + gUnicodeSets[i] = nullptr; + } + gNumberParseUniSetsInitOnce.reset(); + return TRUE; +} + +void U_CALLCONV initNumberParseUniSets(UErrorCode& status) { + ucln_common_registerCleanup(UCLN_COMMON_NUMPARSE_UNISETS, cleanupNumberParseUniSets); + + // Initialize the empty instance for well-defined fallback behavior + new(gEmptyUnicodeSet) UnicodeSet(); + reinterpret_cast(gEmptyUnicodeSet)->freeze(); + gEmptyUnicodeSetInitialized = TRUE; + + // These sets were decided after discussion with icu-design@. See tickets #13084 and #13309. + // Zs+TAB is "horizontal whitespace" according to UTS #18 (blank property). + gUnicodeSets[DEFAULT_IGNORABLES] = new UnicodeSet( + u"[[:Zs:][\\u0009][:Bidi_Control:][:Variation_Selector:]]", status); + gUnicodeSets[STRICT_IGNORABLES] = new UnicodeSet(u"[[:Bidi_Control:]]", status); + + LocalUResourceBundlePointer rb(ures_open(nullptr, "root", &status)); + if (U_FAILURE(status)) { return; } + ParseDataSink sink; + ures_getAllItemsWithFallback(rb.getAlias(), "parse", sink, status); + if (U_FAILURE(status)) { return; } + + // NOTE: It is OK for these assertions to fail if there was a no-data build. + U_ASSERT(gUnicodeSets[COMMA] != nullptr); + U_ASSERT(gUnicodeSets[STRICT_COMMA] != nullptr); + U_ASSERT(gUnicodeSets[PERIOD] != nullptr); + U_ASSERT(gUnicodeSets[STRICT_PERIOD] != nullptr); + + gUnicodeSets[OTHER_GROUPING_SEPARATORS] = new UnicodeSet( + 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); + + U_ASSERT(gUnicodeSets[MINUS_SIGN] != nullptr); + U_ASSERT(gUnicodeSets[PLUS_SIGN] != nullptr); + + gUnicodeSets[PERCENT_SIGN] = new UnicodeSet(u"[%٪]", status); + gUnicodeSets[PERMILLE_SIGN] = new UnicodeSet(u"[‰؉]", status); + gUnicodeSets[INFINITY_KEY] = new UnicodeSet(u"[∞]", status); + + U_ASSERT(gUnicodeSets[DOLLAR_SIGN] != nullptr); + U_ASSERT(gUnicodeSets[POUND_SIGN] != nullptr); + U_ASSERT(gUnicodeSets[RUPEE_SIGN] != nullptr); + gUnicodeSets[YEN_SIGN] = new UnicodeSet(u"[¥\\uffe5]", status); + + gUnicodeSets[DIGITS] = new UnicodeSet(u"[:digit:]", status); + + gUnicodeSets[DIGITS_OR_ALL_SEPARATORS] = computeUnion(DIGITS, ALL_SEPARATORS); + gUnicodeSets[DIGITS_OR_STRICT_ALL_SEPARATORS] = computeUnion(DIGITS, STRICT_ALL_SEPARATORS); + + for (auto* uniset : gUnicodeSets) { + if (uniset != nullptr) { + uniset->freeze(); + } + } +} + +} + +const UnicodeSet* unisets::get(Key key) { + UErrorCode localStatus = U_ZERO_ERROR; + umtx_initOnce(gNumberParseUniSetsInitOnce, &initNumberParseUniSets, localStatus); + if (U_FAILURE(localStatus)) { + return reinterpret_cast(gEmptyUnicodeSet); + } + return getImpl(key); +} + +Key unisets::chooseFrom(UnicodeString str, Key key1) { + return get(key1)->contains(str) ? key1 : NONE; +} + +Key unisets::chooseFrom(UnicodeString str, Key key1, Key key2) { + return get(key1)->contains(str) ? key1 : chooseFrom(str, key2); +} + +//Key unisets::chooseCurrency(UnicodeString str) { +// if (get(DOLLAR_SIGN)->contains(str)) { +// return DOLLAR_SIGN; +// } else if (get(POUND_SIGN)->contains(str)) { +// return POUND_SIGN; +// } else if (get(RUPEE_SIGN)->contains(str)) { +// return RUPEE_SIGN; +// } else if (get(YEN_SIGN)->contains(str)) { +// return YEN_SIGN; +// } else { +// return NONE; +// } +//} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/common/static_unicode_sets.h b/deps/icu-small/source/common/static_unicode_sets.h new file mode 100644 index 0000000000..5f18b3217e --- /dev/null +++ b/deps/icu-small/source/common/static_unicode_sets.h @@ -0,0 +1,119 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +// This file is in common instead of i18n because it is needed by ucurr.cpp. + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __STATIC_UNICODE_SETS_H__ +#define __STATIC_UNICODE_SETS_H__ + +#include "unicode/uniset.h" +#include "unicode/unistr.h" + +U_NAMESPACE_BEGIN +namespace unisets { + +enum Key { + // NONE is used to indicate null in chooseFrom(). + // EMPTY is used to get an empty UnicodeSet. + NONE = -1, + EMPTY = 0, + + // Ignorables + DEFAULT_IGNORABLES, + STRICT_IGNORABLES, + + // Separators + // Notes: + // - COMMA is a superset of STRICT_COMMA + // - PERIOD is a superset of SCRICT_PERIOD + // - ALL_SEPARATORS is the union of COMMA, PERIOD, and OTHER_GROUPING_SEPARATORS + // - STRICT_ALL_SEPARATORS is the union of STRICT_COMMA, STRICT_PERIOD, and OTHER_GRP_SEPARATORS + COMMA, + PERIOD, + STRICT_COMMA, + STRICT_PERIOD, + OTHER_GROUPING_SEPARATORS, + ALL_SEPARATORS, + STRICT_ALL_SEPARATORS, + + // Symbols + MINUS_SIGN, + PLUS_SIGN, + PERCENT_SIGN, + PERMILLE_SIGN, + INFINITY_KEY, // INFINITY is defined in cmath + + // Currency Symbols + DOLLAR_SIGN, + POUND_SIGN, + RUPEE_SIGN, + YEN_SIGN, // not in CLDR data, but Currency.java wants it + + // Other + DIGITS, + + // Combined Separators with Digits (for lead code points) + DIGITS_OR_ALL_SEPARATORS, + DIGITS_OR_STRICT_ALL_SEPARATORS, + + // The number of elements in the enum. + COUNT +}; + +/** + * Gets the static-allocated UnicodeSet according to the provided key. The + * pointer will be deleted during u_cleanup(); the caller should NOT delete it. + * + * Exported as U_COMMON_API for ucurr.cpp + * + * @param key The desired UnicodeSet according to the enum in this file. + * @return The requested UnicodeSet. Guaranteed to be frozen and non-null, but + * may be empty if an error occurred during data loading. + */ +U_COMMON_API const UnicodeSet* get(Key key); + +/** + * Checks if the UnicodeSet given by key1 contains the given string. + * + * Exported as U_COMMON_API for numparse_decimal.cpp + * + * @param str The string to check. + * @param key1 The set to check. + * @return key1 if the set contains str, or NONE if not. + */ +U_COMMON_API Key chooseFrom(UnicodeString str, Key key1); + +/** + * Checks if the UnicodeSet given by either key1 or key2 contains the string. + * + * Exported as U_COMMON_API for numparse_decimal.cpp + * + * @param str The string to check. + * @param key1 The first set to check. + * @param key2 The second set to check. + * @return key1 if that set contains str; key2 if that set contains str; or + * NONE if neither set contains str. + */ +U_COMMON_API Key chooseFrom(UnicodeString str, Key key1, Key key2); + +// Unused in C++: +// Key chooseCurrency(UnicodeString str); +// Used instead: +static const struct { + Key key; + UChar32 exemplar; +} kCurrencyEntries[] = { + {DOLLAR_SIGN, u'$'}, + {POUND_SIGN, u'£'}, + {RUPEE_SIGN, u'₨'}, + {YEN_SIGN, u'¥'}, +}; + +} // namespace unisets +U_NAMESPACE_END + +#endif //__STATIC_UNICODE_SETS_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/common/ubidi_props_data.h b/deps/icu-small/source/common/ubidi_props_data.h index 98f21510e7..55e331b612 100644 --- a/deps/icu-small/source/common/ubidi_props_data.h +++ b/deps/icu-small/source/common/ubidi_props_data.h @@ -11,538 +11,539 @@ #ifdef INCLUDED_FROM_UBIDI_PROPS_C -static const UVersionInfo ubidi_props_dataVersion={0xa,0,0,0}; +static const UVersionInfo ubidi_props_dataVersion={0xb,0,0,0}; -static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={0x10,0x6028,0x5cb0,0x1a,0x620,0x8c0,0x10ac0,0x10af0,0,0,0,0,0,0,0,0x6302b6}; +static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={0x10,0x647c,0x5e98,0x28,0x620,0x8c0,0x10ac0,0x10d24,0,0,0,0,0,0,0,0x6502b6}; -static const uint16_t ubidi_props_trieIndex[11856]={ -0x36a,0x372,0x37a,0x382,0x39a,0x3a2,0x3aa,0x3b2,0x38a,0x392,0x38a,0x392,0x38a,0x392,0x38a,0x392, -0x38a,0x392,0x38a,0x392,0x3b8,0x3c0,0x3c8,0x3d0,0x3d8,0x3e0,0x3dc,0x3e4,0x3ec,0x3f4,0x3ef,0x3f7, -0x38a,0x392,0x38a,0x392,0x3ff,0x407,0x38a,0x392,0x38a,0x392,0x38a,0x392,0x40d,0x415,0x41d,0x425, -0x42d,0x435,0x43d,0x445,0x44b,0x453,0x45b,0x463,0x46b,0x473,0x479,0x481,0x489,0x491,0x499,0x4a1, -0x4ad,0x4a9,0x4b5,0x4bd,0x41f,0x4cd,0x4d5,0x4c5,0x4dd,0x4df,0x4e7,0x4ef,0x4f7,0x4f8,0x500,0x508, -0x510,0x4f8,0x518,0x51d,0x510,0x4f8,0x525,0x52d,0x4f7,0x535,0x53d,0x4ef,0x542,0x38a,0x54a,0x54e, -0x556,0x557,0x55f,0x567,0x4f7,0x56f,0x577,0x4ef,0x401,0x57b,0x500,0x4ef,0x38a,0x38a,0x583,0x38a, -0x38a,0x589,0x591,0x38a,0x38a,0x595,0x59d,0x38a,0x5a1,0x5a8,0x38a,0x5b0,0x5b8,0x5bf,0x541,0x38a, -0x38a,0x5c7,0x5cf,0x5d7,0x5df,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x5e7,0x38a,0x5ef,0x38a,0x38a,0x38a, -0x5f7,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x5ff,0x38a,0x38a,0x38a,0x607,0x607,0x504,0x504,0x38a,0x60d,0x615,0x5ef, -0x62b,0x61d,0x61d,0x633,0x63a,0x623,0x38a,0x38a,0x38a,0x642,0x64a,0x38a,0x38a,0x38a,0x64c,0x654, -0x65c,0x38a,0x663,0x66b,0x38a,0x673,0x38a,0x38a,0x534,0x67b,0x542,0x683,0x401,0x68b,0x38a,0x692, -0x38a,0x697,0x38a,0x38a,0x38a,0x38a,0x69d,0x6a5,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x3d8,0x6ad, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x6b5,0x6bd,0x6c1, -0x6d9,0x6df,0x6c9,0x6d1,0x6e7,0x6ef,0x6f3,0x5c2,0x6fb,0x703,0x70b,0x38a,0x713,0x654,0x654,0x654, -0x723,0x72b,0x733,0x73b,0x740,0x748,0x750,0x71b,0x758,0x760,0x38a,0x766,0x76d,0x654,0x654,0x654, -0x654,0x56d,0x773,0x654,0x77b,0x38a,0x38a,0x651,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654, -0x654,0x654,0x654,0x654,0x654,0x783,0x654,0x654,0x654,0x654,0x654,0x789,0x654,0x654,0x791,0x799, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x654,0x654,0x654,0x654,0x7a9,0x7b0,0x7b8,0x7a1, -0x7c8,0x7d0,0x7d8,0x7df,0x7e7,0x7ef,0x7f6,0x7c0,0x654,0x654,0x654,0x7fe,0x804,0x80a,0x812,0x817, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x81e,0x38a,0x38a,0x38a,0x826,0x38a,0x38a,0x38a,0x3d8, -0x82e,0x836,0x763,0x38a,0x839,0x654,0x654,0x657,0x654,0x654,0x654,0x654,0x654,0x654,0x840,0x846, -0x856,0x84e,0x38a,0x38a,0x85e,0x5f7,0x38a,0x3b1,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x654,0x825, -0x3bf,0x38a,0x866,0x86e,0x38a,0x876,0x817,0x38a,0x38a,0x38a,0x38a,0x87e,0x38a,0x38a,0x64c,0x3b0, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x654,0x654, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x866,0x654,0x56d,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x885,0x38a,0x38a,0x88a,0x557,0x38a,0x38a,0x5a3,0x654,0x64b,0x38a,0x38a,0x892,0x38a,0x38a,0x38a, -0x89a,0x8a1,0x61d,0x8a9,0x38a,0x38a,0x579,0x8b1,0x38a,0x8b8,0x8bf,0x38a,0x4dd,0x8c4,0x38a,0x4f6, -0x38a,0x8cc,0x8d4,0x4f8,0x38a,0x8d8,0x4f7,0x8e0,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x8e7, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x8fb,0x8ef,0x8f3,0x489,0x489,0x489,0x489,0x489, -0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x903,0x489,0x489,0x489,0x489,0x90b,0x90f, -0x917,0x91f,0x923,0x92b,0x489,0x489,0x489,0x92f,0x937,0x37a,0x93f,0x947,0x38a,0x38a,0x38a,0x94f, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0xe28,0xe28,0xe68,0xea8,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xee0,0xf20,0xf60,0xf70,0xfb0,0xfbc, -0xe28,0xe28,0xffc,0xe28,0xe28,0xe28,0x1034,0x1074,0x10b4,0x10f4,0x112c,0x116c,0x11ac,0x11e4,0x1224,0x1264, -0xa40,0xa80,0xac0,0xafa,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xb25,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xb62,0x1a0,0x1a0,0xb97,0xbd7,0xc17,0xc57,0xc97,0xcd7, +static const uint16_t ubidi_props_trieIndex[12100]={ +0x36f,0x377,0x37f,0x387,0x39f,0x3a7,0x3af,0x3b7,0x38f,0x397,0x38f,0x397,0x38f,0x397,0x38f,0x397, +0x38f,0x397,0x38f,0x397,0x3bd,0x3c5,0x3cd,0x3d5,0x3dd,0x3e5,0x3e1,0x3e9,0x3f1,0x3f9,0x3f4,0x3fc, +0x38f,0x397,0x38f,0x397,0x404,0x40c,0x38f,0x397,0x38f,0x397,0x38f,0x397,0x412,0x41a,0x422,0x42a, +0x432,0x43a,0x442,0x44a,0x450,0x458,0x460,0x468,0x470,0x478,0x47e,0x486,0x48e,0x496,0x49e,0x4a6, +0x4b2,0x4ae,0x4ba,0x4c2,0x424,0x4d2,0x4da,0x4ca,0x4e2,0x4e4,0x4ec,0x4f4,0x4fc,0x4fd,0x505,0x50d, +0x515,0x4fd,0x51d,0x522,0x515,0x4fd,0x52a,0x532,0x4fc,0x53a,0x542,0x4f4,0x547,0x38f,0x54f,0x553, +0x55b,0x55d,0x565,0x56d,0x4fc,0x575,0x57d,0x4f4,0x406,0x581,0x505,0x4f4,0x38f,0x38f,0x589,0x38f, +0x38f,0x58f,0x597,0x38f,0x38f,0x59b,0x5a3,0x38f,0x5a7,0x5ae,0x38f,0x5b6,0x5be,0x5c5,0x546,0x38f, +0x38f,0x5cd,0x5d5,0x5dd,0x5e5,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x5ed,0x38f,0x5f5,0x38f,0x38f,0x38f, +0x5fd,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x605,0x38f,0x38f,0x38f,0x60d,0x60d,0x509,0x509,0x38f,0x613,0x61b,0x5f5, +0x631,0x623,0x623,0x639,0x640,0x629,0x38f,0x38f,0x38f,0x648,0x650,0x38f,0x38f,0x38f,0x652,0x65a, +0x662,0x38f,0x669,0x671,0x38f,0x679,0x38f,0x38f,0x539,0x681,0x547,0x689,0x406,0x691,0x38f,0x698, +0x38f,0x69d,0x38f,0x38f,0x38f,0x38f,0x6a3,0x6ab,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x3dd,0x6b3, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x6bb,0x6c3,0x6c7, +0x6df,0x6e5,0x6cf,0x6d7,0x6ed,0x6f5,0x6f9,0x5c8,0x701,0x709,0x711,0x38f,0x719,0x65a,0x65a,0x65a, +0x729,0x731,0x739,0x741,0x746,0x74e,0x756,0x721,0x75e,0x766,0x38f,0x76c,0x773,0x65a,0x65a,0x65a, +0x65a,0x573,0x779,0x65a,0x781,0x38f,0x38f,0x657,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a, +0x65a,0x65a,0x65a,0x65a,0x65a,0x789,0x65a,0x65a,0x65a,0x65a,0x65a,0x78f,0x65a,0x65a,0x797,0x79f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x65a,0x65a,0x65a,0x65a,0x7af,0x7b7,0x7bf,0x7a7, +0x7cf,0x7d7,0x7df,0x7e6,0x7ed,0x7f5,0x7f9,0x7c7,0x65a,0x65a,0x65a,0x801,0x807,0x65a,0x80d,0x810, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x818,0x38f,0x38f,0x38f,0x820,0x38f,0x38f,0x38f,0x3dd, +0x828,0x830,0x835,0x38f,0x83d,0x65a,0x65a,0x65d,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x844,0x84a, +0x85a,0x852,0x38f,0x38f,0x862,0x5fd,0x38f,0x3b6,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x65a,0x81f, +0x3c4,0x38f,0x839,0x86a,0x38f,0x872,0x87a,0x38f,0x38f,0x38f,0x38f,0x87e,0x38f,0x38f,0x652,0x3b5, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x65a,0x65a, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x839,0x65a,0x573,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x885,0x38f,0x38f,0x88a,0x55d,0x38f,0x38f,0x5a9,0x65a,0x651,0x38f,0x38f,0x892,0x38f,0x38f,0x38f, +0x89a,0x8a1,0x623,0x8a9,0x38f,0x38f,0x57f,0x8b1,0x38f,0x8b9,0x8c0,0x38f,0x4e2,0x8c5,0x38f,0x4fb, +0x38f,0x8cd,0x8d5,0x4fd,0x38f,0x8d9,0x4fc,0x8e1,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x8e8, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x8fc,0x8f0,0x8f4,0x48e,0x48e,0x48e,0x48e,0x48e, +0x48e,0x48e,0x48e,0x48e,0x48e,0x48e,0x48e,0x48e,0x48e,0x904,0x48e,0x48e,0x48e,0x48e,0x90c,0x910, +0x918,0x920,0x924,0x92c,0x48e,0x48e,0x48e,0x930,0x938,0x37f,0x940,0x948,0x38f,0x38f,0x38f,0x950, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0xe3c,0xe3c,0xe7c,0xebc,0xe3c,0xe3c,0xe3c,0xe3c,0xe3c,0xe3c,0xef4,0xf34,0xf74,0xf84,0xfc4,0xfd0, +0xe3c,0xe3c,0x1010,0xe3c,0xe3c,0xe3c,0x1048,0x1088,0x10c8,0x1108,0x1140,0x1180,0x11c0,0x11f8,0x1238,0x1278, +0xa40,0xa80,0xac0,0xaff,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xb37,0x1a0,0x1a0, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xb74,0x1a0,0x1a0,0xba9,0xbe9,0xc29,0xc69,0xca9,0xce9, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, -0xd57,0xd67,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, +0xd69,0xd79,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, 0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0, -0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd17, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x957,0x38a,0x654,0x654,0x95f,0x5f7,0x38a,0x4f0, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x967,0x38a,0x38a,0x38a,0x96e,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x976,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f, -0x97e,0x982,0x41f,0x41f,0x41f,0x41f,0x992,0x98a,0x41f,0x99a,0x41f,0x41f,0x9a2,0x9a8,0x41f,0x41f, -0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f, -0x41f,0x41f,0x41f,0x9b0,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f, -0x4f7,0x9b8,0x9bf,0x9c6,0x401,0x9c9,0x38a,0x38a,0x4dd,0x9d1,0x38a,0x9d7,0x401,0x9dc,0x609,0x38a, -0x38a,0x9e4,0x38a,0x38a,0x38a,0x38a,0x826,0x9ec,0x401,0x4f8,0x556,0x9f3,0x38a,0x38a,0x38a,0x38a, -0x38a,0x9b8,0x9fb,0x38a,0x38a,0x9ff,0xa07,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0xa0b,0xa13,0x38a, -0x38a,0xa1b,0x556,0xa23,0x38a,0xa29,0x38a,0x38a,0x5e7,0xa31,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0xa39,0xa3d,0xa45,0x38a,0xa4c,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0xa53,0x38a,0x38a,0xa61,0xa5b, -0x38a,0x38a,0x38a,0xa69,0xa71,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0xa75,0x38a,0xa7b,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0xa81,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x511,0xa89,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0xa90,0xa98,0xa9e,0x38a,0x38a,0x654,0x654,0xaa6,0x38a,0x38a,0x38a,0x38a,0x38a,0x654, -0x654,0xaae,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0xab4,0x38a,0xabb, -0x38a,0xab7,0x38a,0xabe,0x38a,0xac6,0xaca,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x3d8,0xad2,0x3d8,0xad9,0xae0,0xae8,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0xaf0,0xaf8,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0xb00,0x41f,0xb08, -0xb08,0xb0f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f, -0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f, -0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0xb17,0x41f, -0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x41f,0x654,0xb1f,0x654,0x654,0x657,0xb24,0xb28,0x840,0xb30, -0x38a,0x38a,0xb36,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x764,0x38a,0x38a,0x38a,0x38a,0x654, -0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654, -0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0xb3e,0xb46,0x654, -0x654,0x654,0x657,0x654,0x654,0xb3e,0x38a,0xb1f,0x654,0xb4e,0x654,0xb56,0x842,0x38a,0x38a,0xb1f, -0xb5a,0xb62,0x659,0x656,0x38a,0xb6a,0x56d,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0xb72,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0x38a, -0x38a,0x38a,0x38a,0x38a,0x38a,0x38a,0xb72,0xb82,0xb7a,0xb7a,0xb7a,0xb83,0xb83,0xb83,0xb83,0x3d8, -0x3d8,0x3d8,0x3d8,0x3d8,0x3d8,0x3d8,0xb8b,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83, -0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83, -0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83, -0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83, -0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0xb83,0x369,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, -0x12,8,7,8,9,7,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, -0x12,0x12,0x12,0x12,7,7,7,8,9,0xa,0xa,4,4,4,0xa,0xa, -0x310a,0xf20a,0xa,3,6,3,6,6,2,2,2,2,2,2,2,2, -2,2,6,0xa,0x500a,0xa,0xd00a,0xa,0xa,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0x510a,0xa,0xd20a,0xa,0xa,0xa,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0x510a,0xa,0xd20a,0xa,0x12,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0x12,0x12,0x12,0x12,0x12,7,0x12,0x12, -0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, -0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,6,0xa,4,4,4,4,0xa,0xa, -0xa,0xa,0,0x900a,0xa,0xb2,0xa,0xa,4,4,2,2,0xa,0,0xa,0xa, -0xa,2,0,0x900a,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa, +0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xd29, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x958,0x38f,0x65a,0x65a,0x960,0x5fd,0x38f,0x4f5, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x968,0x38f,0x38f,0x38f,0x96f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x977,0x424,0x424,0x424,0x424,0x424,0x424,0x424, +0x97f,0x983,0x424,0x424,0x424,0x424,0x993,0x98b,0x424,0x99b,0x424,0x424,0x9a3,0x9a9,0x424,0x424, +0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x9b9,0x9b1,0x424,0x424,0x424,0x424,0x424,0x424, +0x424,0x424,0x424,0x9c1,0x424,0x424,0x424,0x424,0x424,0x9c9,0x9d0,0x9d6,0x424,0x424,0x424,0x424, +0x4fc,0x9de,0x9e5,0x9ec,0x406,0x9ef,0x38f,0x38f,0x4e2,0x9f6,0x38f,0x9fc,0x406,0xa01,0xa09,0x38f, +0x38f,0xa0e,0x38f,0x38f,0x38f,0x38f,0x820,0xa16,0x406,0x581,0x55c,0xa1d,0x38f,0x38f,0x38f,0x38f, +0x38f,0x9de,0xa25,0x38f,0x38f,0xa2d,0xa35,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0xa39,0xa41,0x38f, +0x38f,0xa49,0x55c,0xa51,0x38f,0xa57,0x38f,0x38f,0x5ed,0xa5f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0xa64,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0xa6c, +0xa70,0xa78,0x38f,0xa7f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0xa86,0x38f,0x38f,0xa94,0xa8e,0x38f,0x38f,0x38f,0xa9c,0xaa4,0x38f,0xaa8,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x583,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0xaae,0x38f, +0xab4,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0xaba,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x516,0xac2,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0xac9,0xad1,0xad7,0x38f,0x38f,0x65a,0x65a,0xadf,0x38f,0x38f,0x38f,0x38f, +0x38f,0x65a,0x65a,0x833,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0xae1, +0x38f,0xae8,0x38f,0xae4,0x38f,0xaeb,0x38f,0xaf3,0xaf7,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x3dd,0xaff,0x3dd,0xb06,0xb0d,0xb15,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0xb1d,0xb25,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x424,0x424,0x424,0x424,0x424,0x424,0xb2d, +0x424,0xb35,0xb35,0xb3c,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424, +0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x8f4,0x48e,0x48e,0x424, +0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x48e,0x48e,0x48e,0x48e,0x48e,0x48e,0x48e, +0xb44,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x65a,0xb4c,0x65a,0x65a,0x65d,0xb51,0xb55, +0x844,0xb5d,0x3b1,0x38f,0xb63,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x76a,0x38f,0x38f,0x38f, +0x38f,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a, +0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0xb6b, +0xb73,0x65a,0x65a,0x65a,0x65d,0x65a,0x65a,0xb7b,0x38f,0xb4c,0x65a,0xb83,0x65a,0xb8b,0x846,0x38f, +0x38f,0xb4c,0xb8f,0x65a,0xb97,0x65a,0xb9f,0xba7,0x65a,0x38f,0x38f,0x38f,0x846,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0xbaf,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f, +0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0x38f,0xbaf,0xbbf,0xbb7,0xbb7,0xbb7,0xbc0,0xbc0,0xbc0, +0xbc0,0x3dd,0x3dd,0x3dd,0x3dd,0x3dd,0x3dd,0x3dd,0xbc8,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0, +0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0, +0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0, +0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0, +0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0xbc0,0x36e,0x36e,0x36e,0x12,0x12,0x12,0x12, +0x12,0x12,0x12,0x12,0x12,8,7,8,9,7,0x12,0x12,0x12,0x12,0x12,0x12, +0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,7,7,7,8,9,0xa,0xa,4, +4,4,0xa,0xa,0x310a,0xf20a,0xa,3,6,3,6,6,2,2,2,2, +2,2,2,2,2,2,6,0xa,0x500a,0xa,0xd00a,0xa,0xa,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa, +0,0,0,0,0,0,0,0x510a,0xa,0xd20a,0xa,0xa,0xa,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0x510a,0xa,0xd20a,0xa,0x12,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0xa,0xa,0,0,0,0,0, -0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0x12,0x12,0x12,0x12, +0x12,7,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, +0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,6,0xa,4,4, +4,4,0xa,0xa,0xa,0xa,0,0x900a,0xa,0xb2,0xa,0xa,4,4,2,2, +0xa,0,0xa,0xa,0xa,2,0,0x900a,0xa,0xa,0xa,0xa,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0xa,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0xa,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0, +0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0,0,0,0,0xa,0xa,0,0,0,0,0,0,0,0,0xa,0, -0,0,0,0,0xa,0xa,0,0xa,0,0,0,0,0,0,0,0, +0xb1,0xb1,0xb1,0xb1,0,0,0,0,0xa,0xa,0,0,0,0,0,0, +0,0,0xa,0,0,0,0,0,0xa,0xa,0,0xa,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0xa,0,0,0,0,0,0,0,0,0, +0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa,0, -0,0xa,0xa,4,1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0xa,0,0,0xa,0xa,4,1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,1,0xb1,1,0xb1,0xb1,1,0xb1,0xb1,1,0xb1,1,1,1,1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,0xb1,1,0xb1,0xb1,1,0xb1,0xb1,1,0xb1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,5,5,5,5,5,5,0xa,0xa,0xd,4,4,0xd, -6,0xd,0xa,0xa,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xd, -0x8ad,0xd,0xd,0xd,0x4d,0xd,0x8d,0x8d,0x8d,0x8d,0x4d,0x8d,0x4d,0x8d,0x4d,0x4d, -0x4d,0x4d,0x4d,0x8d,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, -0x4d,0x4d,0x4d,0x4d,0x2d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x4d,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,5,5,5,5,5,5,5,5,5,5,4,5, -5,0xd,0x4d,0x4d,0xb1,0x8d,0x8d,0x8d,0xd,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d, -0x4d,0x4d,0x4d,0x4d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d, -0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +1,1,1,1,1,1,1,1,5,5,5,5,5,5,0xa,0xa, +0xd,4,4,0xd,6,0xd,0xa,0xa,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xd,0x8ad,0xd,0xd,0xd,0x4d,0xd,0x8d,0x8d,0x8d,0x8d,0x4d,0x8d, +0x4d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x2d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x8d,0x4d,0x4d,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,5,5,5,5,5,5,5,5, +5,5,4,5,5,0xd,0x4d,0x4d,0xb1,0x8d,0x8d,0x8d,0xd,0x8d,0x8d,0x8d, +0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d, +0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, -0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x4d,0x8d, -0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x4d,0x8d,0x4d,0x8d,0x4d,0x4d,0x8d,0x8d, -0xd,0x8d,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,5,0xa,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xd,0xd,0xb1,0xb1,0xa,0xb1,0xb1,0xb1,0xb1,0x8d,0x8d,2,2,2,2, -2,2,2,2,2,2,0x4d,0x4d,0x4d,0xd,0xd,0x4d,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xad,0x8d,0xb1,0x4d,0x4d, -0x4d,0x8d,0x8d,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d, -0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x8d,0x4d,0x8d,0x4d,0x4d,0x8d,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xd, -0xd,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x8d,0x8d, -0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d, -0x8d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x8d,0x8d,0x4d,0x4d,0x4d,0x8d,0x8d,0x4d,0x4d, -0x4d,0x4d,0x4d,0x4d,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, +0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x8d,0x4d,0x4d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x4d,0x8d,0x4d,0x8d, +0x4d,0x4d,0x8d,0x8d,0xd,0x8d,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,5,0xa,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xd,0xd,0xb1,0xb1,0xa,0xb1,0xb1,0xb1,0xb1,0x8d,0x8d, +2,2,2,2,2,2,2,2,2,2,0x4d,0x4d,0x4d,0xd,0xd,0x4d, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xad, +0x8d,0xb1,0x4d,0x4d,0x4d,0x8d,0x8d,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d, +0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x8d,0x4d,0x8d,0x4d,0x4d,0x8d, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xd,0xd,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x4d,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x4d,0x4d,0x4d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x8d,0x8d,0x4d,0x4d,0x4d, +0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, 0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,1,1,1,1,1,1,1,1,1,1,0x41,0x41, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xd,0xd,0xd,0xd,0xd,0xd,0xd, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,1,1,1,1,1,1,1,1, +1,1,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, -0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,0xa,0xa,0xa,0xa,0x21,1, -1,1,1,1,0xb1,0xb1,0xb1,0xb1,1,0xb1,0xb1,0xb1,1,0xb1,0xb1,0xb1, -0xb1,0xb1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,0xb1,0xb1,0xb1,0xb1,1,0xb1, -0xb1,0xb1,0xb1,0xb1,0x81,0x41,0x41,0x41,0x41,0x41,0x81,0x81,0x41,0x81,0x41,0x41, -0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x81,0x41,1,1,1,0xb1,0xb1,0xb1, -1,1,1,1,0x4d,0xd,0x4d,0x4d,0x4d,0x4d,0xd,0x8d,0x4d,0x8d,0x8d,0xd, -0xd,0xd,0xd,0xd,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,0xb1,0xb1,5,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0x41,0x41,0x41,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,0xa,0xa, +0xa,0xa,0x21,1,1,0xb1,1,1,0xb1,0xb1,0xb1,0xb1,1,0xb1,0xb1,0xb1, +1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0xb1,0xb1, +0xb1,0xb1,1,0xb1,0xb1,0xb1,0xb1,0xb1,0x81,0x41,0x41,0x41,0x41,0x41,0x81,0x81, +0x41,0x81,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x81,0x41,1,1, +1,0xb1,0xb1,0xb1,1,1,1,1,0x4d,0xd,0x4d,0x4d,0x4d,0x4d,0xd,0x8d, +0x4d,0x8d,0x8d,0xd,0xd,0xd,0xd,0xd,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0xb1,0xb1,5,0xb1,0xb1,0xb1,0xb1,0xb1, 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x8d, -0x8d,0xd,0x8d,0x4d,0x4d,0x8d,0x8d,0x4d,0x4d,0xd,0x4d,0x4d,0x4d,0x8d,0x4d,0x4d, -0x4d,0x4d,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0xb1,0,0xb1,0,0,0,0,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0xb1,0,0,0,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0,0, -0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0xb1,0,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x4d,0x4d,0x8d,0x8d,0x8d,0xd,0x8d,0x4d,0x4d,0x8d,0x8d,0x4d,0x4d,0xd,0x4d,0x4d, +0x4d,0x8d,0x4d,0x4d,0x4d,0x4d,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0xb1,0,0xb1,0,0,0, +0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0xb1,0,0, +0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0, 0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,4,4,0,0,0,0,0,0,0,4,0,0,0,0, -0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0xb1,0xb1,0,0,0,0,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0,0, 0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0xb1,0xb1,0,0,0,0xb1,0,0,0,0,0,0, -0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0xb1,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0, 0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0, -0,0,0,0,0,4,0,0,0,0,0,0,0,0,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0xb1,0,0,0xb1,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0, -0,0xb1,0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0, +0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,4, +0,0,0xb1,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0,0, -0,0,0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa, -0xa,4,0xa,0,0,0,0,0,0xb1,0,0,0,0,0,0,0, +0,0,0,0,0,0xb1,0xb1,0,0,0,0,0xb1,0xb1,0,0,0xb1, +0xb1,0xb1,0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0xb1,0xb1,0,0,0,0xb1,0,0, +0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1, +0xb1,0,0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0,0,0,0, +0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0, +0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,0, -0,0,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0, -0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1, +0,0,0,0,0xb1,0,0,0xb1,0,0xb1,0xb1,0xb1,0xb1,0,0,0, +0,0,0,0,0,0xb1,0,0,0,0,0,0,0,0,0xb1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0,0, +0,0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa, +0xa,0xa,0xa,0xa,0xa,4,0xa,0,0,0,0,0,0xb1,0,0,0, +0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xb1,0,0,0xa0,0,0,0,0, -0,0,0xa0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,0,0, +0,0,0xb1,0xb1,0xb1,0,0,0,0,0,0xb1,0xb1,0xb1,0,0xb1,0xb1, +0xb1,0xb1,0,0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,0, +0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,0,0,0, -0,0,0,0,0,0,0xb1,0,0,0,0,0,0,0,0xb1,0xb1, -0xb1,0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0, -0,0,0,4,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1, -0xb1,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1, +0xb1,0,0,0xa0,0,0,0,0,0,0,0xa0,0,0,0,0,0, 0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0xb1,0,0xb1,0,0xb1,0x310a,0xf20a,0x310a,0xf20a,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0, -0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0,0,0,0,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0xb1,0xb1,0,0,0,0,0xb1,0xb1,0xb1,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, 0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0, -0,0xb1,0xb1,0,0,0,0,0,0,0xb1,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0, +0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,4,0,0,0,0, +0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0,0,0,0,0,0, +0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0xb1, +0,0xb1,0x310a,0xf20a,0x310a,0xf20a,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1, +0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0, +0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0,0, +0,0,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0xb1,0,0,0xb1,0xb1,0,0,0,0,0, +0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0xa,0,0,0, +0,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0, +0,0,0,0,0xa,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0, +0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x310a, +0xf20a,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0x310a,0xf20a,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1, -0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0,0,0,0,0,0,0,0,0xb1,0,0,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,4, -0,0xb1,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, -0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, -0x40,0x40,0x40,0x40,0x40,0xb1,0x40,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0x4a,0xa,0xa,0x2a,0xb1,0xb1,0xb1,0x12,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,0x40, +0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0, +0,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0,0,0,0,0,0,0,4,0,0xb1,0,0,0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, -0x40,0x40,0x40,0x40,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xb1,0x40,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x4a,0xa,0xa,0x2a,0xb1, +0xb1,0xb1,0x12,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0,0, +0,0,0,0,0,0xb1,0xb1,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, -0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xb1,0xb1,0xb1,0,0,0,0,0xb1, -0xb1,0,0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0, -0,0xb1,0xb1,0xb1,0,0,0,0,0xa,0,0,0,0xa,0xa,0,0, +0xb1,0xb1,0xb1,0,0,0,0,0xb1,0xb1,0,0,0,0,0,0,0, +0,0,0xb1,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,0,0, +0xa,0,0,0,0xa,0xa,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0xb1,0xb1,0,0,0xb1,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0,0xb1,0, -0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1, -0xb1,0xb1,0,0,0xb1,0xb1,0,0xb1,0xb1,0xb1,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0, -0xb1,0xb1,0,0,0,0xb1,0,0xb1,0xb1,0xb1,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0, -0,0xb1,0,0,0,0,0,0,0xb1,0,0,0,0xb1,0xb1,0,0, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, +0xb1,0,0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0xb1,0,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0,0xb1,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0,0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1, -0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0xa,0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0, -0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0, -0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0, -0,0xa,0xa,0,0xa,0xa,0xa,0xa,6,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,9,0xb2,0xb2,0xb2,0xb2,0xb2,0x12,0x814,0x815,0x813,0x816,0xb2,0xb2, -0xb2,0xb2,0xb2,0xb2,2,0,0,0,2,2,2,2,2,2,3,3, -0xa,0x310a,0xf20a,0,9,9,9,9,9,9,9,9,9,9,9,0xb2, -0x412,0x432,0x8a0,0x8a1,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,9,7,0x8ab,0x8ae,0x8b0,0x8ac,0x8af,6,4,4,4,4, -4,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,2,2,2,2, -2,2,2,2,2,2,3,3,0xa,0x310a,0xf20a,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4, +0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0, +0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,0xb1, +0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0xb1,0,0xb1,0xb1,0,0,0,0xb1,0,0xb1, +0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0xb1,0,0,0,0,0,0, +0xb1,0,0,0,0xb1,0xb1,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0xa,0,0xa,0xa,0xa,0,0, +0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0,0,0,0, +0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0,0,0,0, +0,0,0,0,0,0,0,0,0,0xa,0xa,0,0xa,0xa,0xa,0xa, +6,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,9,0xb2,0xb2,0xb2,0xb2, +0xb2,0x12,0x814,0x815,0x813,0x816,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,2,0,0,0, +2,2,2,2,2,2,3,3,0xa,0x310a,0xf20a,0,9,9,9,9, +9,9,9,9,9,9,9,0xb2,0x412,0x432,0x8a0,0x8a1,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,9,7,0x8ab,0x8ae, +0x8b0,0x8ac,0x8af,6,4,4,4,4,4,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa, +0xa,0xa,0xa,0xa,2,2,2,2,2,2,2,2,2,2,3,3, +0xa,0x310a,0xf20a,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, -4,4,4,4,4,4,4,4,4,4,4,4,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xa,0xa,0,0xa, -0xa,0xa,0xa,0,0xa,0xa,0,0,0,0,0,0,0,0,0,0, -0xa,0,0xa,0xa,0xa,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa, -0,0xa,0,0xa,0,0xa,0,0,0,0,4,0,0,0,0,0, -0,0,0,0,0,0,0xa,0xa,0,0,0,0,0x100a,0xa,0xa,0xa, -0xa,0,0,0,0,0,0xa,0xa,0xa,0xa,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0, -0,0,0,0,0,0xa,0xa,0xa,0,0,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a, -0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0x300a,0xf00a,0x900a,0x900a, -0x900a,0x100a,0x900a,0x900a,0x100a,0x100a,0x900a,0x900a,0x900a,0x900a,0x900a,0x100a,0xa,0x100a,0x100a,0x100a, -0x100a,0xa,0xa,0xa,0x700a,0x700a,0x700a,0xb00a,0xb00a,0xb00a,0xa,0xa,0xa,0x100a,3,4, -0xa,0x900a,0x100a,0xa,0xa,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0x100a,0x100a,0x100a,0x100a,0xa, -0x100a,0xa,0x100a,0xa,0xa,0xa,0xa,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a, -0xa,0xa,0xa,0xa,0xa,0x100a,0xa,0x100a,0x300a,0xf00a,0x100a,0x100a,0x100a,0x100a,0x100a,0x900a, -0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a, -0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0xa,0x100a,0xa, -0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a, -0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x100a,0xa,0xa,0x300a, -0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0x900a,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0x300a,0xf00a,0xa,0xa,0x900a,0x100a,0x900a,0x900a,0x100a,0x900a,0x100a,0x100a,0x100a,0x100a, -0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x100a,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x900a,0xa,0xa, -0x300a,0xf00a,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0xa,0xa, +4,4,4,4,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xa,0xa,0,0xa,0xa,0xa,0xa,0,0xa,0xa,0,0, +0,0,0,0,0,0,0,0,0xa,0,0xa,0xa,0xa,0,0,0, +0,0,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0,0xa,0,0xa,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa, +0,0,0,0,0x100a,0xa,0xa,0xa,0xa,0,0,0,0,0,0xa,0xa, +0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa, +0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a, +0x300a,0xf00a,0xa,0xa,0x300a,0xf00a,0x900a,0x900a,0x900a,0x100a,0x900a,0x900a,0x100a,0x100a,0x900a,0x900a, +0x900a,0x900a,0x900a,0x100a,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0xa,0xa,0x700a,0x700a,0x700a,0xb00a, +0xb00a,0xb00a,0xa,0xa,0xa,0x100a,3,4,0xa,0x900a,0x100a,0xa,0xa,0xa,0x100a,0x100a, +0x100a,0x100a,0xa,0x900a,0x900a,0x900a,0x900a,0xa,0x900a,0xa,0x100a,0xa,0xa,0xa,0xa,0x100a, +0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0x100a,0xa,0x100a, +0x300a,0xf00a,0x100a,0x100a,0x100a,0x100a,0x100a,0x900a,0x100a,0x900a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a, +0x900a,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0x100a,0x100a,0xa,0x100a,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a, +0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a, +0x300a,0xf00a,0x300a,0xf00a,0x100a,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa, +0x900a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,0x900a,0x100a, +0x900a,0x900a,0x100a,0x900a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a, +0x900a,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0x300a,0xf00a,0x300a,0xf00a,0x900a,0xa,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0x300a,0xf00a, +0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0, +0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,2,0,0,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a, -0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0x100a,0xa,0xa,0x300a,0xf00a,0x310a,0xf20a,0xa,0x300a,0xf00a,0xa,0x500a, -0x100a,0xd00a,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa, -0x100a,0x300a,0xf00a,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a, -0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0x100a,0xa,0x100a,0x100a,0x100a,0xa,0xa,0x100a,0x100a,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0x900a,0x100a,0x100a,0x300a,0xf00a,0xa,0xa, -0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a, -0xf20a,0x710a,0x320a,0xf10a,0xb20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0x100a, -0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x900a,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0x300a,0xf00a,0x100a,0x100a,0x300a,0xf00a,0xa,0xa,0xa,0x100a,0xa,0xa,0xa,0xa,0x100a,0x300a, -0xf00a,0x300a,0xf00a,0xa,0x300a,0xf00a,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a,0x100a,0xa,0xa,0xa, -0xa,0xa,0x100a,0x900a,0x900a,0x900a,0x100a,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x100a,0xa, -0xa,0xa,0xa,0x100a,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x100a,0xa,0x100a,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a, -0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0xa,0x100a,0x100a, -0x100a,0x100a,0xa,0xa,0x100a,0xa,0x100a,0xa,0xa,0x100a,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa, -0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x100a,0xa, +0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a, +0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0xa,0xa,0x300a, +0xf00a,0x310a,0xf20a,0xa,0x300a,0xf00a,0xa,0x500a,0x100a,0xd00a,0xa,0xa,0xa,0xa,0xa,0x100a, +0x100a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0x900a,0x300a,0xf00a,0xa,0xa,0xa,0x300a,0xf00a, +0x300a,0xf00a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0xa,0x100a, +0x100a,0x100a,0xa,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0x100a,0x900a,0x100a,0x100a,0x300a,0xf00a,0xa,0xa,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0x310a, +0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x710a,0x320a,0xf10a,0xb20a,0x310a,0xf20a,0x310a, +0xf20a,0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0x900a,0x100a,0x100a,0x100a,0x100a,0x900a,0xa,0x100a,0x900a, +0x300a,0xf00a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0x900a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x100a,0x100a, +0x300a,0xf00a,0xa,0xa,0xa,0x100a,0xa,0xa,0xa,0xa,0x100a,0x300a,0xf00a,0x300a,0xf00a,0xa, +0x300a,0xf00a,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a,0x100a,0xa,0xa,0xa,0xa,0xa,0x100a,0x900a, +0x900a,0x900a,0x100a,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x900a,0xa,0xa,0xa,0xa,0x100a, +0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x100a,0xa,0x100a,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a, +0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0xa, +0x100a,0xa,0x100a,0xa,0xa,0x100a,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa, +0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x100a,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0x300a,0xf00a,0xa,0xa,0xa,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0x100a,0x100a,0xa,0xa,0x100a, -0x100a,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a, -0xf00a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x300a, -0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x100a, -0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0x300a,0xf00a,0x100a,0x100a,0x300a, -0xf00a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x100a, -0x100a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa, -0xa,0xa,0xa,0xa,0x100a,0xa,0x900a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0xa,0xa, +0xa,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa, +0xa,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0x100a,0x100a,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa, +0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a, +0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a, +0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x100a,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a, +0x300a,0xf00a,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a, +0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa, +0x100a,0xa,0x900a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x900a,0, +0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0xb1, +0xb1,0xb1,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, +0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0x300a,0xf00a,0xa,0x300a,0xf00a,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa, +0x300a,0xf00a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa, -0xa,0xa,0xa,0,0,0,0,0xb1,0xb1,0xb1,0,0,0,0,0,0, -0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0xb1,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa, -0xa,0x300a,0xf00a,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,0x300a,0xf00a,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a, -0x310a,0xf20a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0, @@ -554,12 +555,11 @@ static const uint16_t ubidi_props_trieIndex[11856]={ 0x310a,0xf20a,0x310a,0xf20a,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xb1,0xb1,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, +0,0,0,0,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa, 0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0, @@ -574,194 +574,211 @@ static const uint16_t ubidi_props_trieIndex[11856]={ 0x40,0x40,0x40,0x40,0x40,0x40,0x60,0,0xa,0xa,0xa,0xa,0,0,0,0, 0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0, +0,0,0,0xb1,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0,0, +0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,0,0, +0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0,0,0, +0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0xb1,0,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0, +0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, +0xb1,0xb1,0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0, +0,0,0,0,0,0xb1,0,0,0xb1,0,0,0,0,0xb1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0,0,0, -0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0, -0,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0, -0,0,0,0xb1,0,0,0,0,0,0,0,0,0xb1,0,0,0, +1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0xb1,0,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,0,0,0xb1,0xb1, -0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0,0, -0,0,0,0,0,0,0xb1,0,0,0,0,0,0,0,0,0, -0,0xb1,0,0,0xb1,0,0,0,0,0xb1,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, -1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,1,0xb1,1,0xd,0xd,0xd,0xd, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0xb1,1, 0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa,0xa,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0x12,0x12,0x12,0x12, -0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa,0xd,0xd,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,6,0xa,6,0, -0xa,6,0xa,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,4,0xa,0xa,3,3, -0x300a,0xf00a,0xa,0,0xa,4,4,0xa,0,0,0,0,0xd,0xd,0xd,0xd, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa,0xa, 0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xb2,0,0xa,0xa,4, -4,4,0xa,0xa,0x310a,0xf20a,0xa,3,6,3,6,6,2,2,2,2, -2,2,2,2,2,2,6,0xa,0x500a,0xa,0xd00a,0xa,0xa,0,0,0, +0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa,0xd,0xd, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +6,0xa,6,0,0xa,6,0xa,0xa,0xa,0x310a,0xf20a,0x310a,0xf20a,0x310a,0xf20a,4, +0xa,0xa,3,3,0x300a,0xf00a,0xa,0,0xa,4,4,0xa,0,0,0,0, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xb2, +0,0xa,0xa,4,4,4,0xa,0xa,0x310a,0xf20a,0xa,3,6,3,6,6, +2,2,2,2,2,2,2,2,2,2,6,0xa,0x500a,0xa,0xd00a,0xa, +0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0x510a,0xa,0xd20a,0xa,0x310a, +0xf20a,0xa,0x310a,0xf20a,0xa,0xa,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0x510a,0xa,0xd20a,0xa,0x310a,0xf20a,0xa,0x310a,0xf20a, -0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,4,4,0xa,0xa, -0xa,4,4,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0x12,0x12,0x12,0x12, -0x12,0x12,0x12,0x12,0x12,0xaa,0xaa,0xaa,0xa,0xa,0x12,0x12,0,0xa,0,0, +4,4,0xa,0xa,0xa,4,4,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0, +0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0xaa,0xaa,0xaa,0xa,0xa,0x12,0x12, +0,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0xb1,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1, -0xb1,0xb1,0xb1,0,0,0,0,0,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,0xa,1,0xb1,0xb1,0xb1,1,0xb1,0xb1,1, -1,1,1,1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1,1,1,1, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0, +0xb1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xb1,0xb1,0xb1,1,1,1,1,0xb1,0x41,0x81,1,1,0x81,0xb1,0xb1,1, -1,1,1,0x41,0x41,0x41,0x41,0x81,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,0x41,0x41,0x41,0x41,0x41,0x81,1,0x81, -1,0x81,0x81,1,1,0x61,0x81,0x81,0x81,0x81,0x81,0x41,0x41,0x41,0x41,0x61, -0x41,0x41,0x41,0x41,0x41,0x81,0x41,0x41,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0xa,1,0xb1,0xb1,0xb1, +1,0xb1,0xb1,1,1,1,1,1,0xb1,0xb1,0xb1,0xb1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x41,0x81,0x41,0x81,0x81,0x81,0x41,0x41, -0x41,0x81,0x41,0x41,0x81,0x41,0x81,0x81,0x41,0x81,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,0x81,0x81,0x81,0x81,0x41,0x41,1, +1,1,1,1,0xb1,0xb1,0xb1,1,1,1,1,0xb1,0x41,0x81,1,1, +0x81,0xb1,0xb1,1,1,1,1,0x41,0x41,0x41,0x41,0x81,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,0x41,0x41,0x41,0x41, +0x41,0x81,1,0x81,1,0x81,0x81,1,1,0x61,0x81,0x81,0x81,0x81,0x81,0x41, +0x41,0x41,0x41,0x61,0x41,0x41,0x41,0x41,0x41,0x81,0x41,0x41,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x41,0x81,0x41,0x81, +0x81,0x81,0x41,0x41,0x41,0x81,0x41,0x41,0x81,0x41,0x81,0x81,0x41,0x81,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,0x81,0x81,0x81, +0x81,0x41,0x41,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0x4d,0x4d,0x8d,0x4d,0xb1,0xb1,0xb1,0xb1,0xd,0xd,0xd,0xd, +0xd,0xd,0xd,0xd,5,5,5,5,5,5,5,5,5,5,0xd,0xd, +0xd,0xd,0xd,0xd,0x6d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x4d,0x4d,0x4d,0x4d,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1, +5,5,5,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0x4d,0x4d,0x4d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, +0x4d,0x4d,0x4d,0x4d,0x4d,0xd,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0x4d,0x4d,0x4d,0x8d,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0, -0,0xa0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1, -0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0, +0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, +0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0xb1, +0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, -0xb1,0xb1,0,0,0xb1,0,0xb1,0xb1,0,0,0,0,0,0,0xb1,0, -0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0, +0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1, +0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,0xb1,0,0xb1,0xb1, +0,0,0,0,0,0,0xb1,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0xb1,0xb1,0xb1,0xb1, -0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1, -0xb1,0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0,0xb1,0xb1,0,0xb1,0xb1, +0,0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0, +0,0,0,0xb1,0xb1,0,0xb1,0xb1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1, -0xb1,0xb1,0,0,0,0,0,0,0xb1,0xb1,0,0xb1,0xb1,0,0,0, +0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0, +0xb1,0xb1,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0,0xb1,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0, +0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0, +0,0xb1,0,0xb1,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0xb1,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0,0xb1,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1, +0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, -0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0, -0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0,0,0,0, +0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xa0,0xa0,0xb1,0xb1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1, -0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0xb1,0,0,0,0, -0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1, -0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xa0,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1, -0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0, +0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0,0,0, +0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0,0,0,0, 0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0xb1,0, -0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0, +0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xa0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0xb1,0xb1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0, -0,0,0,0,0xb2,0xb2,0xb2,0xb2,0,0,0,0,0,0,0,0, +0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,0,0,0,0, -0,0,0,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0, +0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0xb1,0,0xb1,0xb1,0,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xa,0xa,0xb1,0xb1,0xb1,0xa,0,0, +0xb1,0xb1,0,0,0,0xb1,0,0xb1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0, +0,0,0,0,0,0,0,0,0xb2,0xb2,0xb2,0xb2,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0x100a,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0, +0,0,0,0,0,0,0,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0x100a,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0x100a,0,0,0,0, -0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,2,2,2,2,2,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0, -0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0, -0,0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1, -0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xb1,0xb1, +0xb1,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x100a, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0, +0,0,0,0,0,0x100a,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x100a, +0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0xb1,0,0, +0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1, +0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1,1,1,1,1, -0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, +0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1, +1,1,1,1,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,0xd,0xd,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa,0xa,0xd,0xd, -0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0, -0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -2,2,2,2,2,2,2,2,2,2,2,0xa,0xa,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0x41,0x41,0x41,0x41,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, +0xa,0xa,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0, 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, -0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0, +0xa,0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,2,2,2,2,2,2,2,2,2,2,2,0xa, +0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0xa,0xa,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0xa, +0xa,0xa,0xa,0,0,0,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0, +0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0xa,0xa,0xa,0, +0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0x12,0x12,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2, +0,0,0,0,0,0,0,0,0,0,0x12,0x12,0xb2,0xb2,0xb2,0xb2, 0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2, -0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0x12,0xb2,0x12,0x12,0x12,0x12,0x12,0x12, +0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0x12,0xb2,0x12,0x12, 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, -0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0xb1,0xb1,0xb1,0xb1, -0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0x12,0x12,0x12,0x12, -0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0,0,0,0 +0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, +0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, +0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, +0,0,0,0 }; -static const uint32_t ubidi_props_mirrors[26]={ -0x2000ab,0xbb,0x2a02215,0x1202243,0x2802298,0x2c022a6,0x30022a8,0x2e022a9,0x32022ab,0x6022cd,0x1e022f2,0x20022f3,0x22022f4,0x24022f6,0x26022f7,0x14022fa, -0x16022fb,0x18022fc,0x1a022fd,0x1c022fe,0x8029b8,0x4029f5,0xa02ade,0xe02ae3,0xc02ae4,0x1002ae5 +static const uint32_t ubidi_props_mirrors[40]={ +0x2000ab,0xbb,0x4202215,0x4e0221f,0x3e02220,0x3a02221,0x3c02222,0x4c02224,0x2202243,0x1402245,0x120224c,0x4002298,0x44022a6,0x48022a8,0x46022a9,0x4a022ab, +0x38022b8,0x10022cd,0x2e022f2,0x30022f3,0x32022f4,0x34022f6,0x36022f7,0x24022fa,0x26022fb,0x28022fc,0x2a022fd,0x2c022fe,0x20027dc,0xa0299b,0xc029a0,0x8029a3, +0x16029b8,0x4029f5,0x1802ade,0x1c02ae3,0x1a02ae4,0x1e02ae5,0xe02aee,0x602bfe }; static const uint8_t ubidi_props_jgArray[672]={ @@ -809,10 +826,46 @@ static const uint8_t ubidi_props_jgArray[672]={ 0xb,0x55,0x1f,1,0x13,0,4,4,4,0x1f,0x2d,0x56,0x58,0x57,0,0 }; -static const uint8_t ubidi_props_jgArray2[48]={ +static const uint8_t ubidi_props_jgArray2[612]={ 0x3a,0x3c,0x3c,0x40,0x40,0x3d,0,0x52,0,0x54,0x54,0,0,0x41,0x4f,0x53, 0x43,0x43,0x43,0x44,0x3e,0x50,0x45,0x46,0x4c,0x3b,0x3b,0x48,0x48,0x4b,0x49,0x49, -0x49,0x4a,0,0,0x4d,0,0,0,0,0,0,0x47,0x3f,0x4e,0x51,0x42 +0x49,0x4a,0,0,0x4d,0,0,0,0,0,0,0x47,0x3f,0x4e,0x51,0x42, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0x65,0,0,0,0,0,0,0x65,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0x64,0,0,0x65,0,0x64,0, +0x64,0,0,0x64 }; static const UBiDiProps ubidi_props_singleton={ @@ -823,16 +876,16 @@ static const UBiDiProps ubidi_props_singleton={ ubidi_props_jgArray2, { ubidi_props_trieIndex, - ubidi_props_trieIndex+3496, + ubidi_props_trieIndex+3516, NULL, - 3496, - 8360, + 3516, + 8584, 0x1a0, - 0xe28, + 0xe3c, 0x0, 0x0, 0x110000, - 0x2e4c, + 0x2f40, NULL, 0, FALSE, FALSE, 0, NULL }, { 2,2,0,0 } diff --git a/deps/icu-small/source/common/ucase.cpp b/deps/icu-small/source/common/ucase.cpp index 28d5a4cac6..43c57f896e 100644 --- a/deps/icu-small/source/common/ucase.cpp +++ b/deps/icu-small/source/common/ucase.cpp @@ -138,6 +138,11 @@ ucase_tolower(UChar32 c) { } else { const uint16_t *pe=GET_EXCEPTIONS(&ucase_props_singleton, props); uint16_t excWord=*pe++; + if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_IS_UPPER_OR_TITLE(props)) { + int32_t delta; + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; + } if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) { GET_SLOT_VALUE(excWord, UCASE_EXC_LOWER, pe, c); } @@ -155,6 +160,11 @@ ucase_toupper(UChar32 c) { } else { const uint16_t *pe=GET_EXCEPTIONS(&ucase_props_singleton, props); uint16_t excWord=*pe++; + if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_GET_TYPE(props)==UCASE_LOWER) { + int32_t delta; + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; + } if(HAS_SLOT(excWord, UCASE_EXC_UPPER)) { GET_SLOT_VALUE(excWord, UCASE_EXC_UPPER, pe, c); } @@ -172,6 +182,11 @@ ucase_totitle(UChar32 c) { } else { const uint16_t *pe=GET_EXCEPTIONS(&ucase_props_singleton, props); uint16_t excWord=*pe++; + if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_GET_TYPE(props)==UCASE_LOWER) { + int32_t delta; + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; + } int32_t idx; if(HAS_SLOT(excWord, UCASE_EXC_TITLE)) { idx=UCASE_EXC_TITLE; @@ -254,6 +269,11 @@ ucase_addCaseClosure(UChar32 c, const USetAdder *sa) { sa->add(sa->set, c); } } + if(HAS_SLOT(excWord, UCASE_EXC_DELTA)) { + int32_t delta; + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + sa->add(sa->set, (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta); + } /* get the closure string pointer & length */ if(HAS_SLOT(excWord, UCASE_EXC_CLOSURE)) { @@ -590,7 +610,12 @@ ucase_isSoftDotted(UChar32 c) { U_CAPI UBool U_EXPORT2 ucase_isCaseSensitive(UChar32 c) { uint16_t props=UTRIE2_GET16(&ucase_props_singleton.trie, c); - return (UBool)((props&UCASE_SENSITIVE)!=0); + if(!UCASE_HAS_EXCEPTION(props)) { + return (UBool)((props&UCASE_SENSITIVE)!=0); + } else { + const uint16_t *pe=GET_EXCEPTIONS(&ucase_props_singleton, props); + return (UBool)((*pe&UCASE_EXC_SENSITIVE)!=0); + } } /* string casing ------------------------------------------------------------ */ @@ -1140,6 +1165,11 @@ ucase_toFullLower(UChar32 c, } } + if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_IS_UPPER_OR_TITLE(props)) { + int32_t delta; + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; + } if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) { GET_SLOT_VALUE(excWord, UCASE_EXC_LOWER, pe2, result); } @@ -1229,6 +1259,11 @@ toUpperOrTitle(UChar32 c, } } + if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_GET_TYPE(props)==UCASE_LOWER) { + int32_t delta; + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; + } if(!upperNotTitle && HAS_SLOT(excWord, UCASE_EXC_TITLE)) { idx=UCASE_EXC_TITLE; } else if(HAS_SLOT(excWord, UCASE_EXC_UPPER)) { @@ -1334,6 +1369,14 @@ ucase_fold(UChar32 c, uint32_t options) { } } } + if((excWord&UCASE_EXC_NO_SIMPLE_CASE_FOLDING)!=0) { + return c; + } + if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_IS_UPPER_OR_TITLE(props)) { + int32_t delta; + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; + } if(HAS_SLOT(excWord, UCASE_EXC_FOLD)) { idx=UCASE_EXC_FOLD; } else if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) { @@ -1421,6 +1464,14 @@ ucase_toFullFolding(UChar32 c, } } + if((excWord&UCASE_EXC_NO_SIMPLE_CASE_FOLDING)!=0) { + return ~c; + } + if(HAS_SLOT(excWord, UCASE_EXC_DELTA) && UCASE_IS_UPPER_OR_TITLE(props)) { + int32_t delta; + GET_SLOT_VALUE(excWord, UCASE_EXC_DELTA, pe, delta); + return (excWord&UCASE_EXC_DELTA_IS_NEGATIVE)==0 ? c+delta : c-delta; + } if(HAS_SLOT(excWord, UCASE_EXC_FOLD)) { idx=UCASE_EXC_FOLD; } else if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) { diff --git a/deps/icu-small/source/common/ucase.h b/deps/icu-small/source/common/ucase.h index a7a8c9f00d..b0a453b87e 100644 --- a/deps/icu-small/source/common/ucase.h +++ b/deps/icu-small/source/common/ucase.h @@ -354,8 +354,8 @@ enum { #define UCASE_IS_UPPER_OR_TITLE(props) ((props)&2) #define UCASE_IGNORABLE 4 -#define UCASE_SENSITIVE 8 -#define UCASE_EXCEPTION 0x10 +#define UCASE_EXCEPTION 8 +#define UCASE_SENSITIVE 0x10 #define UCASE_HAS_EXCEPTION(props) ((props)&UCASE_EXCEPTION) @@ -379,9 +379,9 @@ enum { # define UCASE_GET_DELTA(props) (int16_t)(((props)&0x8000) ? (((props)>>UCASE_DELTA_SHIFT)|0xfe00) : ((uint16_t)(props)>>UCASE_DELTA_SHIFT)) #endif -/* exception: bits 15..5 are an unsigned 11-bit index into the exceptions array */ -#define UCASE_EXC_SHIFT 5 -#define UCASE_EXC_MASK 0xffe0 +/* exception: bits 15..4 are an unsigned 12-bit index into the exceptions array */ +#define UCASE_EXC_SHIFT 4 +#define UCASE_EXC_MASK 0xfff0 #define UCASE_MAX_EXCEPTIONS ((UCASE_EXC_MASK>>UCASE_EXC_SHIFT)+1) /* definitions for 16-bit main exceptions word ------------------------------ */ @@ -392,7 +392,7 @@ enum { UCASE_EXC_FOLD, UCASE_EXC_UPPER, UCASE_EXC_TITLE, - UCASE_EXC_4, /* reserved */ + UCASE_EXC_DELTA, UCASE_EXC_5, /* reserved */ UCASE_EXC_CLOSURE, UCASE_EXC_FULL_MAPPINGS, @@ -402,7 +402,11 @@ enum { /* each slot is 2 uint16_t instead of 1 */ #define UCASE_EXC_DOUBLE_SLOTS 0x100 -/* reserved: exception bits 11..9 */ +enum { + UCASE_EXC_NO_SIMPLE_CASE_FOLDING=0x200, + UCASE_EXC_DELTA_IS_NEGATIVE=0x400, + UCASE_EXC_SENSITIVE=0x800 +}; /* UCASE_EXC_DOT_MASK=UCASE_DOT_MASK< *maxMatchLen && len <= textLen && uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) { + *partialMatchLen = MAX(*partialMatchLen, len); *maxMatchIndex = index; *maxMatchLen = len; #ifdef UCURR_DEBUG printf("maxMatchIndex = %d, maxMatchLen = %d\n", *maxMatchIndex, *maxMatchLen); #endif + } else { + // Check for partial matches. + for (int32_t i=initialPartialMatchLen; icurrencyNames; - total_currency_name_count = cacheEntry->totalCurrencyNameCount; - currencySymbols = cacheEntry->currencySymbols; - total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount; ++(cacheEntry->refCount); } umtx_unlock(&gCurrencyCacheMutex); if (found == -1) { collectCurrencyNames(locale, ¤cyNames, &total_currency_name_count, ¤cySymbols, &total_currency_symbol_count, ec); if (U_FAILURE(ec)) { - return; + return NULL; } umtx_lock(&gCurrencyCacheMutex); // check again. @@ -1500,20 +1500,50 @@ uprv_parseCurrency(const char* locale, cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count; cacheEntry->refCount = 2; // one for cache, one for reference currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM; - ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cache_cleanup); + ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup); } else { deleteCurrencyNames(currencyNames, total_currency_name_count); deleteCurrencyNames(currencySymbols, total_currency_symbol_count); cacheEntry = currCache[found]; - currencyNames = cacheEntry->currencyNames; - total_currency_name_count = cacheEntry->totalCurrencyNameCount; - currencySymbols = cacheEntry->currencySymbols; - total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount; ++(cacheEntry->refCount); } umtx_unlock(&gCurrencyCacheMutex); } + return cacheEntry; +} + +static void releaseCacheEntry(CurrencyNameCacheEntry* cacheEntry) { + umtx_lock(&gCurrencyCacheMutex); + --(cacheEntry->refCount); + if (cacheEntry->refCount == 0) { // remove + deleteCacheEntry(cacheEntry); + } + umtx_unlock(&gCurrencyCacheMutex); +} + +U_CAPI void +uprv_parseCurrency(const char* locale, + const icu::UnicodeString& text, + icu::ParsePosition& pos, + int8_t type, + int32_t* partialMatchLen, + UChar* result, + UErrorCode& ec) { + U_NAMESPACE_USE + if (U_FAILURE(ec)) { + return; + } + CurrencyNameCacheEntry* cacheEntry = getCacheEntry(locale, ec); + if (U_FAILURE(ec)) { + return; + } + + int32_t total_currency_name_count = cacheEntry->totalCurrencyNameCount; + CurrencyNameStruct* currencyNames = cacheEntry->currencyNames; + int32_t total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount; + CurrencyNameStruct* currencySymbols = cacheEntry->currencySymbols; + int32_t start = pos.getIndex(); UChar inputText[MAX_CURRENCY_NAME_LEN]; @@ -1523,11 +1553,14 @@ uprv_parseCurrency(const char* locale, UErrorCode ec1 = U_ZERO_ERROR; textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, locale, &ec1); + // Make sure partialMatchLen is initialized + *partialMatchLen = 0; + int32_t max = 0; int32_t matchIndex = -1; // case in-sensitive comparision against currency names searchCurrencyName(currencyNames, total_currency_name_count, - upperText, textLen, &max, &matchIndex); + upperText, textLen, partialMatchLen, &max, &matchIndex); #ifdef UCURR_DEBUG printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex); @@ -1539,6 +1572,7 @@ uprv_parseCurrency(const char* locale, // case sensitive comparison against currency symbols and ISO code. searchCurrencyName(currencySymbols, total_currency_symbol_count, inputText, textLen, + partialMatchLen, &maxInSymbol, &matchIndexInSymbol); } @@ -1558,12 +1592,35 @@ uprv_parseCurrency(const char* locale, } // decrease reference count - umtx_lock(&gCurrencyCacheMutex); - --(cacheEntry->refCount); - if (cacheEntry->refCount == 0) { // remove - deleteCacheEntry(cacheEntry); + releaseCacheEntry(cacheEntry); +} + +void uprv_currencyLeads(const char* locale, icu::UnicodeSet& result, UErrorCode& ec) { + U_NAMESPACE_USE + if (U_FAILURE(ec)) { + return; } - umtx_unlock(&gCurrencyCacheMutex); + CurrencyNameCacheEntry* cacheEntry = getCacheEntry(locale, ec); + if (U_FAILURE(ec)) { + return; + } + + for (int32_t i=0; itotalCurrencySymbolCount; i++) { + const CurrencyNameStruct& info = cacheEntry->currencySymbols[i]; + UChar32 cp; + U16_GET(info.currencyName, 0, 0, info.currencyNameLen, cp); + result.add(cp); + } + + for (int32_t i=0; itotalCurrencyNameCount; i++) { + const CurrencyNameStruct& info = cacheEntry->currencyNames[i]; + UChar32 cp; + U16_GET(info.currencyName, 0, 0, info.currencyNameLen, cp); + result.add(cp); + } + + // decrease reference count + releaseCacheEntry(cacheEntry); } @@ -1729,7 +1786,8 @@ static const struct CurrencyList { {"BUK", UCURR_COMMON|UCURR_DEPRECATED}, {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"BYB", UCURR_COMMON|UCURR_DEPRECATED}, - {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BYN", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"BYR", UCURR_COMMON|UCURR_DEPRECATED}, {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED}, @@ -1739,6 +1797,7 @@ static const struct CurrencyList { {"CLE", UCURR_COMMON|UCURR_DEPRECATED}, {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"CNH", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED}, {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED}, @@ -1761,7 +1820,7 @@ static const struct CurrencyList { {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED}, {"EEK", UCURR_COMMON|UCURR_DEPRECATED}, {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED}, - {"EQE", UCURR_COMMON|UCURR_DEPRECATED}, + {"EQE", UCURR_COMMON|UCURR_DEPRECATED}, // questionable, remove? {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED}, {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED}, @@ -1785,7 +1844,7 @@ static const struct CurrencyList { {"GRD", UCURR_COMMON|UCURR_DEPRECATED}, {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"GWE", UCURR_COMMON|UCURR_DEPRECATED}, - {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"GWP", UCURR_COMMON|UCURR_DEPRECATED}, {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED}, @@ -1823,13 +1882,13 @@ static const struct CurrencyList { {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED}, - {"LSM", UCURR_COMMON|UCURR_DEPRECATED}, - {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LSM", UCURR_COMMON|UCURR_DEPRECATED}, // questionable, remove? + {"LTL", UCURR_COMMON|UCURR_DEPRECATED}, {"LTT", UCURR_COMMON|UCURR_DEPRECATED}, {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED}, {"LUF", UCURR_COMMON|UCURR_DEPRECATED}, {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED}, - {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"LVL", UCURR_COMMON|UCURR_DEPRECATED}, {"LVR", UCURR_COMMON|UCURR_DEPRECATED}, {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, @@ -1845,18 +1904,19 @@ static const struct CurrencyList { {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED}, - {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MRO", UCURR_COMMON|UCURR_DEPRECATED}, + {"MRU", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"MTL", UCURR_COMMON|UCURR_DEPRECATED}, {"MTP", UCURR_COMMON|UCURR_DEPRECATED}, {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED}, - {"MVP", UCURR_COMMON|UCURR_DEPRECATED}, + {"MVP", UCURR_COMMON|UCURR_DEPRECATED}, // questionable, remove? {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"MXP", UCURR_COMMON|UCURR_DEPRECATED}, {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED}, - {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"MZE", UCURR_COMMON|UCURR_DEPRECATED}, {"MZM", UCURR_COMMON|UCURR_DEPRECATED}, {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED}, @@ -1897,15 +1957,16 @@ static const struct CurrencyList { {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"SIT", UCURR_COMMON|UCURR_DEPRECATED}, - {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SKK", UCURR_COMMON|UCURR_DEPRECATED}, {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"SRG", UCURR_COMMON|UCURR_DEPRECATED}, {"SSP", UCURR_COMMON|UCURR_NON_DEPRECATED}, - {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"STD", UCURR_COMMON|UCURR_DEPRECATED}, + {"STN", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"SUR", UCURR_COMMON|UCURR_DEPRECATED}, - {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED}, + {"SVC", UCURR_COMMON|UCURR_DEPRECATED}, {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED}, @@ -1954,7 +2015,7 @@ static const struct CurrencyList { {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, - {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"XRE", UCURR_UNCOMMON|UCURR_DEPRECATED}, {"XSU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, {"XUA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, @@ -1965,15 +2026,15 @@ static const struct CurrencyList { {"YUM", UCURR_COMMON|UCURR_DEPRECATED}, {"YUN", UCURR_COMMON|UCURR_DEPRECATED}, {"YUR", UCURR_COMMON|UCURR_DEPRECATED}, - {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED}, + {"ZAL", UCURR_UNCOMMON|UCURR_DEPRECATED}, {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"ZMK", UCURR_COMMON|UCURR_DEPRECATED}, {"ZMW", UCURR_COMMON|UCURR_NON_DEPRECATED}, {"ZRN", UCURR_COMMON|UCURR_DEPRECATED}, {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED}, + {"ZWD", UCURR_COMMON|UCURR_DEPRECATED}, {"ZWL", UCURR_COMMON|UCURR_DEPRECATED}, {"ZWR", UCURR_COMMON|UCURR_DEPRECATED}, - {"ZWD", UCURR_COMMON|UCURR_DEPRECATED}, { NULL, 0 } // Leave here to denote the end of the list. }; @@ -2144,16 +2205,20 @@ static void U_CALLCONV initIsoCodes(UErrorCode &status) { } static void populateCurrSymbolsEquiv(icu::Hashtable *hash, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - int32_t length = UPRV_LENGTHOF(EQUIV_CURRENCY_SYMBOLS); - for (int32_t i = 0; i < length; ++i) { - icu::UnicodeString lhs(EQUIV_CURRENCY_SYMBOLS[i][0], -1, US_INV); - icu::UnicodeString rhs(EQUIV_CURRENCY_SYMBOLS[i][1], -1, US_INV); - makeEquivalent(lhs.unescape(), rhs.unescape(), hash, status); - if (U_FAILURE(status)) { - return; + if (U_FAILURE(status)) { return; } + for (auto& entry : unisets::kCurrencyEntries) { + UnicodeString exemplar(entry.exemplar); + const UnicodeSet* set = unisets::get(entry.key); + if (set == nullptr) { return; } + UnicodeSetIterator it(*set); + while (it.next()) { + UnicodeString value = it.getString(); + if (value == exemplar) { + // No need to mark the exemplar character as an equivalent + continue; + } + makeEquivalent(exemplar, value, hash, status); + if (U_FAILURE(status)) { return; } } } } diff --git a/deps/icu-small/source/common/ucurrimp.h b/deps/icu-small/source/common/ucurrimp.h index 6e468fd4c9..6d9588295d 100644 --- a/deps/icu-small/source/common/ucurrimp.h +++ b/deps/icu-small/source/common/ucurrimp.h @@ -13,6 +13,7 @@ #include "unicode/utypes.h" #include "unicode/unistr.h" #include "unicode/parsepos.h" +#include "unicode/uniset.h" /** * Internal method. Given a currency ISO code and a locale, return @@ -36,6 +37,8 @@ uprv_getStaticCurrencyName(const UChar* iso, const char* loc, * match, then the display name is preferred, unless it's length * is less than 3. * + * The parameters must not be NULL. + * * @param locale the locale of the display names to match * @param text the text to parse * @param pos input-output position; on input, the position within @@ -43,6 +46,8 @@ uprv_getStaticCurrencyName(const UChar* iso, const char* loc, * on output, the position after the last matched character. If * the parse fails, the position in unchanged upon output. * @param type currency type to parse against, LONG_NAME only or not + * @param partialMatchLen The length of the longest matching prefix; + * this may be nonzero even if no full currency was matched. * @return the ISO 4217 code, as a string, of the best match, or * null if there is no match * @@ -53,9 +58,21 @@ uprv_parseCurrency(const char* locale, const icu::UnicodeString& text, icu::ParsePosition& pos, int8_t type, + int32_t* partialMatchLen, UChar* result, UErrorCode& ec); +/** + * Puts all possible first-characters of a currency into the + * specified UnicodeSet. + * + * @param locale the locale of the display names of interest + * @param result the UnicodeSet to which to add the starting characters + */ +void uprv_currencyLeads(const char* locale, icu::UnicodeSet& result, UErrorCode& ec); + + + #endif /* #ifndef _UCURR_IMP_H_ */ //eof diff --git a/deps/icu-small/source/common/unicode/brkiter.h b/deps/icu-small/source/common/unicode/brkiter.h index 607f3ec625..5faeedfa93 100644 --- a/deps/icu-small/source/common/unicode/brkiter.h +++ b/deps/icu-small/source/common/unicode/brkiter.h @@ -638,7 +638,7 @@ protected: private: - /** @internal */ + /** @internal (private) */ char actualLocale[ULOC_FULLNAME_CAPACITY]; char validLocale[ULOC_FULLNAME_CAPACITY]; }; diff --git a/deps/icu-small/source/common/unicode/bytestriebuilder.h b/deps/icu-small/source/common/unicode/bytestriebuilder.h index 7a806bb7f0..b164e3bbd6 100644 --- a/deps/icu-small/source/common/unicode/bytestriebuilder.h +++ b/deps/icu-small/source/common/unicode/bytestriebuilder.h @@ -143,7 +143,7 @@ private: virtual int32_t getMaxLinearMatchLength() const { return BytesTrie::kMaxLinearMatchLength; } /** - * @internal + * @internal (private) */ class BTLinearMatchNode : public LinearMatchNode { public: diff --git a/deps/icu-small/source/common/unicode/caniter.h b/deps/icu-small/source/common/unicode/caniter.h index 543341f42c..b47e35da07 100644 --- a/deps/icu-small/source/common/unicode/caniter.h +++ b/deps/icu-small/source/common/unicode/caniter.h @@ -153,13 +153,13 @@ private: /** * Copy constructor. Private for now. - * @internal + * @internal (private) */ CanonicalIterator(const CanonicalIterator& other); /** * Assignment operator. Private for now. - * @internal + * @internal (private) */ CanonicalIterator& operator=(const CanonicalIterator& other); diff --git a/deps/icu-small/source/common/unicode/docmain.h b/deps/icu-small/source/common/unicode/docmain.h index 3e645aee4a..91e5ae3fa2 100644 --- a/deps/icu-small/source/common/unicode/docmain.h +++ b/deps/icu-small/source/common/unicode/docmain.h @@ -139,7 +139,7 @@ * * * Number Formatting - * unum.h + * unumberformatter.h, unum.h * icu::number::NumberFormatter (ICU 60+) or icu::NumberFormat (older versions) * * diff --git a/deps/icu-small/source/common/unicode/edits.h b/deps/icu-small/source/common/unicode/edits.h index 5a72574c14..f767a8d3b4 100644 --- a/deps/icu-small/source/common/unicode/edits.h +++ b/deps/icu-small/source/common/unicode/edits.h @@ -17,10 +17,57 @@ U_NAMESPACE_BEGIN +class UnicodeString; + /** - * Records lengths of string edits but not replacement text. - * Supports replacements, insertions, deletions in linear progression. - * Does not support moving/reordering of text. + * Records lengths of string edits but not replacement text. Supports replacements, insertions, deletions + * in linear progression. Does not support moving/reordering of text. + * + * There are two types of edits: change edits and no-change edits. Add edits to + * instances of this class using {@link #addReplace(int, int)} (for change edits) and + * {@link #addUnchanged(int)} (for no-change edits). Change edits are retained with full granularity, + * whereas adjacent no-change edits are always merged together. In no-change edits, there is a one-to-one + * mapping between code points in the source and destination strings. + * + * After all edits have been added, instances of this class should be considered immutable, and an + * {@link Edits::Iterator} can be used for queries. + * + * There are four flavors of Edits::Iterator: + * + *
    + *
  • {@link #getFineIterator()} retains full granularity of change edits. + *
  • {@link #getFineChangesIterator()} retains full granularity of change edits, and when calling + * next() on the iterator, skips over no-change edits (unchanged regions). + *
  • {@link #getCoarseIterator()} treats adjacent change edits as a single edit. (Adjacent no-change + * edits are automatically merged during the construction phase.) + *
  • {@link #getCoarseChangesIterator()} treats adjacent change edits as a single edit, and when + * calling next() on the iterator, skips over no-change edits (unchanged regions). + *
+ * + * For example, consider the string "abcßDeF", which case-folds to "abcssdef". This string has the + * following fine edits: + *
    + *
  • abc ⇨ abc (no-change) + *
  • ß ⇨ ss (change) + *
  • D ⇨ d (change) + *
  • e ⇨ e (no-change) + *
  • F ⇨ f (change) + *
+ * and the following coarse edits (note how adjacent change edits get merged together): + *
    + *
  • abc ⇨ abc (no-change) + *
  • ßD ⇨ ssd (change) + *
  • e ⇨ e (no-change) + *
  • F ⇨ f (change) + *
+ * + * The "fine changes" and "coarse changes" iterators will step through only the change edits when their + * {@link Edits::Iterator#next()} methods are called. They are identical to the non-change iterators when + * their {@link Edits::Iterator#findSourceIndex(int)} or {@link Edits::Iterator#findDestinationIndex(int)} + * methods are used to walk through the string. + * + * For examples of how to use this class, see the test TestCaseMapEditsIteratorDocs in + * UCharacterCaseTest.java. * * An Edits object tracks a separate UErrorCode, but ICU string transformation functions * (e.g., case mapping functions) merge any such errors into their API's UErrorCode. @@ -91,13 +138,13 @@ public: void reset() U_NOEXCEPT; /** - * Adds a record for an unchanged segment of text. + * Adds a no-change edit: a record for an unchanged segment of text. * Normally called from inside ICU string transformation functions, not user code. * @stable ICU 59 */ void addUnchanged(int32_t unchangedLength); /** - * Adds a record for a text replacement/insertion/deletion. + * Adds a change edit: a record for a text replacement/insertion/deletion. * Normally called from inside ICU string transformation functions, not user code. * @stable ICU 59 */ @@ -136,6 +183,18 @@ public: /** * Access to the list of edits. + * + * At any moment in time, an instance of this class points to a single edit: a "window" into a span + * of the source string and the corresponding span of the destination string. The source string span + * starts at {@link #sourceIndex()} and runs for {@link #oldLength()} chars; the destination string + * span starts at {@link #destinationIndex()} and runs for {@link #newLength()} chars. + * + * The iterator can be moved between edits using the {@link #next()}, {@link #findSourceIndex(int)}, + * and {@link #findDestinationIndex(int)} methods. Calling any of these methods mutates the iterator + * to make it point to the corresponding edit. + * + * For more information, see the documentation for {@link Edits}. + * * @see getCoarseIterator * @see getFineIterator * @stable ICU 59 @@ -162,7 +221,7 @@ public: Iterator &operator=(const Iterator &other) = default; /** - * Advances to the next edit. + * Advances the iterator to the next edit. * @param errorCode ICU error code. Its input value must pass the U_SUCCESS() test, * or else the function returns immediately. Check for U_FAILURE() * on output or use with function chaining. (See User Guide for details.) @@ -172,9 +231,9 @@ public: UBool next(UErrorCode &errorCode) { return next(onlyChanges_, errorCode); } /** - * Finds the edit that contains the source index. - * The source index may be found in a non-change - * even if normal iteration would skip non-changes. + * Moves the iterator to the edit that contains the source index. + * The source index may be found in a no-change edit + * even if normal iteration would skip no-change edits. * Normal iteration can continue from a found edit. * * The iterator state before this search logically does not matter. @@ -196,9 +255,9 @@ public: #ifndef U_HIDE_DRAFT_API /** - * Finds the edit that contains the destination index. - * The destination index may be found in a non-change - * even if normal iteration would skip non-changes. + * Moves the iterator to the edit that contains the destination index. + * The destination index may be found in a no-change edit + * even if normal iteration would skip no-change edits. * Normal iteration can continue from a found edit. * * The iterator state before this search logically does not matter. @@ -219,7 +278,7 @@ public: } /** - * Returns the destination index corresponding to the given source index. + * Computes the destination index corresponding to the given source index. * If the source index is inside a change edit (not at its start), * then the destination index at the end of that edit is returned, * since there is no information about index mapping inside a change edit. @@ -243,7 +302,7 @@ public: int32_t destinationIndexFromSourceIndex(int32_t i, UErrorCode &errorCode); /** - * Returns the source index corresponding to the given destination index. + * Computes the source index corresponding to the given destination index. * If the destination index is inside a change edit (not at its start), * then the source index at the end of that edit is returned, * since there is no information about index mapping inside a change edit. @@ -268,17 +327,27 @@ public: #endif // U_HIDE_DRAFT_API /** + * Returns whether the edit currently represented by the iterator is a change edit. + * * @return TRUE if this edit replaces oldLength() units with newLength() different ones. * FALSE if oldLength units remain unchanged. * @stable ICU 59 */ UBool hasChange() const { return changed; } + /** + * The length of the current span in the source string, which starts at {@link #sourceIndex}. + * * @return the number of units in the original string which are replaced or remain unchanged. * @stable ICU 59 */ int32_t oldLength() const { return oldLength_; } + /** + * The length of the current span in the destination string, which starts at + * {@link #destinationIndex}, or in the replacement string, which starts at + * {@link #replacementIndex}. + * * @return the number of units in the modified string, if hasChange() is TRUE. * Same as oldLength if hasChange() is FALSE. * @stable ICU 59 @@ -286,22 +355,52 @@ public: int32_t newLength() const { return newLength_; } /** + * The start index of the current span in the source string; the span has length + * {@link #oldLength}. + * * @return the current index into the source string * @stable ICU 59 */ int32_t sourceIndex() const { return srcIndex; } + /** + * The start index of the current span in the replacement string; the span has length + * {@link #newLength}. Well-defined only if the current edit is a change edit. + *

+ * The replacement string is the concatenation of all substrings of the destination + * string corresponding to change edits. + *

+ * This method is intended to be used together with operations that write only replacement + * characters (e.g., {@link CaseMap#omitUnchangedText()}). The source string can then be modified + * in-place. + * * @return the current index into the replacement-characters-only string, * not counting unchanged spans * @stable ICU 59 */ - int32_t replacementIndex() const { return replIndex; } + int32_t replacementIndex() const { + // TODO: Throw an exception if we aren't in a change edit? + return replIndex; + } + /** + * The start index of the current span in the destination string; the span has length + * {@link #newLength}. + * * @return the current index into the full destination string * @stable ICU 59 */ int32_t destinationIndex() const { return destIndex; } +#ifndef U_HIDE_INTERNAL_API + /** + * A string representation of the current edit represented by the iterator for debugging. You + * should not depend on the contents of the return string. + * @internal + */ + UnicodeString& toString(UnicodeString& appendTo) const; +#endif // U_HIDE_INTERNAL_API + private: friend class Edits; @@ -330,8 +429,10 @@ public: }; /** - * Returns an Iterator for coarse-grained changes for simple string updates. - * Skips non-changes. + * Returns an Iterator for coarse-grained change edits + * (adjacent change edits are treated as one). + * Can be used to perform simple string updates. + * Skips no-change edits. * @return an Iterator that merges adjacent changes. * @stable ICU 59 */ @@ -340,7 +441,10 @@ public: } /** - * Returns an Iterator for coarse-grained changes and non-changes for simple string updates. + * Returns an Iterator for coarse-grained change and no-change edits + * (adjacent change edits are treated as one). + * Can be used to perform simple string updates. + * Adjacent change edits are treated as one edit. * @return an Iterator that merges adjacent changes. * @stable ICU 59 */ @@ -349,8 +453,10 @@ public: } /** - * Returns an Iterator for fine-grained changes for modifying styled text. - * Skips non-changes. + * Returns an Iterator for fine-grained change edits + * (full granularity of change edits is retained). + * Can be used for modifying styled text. + * Skips no-change edits. * @return an Iterator that separates adjacent changes. * @stable ICU 59 */ @@ -359,7 +465,9 @@ public: } /** - * Returns an Iterator for fine-grained changes and non-changes for modifying styled text. + * Returns an Iterator for fine-grained change and no-change edits + * (full granularity of change edits is retained). + * Can be used for modifying styled text. * @return an Iterator that separates adjacent changes. * @stable ICU 59 */ diff --git a/deps/icu-small/source/common/unicode/platform.h b/deps/icu-small/source/common/unicode/platform.h index a3f8d32f89..d9636580c3 100644 --- a/deps/icu-small/source/common/unicode/platform.h +++ b/deps/icu-small/source/common/unicode/platform.h @@ -196,20 +196,6 @@ # define U_PLATFORM U_PF_UNKNOWN #endif -/** - * \def UPRV_INCOMPLETE_CPP11_SUPPORT - * This switch turns off ICU 60 NumberFormatter code. - * By default, this switch is enabled on AIX and z/OS, - * which have poor C++11 support. - * - * NOTE: This switch is intended to be temporary; see #13393. - * - * @internal - */ -#ifndef UPRV_INCOMPLETE_CPP11_SUPPORT -# define UPRV_INCOMPLETE_CPP11_SUPPORT (U_PLATFORM == U_PF_AIX || U_PLATFORM == U_PF_OS390 || U_PLATFORM == U_PF_SOLARIS ) -#endif - /** * \def CYGWINMSVC * Defined if this is Windows with Cygwin, but using MSVC rather than gcc. diff --git a/deps/icu-small/source/common/unicode/rbbi.h b/deps/icu-small/source/common/unicode/rbbi.h index 0c41d69d23..e9b82cd520 100644 --- a/deps/icu-small/source/common/unicode/rbbi.h +++ b/deps/icu-small/source/common/unicode/rbbi.h @@ -55,7 +55,7 @@ class U_COMMON_API RuleBasedBreakIterator /*U_FINAL*/ : public BreakIterator { private: /** * The UText through which this BreakIterator accesses the text - * @internal + * @internal (private) */ UText fText; @@ -70,13 +70,6 @@ public: RBBIDataWrapper *fData; private: - /** - * The iteration state - current position, rule status for the current position, - * and whether the iterator ran off the end, yielding UBRK_DONE. - * Current position is pinned to be 0 < position <= text.length. - * Current position is always set to a boundary. - * @internal - */ /** * The current position of the iterator. Pinned, 0 < fPosition <= text.length. * Never has the value UBRK_DONE (-1). @@ -628,25 +621,26 @@ private: /** * Dumps caches and performs other actions associated with a complete change * in text or iteration position. - * @internal + * @internal (private) */ void reset(void); /** * Common initialization function, used by constructors and bufferClone. - * @internal + * @internal (private) */ void init(UErrorCode &status); /** - * Iterate backwards from an arbitrary position in the input text using the Safe Reverse rules. + * Iterate backwards from an arbitrary position in the input text using the + * synthesized Safe Reverse rules. * This locates a "Safe Position" from which the forward break rules * will operate correctly. A Safe Position is not necessarily a boundary itself. * * @param fromPosition the position in the input text to begin the iteration. - * @internal + * @internal (private) */ - int32_t handlePrevious(int32_t fromPosition); + int32_t handleSafePrevious(int32_t fromPosition); /** * Find a rule-based boundary by running the state machine. @@ -658,7 +652,7 @@ private: * If > 0, the segment will be further subdivided * fRuleStatusIndex Info from the state table indicating which rules caused the boundary. * - * @internal + * @internal (private) */ int32_t handleNext(); @@ -667,7 +661,7 @@ private: * This function returns the appropriate LanguageBreakEngine for a * given character c. * @param c A character in the dictionary set - * @internal + * @internal (private) */ const LanguageBreakEngine *getLanguageBreakEngine(UChar32 c); diff --git a/deps/icu-small/source/common/unicode/uchar.h b/deps/icu-small/source/common/unicode/uchar.h index 4b72ecfc26..6d31083e66 100644 --- a/deps/icu-small/source/common/unicode/uchar.h +++ b/deps/icu-small/source/common/unicode/uchar.h @@ -42,7 +42,7 @@ U_CDECL_BEGIN * @see u_getUnicodeVersion * @stable ICU 2.0 */ -#define U_UNICODE_VERSION "10.0" +#define U_UNICODE_VERSION "11.0" /** * \file @@ -446,6 +446,13 @@ typedef enum UProperty { * @stable ICU 60 */ UCHAR_PREPENDED_CONCATENATION_MARK=63, + /** + * Binary property Extended_Pictographic. + * See http://www.unicode.org/reports/tr51/#Emoji_Properties + * + * @stable ICU 62 + */ + UCHAR_EXTENDED_PICTOGRAPHIC=64, #ifndef U_HIDE_DEPRECATED_API /** * One more than the last constant for binary Unicode properties. @@ -1683,6 +1690,31 @@ enum UBlockCode { /** @stable ICU 60 */ UBLOCK_ZANABAZAR_SQUARE = 280, /*[11A00]*/ + // New blocks in Unicode 11.0 + + /** @stable ICU 62 */ + UBLOCK_CHESS_SYMBOLS = 281, /*[1FA00]*/ + /** @stable ICU 62 */ + UBLOCK_DOGRA = 282, /*[11800]*/ + /** @stable ICU 62 */ + UBLOCK_GEORGIAN_EXTENDED = 283, /*[1C90]*/ + /** @stable ICU 62 */ + UBLOCK_GUNJALA_GONDI = 284, /*[11D60]*/ + /** @stable ICU 62 */ + UBLOCK_HANIFI_ROHINGYA = 285, /*[10D00]*/ + /** @stable ICU 62 */ + UBLOCK_INDIC_SIYAQ_NUMBERS = 286, /*[1EC70]*/ + /** @stable ICU 62 */ + UBLOCK_MAKASAR = 287, /*[11EE0]*/ + /** @stable ICU 62 */ + UBLOCK_MAYAN_NUMERALS = 288, /*[1D2E0]*/ + /** @stable ICU 62 */ + UBLOCK_MEDEFAIDRIN = 289, /*[16E40]*/ + /** @stable ICU 62 */ + UBLOCK_OLD_SOGDIAN = 290, /*[10F00]*/ + /** @stable ICU 62 */ + UBLOCK_SOGDIAN = 291, /*[10F30]*/ + #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal UBlockCode value. @@ -1690,7 +1722,7 @@ enum UBlockCode { * * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420. */ - UBLOCK_COUNT = 281, + UBLOCK_COUNT = 292, #endif // U_HIDE_DEPRECATED_API /** @stable ICU 2.0 */ @@ -1979,6 +2011,9 @@ typedef enum UJoiningGroup { U_JG_MALAYALAM_SSA, /**< @stable ICU 60 */ U_JG_MALAYALAM_TTA, /**< @stable ICU 60 */ + U_JG_HANIFI_ROHINGYA_KINNA_YA, /**< @stable ICU 62 */ + U_JG_HANIFI_ROHINGYA_PA, /**< @stable ICU 62 */ + #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal UJoiningGroup value. @@ -2029,6 +2064,7 @@ typedef enum UGraphemeClusterBreak { U_GCB_GLUE_AFTER_ZWJ = 16, /*[GAZ]*/ /** @stable ICU 58 */ U_GCB_ZWJ = 17, /*[ZWJ]*/ + #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal UGraphemeClusterBreak value. @@ -2090,6 +2126,9 @@ typedef enum UWordBreakValues { U_WB_GLUE_AFTER_ZWJ = 20, /*[GAZ]*/ /** @stable ICU 58 */ U_WB_ZWJ = 21, /*[ZWJ]*/ + /** @stable ICU 62 */ + U_WB_WSEGSPACE = 22, /*[WSEGSPACE]*/ + #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal UWordBreakValues value. @@ -2097,7 +2136,7 @@ typedef enum UWordBreakValues { * * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420. */ - U_WB_COUNT = 22 + U_WB_COUNT = 23 #endif // U_HIDE_DEPRECATED_API } UWordBreakValues; diff --git a/deps/icu-small/source/common/unicode/unistr.h b/deps/icu-small/source/common/unicode/unistr.h index d0b271754b..b84f40bd44 100644 --- a/deps/icu-small/source/common/unicode/unistr.h +++ b/deps/icu-small/source/common/unicode/unistr.h @@ -1892,7 +1892,7 @@ public: UnicodeString &fastCopyFrom(const UnicodeString &src); /** - * Move assignment operator, might leave src in bogus state. + * Move assignment operator; might leave src in bogus state. * This string will have the same contents and state that the source string had. * The behavior is undefined if *this and src are the same object. * @param src source string @@ -1905,7 +1905,7 @@ public: // do not use #ifndef U_HIDE_DRAFT_API for moveFrom, needed by non-draft API /** - * Move assignment, might leave src in bogus state. + * Move assignment; might leave src in bogus state. * This string will have the same contents and state that the source string had. * The behavior is undefined if *this and src are the same object. * @@ -3314,7 +3314,7 @@ public: UnicodeString(const UnicodeString& that); /** - * Move constructor, might leave src in bogus state. + * Move constructor; might leave src in bogus state. * This string will have the same contents and state that the source string had. * @param src source string * @stable ICU 56 diff --git a/deps/icu-small/source/common/unicode/urename.h b/deps/icu-small/source/common/unicode/urename.h index d8ab85091f..4175e527f4 100644 --- a/deps/icu-small/source/common/unicode/urename.h +++ b/deps/icu-small/source/common/unicode/urename.h @@ -613,6 +613,7 @@ #define ucnv_createConverterFromPackage U_ICU_ENTRY_POINT_RENAME(ucnv_createConverterFromPackage) #define ucnv_createConverterFromSharedData U_ICU_ENTRY_POINT_RENAME(ucnv_createConverterFromSharedData) #define ucnv_detectUnicodeSignature U_ICU_ENTRY_POINT_RENAME(ucnv_detectUnicodeSignature) +#define ucnv_enableCleanup U_ICU_ENTRY_POINT_RENAME(ucnv_enableCleanup) #define ucnv_extContinueMatchFromU U_ICU_ENTRY_POINT_RENAME(ucnv_extContinueMatchFromU) #define ucnv_extContinueMatchToU U_ICU_ENTRY_POINT_RENAME(ucnv_extContinueMatchToU) #define ucnv_extGetUnicodeSet U_ICU_ENTRY_POINT_RENAME(ucnv_extGetUnicodeSet) @@ -1170,6 +1171,16 @@ #define unum_setSymbol U_ICU_ENTRY_POINT_RENAME(unum_setSymbol) #define unum_setTextAttribute U_ICU_ENTRY_POINT_RENAME(unum_setTextAttribute) #define unum_toPattern U_ICU_ENTRY_POINT_RENAME(unum_toPattern) +#define unumf_close U_ICU_ENTRY_POINT_RENAME(unumf_close) +#define unumf_closeResult U_ICU_ENTRY_POINT_RENAME(unumf_closeResult) +#define unumf_formatDecimal U_ICU_ENTRY_POINT_RENAME(unumf_formatDecimal) +#define unumf_formatDouble U_ICU_ENTRY_POINT_RENAME(unumf_formatDouble) +#define unumf_formatInt U_ICU_ENTRY_POINT_RENAME(unumf_formatInt) +#define unumf_openForSkeletonAndLocale U_ICU_ENTRY_POINT_RENAME(unumf_openForSkeletonAndLocale) +#define unumf_openResult U_ICU_ENTRY_POINT_RENAME(unumf_openResult) +#define unumf_resultGetAllFieldPositions U_ICU_ENTRY_POINT_RENAME(unumf_resultGetAllFieldPositions) +#define unumf_resultNextFieldPosition U_ICU_ENTRY_POINT_RENAME(unumf_resultNextFieldPosition) +#define unumf_resultToString U_ICU_ENTRY_POINT_RENAME(unumf_resultToString) #define unumsys_close U_ICU_ENTRY_POINT_RENAME(unumsys_close) #define unumsys_getDescription U_ICU_ENTRY_POINT_RENAME(unumsys_getDescription) #define unumsys_getName U_ICU_ENTRY_POINT_RENAME(unumsys_getName) @@ -1209,6 +1220,7 @@ #define uplug_setPlugNoUnload U_ICU_ENTRY_POINT_RENAME(uplug_setPlugNoUnload) #define uprops_getSource U_ICU_ENTRY_POINT_RENAME(uprops_getSource) #define upropsvec_addPropertyStarts U_ICU_ENTRY_POINT_RENAME(upropsvec_addPropertyStarts) +#define uprv_add32_overflow U_ICU_ENTRY_POINT_RENAME(uprv_add32_overflow) #define uprv_aestrncpy U_ICU_ENTRY_POINT_RENAME(uprv_aestrncpy) #define uprv_asciiFromEbcdic U_ICU_ENTRY_POINT_RENAME(uprv_asciiFromEbcdic) #define uprv_asciitolower U_ICU_ENTRY_POINT_RENAME(uprv_asciitolower) @@ -1343,6 +1355,7 @@ #define uprv_maximumPtr U_ICU_ENTRY_POINT_RENAME(uprv_maximumPtr) #define uprv_min U_ICU_ENTRY_POINT_RENAME(uprv_min) #define uprv_modf U_ICU_ENTRY_POINT_RENAME(uprv_modf) +#define uprv_mul32_overflow U_ICU_ENTRY_POINT_RENAME(uprv_mul32_overflow) #define uprv_parseCurrency U_ICU_ENTRY_POINT_RENAME(uprv_parseCurrency) #define uprv_pathIsAbsolute U_ICU_ENTRY_POINT_RENAME(uprv_pathIsAbsolute) #define uprv_pow U_ICU_ENTRY_POINT_RENAME(uprv_pow) diff --git a/deps/icu-small/source/common/unicode/uscript.h b/deps/icu-small/source/common/unicode/uscript.h index 0befa1cd42..faf9edf8ae 100644 --- a/deps/icu-small/source/common/unicode/uscript.h +++ b/deps/icu-small/source/common/unicode/uscript.h @@ -451,6 +451,21 @@ typedef enum UScriptCode { /** @stable ICU 60 */ USCRIPT_ZANABAZAR_SQUARE = 177,/* Zanb */ + /** @stable ICU 62 */ + USCRIPT_DOGRA = 178,/* Dogr */ + /** @stable ICU 62 */ + USCRIPT_GUNJALA_GONDI = 179,/* Gong */ + /** @stable ICU 62 */ + USCRIPT_MAKASAR = 180,/* Maka */ + /** @stable ICU 62 */ + USCRIPT_MEDEFAIDRIN = 181,/* Medf */ + /** @stable ICU 62 */ + USCRIPT_HANIFI_ROHINGYA = 182,/* Rohg */ + /** @stable ICU 62 */ + USCRIPT_SOGDIAN = 183,/* Sogd */ + /** @stable ICU 62 */ + USCRIPT_OLD_SOGDIAN = 184,/* Sogo */ + #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal UScriptCode value. @@ -458,7 +473,7 @@ typedef enum UScriptCode { * * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420. */ - USCRIPT_CODE_LIMIT = 178 + USCRIPT_CODE_LIMIT = 185 #endif // U_HIDE_DEPRECATED_API } UScriptCode; diff --git a/deps/icu-small/source/common/unicode/utypes.h b/deps/icu-small/source/common/unicode/utypes.h index b6cf496511..f43056b6f2 100644 --- a/deps/icu-small/source/common/unicode/utypes.h +++ b/deps/icu-small/source/common/unicode/utypes.h @@ -542,12 +542,15 @@ typedef enum UErrorCode { #ifndef U_HIDE_DRAFT_API U_NUMBER_ARG_OUTOFBOUNDS_ERROR, /**< The argument to a NumberFormatter helper method was out of bounds; the bounds are usually 0 to 999. @draft ICU 61 */ #endif // U_HIDE_DRAFT_API +#ifndef U_HIDE_DRAFT_API + U_NUMBER_SKELETON_SYNTAX_ERROR, /**< The number skeleton passed to C++ NumberFormatter or C UNumberFormatter was invalid or contained a syntax error. @draft ICU 62 */ +#endif // U_HIDE_DRAFT_API #ifndef U_HIDE_DEPRECATED_API /** * One more than the highest normal formatting API error code. * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420. */ - U_FMT_PARSE_ERROR_LIMIT = 0x10113, + U_FMT_PARSE_ERROR_LIMIT = 0x10114, #endif // U_HIDE_DEPRECATED_API /* diff --git a/deps/icu-small/source/common/unicode/uvernum.h b/deps/icu-small/source/common/unicode/uvernum.h index 0427bcb03d..2240661112 100644 --- a/deps/icu-small/source/common/unicode/uvernum.h +++ b/deps/icu-small/source/common/unicode/uvernum.h @@ -58,7 +58,7 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.4 */ -#define U_ICU_VERSION_MAJOR_NUM 61 +#define U_ICU_VERSION_MAJOR_NUM 62 /** The current ICU minor version as an integer. * This value will change in the subsequent releases of ICU @@ -84,7 +84,7 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.6 */ -#define U_ICU_VERSION_SUFFIX _61 +#define U_ICU_VERSION_SUFFIX _62 /** * \def U_DEF2_ICU_ENTRY_POINT_RENAME @@ -119,7 +119,7 @@ * This value will change in the subsequent releases of ICU * @stable ICU 2.4 */ -#define U_ICU_VERSION "61.1" +#define U_ICU_VERSION "62.1" /** * The current ICU library major version number as a string, for library name suffixes. @@ -132,13 +132,13 @@ * * @stable ICU 2.6 */ -#define U_ICU_VERSION_SHORT "61" +#define U_ICU_VERSION_SHORT "62" #ifndef U_HIDE_INTERNAL_API /** Data version in ICU4C. * @internal ICU 4.4 Internal Use Only **/ -#define U_ICU_DATA_VERSION "61.1" +#define U_ICU_DATA_VERSION "62.1" #endif /* U_HIDE_INTERNAL_API */ /*=========================================================================== diff --git a/deps/icu-small/source/common/uprops.cpp b/deps/icu-small/source/common/uprops.cpp index b76896db1b..21723b32aa 100644 --- a/deps/icu-small/source/common/uprops.cpp +++ b/deps/icu-small/source/common/uprops.cpp @@ -282,6 +282,7 @@ static const BinaryProperty binProps[UCHAR_BINARY_LIMIT]={ { 2, U_MASK(UPROPS_2_EMOJI_COMPONENT), defaultContains }, { 2, 0, isRegionalIndicator }, { 1, U_MASK(UPROPS_PREPENDED_CONCATENATION_MARK), defaultContains }, + { 2, U_MASK(UPROPS_2_EXTENDED_PICTOGRAPHIC), defaultContains }, }; U_CAPI UBool U_EXPORT2 diff --git a/deps/icu-small/source/common/uprops.h b/deps/icu-small/source/common/uprops.h index 6f67756cd9..2078384c3e 100644 --- a/deps/icu-small/source/common/uprops.h +++ b/deps/icu-small/source/common/uprops.h @@ -196,8 +196,7 @@ enum { /* * Properties in vector word 2 * Bits - * 31..27 http://www.unicode.org/reports/tr51/#Emoji_Properties - * 26 reserved + * 31..26 http://www.unicode.org/reports/tr51/#Emoji_Properties * 25..20 Line Break * 19..15 Sentence Break * 14..10 Word Break @@ -205,7 +204,8 @@ enum { * 4.. 0 Decomposition Type */ enum { - UPROPS_2_EMOJI_COMPONENT=27, + UPROPS_2_EXTENDED_PICTOGRAPHIC=26, + UPROPS_2_EMOJI_COMPONENT, UPROPS_2_EMOJI, UPROPS_2_EMOJI_PRESENTATION, UPROPS_2_EMOJI_MODIFIER, diff --git a/deps/icu-small/source/common/uscript_props.cpp b/deps/icu-small/source/common/uscript_props.cpp index 7998c52c7f..bfdb68c7a9 100644 --- a/deps/icu-small/source/common/uscript_props.cpp +++ b/deps/icu-small/source/common/uscript_props.cpp @@ -71,7 +71,7 @@ const int32_t SCRIPT_PROPS[] = { 0x0EA5 | RECOMMENDED | LB_LETTERS, // Laoo 0x004C | RECOMMENDED | CASED, // Latn 0x0D15 | RECOMMENDED, // Mlym - 0x1826 | LIMITED_USE, // Mong + 0x1826 | EXCLUSION, // Mong 0x1000 | RECOMMENDED | LB_LETTERS, // Mymr 0x168F | EXCLUSION, // Ogam 0x10300 | EXCLUSION, // Ital @@ -222,6 +222,13 @@ const int32_t SCRIPT_PROPS[] = { 0x11D10 | EXCLUSION, // Gonm 0x11A5C | EXCLUSION, // Soyo 0x11A0B | EXCLUSION, // Zanb + 0x1180B | EXCLUSION, // Dogr + 0x11D71 | LIMITED_USE, // Gong + 0x11EE5 | EXCLUSION, // Maka + 0x16E40 | EXCLUSION | CASED, // Medf + 0x10D12 | LIMITED_USE | RTL, // Rohg + 0x10F42 | EXCLUSION | RTL, // Sogd + 0x10F19 | EXCLUSION | RTL, // Sogo // End copy-paste from parsescriptmetadata.py }; diff --git a/deps/icu-small/source/common/ustr_cnv.cpp b/deps/icu-small/source/common/ustr_cnv.cpp index 951864f4a6..eb37232c25 100644 --- a/deps/icu-small/source/common/ustr_cnv.cpp +++ b/deps/icu-small/source/common/ustr_cnv.cpp @@ -28,6 +28,7 @@ #include "cmemory.h" #include "umutex.h" #include "ustr_cnv.h" +#include "ucnv_bld.h" /* mutexed access to a shared default converter ----------------------------- */ @@ -68,8 +69,8 @@ u_releaseDefaultConverter(UConverter *converter) if (converter != NULL) { ucnv_reset(converter); } + ucnv_enableCleanup(); umtx_lock(NULL); - if(gDefaultConverter == NULL) { gDefaultConverter = converter; converter = NULL; diff --git a/deps/icu-small/source/common/util.h b/deps/icu-small/source/common/util.h index 7af9a32d8f..92cdc9ef69 100644 --- a/deps/icu-small/source/common/util.h +++ b/deps/icu-small/source/common/util.h @@ -46,6 +46,13 @@ class U_COMMON_API ICU_Utility /* not : public UObject because all methods are s int32_t radix = 10, int32_t minDigits = 1); + /** Returns a bogus UnicodeString by value. */ + static inline UnicodeString makeBogusString() { + UnicodeString result; + result.setToBogus(); + return result; + } + /** * Return true if the character is NOT printable ASCII. * diff --git a/deps/icu-small/source/common/utypes.cpp b/deps/icu-small/source/common/utypes.cpp index 5d6a0504ba..7531e46568 100644 --- a/deps/icu-small/source/common/utypes.cpp +++ b/deps/icu-small/source/common/utypes.cpp @@ -126,7 +126,8 @@ _uFmtErrorName[U_FMT_PARSE_ERROR_LIMIT - U_FMT_PARSE_ERROR_START] = { "U_DEFAULT_KEYWORD_MISSING", "U_DECIMAL_NUMBER_SYNTAX_ERROR", "U_FORMAT_INEXACT_ERROR", - "U_NUMBER_ARG_OUTOFBOUNDS_ERROR" + "U_NUMBER_ARG_OUTOFBOUNDS_ERROR", + "U_NUMBER_SKELETON_SYNTAX_ERROR", }; static const char * const diff --git a/deps/icu-small/source/common/wintz.cpp b/deps/icu-small/source/common/wintz.cpp index c30a5dbc60..3708925b38 100644 --- a/deps/icu-small/source/common/wintz.cpp +++ b/deps/icu-small/source/common/wintz.cpp @@ -49,7 +49,7 @@ typedef struct /** * Various registry keys and key fragments. */ -static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\"; +static const wchar_t CURRENT_ZONE_REGKEY[] = L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\"; static const char STANDARD_TIME_REGKEY[] = " Standard Time"; static const char TZI_REGKEY[] = "TZI"; static const char STD_REGKEY[] = "Std"; @@ -121,27 +121,39 @@ static LONG getSTDName(const char *winid, char *regStdName, int32_t length) return result; } -static LONG getTZKeyName(char* tzKeyName, int32_t length) +static LONG getTZKeyName(char* tzKeyName, int32_t tzKeyNamelength) { HKEY hkey; LONG result = FALSE; - DWORD cbData = length; + WCHAR timeZoneKeyNameData[128]; + DWORD timeZoneKeyNameLength = static_cast(sizeof(timeZoneKeyNameData)); - if(ERROR_SUCCESS == RegOpenKeyExA( + if(ERROR_SUCCESS == RegOpenKeyExW( HKEY_LOCAL_MACHINE, CURRENT_ZONE_REGKEY, 0, KEY_QUERY_VALUE, &hkey)) { - result = RegQueryValueExA( + if (ERROR_SUCCESS == RegQueryValueExW( hkey, - "TimeZoneKeyName", + L"TimeZoneKeyName", NULL, NULL, - (LPBYTE)tzKeyName, - &cbData); + (LPBYTE)timeZoneKeyNameData, + &timeZoneKeyNameLength)) + { + // Ensure null termination. + timeZoneKeyNameData[UPRV_LENGTHOF(timeZoneKeyNameData) - 1] = L'\0'; + // Convert the UTF-16 string to UTF-8. + UErrorCode status = U_ZERO_ERROR; + u_strToUTF8(tzKeyName, tzKeyNamelength, NULL, reinterpret_cast(timeZoneKeyNameData), -1, &status); + if (U_ZERO_ERROR == status) + { + result = ERROR_SUCCESS; + } + } RegCloseKey(hkey); } diff --git a/deps/icu-small/source/data/in/icudt61l.dat b/deps/icu-small/source/data/in/icudt61l.dat deleted file mode 100644 index e9c24d8d1a..0000000000 Binary files a/deps/icu-small/source/data/in/icudt61l.dat and /dev/null differ diff --git a/deps/icu-small/source/data/in/icudt62l.dat b/deps/icu-small/source/data/in/icudt62l.dat new file mode 100644 index 0000000000..a6ac7ebb37 Binary files /dev/null and b/deps/icu-small/source/data/in/icudt62l.dat differ diff --git a/deps/icu-small/source/i18n/affixpatternparser.cpp b/deps/icu-small/source/i18n/affixpatternparser.cpp deleted file mode 100644 index d9e122953a..0000000000 --- a/deps/icu-small/source/i18n/affixpatternparser.cpp +++ /dev/null @@ -1,698 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: affixpatternparser.cpp - */ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/dcfmtsym.h" -#include "unicode/plurrule.h" -#include "unicode/strenum.h" -#include "unicode/ucurr.h" -#include "unicode/ustring.h" -#include "affixpatternparser.h" -#include "charstr.h" -#include "precision.h" -#include "uassert.h" -#include "unistrappender.h" - -static const UChar gDefaultSymbols[] = {0xa4, 0xa4, 0xa4}; - -static const UChar gPercent = 0x25; -static const UChar gPerMill = 0x2030; -static const UChar gNegative = 0x2D; -static const UChar gPositive = 0x2B; - -#define PACK_TOKEN_AND_LENGTH(t, l) ((UChar) (((t) << 8) | (l & 0xFF))) - -#define UNPACK_TOKEN(c) ((AffixPattern::ETokenType) (((c) >> 8) & 0x7F)) - -#define UNPACK_LONG(c) (((c) >> 8) & 0x80) - -#define UNPACK_LENGTH(c) ((c) & 0xFF) - -U_NAMESPACE_BEGIN - -static int32_t -nextToken(const UChar *buffer, int32_t idx, int32_t len, UChar *token) { - if (buffer[idx] != 0x27 || idx + 1 == len) { - *token = buffer[idx]; - return 1; - } - *token = buffer[idx + 1]; - if (buffer[idx + 1] == 0xA4) { - int32_t i = 2; - for (; idx + i < len && i < 4 && buffer[idx + i] == buffer[idx + 1]; ++i) - ; - return i; - } - return 2; -} - -static int32_t -nextUserToken(const UChar *buffer, int32_t idx, int32_t len, UChar *token) { - *token = buffer[idx]; - int32_t max; - switch (buffer[idx]) { - case 0x27: - max = 2; - break; - case 0xA4: - max = 3; - break; - default: - max = 1; - break; - } - int32_t i = 1; - for (; idx + i < len && i < max && buffer[idx + i] == buffer[idx]; ++i) - ; - return i; -} - -CurrencyAffixInfo::CurrencyAffixInfo() - : fSymbol(gDefaultSymbols, 1), - fISO(gDefaultSymbols, 2), - fLong(DigitAffix(gDefaultSymbols, 3)), - fIsDefault(TRUE) { -} - -void -CurrencyAffixInfo::set( - const char *locale, - const PluralRules *rules, - const UChar *currency, - UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - fIsDefault = FALSE; - if (currency == NULL) { - fSymbol.setTo(gDefaultSymbols, 1); - fISO.setTo(gDefaultSymbols, 2); - fLong.remove(); - fLong.append(gDefaultSymbols, 3); - fIsDefault = TRUE; - return; - } - int32_t len; - UBool unusedIsChoice; - const UChar *symbol = ucurr_getName( - currency, locale, UCURR_SYMBOL_NAME, &unusedIsChoice, - &len, &status); - if (U_FAILURE(status)) { - return; - } - fSymbol.setTo(symbol, len); - fISO.setTo(currency, u_strlen(currency)); - fLong.remove(); - StringEnumeration* keywords = rules->getKeywords(status); - if (U_FAILURE(status)) { - return; - } - const UnicodeString* pluralCount; - while ((pluralCount = keywords->snext(status)) != NULL) { - CharString pCount; - pCount.appendInvariantChars(*pluralCount, status); - const UChar *pluralName = ucurr_getPluralName( - currency, locale, &unusedIsChoice, pCount.data(), - &len, &status); - fLong.setVariant(pCount.data(), UnicodeString(pluralName, len), status); - } - delete keywords; -} - -void -CurrencyAffixInfo::adjustPrecision( - const UChar *currency, const UCurrencyUsage usage, - FixedPrecision &precision, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - - int32_t digitCount = ucurr_getDefaultFractionDigitsForUsage( - currency, usage, &status); - precision.fMin.setFracDigitCount(digitCount); - precision.fMax.setFracDigitCount(digitCount); - double increment = ucurr_getRoundingIncrementForUsage( - currency, usage, &status); - if (increment == 0.0) { - precision.fRoundingIncrement.clear(); - } else { - precision.fRoundingIncrement.set(increment); - // guard against round-off error - precision.fRoundingIncrement.round(6); - } -} - -void -AffixPattern::addLiteral( - const UChar *literal, int32_t start, int32_t len) { - char32Count += u_countChar32(literal + start, len); - literals.append(literal, start, len); - int32_t tlen = tokens.length(); - // Takes 4 UChars to encode maximum literal length. - UChar *tokenChars = tokens.getBuffer(tlen + 4); - - // find start of literal size. May be tlen if there is no literal. - // While finding start of literal size, compute literal length - int32_t literalLength = 0; - int32_t tLiteralStart = tlen; - while (tLiteralStart > 0 && UNPACK_TOKEN(tokenChars[tLiteralStart - 1]) == kLiteral) { - tLiteralStart--; - literalLength <<= 8; - literalLength |= UNPACK_LENGTH(tokenChars[tLiteralStart]); - } - // Add number of chars we just added to literal - literalLength += len; - - // Now encode the new length starting at tLiteralStart - tlen = tLiteralStart; - tokenChars[tlen++] = PACK_TOKEN_AND_LENGTH(kLiteral, literalLength & 0xFF); - literalLength >>= 8; - while (literalLength) { - tokenChars[tlen++] = PACK_TOKEN_AND_LENGTH(kLiteral | 0x80, literalLength & 0xFF); - literalLength >>= 8; - } - tokens.releaseBuffer(tlen); -} - -void -AffixPattern::add(ETokenType t) { - add(t, 1); -} - -void -AffixPattern::addCurrency(uint8_t count) { - add(kCurrency, count); -} - -void -AffixPattern::add(ETokenType t, uint8_t count) { - U_ASSERT(t != kLiteral); - char32Count += count; - switch (t) { - case kCurrency: - hasCurrencyToken = TRUE; - break; - case kPercent: - hasPercentToken = TRUE; - break; - case kPerMill: - hasPermillToken = TRUE; - break; - default: - // Do nothing - break; - } - tokens.append(PACK_TOKEN_AND_LENGTH(t, count)); -} - -AffixPattern & -AffixPattern::append(const AffixPattern &other) { - AffixPatternIterator iter; - other.iterator(iter); - UnicodeString literal; - while (iter.nextToken()) { - switch (iter.getTokenType()) { - case kLiteral: - iter.getLiteral(literal); - addLiteral(literal.getBuffer(), 0, literal.length()); - break; - case kCurrency: - addCurrency(static_cast(iter.getTokenLength())); - break; - default: - add(iter.getTokenType()); - break; - } - } - return *this; -} - -void -AffixPattern::remove() { - tokens.remove(); - literals.remove(); - hasCurrencyToken = FALSE; - hasPercentToken = FALSE; - hasPermillToken = FALSE; - char32Count = 0; -} - -// escapes literals for strings where special characters are NOT escaped -// except for apostrophe. -static void escapeApostropheInLiteral( - const UnicodeString &literal, UnicodeStringAppender &appender) { - int32_t len = literal.length(); - const UChar *buffer = literal.getBuffer(); - for (int32_t i = 0; i < len; ++i) { - UChar ch = buffer[i]; - switch (ch) { - case 0x27: - appender.append((UChar) 0x27); - appender.append((UChar) 0x27); - break; - default: - appender.append(ch); - break; - } - } -} - - -// escapes literals for user strings where special characters in literals -// are escaped with apostrophe. -static void escapeLiteral( - const UnicodeString &literal, UnicodeStringAppender &appender) { - int32_t len = literal.length(); - const UChar *buffer = literal.getBuffer(); - for (int32_t i = 0; i < len; ++i) { - UChar ch = buffer[i]; - switch (ch) { - case 0x27: - appender.append((UChar) 0x27); - appender.append((UChar) 0x27); - break; - case 0x25: - appender.append((UChar) 0x27); - appender.append((UChar) 0x25); - appender.append((UChar) 0x27); - break; - case 0x2030: - appender.append((UChar) 0x27); - appender.append((UChar) 0x2030); - appender.append((UChar) 0x27); - break; - case 0xA4: - appender.append((UChar) 0x27); - appender.append((UChar) 0xA4); - appender.append((UChar) 0x27); - break; - case 0x2D: - appender.append((UChar) 0x27); - appender.append((UChar) 0x2D); - appender.append((UChar) 0x27); - break; - case 0x2B: - appender.append((UChar) 0x27); - appender.append((UChar) 0x2B); - appender.append((UChar) 0x27); - break; - default: - appender.append(ch); - break; - } - } -} - -UnicodeString & -AffixPattern::toString(UnicodeString &appendTo) const { - AffixPatternIterator iter; - iterator(iter); - UnicodeStringAppender appender(appendTo); - UnicodeString literal; - while (iter.nextToken()) { - switch (iter.getTokenType()) { - case kLiteral: - escapeApostropheInLiteral(iter.getLiteral(literal), appender); - break; - case kPercent: - appender.append((UChar) 0x27); - appender.append((UChar) 0x25); - break; - case kPerMill: - appender.append((UChar) 0x27); - appender.append((UChar) 0x2030); - break; - case kCurrency: - { - appender.append((UChar) 0x27); - int32_t cl = iter.getTokenLength(); - for (int32_t i = 0; i < cl; ++i) { - appender.append((UChar) 0xA4); - } - } - break; - case kNegative: - appender.append((UChar) 0x27); - appender.append((UChar) 0x2D); - break; - case kPositive: - appender.append((UChar) 0x27); - appender.append((UChar) 0x2B); - break; - default: - U_ASSERT(FALSE); - break; - } - } - return appendTo; -} - -UnicodeString & -AffixPattern::toUserString(UnicodeString &appendTo) const { - AffixPatternIterator iter; - iterator(iter); - UnicodeStringAppender appender(appendTo); - UnicodeString literal; - while (iter.nextToken()) { - switch (iter.getTokenType()) { - case kLiteral: - escapeLiteral(iter.getLiteral(literal), appender); - break; - case kPercent: - appender.append((UChar) 0x25); - break; - case kPerMill: - appender.append((UChar) 0x2030); - break; - case kCurrency: - { - int32_t cl = iter.getTokenLength(); - for (int32_t i = 0; i < cl; ++i) { - appender.append((UChar) 0xA4); - } - } - break; - case kNegative: - appender.append((UChar) 0x2D); - break; - case kPositive: - appender.append((UChar) 0x2B); - break; - default: - U_ASSERT(FALSE); - break; - } - } - return appendTo; -} - -class AffixPatternAppender : public UMemory { -public: - AffixPatternAppender(AffixPattern &dest) : fDest(&dest), fIdx(0) { } - - inline void append(UChar x) { - if (fIdx == UPRV_LENGTHOF(fBuffer)) { - fDest->addLiteral(fBuffer, 0, fIdx); - fIdx = 0; - } - fBuffer[fIdx++] = x; - } - - inline void append(UChar32 x) { - if (fIdx >= UPRV_LENGTHOF(fBuffer) - 1) { - fDest->addLiteral(fBuffer, 0, fIdx); - fIdx = 0; - } - U16_APPEND_UNSAFE(fBuffer, fIdx, x); - } - - inline void flush() { - if (fIdx) { - fDest->addLiteral(fBuffer, 0, fIdx); - } - fIdx = 0; - } - - /** - * flush the buffer when we go out of scope. - */ - ~AffixPatternAppender() { - flush(); - } -private: - AffixPattern *fDest; - int32_t fIdx; - UChar fBuffer[32]; - AffixPatternAppender(const AffixPatternAppender &other); - AffixPatternAppender &operator=(const AffixPatternAppender &other); -}; - - -AffixPattern & -AffixPattern::parseUserAffixString( - const UnicodeString &affixStr, - AffixPattern &appendTo, - UErrorCode &status) { - if (U_FAILURE(status)) { - return appendTo; - } - int32_t len = affixStr.length(); - const UChar *buffer = affixStr.getBuffer(); - // 0 = not quoted; 1 = quoted. - int32_t state = 0; - AffixPatternAppender appender(appendTo); - for (int32_t i = 0; i < len; ) { - UChar token; - int32_t tokenSize = nextUserToken(buffer, i, len, &token); - i += tokenSize; - if (token == 0x27 && tokenSize == 1) { // quote - state = 1 - state; - continue; - } - if (state == 0) { - switch (token) { - case 0x25: - appender.flush(); - appendTo.add(kPercent, 1); - break; - case 0x27: // double quote - appender.append((UChar) 0x27); - break; - case 0x2030: - appender.flush(); - appendTo.add(kPerMill, 1); - break; - case 0x2D: - appender.flush(); - appendTo.add(kNegative, 1); - break; - case 0x2B: - appender.flush(); - appendTo.add(kPositive, 1); - break; - case 0xA4: - appender.flush(); - appendTo.add(kCurrency, static_cast(tokenSize)); - break; - default: - appender.append(token); - break; - } - } else { - switch (token) { - case 0x27: // double quote - appender.append((UChar) 0x27); - break; - case 0xA4: // included b/c tokenSize can be > 1 - for (int32_t j = 0; j < tokenSize; ++j) { - appender.append((UChar) 0xA4); - } - break; - default: - appender.append(token); - break; - } - } - } - return appendTo; -} - -AffixPattern & -AffixPattern::parseAffixString( - const UnicodeString &affixStr, - AffixPattern &appendTo, - UErrorCode &status) { - if (U_FAILURE(status)) { - return appendTo; - } - int32_t len = affixStr.length(); - const UChar *buffer = affixStr.getBuffer(); - for (int32_t i = 0; i < len; ) { - UChar token; - int32_t tokenSize = nextToken(buffer, i, len, &token); - if (tokenSize == 1) { - int32_t literalStart = i; - ++i; - while (i < len && (tokenSize = nextToken(buffer, i, len, &token)) == 1) { - ++i; - } - appendTo.addLiteral(buffer, literalStart, i - literalStart); - - // If we reached end of string, we are done - if (i == len) { - return appendTo; - } - } - i += tokenSize; - switch (token) { - case 0x25: - appendTo.add(kPercent, 1); - break; - case 0x2030: - appendTo.add(kPerMill, 1); - break; - case 0x2D: - appendTo.add(kNegative, 1); - break; - case 0x2B: - appendTo.add(kPositive, 1); - break; - case 0xA4: - { - if (tokenSize - 1 > 3) { - status = U_PARSE_ERROR; - return appendTo; - } - appendTo.add(kCurrency, tokenSize - 1); - } - break; - default: - appendTo.addLiteral(&token, 0, 1); - break; - } - } - return appendTo; -} - -AffixPatternIterator & -AffixPattern::iterator(AffixPatternIterator &result) const { - result.nextLiteralIndex = 0; - result.lastLiteralLength = 0; - result.nextTokenIndex = 0; - result.tokens = &tokens; - result.literals = &literals; - return result; -} - -UBool -AffixPatternIterator::nextToken() { - int32_t tlen = tokens->length(); - if (nextTokenIndex == tlen) { - return FALSE; - } - ++nextTokenIndex; - const UChar *tokenBuffer = tokens->getBuffer(); - if (UNPACK_TOKEN(tokenBuffer[nextTokenIndex - 1]) == - AffixPattern::kLiteral) { - while (nextTokenIndex < tlen && - UNPACK_LONG(tokenBuffer[nextTokenIndex])) { - ++nextTokenIndex; - } - lastLiteralLength = 0; - int32_t i = nextTokenIndex - 1; - for (; UNPACK_LONG(tokenBuffer[i]); --i) { - lastLiteralLength <<= 8; - lastLiteralLength |= UNPACK_LENGTH(tokenBuffer[i]); - } - lastLiteralLength <<= 8; - lastLiteralLength |= UNPACK_LENGTH(tokenBuffer[i]); - nextLiteralIndex += lastLiteralLength; - } - return TRUE; -} - -AffixPattern::ETokenType -AffixPatternIterator::getTokenType() const { - return UNPACK_TOKEN(tokens->charAt(nextTokenIndex - 1)); -} - -UnicodeString & -AffixPatternIterator::getLiteral(UnicodeString &result) const { - const UChar *buffer = literals->getBuffer(); - result.setTo(buffer + (nextLiteralIndex - lastLiteralLength), lastLiteralLength); - return result; -} - -int32_t -AffixPatternIterator::getTokenLength() const { - const UChar *tokenBuffer = tokens->getBuffer(); - AffixPattern::ETokenType type = UNPACK_TOKEN(tokenBuffer[nextTokenIndex - 1]); - return type == AffixPattern::kLiteral ? lastLiteralLength : UNPACK_LENGTH(tokenBuffer[nextTokenIndex - 1]); -} - -AffixPatternParser::AffixPatternParser() - : fPercent(gPercent), fPermill(gPerMill), fNegative(gNegative), fPositive(gPositive) { -} - -AffixPatternParser::AffixPatternParser( - const DecimalFormatSymbols &symbols) { - setDecimalFormatSymbols(symbols); -} - -void -AffixPatternParser::setDecimalFormatSymbols( - const DecimalFormatSymbols &symbols) { - fPercent = symbols.getConstSymbol(DecimalFormatSymbols::kPercentSymbol); - fPermill = symbols.getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); - fNegative = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); - fPositive = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); -} - -PluralAffix & -AffixPatternParser::parse( - const AffixPattern &affixPattern, - const CurrencyAffixInfo ¤cyAffixInfo, - PluralAffix &appendTo, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return appendTo; - } - AffixPatternIterator iter; - affixPattern.iterator(iter); - UnicodeString literal; - while (iter.nextToken()) { - switch (iter.getTokenType()) { - case AffixPattern::kPercent: - appendTo.append(fPercent, UNUM_PERCENT_FIELD); - break; - case AffixPattern::kPerMill: - appendTo.append(fPermill, UNUM_PERMILL_FIELD); - break; - case AffixPattern::kNegative: - appendTo.append(fNegative, UNUM_SIGN_FIELD); - break; - case AffixPattern::kPositive: - appendTo.append(fPositive, UNUM_SIGN_FIELD); - break; - case AffixPattern::kCurrency: - switch (iter.getTokenLength()) { - case 1: - appendTo.append( - currencyAffixInfo.getSymbol(), UNUM_CURRENCY_FIELD); - break; - case 2: - appendTo.append( - currencyAffixInfo.getISO(), UNUM_CURRENCY_FIELD); - break; - case 3: - appendTo.append( - currencyAffixInfo.getLong(), UNUM_CURRENCY_FIELD, status); - break; - default: - U_ASSERT(FALSE); - break; - } - break; - case AffixPattern::kLiteral: - appendTo.append(iter.getLiteral(literal)); - break; - default: - U_ASSERT(FALSE); - break; - } - } - return appendTo; -} - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/affixpatternparser.h b/deps/icu-small/source/i18n/affixpatternparser.h deleted file mode 100644 index b54c749c70..0000000000 --- a/deps/icu-small/source/i18n/affixpatternparser.h +++ /dev/null @@ -1,402 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* affixpatternparser.h -* -* created on: 2015jan06 -* created by: Travis Keep -*/ - -#ifndef __AFFIX_PATTERN_PARSER_H__ -#define __AFFIX_PATTERN_PARSER_H__ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/unistr.h" -#include "unicode/uobject.h" -#include "pluralaffix.h" - -U_NAMESPACE_BEGIN - -class PluralRules; -class FixedPrecision; -class DecimalFormatSymbols; - -/** - * A representation of the various forms of a particular currency according - * to some locale and usage context. - * - * Includes the symbol, ISO code form, and long form(s) of the currency name - * for each plural variation. - */ -class U_I18N_API CurrencyAffixInfo : public UMemory { -public: - /** - * Symbol is \u00a4; ISO form is \u00a4\u00a4; - * long form is \u00a4\u00a4\u00a4. - */ - CurrencyAffixInfo(); - - const UnicodeString &getSymbol() const { return fSymbol; } - const UnicodeString &getISO() const { return fISO; } - const PluralAffix &getLong() const { return fLong; } - void setSymbol(const UnicodeString &symbol) { - fSymbol = symbol; - fIsDefault = FALSE; - } - void setISO(const UnicodeString &iso) { - fISO = iso; - fIsDefault = FALSE; - } - UBool - equals(const CurrencyAffixInfo &other) const { - return (fSymbol == other.fSymbol) - && (fISO == other.fISO) - && (fLong.equals(other.fLong)) - && (fIsDefault == other.fIsDefault); - } - - /** - * Intializes this instance. - * - * @param locale the locale for the currency forms. - * @param rules The plural rules for the locale. - * @param currency the null terminated, 3 character ISO code of the - * currency. If NULL, resets this instance as if it were just created. - * In this case, the first 2 parameters may be NULL as well. - * @param status any error returned here. - */ - void set( - const char *locale, const PluralRules *rules, - const UChar *currency, UErrorCode &status); - - /** - * Returns true if this instance is the default. That is has no real - * currency. For instance never initialized with set() - * or reset with set(NULL, NULL, NULL, status). - */ - UBool isDefault() const { return fIsDefault; } - - /** - * Adjusts the precision used for a particular currency. - * @param currency the null terminated, 3 character ISO code of the - * currency. - * @param usage the usage of the currency - * @param precision min/max fraction digits and rounding increment - * adjusted. - * @params status any error reported here. - */ - static void adjustPrecision( - const UChar *currency, const UCurrencyUsage usage, - FixedPrecision &precision, UErrorCode &status); - -private: - /** - * The symbol form of the currency. - */ - UnicodeString fSymbol; - - /** - * The ISO form of the currency, usually three letter abbreviation. - */ - UnicodeString fISO; - - /** - * The long forms of the currency keyed by plural variation. - */ - PluralAffix fLong; - - UBool fIsDefault; - -}; - -class AffixPatternIterator; - -/** - * A locale agnostic representation of an affix pattern. - */ -class U_I18N_API AffixPattern : public UMemory { -public: - - /** - * The token types that can appear in an affix pattern. - */ - enum ETokenType { - kLiteral, - kPercent, - kPerMill, - kCurrency, - kNegative, - kPositive - }; - - /** - * An empty affix pattern. - */ - AffixPattern() - : tokens(), literals(), hasCurrencyToken(FALSE), - hasPercentToken(FALSE), hasPermillToken(FALSE), char32Count(0) { - } - - /** - * Adds a string literal to this affix pattern. - */ - void addLiteral(const UChar *, int32_t start, int32_t len); - - /** - * Adds a token to this affix pattern. t must not be kLiteral as - * the addLiteral() method adds literals. - * @param t the token type to add - */ - void add(ETokenType t); - - /** - * Adds a currency token with specific count to this affix pattern. - * @param count the token count. Used to distinguish between - * one, two, or three currency symbols. Note that adding a currency - * token with count=2 (Use ISO code) is different than adding two - * currency tokens each with count=1 (two currency symbols). - */ - void addCurrency(uint8_t count); - - /** - * Makes this instance be an empty affix pattern. - */ - void remove(); - - /** - * Provides an iterator over the tokens in this instance. - * @param result this is initialized to point just before the - * first token of this instance. Caller must call nextToken() - * on the iterator once it is set up to have it actually point - * to the first token. This first call to nextToken() will return - * FALSE if the AffixPattern being iterated over is empty. - * @return result - */ - AffixPatternIterator &iterator(AffixPatternIterator &result) const; - - /** - * Returns TRUE if this instance has currency tokens in it. - */ - UBool usesCurrency() const { - return hasCurrencyToken; - } - - UBool usesPercent() const { - return hasPercentToken; - } - - UBool usesPermill() const { - return hasPermillToken; - } - - /** - * Returns the number of code points a string of this instance - * would have if none of the special tokens were escaped. - * Used to compute the padding size. - */ - int32_t countChar32() const { - return char32Count; - } - - /** - * Appends other to this instance mutating this instance in place. - * @param other The pattern appended to the end of this one. - * @return a reference to this instance for chaining. - */ - AffixPattern &append(const AffixPattern &other); - - /** - * Converts this AffixPattern back into a user string. - * It is the inverse of parseUserAffixString. - */ - UnicodeString &toUserString(UnicodeString &appendTo) const; - - /** - * Converts this AffixPattern back into a string. - * It is the inverse of parseAffixString. - */ - UnicodeString &toString(UnicodeString &appendTo) const; - - /** - * Parses an affix pattern string appending it to an AffixPattern. - * Parses affix pattern strings produced from using - * DecimalFormatPatternParser to parse a format pattern. Affix patterns - * include the positive prefix and suffix and the negative prefix - * and suffix. This method expects affix patterns strings to be in the - * same format that DecimalFormatPatternParser produces. Namely special - * characters in the affix that correspond to a field type must be - * prefixed with an apostrophe ('). These special character sequences - * inluce minus (-), percent (%), permile (U+2030), plus (+), - * short currency (U+00a4), medium currency (u+00a4 * 2), - * long currency (u+a4 * 3), and apostrophe (') - * (apostrophe does not correspond to a field type but has to be escaped - * because it itself is the escape character). - * Since the expansion of these special character - * sequences is locale dependent, these sequences are not expanded in - * an AffixPattern instance. - * If these special characters are not prefixed with an apostrophe in - * the affix pattern string, then they are treated verbatim just as - * any other character. If an apostrophe prefixes a non special - * character in the affix pattern, the apostrophe is simply ignored. - * - * @param affixStr the string from DecimalFormatPatternParser - * @param appendTo parsed result appended here. - * @param status any error parsing returned here. - */ - static AffixPattern &parseAffixString( - const UnicodeString &affixStr, - AffixPattern &appendTo, - UErrorCode &status); - - /** - * Parses an affix pattern string appending it to an AffixPattern. - * Parses affix pattern strings as the user would supply them. - * In this function, quoting makes special characters like normal - * characters whereas in parseAffixString, quoting makes special - * characters special. - * - * @param affixStr the string from the user - * @param appendTo parsed result appended here. - * @param status any error parsing returned here. - */ - static AffixPattern &parseUserAffixString( - const UnicodeString &affixStr, - AffixPattern &appendTo, - UErrorCode &status); - - UBool equals(const AffixPattern &other) const { - return (tokens == other.tokens) - && (literals == other.literals) - && (hasCurrencyToken == other.hasCurrencyToken) - && (hasPercentToken == other.hasPercentToken) - && (hasPermillToken == other.hasPermillToken) - && (char32Count == other.char32Count); - } - -private: - /* - * Tokens stored here. Each UChar generally stands for one token. A - * Each token is of form 'etttttttllllllll' llllllll is the length of - * the token and ranges from 0-255. ttttttt is the token type and ranges - * from 0-127. If e is set it means this is an extendo token (to be - * described later). To accomodate token lengths above 255, each normal - * token (e=0) can be followed by 0 or more extendo tokens (e=1) with - * the same type. Right now only kLiteral Tokens have extendo tokens. - * Each extendo token provides the next 8 higher bits for the length. - * If a kLiteral token is followed by 2 extendo tokens then, then the - * llllllll of the next extendo token contains bits 8-15 of the length - * and the last extendo token contains bits 16-23 of the length. - */ - UnicodeString tokens; - - /* - * The characters of the kLiteral tokens are concatenated together here. - * The first characters go with the first kLiteral token, the next - * characters go with the next kLiteral token etc. - */ - UnicodeString literals; - UBool hasCurrencyToken; - UBool hasPercentToken; - UBool hasPermillToken; - int32_t char32Count; - void add(ETokenType t, uint8_t count); - -}; - -/** - * An iterator over the tokens in an AffixPattern instance. - */ -class U_I18N_API AffixPatternIterator : public UMemory { -public: - - /** - * Using an iterator without first calling iterator on an AffixPattern - * instance to initialize the iterator results in - * undefined behavior. - */ - AffixPatternIterator() : nextLiteralIndex(0), lastLiteralLength(0), nextTokenIndex(0), tokens(NULL), literals(NULL) { } - /** - * Advances this iterator to the next token. Returns FALSE when there - * are no more tokens. Calling the other methods after nextToken() - * returns FALSE results in undefined behavior. - */ - UBool nextToken(); - - /** - * Returns the type of token. - */ - AffixPattern::ETokenType getTokenType() const; - - /** - * For literal tokens, returns the literal string. Calling this for - * other token types results in undefined behavior. - * @param result replaced with a read-only alias to the literal string. - * @return result - */ - UnicodeString &getLiteral(UnicodeString &result) const; - - /** - * Returns the token length. Usually 1, but for currency tokens may - * be 2 for ISO code and 3 for long form. - */ - int32_t getTokenLength() const; -private: - int32_t nextLiteralIndex; - int32_t lastLiteralLength; - int32_t nextTokenIndex; - const UnicodeString *tokens; - const UnicodeString *literals; - friend class AffixPattern; - AffixPatternIterator(const AffixPatternIterator &); - AffixPatternIterator &operator=(const AffixPatternIterator &); -}; - -/** - * A locale aware class that converts locale independent AffixPattern - * instances into locale dependent PluralAffix instances. - */ -class U_I18N_API AffixPatternParser : public UMemory { -public: -AffixPatternParser(); -AffixPatternParser(const DecimalFormatSymbols &symbols); -void setDecimalFormatSymbols(const DecimalFormatSymbols &symbols); - -/** - * Parses affixPattern appending the result to appendTo. - * @param affixPattern The affix pattern. - * @param currencyAffixInfo contains the currency forms. - * @param appendTo The result of parsing affixPattern is appended here. - * @param status any error returned here. - * @return appendTo. - */ -PluralAffix &parse( - const AffixPattern &affixPattern, - const CurrencyAffixInfo ¤cyAffixInfo, - PluralAffix &appendTo, - UErrorCode &status) const; - -UBool equals(const AffixPatternParser &other) const { - return (fPercent == other.fPercent) - && (fPermill == other.fPermill) - && (fNegative == other.fNegative) - && (fPositive == other.fPositive); -} - -private: -UnicodeString fPercent; -UnicodeString fPermill; -UnicodeString fNegative; -UnicodeString fPositive; -}; - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ -#endif // __AFFIX_PATTERN_PARSER_H__ diff --git a/deps/icu-small/source/i18n/collationfcd.cpp b/deps/icu-small/source/i18n/collationfcd.cpp index 19841ee648..1aff936dee 100644 --- a/deps/icu-small/source/i18n/collationfcd.cpp +++ b/deps/icu-small/source/i18n/collationfcd.cpp @@ -22,27 +22,27 @@ const uint8_t CollationFCD::lcccIndex[2048]={ 0,0,0,0,0,0,0,0,1,1,2,3,0,0,0,0, 0,0,0,0,4,0,0,0,0,0,0,0,5,6,7,0, 8,0,9,0xa,0,0,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0x10, -0x11,0x12,0x13,0,0,0,0x14,0x15,0,0x16,0x17,0,0,0x16,0x18,0, +0x11,0x12,0x13,0,0,0,0x14,0x15,0,0x16,0x17,0,0,0x16,0x18,0x19, 0,0x16,0x18,0,0,0x16,0x18,0,0,0x16,0x18,0,0,0,0x18,0, -0,0,0x19,0,0,0x16,0x18,0,0,0x1a,0x18,0,0,0,0x1b,0, -0,0x1c,0x1d,0,0,0x1e,0x1d,0,0x1e,0x1f,0,0x20,0x21,0,0x22,0, -0,0x23,0,0,0x18,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0x24,0,0,0,0,0, +0,0,0x1a,0,0,0x16,0x18,0,0,0x1b,0x18,0,0,0,0x1c,0, +0,0x1d,0x1e,0,0,0x1f,0x1e,0,0x1f,0x20,0,0x21,0x22,0,0x23,0, +0,0x24,0,0,0x18,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0x25,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0x25,0x25,0,0,0,0,0x26,0, -0,0,0,0,0,0x27,0,0,0,0x13,0,0,0,0,0,0, -0x28,0,0,0x29,0,0x2a,0,0,0,0x25,0x2b,0x10,0,0x2c,0,0x2d, -0,0x2e,0,0,0,0,0x2f,0x30,0,0,0,0,0,0,1,0x31, +0,0,0,0,0,0,0,0,0x26,0x26,0,0,0,0,0x27,0, +0,0,0,0,0,0x28,0,0,0,0x13,0,0,0,0,0,0, +0x29,0,0,0x2a,0,0x2b,0,0,0,0x26,0x2c,0x2d,0,0x2e,0,0x2f, +0,0x30,0,0,0,0,0x31,0x32,0,0,0,0,0,0,1,0x33, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0x32,0x33,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0x34,0x35,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0x34,0,0,0,0x35,0,0,0,1, +0,0,0,0,0,0,0,0x36,0,0,0,0x37,0,0,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0x36,0,0,0x37,0,0,0,0,0,0,0,0,0,0,0, +0,0x38,0,0,0x39,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -101,9 +101,9 @@ const uint8_t CollationFCD::lcccIndex[2048]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0x38,0x39,0,0,0x3a,0,0,0,0,0,0,0,0, -0x22,0,0,0,0,0,0x2b,0x3b,0,0x3c,0x3d,0,0,0x3d,0x3e,0, -0,0,0,0,0,0x3f,0x40,0x41,0,0,0,0,0,0,0,0x18, +0,0,0,0x3a,0x3b,0,0,0x3c,0,0,0,0,0,0,0,0, +0x23,0,0,0,0,0,0x2c,0x3d,0,0x3e,0x3f,0,0,0x3f,0x40,0, +0,0,0,0,0,0x41,0x42,0x43,0,0,0,0,0,0,0,0x18, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -126,7 +126,7 @@ const uint8_t CollationFCD::lcccIndex[2048]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x42,0x43,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0x44,0x45,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, @@ -143,17 +143,17 @@ const uint8_t CollationFCD::lcccIndex[2048]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0x44,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x19,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -const uint32_t CollationFCD::lcccBits[69]={ +const uint32_t CollationFCD::lcccBits[70]={ 0,0xffffffff,0xffff7fff,0xffff,0xf8,0xfffe0000,0xbfffffff,0xb6,0x7ff0000,0xfffff800,0x10000,0x9fc00000,0x3d9f,0x20000,0xffff0000,0x7ff, -0xff800,0xfbc00000,0x3eef,0xe000000,0xfff00000,0xfffffffb,0x10000000,0x1e2000,0x2000,0x602000,0x18000000,0x400,0x7000000,0xf00,0x3000000,0x2a00000, -0x3c3e0000,0xdf,0x40,0x6800000,0xe0000000,0x100000,0x20040000,0x200,0x1800000,0x9fe00001,0x3fff0000,0x10,0xc00,0xc0040,0x800000,0xfff70000, -0x31021fd,0xfbffffff,0x1fff0000,0x1ffe2,0x38000,0x80000000,0xfc00,0x6000000,0x3ff08000,0xc0000000,0x30000,0x3ffff,0x3800,0x80000,1,0xc19d0000, -2,0x400000,0x40000f5,0x5108000,0x40000000 +0x200ff800,0xfbc00000,0x3eef,0xe000000,0xfff80000,0xfffffffb,0x10000000,0x1e2000,0x2000,0x40000000,0x602000,0x18000000,0x400,0x7000000,0xf00,0x3000000, +0x2a00000,0x3c3e0000,0xdf,0x40,0x6800000,0xe0000000,0x100000,0x20040000,0x200,0x1800000,0x9fe00001,0x3fff0000,0x10,0xff800,0xc00,0xc0040, +0x800000,0xfff70000,0x31021fd,0xfbffffff,0x1fff0000,0x1ffe2,0x38000,0x80000000,0xfc00,0x6000000,0x3ff08000,0xc0000000,0x30000,0x3ffff,0x3800,0x80000, +1,0xc19d0000,2,0x400000,0x40000fd,0x5108000 }; const uint8_t CollationFCD::tcccIndex[2048]={ @@ -161,27 +161,27 @@ const uint8_t CollationFCD::tcccIndex[2048]={ 0xb,0xc,0,0,0,0,0,0,1,1,0xd,0xe,0xf,0x10,0x11,0, 0x12,0x13,0x14,0x15,0x16,0,0x17,0x18,0,0,0,0,0x19,0x1a,0x1b,0, 0x1c,0x1d,0x1e,0x1f,0,0,0x20,0x21,0x22,0x23,0x24,0,0,0,0,0x25, -0x26,0x27,0x28,0,0,0,0x29,0x2a,0,0x2b,0x2c,0,0,0x2d,0x2e,0, -0,0x2f,0x30,0,0,0x2d,0x31,0,0,0x2d,0x32,0,0,0,0x31,0, -0,0,0x33,0,0,0x2d,0x31,0,0,0x34,0x31,0,0,0,0x35,0, -0,0x36,0x37,0,0,0x38,0x37,0,0x38,0x39,0,0x3a,0x3b,0,0x3c,0, -0,0x3d,0,0,0x31,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0x3e,0,0,0,0,0, +0x26,0x27,0x28,0,0,0,0x29,0x2a,0,0x2b,0x2c,0,0,0x2d,0x2e,0x2f, +0,0x30,0x31,0,0,0x2d,0x32,0,0,0x2d,0x33,0,0,0,0x32,0, +0,0,0x34,0,0,0x2d,0x32,0,0,0x35,0x32,0,0,0,0x36,0, +0,0x37,0x38,0,0,0x39,0x38,0,0x39,0x3a,0,0x3b,0x3c,0,0x3d,0, +0,0x3e,0,0,0x32,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0x3f,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0x3f,0x3f,0,0,0,0,0x40,0, -0,0,0,0,0,0x41,0,0,0,0x28,0,0,0,0,0,0, -0x42,0,0,0x43,0,0x44,0,0,0,0x3f,0x45,0x25,0,0x46,0,0x47, -0,0x48,0,0,0,0,0x49,0x4a,0,0,0,0,0,0,1,0x4b, -1,1,1,1,0x4c,1,1,0x4d,0x4e,1,0x4f,0x50,1,0x51,0x52,0x53, -0,0,0,0,0,0,0x54,0x55,0,0x56,0,0,0x57,0x58,0x59,0, -0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0,0x60,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x40,0x40,0,0,0,0,0x41,0, +0,0,0,0,0,0x42,0,0,0,0x28,0,0,0,0,0,0, +0x43,0,0,0x44,0,0x45,0,0,0,0x40,0x46,0x47,0,0x48,0,0x49, +0,0x4a,0,0,0,0,0x4b,0x4c,0,0,0,0,0,0,1,0x4d, +1,1,1,1,0x4e,1,1,0x4f,0x50,1,0x51,0x52,1,0x53,0x54,0x55, +0,0,0,0,0,0,0x56,0x57,0,0x58,0,0,0x59,0x5a,0x5b,0, +0x5c,0x5d,0x5e,0x5f,0x60,0x61,0,0x62,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0x2d,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0x61,0,0,0,0x62,0,0,0,1, +0,0,0,0,0,0,0,0x63,0,0,0,0x64,0,0,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0x63,0x64,0x65,0x66,0x64,0x65,0x67,0,0,0,0,0,0,0,0, +0,0x65,0x66,0x67,0x68,0x66,0x67,0x69,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -240,9 +240,9 @@ const uint8_t CollationFCD::tcccIndex[2048]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0x68,0x69,0,0,0x6a,0,0,0,0,0,0,0,0, -0x3c,0,0,0,0,0,0x45,0x6b,0,0x6c,0x6d,0,0,0x6d,0x6e,0, -0,0,0,0,0,0x6f,0x70,0x71,0,0,0,0,0,0,0,0x31, +0,0,0,0x6a,0x6b,0,0,0x6c,0,0,0,0,0,0,0,0, +0x3d,0,0,0,0,0,0x46,0x6d,0,0x6e,0x6f,0,0,0x6f,0x70,0, +0,0,0,0,0,0x71,0x72,0x73,0,0,0,0,0,0,0,0x32, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -265,7 +265,7 @@ const uint8_t CollationFCD::tcccIndex[2048]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x72,0x73,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0x74,0x75,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -282,20 +282,20 @@ const uint8_t CollationFCD::tcccIndex[2048]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0x3e,0x74,0x75,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x3f,0x76,0x77,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xe,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -const uint32_t CollationFCD::tcccBits[118]={ +const uint32_t CollationFCD::tcccBits[120]={ 0,0xffffffff,0x3e7effbf,0xbe7effbf,0xfffcffff,0x7ef1ff3f,0xfff3f1f8,0x7fffff3f,0x18003,0xdfffe000,0xff31ffcf,0xcfffffff,0xfffc0,0xffff7fff,0xffff,0x1d760, 0x1fc00,0x187c00,0x200708b,0x2000000,0x708b0000,0xc00000,0xf8,0xfccf0006,0x33ffcfc,0xfffe0000,0xbfffffff,0xb6,0x7ff0000,0x7c,0xfffff800,0x10000, -0x9fc80005,0x3d9f,0x20000,0xffff0000,0x7ff,0xff800,0xfbc00000,0x3eef,0xe000000,0xfff00000,0xfffffffb,0x10120200,0xff1e2000,0x10000000,0xb0002000,0x10480000, -0x4e002000,0x2000,0x30002000,0x602100,0x18000000,0x24000400,0x7000000,0xf00,0x3000000,0x2a00000,0x3d7e0000,0xdf,0x40,0x6800000,0xe0000000,0x100000, -0x20040000,0x200,0x1800000,0x9fe00001,0x3fff0000,0x10,0xc00,0xc0040,0x800000,0xfff70000,0x31021fd,0xfbffffff,0xbffffff,0x3ffffff,0x3f3fffff,0xaaff3f3f, -0x3fffffff,0x1fdfffff,0xefcfffde,0x1fdc7fff,0x1fff0000,0x1ffe2,0x800,0xc000000,0x4000,0xe000,0x1210,0x50,0x292,0x333e005,0x333,0xf000, -0x3c0f,0x38000,0x80000000,0xfc00,0x55555000,0x36db02a5,0x46100000,0x47900000,0x3ff08000,0xc0000000,0x30000,0x3ffff,0x3800,0x80000,1,0xc19d0000, -2,0x400000,0x40000f5,0x5108000,0x5f7ffc00,0x7fdb +0x9fc80005,0x3d9f,0x20000,0xffff0000,0x7ff,0x200ff800,0xfbc00000,0x3eef,0xe000000,0xfff80000,0xfffffffb,0x10120200,0xff1e2000,0x10000000,0xb0002000,0x40000000, +0x10480000,0x4e002000,0x2000,0x30002000,0x602100,0x18000000,0x24000400,0x7000000,0xf00,0x3000000,0x2a00000,0x3d7e0000,0xdf,0x40,0x6800000,0xe0000000, +0x100000,0x20040000,0x200,0x1800000,0x9fe00001,0x3fff0000,0x10,0xff800,0xc00,0xc0040,0x800000,0xfff70000,0x31021fd,0xfbffffff,0xbffffff,0x3ffffff, +0x3f3fffff,0xaaff3f3f,0x3fffffff,0x1fdfffff,0xefcfffde,0x1fdc7fff,0x1fff0000,0x1ffe2,0x800,0xc000000,0x4000,0xe000,0x1210,0x50,0x292,0x333e005, +0x333,0xf000,0x3c0f,0x38000,0x80000000,0xfc00,0x55555000,0x36db02a5,0x46100000,0x47900000,0x3ff08000,0xc0000000,0x30000,0x3ffff,0x3800,0x80000, +1,0xc19d0000,2,0x400000,0x40000fd,0x5108000,0x5f7ffc00,0x7fdb }; U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/compactdecimalformat.cpp b/deps/icu-small/source/i18n/compactdecimalformat.cpp index b2aacc45cd..4dd2241b23 100644 --- a/deps/icu-small/source/i18n/compactdecimalformat.cpp +++ b/deps/icu-small/source/i18n/compactdecimalformat.cpp @@ -1,1013 +1,75 @@ -// © 2016 and later: Unicode, Inc. and others. +// © 2018 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 1997-2015, International Business Machines Corporation and * -* others. All Rights Reserved. * -******************************************************************************* -* -* File COMPACTDECIMALFORMAT.CPP -* -******************************************************************************** -*/ + #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING -#include "charstr.h" -#include "cstring.h" -#include "digitlst.h" -#include "mutex.h" -#include "unicode/compactdecimalformat.h" -#include "unicode/numsys.h" -#include "unicode/plurrule.h" -#include "unicode/ures.h" -#include "ucln_in.h" -#include "uhash.h" -#include "umutex.h" -#include "unicode/ures.h" -#include "uresimp.h" - -// Maps locale name to CDFLocaleData struct. -static UHashtable* gCompactDecimalData = NULL; -static UMutex gCompactDecimalMetaLock = U_MUTEX_INITIALIZER; - -U_NAMESPACE_BEGIN - -static const int32_t MAX_DIGITS = 15; -static const char gOther[] = "other"; -static const char gLatnTag[] = "latn"; -static const char gNumberElementsTag[] = "NumberElements"; -static const char gDecimalFormatTag[] = "decimalFormat"; -static const char gPatternsShort[] = "patternsShort"; -static const char gPatternsLong[] = "patternsLong"; -static const char gLatnPath[] = "NumberElements/latn"; - -static const UChar u_0 = 0x30; -static const UChar u_apos = 0x27; - -static const UChar kZero[] = {u_0}; - -// Used to unescape single quotes. -enum QuoteState { - OUTSIDE, - INSIDE_EMPTY, - INSIDE_FULL -}; - -enum FallbackFlags { - ANY = 0, - MUST = 1, - NOT_ROOT = 2 - // Next one will be 4 then 6 etc. -}; - - -// CDFUnit represents a prefix-suffix pair for a particular variant -// and log10 value. -struct CDFUnit : public UMemory { - UnicodeString prefix; - UnicodeString suffix; - inline CDFUnit() : prefix(), suffix() { - prefix.setToBogus(); - } - inline ~CDFUnit() {} - inline UBool isSet() const { - return !prefix.isBogus(); - } - inline void markAsSet() { - prefix.remove(); - } -}; - -// CDFLocaleStyleData contains formatting data for a particular locale -// and style. -class CDFLocaleStyleData : public UMemory { - public: - // What to divide by for each log10 value when formatting. These values - // will be powers of 10. For English, would be: - // 1, 1, 1, 1000, 1000, 1000, 1000000, 1000000, 1000000, 1000000000 ... - double divisors[MAX_DIGITS]; - // Maps plural variants to CDFUnit[MAX_DIGITS] arrays. - // To format a number x, - // first compute log10(x). Compute displayNum = (x / divisors[log10(x)]). - // Compute the plural variant for displayNum - // (e.g zero, one, two, few, many, other). - // Compute cdfUnits = unitsByVariant[pluralVariant]. - // Prefix and suffix to use at cdfUnits[log10(x)] - UHashtable* unitsByVariant; - // A flag for whether or not this CDFLocaleStyleData was loaded from the - // Latin numbering system as a fallback from the locale numbering system. - // This value is meaningless if the object is bogus or empty. - UBool fromFallback; - inline CDFLocaleStyleData() : unitsByVariant(NULL), fromFallback(FALSE) { - uprv_memset(divisors, 0, sizeof(divisors)); - } - ~CDFLocaleStyleData(); - // Init initializes this object. - void Init(UErrorCode& status); - inline UBool isBogus() const { - return unitsByVariant == NULL; - } - void setToBogus(); - UBool isEmpty() { - return unitsByVariant == NULL || unitsByVariant->count == 0; - } - private: - CDFLocaleStyleData(const CDFLocaleStyleData&); - CDFLocaleStyleData& operator=(const CDFLocaleStyleData&); -}; - -// CDFLocaleData contains formatting data for a particular locale. -struct CDFLocaleData : public UMemory { - CDFLocaleStyleData shortData; - CDFLocaleStyleData longData; - inline CDFLocaleData() : shortData(), longData() { } - inline ~CDFLocaleData() { } - // Init initializes this object. - void Init(UErrorCode& status); -}; - -U_NAMESPACE_END - -U_CDECL_BEGIN - -static UBool U_CALLCONV cdf_cleanup(void) { - if (gCompactDecimalData != NULL) { - uhash_close(gCompactDecimalData); - gCompactDecimalData = NULL; - } - return TRUE; -} - -static void U_CALLCONV deleteCDFUnits(void* ptr) { - delete [] (icu::CDFUnit*) ptr; -} - -static void U_CALLCONV deleteCDFLocaleData(void* ptr) { - delete (icu::CDFLocaleData*) ptr; -} - -U_CDECL_END +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT -U_NAMESPACE_BEGIN +#include "unicode/compactdecimalformat.h" +#include "number_mapper.h" +#include "number_decimfmtprops.h" -static UBool divisors_equal(const double* lhs, const double* rhs); -static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status); +using namespace icu; -static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status); -static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status); -static void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status); -static int32_t populatePrefixSuffix(const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UBool overwrite, UErrorCode& status); -static double calculateDivisor(double power10, int32_t numZeros); -static UBool onlySpaces(UnicodeString u); -static void fixQuotes(UnicodeString& s); -static void checkForOtherVariants(CDFLocaleStyleData* result, UErrorCode& status); -static void fillInMissing(CDFLocaleStyleData* result); -static int32_t computeLog10(double x, UBool inRange); -static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status); -static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value); UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat) -CompactDecimalFormat::CompactDecimalFormat( - const DecimalFormat& decimalFormat, - const UHashtable* unitsByVariant, - const double* divisors, - PluralRules* pluralRules) - : DecimalFormat(decimalFormat), _unitsByVariant(unitsByVariant), _divisors(divisors), _pluralRules(pluralRules) { -} - -CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source) - : DecimalFormat(source), _unitsByVariant(source._unitsByVariant), _divisors(source._divisors), _pluralRules(source._pluralRules->clone()) { -} - -CompactDecimalFormat* U_EXPORT2 -CompactDecimalFormat::createInstance( - const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) { - LocalPointer decfmt((DecimalFormat*) NumberFormat::makeInstance(inLocale, UNUM_DECIMAL, TRUE, status)); - if (U_FAILURE(status)) { - return NULL; - } - LocalPointer pluralRules(PluralRules::forLocale(inLocale, status)); - if (U_FAILURE(status)) { - return NULL; - } - const CDFLocaleStyleData* data = getCDFLocaleStyleData(inLocale, style, status); - if (U_FAILURE(status)) { - return NULL; - } - CompactDecimalFormat* result = - new CompactDecimalFormat(*decfmt, data->unitsByVariant, data->divisors, pluralRules.getAlias()); - if (result == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - pluralRules.orphan(); - result->setMaximumSignificantDigits(3); - result->setSignificantDigitsUsed(TRUE); - result->setGroupingUsed(FALSE); - return result; -} - -CompactDecimalFormat& -CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) { - if (this != &rhs) { - DecimalFormat::operator=(rhs); - _unitsByVariant = rhs._unitsByVariant; - _divisors = rhs._divisors; - delete _pluralRules; - _pluralRules = rhs._pluralRules->clone(); - } - return *this; -} - -CompactDecimalFormat::~CompactDecimalFormat() { - delete _pluralRules; -} - -Format* -CompactDecimalFormat::clone(void) const { - return new CompactDecimalFormat(*this); +CompactDecimalFormat* +CompactDecimalFormat::createInstance(const Locale& inLocale, UNumberCompactStyle style, + UErrorCode& status) { + return new CompactDecimalFormat(inLocale, style, status); } -UBool -CompactDecimalFormat::operator==(const Format& that) const { - if (this == &that) { - return TRUE; - } - return (DecimalFormat::operator==(that) && eqHelper((const CompactDecimalFormat&) that)); -} - -UBool -CompactDecimalFormat::eqHelper(const CompactDecimalFormat& that) const { - return uhash_equals(_unitsByVariant, that._unitsByVariant) && divisors_equal(_divisors, that._divisors) && (*_pluralRules == *that._pluralRules); -} - -UnicodeString& -CompactDecimalFormat::format( - double number, - UnicodeString& appendTo, - FieldPosition& pos) const { - UErrorCode status = U_ZERO_ERROR; - return format(number, appendTo, pos, status); -} - -UnicodeString& -CompactDecimalFormat::format( - double number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return appendTo; - } - DigitList orig, rounded; - orig.set(number); - UBool isNegative; - _round(orig, rounded, isNegative, status); - if (U_FAILURE(status)) { - return appendTo; - } - double roundedDouble = rounded.getDouble(); - if (isNegative) { - roundedDouble = -roundedDouble; - } - int32_t baseIdx = computeLog10(roundedDouble, TRUE); - double numberToFormat = roundedDouble / _divisors[baseIdx]; - UnicodeString variant = _pluralRules->select(numberToFormat); - if (isNegative) { - numberToFormat = -numberToFormat; - } - const CDFUnit* unit = getCDFUnitFallback(_unitsByVariant, variant, baseIdx); - appendTo += unit->prefix; - DecimalFormat::format(numberToFormat, appendTo, pos); - appendTo += unit->suffix; - return appendTo; -} - -UnicodeString& -CompactDecimalFormat::format( - double /* number */, - UnicodeString& appendTo, - FieldPositionIterator* /* posIter */, - UErrorCode& status) const { - status = U_UNSUPPORTED_ERROR; - return appendTo; -} - -UnicodeString& -CompactDecimalFormat::format( - int32_t number, - UnicodeString& appendTo, - FieldPosition& pos) const { - return format((double) number, appendTo, pos); -} - -UnicodeString& -CompactDecimalFormat::format( - int32_t number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const { - return format((double) number, appendTo, pos, status); -} - -UnicodeString& -CompactDecimalFormat::format( - int32_t /* number */, - UnicodeString& appendTo, - FieldPositionIterator* /* posIter */, - UErrorCode& status) const { - status = U_UNSUPPORTED_ERROR; - return appendTo; -} - -UnicodeString& -CompactDecimalFormat::format( - int64_t number, - UnicodeString& appendTo, - FieldPosition& pos) const { - return format((double) number, appendTo, pos); -} - -UnicodeString& -CompactDecimalFormat::format( - int64_t number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const { - return format((double) number, appendTo, pos, status); +CompactDecimalFormat::CompactDecimalFormat(const Locale& inLocale, UNumberCompactStyle style, + UErrorCode& status) + : DecimalFormat(new DecimalFormatSymbols(inLocale, status), status) { + if (U_FAILURE(status)) return; + // Minimal properties: let the non-shim code path do most of the logic for us. + fields->properties->compactStyle = style; + fields->properties->groupingSize = -2; // do not forward grouping information + fields->properties->minimumGroupingDigits = 2; + touch(status); } -UnicodeString& -CompactDecimalFormat::format( - int64_t /* number */, - UnicodeString& appendTo, - FieldPositionIterator* /* posIter */, - UErrorCode& status) const { - status = U_UNSUPPORTED_ERROR; - return appendTo; -} +CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source) = default; -UnicodeString& -CompactDecimalFormat::format( - StringPiece /* number */, - UnicodeString& appendTo, - FieldPositionIterator* /* posIter */, - UErrorCode& status) const { - status = U_UNSUPPORTED_ERROR; - return appendTo; -} +CompactDecimalFormat::~CompactDecimalFormat() = default; -UnicodeString& -CompactDecimalFormat::format( - const DigitList& /* number */, - UnicodeString& appendTo, - FieldPositionIterator* /* posIter */, - UErrorCode& status) const { - status = U_UNSUPPORTED_ERROR; - return appendTo; +CompactDecimalFormat& CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) { + DecimalFormat::operator=(rhs); + return *this; } -UnicodeString& -CompactDecimalFormat::format(const DigitList& /* number */, - UnicodeString& appendTo, - FieldPosition& /* pos */, - UErrorCode& status) const { - status = U_UNSUPPORTED_ERROR; - return appendTo; +Format* CompactDecimalFormat::clone() const { + return new CompactDecimalFormat(*this); } void CompactDecimalFormat::parse( - const UnicodeString& /* text */, - Formattable& /* result */, - ParsePosition& /* parsePosition */) const { + const UnicodeString& /* text */, + Formattable& /* result */, + ParsePosition& /* parsePosition */) const { } void CompactDecimalFormat::parse( - const UnicodeString& /* text */, - Formattable& /* result */, - UErrorCode& status) const { - status = U_UNSUPPORTED_ERROR; + const UnicodeString& /* text */, + Formattable& /* result */, + UErrorCode& status) const { + status = U_UNSUPPORTED_ERROR; } CurrencyAmount* CompactDecimalFormat::parseCurrency( - const UnicodeString& /* text */, - ParsePosition& /* pos */) const { - return NULL; -} - -void CDFLocaleStyleData::Init(UErrorCode& status) { - if (unitsByVariant != NULL) { - return; - } - unitsByVariant = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); - if (U_FAILURE(status)) { - return; - } - uhash_setKeyDeleter(unitsByVariant, uprv_free); - uhash_setValueDeleter(unitsByVariant, deleteCDFUnits); -} - -CDFLocaleStyleData::~CDFLocaleStyleData() { - setToBogus(); -} - -void CDFLocaleStyleData::setToBogus() { - if (unitsByVariant != NULL) { - uhash_close(unitsByVariant); - unitsByVariant = NULL; - } -} - -void CDFLocaleData::Init(UErrorCode& status) { - shortData.Init(status); - if (U_FAILURE(status)) { - return; - } - longData.Init(status); -} - -// Helper method for operator= -static UBool divisors_equal(const double* lhs, const double* rhs) { - for (int32_t i = 0; i < MAX_DIGITS; ++i) { - if (lhs[i] != rhs[i]) { - return FALSE; - } - } - return TRUE; -} - -// getCDFLocaleStyleData returns pointer to formatting data for given locale and -// style within the global cache. On cache miss, getCDFLocaleStyleData loads -// the data from CLDR into the global cache before returning the pointer. If a -// UNUM_LONG data is requested for a locale, and that locale does not have -// UNUM_LONG data, getCDFLocaleStyleData will fall back to UNUM_SHORT data for -// that locale. -static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) { - if (U_FAILURE(status)) { - return NULL; - } - CDFLocaleData* result = NULL; - const char* key = inLocale.getName(); - { - Mutex lock(&gCompactDecimalMetaLock); - if (gCompactDecimalData == NULL) { - gCompactDecimalData = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); - if (U_FAILURE(status)) { - return NULL; - } - uhash_setKeyDeleter(gCompactDecimalData, uprv_free); - uhash_setValueDeleter(gCompactDecimalData, deleteCDFLocaleData); - ucln_i18n_registerCleanup(UCLN_I18N_CDFINFO, cdf_cleanup); - } else { - result = (CDFLocaleData*) uhash_get(gCompactDecimalData, key); - } - } - if (result != NULL) { - return extractDataByStyleEnum(*result, style, status); - } - - result = loadCDFLocaleData(inLocale, status); - if (U_FAILURE(status)) { - return NULL; - } - - { - Mutex lock(&gCompactDecimalMetaLock); - CDFLocaleData* temp = (CDFLocaleData*) uhash_get(gCompactDecimalData, key); - if (temp != NULL) { - delete result; - result = temp; - } else { - uhash_put(gCompactDecimalData, uprv_strdup(key), (void*) result, &status); - if (U_FAILURE(status)) { - return NULL; - } - } - } - return extractDataByStyleEnum(*result, style, status); -} - -static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status) { - switch (style) { - case UNUM_SHORT: - return &data.shortData; - case UNUM_LONG: - if (!data.longData.isBogus()) { - return &data.longData; - } - return &data.shortData; - default: - status = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; - } -} - -// loadCDFLocaleData loads formatting data from CLDR for a given locale. The -// caller owns the returned pointer. -static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status) { - if (U_FAILURE(status)) { - return NULL; - } - CDFLocaleData* result = new CDFLocaleData; - if (result == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - result->Init(status); - if (U_FAILURE(status)) { - delete result; - return NULL; - } - - load(inLocale, result, status); - - if (U_FAILURE(status)) { - delete result; - return NULL; - } - return result; -} - -namespace { - -struct CmptDecDataSink : public ResourceSink { - - CDFLocaleData& dataBundle; // Where to save values when they are read - UBool isLatin; // Whether or not we are traversing the Latin tree - UBool isFallback; // Whether or not we are traversing the Latin tree as fallback - - enum EPatternsTableKey { PATTERNS_SHORT, PATTERNS_LONG }; - enum EFormatsTableKey { DECIMAL_FORMAT, CURRENCY_FORMAT }; - - /* - * NumberElements{ <-- top (numbering system table) - * latn{ <-- patternsTable (one per numbering system) - * patternsLong{ <-- formatsTable (one per pattern) - * decimalFormat{ <-- powersOfTenTable (one per format) - * 1000{ <-- pluralVariantsTable (one per power of ten) - * one{"0 thousand"} <-- plural variant and template - */ - - CmptDecDataSink(CDFLocaleData& _dataBundle) - : dataBundle(_dataBundle), isLatin(FALSE), isFallback(FALSE) {} - virtual ~CmptDecDataSink(); - - virtual void put(const char *key, ResourceValue &value, UBool isRoot, UErrorCode &errorCode) { - // SPECIAL CASE: Don't consume root in the non-Latin numbering system - if (isRoot && !isLatin) { return; } - - ResourceTable patternsTable = value.getTable(errorCode); - if (U_FAILURE(errorCode)) { return; } - for (int i1 = 0; patternsTable.getKeyAndValue(i1, key, value); ++i1) { - - // Check for patternsShort or patternsLong - EPatternsTableKey patternsTableKey; - if (uprv_strcmp(key, gPatternsShort) == 0) { - patternsTableKey = PATTERNS_SHORT; - } else if (uprv_strcmp(key, gPatternsLong) == 0) { - patternsTableKey = PATTERNS_LONG; - } else { - continue; - } - - // Traverse into the formats table - ResourceTable formatsTable = value.getTable(errorCode); - if (U_FAILURE(errorCode)) { return; } - for (int i2 = 0; formatsTable.getKeyAndValue(i2, key, value); ++i2) { - - // Check for decimalFormat or currencyFormat - EFormatsTableKey formatsTableKey; - if (uprv_strcmp(key, gDecimalFormatTag) == 0) { - formatsTableKey = DECIMAL_FORMAT; - // TODO: Enable this statement when currency support is added - // } else if (uprv_strcmp(key, gCurrencyFormat) == 0) { - // formatsTableKey = CURRENCY_FORMAT; - } else { - continue; - } - - // Set the current style and destination based on the two keys - UNumberCompactStyle style; - CDFLocaleStyleData* destination = NULL; - if (patternsTableKey == PATTERNS_LONG - && formatsTableKey == DECIMAL_FORMAT) { - style = UNUM_LONG; - destination = &dataBundle.longData; - } else if (patternsTableKey == PATTERNS_SHORT - && formatsTableKey == DECIMAL_FORMAT) { - style = UNUM_SHORT; - destination = &dataBundle.shortData; - // TODO: Enable the following statements when currency support is added - // } else if (patternsTableKey == PATTERNS_SHORT - // && formatsTableKey == CURRENCY_FORMAT) { - // style = UNUM_SHORT_CURRENCY; // or whatever the enum gets named - // destination = &dataBundle.shortCurrencyData; - // } else { - // // Silently ignore this case - // continue; - } - - // SPECIAL CASE: RULES FOR WHETHER OR NOT TO CONSUME THIS TABLE: - // 1) Don't consume longData if shortData was consumed from the non-Latin - // locale numbering system - // 2) Don't consume longData for the first time if this is the root bundle and - // shortData is already populated from a more specific locale. Note that if - // both longData and shortData are both only in root, longData will be - // consumed since it is alphabetically before shortData in the bundle. - if (isFallback - && style == UNUM_LONG - && !dataBundle.shortData.isEmpty() - && !dataBundle.shortData.fromFallback) { - continue; - } - if (isRoot - && style == UNUM_LONG - && dataBundle.longData.isEmpty() - && !dataBundle.shortData.isEmpty()) { - continue; - } - - // Set the "fromFallback" flag on the data object - destination->fromFallback = isFallback; - - // Traverse into the powers of ten table - ResourceTable powersOfTenTable = value.getTable(errorCode); - if (U_FAILURE(errorCode)) { return; } - for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) { - - // The key will always be some even power of 10. e.g 10000. - char* endPtr = NULL; - double power10 = uprv_strtod(key, &endPtr); - if (*endPtr != 0) { - errorCode = U_INTERNAL_PROGRAM_ERROR; - return; - } - int32_t log10Value = computeLog10(power10, FALSE); - - // Silently ignore divisors that are too big. - if (log10Value >= MAX_DIGITS) continue; - - // Iterate over the plural variants ("one", "other", etc) - ResourceTable pluralVariantsTable = value.getTable(errorCode); - if (U_FAILURE(errorCode)) { return; } - for (int i4 = 0; pluralVariantsTable.getKeyAndValue(i4, key, value); ++i4) { - const char* pluralVariant = key; - const UnicodeString formatStr = value.getUnicodeString(errorCode); - - // Copy the data into the in-memory data bundle (do not overwrite - // existing values) - int32_t numZeros = populatePrefixSuffix( - pluralVariant, log10Value, formatStr, - destination->unitsByVariant, FALSE, errorCode); - - // If populatePrefixSuffix returns -1, it means that this key has been - // encountered already. - if (numZeros < 0) { - continue; - } - - // Set the divisor, which is based on the number of zeros in the template - // string. If the divisor from here is different from the one previously - // stored, it means that the number of zeros in different plural variants - // differs; throw an exception. - // TODO: How should I check for floating-point errors here? - // Is there a good reason why "divisor" is double and not long like Java? - double divisor = calculateDivisor(power10, numZeros); - if (destination->divisors[log10Value] != 0.0 - && destination->divisors[log10Value] != divisor) { - errorCode = U_INTERNAL_PROGRAM_ERROR; - return; - } - destination->divisors[log10Value] = divisor; - } - } - } - } - } -}; - -// Virtual destructors must be defined out of line. -CmptDecDataSink::~CmptDecDataSink() {} - -} // namespace - -static void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status) { - LocalPointer ns(NumberingSystem::createInstance(inLocale, status)); - if (U_FAILURE(status)) { - return; - } - const char* nsName = ns->getName(); - - LocalUResourceBundlePointer resource(ures_open(NULL, inLocale.getName(), &status)); - if (U_FAILURE(status)) { - return; - } - CmptDecDataSink sink(*result); - sink.isFallback = FALSE; - - // First load the number elements data if nsName is not Latin. - if (uprv_strcmp(nsName, gLatnTag) != 0) { - sink.isLatin = FALSE; - CharString path; - path.append(gNumberElementsTag, status) - .append('/', status) - .append(nsName, status); - ures_getAllItemsWithFallback(resource.getAlias(), path.data(), sink, status); - if (status == U_MISSING_RESOURCE_ERROR) { - // Silently ignore and use Latin - status = U_ZERO_ERROR; - } else if (U_FAILURE(status)) { - return; - } - sink.isFallback = TRUE; - } - - // Now load Latin. - sink.isLatin = TRUE; - ures_getAllItemsWithFallback(resource.getAlias(), gLatnPath, sink, status); - if (U_FAILURE(status)) return; - - // If longData is empty, default it to be equal to shortData - if (result->longData.isEmpty()) { - result->longData.setToBogus(); - } - - // Check for "other" variants in each of the three data classes, and resolve missing elements. - - if (!result->longData.isBogus()) { - checkForOtherVariants(&result->longData, status); - if (U_FAILURE(status)) return; - fillInMissing(&result->longData); - } - - checkForOtherVariants(&result->shortData, status); - if (U_FAILURE(status)) return; - fillInMissing(&result->shortData); - - // TODO: Enable this statement when currency support is added - // checkForOtherVariants(&result->shortCurrencyData, status); - // if (U_FAILURE(status)) return; - // fillInMissing(&result->shortCurrencyData); -} - -// populatePrefixSuffix Adds a specific prefix-suffix pair to result for a -// given variant and log10 value. -// variant is 'zero', 'one', 'two', 'few', 'many', or 'other'. -// formatStr is the format string from which the prefix and suffix are -// extracted. It is usually of form 'Pefix 000 suffix'. -// populatePrefixSuffix returns the number of 0's found in formatStr -// before the decimal point. -// In the special case that formatStr contains only spaces for prefix -// and suffix, populatePrefixSuffix returns log10Value + 1. -static int32_t populatePrefixSuffix( - const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UBool overwrite, UErrorCode& status) { - if (U_FAILURE(status)) { - return 0; - } - - // ICU 59 HACK: Ignore negative part of format string, mimicking ICU 58 behavior. - // TODO(sffc): Make sure this is fixed during the overhaul port in ICU 60. - int32_t semiPos = formatStr.indexOf(';', 0); - if (semiPos == -1) { - semiPos = formatStr.length(); - } - UnicodeString positivePart = formatStr.tempSubString(0, semiPos); - - int32_t firstIdx = positivePart.indexOf(kZero, UPRV_LENGTHOF(kZero), 0); - // We must have 0's in format string. - if (firstIdx == -1) { - status = U_INTERNAL_PROGRAM_ERROR; - return 0; - } - int32_t lastIdx = positivePart.lastIndexOf(kZero, UPRV_LENGTHOF(kZero), firstIdx); - CDFUnit* unit = createCDFUnit(variant, log10Value, result, status); - if (U_FAILURE(status)) { - return 0; - } - - // Return -1 if we are not overwriting an existing value - if (unit->isSet() && !overwrite) { - return -1; - } - unit->markAsSet(); - - // Everything up to first 0 is the prefix - unit->prefix = positivePart.tempSubString(0, firstIdx); - fixQuotes(unit->prefix); - // Everything beyond the last 0 is the suffix - unit->suffix = positivePart.tempSubString(lastIdx + 1); - fixQuotes(unit->suffix); - - // If there is effectively no prefix or suffix, ignore the actual number of - // 0's and act as if the number of 0's matches the size of the number. - if (onlySpaces(unit->prefix) && onlySpaces(unit->suffix)) { - return log10Value + 1; - } - - // Calculate number of zeros before decimal point - int32_t idx = firstIdx + 1; - while (idx <= lastIdx && positivePart.charAt(idx) == u_0) { - ++idx; - } - return (idx - firstIdx); -} - -// Calculate a divisor based on the magnitude and number of zeros in the -// template string. -static double calculateDivisor(double power10, int32_t numZeros) { - double divisor = power10; - for (int32_t i = 1; i < numZeros; ++i) { - divisor /= 10.0; - } - return divisor; -} - -static UBool onlySpaces(UnicodeString u) { - return u.trim().length() == 0; + const UnicodeString& /* text */, + ParsePosition& /* pos */) const { + return nullptr; } -// fixQuotes unescapes single quotes. Don''t -> Don't. Letter 'j' -> Letter j. -// Modifies s in place. -static void fixQuotes(UnicodeString& s) { - QuoteState state = OUTSIDE; - int32_t len = s.length(); - int32_t dest = 0; - for (int32_t i = 0; i < len; ++i) { - UChar ch = s.charAt(i); - if (ch == u_apos) { - if (state == INSIDE_EMPTY) { - s.setCharAt(dest, ch); - ++dest; - } - } else { - s.setCharAt(dest, ch); - ++dest; - } - - // Update state - switch (state) { - case OUTSIDE: - state = ch == u_apos ? INSIDE_EMPTY : OUTSIDE; - break; - case INSIDE_EMPTY: - case INSIDE_FULL: - state = ch == u_apos ? OUTSIDE : INSIDE_FULL; - break; - default: - break; - } - } - s.truncate(dest); -} - -// Checks to make sure that an "other" variant is present in all -// powers of 10. -static void checkForOtherVariants(CDFLocaleStyleData* result, - UErrorCode& status) { - if (result == NULL || result->unitsByVariant == NULL) { - return; - } - - const CDFUnit* otherByBase = - (const CDFUnit*) uhash_get(result->unitsByVariant, gOther); - if (otherByBase == NULL) { - status = U_INTERNAL_PROGRAM_ERROR; - return; - } - - // Check all other plural variants, and make sure that if - // any of them are populated, then other is also populated - int32_t pos = UHASH_FIRST; - const UHashElement* element; - while ((element = uhash_nextElement(result->unitsByVariant, &pos)) != NULL) { - CDFUnit* variantsByBase = (CDFUnit*) element->value.pointer; - if (variantsByBase == otherByBase) continue; - for (int32_t log10Value = 0; log10Value < MAX_DIGITS; ++log10Value) { - if (variantsByBase[log10Value].isSet() - && !otherByBase[log10Value].isSet()) { - status = U_INTERNAL_PROGRAM_ERROR; - return; - } - } - } -} - -// fillInMissing ensures that the data in result is complete. -// result data is complete if for each variant in result, there exists -// a prefix-suffix pair for each log10 value and there also exists -// a divisor for each log10 value. -// -// First this function figures out for which log10 values, the other -// variant already had data. These are the same log10 values defined -// in CLDR. -// -// For each log10 value not defined in CLDR, it uses the divisor for -// the last defined log10 value or 1. -// -// Then for each variant, it does the following. For each log10 -// value not defined in CLDR, copy the prefix-suffix pair from the -// previous log10 value. If log10 value is defined in CLDR but is -// missing from given variant, copy the prefix-suffix pair for that -// log10 value from the 'other' variant. -static void fillInMissing(CDFLocaleStyleData* result) { - const CDFUnit* otherUnits = - (const CDFUnit*) uhash_get(result->unitsByVariant, gOther); - UBool definedInCLDR[MAX_DIGITS]; - double lastDivisor = 1.0; - for (int32_t i = 0; i < MAX_DIGITS; ++i) { - if (!otherUnits[i].isSet()) { - result->divisors[i] = lastDivisor; - definedInCLDR[i] = FALSE; - } else { - lastDivisor = result->divisors[i]; - definedInCLDR[i] = TRUE; - } - } - // Iterate over each variant. - int32_t pos = UHASH_FIRST; - const UHashElement* element = uhash_nextElement(result->unitsByVariant, &pos); - for (;element != NULL; element = uhash_nextElement(result->unitsByVariant, &pos)) { - CDFUnit* units = (CDFUnit*) element->value.pointer; - for (int32_t i = 0; i < MAX_DIGITS; ++i) { - if (definedInCLDR[i]) { - if (!units[i].isSet()) { - units[i] = otherUnits[i]; - } - } else { - if (i == 0) { - units[0].markAsSet(); - } else { - units[i] = units[i - 1]; - } - } - } - } -} - -// computeLog10 computes floor(log10(x)). If inRange is TRUE, the biggest -// value computeLog10 will return MAX_DIGITS -1 even for -// numbers > 10^MAX_DIGITS. If inRange is FALSE, computeLog10 will return -// up to MAX_DIGITS. -static int32_t computeLog10(double x, UBool inRange) { - int32_t result = 0; - int32_t max = inRange ? MAX_DIGITS - 1 : MAX_DIGITS; - while (x >= 10.0) { - x /= 10.0; - ++result; - if (result == max) { - break; - } - } - return result; -} - -// createCDFUnit returns a pointer to the prefix-suffix pair for a given -// variant and log10 value within table. If no such prefix-suffix pair is -// stored in table, one is created within table before returning pointer. -static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status) { - if (U_FAILURE(status)) { - return NULL; - } - CDFUnit *cdfUnit = (CDFUnit*) uhash_get(table, variant); - if (cdfUnit == NULL) { - cdfUnit = new CDFUnit[MAX_DIGITS]; - if (cdfUnit == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - uhash_put(table, uprv_strdup(variant), cdfUnit, &status); - if (U_FAILURE(status)) { - return NULL; - } - } - CDFUnit* result = &cdfUnit[log10Value]; - return result; -} - -// getCDFUnitFallback returns a pointer to the prefix-suffix pair for a given -// variant and log10 value within table. If the given variant doesn't exist, it -// falls back to the OTHER variant. Therefore, this method will always return -// some non-NULL value. -static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value) { - CharString cvariant; - UErrorCode status = U_ZERO_ERROR; - const CDFUnit *cdfUnit = NULL; - cvariant.appendInvariantChars(variant, status); - if (!U_FAILURE(status)) { - cdfUnit = (const CDFUnit*) uhash_get(table, cvariant.data()); - } - if (cdfUnit == NULL) { - cdfUnit = (const CDFUnit*) uhash_get(table, gOther); - } - return &cdfUnit[log10Value]; -} -U_NAMESPACE_END -#endif +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/currpinf.cpp b/deps/icu-small/source/i18n/currpinf.cpp index 5d3ca62089..6b1efd5f4d 100644 --- a/deps/icu-small/source/i18n/currpinf.cpp +++ b/deps/icu-small/source/i18n/currpinf.cpp @@ -203,6 +203,9 @@ CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount, const UnicodeString& pattern, UErrorCode& status) { if (U_SUCCESS(status)) { + UnicodeString* oldValue = static_cast( + fPluralCountToCurrencyUnitPattern->get(pluralCount)); + delete oldValue; fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status); } } diff --git a/deps/icu-small/source/i18n/currunit.cpp b/deps/icu-small/source/i18n/currunit.cpp index 83429c0169..6d8d1cd6c6 100644 --- a/deps/icu-small/source/i18n/currunit.cpp +++ b/deps/icu-small/source/i18n/currunit.cpp @@ -17,21 +17,32 @@ #include "unicode/currunit.h" #include "unicode/ustring.h" #include "cstring.h" +#include "uinvchar.h" + +static constexpr char16_t kDefaultCurrency[] = u"XXX"; U_NAMESPACE_BEGIN CurrencyUnit::CurrencyUnit(ConstChar16Ptr _isoCode, UErrorCode& ec) { - *isoCode = 0; - if (U_SUCCESS(ec)) { - if (_isoCode != nullptr && u_strlen(_isoCode)==3) { - u_strcpy(isoCode, _isoCode); - char simpleIsoCode[4]; - u_UCharsToChars(isoCode, simpleIsoCode, 4); - initCurrency(simpleIsoCode); - } else { - ec = U_ILLEGAL_ARGUMENT_ERROR; - } + // The constructor always leaves the CurrencyUnit in a valid state (with a 3-character currency code). + // Note: in ICU4J Currency.getInstance(), we check string length for 3, but in ICU4C we allow a + // non-NUL-terminated string to be passed as an argument, so it is not possible to check length. + const char16_t* isoCodeToUse; + if (U_FAILURE(ec) || _isoCode == nullptr) { + isoCodeToUse = kDefaultCurrency; + } else if (!uprv_isInvariantUString(_isoCode, 3)) { + // TODO: Perform a more strict ASCII check like in ICU4J isAlpha3Code? + isoCodeToUse = kDefaultCurrency; + ec = U_INVARIANT_CONVERSION_ERROR; + } else { + isoCodeToUse = _isoCode; } + // TODO: Perform uppercasing here like in ICU4J Currency.getInstance()? + uprv_memcpy(isoCode, isoCodeToUse, sizeof(UChar) * 3); + isoCode[3] = 0; + char simpleIsoCode[4]; + u_UCharsToChars(isoCode, simpleIsoCode, 4); + initCurrency(simpleIsoCode); } CurrencyUnit::CurrencyUnit(const CurrencyUnit& other) : MeasureUnit(other) { @@ -52,7 +63,7 @@ CurrencyUnit::CurrencyUnit(const MeasureUnit& other, UErrorCode& ec) : MeasureUn } CurrencyUnit::CurrencyUnit() : MeasureUnit() { - u_strcpy(isoCode, u"XXX"); + u_strcpy(isoCode, kDefaultCurrency); char simpleIsoCode[4]; u_UCharsToChars(isoCode, simpleIsoCode, 4); initCurrency(simpleIsoCode); diff --git a/deps/icu-small/source/i18n/dcfmtimp.h b/deps/icu-small/source/i18n/dcfmtimp.h deleted file mode 100644 index e582efb344..0000000000 --- a/deps/icu-small/source/i18n/dcfmtimp.h +++ /dev/null @@ -1,54 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************** -* Copyright (C) 2012-2014, International Business Machines -* Corporation and others. All Rights Reserved. -********************************************************************************/ - -#ifndef DCFMTIMP_H -#define DCFMTIMP_H - -#include "unicode/utypes.h" - - -#if UCONFIG_FORMAT_FASTPATHS_49 - -U_NAMESPACE_BEGIN - -enum EDecimalFormatFastpathStatus { - kFastpathNO = 0, - kFastpathYES = 1, - kFastpathUNKNOWN = 2, /* not yet set */ - kFastpathMAYBE = 3 /* depends on value being formatted. */ -}; - -/** - * Must be smaller than DecimalFormat::fReserved - */ -struct DecimalFormatInternal { - uint8_t fFastFormatStatus; - uint8_t fFastParseStatus; - - DecimalFormatInternal &operator=(const DecimalFormatInternal& rhs) { - fFastParseStatus = rhs.fFastParseStatus; - fFastFormatStatus = rhs.fFastFormatStatus; - return *this; - } -#ifdef FMT_DEBUG - void dump() const { - printf("DecimalFormatInternal: fFastFormatStatus=%c, fFastParseStatus=%c\n", - "NY?"[(int)fFastFormatStatus&3], - "NY?"[(int)fFastParseStatus&3] - ); - } -#endif -}; - - - -U_NAMESPACE_END - -#endif - -#endif diff --git a/deps/icu-small/source/i18n/dcfmtsym.cpp b/deps/icu-small/source/i18n/dcfmtsym.cpp index 680c3120a1..5a432aec8e 100644 --- a/deps/icu-small/source/i18n/dcfmtsym.cpp +++ b/deps/icu-small/source/i18n/dcfmtsym.cpp @@ -66,7 +66,7 @@ static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0}; static const char *gNumberElementKeys[DecimalFormatSymbols::kFormatSymbolCount] = { "decimal", "group", - "list", + NULL, /* #11897: the symbol is NOT the pattern separator symbol */ "percentSign", NULL, /* Native zero digit is deprecated from CLDR - get it from the numbering system */ NULL, /* Pattern digit character is deprecated from CLDR - use # by default always */ @@ -98,7 +98,7 @@ static const char *gNumberElementKeys[DecimalFormatSymbols::kFormatSymbolCount] // Initializes this with the decimal format symbols in the default locale. DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status) - : UObject(), locale() { + : UObject(), locale(), currPattern(NULL) { initialize(locale, status, TRUE); } @@ -106,12 +106,12 @@ DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status) // Initializes this with the decimal format symbols in the desired locale. DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status) - : UObject(), locale(loc) { + : UObject(), locale(loc), currPattern(NULL) { initialize(locale, status); } DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSystem& ns, UErrorCode& status) - : UObject(), locale(loc) { + : UObject(), locale(loc), currPattern(NULL) { initialize(locale, status, FALSE, &ns); } @@ -349,7 +349,6 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, { if (U_FAILURE(status)) { return; } *validLocale = *actualLocale = 0; - currPattern = NULL; // First initialize all the symbols to the fallbacks for anything we can't find initialize(); @@ -477,6 +476,7 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, UErrorCode localStatus = U_ZERO_ERROR; uccLen = ucurr_forLocale(locName, ucc, uccLen, &localStatus); + // TODO: Currency pattern data loading is duplicated in number_formatimpl.cpp if(U_SUCCESS(localStatus) && uccLen > 0) { char cc[4]={0}; u_UCharsToChars(ucc, cc, uccLen); diff --git a/deps/icu-small/source/i18n/decfmtst.cpp b/deps/icu-small/source/i18n/decfmtst.cpp deleted file mode 100644 index 5943affad4..0000000000 --- a/deps/icu-small/source/i18n/decfmtst.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2009-2016, International Business Machines Corporation and -* others. All Rights Reserved. -******************************************************************************* -* -* This file contains the class DecimalFormatStaticSets -* -* DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient -* parsing of decimal and group separators. -******************************************************************************** -*/ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/unistr.h" -#include "unicode/uniset.h" -#include "unicode/uchar.h" -#include "cmemory.h" -#include "cstring.h" -#include "uassert.h" -#include "ucln_in.h" -#include "umutex.h" - -#include "decfmtst.h" - -U_NAMESPACE_BEGIN - - -//------------------------------------------------------------------------------ -// -// Unicode Set pattern strings for all of the required constant sets. -// Initialized with hex values for portability to EBCDIC based machines. -// Really ugly, but there's no good way to avoid it. -// -//------------------------------------------------------------------------------ - -static const UChar gDotEquivalentsPattern[] = { - // [ . \u2024 \u3002 \uFE12 \uFE52 \uFF0E \uFF61 ] - 0x005B, 0x002E, 0x2024, 0x3002, 0xFE12, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; - -static const UChar gCommaEquivalentsPattern[] = { - // [ , \u060C \u066B \u3001 \uFE10 \uFE11 \uFE50 \uFE51 \uFF0C \uFF64 ] - 0x005B, 0x002C, 0x060C, 0x066B, 0x3001, 0xFE10, 0xFE11, 0xFE50, 0xFE51, 0xFF0C, 0xFF64, 0x005D, 0x0000}; - -static const UChar gOtherGroupingSeparatorsPattern[] = { - // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ] - 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000}; - -static const UChar gDashEquivalentsPattern[] = { - // [ \ - HYPHEN F_DASH N_DASH MINUS ] - 0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000}; - -static const UChar gStrictDotEquivalentsPattern[] = { - // [ . \u2024 \uFE52 \uFF0E \uFF61 ] - 0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; - -static const UChar gStrictCommaEquivalentsPattern[] = { - // [ , \u066B \uFE10 \uFE50 \uFF0C ] - 0x005B, 0x002C, 0x066B, 0xFE10, 0xFE50, 0xFF0C, 0x005D, 0x0000}; - -static const UChar gStrictOtherGroupingSeparatorsPattern[] = { - // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ] - 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000}; - -static const UChar gStrictDashEquivalentsPattern[] = { - // [ \ - MINUS ] - 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000}; - -static const UChar32 gMinusSigns[] = { - 0x002D, - 0x207B, - 0x208B, - 0x2212, - 0x2796, - 0xFE63, - 0xFF0D}; - -static const UChar32 gPlusSigns[] = { - 0x002B, - 0x207A, - 0x208A, - 0x2795, - 0xfB29, - 0xFE62, - 0xFF0B}; - -static void initUnicodeSet(const UChar32 *raw, int32_t len, UnicodeSet *s) { - for (int32_t i = 0; i < len; ++i) { - s->add(raw[i]); - } -} - -DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode &status) -: fDotEquivalents(NULL), - fCommaEquivalents(NULL), - fOtherGroupingSeparators(NULL), - fDashEquivalents(NULL), - fStrictDotEquivalents(NULL), - fStrictCommaEquivalents(NULL), - fStrictOtherGroupingSeparators(NULL), - fStrictDashEquivalents(NULL), - fDefaultGroupingSeparators(NULL), - fStrictDefaultGroupingSeparators(NULL), - fMinusSigns(NULL), - fPlusSigns(NULL) -{ - fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), status); - fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), status); - fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), status); - fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), status); - - fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), status); - fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), status); - fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), status); - fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), status); - - - fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents); - fDefaultGroupingSeparators->addAll(*fCommaEquivalents); - fDefaultGroupingSeparators->addAll(*fOtherGroupingSeparators); - - fStrictDefaultGroupingSeparators = new UnicodeSet(*fStrictDotEquivalents); - fStrictDefaultGroupingSeparators->addAll(*fStrictCommaEquivalents); - fStrictDefaultGroupingSeparators->addAll(*fStrictOtherGroupingSeparators); - - fMinusSigns = new UnicodeSet(); - fPlusSigns = new UnicodeSet(); - - // Check for null pointers - if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL || fDashEquivalents == NULL || - fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL || fStrictDashEquivalents == NULL || - fDefaultGroupingSeparators == NULL || fStrictOtherGroupingSeparators == NULL || - fMinusSigns == NULL || fPlusSigns == NULL) { - cleanup(); - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - - initUnicodeSet( - gMinusSigns, - UPRV_LENGTHOF(gMinusSigns), - fMinusSigns); - initUnicodeSet( - gPlusSigns, - UPRV_LENGTHOF(gPlusSigns), - fPlusSigns); - - // Freeze all the sets - fDotEquivalents->freeze(); - fCommaEquivalents->freeze(); - fOtherGroupingSeparators->freeze(); - fDashEquivalents->freeze(); - fStrictDotEquivalents->freeze(); - fStrictCommaEquivalents->freeze(); - fStrictOtherGroupingSeparators->freeze(); - fStrictDashEquivalents->freeze(); - fDefaultGroupingSeparators->freeze(); - fStrictDefaultGroupingSeparators->freeze(); - fMinusSigns->freeze(); - fPlusSigns->freeze(); -} - -DecimalFormatStaticSets::~DecimalFormatStaticSets() { - cleanup(); -} - -void DecimalFormatStaticSets::cleanup() { // Be sure to clean up newly added fields! - delete fDotEquivalents; fDotEquivalents = NULL; - delete fCommaEquivalents; fCommaEquivalents = NULL; - delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL; - delete fDashEquivalents; fDashEquivalents = NULL; - delete fStrictDotEquivalents; fStrictDotEquivalents = NULL; - delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL; - delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; - delete fStrictDashEquivalents; fStrictDashEquivalents = NULL; - delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL; - delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL; - delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; - delete fMinusSigns; fMinusSigns = NULL; - delete fPlusSigns; fPlusSigns = NULL; -} - -static DecimalFormatStaticSets *gStaticSets; -static icu::UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER; - - -//------------------------------------------------------------------------------ -// -// decfmt_cleanup Memory cleanup function, free/delete all -// cached memory. Called by ICU's u_cleanup() function. -// -//------------------------------------------------------------------------------ -U_CDECL_BEGIN -static UBool U_CALLCONV -decimfmt_cleanup(void) -{ - delete gStaticSets; - gStaticSets = NULL; - gStaticSetsInitOnce.reset(); - return TRUE; -} - -static void U_CALLCONV initSets(UErrorCode &status) { - U_ASSERT(gStaticSets == NULL); - ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup); - gStaticSets = new DecimalFormatStaticSets(status); - if (U_FAILURE(status)) { - delete gStaticSets; - gStaticSets = NULL; - return; - } - if (gStaticSets == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } -} -U_CDECL_END - -const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) { - umtx_initOnce(gStaticSetsInitOnce, initSets, status); - return gStaticSets; -} - - -const UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse) -{ - UErrorCode status = U_ZERO_ERROR; - umtx_initOnce(gStaticSetsInitOnce, initSets, status); - if (U_FAILURE(status)) { - return NULL; - } - - if (gStaticSets->fDotEquivalents->contains(decimal)) { - return strictParse ? gStaticSets->fStrictDotEquivalents : gStaticSets->fDotEquivalents; - } - - if (gStaticSets->fCommaEquivalents->contains(decimal)) { - return strictParse ? gStaticSets->fStrictCommaEquivalents : gStaticSets->fCommaEquivalents; - } - - // if there is no match, return NULL - return NULL; -} - - -U_NAMESPACE_END -#endif // !UCONFIG_NO_FORMATTING diff --git a/deps/icu-small/source/i18n/decfmtst.h b/deps/icu-small/source/i18n/decfmtst.h deleted file mode 100644 index 63ae50c6df..0000000000 --- a/deps/icu-small/source/i18n/decfmtst.h +++ /dev/null @@ -1,69 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2009-2016, International Business Machines Corporation and -* others. All Rights Reserved. -******************************************************************************* -* -* This file contains declarations for the class DecimalFormatStaticSets -* -* DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient -* parsing of decimal and group separators. -******************************************************************************** -*/ - -#ifndef DECFMTST_H -#define DECFMTST_H - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/uobject.h" - -U_NAMESPACE_BEGIN - -class UnicodeSet; - - -class DecimalFormatStaticSets : public UMemory -{ -public: - // Constructor and Destructor not for general use. - // Public to permit access from plain C implementation functions. - DecimalFormatStaticSets(UErrorCode &status); - ~DecimalFormatStaticSets(); - - /** - * Return a pointer to a lazy-initialized singleton instance of this class. - */ - static const DecimalFormatStaticSets *getStaticSets(UErrorCode &status); - - static const UnicodeSet *getSimilarDecimals(UChar32 decimal, UBool strictParse); - - UnicodeSet *fDotEquivalents; - UnicodeSet *fCommaEquivalents; - UnicodeSet *fOtherGroupingSeparators; - UnicodeSet *fDashEquivalents; - - UnicodeSet *fStrictDotEquivalents; - UnicodeSet *fStrictCommaEquivalents; - UnicodeSet *fStrictOtherGroupingSeparators; - UnicodeSet *fStrictDashEquivalents; - - UnicodeSet *fDefaultGroupingSeparators; - UnicodeSet *fStrictDefaultGroupingSeparators; - - UnicodeSet *fMinusSigns; - UnicodeSet *fPlusSigns; -private: - void cleanup(); - -}; - - -U_NAMESPACE_END - -#endif // !UCONFIG_NO_FORMATTING -#endif // DECFMTST_H diff --git a/deps/icu-small/source/i18n/decimalformatpattern.cpp b/deps/icu-small/source/i18n/decimalformatpattern.cpp deleted file mode 100644 index 80a1870f33..0000000000 --- a/deps/icu-small/source/i18n/decimalformatpattern.cpp +++ /dev/null @@ -1,656 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 1997-2015, International Business Machines Corporation and * -* others. All Rights Reserved. * -******************************************************************************* -*/ - -#include "uassert.h" -#include "decimalformatpattern.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/dcfmtsym.h" -#include "unicode/format.h" -#include "unicode/utf16.h" -#include "decimalformatpatternimpl.h" - - -#ifdef FMT_DEBUG -#define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x); -#else -#define debug(x) -#endif - -U_NAMESPACE_BEGIN - -// TODO: Travis Keep: Copied from numfmt.cpp -static int32_t kDoubleIntegerDigits = 309; -static int32_t kDoubleFractionDigits = 340; - - -// TODO: Travis Keep: Copied from numfmt.cpp -static int32_t gDefaultMaxIntegerDigits = 2000000000; - -// TODO: Travis Keep: This function was copied from format.cpp -static void syntaxError(const UnicodeString& pattern, - int32_t pos, - UParseError& parseError) { - parseError.offset = pos; - parseError.line=0; // we are not using line number - - // for pre-context - int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1 - /* subtract 1 so that we have room for null*/)); - int32_t stop = pos; - pattern.extract(start,stop-start,parseError.preContext,0); - //null terminate the buffer - parseError.preContext[stop-start] = 0; - - //for post-context - start = pattern.moveIndex32(pos, 1); - stop = pos + U_PARSE_CONTEXT_LEN - 1; - if (stop > pattern.length()) { - stop = pattern.length(); - } - pattern.extract(start, stop - start, parseError.postContext, 0); - //null terminate the buffer - parseError.postContext[stop-start]= 0; -} - -DecimalFormatPattern::DecimalFormatPattern() - : fMinimumIntegerDigits(1), - fMaximumIntegerDigits(gDefaultMaxIntegerDigits), - fMinimumFractionDigits(0), - fMaximumFractionDigits(3), - fUseSignificantDigits(FALSE), - fMinimumSignificantDigits(1), - fMaximumSignificantDigits(6), - fUseExponentialNotation(FALSE), - fMinExponentDigits(0), - fExponentSignAlwaysShown(FALSE), - fCurrencySignCount(fgCurrencySignCountZero), - fGroupingUsed(TRUE), - fGroupingSize(0), - fGroupingSize2(0), - fMultiplier(1), - fDecimalSeparatorAlwaysShown(FALSE), - fFormatWidth(0), - fRoundingIncrementUsed(FALSE), - fRoundingIncrement(), - fPad(kDefaultPad), - fNegPatternsBogus(TRUE), - fPosPatternsBogus(TRUE), - fNegPrefixPattern(), - fNegSuffixPattern(), - fPosPrefixPattern(), - fPosSuffixPattern(), - fPadPosition(DecimalFormatPattern::kPadBeforePrefix) { -} - - -DecimalFormatPatternParser::DecimalFormatPatternParser() : - fZeroDigit(kPatternZeroDigit), - fSigDigit(kPatternSignificantDigit), - fGroupingSeparator((UChar)kPatternGroupingSeparator), - fDecimalSeparator((UChar)kPatternDecimalSeparator), - fPercent((UChar)kPatternPercent), - fPerMill((UChar)kPatternPerMill), - fDigit((UChar)kPatternDigit), - fSeparator((UChar)kPatternSeparator), - fExponent((UChar)kPatternExponent), - fPlus((UChar)kPatternPlus), - fMinus((UChar)kPatternMinus), - fPadEscape((UChar)kPatternPadEscape) { -} - -void DecimalFormatPatternParser::useSymbols( - const DecimalFormatSymbols& symbols) { - fZeroDigit = symbols.getConstSymbol( - DecimalFormatSymbols::kZeroDigitSymbol).char32At(0); - fSigDigit = symbols.getConstSymbol( - DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0); - fGroupingSeparator = symbols.getConstSymbol( - DecimalFormatSymbols::kGroupingSeparatorSymbol); - fDecimalSeparator = symbols.getConstSymbol( - DecimalFormatSymbols::kDecimalSeparatorSymbol); - fPercent = symbols.getConstSymbol( - DecimalFormatSymbols::kPercentSymbol); - fPerMill = symbols.getConstSymbol( - DecimalFormatSymbols::kPerMillSymbol); - fDigit = symbols.getConstSymbol( - DecimalFormatSymbols::kDigitSymbol); - fSeparator = symbols.getConstSymbol( - DecimalFormatSymbols::kPatternSeparatorSymbol); - fExponent = symbols.getConstSymbol( - DecimalFormatSymbols::kExponentialSymbol); - fPlus = symbols.getConstSymbol( - DecimalFormatSymbols::kPlusSignSymbol); - fMinus = symbols.getConstSymbol( - DecimalFormatSymbols::kMinusSignSymbol); - fPadEscape = symbols.getConstSymbol( - DecimalFormatSymbols::kPadEscapeSymbol); -} - -void -DecimalFormatPatternParser::applyPatternWithoutExpandAffix( - const UnicodeString& pattern, - DecimalFormatPattern& out, - UParseError& parseError, - UErrorCode& status) { - if (U_FAILURE(status)) - { - return; - } - out = DecimalFormatPattern(); - - // Clear error struct - parseError.offset = -1; - parseError.preContext[0] = parseError.postContext[0] = (UChar)0; - - // TODO: Travis Keep: This won't always work. - UChar nineDigit = (UChar)(fZeroDigit + 9); - int32_t digitLen = fDigit.length(); - int32_t groupSepLen = fGroupingSeparator.length(); - int32_t decimalSepLen = fDecimalSeparator.length(); - - int32_t pos = 0; - int32_t patLen = pattern.length(); - // Part 0 is the positive pattern. Part 1, if present, is the negative - // pattern. - for (int32_t part=0; part<2 && pos 0 || sigDigitCount > 0) { - ++digitRightCount; - } else { - ++digitLeftCount; - } - if (groupingCount >= 0 && decimalPos < 0) { - ++groupingCount; - } - pos += digitLen; - } else if ((ch >= fZeroDigit && ch <= nineDigit) || - ch == fSigDigit) { - if (digitRightCount > 0) { - // Unexpected '0' - debug("Unexpected '0'") - status = U_UNEXPECTED_TOKEN; - syntaxError(pattern,pos,parseError); - return; - } - if (ch == fSigDigit) { - ++sigDigitCount; - } else { - if (ch != fZeroDigit && roundingPos < 0) { - roundingPos = digitLeftCount + zeroDigitCount; - } - if (roundingPos >= 0) { - roundingInc.append((char)(ch - fZeroDigit + '0')); - } - ++zeroDigitCount; - } - if (groupingCount >= 0 && decimalPos < 0) { - ++groupingCount; - } - pos += U16_LENGTH(ch); - } else if (pattern.compare(pos, groupSepLen, fGroupingSeparator) == 0) { - if (decimalPos >= 0) { - // Grouping separator after decimal - debug("Grouping separator after decimal") - status = U_UNEXPECTED_TOKEN; - syntaxError(pattern,pos,parseError); - return; - } - groupingCount2 = groupingCount; - groupingCount = 0; - pos += groupSepLen; - } else if (pattern.compare(pos, decimalSepLen, fDecimalSeparator) == 0) { - if (decimalPos >= 0) { - // Multiple decimal separators - debug("Multiple decimal separators") - status = U_MULTIPLE_DECIMAL_SEPARATORS; - syntaxError(pattern,pos,parseError); - return; - } - // Intentionally incorporate the digitRightCount, - // even though it is illegal for this to be > 0 - // at this point. We check pattern syntax below. - decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; - pos += decimalSepLen; - } else { - if (pattern.compare(pos, fExponent.length(), fExponent) == 0) { - if (expDigits >= 0) { - // Multiple exponential symbols - debug("Multiple exponential symbols") - status = U_MULTIPLE_EXPONENTIAL_SYMBOLS; - syntaxError(pattern,pos,parseError); - return; - } - if (groupingCount >= 0) { - // Grouping separator in exponential pattern - debug("Grouping separator in exponential pattern") - status = U_MALFORMED_EXPONENTIAL_PATTERN; - syntaxError(pattern,pos,parseError); - return; - } - pos += fExponent.length(); - // Check for positive prefix - if (pos < patLen - && pattern.compare(pos, fPlus.length(), fPlus) == 0) { - expSignAlways = TRUE; - pos += fPlus.length(); - } - // Use lookahead to parse out the exponential part of the - // pattern, then jump into suffix subpart. - expDigits = 0; - while (pos < patLen && - pattern.char32At(pos) == fZeroDigit) { - ++expDigits; - pos += U16_LENGTH(fZeroDigit); - } - - // 1. Require at least one mantissa pattern digit - // 2. Disallow "#+ @" in mantissa - // 3. Require at least one exponent pattern digit - if (((digitLeftCount + zeroDigitCount) < 1 && - (sigDigitCount + digitRightCount) < 1) || - (sigDigitCount > 0 && digitLeftCount > 0) || - expDigits < 1) { - // Malformed exponential pattern - debug("Malformed exponential pattern") - status = U_MALFORMED_EXPONENTIAL_PATTERN; - syntaxError(pattern,pos,parseError); - return; - } - } - // Transition to suffix subpart - subpart = 2; // suffix subpart - affix = &suffix; - sub0Limit = pos; - continue; - } - break; - case 1: // Prefix subpart - case 2: // Suffix subpart - // Process the prefix / suffix characters - // Process unquoted characters seen in prefix or suffix - // subpart. - - // Several syntax characters implicitly begins the - // next subpart if we are in the prefix; otherwise - // they are illegal if unquoted. - if (!pattern.compare(pos, digitLen, fDigit) || - !pattern.compare(pos, groupSepLen, fGroupingSeparator) || - !pattern.compare(pos, decimalSepLen, fDecimalSeparator) || - (ch >= fZeroDigit && ch <= nineDigit) || - ch == fSigDigit) { - if (subpart == 1) { // prefix subpart - subpart = 0; // pattern proper subpart - sub0Start = pos; // Reprocess this character - continue; - } else { - status = U_UNQUOTED_SPECIAL; - syntaxError(pattern,pos,parseError); - return; - } - } else if (ch == kCurrencySign) { - affix->append(kQuote); // Encode currency - // Use lookahead to determine if the currency sign is - // doubled or not. - U_ASSERT(U16_LENGTH(kCurrencySign) == 1); - if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) { - affix->append(kCurrencySign); - ++pos; // Skip over the doubled character - if ((pos+1) < pattern.length() && - pattern[pos+1] == kCurrencySign) { - affix->append(kCurrencySign); - ++pos; // Skip over the doubled character - out.fCurrencySignCount = fgCurrencySignCountInPluralFormat; - } else { - out.fCurrencySignCount = fgCurrencySignCountInISOFormat; - } - } else { - out.fCurrencySignCount = fgCurrencySignCountInSymbolFormat; - } - // Fall through to append(ch) - } else if (ch == kQuote) { - // A quote outside quotes indicates either the opening - // quote or two quotes, which is a quote literal. That is, - // we have the first quote in 'do' or o''clock. - U_ASSERT(U16_LENGTH(kQuote) == 1); - ++pos; - if (pos < pattern.length() && pattern[pos] == kQuote) { - affix->append(kQuote); // Encode quote - // Fall through to append(ch) - } else { - subpart += 2; // open quote - continue; - } - } else if (pattern.compare(pos, fSeparator.length(), fSeparator) == 0) { - // Don't allow separators in the prefix, and don't allow - // separators in the second pattern (part == 1). - if (subpart == 1 || part == 1) { - // Unexpected separator - debug("Unexpected separator") - status = U_UNEXPECTED_TOKEN; - syntaxError(pattern,pos,parseError); - return; - } - sub2Limit = pos; - isPartDone = TRUE; // Go to next part - pos += fSeparator.length(); - break; - } else if (pattern.compare(pos, fPercent.length(), fPercent) == 0) { - // Next handle characters which are appended directly. - if (multiplier != 1) { - // Too many percent/perMill characters - debug("Too many percent characters") - status = U_MULTIPLE_PERCENT_SYMBOLS; - syntaxError(pattern,pos,parseError); - return; - } - affix->append(kQuote); // Encode percent/perMill - affix->append(kPatternPercent); // Use unlocalized pattern char - multiplier = 100; - pos += fPercent.length(); - break; - } else if (pattern.compare(pos, fPerMill.length(), fPerMill) == 0) { - // Next handle characters which are appended directly. - if (multiplier != 1) { - // Too many percent/perMill characters - debug("Too many perMill characters") - status = U_MULTIPLE_PERMILL_SYMBOLS; - syntaxError(pattern,pos,parseError); - return; - } - affix->append(kQuote); // Encode percent/perMill - affix->append(kPatternPerMill); // Use unlocalized pattern char - multiplier = 1000; - pos += fPerMill.length(); - break; - } else if (pattern.compare(pos, fPadEscape.length(), fPadEscape) == 0) { - if (padPos >= 0 || // Multiple pad specifiers - (pos+1) == pattern.length()) { // Nothing after padEscape - debug("Multiple pad specifiers") - status = U_MULTIPLE_PAD_SPECIFIERS; - syntaxError(pattern,pos,parseError); - return; - } - padPos = pos; - pos += fPadEscape.length(); - padChar = pattern.char32At(pos); - pos += U16_LENGTH(padChar); - break; - } else if (pattern.compare(pos, fMinus.length(), fMinus) == 0) { - affix->append(kQuote); // Encode minus - affix->append(kPatternMinus); - pos += fMinus.length(); - break; - } else if (pattern.compare(pos, fPlus.length(), fPlus) == 0) { - affix->append(kQuote); // Encode plus - affix->append(kPatternPlus); - pos += fPlus.length(); - break; - } - // Unquoted, non-special characters fall through to here, as - // well as other code which needs to append something to the - // affix. - affix->append(ch); - pos += U16_LENGTH(ch); - break; - case 3: // Prefix subpart, in quote - case 4: // Suffix subpart, in quote - // A quote within quotes indicates either the closing - // quote or two quotes, which is a quote literal. That is, - // we have the second quote in 'do' or 'don''t'. - if (ch == kQuote) { - ++pos; - if (pos < pattern.length() && pattern[pos] == kQuote) { - affix->append(kQuote); // Encode quote - // Fall through to append(ch) - } else { - subpart -= 2; // close quote - continue; - } - } - affix->append(ch); - pos += U16_LENGTH(ch); - break; - } - } - - if (sub0Limit == 0) { - sub0Limit = pattern.length(); - } - - if (sub2Limit == 0) { - sub2Limit = pattern.length(); - } - - /* Handle patterns with no '0' pattern character. These patterns - * are legal, but must be recodified to make sense. "##.###" -> - * "#0.###". ".###" -> ".0##". - * - * We allow patterns of the form "####" to produce a zeroDigitCount - * of zero (got that?); although this seems like it might make it - * possible for format() to produce empty strings, format() checks - * for this condition and outputs a zero digit in this situation. - * Having a zeroDigitCount of zero yields a minimum integer digits - * of zero, which allows proper round-trip patterns. We don't want - * "#" to become "#0" when toPattern() is called (even though that's - * what it really is, semantically). - */ - if (zeroDigitCount == 0 && sigDigitCount == 0 && - digitLeftCount > 0 && decimalPos >= 0) { - // Handle "###.###" and "###." and ".###" - int n = decimalPos; - if (n == 0) - ++n; // Handle ".###" - digitRightCount = digitLeftCount - n; - digitLeftCount = n - 1; - zeroDigitCount = 1; - } - - // Do syntax checking on the digits, decimal points, and quotes. - if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) || - (decimalPos >= 0 && - (sigDigitCount > 0 || - decimalPos < digitLeftCount || - decimalPos > (digitLeftCount + zeroDigitCount))) || - groupingCount == 0 || groupingCount2 == 0 || - (sigDigitCount > 0 && zeroDigitCount > 0) || - subpart > 2) - { // subpart > 2 == unmatched quote - debug("Syntax error") - status = U_PATTERN_SYNTAX_ERROR; - syntaxError(pattern,pos,parseError); - return; - } - - // Make sure pad is at legal position before or after affix. - if (padPos >= 0) { - if (padPos == start) { - padPos = DecimalFormatPattern::kPadBeforePrefix; - } else if (padPos+2 == sub0Start) { - padPos = DecimalFormatPattern::kPadAfterPrefix; - } else if (padPos == sub0Limit) { - padPos = DecimalFormatPattern::kPadBeforeSuffix; - } else if (padPos+2 == sub2Limit) { - padPos = DecimalFormatPattern::kPadAfterSuffix; - } else { - // Illegal pad position - debug("Illegal pad position") - status = U_ILLEGAL_PAD_POSITION; - syntaxError(pattern,pos,parseError); - return; - } - } - - if (part == 0) { - out.fPosPatternsBogus = FALSE; - out.fPosPrefixPattern = prefix; - out.fPosSuffixPattern = suffix; - out.fNegPatternsBogus = TRUE; - out.fNegPrefixPattern.remove(); - out.fNegSuffixPattern.remove(); - - out.fUseExponentialNotation = (expDigits >= 0); - if (out.fUseExponentialNotation) { - out.fMinExponentDigits = expDigits; - } - out.fExponentSignAlwaysShown = expSignAlways; - int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount; - // The effectiveDecimalPos is the position the decimal is at or - // would be at if there is no decimal. Note that if - // decimalPos<0, then digitTotalCount == digitLeftCount + - // zeroDigitCount. - int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount; - UBool isSigDig = (sigDigitCount > 0); - out.fUseSignificantDigits = isSigDig; - if (isSigDig) { - out.fMinimumSignificantDigits = sigDigitCount; - out.fMaximumSignificantDigits = sigDigitCount + digitRightCount; - } else { - int32_t minInt = effectiveDecimalPos - digitLeftCount; - out.fMinimumIntegerDigits = minInt; - out.fMaximumIntegerDigits = out.fUseExponentialNotation - ? digitLeftCount + out.fMinimumIntegerDigits - : gDefaultMaxIntegerDigits; - out.fMaximumFractionDigits = decimalPos >= 0 - ? (digitTotalCount - decimalPos) : 0; - out.fMinimumFractionDigits = decimalPos >= 0 - ? (digitLeftCount + zeroDigitCount - decimalPos) : 0; - } - out.fGroupingUsed = groupingCount > 0; - out.fGroupingSize = (groupingCount > 0) ? groupingCount : 0; - out.fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount) - ? groupingCount2 : 0; - out.fMultiplier = multiplier; - out.fDecimalSeparatorAlwaysShown = decimalPos == 0 - || decimalPos == digitTotalCount; - if (padPos >= 0) { - out.fPadPosition = (DecimalFormatPattern::EPadPosition) padPos; - // To compute the format width, first set up sub0Limit - - // sub0Start. Add in prefix/suffix length later. - - // fFormatWidth = prefix.length() + suffix.length() + - // sub0Limit - sub0Start; - out.fFormatWidth = sub0Limit - sub0Start; - out.fPad = padChar; - } else { - out.fFormatWidth = 0; - } - if (roundingPos >= 0) { - out.fRoundingIncrementUsed = TRUE; - roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos); - out.fRoundingIncrement = roundingInc; - } else { - out.fRoundingIncrementUsed = FALSE; - } - } else { - out.fNegPatternsBogus = FALSE; - out.fNegPrefixPattern = prefix; - out.fNegSuffixPattern = suffix; - } - } - - if (pattern.length() == 0) { - out.fNegPatternsBogus = TRUE; - out.fNegPrefixPattern.remove(); - out.fNegSuffixPattern.remove(); - out.fPosPatternsBogus = FALSE; - out.fPosPrefixPattern.remove(); - out.fPosSuffixPattern.remove(); - - out.fMinimumIntegerDigits = 0; - out.fMaximumIntegerDigits = kDoubleIntegerDigits; - out.fMinimumFractionDigits = 0; - out.fMaximumFractionDigits = kDoubleFractionDigits; - - out.fUseExponentialNotation = FALSE; - out.fCurrencySignCount = fgCurrencySignCountZero; - out.fGroupingUsed = FALSE; - out.fGroupingSize = 0; - out.fGroupingSize2 = 0; - out.fMultiplier = 1; - out.fDecimalSeparatorAlwaysShown = FALSE; - out.fFormatWidth = 0; - out.fRoundingIncrementUsed = FALSE; - } - - // If there was no negative pattern, or if the negative pattern is - // identical to the positive pattern, then prepend the minus sign to the - // positive pattern to form the negative pattern. - if (out.fNegPatternsBogus || - (out.fNegPrefixPattern == out.fPosPrefixPattern - && out.fNegSuffixPattern == out.fPosSuffixPattern)) { - out.fNegPatternsBogus = FALSE; - out.fNegSuffixPattern = out.fPosSuffixPattern; - out.fNegPrefixPattern.remove(); - out.fNegPrefixPattern.append(kQuote).append(kPatternMinus) - .append(out.fPosPrefixPattern); - } - // TODO: Deprecate/Remove out.fNegSuffixPattern and 3 other fields. - AffixPattern::parseAffixString( - out.fNegSuffixPattern, out.fNegSuffixAffix, status); - AffixPattern::parseAffixString( - out.fPosSuffixPattern, out.fPosSuffixAffix, status); - AffixPattern::parseAffixString( - out.fNegPrefixPattern, out.fNegPrefixAffix, status); - AffixPattern::parseAffixString( - out.fPosPrefixPattern, out.fPosPrefixAffix, status); -} - -U_NAMESPACE_END - -#endif /* !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/decimalformatpattern.h b/deps/icu-small/source/i18n/decimalformatpattern.h deleted file mode 100644 index 1c297575ea..0000000000 --- a/deps/icu-small/source/i18n/decimalformatpattern.h +++ /dev/null @@ -1,106 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 1997-2015, International Business Machines Corporation and * -* others. All Rights Reserved. * -******************************************************************************* -*/ -#ifndef _DECIMAL_FORMAT_PATTERN -#define _DECIMAL_FORMAT_PATTERN - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/uobject.h" -#include "unicode/unistr.h" -#include "digitlst.h" -#include "affixpatternparser.h" - -U_NAMESPACE_BEGIN - -// currency sign count -enum CurrencySignCount { - fgCurrencySignCountZero, - fgCurrencySignCountInSymbolFormat, - fgCurrencySignCountInISOFormat, - fgCurrencySignCountInPluralFormat -}; - -class DecimalFormatSymbols; - -struct DecimalFormatPattern : public UMemory { - enum EPadPosition { - kPadBeforePrefix, - kPadAfterPrefix, - kPadBeforeSuffix, - kPadAfterSuffix - }; - - DecimalFormatPattern(); - - int32_t fMinimumIntegerDigits; - int32_t fMaximumIntegerDigits; - int32_t fMinimumFractionDigits; - int32_t fMaximumFractionDigits; - UBool fUseSignificantDigits; - int32_t fMinimumSignificantDigits; - int32_t fMaximumSignificantDigits; - UBool fUseExponentialNotation; - int32_t fMinExponentDigits; - UBool fExponentSignAlwaysShown; - int32_t fCurrencySignCount; - UBool fGroupingUsed; - int32_t fGroupingSize; - int32_t fGroupingSize2; - int32_t fMultiplier; - UBool fDecimalSeparatorAlwaysShown; - int32_t fFormatWidth; - UBool fRoundingIncrementUsed; - DigitList fRoundingIncrement; - UChar32 fPad; - UBool fNegPatternsBogus; - UBool fPosPatternsBogus; - UnicodeString fNegPrefixPattern; - UnicodeString fNegSuffixPattern; - UnicodeString fPosPrefixPattern; - UnicodeString fPosSuffixPattern; - AffixPattern fNegPrefixAffix; - AffixPattern fNegSuffixAffix; - AffixPattern fPosPrefixAffix; - AffixPattern fPosSuffixAffix; - EPadPosition fPadPosition; -}; - -class DecimalFormatPatternParser : public UMemory { - public: - DecimalFormatPatternParser(); - void useSymbols(const DecimalFormatSymbols& symbols); - - void applyPatternWithoutExpandAffix( - const UnicodeString& pattern, - DecimalFormatPattern& out, - UParseError& parseError, - UErrorCode& status); - private: - DecimalFormatPatternParser(const DecimalFormatPatternParser&); - DecimalFormatPatternParser& operator=(DecimalFormatPatternParser& rhs); - UChar32 fZeroDigit; - UChar32 fSigDigit; - UnicodeString fGroupingSeparator; - UnicodeString fDecimalSeparator; - UnicodeString fPercent; - UnicodeString fPerMill; - UnicodeString fDigit; - UnicodeString fSeparator; - UnicodeString fExponent; - UnicodeString fPlus; - UnicodeString fMinus; - UnicodeString fPadEscape; -}; - -U_NAMESPACE_END - -#endif /* !UCONFIG_NO_FORMATTING */ -#endif diff --git a/deps/icu-small/source/i18n/decimalformatpatternimpl.h b/deps/icu-small/source/i18n/decimalformatpatternimpl.h deleted file mode 100644 index 8cecc8cca0..0000000000 --- a/deps/icu-small/source/i18n/decimalformatpatternimpl.h +++ /dev/null @@ -1,35 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************** -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************** -* -* File decimalformatpatternimpl.h -******************************************************************************** -*/ - -#ifndef DECIMALFORMATPATTERNIMPL_H -#define DECIMALFORMATPATTERNIMPL_H - -#include "unicode/utypes.h" - -#define kPatternZeroDigit ((UChar)0x0030) /*'0'*/ -#define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/ -#define kPatternGroupingSeparator ((UChar)0x002C) /*','*/ -#define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/ -#define kPatternPerMill ((UChar)0x2030) -#define kPatternPercent ((UChar)0x0025) /*'%'*/ -#define kPatternDigit ((UChar)0x0023) /*'#'*/ -#define kPatternSeparator ((UChar)0x003B) /*';'*/ -#define kPatternExponent ((UChar)0x0045) /*'E'*/ -#define kPatternPlus ((UChar)0x002B) /*'+'*/ -#define kPatternMinus ((UChar)0x002D) /*'-'*/ -#define kPatternPadEscape ((UChar)0x002A) /*'*'*/ -#define kQuote ((UChar)0x0027) /*'\''*/ - -#define kCurrencySign ((UChar)0x00A4) -#define kDefaultPad ((UChar)0x0020) /* */ - -#endif diff --git a/deps/icu-small/source/i18n/decimfmt.cpp b/deps/icu-small/source/i18n/decimfmt.cpp index 80a9446e14..a2638bb742 100644 --- a/deps/icu-small/source/i18n/decimfmt.cpp +++ b/deps/icu-small/source/i18n/decimfmt.cpp @@ -1,3295 +1,1383 @@ -// © 2016 and later: Unicode, Inc. and others. +// © 2018 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 1997-2015, International Business Machines Corporation and * -* others. All Rights Reserved. * -******************************************************************************* -* -* File DECIMFMT.CPP -* -* Modification History: -* -* Date Name Description -* 02/19/97 aliu Converted from java. -* 03/20/97 clhuang Implemented with new APIs. -* 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it. -* 04/3/97 aliu Rewrote parsing and formatting completely, and -* cleaned up and debugged. Actually works now. -* Implemented NAN and INF handling, for both parsing -* and formatting. Extensive testing & debugging. -* 04/10/97 aliu Modified to compile on AIX. -* 04/16/97 aliu Rewrote to use DigitList, which has been resurrected. -* Changed DigitCount to int per code review. -* 07/09/97 helena Made ParsePosition into a class. -* 08/26/97 aliu Extensive changes to applyPattern; completely -* rewritten from the Java. -* 09/09/97 aliu Ported over support for exponential formats. -* 07/20/98 stephen JDK 1.2 sync up. -* Various instances of '0' replaced with 'NULL' -* Check for grouping size in subFormat() -* Brought subParse() in line with Java 1.2 -* Added method appendAffix() -* 08/24/1998 srl Removed Mutex calls. This is not a thread safe class! -* 02/22/99 stephen Removed character literals for EBCDIC safety -* 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes -* 06/28/99 stephen Fixed bugs in toPattern(). -* 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad, -* fPadPosition -******************************************************************************** -*/ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING -#include "unicode/uniset.h" -#include "unicode/currpinf.h" -#include "unicode/plurrule.h" -#include "unicode/utf16.h" -#include "unicode/numsys.h" -#include "unicode/localpointer.h" -#include "unicode/ustring.h" -#include "uresimp.h" -#include "ucurrimp.h" -#include "charstr.h" -#include "patternprops.h" -#include "cstring.h" -#include "uassert.h" -#include "hash.h" -#include "decfmtst.h" -#include "plurrule_impl.h" -#include "decimalformatpattern.h" -#include "fmtableimp.h" -#include "decimfmtimpl.h" -#include "visibledigits.h" - -/* - * On certain platforms, round is a macro defined in math.h - * This undefine is to avoid conflict between the macro and - * the function defined below. - */ -#ifdef round -#undef round -#endif - - -U_NAMESPACE_BEGIN - -#ifdef FMT_DEBUG -#include -static void _debugout(const char *f, int l, const UnicodeString& s) { - char buf[2000]; - s.extract((int32_t) 0, s.length(), buf, "utf-8"); - printf("%s:%d: %s\n", f,l, buf); -} -#define debugout(x) _debugout(__FILE__,__LINE__,x) -#define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x); -static const UnicodeString dbg_null("",""); -#define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null)) +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include +#include +#include +#include "unicode/errorcode.h" +#include "unicode/decimfmt.h" +#include "number_decimalquantity.h" +#include "number_types.h" +#include "numparse_impl.h" +#include "number_mapper.h" +#include "number_patternstring.h" +#include "putilimp.h" +#include "number_utils.h" +#include "number_utypes.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; +using namespace icu::numparse; +using namespace icu::numparse::impl; +using ERoundingMode = icu::DecimalFormat::ERoundingMode; +using EPadPosition = icu::DecimalFormat::EPadPosition; + +// MSVC warns C4805 when comparing bool with UBool +// TODO: Move this macro into a better place? +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +#define UBOOL_TO_BOOL(b) static_cast(b) #else -#define debugout(x) -#define debug(x) -#endif - - -/* For currency parsing purose, - * Need to remember all prefix patterns and suffix patterns of - * every currency format pattern, - * including the pattern of default currecny style - * and plural currency style. And the patterns are set through applyPattern. - */ -struct AffixPatternsForCurrency : public UMemory { - // negative prefix pattern - UnicodeString negPrefixPatternForCurrency; - // negative suffix pattern - UnicodeString negSuffixPatternForCurrency; - // positive prefix pattern - UnicodeString posPrefixPatternForCurrency; - // positive suffix pattern - UnicodeString posSuffixPatternForCurrency; - int8_t patternType; - - AffixPatternsForCurrency(const UnicodeString& negPrefix, - const UnicodeString& negSuffix, - const UnicodeString& posPrefix, - const UnicodeString& posSuffix, - int8_t type) { - negPrefixPatternForCurrency = negPrefix; - negSuffixPatternForCurrency = negSuffix; - posPrefixPatternForCurrency = posPrefix; - posSuffixPatternForCurrency = posSuffix; - patternType = type; - } -#ifdef FMT_DEBUG - void dump() const { - debugout( UnicodeString("AffixPatternsForCurrency( -=\"") + - negPrefixPatternForCurrency + (UnicodeString)"\"/\"" + - negSuffixPatternForCurrency + (UnicodeString)"\" +=\"" + - posPrefixPatternForCurrency + (UnicodeString)"\"/\"" + - posSuffixPatternForCurrency + (UnicodeString)"\" )"); - } +#define UBOOL_TO_BOOL(b) b #endif -}; - -/* affix for currency formatting when the currency sign in the pattern - * equals to 3, such as the pattern contains 3 currency sign or - * the formatter style is currency plural format style. - */ -struct AffixesForCurrency : public UMemory { - // negative prefix - UnicodeString negPrefixForCurrency; - // negative suffix - UnicodeString negSuffixForCurrency; - // positive prefix - UnicodeString posPrefixForCurrency; - // positive suffix - UnicodeString posSuffixForCurrency; - - int32_t formatWidth; - - AffixesForCurrency(const UnicodeString& negPrefix, - const UnicodeString& negSuffix, - const UnicodeString& posPrefix, - const UnicodeString& posSuffix) { - negPrefixForCurrency = negPrefix; - negSuffixForCurrency = negSuffix; - posPrefixForCurrency = posPrefix; - posSuffixForCurrency = posSuffix; - } -#ifdef FMT_DEBUG - void dump() const { - debugout( UnicodeString("AffixesForCurrency( -=\"") + - negPrefixForCurrency + (UnicodeString)"\"/\"" + - negSuffixForCurrency + (UnicodeString)"\" +=\"" + - posPrefixForCurrency + (UnicodeString)"\"/\"" + - posSuffixForCurrency + (UnicodeString)"\" )"); - } -#endif -}; - -U_CDECL_BEGIN - -/** - * @internal ICU 4.2 - */ -static UBool U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2); - - -static UBool -U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) { - const AffixPatternsForCurrency* affix_1 = - (AffixPatternsForCurrency*)val1.pointer; - const AffixPatternsForCurrency* affix_2 = - (AffixPatternsForCurrency*)val2.pointer; - return affix_1->negPrefixPatternForCurrency == - affix_2->negPrefixPatternForCurrency && - affix_1->negSuffixPatternForCurrency == - affix_2->negSuffixPatternForCurrency && - affix_1->posPrefixPatternForCurrency == - affix_2->posPrefixPatternForCurrency && - affix_1->posSuffixPatternForCurrency == - affix_2->posSuffixPatternForCurrency && - affix_1->patternType == affix_2->patternType; -} - -U_CDECL_END - - -// ***************************************************************************** -// class DecimalFormat -// ***************************************************************************** - UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat) -// Constants for characters used in programmatic (unlocalized) patterns. -#define kPatternZeroDigit ((UChar)0x0030) /*'0'*/ -#define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/ -#define kPatternGroupingSeparator ((UChar)0x002C) /*','*/ -#define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/ -#define kPatternPerMill ((UChar)0x2030) -#define kPatternPercent ((UChar)0x0025) /*'%'*/ -#define kPatternDigit ((UChar)0x0023) /*'#'*/ -#define kPatternSeparator ((UChar)0x003B) /*';'*/ -#define kPatternExponent ((UChar)0x0045) /*'E'*/ -#define kPatternPlus ((UChar)0x002B) /*'+'*/ -#define kPatternMinus ((UChar)0x002D) /*'-'*/ -#define kPatternPadEscape ((UChar)0x002A) /*'*'*/ -#define kQuote ((UChar)0x0027) /*'\''*/ -/** - * The CURRENCY_SIGN is the standard Unicode symbol for currency. It - * is used in patterns and substitued with either the currency symbol, - * or if it is doubled, with the international currency symbol. If the - * CURRENCY_SIGN is seen in a pattern, then the decimal separator is - * replaced with the monetary decimal separator. - */ -#define kCurrencySign ((UChar)0x00A4) -#define kDefaultPad ((UChar)0x0020) /* */ - -const int32_t DecimalFormat::kDoubleIntegerDigits = 309; -const int32_t DecimalFormat::kDoubleFractionDigits = 340; - -const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8; - -/** - * These are the tags we expect to see in normal resource bundle files associated - * with a locale. - */ -const char DecimalFormat::fgNumberPatterns[]="NumberPatterns"; // Deprecated - not used -static const char fgNumberElements[]="NumberElements"; -static const char fgLatn[]="latn"; -static const char fgPatterns[]="patterns"; -static const char fgDecimalFormat[]="decimalFormat"; -static const char fgCurrencyFormat[]="currencyFormat"; - -inline int32_t _min(int32_t a, int32_t b) { return (a adoptedSymbols(symbolsToAdopt); - if (U_FAILURE(status)) - return; - - if (adoptedSymbols.isNull()) - { - adoptedSymbols.adoptInstead( - new DecimalFormatSymbols(Locale::getDefault(), status)); - if (adoptedSymbols.isNull() && U_SUCCESS(status)) { - status = U_MEMORY_ALLOCATION_ERROR; - } - if (U_FAILURE(status)) { - return; - } - } - fStaticSets = DecimalFormatStaticSets::getStaticSets(status); - if (U_FAILURE(status)) { - return; - } - - UnicodeString str; - // Uses the default locale's number format pattern if there isn't - // one specified. - if (pattern == NULL) - { - UErrorCode nsStatus = U_ZERO_ERROR; - LocalPointer ns( - NumberingSystem::createInstance(nsStatus)); - if (U_FAILURE(nsStatus)) { - status = nsStatus; - return; - } - - int32_t len = 0; - UResourceBundle *top = ures_open(NULL, Locale::getDefault().getName(), &status); - - UResourceBundle *resource = ures_getByKeyWithFallback(top, fgNumberElements, NULL, &status); - resource = ures_getByKeyWithFallback(resource, ns->getName(), resource, &status); - resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status); - const UChar *resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status); - if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(fgLatn,ns->getName())) { - status = U_ZERO_ERROR; - resource = ures_getByKeyWithFallback(top, fgNumberElements, resource, &status); - resource = ures_getByKeyWithFallback(resource, fgLatn, resource, &status); - resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status); - resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status); - } - str.setTo(TRUE, resStr, len); - pattern = &str; - ures_close(resource); - ures_close(top); - } - - fImpl = new DecimalFormatImpl(this, *pattern, adoptedSymbols.getAlias(), parseErr, status); - if (fImpl) { - adoptedSymbols.orphan(); - } else if (U_SUCCESS(status)) { - status = U_MEMORY_ALLOCATION_ERROR; - } - if (U_FAILURE(status)) { - return; - } - - if (U_FAILURE(status)) - { - return; - } - - const UnicodeString* patternUsed; - UnicodeString currencyPluralPatternForOther; - // apply pattern - if (fStyle == UNUM_CURRENCY_PLURAL) { - fCurrencyPluralInfo = new CurrencyPluralInfo(fImpl->fSymbols->getLocale(), status); - if (U_FAILURE(status)) { - return; - } - - // the pattern used in format is not fixed until formatting, - // in which, the number is known and - // will be used to pick the right pattern based on plural count. - // Here, set the pattern as the pattern of plural count == "other". - // For most locale, the patterns are probably the same for all - // plural count. If not, the right pattern need to be re-applied - // during format. - fCurrencyPluralInfo->getCurrencyPluralPattern(UNICODE_STRING("other", 5), currencyPluralPatternForOther); - // TODO(refactor): Revisit, we are setting the pattern twice. - fImpl->applyPatternFavorCurrencyPrecision( - currencyPluralPatternForOther, status); - patternUsed = ¤cyPluralPatternForOther; +DecimalFormat::DecimalFormat(UErrorCode& status) + : DecimalFormat(nullptr, status) { + // Use the default locale and decimal pattern. + const char* localeName = Locale::getDefault().getName(); + LocalPointer ns(NumberingSystem::createInstance(status)); + UnicodeString patternString = utils::getPatternForStyle( + localeName, + ns->getName(), + CLDR_PATTERN_STYLE_DECIMAL, + status); + setPropertiesFromPattern(patternString, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status) + : DecimalFormat(nullptr, status) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UErrorCode& status) + : DecimalFormat(symbolsToAdopt, status) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UNumberFormatStyle style, UErrorCode& status) + : DecimalFormat(symbolsToAdopt, status) { + // If choice is a currency type, ignore the rounding information. + if (style == UNumberFormatStyle::UNUM_CURRENCY || style == UNumberFormatStyle::UNUM_CURRENCY_ISO || + style == UNumberFormatStyle::UNUM_CURRENCY_ACCOUNTING || + style == UNumberFormatStyle::UNUM_CASH_CURRENCY || + style == UNumberFormatStyle::UNUM_CURRENCY_STANDARD || + style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_ALWAYS, status); } else { - patternUsed = pattern; + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); } - - if (patternUsed->indexOf(kCurrencySign) != -1) { - // initialize for currency, not only for plural format, - // but also for mix parsing - handleCurrencySignInPattern(status); + // Note: in Java, CurrencyPluralInfo is set in NumberFormat.java, but in C++, it is not set there, + // so we have to set it here. + if (style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) { + LocalPointer cpi( + new CurrencyPluralInfo(fields->symbols->getLocale(), status), + status); + if (U_FAILURE(status)) { return; } + fields->properties->currencyPluralInfo.fPtr.adoptInstead(cpi.orphan()); } + touch(status); } -void -DecimalFormat::handleCurrencySignInPattern(UErrorCode& status) { - // initialize for currency, not only for plural format, - // but also for mix parsing +DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) { + LocalPointer adoptedSymbols(symbolsToAdopt); + fields = new DecimalFormatFields(); if (U_FAILURE(status)) { return; } - if (fCurrencyPluralInfo == NULL) { - fCurrencyPluralInfo = new CurrencyPluralInfo(fImpl->fSymbols->getLocale(), status); - if (U_FAILURE(status)) { - return; - } - } - // need it for mix parsing - if (fAffixPatternsForCurrency == NULL) { - setupCurrencyAffixPatterns(status); - } -} - -static void -applyPatternWithNoSideEffects( - const UnicodeString& pattern, - UParseError& parseError, - UnicodeString &negPrefix, - UnicodeString &negSuffix, - UnicodeString &posPrefix, - UnicodeString &posSuffix, - UErrorCode& status) { - if (U_FAILURE(status)) - { + if (fields == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; return; } - DecimalFormatPatternParser patternParser; - DecimalFormatPattern out; - patternParser.applyPatternWithoutExpandAffix( - pattern, - out, - parseError, - status); - if (U_FAILURE(status)) { - return; + fields->properties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status); + fields->exportedProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status); + if (adoptedSymbols.isNull()) { + fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status); + } else { + fields->symbols.adoptInsteadAndCheckErrorCode(adoptedSymbols.orphan(), status); } - negPrefix = out.fNegPrefixPattern; - negSuffix = out.fNegSuffixPattern; - posPrefix = out.fPosPrefixPattern; - posSuffix = out.fPosSuffixPattern; } -void -DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) { - if (U_FAILURE(status)) { - return; - } - UParseError parseErr; - fAffixPatternsForCurrency = initHashForAffixPattern(status); - if (U_FAILURE(status)) { - return; - } - - NumberingSystem *ns = NumberingSystem::createInstance(fImpl->fSymbols->getLocale(),status); - if (U_FAILURE(status)) { - return; - } +#if UCONFIG_HAVE_PARSEALLINPUT - // Save the default currency patterns of this locale. - // Here, chose onlyApplyPatternWithoutExpandAffix without - // expanding the affix patterns into affixes. - UnicodeString currencyPattern; - UErrorCode error = U_ZERO_ERROR; - - UResourceBundle *resource = ures_open(NULL, fImpl->fSymbols->getLocale().getName(), &error); - UResourceBundle *numElements = ures_getByKeyWithFallback(resource, fgNumberElements, NULL, &error); - resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &error); - resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error); - int32_t patLen = 0; - const UChar *patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error); - if ( error == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),fgLatn)) { - error = U_ZERO_ERROR; - resource = ures_getByKeyWithFallback(numElements, fgLatn, resource, &error); - resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error); - patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error); - } - ures_close(numElements); - ures_close(resource); - delete ns; - - if (U_SUCCESS(error)) { - UnicodeString negPrefix; - UnicodeString negSuffix; - UnicodeString posPrefix; - UnicodeString posSuffix; - applyPatternWithNoSideEffects(UnicodeString(patResStr, patLen), - parseErr, - negPrefix, negSuffix, posPrefix, posSuffix, status); - AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency( - negPrefix, - negSuffix, - posPrefix, - posSuffix, - UCURR_SYMBOL_NAME); - fAffixPatternsForCurrency->put(UNICODE_STRING("default", 7), affixPtn, status); - } - - // save the unique currency plural patterns of this locale. - Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPattern; - const UHashElement* element = NULL; - int32_t pos = UHASH_FIRST; - Hashtable pluralPatternSet; - while ((element = pluralPtn->nextElement(pos)) != NULL) { - const UHashTok valueTok = element->value; - const UnicodeString* value = (UnicodeString*)valueTok.pointer; - const UHashTok keyTok = element->key; - const UnicodeString* key = (UnicodeString*)keyTok.pointer; - if (pluralPatternSet.geti(*value) != 1) { - UnicodeString negPrefix; - UnicodeString negSuffix; - UnicodeString posPrefix; - UnicodeString posSuffix; - pluralPatternSet.puti(*value, 1, status); - applyPatternWithNoSideEffects( - *value, parseErr, - negPrefix, negSuffix, posPrefix, posSuffix, status); - AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency( - negPrefix, - negSuffix, - posPrefix, - posSuffix, - UCURR_LONG_NAME); - fAffixPatternsForCurrency->put(*key, affixPtn, status); - } - } +void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) { + if (value == fields->properties->parseAllInput) { return; } + fields->properties->parseAllInput = value; } +#endif -//------------------------------------------------------------------------------ +DecimalFormat& +DecimalFormat::setAttribute(UNumberFormatAttribute attr, int32_t newValue, UErrorCode& status) { + if (U_FAILURE(status)) { return *this; } -DecimalFormat::~DecimalFormat() -{ - deleteHashForAffixPattern(); - delete fCurrencyPluralInfo; - delete fImpl; -} + switch (attr) { + case UNUM_LENIENT_PARSE: + setLenient(newValue != 0); + break; -//------------------------------------------------------------------------------ -// copy constructor + case UNUM_PARSE_INT_ONLY: + setParseIntegerOnly(newValue != 0); + break; -DecimalFormat::DecimalFormat(const DecimalFormat &source) : - NumberFormat(source) { - init(); - *this = source; -} + case UNUM_GROUPING_USED: + setGroupingUsed(newValue != 0); + break; -//------------------------------------------------------------------------------ -// assignment operator + case UNUM_DECIMAL_ALWAYS_SHOWN: + setDecimalSeparatorAlwaysShown(newValue != 0); + break; -template -static void _clone_ptr(T** pdest, const T* source) { - delete *pdest; - if (source == NULL) { - *pdest = NULL; - } else { - *pdest = static_cast(source->clone()); - } -} + case UNUM_MAX_INTEGER_DIGITS: + setMaximumIntegerDigits(newValue); + break; -DecimalFormat& -DecimalFormat::operator=(const DecimalFormat& rhs) -{ - if(this != &rhs) { - UErrorCode status = U_ZERO_ERROR; - NumberFormat::operator=(rhs); - if (fImpl == NULL) { - fImpl = new DecimalFormatImpl(this, *rhs.fImpl, status); - } else { - fImpl->assign(*rhs.fImpl, status); - } - fStaticSets = DecimalFormatStaticSets::getStaticSets(status); - fStyle = rhs.fStyle; - _clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo); - deleteHashForAffixPattern(); - if (rhs.fAffixPatternsForCurrency) { - UErrorCode status = U_ZERO_ERROR; - fAffixPatternsForCurrency = initHashForAffixPattern(status); - copyHashForAffixPattern(rhs.fAffixPatternsForCurrency, - fAffixPatternsForCurrency, status); - } - } + case UNUM_MIN_INTEGER_DIGITS: + setMinimumIntegerDigits(newValue); + break; - return *this; -} + case UNUM_INTEGER_DIGITS: + setMinimumIntegerDigits(newValue); + setMaximumIntegerDigits(newValue); + break; -//------------------------------------------------------------------------------ + case UNUM_MAX_FRACTION_DIGITS: + setMaximumFractionDigits(newValue); + break; -UBool -DecimalFormat::operator==(const Format& that) const -{ - if (this == &that) - return TRUE; + case UNUM_MIN_FRACTION_DIGITS: + setMinimumFractionDigits(newValue); + break; - // NumberFormat::operator== guarantees this cast is safe - const DecimalFormat* other = (DecimalFormat*)&that; + case UNUM_FRACTION_DIGITS: + setMinimumFractionDigits(newValue); + setMaximumFractionDigits(newValue); + break; - return ( - NumberFormat::operator==(that) && - fBoolFlags.getAll() == other->fBoolFlags.getAll() && - *fImpl == *other->fImpl); + case UNUM_SIGNIFICANT_DIGITS_USED: + setSignificantDigitsUsed(newValue != 0); + break; -} + case UNUM_MAX_SIGNIFICANT_DIGITS: + setMaximumSignificantDigits(newValue); + break; -//------------------------------------------------------------------------------ + case UNUM_MIN_SIGNIFICANT_DIGITS: + setMinimumSignificantDigits(newValue); + break; -Format* -DecimalFormat::clone() const -{ - return new DecimalFormat(*this); -} + case UNUM_MULTIPLIER: + setMultiplier(newValue); + break; + case UNUM_SCALE: + setMultiplierScale(newValue); + break; -FixedDecimal -DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const { - VisibleDigitsWithExponent digits; - initVisibleDigitsWithExponent(number, digits, status); - if (U_FAILURE(status)) { - return FixedDecimal(); - } - return FixedDecimal(digits.getMantissa()); -} + case UNUM_GROUPING_SIZE: + setGroupingSize(newValue); + break; -VisibleDigitsWithExponent & -DecimalFormat::initVisibleDigitsWithExponent( - double number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - return fImpl->initVisibleDigitsWithExponent(number, digits, status); -} + case UNUM_ROUNDING_MODE: + setRoundingMode((DecimalFormat::ERoundingMode) newValue); + break; -FixedDecimal -DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const { - VisibleDigitsWithExponent digits; - initVisibleDigitsWithExponent(number, digits, status); - if (U_FAILURE(status)) { - return FixedDecimal(); - } - return FixedDecimal(digits.getMantissa()); -} + case UNUM_FORMAT_WIDTH: + setFormatWidth(newValue); + break; -VisibleDigitsWithExponent & -DecimalFormat::initVisibleDigitsWithExponent( - const Formattable &number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return digits; - } - if (!number.isNumeric()) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return digits; - } + case UNUM_PADDING_POSITION: + /** The position at which padding will take place. */ + setPadPosition((DecimalFormat::EPadPosition) newValue); + break; - DigitList *dl = number.getDigitList(); - if (dl != NULL) { - DigitList dlCopy(*dl); - return fImpl->initVisibleDigitsWithExponent( - dlCopy, digits, status); - } + case UNUM_SECONDARY_GROUPING_SIZE: + setSecondaryGroupingSize(newValue); + break; - Formattable::Type type = number.getType(); - if (type == Formattable::kDouble || type == Formattable::kLong) { - return fImpl->initVisibleDigitsWithExponent( - number.getDouble(status), digits, status); - } - return fImpl->initVisibleDigitsWithExponent( - number.getInt64(), digits, status); -} +#if UCONFIG_HAVE_PARSEALLINPUT + case UNUM_PARSE_ALL_INPUT: + setParseAllInput((UNumberFormatAttributeValue) newValue); + break; +#endif + case UNUM_PARSE_NO_EXPONENT: + setParseNoExponent((UBool) newValue); + break; -// Create a fixed decimal from a DigitList. -// The digit list may be modified. -// Internal function only. -FixedDecimal -DecimalFormat::getFixedDecimal(DigitList &number, UErrorCode &status) const { - VisibleDigitsWithExponent digits; - initVisibleDigitsWithExponent(number, digits, status); - if (U_FAILURE(status)) { - return FixedDecimal(); - } - return FixedDecimal(digits.getMantissa()); -} + case UNUM_PARSE_DECIMAL_MARK_REQUIRED: + setDecimalPatternMatchRequired((UBool) newValue); + break; -VisibleDigitsWithExponent & -DecimalFormat::initVisibleDigitsWithExponent( - DigitList &number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - return fImpl->initVisibleDigitsWithExponent( - number, digits, status); -} + case UNUM_CURRENCY_USAGE: + setCurrencyUsage((UCurrencyUsage) newValue, &status); + break; + case UNUM_MINIMUM_GROUPING_DIGITS: + setMinimumGroupingDigits(newValue); + break; -//------------------------------------------------------------------------------ + case UNUM_PARSE_CASE_SENSITIVE: + setParseCaseSensitive(static_cast(newValue)); + break; -UnicodeString& -DecimalFormat::format(int32_t number, - UnicodeString& appendTo, - FieldPosition& fieldPosition) const -{ - UErrorCode status = U_ZERO_ERROR; - return fImpl->format(number, appendTo, fieldPosition, status); -} + case UNUM_SIGN_ALWAYS_SHOWN: + setSignAlwaysShown(static_cast(newValue)); + break; -UnicodeString& -DecimalFormat::format(int32_t number, - UnicodeString& appendTo, - FieldPosition& fieldPosition, - UErrorCode& status) const -{ - return fImpl->format(number, appendTo, fieldPosition, status); -} + case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: + setFormatFailIfMoreThanMaxDigits(static_cast(newValue)); + break; -UnicodeString& -DecimalFormat::format(int32_t number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const -{ - return fImpl->format(number, appendTo, posIter, status); + default: + status = U_UNSUPPORTED_ERROR; + break; + } + return *this; } +int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const { + if (U_FAILURE(status)) { return -1; } + switch (attr) { + case UNUM_LENIENT_PARSE: + return isLenient(); -//------------------------------------------------------------------------------ + case UNUM_PARSE_INT_ONLY: + return isParseIntegerOnly(); -UnicodeString& -DecimalFormat::format(int64_t number, - UnicodeString& appendTo, - FieldPosition& fieldPosition) const -{ - UErrorCode status = U_ZERO_ERROR; /* ignored */ - return fImpl->format(number, appendTo, fieldPosition, status); -} + case UNUM_GROUPING_USED: + return isGroupingUsed(); -UnicodeString& -DecimalFormat::format(int64_t number, - UnicodeString& appendTo, - FieldPosition& fieldPosition, - UErrorCode& status) const -{ - return fImpl->format(number, appendTo, fieldPosition, status); -} + case UNUM_DECIMAL_ALWAYS_SHOWN: + return isDecimalSeparatorAlwaysShown(); -UnicodeString& -DecimalFormat::format(int64_t number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const -{ - return fImpl->format(number, appendTo, posIter, status); -} + case UNUM_MAX_INTEGER_DIGITS: + return getMaximumIntegerDigits(); -//------------------------------------------------------------------------------ + case UNUM_MIN_INTEGER_DIGITS: + return getMinimumIntegerDigits(); -UnicodeString& -DecimalFormat::format( double number, - UnicodeString& appendTo, - FieldPosition& fieldPosition) const -{ - UErrorCode status = U_ZERO_ERROR; /* ignored */ - return fImpl->format(number, appendTo, fieldPosition, status); -} + case UNUM_INTEGER_DIGITS: + // TBD: what should this return? + return getMinimumIntegerDigits(); -UnicodeString& -DecimalFormat::format( double number, - UnicodeString& appendTo, - FieldPosition& fieldPosition, - UErrorCode& status) const -{ - return fImpl->format(number, appendTo, fieldPosition, status); -} + case UNUM_MAX_FRACTION_DIGITS: + return getMaximumFractionDigits(); -UnicodeString& -DecimalFormat::format( double number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const -{ - return fImpl->format(number, appendTo, posIter, status); -} + case UNUM_MIN_FRACTION_DIGITS: + return getMinimumFractionDigits(); -//------------------------------------------------------------------------------ + case UNUM_FRACTION_DIGITS: + // TBD: what should this return? + return getMinimumFractionDigits(); + case UNUM_SIGNIFICANT_DIGITS_USED: + return areSignificantDigitsUsed(); -UnicodeString& -DecimalFormat::format(StringPiece number, - UnicodeString &toAppendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const -{ - return fImpl->format(number, toAppendTo, posIter, status); -} + case UNUM_MAX_SIGNIFICANT_DIGITS: + return getMaximumSignificantDigits(); + case UNUM_MIN_SIGNIFICANT_DIGITS: + return getMinimumSignificantDigits(); -UnicodeString& -DecimalFormat::format(const DigitList &number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const { - return fImpl->format(number, appendTo, posIter, status); -} + case UNUM_MULTIPLIER: + return getMultiplier(); + case UNUM_SCALE: + return getMultiplierScale(); -UnicodeString& -DecimalFormat::format(const DigitList &number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const { - return fImpl->format(number, appendTo, pos, status); -} + case UNUM_GROUPING_SIZE: + return getGroupingSize(); -UnicodeString& -DecimalFormat::format(const VisibleDigitsWithExponent &number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const { - return fImpl->format(number, appendTo, posIter, status); -} + case UNUM_ROUNDING_MODE: + return getRoundingMode(); + case UNUM_FORMAT_WIDTH: + return getFormatWidth(); -UnicodeString& -DecimalFormat::format(const VisibleDigitsWithExponent &number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const { - return fImpl->format(number, appendTo, pos, status); -} + case UNUM_PADDING_POSITION: + return getPadPosition(); -DigitList& -DecimalFormat::_round(const DigitList& number, DigitList& adjustedNum, UBool& isNegative, UErrorCode& status) const { - adjustedNum = number; - fImpl->round(adjustedNum, status); - isNegative = !adjustedNum.isPositive(); - return adjustedNum; -} + case UNUM_SECONDARY_GROUPING_SIZE: + return getSecondaryGroupingSize(); -void -DecimalFormat::parse(const UnicodeString& text, - Formattable& result, - ParsePosition& parsePosition) const { - parse(text, result, parsePosition, NULL); -} - -CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, - ParsePosition& pos) const { - Formattable parseResult; - int32_t start = pos.getIndex(); - UChar curbuf[4] = {}; - parse(text, parseResult, pos, curbuf); - if (pos.getIndex() != start) { - UErrorCode ec = U_ZERO_ERROR; - LocalPointer currAmt(new CurrencyAmount(parseResult, curbuf, ec), ec); - if (U_FAILURE(ec)) { - pos.setIndex(start); // indicate failure - } else { - return currAmt.orphan(); - } - } - return NULL; -} - -/** - * Parses the given text as a number, optionally providing a currency amount. - * @param text the string to parse - * @param result output parameter for the numeric result. - * @param parsePosition input-output position; on input, the - * position within text to match; must have 0 <= pos.getIndex() < - * text.length(); on output, the position after the last matched - * character. If the parse fails, the position in unchanged upon - * output. - * @param currency if non-NULL, it should point to a 4-UChar buffer. - * In this case the text is parsed as a currency format, and the - * ISO 4217 code for the parsed currency is put into the buffer. - * Otherwise the text is parsed as a non-currency format. - */ -void DecimalFormat::parse(const UnicodeString& text, - Formattable& result, - ParsePosition& parsePosition, - UChar* currency) const { - int32_t startIdx, backup; - int32_t i = startIdx = backup = parsePosition.getIndex(); - - // clear any old contents in the result. In particular, clears any DigitList - // that it may be holding. - result.setLong(0); - if (currency != NULL) { - for (int32_t ci=0; ci<4; ci++) { - currency[ci] = 0; - } - } + case UNUM_PARSE_NO_EXPONENT: + return isParseNoExponent(); - // Handle NaN as a special case: - int32_t formatWidth = fImpl->getOldFormatWidth(); + case UNUM_PARSE_DECIMAL_MARK_REQUIRED: + return isDecimalPatternMatchRequired(); - // Skip padding characters, if around prefix - if (formatWidth > 0 && ( - fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix || - fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix)) { - i = skipPadding(text, i); - } + case UNUM_CURRENCY_USAGE: + return getCurrencyUsage(); - if (isLenient()) { - // skip any leading whitespace - i = backup = skipUWhiteSpace(text, i); - } + case UNUM_MINIMUM_GROUPING_DIGITS: + return getMinimumGroupingDigits(); - // If the text is composed of the representation of NaN, returns NaN.length - const UnicodeString *nan = &fImpl->getConstSymbol(DecimalFormatSymbols::kNaNSymbol); - int32_t nanLen = (text.compare(i, nan->length(), *nan) - ? 0 : nan->length()); - if (nanLen) { - i += nanLen; - if (formatWidth > 0 && (fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix || fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix)) { - i = skipPadding(text, i); - } - parsePosition.setIndex(i); - result.setDouble(uprv_getNaN()); - return; - } + case UNUM_PARSE_CASE_SENSITIVE: + return isParseCaseSensitive(); - // NaN parse failed; start over - i = backup; - parsePosition.setIndex(i); + case UNUM_SIGN_ALWAYS_SHOWN: + return isSignAlwaysShown(); - // status is used to record whether a number is infinite. - UBool status[fgStatusLength]; + case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: + return isFormatFailIfMoreThanMaxDigits(); - DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer - if (digits == NULL) { - return; // no way to report error from here. + default: + status = U_UNSUPPORTED_ERROR; + break; } - if (fImpl->fMonetary) { - if (!parseForCurrency(text, parsePosition, *digits, - status, currency)) { - return; - } - } else { - if (!subparse(text, - &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(), - &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(), - &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(), - &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(), - FALSE, UCURR_SYMBOL_NAME, - parsePosition, *digits, status, currency)) { - debug("!subparse(...) - rewind"); - parsePosition.setIndex(startIdx); - return; - } - } + return -1; /* undefined */ +} - // Handle infinity - if (status[fgStatusInfinite]) { - double inf = uprv_getInfinity(); - result.setDouble(digits->isPositive() ? inf : -inf); - // TODO: set the dl to infinity, and let it fall into the code below. - } +void DecimalFormat::setGroupingUsed(UBool enabled) { + if (UBOOL_TO_BOOL(enabled) == fields->properties->groupingUsed) { return; } + NumberFormat::setGroupingUsed(enabled); // to set field for compatibility + fields->properties->groupingUsed = enabled; + touchNoError(); +} - else { +void DecimalFormat::setParseIntegerOnly(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->parseIntegerOnly) { return; } + NumberFormat::setParseIntegerOnly(value); // to set field for compatibility + fields->properties->parseIntegerOnly = value; + touchNoError(); +} - if (!fImpl->fMultiplier.isZero()) { - UErrorCode ec = U_ZERO_ERROR; - digits->div(fImpl->fMultiplier, ec); - } +void DecimalFormat::setLenient(UBool enable) { + ParseMode mode = enable ? PARSE_MODE_LENIENT : PARSE_MODE_STRICT; + if (!fields->properties->parseMode.isNull() && mode == fields->properties->parseMode.getNoError()) { return; } + NumberFormat::setLenient(enable); // to set field for compatibility + fields->properties->parseMode = mode; + touchNoError(); +} - if (fImpl->fScale != 0) { - DigitList ten; - ten.set((int32_t)10); - if (fImpl->fScale > 0) { - for (int32_t i = fImpl->fScale; i > 0; i--) { - UErrorCode ec = U_ZERO_ERROR; - digits->div(ten,ec); - } - } else { - for (int32_t i = fImpl->fScale; i < 0; i++) { - UErrorCode ec = U_ZERO_ERROR; - digits->mult(ten,ec); - } - } - } +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UParseError&, UErrorCode& status) + : DecimalFormat(symbolsToAdopt, status) { + // TODO: What is parseError for? + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} - // Negative zero special case: - // if parsing integerOnly, change to +0, which goes into an int32 in a Formattable. - // if not parsing integerOnly, leave as -0, which a double can represent. - if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) { - digits->setPositive(TRUE); - } - result.adoptDigitList(digits); - } -} - - - -UBool -DecimalFormat::parseForCurrency(const UnicodeString& text, - ParsePosition& parsePosition, - DigitList& digits, - UBool* status, - UChar* currency) const { - UnicodeString positivePrefix; - UnicodeString positiveSuffix; - UnicodeString negativePrefix; - UnicodeString negativeSuffix; - fImpl->fPositivePrefixPattern.toString(positivePrefix); - fImpl->fPositiveSuffixPattern.toString(positiveSuffix); - fImpl->fNegativePrefixPattern.toString(negativePrefix); - fImpl->fNegativeSuffixPattern.toString(negativeSuffix); - - int origPos = parsePosition.getIndex(); - int maxPosIndex = origPos; - int maxErrorPos = -1; - // First, parse against current pattern. - // Since current pattern could be set by applyPattern(), - // it could be an arbitrary pattern, and it may not be the one - // defined in current locale. - UBool tmpStatus[fgStatusLength]; - ParsePosition tmpPos(origPos); - DigitList tmpDigitList; - UBool found; - if (fStyle == UNUM_CURRENCY_PLURAL) { - found = subparse(text, - &negativePrefix, &negativeSuffix, - &positivePrefix, &positiveSuffix, - TRUE, UCURR_LONG_NAME, - tmpPos, tmpDigitList, tmpStatus, currency); - } else { - found = subparse(text, - &negativePrefix, &negativeSuffix, - &positivePrefix, &positiveSuffix, - TRUE, UCURR_SYMBOL_NAME, - tmpPos, tmpDigitList, tmpStatus, currency); - } - if (found) { - if (tmpPos.getIndex() > maxPosIndex) { - maxPosIndex = tmpPos.getIndex(); - for (int32_t i = 0; i < fgStatusLength; ++i) { - status[i] = tmpStatus[i]; - } - digits = tmpDigitList; - } - } else { - maxErrorPos = tmpPos.getErrorIndex(); - } - // Then, parse against affix patterns. - // Those are currency patterns and currency plural patterns. - int32_t pos = UHASH_FIRST; - const UHashElement* element = NULL; - while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) { - const UHashTok valueTok = element->value; - const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)valueTok.pointer; - UBool tmpStatus[fgStatusLength]; - ParsePosition tmpPos(origPos); - DigitList tmpDigitList; - -#ifdef FMT_DEBUG - debug("trying affix for currency.."); - affixPtn->dump(); -#endif +DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols, + UErrorCode& status) + : DecimalFormat(new DecimalFormatSymbols(symbols), status) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} - UBool result = subparse(text, - &affixPtn->negPrefixPatternForCurrency, - &affixPtn->negSuffixPatternForCurrency, - &affixPtn->posPrefixPatternForCurrency, - &affixPtn->posSuffixPatternForCurrency, - TRUE, affixPtn->patternType, - tmpPos, tmpDigitList, tmpStatus, currency); - if (result) { - found = true; - if (tmpPos.getIndex() > maxPosIndex) { - maxPosIndex = tmpPos.getIndex(); - for (int32_t i = 0; i < fgStatusLength; ++i) { - status[i] = tmpStatus[i]; - } - digits = tmpDigitList; - } - } else { - maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ? - tmpPos.getErrorIndex() : maxErrorPos; - } +DecimalFormat::DecimalFormat(const DecimalFormat& source) : NumberFormat(source) { + // Note: it is not safe to copy fields->formatter or fWarehouse directly because fields->formatter might have + // dangling pointers to fields inside fWarehouse. The safe thing is to re-construct fields->formatter from + // the property bag, despite being somewhat slower. + fields = new DecimalFormatFields(); + if (fields == nullptr) { + return; } - // Finally, parse against simple affix to find the match. - // For example, in TestMonster suite, - // if the to-be-parsed text is "-\u00A40,00". - // complexAffixCompare will not find match, - // since there is no ISO code matches "\u00A4", - // and the parse stops at "\u00A4". - // We will just use simple affix comparison (look for exact match) - // to pass it. - // - // TODO: We should parse against simple affix first when - // output currency is not requested. After the complex currency - // parsing implementation was introduced, the default currency - // instance parsing slowed down because of the new code flow. - // I filed #10312 - Yoshito - UBool tmpStatus_2[fgStatusLength]; - ParsePosition tmpPos_2(origPos); - DigitList tmpDigitList_2; - - // Disable complex currency parsing and try it again. - UBool result = subparse(text, - &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(), - &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(), - &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(), - &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(), - FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME, - tmpPos_2, tmpDigitList_2, tmpStatus_2, - currency); - if (result) { - if (tmpPos_2.getIndex() > maxPosIndex) { - maxPosIndex = tmpPos_2.getIndex(); - for (int32_t i = 0; i < fgStatusLength; ++i) { - status[i] = tmpStatus_2[i]; - } - digits = tmpDigitList_2; - } - found = true; - } else { - maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ? - tmpPos_2.getErrorIndex() : maxErrorPos; + fields->properties.adoptInstead(new DecimalFormatProperties(*source.fields->properties)); + fields->symbols.adoptInstead(new DecimalFormatSymbols(*source.fields->symbols)); + fields->exportedProperties.adoptInstead(new DecimalFormatProperties()); + if (fields->properties == nullptr || fields->symbols == nullptr || fields->exportedProperties == nullptr) { + return; } + touchNoError(); +} - if (!found) { - //parsePosition.setIndex(origPos); - parsePosition.setErrorIndex(maxErrorPos); - } else { - parsePosition.setIndex(maxPosIndex); - parsePosition.setErrorIndex(-1); - } - return found; -} - - -/** - * Parse the given text into a number. The text is parsed beginning at - * parsePosition, until an unparseable character is seen. - * @param text the string to parse. - * @param negPrefix negative prefix. - * @param negSuffix negative suffix. - * @param posPrefix positive prefix. - * @param posSuffix positive suffix. - * @param complexCurrencyParsing whether it is complex currency parsing or not. - * @param type the currency type to parse against, LONG_NAME only or not. - * @param parsePosition The position at which to being parsing. Upon - * return, the first unparsed character. - * @param digits the DigitList to set to the parsed value. - * @param status output param containing boolean status flags indicating - * whether the value was infinite and whether it was positive. - * @param currency return value for parsed currency, for generic - * currency parsing mode, or NULL for normal parsing. In generic - * currency parsing mode, any currency is parsed, not just the - * currency that this formatter is set to. - */ -UBool DecimalFormat::subparse(const UnicodeString& text, - const UnicodeString* negPrefix, - const UnicodeString* negSuffix, - const UnicodeString* posPrefix, - const UnicodeString* posSuffix, - UBool complexCurrencyParsing, - int8_t type, - ParsePosition& parsePosition, - DigitList& digits, UBool* status, - UChar* currency) const -{ - // The parsing process builds up the number as char string, in the neutral format that - // will be acceptable to the decNumber library, then at the end passes that string - // off for conversion to a decNumber. - UErrorCode err = U_ZERO_ERROR; - CharString parsedNum; - digits.setToZero(); - - int32_t position = parsePosition.getIndex(); - int32_t oldStart = position; - int32_t textLength = text.length(); // One less pointer to follow - UBool strictParse = !isLenient(); - UChar32 zero = fImpl->getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0); - const UnicodeString *groupingString = &fImpl->getConstSymbol( - !fImpl->fMonetary ? - DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); - UChar32 groupingChar = groupingString->char32At(0); - int32_t groupingStringLength = groupingString->length(); - int32_t groupingCharLength = U16_LENGTH(groupingChar); - UBool groupingUsed = isGroupingUsed(); -#ifdef FMT_DEBUG - UChar dbgbuf[300]; - UnicodeString s(dbgbuf,0,300);; - s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " ); -#define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "=")); if(x->isEmpty()) { s.append(UnicodeString("")); } else { s.append(*x); } s.append(UnicodeString(" ")); } else { s.append(UnicodeString(#x "=NULL ")); } - DBGAPPD(negPrefix); - DBGAPPD(negSuffix); - DBGAPPD(posPrefix); - DBGAPPD(posSuffix); - debugout(s); -#endif - - UBool fastParseOk = false; /* TRUE iff fast parse is OK */ - // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */ - if((fImpl->isParseFastpath()) && !fImpl->fMonetary && - text.length()>0 && - text.length()<32 && - (posPrefix==NULL||posPrefix->isEmpty()) && - (posSuffix==NULL||posSuffix->isEmpty()) && - // (negPrefix==NULL||negPrefix->isEmpty()) && - // (negSuffix==NULL||(negSuffix->isEmpty()) ) && - TRUE) { // optimized path - int j=position; - int l=text.length(); - int digitCount=0; - UChar32 ch = text.char32At(j); - const UnicodeString *decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); - UChar32 decimalChar = 0; - UBool intOnly = FALSE; - UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0; - - int32_t decimalCount = decimalString->countChar32(0,3); - if(isParseIntegerOnly()) { - decimalChar = 0; // not allowed - intOnly = TRUE; // Don't look for decimals. - } else if(decimalCount==1) { - decimalChar = decimalString->char32At(0); // Look for this decimal - } else if(decimalCount==0) { - decimalChar=0; // NO decimal set - } else { - j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation. - } - -#ifdef FMT_DEBUG - printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n", - decimalChar, groupingChar, ch, - (intOnly)?'y':'n', - (strictParse)?'y':'n'); -#endif - if(ch==0x002D) { // '-' - j=l+1;//=break - negative number. - - /* - parsedNum.append('-',err); - j+=U16_LENGTH(ch); - if(j=0 && digit <= 9) { - parsedNum.append((char)(digit + '0'), err); - if((digitCount>0) || digit!=0 || j==(l-1)) { - digitCount++; - } - } else if(ch == 0) { // break out - digitCount=-1; - break; - } else if(ch == decimalChar) { - parsedNum.append((char)('.'), err); - decimalChar=0; // no more decimals. - // fastParseHadDecimal=TRUE; - } else if(ch == lookForGroup) { - // ignore grouping char. No decimals, so it has to be an ignorable grouping sep - } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) { - // parsing integer only and can fall through - } else { - digitCount=-1; // fail - fall through to slow parse - break; - } - j+=U16_LENGTH(ch); - ch = text.char32At(j); // for next - } - if( - ((j==l)||intOnly) // end OR only parsing integer - && (digitCount>0)) { // and have at least one digit - fastParseOk=true; // Fast parse OK! - -#ifdef SKIP_OPT - debug("SKIP_OPT"); - /* for testing, try it the slow way. also */ - fastParseOk=false; - parsedNum.clear(); -#else - parsePosition.setIndex(position=j); - status[fgStatusInfinite]=false; -#endif - } else { - // was not OK. reset, retry -#ifdef FMT_DEBUG - printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount); -#endif - parsedNum.clear(); - } - } else { -#ifdef FMT_DEBUG - printf("Could not fastpath parse. "); - printf("text.length()=%d ", text.length()); - printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix); +DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) { + *fields->properties = *rhs.fields->properties; + fields->exportedProperties->clear(); + fields->symbols.adoptInstead(new DecimalFormatSymbols(*rhs.fields->symbols)); + touchNoError(); + return *this; +} - printf("\n"); -#endif - } +DecimalFormat::~DecimalFormat() { + delete fields->atomicParser.exchange(nullptr); + delete fields->atomicCurrencyParser.exchange(nullptr); + delete fields; +} - UnicodeString formatPattern; - toPattern(formatPattern); +Format* DecimalFormat::clone() const { + return new DecimalFormat(*this); +} - if(!fastParseOk -#if UCONFIG_HAVE_PARSEALLINPUT - && fParseAllInput!=UNUM_YES -#endif - ) - { - int32_t formatWidth = fImpl->getOldFormatWidth(); - // Match padding before prefix - if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) { - position = skipPadding(text, position); - } - - // Match positive and negative prefixes; prefer longest match. - int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency); - int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, complexCurrencyParsing, type, currency); - if (posMatch >= 0 && negMatch >= 0) { - if (posMatch > negMatch) { - negMatch = -1; - } else if (negMatch > posMatch) { - posMatch = -1; - } - } - if (posMatch >= 0) { - position += posMatch; - parsedNum.append('+', err); - } else if (negMatch >= 0) { - position += negMatch; - parsedNum.append('-', err); - } else if (strictParse){ - parsePosition.setErrorIndex(position); - return FALSE; - } else { - // Temporary set positive. This might be changed after checking suffix - parsedNum.append('+', err); +UBool DecimalFormat::operator==(const Format& other) const { + auto* otherDF = dynamic_cast(&other); + if (otherDF == nullptr) { + return false; } + return *fields->properties == *otherDF->fields->properties && *fields->symbols == *otherDF->fields->symbols; +} - // Match padding before prefix - if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) { - position = skipPadding(text, position); +UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const { + if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) { + return appendTo; } + UErrorCode localStatus = U_ZERO_ERROR; + FormattedNumber output = fields->formatter->formatDouble(number, localStatus); + fieldPositionHelper(output, pos, appendTo.length(), localStatus); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} - if (! strictParse) { - position = skipUWhiteSpace(text, position); +UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const { + if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) { + return appendTo; } + FormattedNumber output = fields->formatter->formatDouble(number, status); + fieldPositionHelper(output, pos, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} - // process digits or Inf, find decimal position - const UnicodeString *inf = &fImpl->getConstSymbol(DecimalFormatSymbols::kInfinitySymbol); - int32_t infLen = (text.compare(position, inf->length(), *inf) - ? 0 : inf->length()); - position += infLen; // infLen is non-zero when it does equal to infinity - status[fgStatusInfinite] = infLen != 0; - - if (infLen != 0) { - parsedNum.append("Infinity", err); - } else { - // We now have a string of digits, possibly with grouping symbols, - // and decimal points. We want to process these into a DigitList. - // We don't want to put a bunch of leading zeros into the DigitList - // though, so we keep track of the location of the decimal point, - // put only significant digits into the DigitList, and adjust the - // exponent as needed. - - - UBool strictFail = FALSE; // did we exit with a strict parse failure? - int32_t lastGroup = -1; // after which digit index did we last see a grouping separator? - int32_t currGroup = -1; // for temporary storage the digit index of the current grouping separator - int32_t gs2 = fImpl->fEffGrouping.fGrouping2 == 0 ? fImpl->fEffGrouping.fGrouping : fImpl->fEffGrouping.fGrouping2; - - const UnicodeString *decimalString; - if (fImpl->fMonetary) { - decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); - } else { - decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); - } - UChar32 decimalChar = decimalString->char32At(0); - int32_t decimalStringLength = decimalString->length(); - int32_t decimalCharLength = U16_LENGTH(decimalChar); - - UBool sawDecimal = FALSE; - UChar32 sawDecimalChar = 0xFFFF; - UBool sawGrouping = FALSE; - UChar32 sawGroupingChar = 0xFFFF; - UBool sawDigit = FALSE; - int32_t backup = -1; - int32_t digit; - - // equivalent grouping and decimal support - const UnicodeSet *decimalSet = NULL; - const UnicodeSet *groupingSet = NULL; - - if (decimalCharLength == decimalStringLength) { - decimalSet = DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse); - } - - if (groupingCharLength == groupingStringLength) { - if (strictParse) { - groupingSet = fStaticSets->fStrictDefaultGroupingSeparators; - } else { - groupingSet = fStaticSets->fDefaultGroupingSeparators; - } - } - - // We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized. - // If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet - // If a character matches decimalSet, don't consider it to be a member of the groupingSet. - - // We have to track digitCount ourselves, because digits.fCount will - // pin when the maximum allowable digits is reached. - int32_t digitCount = 0; - int32_t integerDigitCount = 0; - - for (; position < textLength; ) - { - UChar32 ch = text.char32At(position); - - /* We recognize all digit ranges, not only the Latin digit range - * '0'..'9'. We do so by using the Character.digit() method, - * which converts a valid Unicode digit to the range 0..9. - * - * The character 'ch' may be a digit. If so, place its value - * from 0 to 9 in 'digit'. First try using the locale digit, - * which may or MAY NOT be a standard Unicode digit range. If - * this fails, try using the standard Unicode digit ranges by - * calling Character.digit(). If this also fails, digit will - * have a value outside the range 0..9. - */ - digit = ch - zero; - if (digit < 0 || digit > 9) - { - digit = u_charDigitValue(ch); - } - - // As a last resort, look through the localized digits if the zero digit - // is not a "standard" Unicode digit. - if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) { - digit = 0; - if ( fImpl->getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kZeroDigitSymbol)).char32At(0) == ch ) { - break; - } - for (digit = 1 ; digit < 10 ; digit++ ) { - if ( fImpl->getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) { - break; - } - } - } - - if (digit >= 0 && digit <= 9) - { - if (strictParse && backup != -1) { - // comma followed by digit, so group before comma is a - // secondary group. If there was a group separator - // before that, the group must == the secondary group - // length, else it can be <= the the secondary group - // length. - if ((lastGroup != -1 && currGroup - lastGroup != gs2) || - (lastGroup == -1 && digitCount - 1 > gs2)) { - strictFail = TRUE; - break; - } - - lastGroup = currGroup; - } - - // Cancel out backup setting (see grouping handler below) - currGroup = -1; - backup = -1; - sawDigit = TRUE; - - // Note: this will append leading zeros - parsedNum.append((char)(digit + '0'), err); - - // count any digit that's not a leading zero - if (digit > 0 || digitCount > 0 || sawDecimal) { - digitCount += 1; - - // count any integer digit that's not a leading zero - if (! sawDecimal) { - integerDigitCount += 1; - } - } - - position += U16_LENGTH(ch); - } - else if (groupingStringLength > 0 && - matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet, - decimalChar, decimalSet, - ch) && groupingUsed) - { - if (sawDecimal) { - break; - } - - if (strictParse) { - if ((!sawDigit || backup != -1)) { - // leading group, or two group separators in a row - strictFail = TRUE; - break; - } - } - - // Ignore grouping characters, if we are using them, but require - // that they be followed by a digit. Otherwise we backup and - // reprocess them. - currGroup = digitCount; - backup = position; - position += groupingStringLength; - sawGrouping=TRUE; - // Once we see a grouping character, we only accept that grouping character from then on. - sawGroupingChar=ch; - } - else if (matchDecimal(decimalChar,sawDecimal,sawDecimalChar, decimalSet, ch)) - { - if (strictParse) { - if (backup != -1 || - (lastGroup != -1 && digitCount - lastGroup != fImpl->fEffGrouping.fGrouping)) { - strictFail = TRUE; - break; - } - } - - // If we're only parsing integers, or if we ALREADY saw the - // decimal, then don't parse this one. - if (isParseIntegerOnly() || sawDecimal) { - break; - } - - parsedNum.append('.', err); - position += decimalStringLength; - sawDecimal = TRUE; - // Once we see a decimal character, we only accept that decimal character from then on. - sawDecimalChar=ch; - // decimalSet is considered to consist of (ch,ch) - } - else { - - if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless.. - isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways - const UnicodeString *tmp; - tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); - // TODO: CASE - if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit - { - // Parse sign, if present - int32_t pos = position + tmp->length(); - char exponentSign = '+'; - - if (pos < textLength) - { - tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); - if (!text.compare(pos, tmp->length(), *tmp)) - { - pos += tmp->length(); - } - else { - tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); - if (!text.compare(pos, tmp->length(), *tmp)) - { - exponentSign = '-'; - pos += tmp->length(); - } - } - } - - UBool sawExponentDigit = FALSE; - while (pos < textLength) { - ch = text.char32At(pos); - digit = ch - zero; - - if (digit < 0 || digit > 9) { - digit = u_charDigitValue(ch); - } - if (0 <= digit && digit <= 9) { - if (!sawExponentDigit) { - parsedNum.append('E', err); - parsedNum.append(exponentSign, err); - sawExponentDigit = TRUE; - } - pos += U16_LENGTH(ch); - parsedNum.append((char)(digit + '0'), err); - } else { - break; - } - } - - if (sawExponentDigit) { - position = pos; // Advance past the exponent - } - - break; // Whether we fail or succeed, we exit this loop - } else { - break; - } - } else { // not parsing exponent - break; - } - } - } - - // if we didn't see a decimal and it is required, check to see if the pattern had one - if(!sawDecimal && isDecimalPatternMatchRequired()) - { - if(formatPattern.indexOf(kPatternDecimalSeparator) != -1) - { - parsePosition.setIndex(oldStart); - parsePosition.setErrorIndex(position); - debug("decimal point match required fail!"); - return FALSE; - } - } - - if (backup != -1) - { - position = backup; - } - - if (strictParse && !sawDecimal) { - if (lastGroup != -1 && digitCount - lastGroup != fImpl->fEffGrouping.fGrouping) { - strictFail = TRUE; - } - } +UnicodeString& +DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const { + if (posIter == nullptr && fastFormatDouble(number, appendTo)) { + return appendTo; + } + FormattedNumber output = fields->formatter->formatDouble(number, status); + fieldPositionIteratorHelper(output, posIter, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} - if (strictFail) { - // only set with strictParse and a grouping separator error +UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const { + return format(static_cast (number), appendTo, pos); +} - parsePosition.setIndex(oldStart); - parsePosition.setErrorIndex(position); - debug("strictFail!"); - return FALSE; - } +UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const { + return format(static_cast (number), appendTo, pos, status); +} - // If there was no decimal point we have an integer +UnicodeString& +DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const { + return format(static_cast (number), appendTo, posIter, status); +} - // If none of the text string was recognized. For example, parse - // "x" with pattern "#0.00" (return index and error index both 0) - // parse "$" with pattern "$#0.00". (return index 0 and error index - // 1). - if (!sawDigit && digitCount == 0) { -#ifdef FMT_DEBUG - debug("none of text rec"); - printf("position=%d\n",position); -#endif - parsePosition.setIndex(oldStart); - parsePosition.setErrorIndex(oldStart); - return FALSE; - } +UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const { + if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) { + return appendTo; } + UErrorCode localStatus = U_ZERO_ERROR; + FormattedNumber output = fields->formatter->formatInt(number, localStatus); + fieldPositionHelper(output, pos, appendTo.length(), localStatus); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} - // Match padding before suffix - if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) { - position = skipPadding(text, position); +UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const { + if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) { + return appendTo; } + FormattedNumber output = fields->formatter->formatInt(number, status); + fieldPositionHelper(output, pos, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} - int32_t posSuffixMatch = -1, negSuffixMatch = -1; - - // Match positive and negative suffixes; prefer longest match. - if (posMatch >= 0 || (!strictParse && negMatch < 0)) { - posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency); - } - if (negMatch >= 0) { - negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency); - } - if (posSuffixMatch >= 0 && negSuffixMatch >= 0) { - if (posSuffixMatch > negSuffixMatch) { - negSuffixMatch = -1; - } else if (negSuffixMatch > posSuffixMatch) { - posSuffixMatch = -1; - } +UnicodeString& +DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const { + if (posIter == nullptr && fastFormatInt64(number, appendTo)) { + return appendTo; } + FormattedNumber output = fields->formatter->formatInt(number, status); + fieldPositionIteratorHelper(output, posIter, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} - // Fail if neither or both - if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) { - parsePosition.setErrorIndex(position); - debug("neither or both"); - return FALSE; - } +UnicodeString& +DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const { + FormattedNumber output = fields->formatter->formatDecimal(number, status); + fieldPositionIteratorHelper(output, posIter, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} - position += (posSuffixMatch >= 0 ? posSuffixMatch : (negSuffixMatch >= 0 ? negSuffixMatch : 0)); +UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, + FieldPositionIterator* posIter, UErrorCode& status) const { + FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status); + fieldPositionIteratorHelper(output, posIter, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} - // Match padding before suffix - if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) { - position = skipPadding(text, position); +UnicodeString& +DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const { + FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status); + fieldPositionHelper(output, pos, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +void DecimalFormat::parse(const UnicodeString& text, Formattable& output, + ParsePosition& parsePosition) const { + if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) { + return; } - parsePosition.setIndex(position); - - parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-'; -#ifdef FMT_DEBUG -printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err)); -#endif - } /* end SLOW parse */ - if(parsePosition.getIndex() == oldStart) - { -#ifdef FMT_DEBUG - printf(" PP didnt move, err\n"); -#endif - parsePosition.setErrorIndex(position); - return FALSE; - } -#if UCONFIG_HAVE_PARSEALLINPUT - else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength) - { -#ifdef FMT_DEBUG - printf(" PP didnt consume all (UNUM_YES), err\n"); -#endif - parsePosition.setErrorIndex(position); - return FALSE; - } -#endif - // uint32_t bits = (fastParseOk?kFastpathOk:0) | - // (fastParseHadDecimal?0:kNoDecimal); - //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits); - digits.set(parsedNum.toStringPiece(), - err, - 0//bits - ); - - if (U_FAILURE(err)) { -#ifdef FMT_DEBUG - printf(" err setting %s\n", u_errorName(err)); -#endif - parsePosition.setErrorIndex(position); - return FALSE; - } - - // check if we missed a required decimal point - if(fastParseOk && isDecimalPatternMatchRequired()) - { - if(formatPattern.indexOf(kPatternDecimalSeparator) != -1) - { - parsePosition.setIndex(oldStart); - parsePosition.setErrorIndex(position); - debug("decimal point match required fail!"); - return FALSE; - } + ErrorCode status; + ParsedNumber result; + // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the + // parseCurrency method (backwards compatibility) + int32_t startIndex = parsePosition.getIndex(); + const NumberParserImpl* parser = getParser(status); + if (U_FAILURE(status)) { return; } + parser->parse(text, startIndex, true, result, status); + // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here? + if (result.success()) { + parsePosition.setIndex(result.charEnd); + result.populateFormattable(output, parser->getParseFlags()); + } else { + parsePosition.setErrorIndex(startIndex + result.charEnd); } +} - - return TRUE; -} - -/** - * Starting at position, advance past a run of pad characters, if any. - * Return the index of the first character after position that is not a pad - * character. Result is >= position. - */ -int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) const { - int32_t padLen = U16_LENGTH(fImpl->fAffixes.fPadChar); - while (position < text.length() && - text.char32At(position) == fImpl->fAffixes.fPadChar) { - position += padLen; - } - return position; -} - -/** - * Return the length matched by the given affix, or -1 if none. - * Runs of white space in the affix, match runs of white space in - * the input. Pattern white space and input white space are - * determined differently; see code. - * @param text input text - * @param pos offset into input at which to begin matching - * @param isNegative - * @param isPrefix - * @param affixPat affix pattern used for currency affix comparison. - * @param complexCurrencyParsing whether it is currency parsing or not - * @param type the currency type to parse against, LONG_NAME only or not. - * @param currency return value for parsed currency, for generic - * currency parsing mode, or null for normal parsing. In generic - * currency parsing mode, any currency is parsed, not just the - * currency that this formatter is set to. - * @return length of input that matches, or -1 if match failure - */ -int32_t DecimalFormat::compareAffix(const UnicodeString& text, - int32_t pos, - UBool isNegative, - UBool isPrefix, - const UnicodeString* affixPat, - UBool complexCurrencyParsing, - int8_t type, - UChar* currency) const -{ - const UnicodeString *patternToCompare; - if (currency != NULL || - (fImpl->fMonetary && complexCurrencyParsing)) { - - if (affixPat != NULL) { - return compareComplexAffix(*affixPat, text, pos, type, currency); - } +CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& parsePosition) const { + if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) { + return nullptr; } - if (isNegative) { - if (isPrefix) { - patternToCompare = &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(); - } - else { - patternToCompare = &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(); - } - } - else { - if (isPrefix) { - patternToCompare = &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(); - } - else { - patternToCompare = &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(); - } + ErrorCode status; + ParsedNumber result; + // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the + // parseCurrency method (backwards compatibility) + int32_t startIndex = parsePosition.getIndex(); + const NumberParserImpl* parser = getCurrencyParser(status); + if (U_FAILURE(status)) { return nullptr; } + parser->parse(text, startIndex, true, result, status); + // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here? + if (result.success()) { + parsePosition.setIndex(result.charEnd); + Formattable formattable; + result.populateFormattable(formattable, parser->getParseFlags()); + return new CurrencyAmount(formattable, result.currencyCode, status); + } else { + parsePosition.setErrorIndex(startIndex + result.charEnd); + return nullptr; } - return compareSimpleAffix(*patternToCompare, text, pos, isLenient()); } -UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const { - if (lhs == rhs) { - return TRUE; - } - U_ASSERT(fStaticSets != NULL); // should already be loaded - const UnicodeSet *minusSigns = fStaticSets->fMinusSigns; - const UnicodeSet *plusSigns = fStaticSets->fPlusSigns; - return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) || - (plusSigns->contains(lhs) && plusSigns->contains(rhs)); +const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const { + return fields->symbols.getAlias(); } -// check for LRM 0x200E, RLM 0x200F, ALM 0x061C -#define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C) +void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) { + if (symbolsToAdopt == nullptr) { + return; // do not allow caller to set fields->symbols to NULL + } + fields->symbols.adoptInstead(symbolsToAdopt); + touchNoError(); +} -#define TRIM_BUFLEN 32 -UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) { - UChar trimBuf[TRIM_BUFLEN]; - int32_t affixLen = affix.length(); - int32_t affixPos, trimLen = 0; +void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) { + fields->symbols.adoptInstead(new DecimalFormatSymbols(symbols)); + touchNoError(); +} - for (affixPos = 0; affixPos < affixLen; affixPos++) { - UChar c = affix.charAt(affixPos); - if (!IS_BIDI_MARK(c)) { - if (trimLen < TRIM_BUFLEN) { - trimBuf[trimLen++] = c; - } else { - trimLen = 0; - break; - } - } - } - return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix); -} - -/** - * Return the length matched by the given affix, or -1 if none. - * Runs of white space in the affix, match runs of white space in - * the input. Pattern white space and input white space are - * determined differently; see code. - * @param affix pattern string, taken as a literal - * @param input input text - * @param pos offset into input at which to begin matching - * @return length of input that matches, or -1 if match failure - */ -int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix, - const UnicodeString& input, - int32_t pos, - UBool lenient) const { - int32_t start = pos; - UnicodeString trimmedAffix; - // For more efficiency we should keep lazily-created trimmed affixes around in - // instance variables instead of trimming each time they are used (the next step) - trimMarksFromAffix(affix, trimmedAffix); - UChar32 affixChar = trimmedAffix.char32At(0); - int32_t affixLength = trimmedAffix.length(); - int32_t inputLength = input.length(); - int32_t affixCharLength = U16_LENGTH(affixChar); - UnicodeSet *affixSet; - UErrorCode status = U_ZERO_ERROR; - - U_ASSERT(fStaticSets != NULL); // should already be loaded +const CurrencyPluralInfo* DecimalFormat::getCurrencyPluralInfo(void) const { + return fields->properties->currencyPluralInfo.fPtr.getAlias(); +} - if (U_FAILURE(status)) { - return -1; - } - if (!lenient) { - affixSet = fStaticSets->fStrictDashEquivalents; - - // If the trimmedAffix is exactly one character long and that character - // is in the dash set and the very next input character is also - // in the dash set, return a match. - if (affixCharLength == affixLength && affixSet->contains(affixChar)) { - UChar32 ic = input.char32At(pos); - if (affixSet->contains(ic)) { - pos += U16_LENGTH(ic); - pos = skipBidiMarks(input, pos); // skip any trailing bidi marks - return pos - start; - } - } +void DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) { + fields->properties->currencyPluralInfo.fPtr.adoptInstead(toAdopt); + touchNoError(); +} - for (int32_t i = 0; i < affixLength; ) { - UChar32 c = trimmedAffix.char32At(i); - int32_t len = U16_LENGTH(c); - if (PatternProps::isWhiteSpace(c)) { - // We may have a pattern like: \u200F \u0020 - // and input text like: \u200F \u0020 - // Note that U+200F and U+0020 are Pattern_White_Space but only - // U+0020 is UWhiteSpace. So we have to first do a direct - // match of the run of Pattern_White_Space in the pattern, - // then match any extra characters. - UBool literalMatch = FALSE; - while (pos < inputLength) { - UChar32 ic = input.char32At(pos); - if (ic == c) { - literalMatch = TRUE; - i += len; - pos += len; - if (i == affixLength) { - break; - } - c = trimmedAffix.char32At(i); - len = U16_LENGTH(c); - if (!PatternProps::isWhiteSpace(c)) { - break; - } - } else if (IS_BIDI_MARK(ic)) { - pos ++; // just skip over this input text - } else { - break; - } - } - - // Advance over run in pattern - i = skipPatternWhiteSpace(trimmedAffix, i); - - // Advance over run in input text - // Must see at least one white space char in input, - // unless we've already matched some characters literally. - int32_t s = pos; - pos = skipUWhiteSpace(input, pos); - if (pos == s && !literalMatch) { - return -1; - } - - // If we skip UWhiteSpace in the input text, we need to skip it in the pattern. - // Otherwise, the previous lines may have skipped over text (such as U+00A0) that - // is also in the trimmedAffix. - i = skipUWhiteSpace(trimmedAffix, i); - } else { - UBool match = FALSE; - while (pos < inputLength) { - UChar32 ic = input.char32At(pos); - if (!match && ic == c) { - i += len; - pos += len; - match = TRUE; - } else if (IS_BIDI_MARK(ic)) { - pos++; // just skip over this input text - } else { - break; - } - } - if (!match) { - return -1; - } - } - } +void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) { + if (fields->properties->currencyPluralInfo.fPtr.isNull()) { + fields->properties->currencyPluralInfo.fPtr.adoptInstead(info.clone()); } else { - UBool match = FALSE; + *fields->properties->currencyPluralInfo.fPtr = info; // copy-assignment operator + } + touchNoError(); +} - affixSet = fStaticSets->fDashEquivalents; +UnicodeString& DecimalFormat::getPositivePrefix(UnicodeString& result) const { + ErrorCode localStatus; + fields->formatter->getAffixImpl(true, false, result, localStatus); + return result; +} - if (affixCharLength == affixLength && affixSet->contains(affixChar)) { - pos = skipUWhiteSpaceAndMarks(input, pos); - UChar32 ic = input.char32At(pos); +void DecimalFormat::setPositivePrefix(const UnicodeString& newValue) { + if (newValue == fields->properties->positivePrefix) { return; } + fields->properties->positivePrefix = newValue; + touchNoError(); +} - if (affixSet->contains(ic)) { - pos += U16_LENGTH(ic); - pos = skipBidiMarks(input, pos); - return pos - start; - } - } +UnicodeString& DecimalFormat::getNegativePrefix(UnicodeString& result) const { + ErrorCode localStatus; + fields->formatter->getAffixImpl(true, true, result, localStatus); + return result; +} - for (int32_t i = 0; i < affixLength; ) - { - //i = skipRuleWhiteSpace(trimmedAffix, i); - i = skipUWhiteSpace(trimmedAffix, i); - pos = skipUWhiteSpaceAndMarks(input, pos); +void DecimalFormat::setNegativePrefix(const UnicodeString& newValue) { + if (newValue == fields->properties->negativePrefix) { return; } + fields->properties->negativePrefix = newValue; + touchNoError(); +} - if (i >= affixLength || pos >= inputLength) { - break; - } +UnicodeString& DecimalFormat::getPositiveSuffix(UnicodeString& result) const { + ErrorCode localStatus; + fields->formatter->getAffixImpl(false, false, result, localStatus); + return result; +} - UChar32 c = trimmedAffix.char32At(i); - UChar32 ic = input.char32At(pos); +void DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) { + if (newValue == fields->properties->positiveSuffix) { return; } + fields->properties->positiveSuffix = newValue; + touchNoError(); +} - if (!equalWithSignCompatibility(ic, c)) { - return -1; - } +UnicodeString& DecimalFormat::getNegativeSuffix(UnicodeString& result) const { + ErrorCode localStatus; + fields->formatter->getAffixImpl(false, true, result, localStatus); + return result; +} - match = TRUE; - i += U16_LENGTH(c); - pos += U16_LENGTH(ic); - pos = skipBidiMarks(input, pos); - } +void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) { + if (newValue == fields->properties->negativeSuffix) { return; } + fields->properties->negativeSuffix = newValue; + touchNoError(); +} - if (affixLength > 0 && ! match) { - return -1; - } - } - return pos - start; +UBool DecimalFormat::isSignAlwaysShown() const { + return fields->properties->signAlwaysShown; } -/** - * Skip over a run of zero or more Pattern_White_Space characters at - * pos in text. - */ -int32_t DecimalFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) { - const UChar* s = text.getBuffer(); - return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s); +void DecimalFormat::setSignAlwaysShown(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->signAlwaysShown) { return; } + fields->properties->signAlwaysShown = value; + touchNoError(); } -/** - * Skip over a run of zero or more isUWhiteSpace() characters at pos - * in text. - */ -int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) { - while (pos < text.length()) { - UChar32 c = text.char32At(pos); - if (!u_isUWhiteSpace(c)) { - break; - } - pos += U16_LENGTH(c); +int32_t DecimalFormat::getMultiplier(void) const { + if (fields->properties->multiplier != 1) { + return fields->properties->multiplier; + } else if (fields->properties->magnitudeMultiplier != 0) { + return static_cast(uprv_pow10(fields->properties->magnitudeMultiplier)); + } else { + return 1; } - return pos; } -/** - * Skip over a run of zero or more isUWhiteSpace() characters or bidi marks at pos - * in text. - */ -int32_t DecimalFormat::skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos) { - while (pos < text.length()) { - UChar32 c = text.char32At(pos); - if (!u_isUWhiteSpace(c) && !IS_BIDI_MARK(c)) { // u_isUWhiteSpace doesn't include LRM,RLM,ALM - break; - } - pos += U16_LENGTH(c); +void DecimalFormat::setMultiplier(int32_t multiplier) { + if (multiplier == 0) { + multiplier = 1; // one being the benign default value for a multiplier. } - return pos; -} -/** - * Skip over a run of zero or more bidi marks at pos in text. - */ -int32_t DecimalFormat::skipBidiMarks(const UnicodeString& text, int32_t pos) { - while (pos < text.length()) { - UChar c = text.charAt(pos); - if (!IS_BIDI_MARK(c)) { + // Try to convert to a magnitude multiplier first + int delta = 0; + int value = multiplier; + while (value != 1) { + delta++; + int temp = value / 10; + if (temp * 10 != value) { + delta = -1; break; } - pos++; - } - return pos; -} - -/** - * Return the length matched by the given affix, or -1 if none. - * @param affixPat pattern string - * @param input input text - * @param pos offset into input at which to begin matching - * @param type the currency type to parse against, LONG_NAME only or not. - * @param currency return value for parsed currency, for generic - * currency parsing mode, or null for normal parsing. In generic - * currency parsing mode, any currency is parsed, not just the - * currency that this formatter is set to. - * @return length of input that matches, or -1 if match failure - */ -int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat, - const UnicodeString& text, - int32_t pos, - int8_t type, - UChar* currency) const -{ - int32_t start = pos; - U_ASSERT(currency != NULL || fImpl->fMonetary); - - for (int32_t i=0; - i= 0; ) { - UChar32 c = affixPat.char32At(i); - i += U16_LENGTH(c); - - if (c == kQuote) { - U_ASSERT(i <= affixPat.length()); - c = affixPat.char32At(i); - i += U16_LENGTH(c); - - const UnicodeString* affix = NULL; - - switch (c) { - case kCurrencySign: { - // since the currency names in choice format is saved - // the same way as other currency names, - // do not need to do currency choice parsing here. - // the general currency parsing parse against all names, - // including names in choice format. - UBool intl = igetLocale().getName(); - ParsePosition ppos(pos); - UChar curr[4]; - UErrorCode ec = U_ZERO_ERROR; - // Delegate parse of display name => ISO code to Currency - uprv_parseCurrency(loc, text, ppos, type, curr, ec); - - // If parse succeeds, populate currency[0] - if (U_SUCCESS(ec) && ppos.getIndex() != pos) { - if (currency) { - u_strcpy(currency, curr); - } else { - // The formatter is currency-style but the client has not requested - // the value of the parsed currency. In this case, if that value does - // not match the formatter's current value, then the parse fails. - UChar effectiveCurr[4]; - getEffectiveCurrency(effectiveCurr, ec); - if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) { - pos = -1; - continue; - } - } - pos = ppos.getIndex(); - } else if (!isLenient()){ - pos = -1; - } - continue; - } - case kPatternPercent: - affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPercentSymbol); - break; - case kPatternPerMill: - affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); - break; - case kPatternPlus: - affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); - break; - case kPatternMinus: - affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); - break; - default: - // fall through to affix!=0 test, which will fail - break; - } - - if (affix != NULL) { - pos = match(text, pos, *affix); - continue; - } - } - - pos = match(text, pos, c); - if (PatternProps::isWhiteSpace(c)) { - i = skipPatternWhiteSpace(affixPat, i); - } + value = temp; } - return pos - start; -} - -/** - * Match a single character at text[pos] and return the index of the - * next character upon success. Return -1 on failure. If - * ch is a Pattern_White_Space then match a run of white space in text. - */ -int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) { - if (PatternProps::isWhiteSpace(ch)) { - // Advance over run of white space in input text - // Must see at least one white space char in input - int32_t s = pos; - pos = skipPatternWhiteSpace(text, pos); - if (pos == s) { - return -1; - } - return pos; - } - return (pos >= 0 && text.char32At(pos) == ch) ? - (pos + U16_LENGTH(ch)) : -1; -} - -/** - * Match a string at text[pos] and return the index of the next - * character upon success. Return -1 on failure. Match a run of - * white space in str with a run of white space in text. - */ -int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const UnicodeString& str) { - for (int32_t i=0; i= 0; ) { - UChar32 ch = str.char32At(i); - i += U16_LENGTH(ch); - if (PatternProps::isWhiteSpace(ch)) { - i = skipPatternWhiteSpace(str, i); - } - pos = match(text, pos, ch); - } - return pos; -} - -UBool DecimalFormat::matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol, - UnicodeSet *sset, UChar32 schar) -{ - if (sset != NULL) { - return sset->contains(schar); - } - - return text.compare(position, length, symbol) == 0; -} - -UBool DecimalFormat::matchDecimal(UChar32 symbolChar, - UBool sawDecimal, UChar32 sawDecimalChar, - const UnicodeSet *sset, UChar32 schar) { - if(sawDecimal) { - return schar==sawDecimalChar; - } else if(schar==symbolChar) { - return TRUE; - } else if(sset!=NULL) { - return sset->contains(schar); - } else { - return FALSE; - } -} - -UBool DecimalFormat::matchGrouping(UChar32 groupingChar, - UBool sawGrouping, UChar32 sawGroupingChar, - const UnicodeSet *sset, - UChar32 /*decimalChar*/, const UnicodeSet *decimalSet, - UChar32 schar) { - if(sawGrouping) { - return schar==sawGroupingChar; // previously found - } else if(schar==groupingChar) { - return TRUE; // char from symbols - } else if(sset!=NULL) { - return sset->contains(schar) && // in groupingSet but... - ((decimalSet==NULL) || !decimalSet->contains(schar)); // Exclude decimalSet from groupingSet + if (delta != -1) { + fields->properties->magnitudeMultiplier = delta; + fields->properties->multiplier = 1; } else { - return FALSE; + fields->properties->magnitudeMultiplier = 0; + fields->properties->multiplier = multiplier; } + touchNoError(); } +int32_t DecimalFormat::getMultiplierScale() const { + return fields->properties->multiplierScale; +} +void DecimalFormat::setMultiplierScale(int32_t newValue) { + if (newValue == fields->properties->multiplierScale) { return; } + fields->properties->multiplierScale = newValue; + touchNoError(); +} -//------------------------------------------------------------------------------ -// Gets the pointer to the localized decimal format symbols +double DecimalFormat::getRoundingIncrement(void) const { + return fields->exportedProperties->roundingIncrement; +} -const DecimalFormatSymbols* -DecimalFormat::getDecimalFormatSymbols() const -{ - return &fImpl->getDecimalFormatSymbols(); +void DecimalFormat::setRoundingIncrement(double newValue) { + if (newValue == fields->properties->roundingIncrement) { return; } + fields->properties->roundingIncrement = newValue; + touchNoError(); } -//------------------------------------------------------------------------------ -// De-owning the current localized symbols and adopt the new symbols. +ERoundingMode DecimalFormat::getRoundingMode(void) const { + // UNumberFormatRoundingMode and ERoundingMode have the same values. + return static_cast(fields->exportedProperties->roundingMode.getNoError()); +} -void -DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) -{ - if (symbolsToAdopt == NULL) { - return; // do not allow caller to set fSymbols to NULL +void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) { + auto uRoundingMode = static_cast(roundingMode); + if (!fields->properties->roundingMode.isNull() && uRoundingMode == fields->properties->roundingMode.getNoError()) { + return; } - fImpl->adoptDecimalFormatSymbols(symbolsToAdopt); + NumberFormat::setMaximumIntegerDigits(roundingMode); // to set field for compatibility + fields->properties->roundingMode = uRoundingMode; + touchNoError(); } -//------------------------------------------------------------------------------ -// Setting the symbols is equlivalent to adopting a newly created localized -// symbols. -void -DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) -{ - adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols)); +int32_t DecimalFormat::getFormatWidth(void) const { + return fields->properties->formatWidth; } - -const CurrencyPluralInfo* -DecimalFormat::getCurrencyPluralInfo(void) const -{ - return fCurrencyPluralInfo; +void DecimalFormat::setFormatWidth(int32_t width) { + if (width == fields->properties->formatWidth) { return; } + fields->properties->formatWidth = width; + touchNoError(); } - -void -DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) -{ - if (toAdopt != NULL) { - delete fCurrencyPluralInfo; - fCurrencyPluralInfo = toAdopt; - // re-set currency affix patterns and currency affixes. - if (fImpl->fMonetary) { - UErrorCode status = U_ZERO_ERROR; - if (fAffixPatternsForCurrency) { - deleteHashForAffixPattern(); - } - setupCurrencyAffixPatterns(status); - } +UnicodeString DecimalFormat::getPadCharacterString() const { + if (fields->properties->padString.isBogus()) { + // Readonly-alias the static string kFallbackPaddingString + return {TRUE, kFallbackPaddingString, -1}; + } else { + return fields->properties->padString; } } -void -DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) -{ - adoptCurrencyPluralInfo(info.clone()); +void DecimalFormat::setPadCharacter(const UnicodeString& padChar) { + if (padChar == fields->properties->padString) { return; } + if (padChar.length() > 0) { + fields->properties->padString = UnicodeString(padChar.char32At(0)); + } else { + fields->properties->padString.setToBogus(); + } + touchNoError(); } - -//------------------------------------------------------------------------------ -// Gets the positive prefix of the number pattern. - -UnicodeString& -DecimalFormat::getPositivePrefix(UnicodeString& result) const -{ - return fImpl->getPositivePrefix(result); +EPadPosition DecimalFormat::getPadPosition(void) const { + if (fields->properties->padPosition.isNull()) { + return EPadPosition::kPadBeforePrefix; + } else { + // UNumberFormatPadPosition and EPadPosition have the same values. + return static_cast(fields->properties->padPosition.getNoError()); + } } -//------------------------------------------------------------------------------ -// Sets the positive prefix of the number pattern. - -void -DecimalFormat::setPositivePrefix(const UnicodeString& newValue) -{ - fImpl->setPositivePrefix(newValue); +void DecimalFormat::setPadPosition(EPadPosition padPos) { + auto uPadPos = static_cast(padPos); + if (!fields->properties->padPosition.isNull() && uPadPos == fields->properties->padPosition.getNoError()) { + return; + } + fields->properties->padPosition = uPadPos; + touchNoError(); } -//------------------------------------------------------------------------------ -// Gets the negative prefix of the number pattern. - -UnicodeString& -DecimalFormat::getNegativePrefix(UnicodeString& result) const -{ - return fImpl->getNegativePrefix(result); +UBool DecimalFormat::isScientificNotation(void) const { + return fields->properties->minimumExponentDigits != -1; } -//------------------------------------------------------------------------------ -// Gets the negative prefix of the number pattern. - -void -DecimalFormat::setNegativePrefix(const UnicodeString& newValue) -{ - fImpl->setNegativePrefix(newValue); +void DecimalFormat::setScientificNotation(UBool useScientific) { + int32_t minExp = useScientific ? 1 : -1; + if (fields->properties->minimumExponentDigits == minExp) { return; } + if (useScientific) { + fields->properties->minimumExponentDigits = 1; + } else { + fields->properties->minimumExponentDigits = -1; + } + touchNoError(); } -//------------------------------------------------------------------------------ -// Gets the positive suffix of the number pattern. - -UnicodeString& -DecimalFormat::getPositiveSuffix(UnicodeString& result) const -{ - return fImpl->getPositiveSuffix(result); +int8_t DecimalFormat::getMinimumExponentDigits(void) const { + return static_cast(fields->properties->minimumExponentDigits); } -//------------------------------------------------------------------------------ -// Sets the positive suffix of the number pattern. - -void -DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) -{ - fImpl->setPositiveSuffix(newValue); +void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) { + if (minExpDig == fields->properties->minimumExponentDigits) { return; } + fields->properties->minimumExponentDigits = minExpDig; + touchNoError(); } -//------------------------------------------------------------------------------ -// Gets the negative suffix of the number pattern. - -UnicodeString& -DecimalFormat::getNegativeSuffix(UnicodeString& result) const -{ - return fImpl->getNegativeSuffix(result); +UBool DecimalFormat::isExponentSignAlwaysShown(void) const { + return fields->properties->exponentSignAlwaysShown; } -//------------------------------------------------------------------------------ -// Sets the negative suffix of the number pattern. - -void -DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) -{ - fImpl->setNegativeSuffix(newValue); +void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) { + if (UBOOL_TO_BOOL(expSignAlways) == fields->properties->exponentSignAlwaysShown) { return; } + fields->properties->exponentSignAlwaysShown = expSignAlways; + touchNoError(); } -//------------------------------------------------------------------------------ -// Gets the multiplier of the number pattern. -// Multipliers are stored as decimal numbers (DigitLists) because that -// is the most convenient for muliplying or dividing the numbers to be formatted. -// A NULL multiplier implies one, and the scaling operations are skipped. - -int32_t -DecimalFormat::getMultiplier() const -{ - return fImpl->getMultiplier(); +int32_t DecimalFormat::getGroupingSize(void) const { + if (fields->properties->groupingSize < 0) { + return 0; + } + return fields->properties->groupingSize; } -//------------------------------------------------------------------------------ -// Sets the multiplier of the number pattern. -void -DecimalFormat::setMultiplier(int32_t newValue) -{ - fImpl->setMultiplier(newValue); -} - -/** - * Get the rounding increment. - * @return A positive rounding increment, or 0.0 if rounding - * is not in effect. - * @see #setRoundingIncrement - * @see #getRoundingMode - * @see #setRoundingMode - */ -double DecimalFormat::getRoundingIncrement() const { - return fImpl->getRoundingIncrement(); -} - -/** - * Set the rounding increment. This method also controls whether - * rounding is enabled. - * @param newValue A positive rounding increment, or 0.0 to disable rounding. - * Negative increments are equivalent to 0.0. - * @see #getRoundingIncrement - * @see #getRoundingMode - * @see #setRoundingMode - */ -void DecimalFormat::setRoundingIncrement(double newValue) { - fImpl->setRoundingIncrement(newValue); -} - -/** - * Get the rounding mode. - * @return A rounding mode - * @see #setRoundingIncrement - * @see #getRoundingIncrement - * @see #setRoundingMode - */ -DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const { - return fImpl->getRoundingMode(); -} - -/** - * Set the rounding mode. This has no effect unless the rounding - * increment is greater than zero. - * @param roundingMode A rounding mode - * @see #setRoundingIncrement - * @see #getRoundingIncrement - * @see #getRoundingMode - */ -void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) { - fImpl->setRoundingMode(roundingMode); -} - -/** - * Get the width to which the output of format() is padded. - * @return the format width, or zero if no padding is in effect - * @see #setFormatWidth - * @see #getPadCharacter - * @see #setPadCharacter - * @see #getPadPosition - * @see #setPadPosition - */ -int32_t DecimalFormat::getFormatWidth() const { - return fImpl->getFormatWidth(); -} - -/** - * Set the width to which the output of format() is padded. - * This method also controls whether padding is enabled. - * @param width the width to which to pad the result of - * format(), or zero to disable padding. A negative - * width is equivalent to 0. - * @see #getFormatWidth - * @see #getPadCharacter - * @see #setPadCharacter - * @see #getPadPosition - * @see #setPadPosition - */ -void DecimalFormat::setFormatWidth(int32_t width) { - int32_t formatWidth = (width > 0) ? width : 0; - fImpl->setFormatWidth(formatWidth); +void DecimalFormat::setGroupingSize(int32_t newValue) { + if (newValue == fields->properties->groupingSize) { return; } + fields->properties->groupingSize = newValue; + touchNoError(); } -UnicodeString DecimalFormat::getPadCharacterString() const { - return UnicodeString(fImpl->getPadCharacter()); +int32_t DecimalFormat::getSecondaryGroupingSize(void) const { + int grouping2 = fields->properties->secondaryGroupingSize; + if (grouping2 < 0) { + return 0; + } + return grouping2; } -void DecimalFormat::setPadCharacter(const UnicodeString &padChar) { - UChar32 pad; - if (padChar.length() > 0) { - pad = padChar.char32At(0); - } - else { - pad = kDefaultPad; - } - fImpl->setPadCharacter(pad); -} - -static DecimalFormat::EPadPosition fromPadPosition(DigitAffixesAndPadding::EPadPosition padPos) { - switch (padPos) { - case DigitAffixesAndPadding::kPadBeforePrefix: - return DecimalFormat::kPadBeforePrefix; - case DigitAffixesAndPadding::kPadAfterPrefix: - return DecimalFormat::kPadAfterPrefix; - case DigitAffixesAndPadding::kPadBeforeSuffix: - return DecimalFormat::kPadBeforeSuffix; - case DigitAffixesAndPadding::kPadAfterSuffix: - return DecimalFormat::kPadAfterSuffix; - default: - U_ASSERT(FALSE); - break; - } - return DecimalFormat::kPadBeforePrefix; -} - -/** - * Get the position at which padding will take place. This is the location - * at which padding will be inserted if the result of format() - * is shorter than the format width. - * @return the pad position, one of kPadBeforePrefix, - * kPadAfterPrefix, kPadBeforeSuffix, or - * kPadAfterSuffix. - * @see #setFormatWidth - * @see #getFormatWidth - * @see #setPadCharacter - * @see #getPadCharacter - * @see #setPadPosition - * @see #kPadBeforePrefix - * @see #kPadAfterPrefix - * @see #kPadBeforeSuffix - * @see #kPadAfterSuffix - */ -DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const { - return fromPadPosition(fImpl->getPadPosition()); -} - -static DigitAffixesAndPadding::EPadPosition toPadPosition(DecimalFormat::EPadPosition padPos) { - switch (padPos) { - case DecimalFormat::kPadBeforePrefix: - return DigitAffixesAndPadding::kPadBeforePrefix; - case DecimalFormat::kPadAfterPrefix: - return DigitAffixesAndPadding::kPadAfterPrefix; - case DecimalFormat::kPadBeforeSuffix: - return DigitAffixesAndPadding::kPadBeforeSuffix; - case DecimalFormat::kPadAfterSuffix: - return DigitAffixesAndPadding::kPadAfterSuffix; - default: - U_ASSERT(FALSE); - break; - } - return DigitAffixesAndPadding::kPadBeforePrefix; -} - -/** - * NEW - * Set the position at which padding will take place. This is the location - * at which padding will be inserted if the result of format() - * is shorter than the format width. This has no effect unless padding is - * enabled. - * @param padPos the pad position, one of kPadBeforePrefix, - * kPadAfterPrefix, kPadBeforeSuffix, or - * kPadAfterSuffix. - * @see #setFormatWidth - * @see #getFormatWidth - * @see #setPadCharacter - * @see #getPadCharacter - * @see #getPadPosition - * @see #kPadBeforePrefix - * @see #kPadAfterPrefix - * @see #kPadBeforeSuffix - * @see #kPadAfterSuffix - */ -void DecimalFormat::setPadPosition(EPadPosition padPos) { - fImpl->setPadPosition(toPadPosition(padPos)); -} - -/** - * Return whether or not scientific notation is used. - * @return TRUE if this object formats and parses scientific notation - * @see #setScientificNotation - * @see #getMinimumExponentDigits - * @see #setMinimumExponentDigits - * @see #isExponentSignAlwaysShown - * @see #setExponentSignAlwaysShown - */ -UBool DecimalFormat::isScientificNotation() const { - return fImpl->isScientificNotation(); -} - -/** - * Set whether or not scientific notation is used. - * @param useScientific TRUE if this object formats and parses scientific - * notation - * @see #isScientificNotation - * @see #getMinimumExponentDigits - * @see #setMinimumExponentDigits - * @see #isExponentSignAlwaysShown - * @see #setExponentSignAlwaysShown - */ -void DecimalFormat::setScientificNotation(UBool useScientific) { - fImpl->setScientificNotation(useScientific); -} - -/** - * Return the minimum exponent digits that will be shown. - * @return the minimum exponent digits that will be shown - * @see #setScientificNotation - * @see #isScientificNotation - * @see #setMinimumExponentDigits - * @see #isExponentSignAlwaysShown - * @see #setExponentSignAlwaysShown - */ -int8_t DecimalFormat::getMinimumExponentDigits() const { - return fImpl->getMinimumExponentDigits(); -} - -/** - * Set the minimum exponent digits that will be shown. This has no - * effect unless scientific notation is in use. - * @param minExpDig a value >= 1 indicating the fewest exponent digits - * that will be shown. Values less than 1 will be treated as 1. - * @see #setScientificNotation - * @see #isScientificNotation - * @see #getMinimumExponentDigits - * @see #isExponentSignAlwaysShown - * @see #setExponentSignAlwaysShown - */ -void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) { - int32_t minExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1); - fImpl->setMinimumExponentDigits(minExponentDigits); -} - -/** - * Return whether the exponent sign is always shown. - * @return TRUE if the exponent is always prefixed with either the - * localized minus sign or the localized plus sign, false if only negative - * exponents are prefixed with the localized minus sign. - * @see #setScientificNotation - * @see #isScientificNotation - * @see #setMinimumExponentDigits - * @see #getMinimumExponentDigits - * @see #setExponentSignAlwaysShown - */ -UBool DecimalFormat::isExponentSignAlwaysShown() const { - return fImpl->isExponentSignAlwaysShown(); -} - -/** - * Set whether the exponent sign is always shown. This has no effect - * unless scientific notation is in use. - * @param expSignAlways TRUE if the exponent is always prefixed with either - * the localized minus sign or the localized plus sign, false if only - * negative exponents are prefixed with the localized minus sign. - * @see #setScientificNotation - * @see #isScientificNotation - * @see #setMinimumExponentDigits - * @see #getMinimumExponentDigits - * @see #isExponentSignAlwaysShown - */ -void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) { - fImpl->setExponentSignAlwaysShown(expSignAlways); +void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) { + if (newValue == fields->properties->secondaryGroupingSize) { return; } + fields->properties->secondaryGroupingSize = newValue; + touchNoError(); } -//------------------------------------------------------------------------------ -// Gets the grouping size of the number pattern. For example, thousand or 10 -// thousand groupings. - -int32_t -DecimalFormat::getGroupingSize() const -{ - return fImpl->getGroupingSize(); +int32_t DecimalFormat::getMinimumGroupingDigits() const { + return fields->properties->minimumGroupingDigits; } -//------------------------------------------------------------------------------ -// Gets the grouping size of the number pattern. - -void -DecimalFormat::setGroupingSize(int32_t newValue) -{ - fImpl->setGroupingSize(newValue); +void DecimalFormat::setMinimumGroupingDigits(int32_t newValue) { + if (newValue == fields->properties->minimumGroupingDigits) { return; } + fields->properties->minimumGroupingDigits = newValue; + touchNoError(); } -//------------------------------------------------------------------------------ - -int32_t -DecimalFormat::getSecondaryGroupingSize() const -{ - return fImpl->getSecondaryGroupingSize(); +UBool DecimalFormat::isDecimalSeparatorAlwaysShown(void) const { + return fields->properties->decimalSeparatorAlwaysShown; } -//------------------------------------------------------------------------------ - -void -DecimalFormat::setSecondaryGroupingSize(int32_t newValue) -{ - fImpl->setSecondaryGroupingSize(newValue); +void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) { + if (UBOOL_TO_BOOL(newValue) == fields->properties->decimalSeparatorAlwaysShown) { return; } + fields->properties->decimalSeparatorAlwaysShown = newValue; + touchNoError(); } -//------------------------------------------------------------------------------ - -int32_t -DecimalFormat::getMinimumGroupingDigits() const -{ - return fImpl->getMinimumGroupingDigits(); +UBool DecimalFormat::isDecimalPatternMatchRequired(void) const { + return fields->properties->decimalPatternMatchRequired; } -//------------------------------------------------------------------------------ - -void -DecimalFormat::setMinimumGroupingDigits(int32_t newValue) -{ - fImpl->setMinimumGroupingDigits(newValue); +void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) { + if (UBOOL_TO_BOOL(newValue) == fields->properties->decimalPatternMatchRequired) { return; } + fields->properties->decimalPatternMatchRequired = newValue; + touchNoError(); } -//------------------------------------------------------------------------------ -// Checks if to show the decimal separator. - -UBool -DecimalFormat::isDecimalSeparatorAlwaysShown() const -{ - return fImpl->isDecimalSeparatorAlwaysShown(); +UBool DecimalFormat::isParseNoExponent() const { + return fields->properties->parseNoExponent; } -//------------------------------------------------------------------------------ -// Sets to always show the decimal separator. - -void -DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) -{ - fImpl->setDecimalSeparatorAlwaysShown(newValue); +void DecimalFormat::setParseNoExponent(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->parseNoExponent) { return; } + fields->properties->parseNoExponent = value; + touchNoError(); } -//------------------------------------------------------------------------------ -// Checks if decimal point pattern match is required -UBool -DecimalFormat::isDecimalPatternMatchRequired(void) const -{ - return static_cast(fBoolFlags.contains(UNUM_PARSE_DECIMAL_MARK_REQUIRED)); +UBool DecimalFormat::isParseCaseSensitive() const { + return fields->properties->parseCaseSensitive; } -//------------------------------------------------------------------------------ -// Checks if decimal point pattern match is required - -void -DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) -{ - fBoolFlags.set(UNUM_PARSE_DECIMAL_MARK_REQUIRED, newValue); +void DecimalFormat::setParseCaseSensitive(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->parseCaseSensitive) { return; } + fields->properties->parseCaseSensitive = value; + touchNoError(); } - -//------------------------------------------------------------------------------ -// Emits the pattern of this DecimalFormat instance. - -UnicodeString& -DecimalFormat::toPattern(UnicodeString& result) const -{ - return fImpl->toPattern(result); +UBool DecimalFormat::isFormatFailIfMoreThanMaxDigits() const { + return fields->properties->formatFailIfMoreThanMaxDigits; } -//------------------------------------------------------------------------------ -// Emits the localized pattern this DecimalFormat instance. - -UnicodeString& -DecimalFormat::toLocalizedPattern(UnicodeString& result) const -{ - // toLocalizedPattern is deprecated, so we just make it the same as - // toPattern. - return fImpl->toPattern(result); +void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->formatFailIfMoreThanMaxDigits) { return; } + fields->properties->formatFailIfMoreThanMaxDigits = value; + touchNoError(); } -//------------------------------------------------------------------------------ - -void -DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) -{ - if (pattern.indexOf(kCurrencySign) != -1) { - handleCurrencySignInPattern(status); +UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const { + // Pull some properties from exportedProperties and others from properties + // to keep affix patterns intact. In particular, pull rounding properties + // so that CurrencyUsage is reflected properly. + // TODO: Consider putting this logic in number_patternstring.cpp instead. + ErrorCode localStatus; + DecimalFormatProperties tprops(*fields->properties); + bool useCurrency = ((!tprops.currency.isNull()) || !tprops.currencyPluralInfo.fPtr.isNull() || + !tprops.currencyUsage.isNull() || AffixUtils::hasCurrencySymbols( + tprops.positivePrefixPattern, localStatus) || AffixUtils::hasCurrencySymbols( + tprops.positiveSuffixPattern, localStatus) || AffixUtils::hasCurrencySymbols( + tprops.negativePrefixPattern, localStatus) || AffixUtils::hasCurrencySymbols( + tprops.negativeSuffixPattern, localStatus)); + if (useCurrency) { + tprops.minimumFractionDigits = fields->exportedProperties->minimumFractionDigits; + tprops.maximumFractionDigits = fields->exportedProperties->maximumFractionDigits; + tprops.roundingIncrement = fields->exportedProperties->roundingIncrement; } - fImpl->applyPattern(pattern, status); + result = PatternStringUtils::propertiesToPatternString(tprops, localStatus); + return result; } -//------------------------------------------------------------------------------ +UnicodeString& DecimalFormat::toLocalizedPattern(UnicodeString& result) const { + ErrorCode localStatus; + result = toPattern(result); + result = PatternStringUtils::convertLocalized(result, *fields->symbols, true, localStatus); + return result; +} -void -DecimalFormat::applyPattern(const UnicodeString& pattern, - UParseError& parseError, - UErrorCode& status) -{ - if (pattern.indexOf(kCurrencySign) != -1) { - handleCurrencySignInPattern(status); - } - fImpl->applyPattern(pattern, parseError, status); +void DecimalFormat::applyPattern(const UnicodeString& pattern, UParseError&, UErrorCode& status) { + // TODO: What is parseError for? + applyPattern(pattern, status); } -//------------------------------------------------------------------------------ -void -DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status) -{ - if (pattern.indexOf(kCurrencySign) != -1) { - handleCurrencySignInPattern(status); - } - fImpl->applyLocalizedPattern(pattern, status); +void DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_NEVER, status); + touch(status); } -//------------------------------------------------------------------------------ +void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UParseError&, + UErrorCode& status) { + // TODO: What is parseError for? + applyLocalizedPattern(localizedPattern, status); +} -void -DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, - UParseError& parseError, - UErrorCode& status) -{ - if (pattern.indexOf(kCurrencySign) != -1) { - handleCurrencySignInPattern(status); +void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UErrorCode& status) { + if (U_SUCCESS(status)) { + UnicodeString pattern = PatternStringUtils::convertLocalized( + localizedPattern, *fields->symbols, false, status); + applyPattern(pattern, status); } - fImpl->applyLocalizedPattern(pattern, parseError, status); } -//------------------------------------------------------------------------------ - -/** - * Sets the maximum number of digits allowed in the integer portion of a - * number. - * @see NumberFormat#setMaximumIntegerDigits - */ void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { - newValue = _min(newValue, gDefaultMaxIntegerDigits); - NumberFormat::setMaximumIntegerDigits(newValue); - fImpl->updatePrecision(); + if (newValue == fields->properties->maximumIntegerDigits) { return; } + // For backwards compatibility, conflicting min/max need to keep the most recent setting. + int32_t min = fields->properties->minimumIntegerDigits; + if (min >= 0 && min > newValue) { + fields->properties->minimumIntegerDigits = newValue; + } + fields->properties->maximumIntegerDigits = newValue; + touchNoError(); } -/** - * Sets the minimum number of digits allowed in the integer portion of a - * number. This override limits the integer digit count to 309. - * @see NumberFormat#setMinimumIntegerDigits - */ void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) { - newValue = _min(newValue, kDoubleIntegerDigits); - NumberFormat::setMinimumIntegerDigits(newValue); - fImpl->updatePrecision(); + if (newValue == fields->properties->minimumIntegerDigits) { return; } + // For backwards compatibility, conflicting min/max need to keep the most recent setting. + int32_t max = fields->properties->maximumIntegerDigits; + if (max >= 0 && max < newValue) { + fields->properties->maximumIntegerDigits = newValue; + } + fields->properties->minimumIntegerDigits = newValue; + touchNoError(); } -/** - * Sets the maximum number of digits allowed in the fraction portion of a - * number. This override limits the fraction digit count to 340. - * @see NumberFormat#setMaximumFractionDigits - */ void DecimalFormat::setMaximumFractionDigits(int32_t newValue) { - newValue = _min(newValue, kDoubleFractionDigits); - NumberFormat::setMaximumFractionDigits(newValue); - fImpl->updatePrecision(); + if (newValue == fields->properties->maximumFractionDigits) { return; } + // For backwards compatibility, conflicting min/max need to keep the most recent setting. + int32_t min = fields->properties->minimumFractionDigits; + if (min >= 0 && min > newValue) { + fields->properties->minimumFractionDigits = newValue; + } + fields->properties->maximumFractionDigits = newValue; + touchNoError(); } -/** - * Sets the minimum number of digits allowed in the fraction portion of a - * number. This override limits the fraction digit count to 340. - * @see NumberFormat#setMinimumFractionDigits - */ void DecimalFormat::setMinimumFractionDigits(int32_t newValue) { - newValue = _min(newValue, kDoubleFractionDigits); - NumberFormat::setMinimumFractionDigits(newValue); - fImpl->updatePrecision(); + if (newValue == fields->properties->minimumFractionDigits) { return; } + // For backwards compatibility, conflicting min/max need to keep the most recent setting. + int32_t max = fields->properties->maximumFractionDigits; + if (max >= 0 && max < newValue) { + fields->properties->maximumFractionDigits = newValue; + } + fields->properties->minimumFractionDigits = newValue; + touchNoError(); } int32_t DecimalFormat::getMinimumSignificantDigits() const { - return fImpl->getMinimumSignificantDigits(); + return fields->exportedProperties->minimumSignificantDigits; } int32_t DecimalFormat::getMaximumSignificantDigits() const { - return fImpl->getMaximumSignificantDigits(); + return fields->exportedProperties->maximumSignificantDigits; } -void DecimalFormat::setMinimumSignificantDigits(int32_t min) { - if (min < 1) { - min = 1; +void DecimalFormat::setMinimumSignificantDigits(int32_t value) { + if (value == fields->properties->minimumSignificantDigits) { return; } + int32_t max = fields->properties->maximumSignificantDigits; + if (max >= 0 && max < value) { + fields->properties->maximumSignificantDigits = value; } - // pin max sig dig to >= min - int32_t max = _max(fImpl->fMaxSigDigits, min); - fImpl->setMinMaxSignificantDigits(min, max); + fields->properties->minimumSignificantDigits = value; + touchNoError(); } -void DecimalFormat::setMaximumSignificantDigits(int32_t max) { - if (max < 1) { - max = 1; +void DecimalFormat::setMaximumSignificantDigits(int32_t value) { + if (value == fields->properties->maximumSignificantDigits) { return; } + int32_t min = fields->properties->minimumSignificantDigits; + if (min >= 0 && min > value) { + fields->properties->minimumSignificantDigits = value; } - // pin min sig dig to 1..max - U_ASSERT(fImpl->fMinSigDigits >= 1); - int32_t min = _min(fImpl->fMinSigDigits, max); - fImpl->setMinMaxSignificantDigits(min, max); + fields->properties->maximumSignificantDigits = value; + touchNoError(); } UBool DecimalFormat::areSignificantDigitsUsed() const { - return fImpl->areSignificantDigitsUsed(); + return fields->properties->minimumSignificantDigits != -1 || fields->properties->maximumSignificantDigits != -1; } void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) { - fImpl->setSignificantDigitsUsed(useSignificantDigits); -} - -void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) { - // set the currency before compute affixes to get the right currency names - NumberFormat::setCurrency(theCurrency, ec); - fImpl->updateCurrency(ec); -} - -void DecimalFormat::setCurrencyUsage(UCurrencyUsage newContext, UErrorCode* ec){ - fImpl->setCurrencyUsage(newContext, *ec); -} - -UCurrencyUsage DecimalFormat::getCurrencyUsage() const { - return fImpl->getCurrencyUsage(); -} - -// Deprecated variant with no UErrorCode parameter -void DecimalFormat::setCurrency(const UChar* theCurrency) { - UErrorCode ec = U_ZERO_ERROR; - setCurrency(theCurrency, ec); + // These are the default values from the old implementation. + int32_t minSig = useSignificantDigits ? 1 : -1; + int32_t maxSig = useSignificantDigits ? 6 : -1; + if (fields->properties->minimumSignificantDigits == minSig && + fields->properties->maximumSignificantDigits == maxSig) { + return; + } + fields->properties->minimumSignificantDigits = minSig; + fields->properties->maximumSignificantDigits = maxSig; + touchNoError(); } -void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { - if (fImpl->fSymbols == NULL) { - ec = U_MEMORY_ALLOCATION_ERROR; +void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) { + CurrencyUnit currencyUnit(theCurrency, ec); + if (U_FAILURE(ec)) { return; } + if (!fields->properties->currency.isNull() && fields->properties->currency.getNoError() == currencyUnit) { return; } - ec = U_ZERO_ERROR; - const UChar* c = getCurrency(); - if (*c == 0) { - const UnicodeString &intl = - fImpl->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); - c = intl.getBuffer(); // ok for intl to go out of scope - } - u_strncpy(result, c, 3); - result[3] = 0; + NumberFormat::setCurrency(theCurrency, ec); // to set field for compatibility + fields->properties->currency = currencyUnit; + // TODO: Set values in fields->symbols, too? + touchNoError(); } -Hashtable* -DecimalFormat::initHashForAffixPattern(UErrorCode& status) { - if ( U_FAILURE(status) ) { - return NULL; - } - Hashtable* hTable; - if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - if ( U_FAILURE(status) ) { - delete hTable; - return NULL; - } - hTable->setValueComparator(decimfmtAffixPatternValueComparator); - return hTable; +void DecimalFormat::setCurrency(const char16_t* theCurrency) { + ErrorCode localStatus; + setCurrency(theCurrency, localStatus); } -void -DecimalFormat::deleteHashForAffixPattern() -{ - if ( fAffixPatternsForCurrency == NULL ) { +void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) { + if (U_FAILURE(*ec)) { return; } - int32_t pos = UHASH_FIRST; - const UHashElement* element = NULL; - while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) { - const UHashTok valueTok = element->value; - const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer; - delete value; + if (!fields->properties->currencyUsage.isNull() && newUsage == fields->properties->currencyUsage.getNoError()) { + return; } - delete fAffixPatternsForCurrency; - fAffixPatternsForCurrency = NULL; + fields->properties->currencyUsage = newUsage; + touch(*ec); } - -void -DecimalFormat::copyHashForAffixPattern(const Hashtable* source, - Hashtable* target, - UErrorCode& status) { - if ( U_FAILURE(status) ) { - return; - } - int32_t pos = UHASH_FIRST; - const UHashElement* element = NULL; - if ( source ) { - while ( (element = source->nextElement(pos)) != NULL ) { - const UHashTok keyTok = element->key; - const UnicodeString* key = (UnicodeString*)keyTok.pointer; - const UHashTok valueTok = element->value; - const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer; - AffixPatternsForCurrency* copy = new AffixPatternsForCurrency( - value->negPrefixPatternForCurrency, - value->negSuffixPatternForCurrency, - value->posPrefixPatternForCurrency, - value->posSuffixPatternForCurrency, - value->patternType); - target->put(UnicodeString(*key), copy, status); - if ( U_FAILURE(status) ) { - return; - } - } +UCurrencyUsage DecimalFormat::getCurrencyUsage() const { + // CurrencyUsage is not exported, so we have to get it from the input property bag. + // TODO: Should we export CurrencyUsage instead? + if (fields->properties->currencyUsage.isNull()) { + return UCURR_USAGE_STANDARD; } + return fields->properties->currencyUsage.getNoError(); } void -DecimalFormat::setGroupingUsed(UBool newValue) { - NumberFormat::setGroupingUsed(newValue); - fImpl->updateGrouping(); +DecimalFormat::formatToDecimalQuantity(double number, DecimalQuantity& output, UErrorCode& status) const { + fields->formatter->formatDouble(number, status).getDecimalQuantity(output, status); } -void -DecimalFormat::setParseIntegerOnly(UBool newValue) { - NumberFormat::setParseIntegerOnly(newValue); +void DecimalFormat::formatToDecimalQuantity(const Formattable& number, DecimalQuantity& output, + UErrorCode& status) const { + UFormattedNumberData obj; + number.populateDecimalQuantity(obj.quantity, status); + fields->formatter->formatImpl(&obj, status); + output = std::move(obj.quantity); } -void -DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) { - NumberFormat::setContext(value, status); +const number::LocalizedNumberFormatter& DecimalFormat::toNumberFormatter() const { + return *fields->formatter; } -DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr, - int32_t newValue, - UErrorCode &status) { - if(U_FAILURE(status)) return *this; - - switch(attr) { - case UNUM_LENIENT_PARSE: - setLenient(newValue!=0); - break; - - case UNUM_PARSE_INT_ONLY: - setParseIntegerOnly(newValue!=0); - break; - - case UNUM_GROUPING_USED: - setGroupingUsed(newValue!=0); - break; - - case UNUM_DECIMAL_ALWAYS_SHOWN: - setDecimalSeparatorAlwaysShown(newValue!=0); - break; - - case UNUM_MAX_INTEGER_DIGITS: - setMaximumIntegerDigits(newValue); - break; - - case UNUM_MIN_INTEGER_DIGITS: - setMinimumIntegerDigits(newValue); - break; - - case UNUM_INTEGER_DIGITS: - setMinimumIntegerDigits(newValue); - setMaximumIntegerDigits(newValue); - break; - - case UNUM_MAX_FRACTION_DIGITS: - setMaximumFractionDigits(newValue); - break; - - case UNUM_MIN_FRACTION_DIGITS: - setMinimumFractionDigits(newValue); - break; - - case UNUM_FRACTION_DIGITS: - setMinimumFractionDigits(newValue); - setMaximumFractionDigits(newValue); - break; - - case UNUM_SIGNIFICANT_DIGITS_USED: - setSignificantDigitsUsed(newValue!=0); - break; - - case UNUM_MAX_SIGNIFICANT_DIGITS: - setMaximumSignificantDigits(newValue); - break; - - case UNUM_MIN_SIGNIFICANT_DIGITS: - setMinimumSignificantDigits(newValue); - break; - - case UNUM_MULTIPLIER: - setMultiplier(newValue); - break; - - case UNUM_GROUPING_SIZE: - setGroupingSize(newValue); - break; - - case UNUM_ROUNDING_MODE: - setRoundingMode((DecimalFormat::ERoundingMode)newValue); - break; - - case UNUM_FORMAT_WIDTH: - setFormatWidth(newValue); - break; - - case UNUM_PADDING_POSITION: - /** The position at which padding will take place. */ - setPadPosition((DecimalFormat::EPadPosition)newValue); - break; - - case UNUM_SECONDARY_GROUPING_SIZE: - setSecondaryGroupingSize(newValue); - break; - -#if UCONFIG_HAVE_PARSEALLINPUT - case UNUM_PARSE_ALL_INPUT: - setParseAllInput((UNumberFormatAttributeValue)newValue); - break; -#endif +/** Rebuilds the formatter object from the property bag. */ +void DecimalFormat::touch(UErrorCode& status) { + if (fields->exportedProperties == nullptr) { + // fields->exportedProperties is null only when the formatter is not ready yet. + // The only time when this happens is during legacy deserialization. + return; + } - /* These are stored in fBoolFlags */ - case UNUM_PARSE_NO_EXPONENT: - case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: - case UNUM_PARSE_DECIMAL_MARK_REQUIRED: - if(!fBoolFlags.isValidValue(newValue)) { - status = U_ILLEGAL_ARGUMENT_ERROR; - } else { - if (attr == UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS) { - fImpl->setFailIfMoreThanMaxDigits((UBool) newValue); - } - fBoolFlags.set(attr, newValue); - } - break; + // In C++, fields->symbols is the source of truth for the locale. + Locale locale = fields->symbols->getLocale(); - case UNUM_SCALE: - fImpl->setScale(newValue); - break; + // Note: The formatter is relatively cheap to create, and we need it to populate fields->exportedProperties, + // so automatically compute it here. The parser is a bit more expensive and is not needed until the + // parse method is called, so defer that until needed. + // TODO: Only update the pieces that changed instead of re-computing the whole formatter? + fields->formatter.adoptInstead( + new LocalizedNumberFormatter( + NumberPropertyMapper::create( + *fields->properties, *fields->symbols, fields->warehouse, *fields->exportedProperties, status).locale( + locale))); - case UNUM_CURRENCY_USAGE: - setCurrencyUsage((UCurrencyUsage)newValue, &status); - break; + // Do this after fields->exportedProperties are set up + setupFastFormat(); - case UNUM_MINIMUM_GROUPING_DIGITS: - setMinimumGroupingDigits(newValue); - break; + // Delete the parsers if they were made previously + delete fields->atomicParser.exchange(nullptr); + delete fields->atomicCurrencyParser.exchange(nullptr); - default: - status = U_UNSUPPORTED_ERROR; - break; - } - return *this; + // In order for the getters to work, we need to populate some fields in NumberFormat. + NumberFormat::setCurrency(fields->exportedProperties->currency.get(status).getISOCurrency(), status); + NumberFormat::setMaximumIntegerDigits(fields->exportedProperties->maximumIntegerDigits); + NumberFormat::setMinimumIntegerDigits(fields->exportedProperties->minimumIntegerDigits); + NumberFormat::setMaximumFractionDigits(fields->exportedProperties->maximumFractionDigits); + NumberFormat::setMinimumFractionDigits(fields->exportedProperties->minimumFractionDigits); + // fImpl->properties, not fields->exportedProperties, since this information comes from the pattern: + NumberFormat::setGroupingUsed(fields->properties->groupingUsed); } -int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr, - UErrorCode &status ) const { - if(U_FAILURE(status)) return -1; - switch(attr) { - case UNUM_LENIENT_PARSE: - return isLenient(); - - case UNUM_PARSE_INT_ONLY: - return isParseIntegerOnly(); - - case UNUM_GROUPING_USED: - return isGroupingUsed(); - - case UNUM_DECIMAL_ALWAYS_SHOWN: - return isDecimalSeparatorAlwaysShown(); +void DecimalFormat::touchNoError() { + UErrorCode localStatus = U_ZERO_ERROR; + touch(localStatus); +} - case UNUM_MAX_INTEGER_DIGITS: - return getMaximumIntegerDigits(); +void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding, + UErrorCode& status) { + if (U_SUCCESS(status)) { + // Cast workaround to get around putting the enum in the public header file + auto actualIgnoreRounding = static_cast(ignoreRounding); + PatternParser::parseToExistingProperties(pattern, *fields->properties, actualIgnoreRounding, status); + } +} - case UNUM_MIN_INTEGER_DIGITS: - return getMinimumIntegerDigits(); +const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const { + if (U_FAILURE(status)) { return nullptr; } - case UNUM_INTEGER_DIGITS: - // TBD: what should this return? - return getMinimumIntegerDigits(); + // First try to get the pre-computed parser + auto* ptr = fields->atomicParser.load(); + if (ptr != nullptr) { + return ptr; + } - case UNUM_MAX_FRACTION_DIGITS: - return getMaximumFractionDigits(); + // Try computing the parser on our own + auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, false, status); + if (temp == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + // although we may still dereference, call sites should be guarded + } - case UNUM_MIN_FRACTION_DIGITS: - return getMinimumFractionDigits(); + // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the + // atomic if another thread beat us to computing the parser object. + auto* nonConstThis = const_cast(this); + if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the parser + delete temp; + return ptr; + } else { + // Our copy of the parser got stored in the atomic + return temp; + } +} - case UNUM_FRACTION_DIGITS: - // TBD: what should this return? - return getMinimumFractionDigits(); +const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const { + if (U_FAILURE(status)) { return nullptr; } - case UNUM_SIGNIFICANT_DIGITS_USED: - return areSignificantDigitsUsed(); + // First try to get the pre-computed parser + auto* ptr = fields->atomicCurrencyParser.load(); + if (ptr != nullptr) { + return ptr; + } - case UNUM_MAX_SIGNIFICANT_DIGITS: - return getMaximumSignificantDigits(); + // Try computing the parser on our own + auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, true, status); + if (temp == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + // although we may still dereference, call sites should be guarded + } - case UNUM_MIN_SIGNIFICANT_DIGITS: - return getMinimumSignificantDigits(); + // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the + // atomic if another thread beat us to computing the parser object. + auto* nonConstThis = const_cast(this); + if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the parser + delete temp; + return ptr; + } else { + // Our copy of the parser got stored in the atomic + return temp; + } +} - case UNUM_MULTIPLIER: - return getMultiplier(); +void +DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition, + int32_t offset, UErrorCode& status) { + // always return first occurrence: + fieldPosition.setBeginIndex(0); + fieldPosition.setEndIndex(0); + bool found = formatted.nextFieldPosition(fieldPosition, status); + if (found && offset != 0) { + FieldPositionOnlyHandler fpoh(fieldPosition); + fpoh.shiftLast(offset); + } +} - case UNUM_GROUPING_SIZE: - return getGroupingSize(); +void +DecimalFormat::fieldPositionIteratorHelper(const number::FormattedNumber& formatted, FieldPositionIterator* fpi, + int32_t offset, UErrorCode& status) { + if (fpi != nullptr) { + FieldPositionIteratorHandler fpih(fpi, status); + fpih.setShift(offset); + formatted.getAllFieldPositionsImpl(fpih, status); + } +} - case UNUM_ROUNDING_MODE: - return getRoundingMode(); +// To debug fast-format, change void(x) to printf(x) +#define trace(x) void(x) - case UNUM_FORMAT_WIDTH: - return getFormatWidth(); +void DecimalFormat::setupFastFormat() { + // Check the majority of properties: + if (!fields->properties->equalsDefaultExceptFastFormat()) { + trace("no fast format: equality\n"); + fields->canUseFastFormat = false; + return; + } - case UNUM_PADDING_POSITION: - return getPadPosition(); + // Now check the remaining properties. + // Nontrivial affixes: + UBool trivialPP = fields->properties->positivePrefixPattern.isEmpty(); + UBool trivialPS = fields->properties->positiveSuffixPattern.isEmpty(); + UBool trivialNP = fields->properties->negativePrefixPattern.isBogus() || ( + fields->properties->negativePrefixPattern.length() == 1 && + fields->properties->negativePrefixPattern.charAt(0) == u'-'); + UBool trivialNS = fields->properties->negativeSuffixPattern.isEmpty(); + if (!trivialPP || !trivialPS || !trivialNP || !trivialNS) { + trace("no fast format: affixes\n"); + fields->canUseFastFormat = false; + return; + } - case UNUM_SECONDARY_GROUPING_SIZE: - return getSecondaryGroupingSize(); + // Grouping (secondary grouping is forbidden in equalsDefaultExceptFastFormat): + bool groupingUsed = fields->properties->groupingUsed; + int32_t groupingSize = fields->properties->groupingSize; + bool unusualGroupingSize = groupingSize > 0 && groupingSize != 3; + const UnicodeString& groupingString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); + if (groupingUsed && (unusualGroupingSize || groupingString.length() != 1)) { + trace("no fast format: grouping\n"); + fields->canUseFastFormat = false; + return; + } - /* These are stored in fBoolFlags */ - case UNUM_PARSE_NO_EXPONENT: - case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: - case UNUM_PARSE_DECIMAL_MARK_REQUIRED: - return fBoolFlags.get(attr); + // Integer length: + int32_t minInt = fields->exportedProperties->minimumIntegerDigits; + int32_t maxInt = fields->exportedProperties->maximumIntegerDigits; + // Fastpath supports up to only 10 digits (length of INT32_MIN) + if (minInt > 10) { + trace("no fast format: integer\n"); + fields->canUseFastFormat = false; + return; + } - case UNUM_SCALE: - return fImpl->fScale; + // Fraction length (no fraction part allowed in fast path): + int32_t minFrac = fields->exportedProperties->minimumFractionDigits; + if (minFrac > 0) { + trace("no fast format: fraction\n"); + fields->canUseFastFormat = false; + return; + } - case UNUM_CURRENCY_USAGE: - return fImpl->getCurrencyUsage(); + // Other symbols: + const UnicodeString& minusSignString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); + UChar32 codePointZero = fields->symbols->getCodePointZero(); + if (minusSignString.length() != 1 || U16_LENGTH(codePointZero) != 1) { + trace("no fast format: symbols\n"); + fields->canUseFastFormat = false; + return; + } - case UNUM_MINIMUM_GROUPING_DIGITS: - return getMinimumGroupingDigits(); + // Good to go! + trace("can use fast format!\n"); + fields->canUseFastFormat = true; + fields->fastData.cpZero = static_cast(codePointZero); + fields->fastData.cpGroupingSeparator = groupingUsed && groupingSize == 3 ? groupingString.charAt(0) : 0; + fields->fastData.cpMinusSign = minusSignString.charAt(0); + fields->fastData.minInt = (minInt < 0 || minInt > 127) ? 0 : static_cast(minInt); + fields->fastData.maxInt = (maxInt < 0 || maxInt > 127) ? 127 : static_cast(maxInt); +} - default: - status = U_UNSUPPORTED_ERROR; - break; - } +bool DecimalFormat::fastFormatDouble(double input, UnicodeString& output) const { + if (!fields->canUseFastFormat) { + return false; + } + if (std::isnan(input) + || std::trunc(input) != input + || input <= INT32_MIN + || input > INT32_MAX) { + return false; + } + doFastFormatInt32(static_cast(input), std::signbit(input), output); + return true; +} - return -1; /* undefined */ +bool DecimalFormat::fastFormatInt64(int64_t input, UnicodeString& output) const { + if (!fields->canUseFastFormat) { + return false; + } + if (input <= INT32_MIN || input > INT32_MAX) { + return false; + } + doFastFormatInt32(static_cast(input), input < 0, output); + return true; } -#if UCONFIG_HAVE_PARSEALLINPUT -void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) { - fParseAllInput = value; +void DecimalFormat::doFastFormatInt32(int32_t input, bool isNegative, UnicodeString& output) const { + U_ASSERT(fields->canUseFastFormat); + if (isNegative) { + output.append(fields->fastData.cpMinusSign); + U_ASSERT(input != INT32_MIN); // handled by callers + input = -input; + } + // Cap at int32_t to make the buffer small and operations fast. + // Longest string: "2,147,483,648" (13 chars in length) + static constexpr int32_t localCapacity = 13; + char16_t localBuffer[localCapacity]; + char16_t* ptr = localBuffer + localCapacity; + int8_t group = 0; + for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < fields->fastData.minInt); i++) { + if (group++ == 3 && fields->fastData.cpGroupingSeparator != 0) { + *(--ptr) = fields->fastData.cpGroupingSeparator; + group = 1; + } + std::div_t res = std::div(input, 10); + *(--ptr) = static_cast(fields->fastData.cpZero + res.rem); + input = res.quot; + } + int32_t len = localCapacity - static_cast(ptr - localBuffer); + output.append(ptr, len); } -#endif -U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */ - -//eof diff --git a/deps/icu-small/source/i18n/decimfmtimpl.cpp b/deps/icu-small/source/i18n/decimfmtimpl.cpp deleted file mode 100644 index ef44eab010..0000000000 --- a/deps/icu-small/source/i18n/decimfmtimpl.cpp +++ /dev/null @@ -1,1596 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: decimfmtimpl.cpp - */ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include -#include "unicode/numfmt.h" -#include "unicode/plurrule.h" -#include "unicode/ustring.h" -#include "decimalformatpattern.h" -#include "decimalformatpatternimpl.h" -#include "decimfmtimpl.h" -#include "fphdlimp.h" -#include "plurrule_impl.h" -#include "valueformatter.h" -#include "visibledigits.h" - -U_NAMESPACE_BEGIN - -static const int32_t kMaxScientificIntegerDigits = 8; - -static const int32_t kFormattingPosPrefix = (1 << 0); -static const int32_t kFormattingNegPrefix = (1 << 1); -static const int32_t kFormattingPosSuffix = (1 << 2); -static const int32_t kFormattingNegSuffix = (1 << 3); -static const int32_t kFormattingSymbols = (1 << 4); -static const int32_t kFormattingCurrency = (1 << 5); -static const int32_t kFormattingUsesCurrency = (1 << 6); -static const int32_t kFormattingPluralRules = (1 << 7); -static const int32_t kFormattingAffixParser = (1 << 8); -static const int32_t kFormattingCurrencyAffixInfo = (1 << 9); -static const int32_t kFormattingAll = (1 << 10) - 1; -static const int32_t kFormattingAffixes = - kFormattingPosPrefix | kFormattingPosSuffix | - kFormattingNegPrefix | kFormattingNegSuffix; -static const int32_t kFormattingAffixParserWithCurrency = - kFormattingAffixParser | kFormattingCurrencyAffixInfo; - -DecimalFormatImpl::DecimalFormatImpl( - NumberFormat *super, - const Locale &locale, - const UnicodeString &pattern, - UErrorCode &status) - : fSuper(super), - fScale(0), - fRoundingMode(DecimalFormat::kRoundHalfEven), - fSymbols(NULL), - fCurrencyUsage(UCURR_USAGE_STANDARD), - fRules(NULL), - fMonetary(FALSE) { - if (U_FAILURE(status)) { - return; - } - fSymbols = new DecimalFormatSymbols( - locale, status); - if (fSymbols == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - UParseError parseError; - applyPattern(pattern, FALSE, parseError, status); - updateAll(status); -} - -DecimalFormatImpl::DecimalFormatImpl( - NumberFormat *super, - const UnicodeString &pattern, - DecimalFormatSymbols *symbolsToAdopt, - UParseError &parseError, - UErrorCode &status) - : fSuper(super), - fScale(0), - fRoundingMode(DecimalFormat::kRoundHalfEven), - fSymbols(symbolsToAdopt), - fCurrencyUsage(UCURR_USAGE_STANDARD), - fRules(NULL), - fMonetary(FALSE) { - applyPattern(pattern, FALSE, parseError, status); - updateAll(status); -} - -DecimalFormatImpl::DecimalFormatImpl( - NumberFormat *super, const DecimalFormatImpl &other, UErrorCode &status) : - fSuper(super), - fMultiplier(other.fMultiplier), - fScale(other.fScale), - fRoundingMode(other.fRoundingMode), - fMinSigDigits(other.fMinSigDigits), - fMaxSigDigits(other.fMaxSigDigits), - fUseScientific(other.fUseScientific), - fUseSigDigits(other.fUseSigDigits), - fGrouping(other.fGrouping), - fPositivePrefixPattern(other.fPositivePrefixPattern), - fNegativePrefixPattern(other.fNegativePrefixPattern), - fPositiveSuffixPattern(other.fPositiveSuffixPattern), - fNegativeSuffixPattern(other.fNegativeSuffixPattern), - fSymbols(other.fSymbols), - fCurrencyUsage(other.fCurrencyUsage), - fRules(NULL), - fMonetary(other.fMonetary), - fAffixParser(other.fAffixParser), - fCurrencyAffixInfo(other.fCurrencyAffixInfo), - fEffPrecision(other.fEffPrecision), - fEffGrouping(other.fEffGrouping), - fOptions(other.fOptions), - fFormatter(other.fFormatter), - fAffixes(other.fAffixes) { - fSymbols = new DecimalFormatSymbols(*fSymbols); - if (fSymbols == NULL && U_SUCCESS(status)) { - status = U_MEMORY_ALLOCATION_ERROR; - } - if (other.fRules != NULL) { - fRules = new PluralRules(*other.fRules); - if (fRules == NULL && U_SUCCESS(status)) { - status = U_MEMORY_ALLOCATION_ERROR; - } - } -} - - -DecimalFormatImpl & -DecimalFormatImpl::assign(const DecimalFormatImpl &other, UErrorCode &status) { - if (U_FAILURE(status) || this == &other) { - return (*this); - } - UObject::operator=(other); - fMultiplier = other.fMultiplier; - fScale = other.fScale; - fRoundingMode = other.fRoundingMode; - fMinSigDigits = other.fMinSigDigits; - fMaxSigDigits = other.fMaxSigDigits; - fUseScientific = other.fUseScientific; - fUseSigDigits = other.fUseSigDigits; - fGrouping = other.fGrouping; - fPositivePrefixPattern = other.fPositivePrefixPattern; - fNegativePrefixPattern = other.fNegativePrefixPattern; - fPositiveSuffixPattern = other.fPositiveSuffixPattern; - fNegativeSuffixPattern = other.fNegativeSuffixPattern; - fCurrencyUsage = other.fCurrencyUsage; - fMonetary = other.fMonetary; - fAffixParser = other.fAffixParser; - fCurrencyAffixInfo = other.fCurrencyAffixInfo; - fEffPrecision = other.fEffPrecision; - fEffGrouping = other.fEffGrouping; - fOptions = other.fOptions; - fFormatter = other.fFormatter; - fAffixes = other.fAffixes; - *fSymbols = *other.fSymbols; - if (fRules != NULL && other.fRules != NULL) { - *fRules = *other.fRules; - } else { - delete fRules; - fRules = other.fRules; - if (fRules != NULL) { - fRules = new PluralRules(*fRules); - if (fRules == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return *this; - } - } - } - return *this; -} - -UBool -DecimalFormatImpl::operator==(const DecimalFormatImpl &other) const { - if (this == &other) { - return TRUE; - } - return (fMultiplier == other.fMultiplier) - && (fScale == other.fScale) - && (fRoundingMode == other.fRoundingMode) - && (fMinSigDigits == other.fMinSigDigits) - && (fMaxSigDigits == other.fMaxSigDigits) - && (fUseScientific == other.fUseScientific) - && (fUseSigDigits == other.fUseSigDigits) - && fGrouping.equals(other.fGrouping) - && fPositivePrefixPattern.equals(other.fPositivePrefixPattern) - && fNegativePrefixPattern.equals(other.fNegativePrefixPattern) - && fPositiveSuffixPattern.equals(other.fPositiveSuffixPattern) - && fNegativeSuffixPattern.equals(other.fNegativeSuffixPattern) - && fCurrencyUsage == other.fCurrencyUsage - && fAffixParser.equals(other.fAffixParser) - && fCurrencyAffixInfo.equals(other.fCurrencyAffixInfo) - && fEffPrecision.equals(other.fEffPrecision) - && fEffGrouping.equals(other.fEffGrouping) - && fOptions.equals(other.fOptions) - && fFormatter.equals(other.fFormatter) - && fAffixes.equals(other.fAffixes) - && (*fSymbols == *other.fSymbols) - && ((fRules == other.fRules) || ( - (fRules != NULL) && (other.fRules != NULL) - && (*fRules == *other.fRules))) - && (fMonetary == other.fMonetary); -} - -DecimalFormatImpl::~DecimalFormatImpl() { - delete fSymbols; - delete fRules; -} - -ValueFormatter & -DecimalFormatImpl::prepareValueFormatter(ValueFormatter &vf) const { - if (fUseScientific) { - vf.prepareScientificFormatting( - fFormatter, fEffPrecision, fOptions); - return vf; - } - vf.prepareFixedDecimalFormatting( - fFormatter, fEffGrouping, fEffPrecision.fMantissa, fOptions.fMantissa); - return vf; -} - -int32_t -DecimalFormatImpl::getPatternScale() const { - UBool usesPercent = fPositivePrefixPattern.usesPercent() || - fPositiveSuffixPattern.usesPercent() || - fNegativePrefixPattern.usesPercent() || - fNegativeSuffixPattern.usesPercent(); - if (usesPercent) { - return 2; - } - UBool usesPermill = fPositivePrefixPattern.usesPermill() || - fPositiveSuffixPattern.usesPermill() || - fNegativePrefixPattern.usesPermill() || - fNegativeSuffixPattern.usesPermill(); - if (usesPermill) { - return 3; - } - return 0; -} - -void -DecimalFormatImpl::setMultiplierScale(int32_t scale) { - if (scale == 0) { - // Needed to preserve equality. fMultiplier == 0 means - // multiplier is 1. - fMultiplier.set((int32_t)0); - } else { - fMultiplier.set((int32_t)1); - fMultiplier.shiftDecimalRight(scale); - } -} - -UnicodeString & -DecimalFormatImpl::format( - int32_t number, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const { - FieldPositionOnlyHandler handler(pos); - return formatInt32(number, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - int32_t number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const { - FieldPositionIteratorHandler handler(posIter, status); - return formatInt32(number, appendTo, handler, status); -} - -template -UBool DecimalFormatImpl::maybeFormatWithDigitList( - T number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const { - if (!fMultiplier.isZero()) { - DigitList digits; - digits.set(number); - digits.mult(fMultiplier, status); - digits.shiftDecimalRight(fScale); - formatAdjustedDigitList(digits, appendTo, handler, status); - return TRUE; - } - if (fScale != 0) { - DigitList digits; - digits.set(number); - digits.shiftDecimalRight(fScale); - formatAdjustedDigitList(digits, appendTo, handler, status); - return TRUE; - } - return FALSE; -} - -template -UBool DecimalFormatImpl::maybeInitVisibleDigitsFromDigitList( - T number, - VisibleDigitsWithExponent &visibleDigits, - UErrorCode &status) const { - if (!fMultiplier.isZero()) { - DigitList digits; - digits.set(number); - digits.mult(fMultiplier, status); - digits.shiftDecimalRight(fScale); - initVisibleDigitsFromAdjusted(digits, visibleDigits, status); - return TRUE; - } - if (fScale != 0) { - DigitList digits; - digits.set(number); - digits.shiftDecimalRight(fScale); - initVisibleDigitsFromAdjusted(digits, visibleDigits, status); - return TRUE; - } - return FALSE; -} - -UnicodeString & -DecimalFormatImpl::formatInt32( - int32_t number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const { - if (maybeFormatWithDigitList(number, appendTo, handler, status)) { - return appendTo; - } - ValueFormatter vf; - return fAffixes.formatInt32( - number, - prepareValueFormatter(vf), - handler, - fRules, - appendTo, - status); -} - -UnicodeString & -DecimalFormatImpl::formatInt64( - int64_t number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const { - if (number >= INT32_MIN && number <= INT32_MAX) { - return formatInt32((int32_t) number, appendTo, handler, status); - } - VisibleDigitsWithExponent digits; - initVisibleDigitsWithExponent(number, digits, status); - return formatVisibleDigitsWithExponent( - digits, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::formatDouble( - double number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const { - VisibleDigitsWithExponent digits; - initVisibleDigitsWithExponent(number, digits, status); - return formatVisibleDigitsWithExponent( - digits, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - double number, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const { - FieldPositionOnlyHandler handler(pos); - return formatDouble(number, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - const DigitList &number, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const { - DigitList dl(number); - FieldPositionOnlyHandler handler(pos); - return formatDigitList(dl, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - int64_t number, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const { - FieldPositionOnlyHandler handler(pos); - return formatInt64(number, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - int64_t number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const { - FieldPositionIteratorHandler handler(posIter, status); - return formatInt64(number, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - double number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const { - FieldPositionIteratorHandler handler(posIter, status); - return formatDouble(number, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - const DigitList &number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const { - DigitList dl(number); - FieldPositionIteratorHandler handler(posIter, status); - return formatDigitList(dl, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - StringPiece number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const { - DigitList dl; - dl.set(number, status); - FieldPositionIteratorHandler handler(posIter, status); - return formatDigitList(dl, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - const VisibleDigitsWithExponent &digits, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const { - FieldPositionOnlyHandler handler(pos); - return formatVisibleDigitsWithExponent( - digits, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::format( - const VisibleDigitsWithExponent &digits, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const { - FieldPositionIteratorHandler handler(posIter, status); - return formatVisibleDigitsWithExponent( - digits, appendTo, handler, status); -} - -DigitList & -DecimalFormatImpl::adjustDigitList( - DigitList &number, UErrorCode &status) const { - number.setRoundingMode(fRoundingMode); - if (!fMultiplier.isZero()) { - number.mult(fMultiplier, status); - } - if (fScale != 0) { - number.shiftDecimalRight(fScale); - } - number.reduce(); - return number; -} - -UnicodeString & -DecimalFormatImpl::formatDigitList( - DigitList &number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const { - VisibleDigitsWithExponent digits; - initVisibleDigitsWithExponent(number, digits, status); - return formatVisibleDigitsWithExponent( - digits, appendTo, handler, status); -} - -UnicodeString & -DecimalFormatImpl::formatAdjustedDigitList( - DigitList &number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const { - ValueFormatter vf; - return fAffixes.format( - number, - prepareValueFormatter(vf), - handler, - fRules, - appendTo, - status); -} - -UnicodeString & -DecimalFormatImpl::formatVisibleDigitsWithExponent( - const VisibleDigitsWithExponent &digits, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const { - ValueFormatter vf; - return fAffixes.format( - digits, - prepareValueFormatter(vf), - handler, - fRules, - appendTo, - status); -} - -static FixedDecimal &initFixedDecimal( - const VisibleDigits &digits, FixedDecimal &result) { - result.source = 0.0; - result.isNegative = digits.isNegative(); - result._isNaN = digits.isNaN(); - result._isInfinite = digits.isInfinite(); - digits.getFixedDecimal( - result.source, result.intValue, result.decimalDigits, - result.decimalDigitsWithoutTrailingZeros, - result.visibleDecimalDigitCount, result.hasIntegerValue); - return result; -} - -FixedDecimal & -DecimalFormatImpl::getFixedDecimal(double number, FixedDecimal &result, UErrorCode &status) const { - if (U_FAILURE(status)) { - return result; - } - VisibleDigits digits; - fEffPrecision.fMantissa.initVisibleDigits(number, digits, status); - return initFixedDecimal(digits, result); -} - -FixedDecimal & -DecimalFormatImpl::getFixedDecimal( - DigitList &number, FixedDecimal &result, UErrorCode &status) const { - if (U_FAILURE(status)) { - return result; - } - VisibleDigits digits; - fEffPrecision.fMantissa.initVisibleDigits(number, digits, status); - return initFixedDecimal(digits, result); -} - -VisibleDigitsWithExponent & -DecimalFormatImpl::initVisibleDigitsWithExponent( - int64_t number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - if (maybeInitVisibleDigitsFromDigitList( - number, digits, status)) { - return digits; - } - if (fUseScientific) { - fEffPrecision.initVisibleDigitsWithExponent( - number, digits, status); - } else { - fEffPrecision.fMantissa.initVisibleDigitsWithExponent( - number, digits, status); - } - return digits; -} - -VisibleDigitsWithExponent & -DecimalFormatImpl::initVisibleDigitsWithExponent( - double number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - if (maybeInitVisibleDigitsFromDigitList( - number, digits, status)) { - return digits; - } - if (fUseScientific) { - fEffPrecision.initVisibleDigitsWithExponent( - number, digits, status); - } else { - fEffPrecision.fMantissa.initVisibleDigitsWithExponent( - number, digits, status); - } - return digits; -} - -VisibleDigitsWithExponent & -DecimalFormatImpl::initVisibleDigitsWithExponent( - DigitList &number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - adjustDigitList(number, status); - return initVisibleDigitsFromAdjusted(number, digits, status); -} - -VisibleDigitsWithExponent & -DecimalFormatImpl::initVisibleDigitsFromAdjusted( - DigitList &number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - if (fUseScientific) { - fEffPrecision.initVisibleDigitsWithExponent( - number, digits, status); - } else { - fEffPrecision.fMantissa.initVisibleDigitsWithExponent( - number, digits, status); - } - return digits; -} - -DigitList & -DecimalFormatImpl::round( - DigitList &number, UErrorCode &status) const { - if (number.isNaN() || number.isInfinite()) { - return number; - } - adjustDigitList(number, status); - ValueFormatter vf; - prepareValueFormatter(vf); - return vf.round(number, status); -} - -void -DecimalFormatImpl::setMinimumSignificantDigits(int32_t newValue) { - fMinSigDigits = newValue; - fUseSigDigits = TRUE; // ticket 9936 - updatePrecision(); -} - -void -DecimalFormatImpl::setMaximumSignificantDigits(int32_t newValue) { - fMaxSigDigits = newValue; - fUseSigDigits = TRUE; // ticket 9936 - updatePrecision(); -} - -void -DecimalFormatImpl::setMinMaxSignificantDigits(int32_t min, int32_t max) { - fMinSigDigits = min; - fMaxSigDigits = max; - fUseSigDigits = TRUE; // ticket 9936 - updatePrecision(); -} - -void -DecimalFormatImpl::setScientificNotation(UBool newValue) { - fUseScientific = newValue; - updatePrecision(); -} - -void -DecimalFormatImpl::setSignificantDigitsUsed(UBool newValue) { - fUseSigDigits = newValue; - updatePrecision(); -} - -void -DecimalFormatImpl::setGroupingSize(int32_t newValue) { - fGrouping.fGrouping = newValue; - updateGrouping(); -} - -void -DecimalFormatImpl::setSecondaryGroupingSize(int32_t newValue) { - fGrouping.fGrouping2 = newValue; - updateGrouping(); -} - -void -DecimalFormatImpl::setMinimumGroupingDigits(int32_t newValue) { - fGrouping.fMinGrouping = newValue; - updateGrouping(); -} - -void -DecimalFormatImpl::setCurrencyUsage( - UCurrencyUsage currencyUsage, UErrorCode &status) { - fCurrencyUsage = currencyUsage; - updateFormatting(kFormattingCurrency, status); -} - -void -DecimalFormatImpl::setRoundingIncrement(double d) { - if (d > 0.0) { - fEffPrecision.fMantissa.fRoundingIncrement.set(d); - } else { - fEffPrecision.fMantissa.fRoundingIncrement.set(0.0); - } -} - -double -DecimalFormatImpl::getRoundingIncrement() const { - return fEffPrecision.fMantissa.fRoundingIncrement.getDouble(); -} - -int32_t -DecimalFormatImpl::getMultiplier() const { - if (fMultiplier.isZero()) { - return 1; - } - return (int32_t) fMultiplier.getDouble(); -} - -void -DecimalFormatImpl::setMultiplier(int32_t m) { - if (m == 0 || m == 1) { - fMultiplier.set((int32_t)0); - } else { - fMultiplier.set(m); - } -} - -void -DecimalFormatImpl::setPositivePrefix(const UnicodeString &str) { - fPositivePrefixPattern.remove(); - fPositivePrefixPattern.addLiteral(str.getBuffer(), 0, str.length()); - UErrorCode status = U_ZERO_ERROR; - updateFormatting(kFormattingPosPrefix, status); -} - -void -DecimalFormatImpl::setPositiveSuffix(const UnicodeString &str) { - fPositiveSuffixPattern.remove(); - fPositiveSuffixPattern.addLiteral(str.getBuffer(), 0, str.length()); - UErrorCode status = U_ZERO_ERROR; - updateFormatting(kFormattingPosSuffix, status); -} - -void -DecimalFormatImpl::setNegativePrefix(const UnicodeString &str) { - fNegativePrefixPattern.remove(); - fNegativePrefixPattern.addLiteral(str.getBuffer(), 0, str.length()); - UErrorCode status = U_ZERO_ERROR; - updateFormatting(kFormattingNegPrefix, status); -} - -void -DecimalFormatImpl::setNegativeSuffix(const UnicodeString &str) { - fNegativeSuffixPattern.remove(); - fNegativeSuffixPattern.addLiteral(str.getBuffer(), 0, str.length()); - UErrorCode status = U_ZERO_ERROR; - updateFormatting(kFormattingNegSuffix, status); -} - -UnicodeString & -DecimalFormatImpl::getPositivePrefix(UnicodeString &result) const { - result = fAffixes.fPositivePrefix.getOtherVariant().toString(); - return result; -} - -UnicodeString & -DecimalFormatImpl::getPositiveSuffix(UnicodeString &result) const { - result = fAffixes.fPositiveSuffix.getOtherVariant().toString(); - return result; -} - -UnicodeString & -DecimalFormatImpl::getNegativePrefix(UnicodeString &result) const { - result = fAffixes.fNegativePrefix.getOtherVariant().toString(); - return result; -} - -UnicodeString & -DecimalFormatImpl::getNegativeSuffix(UnicodeString &result) const { - result = fAffixes.fNegativeSuffix.getOtherVariant().toString(); - return result; -} - -void -DecimalFormatImpl::adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt) { - if (symbolsToAdopt == NULL) { - return; - } - delete fSymbols; - fSymbols = symbolsToAdopt; - UErrorCode status = U_ZERO_ERROR; - updateFormatting(kFormattingSymbols, status); -} - -void -DecimalFormatImpl::applyPatternFavorCurrencyPrecision( - const UnicodeString &pattern, UErrorCode &status) { - UParseError perror; - applyPattern(pattern, FALSE, perror, status); - updateForApplyPatternFavorCurrencyPrecision(status); -} - -void -DecimalFormatImpl::applyPattern( - const UnicodeString &pattern, UErrorCode &status) { - UParseError perror; - applyPattern(pattern, FALSE, perror, status); - updateForApplyPattern(status); -} - -void -DecimalFormatImpl::applyPattern( - const UnicodeString &pattern, - UParseError &perror, UErrorCode &status) { - applyPattern(pattern, FALSE, perror, status); - updateForApplyPattern(status); -} - -void -DecimalFormatImpl::applyLocalizedPattern( - const UnicodeString &pattern, UErrorCode &status) { - UParseError perror; - applyPattern(pattern, TRUE, perror, status); - updateForApplyPattern(status); -} - -void -DecimalFormatImpl::applyLocalizedPattern( - const UnicodeString &pattern, - UParseError &perror, UErrorCode &status) { - applyPattern(pattern, TRUE, perror, status); - updateForApplyPattern(status); -} - -void -DecimalFormatImpl::applyPattern( - const UnicodeString &pattern, - UBool localized, UParseError &perror, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - DecimalFormatPatternParser patternParser; - if (localized) { - patternParser.useSymbols(*fSymbols); - } - DecimalFormatPattern out; - patternParser.applyPatternWithoutExpandAffix( - pattern, out, perror, status); - if (U_FAILURE(status)) { - return; - } - fUseScientific = out.fUseExponentialNotation; - fUseSigDigits = out.fUseSignificantDigits; - fSuper->NumberFormat::setMinimumIntegerDigits(out.fMinimumIntegerDigits); - fSuper->NumberFormat::setMaximumIntegerDigits(out.fMaximumIntegerDigits); - fSuper->NumberFormat::setMinimumFractionDigits(out.fMinimumFractionDigits); - fSuper->NumberFormat::setMaximumFractionDigits(out.fMaximumFractionDigits); - fMinSigDigits = out.fMinimumSignificantDigits; - fMaxSigDigits = out.fMaximumSignificantDigits; - fEffPrecision.fMinExponentDigits = out.fMinExponentDigits; - fOptions.fExponent.fAlwaysShowSign = out.fExponentSignAlwaysShown; - fSuper->NumberFormat::setGroupingUsed(out.fGroupingUsed); - fGrouping.fGrouping = out.fGroupingSize; - fGrouping.fGrouping2 = out.fGroupingSize2; - fOptions.fMantissa.fAlwaysShowDecimal = out.fDecimalSeparatorAlwaysShown; - if (out.fRoundingIncrementUsed) { - fEffPrecision.fMantissa.fRoundingIncrement = out.fRoundingIncrement; - } else { - fEffPrecision.fMantissa.fRoundingIncrement.clear(); - } - fAffixes.fPadChar = out.fPad; - fNegativePrefixPattern = out.fNegPrefixAffix; - fNegativeSuffixPattern = out.fNegSuffixAffix; - fPositivePrefixPattern = out.fPosPrefixAffix; - fPositiveSuffixPattern = out.fPosSuffixAffix; - - // Work around. Pattern parsing code and DecimalFormat code don't agree - // on the definition of field width, so we have to translate from - // pattern field width to decimal format field width here. - fAffixes.fWidth = out.fFormatWidth == 0 ? 0 : - out.fFormatWidth + fPositivePrefixPattern.countChar32() - + fPositiveSuffixPattern.countChar32(); - switch (out.fPadPosition) { - case DecimalFormatPattern::kPadBeforePrefix: - fAffixes.fPadPosition = DigitAffixesAndPadding::kPadBeforePrefix; - break; - case DecimalFormatPattern::kPadAfterPrefix: - fAffixes.fPadPosition = DigitAffixesAndPadding::kPadAfterPrefix; - break; - case DecimalFormatPattern::kPadBeforeSuffix: - fAffixes.fPadPosition = DigitAffixesAndPadding::kPadBeforeSuffix; - break; - case DecimalFormatPattern::kPadAfterSuffix: - fAffixes.fPadPosition = DigitAffixesAndPadding::kPadAfterSuffix; - break; - default: - break; - } -} - -void -DecimalFormatImpl::updatePrecision() { - if (fUseScientific) { - updatePrecisionForScientific(); - } else { - updatePrecisionForFixed(); - } -} - -static void updatePrecisionForScientificMinMax( - const DigitInterval &min, - const DigitInterval &max, - DigitInterval &resultMin, - DigitInterval &resultMax, - SignificantDigitInterval &resultSignificant) { - resultMin.setIntDigitCount(0); - resultMin.setFracDigitCount(0); - resultSignificant.clear(); - resultMax.clear(); - - int32_t maxIntDigitCount = max.getIntDigitCount(); - int32_t minIntDigitCount = min.getIntDigitCount(); - int32_t maxFracDigitCount = max.getFracDigitCount(); - int32_t minFracDigitCount = min.getFracDigitCount(); - - - // Not in spec: maxIntDigitCount > 8 assume - // maxIntDigitCount = minIntDigitCount. Current DecimalFormat API has - // no provision for unsetting maxIntDigitCount which would be useful for - // scientific notation. The best we can do is assume that if - // maxIntDigitCount is the default of 2000000000 or is "big enough" then - // user did not intend to explicitly set it. The 8 was derived emperically - // by extensive testing of legacy code. - if (maxIntDigitCount > 8) { - maxIntDigitCount = minIntDigitCount; - } - - // Per the spec, exponent grouping happens if maxIntDigitCount is more - // than 1 and more than minIntDigitCount. - UBool bExponentGrouping = maxIntDigitCount > 1 && minIntDigitCount < maxIntDigitCount; - if (bExponentGrouping) { - resultMax.setIntDigitCount(maxIntDigitCount); - - // For exponent grouping minIntDigits is always treated as 1 even - // if it wasn't set to 1! - resultMin.setIntDigitCount(1); - } else { - // Fixed digit count left of decimal. minIntDigitCount doesn't have - // to equal maxIntDigitCount i.e minIntDigitCount == 0 while - // maxIntDigitCount == 1. - int32_t fixedIntDigitCount = maxIntDigitCount; - - // If fixedIntDigitCount is 0 but - // min or max fraction count is 0 too then use 1. This way we can get - // unlimited precision for X.XXXEX - if (fixedIntDigitCount == 0 && (minFracDigitCount == 0 || maxFracDigitCount == 0)) { - fixedIntDigitCount = 1; - } - resultMax.setIntDigitCount(fixedIntDigitCount); - resultMin.setIntDigitCount(fixedIntDigitCount); - } - // Spec says this is how we compute significant digits. 0 means - // unlimited significant digits. - int32_t maxSigDigits = minIntDigitCount + maxFracDigitCount; - if (maxSigDigits > 0) { - int32_t minSigDigits = minIntDigitCount + minFracDigitCount; - resultSignificant.setMin(minSigDigits); - resultSignificant.setMax(maxSigDigits); - } -} - -void -DecimalFormatImpl::updatePrecisionForScientific() { - FixedPrecision *result = &fEffPrecision.fMantissa; - if (fUseSigDigits) { - result->fMax.setFracDigitCount(-1); - result->fMax.setIntDigitCount(1); - result->fMin.setFracDigitCount(0); - result->fMin.setIntDigitCount(1); - result->fSignificant.clear(); - extractSigDigits(result->fSignificant); - return; - } - DigitInterval max; - DigitInterval min; - extractMinMaxDigits(min, max); - updatePrecisionForScientificMinMax( - min, max, - result->fMin, result->fMax, result->fSignificant); -} - -void -DecimalFormatImpl::updatePrecisionForFixed() { - FixedPrecision *result = &fEffPrecision.fMantissa; - if (!fUseSigDigits) { - extractMinMaxDigits(result->fMin, result->fMax); - result->fSignificant.clear(); - } else { - extractSigDigits(result->fSignificant); - result->fMin.setIntDigitCount(1); - result->fMin.setFracDigitCount(0); - result->fMax.clear(); - } -} - -void - DecimalFormatImpl::extractMinMaxDigits( - DigitInterval &min, DigitInterval &max) const { - min.setIntDigitCount(fSuper->getMinimumIntegerDigits()); - max.setIntDigitCount(fSuper->getMaximumIntegerDigits()); - min.setFracDigitCount(fSuper->getMinimumFractionDigits()); - max.setFracDigitCount(fSuper->getMaximumFractionDigits()); -} - -void - DecimalFormatImpl::extractSigDigits( - SignificantDigitInterval &sig) const { - sig.setMin(fMinSigDigits < 0 ? 0 : fMinSigDigits); - sig.setMax(fMaxSigDigits < 0 ? 0 : fMaxSigDigits); -} - -void -DecimalFormatImpl::updateGrouping() { - if (fSuper->isGroupingUsed()) { - fEffGrouping = fGrouping; - } else { - fEffGrouping.clear(); - } -} - -void -DecimalFormatImpl::updateCurrency(UErrorCode &status) { - updateFormatting(kFormattingCurrency, TRUE, status); -} - -void -DecimalFormatImpl::updateFormatting( - int32_t changedFormattingFields, - UErrorCode &status) { - updateFormatting(changedFormattingFields, TRUE, status); -} - -void -DecimalFormatImpl::updateFormatting( - int32_t changedFormattingFields, - UBool updatePrecisionBasedOnCurrency, - UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - // Each function updates one field. Order matters. For instance, - // updatePluralRules comes before updateCurrencyAffixInfo because the - // fRules field is needed to update the fCurrencyAffixInfo field. - updateFormattingUsesCurrency(changedFormattingFields); - updateFormattingFixedPointFormatter(changedFormattingFields); - updateFormattingAffixParser(changedFormattingFields); - updateFormattingPluralRules(changedFormattingFields, status); - updateFormattingCurrencyAffixInfo( - changedFormattingFields, - updatePrecisionBasedOnCurrency, - status); - updateFormattingLocalizedPositivePrefix( - changedFormattingFields, status); - updateFormattingLocalizedPositiveSuffix( - changedFormattingFields, status); - updateFormattingLocalizedNegativePrefix( - changedFormattingFields, status); - updateFormattingLocalizedNegativeSuffix( - changedFormattingFields, status); -} - -void -DecimalFormatImpl::updateFormattingUsesCurrency( - int32_t &changedFormattingFields) { - if ((changedFormattingFields & kFormattingAffixes) == 0) { - // If no affixes changed, don't need to do any work - return; - } - UBool newUsesCurrency = - fPositivePrefixPattern.usesCurrency() || - fPositiveSuffixPattern.usesCurrency() || - fNegativePrefixPattern.usesCurrency() || - fNegativeSuffixPattern.usesCurrency(); - if (fMonetary != newUsesCurrency) { - fMonetary = newUsesCurrency; - changedFormattingFields |= kFormattingUsesCurrency; - } -} - -void -DecimalFormatImpl::updateFormattingPluralRules( - int32_t &changedFormattingFields, UErrorCode &status) { - if ((changedFormattingFields & (kFormattingSymbols | kFormattingUsesCurrency)) == 0) { - // No work to do if both fSymbols and fMonetary - // fields are unchanged - return; - } - if (U_FAILURE(status)) { - return; - } - PluralRules *newRules = NULL; - if (fMonetary) { - newRules = PluralRules::forLocale(fSymbols->getLocale(), status); - if (U_FAILURE(status)) { - return; - } - } - // Its ok to say a field has changed when it really hasn't but not - // the other way around. Here we assume the field changed unless it - // was NULL before and is still NULL now - if (fRules != newRules) { - delete fRules; - fRules = newRules; - changedFormattingFields |= kFormattingPluralRules; - } -} - -void -DecimalFormatImpl::updateFormattingCurrencyAffixInfo( - int32_t &changedFormattingFields, - UBool updatePrecisionBasedOnCurrency, - UErrorCode &status) { - if ((changedFormattingFields & ( - kFormattingSymbols | kFormattingCurrency | - kFormattingUsesCurrency | kFormattingPluralRules)) == 0) { - // If all these fields are unchanged, no work to do. - return; - } - if (U_FAILURE(status)) { - return; - } - if (!fMonetary) { - if (fCurrencyAffixInfo.isDefault()) { - // In this case don't have to do any work - return; - } - fCurrencyAffixInfo.set(NULL, NULL, NULL, status); - if (U_FAILURE(status)) { - return; - } - changedFormattingFields |= kFormattingCurrencyAffixInfo; - } else { - const UChar *currency = fSuper->getCurrency(); - UChar localeCurr[4]; - if (currency[0] == 0) { - ucurr_forLocale(fSymbols->getLocale().getName(), localeCurr, UPRV_LENGTHOF(localeCurr), &status); - if (U_SUCCESS(status)) { - currency = localeCurr; - fSuper->NumberFormat::setCurrency(currency, status); - } else { - currency = NULL; - status = U_ZERO_ERROR; - } - } - fCurrencyAffixInfo.set( - fSymbols->getLocale().getName(), fRules, currency, status); - if (U_FAILURE(status)) { - return; - } - UBool customCurrencySymbol = FALSE; - // If DecimalFormatSymbols has custom currency symbol, prefer - // that over what we just read from the resource bundles - if (fSymbols->isCustomCurrencySymbol()) { - fCurrencyAffixInfo.setSymbol( - fSymbols->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol)); - customCurrencySymbol = TRUE; - } - if (fSymbols->isCustomIntlCurrencySymbol()) { - fCurrencyAffixInfo.setISO( - fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol)); - customCurrencySymbol = TRUE; - } - changedFormattingFields |= kFormattingCurrencyAffixInfo; - if (currency && !customCurrencySymbol && updatePrecisionBasedOnCurrency) { - FixedPrecision precision; - CurrencyAffixInfo::adjustPrecision( - currency, fCurrencyUsage, precision, status); - if (U_FAILURE(status)) { - return; - } - fSuper->NumberFormat::setMinimumFractionDigits( - precision.fMin.getFracDigitCount()); - fSuper->NumberFormat::setMaximumFractionDigits( - precision.fMax.getFracDigitCount()); - updatePrecision(); - fEffPrecision.fMantissa.fRoundingIncrement = - precision.fRoundingIncrement; - } - - } -} - -void -DecimalFormatImpl::updateFormattingFixedPointFormatter( - int32_t &changedFormattingFields) { - if ((changedFormattingFields & (kFormattingSymbols | kFormattingUsesCurrency)) == 0) { - // No work to do if fSymbols is unchanged - return; - } - if (fMonetary) { - fFormatter.setDecimalFormatSymbolsForMonetary(*fSymbols); - } else { - fFormatter.setDecimalFormatSymbols(*fSymbols); - } -} - -void -DecimalFormatImpl::updateFormattingAffixParser( - int32_t &changedFormattingFields) { - if ((changedFormattingFields & kFormattingSymbols) == 0) { - // No work to do if fSymbols is unchanged - return; - } - fAffixParser.setDecimalFormatSymbols(*fSymbols); - changedFormattingFields |= kFormattingAffixParser; -} - -void -DecimalFormatImpl::updateFormattingLocalizedPositivePrefix( - int32_t &changedFormattingFields, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - if ((changedFormattingFields & ( - kFormattingPosPrefix | kFormattingAffixParserWithCurrency)) == 0) { - // No work to do - return; - } - fAffixes.fPositivePrefix.remove(); - fAffixParser.parse( - fPositivePrefixPattern, - fCurrencyAffixInfo, - fAffixes.fPositivePrefix, - status); -} - -void -DecimalFormatImpl::updateFormattingLocalizedPositiveSuffix( - int32_t &changedFormattingFields, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - if ((changedFormattingFields & ( - kFormattingPosSuffix | kFormattingAffixParserWithCurrency)) == 0) { - // No work to do - return; - } - fAffixes.fPositiveSuffix.remove(); - fAffixParser.parse( - fPositiveSuffixPattern, - fCurrencyAffixInfo, - fAffixes.fPositiveSuffix, - status); -} - -void -DecimalFormatImpl::updateFormattingLocalizedNegativePrefix( - int32_t &changedFormattingFields, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - if ((changedFormattingFields & ( - kFormattingNegPrefix | kFormattingAffixParserWithCurrency)) == 0) { - // No work to do - return; - } - fAffixes.fNegativePrefix.remove(); - fAffixParser.parse( - fNegativePrefixPattern, - fCurrencyAffixInfo, - fAffixes.fNegativePrefix, - status); -} - -void -DecimalFormatImpl::updateFormattingLocalizedNegativeSuffix( - int32_t &changedFormattingFields, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - if ((changedFormattingFields & ( - kFormattingNegSuffix | kFormattingAffixParserWithCurrency)) == 0) { - // No work to do - return; - } - fAffixes.fNegativeSuffix.remove(); - fAffixParser.parse( - fNegativeSuffixPattern, - fCurrencyAffixInfo, - fAffixes.fNegativeSuffix, - status); -} - -void -DecimalFormatImpl::updateForApplyPatternFavorCurrencyPrecision( - UErrorCode &status) { - updateAll(kFormattingAll & ~kFormattingSymbols, TRUE, status); -} - -void -DecimalFormatImpl::updateForApplyPattern(UErrorCode &status) { - updateAll(kFormattingAll & ~kFormattingSymbols, FALSE, status); -} - -void -DecimalFormatImpl::updateAll(UErrorCode &status) { - updateAll(kFormattingAll, TRUE, status); -} - -void -DecimalFormatImpl::updateAll( - int32_t formattingFlags, - UBool updatePrecisionBasedOnCurrency, - UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - updatePrecision(); - updateGrouping(); - updateFormatting( - formattingFlags, updatePrecisionBasedOnCurrency, status); - setMultiplierScale(getPatternScale()); -} - - -static int32_t -getMinimumLengthToDescribeGrouping(const DigitGrouping &grouping) { - if (grouping.fGrouping <= 0) { - return 0; - } - if (grouping.fGrouping2 <= 0) { - return grouping.fGrouping + 1; - } - return grouping.fGrouping + grouping.fGrouping2 + 1; -} - -/** - * Given a grouping policy, calculates how many digits are needed left of - * the decimal point to achieve a desired length left of the - * decimal point. - * @param grouping the grouping policy - * @param desiredLength number of characters needed left of decimal point - * @param minLeftDigits at least this many digits is returned - * @param leftDigits the number of digits needed stored here - * which is >= minLeftDigits. - * @return true if a perfect fit or false if having leftDigits would exceed - * desiredLength - */ -static UBool -getLeftDigitsForLeftLength( - const DigitGrouping &grouping, - int32_t desiredLength, - int32_t minLeftDigits, - int32_t &leftDigits) { - leftDigits = minLeftDigits; - int32_t lengthSoFar = leftDigits + grouping.getSeparatorCount(leftDigits); - while (lengthSoFar < desiredLength) { - lengthSoFar += grouping.isSeparatorAt(leftDigits + 1, leftDigits) ? 2 : 1; - ++leftDigits; - } - return (lengthSoFar == desiredLength); -} - -int32_t -DecimalFormatImpl::computeExponentPatternLength() const { - if (fUseScientific) { - return 1 + (fOptions.fExponent.fAlwaysShowSign ? 1 : 0) + fEffPrecision.fMinExponentDigits; - } - return 0; -} - -int32_t -DecimalFormatImpl::countFractionDigitAndDecimalPatternLength( - int32_t fracDigitCount) const { - if (!fOptions.fMantissa.fAlwaysShowDecimal && fracDigitCount == 0) { - return 0; - } - return fracDigitCount + 1; -} - -UnicodeString& -DecimalFormatImpl::toNumberPattern( - UBool hasPadding, int32_t minimumLength, UnicodeString& result) const { - // Get a grouping policy like the one in this object that does not - // have minimum grouping since toPattern doesn't support it. - DigitGrouping grouping(fEffGrouping); - grouping.fMinGrouping = 0; - - // Only for fixed digits, these are the digits that get 0's. - DigitInterval minInterval; - - // Only for fixed digits, these are the digits that get #'s. - DigitInterval maxInterval; - - // Only for significant digits - int32_t sigMin = 0; /* initialize to avoid compiler warning */ - int32_t sigMax = 0; /* initialize to avoid compiler warning */ - - // These are all the digits to be displayed. For significant digits, - // this interval always starts at the 1's place an extends left. - DigitInterval fullInterval; - - // Digit range of rounding increment. If rounding increment is .025. - // then roundingIncrementLowerExp = -3 and roundingIncrementUpperExp = -1 - int32_t roundingIncrementLowerExp = 0; - int32_t roundingIncrementUpperExp = 0; - - if (fUseSigDigits) { - SignificantDigitInterval sigInterval; - extractSigDigits(sigInterval); - sigMax = sigInterval.getMax(); - sigMin = sigInterval.getMin(); - fullInterval.setFracDigitCount(0); - fullInterval.setIntDigitCount(sigMax); - } else { - extractMinMaxDigits(minInterval, maxInterval); - if (fUseScientific) { - if (maxInterval.getIntDigitCount() > kMaxScientificIntegerDigits) { - maxInterval.setIntDigitCount(1); - minInterval.shrinkToFitWithin(maxInterval); - } - } else if (hasPadding) { - // Make max int digits match min int digits for now, we - // compute necessary padding later. - maxInterval.setIntDigitCount(minInterval.getIntDigitCount()); - } else { - // For some reason toPattern adds at least one leading '#' - maxInterval.setIntDigitCount(minInterval.getIntDigitCount() + 1); - } - if (!fEffPrecision.fMantissa.fRoundingIncrement.isZero()) { - roundingIncrementLowerExp = - fEffPrecision.fMantissa.fRoundingIncrement.getLowerExponent(); - roundingIncrementUpperExp = - fEffPrecision.fMantissa.fRoundingIncrement.getUpperExponent(); - // We have to include the rounding increment in what we display - maxInterval.expandToContainDigit(roundingIncrementLowerExp); - maxInterval.expandToContainDigit(roundingIncrementUpperExp - 1); - } - fullInterval = maxInterval; - } - // We have to include enough digits to show grouping strategy - int32_t minLengthToDescribeGrouping = - getMinimumLengthToDescribeGrouping(grouping); - if (minLengthToDescribeGrouping > 0) { - fullInterval.expandToContainDigit( - getMinimumLengthToDescribeGrouping(grouping) - 1); - } - - // If we have a minimum length, we have to add digits to the left to - // depict padding. - if (hasPadding) { - // For non scientific notation, - // minimumLengthForMantissa = minimumLength - int32_t minimumLengthForMantissa = - minimumLength - computeExponentPatternLength(); - int32_t mininumLengthForMantissaIntPart = - minimumLengthForMantissa - - countFractionDigitAndDecimalPatternLength( - fullInterval.getFracDigitCount()); - // Because of grouping, we may need fewer than expected digits to - // achieve the length we need. - int32_t digitsNeeded; - if (getLeftDigitsForLeftLength( - grouping, - mininumLengthForMantissaIntPart, - fullInterval.getIntDigitCount(), - digitsNeeded)) { - - // In this case, we achieved the exact length that we want. - fullInterval.setIntDigitCount(digitsNeeded); - } else if (digitsNeeded > fullInterval.getIntDigitCount()) { - - // Having digitsNeeded digits goes over desired length which - // means that to have desired length would mean starting on a - // grouping sepearator e.g ,###,### so add a '#' and use one - // less digit. This trick gives ####,### but that is the best - // we can do. - result.append(kPatternDigit); - fullInterval.setIntDigitCount(digitsNeeded - 1); - } - } - int32_t maxDigitPos = fullInterval.getMostSignificantExclusive(); - int32_t minDigitPos = fullInterval.getLeastSignificantInclusive(); - for (int32_t i = maxDigitPos - 1; i >= minDigitPos; --i) { - if (!fOptions.fMantissa.fAlwaysShowDecimal && i == -1) { - result.append(kPatternDecimalSeparator); - } - if (fUseSigDigits) { - // Use digit symbol - if (i >= sigMax || i < sigMax - sigMin) { - result.append(kPatternDigit); - } else { - result.append(kPatternSignificantDigit); - } - } else { - if (i < roundingIncrementUpperExp && i >= roundingIncrementLowerExp) { - result.append((UChar)(fEffPrecision.fMantissa.fRoundingIncrement.getDigitByExponent(i) + kPatternZeroDigit)); - } else if (minInterval.contains(i)) { - result.append(kPatternZeroDigit); - } else { - result.append(kPatternDigit); - } - } - if (grouping.isSeparatorAt(i + 1, i)) { - result.append(kPatternGroupingSeparator); - } - if (fOptions.fMantissa.fAlwaysShowDecimal && i == 0) { - result.append(kPatternDecimalSeparator); - } - } - if (fUseScientific) { - result.append(kPatternExponent); - if (fOptions.fExponent.fAlwaysShowSign) { - result.append(kPatternPlus); - } - for (int32_t i = 0; i < 1 || i < fEffPrecision.fMinExponentDigits; ++i) { - result.append(kPatternZeroDigit); - } - } - return result; -} - -UnicodeString& -DecimalFormatImpl::toPattern(UnicodeString& result) const { - result.remove(); - UnicodeString padSpec; - if (fAffixes.fWidth > 0) { - padSpec.append(kPatternPadEscape); - padSpec.append(fAffixes.fPadChar); - } - if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) { - result.append(padSpec); - } - fPositivePrefixPattern.toUserString(result); - if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) { - result.append(padSpec); - } - toNumberPattern( - fAffixes.fWidth > 0, - fAffixes.fWidth - fPositivePrefixPattern.countChar32() - fPositiveSuffixPattern.countChar32(), - result); - if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) { - result.append(padSpec); - } - fPositiveSuffixPattern.toUserString(result); - if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) { - result.append(padSpec); - } - AffixPattern withNegative; - withNegative.add(AffixPattern::kNegative); - withNegative.append(fPositivePrefixPattern); - if (!fPositiveSuffixPattern.equals(fNegativeSuffixPattern) || - !withNegative.equals(fNegativePrefixPattern)) { - result.append(kPatternSeparator); - if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) { - result.append(padSpec); - } - fNegativePrefixPattern.toUserString(result); - if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) { - result.append(padSpec); - } - toNumberPattern( - fAffixes.fWidth > 0, - fAffixes.fWidth - fNegativePrefixPattern.countChar32() - fNegativeSuffixPattern.countChar32(), - result); - if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) { - result.append(padSpec); - } - fNegativeSuffixPattern.toUserString(result); - if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) { - result.append(padSpec); - } - } - return result; -} - -int32_t -DecimalFormatImpl::getOldFormatWidth() const { - if (fAffixes.fWidth == 0) { - return 0; - } - return fAffixes.fWidth - fPositiveSuffixPattern.countChar32() - fPositivePrefixPattern.countChar32(); -} - -const UnicodeString & -DecimalFormatImpl::getConstSymbol( - DecimalFormatSymbols::ENumberFormatSymbol symbol) const { - return fSymbols->getConstSymbol(symbol); -} - -UBool -DecimalFormatImpl::isParseFastpath() const { - AffixPattern negative; - negative.add(AffixPattern::kNegative); - - return fAffixes.fWidth == 0 && - fPositivePrefixPattern.countChar32() == 0 && - fNegativePrefixPattern.equals(negative) && - fPositiveSuffixPattern.countChar32() == 0 && - fNegativeSuffixPattern.countChar32() == 0; -} - - -U_NAMESPACE_END - -#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/decimfmtimpl.h b/deps/icu-small/source/i18n/decimfmtimpl.h deleted file mode 100644 index b4438cba9e..0000000000 --- a/deps/icu-small/source/i18n/decimfmtimpl.h +++ /dev/null @@ -1,549 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************** -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************** -* -* File decimfmtimpl.h -******************************************************************************** -*/ - -#ifndef DECIMFMTIMPL_H -#define DECIMFMTIMPL_H - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/decimfmt.h" -#include "unicode/uobject.h" -#include "affixpatternparser.h" -#include "digitaffixesandpadding.h" -#include "digitformatter.h" -#include "digitgrouping.h" -#include "precision.h" - -U_NAMESPACE_BEGIN - -class UnicodeString; -class FieldPosition; -class ValueFormatter; -class FieldPositionHandler; -class FixedDecimal; - -/** - * DecimalFormatImpl is the glue code between the legacy DecimalFormat class - * and the new decimal formatting classes. DecimalFormat still handles - * parsing directly. However, DecimalFormat uses attributes of this class - * for parsing when possible. - * - * The public API of this class closely mirrors the legacy API of the - * legacy DecimalFormat deviating only when the legacy API does not make - * sense. For example, although DecimalFormat has a - * getPadCharacterString() method, DecimalFormatImpl has a getPadCharacter() - * method because formatting uses only a single pad character for padding. - * - * Each legacy DecimalFormat instance heap allocates its own instance of - * this class. Most DecimalFormat methods that deal with formatting simply - * delegate to the DecimalFormat's DecimalFormatImpl method. - * - * Because DecimalFormat extends NumberFormat, Each instance of this class - * "borrows" a pointer to the NumberFormat part of its enclosing DecimalFormat - * instance. This way each DecimalFormatImpl instance can read or even modify - * the NumberFormat portion of its enclosing DecimalFormat instance. - * - * Directed acyclic graph (DAG): - * - * This class can be represented as a directed acyclic graph (DAG) where each - * vertex is an attribute, and each directed edge indicates that the value - * of the destination attribute is calculated from the value of the source - * attribute. Attributes with setter methods reside at the bottom of the - * DAG. That is, no edges point to them. We call these independent attributes - * because their values can be set independently of one another. The rest of - * the attributes are derived attributes because their values depend on the - * independent attributes. DecimalFormatImpl often uses the derived - * attributes, not the independent attributes, when formatting numbers. - * - * The independent attributes at the bottom of the DAG correspond to the legacy - * attributes of DecimalFormat while the attributes at the top of the DAG - * correspond to the attributes of the new code. The edges of the DAG - * correspond to the code that handles the complex interaction among all the - * legacy attributes of the DecimalFormat API. - * - * We use a DAG for three reasons. - * - * First, the DAG preserves backward compatibility. Clients of the legacy - * DecimalFormat expect existing getters and setters of each attribute to be - * consistent. That means if a client sets a particular attribute to a new - * value, the attribute should retain that value until the client sets it to - * a new value. The DAG allows these attributes to remain consistent even - * though the new code may not use them when formatting. - * - * Second, the DAG obviates the need to recalculate derived attributes with - * each format. Instead, the DAG "remembers" the values of all derived - * attributes. Only setting an independent attribute requires a recalculation. - * Moreover, setting an independent attribute recalculates only the affected - * dependent attributes rather than all dependent attributes. - * - * Third, the DAG abstracts away the complex interaction among the legacy - * attributes of the DecimalFormat API. - * - * Only the independent attributes of the DAG have setters and getters. - * Derived attributes have no setters (and often no getters either). - * - * Copy and assign: - * - * For copy and assign, DecimalFormatImpl copies and assigns every attribute - * regardless of whether or not it is independent. We do this for simplicity. - * - * Implementation of the DAG: - * - * The DAG consists of three smaller DAGs: - * 1. Grouping attributes - * 2. Precision attributes - * 3. Formatting attributes. - * - * The first two DAGs are simple in that setting any independent attribute - * in the DAG recalculates all the dependent attributes in that DAG. - * The updateGrouping() and updatePrecision() perform the respective - * recalculations. - * - * Because some of the derived formatting attributes are expensive to - * calculate, the formatting attributes DAG is more complex. The - * updateFormatting() method is composed of many updateFormattingXXX() - * methods, each of which recalculates a single derived attribute. The - * updateFormatting() method accepts a bitfield of recently changed - * attributes and passes this bitfield by reference to each of the - * updateFormattingXXX() methods. Each updateFormattingXXX() method checks - * the bitfield to see if any of the attributes it uses to compute the XXX - * attribute changed. If none of them changed, it exists immediately. However, - * if at least one of them changed, it recalculates the XXX attribute and - * sets the corresponding bit in the bitfield. In this way, each - * updateFormattingXXX() method encodes the directed edges in the formatting - * DAG that point to the attribute its calculating. - * - * Maintenance of the updateFormatting() method. - * - * Use care when changing the updateFormatting() method. - * The updateFormatting() method must call each updateFormattingXXX() in the - * same partial order that the formatting DAG prescribes. That is, the - * attributes near the bottom of the DAG must be calculated before attributes - * further up. As we mentioned in the prvious paragraph, the directed edges of - * the formatting DAG are encoded within each updateFormattingXXX() method. - * Finally, adding new attributes may involve adding to the bitmap that the - * updateFormatting() method uses. The top most attributes in the DAG, - * those that do not point to any attributes but only have attributes - * pointing to it, need not have a slot in the bitmap. - * - * Keep in mind that most of the code that makes the legacy DecimalFormat API - * work the way it always has before can be found in these various updateXXX() - * methods. For example the updatePrecisionForScientific() method - * handles the complex interactions amoung the various precision attributes - * when formatting in scientific notation. Changing the way attributes - * interract, often means changing one of these updateXXX() methods. - * - * Conclusion: - * - * The DecimFmtImpl class is the glue code between the legacy and new - * number formatting code. It uses a direct acyclic graph (DAG) to - * maintain backward compatibility, to make the code efficient, and to - * abstract away the complex interraction among legacy attributs. - */ - - -class DecimalFormatImpl : public UObject { -public: - -DecimalFormatImpl( - NumberFormat *super, - const Locale &locale, - const UnicodeString &pattern, - UErrorCode &status); -DecimalFormatImpl( - NumberFormat *super, - const UnicodeString &pattern, - DecimalFormatSymbols *symbolsToAdopt, - UParseError &parseError, - UErrorCode &status); -DecimalFormatImpl( - NumberFormat *super, - const DecimalFormatImpl &other, - UErrorCode &status); -DecimalFormatImpl &assign( - const DecimalFormatImpl &other, UErrorCode &status); -virtual ~DecimalFormatImpl(); -void adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt); -const DecimalFormatSymbols &getDecimalFormatSymbols() const { - return *fSymbols; -} -UnicodeString &format( - int32_t number, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const; -UnicodeString &format( - int32_t number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const; -UnicodeString &format( - int64_t number, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const; -UnicodeString &format( - double number, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const; -UnicodeString &format( - const DigitList &number, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const; -UnicodeString &format( - int64_t number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const; -UnicodeString &format( - double number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const; -UnicodeString &format( - const DigitList &number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const; -UnicodeString &format( - StringPiece number, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const; -UnicodeString &format( - const VisibleDigitsWithExponent &digits, - UnicodeString &appendTo, - FieldPosition &pos, - UErrorCode &status) const; -UnicodeString &format( - const VisibleDigitsWithExponent &digits, - UnicodeString &appendTo, - FieldPositionIterator *posIter, - UErrorCode &status) const; - -UBool operator==(const DecimalFormatImpl &) const; - -UBool operator!=(const DecimalFormatImpl &other) const { - return !(*this == other); -} - -void setRoundingMode(DecimalFormat::ERoundingMode mode) { - fRoundingMode = mode; - fEffPrecision.fMantissa.fExactOnly = (fRoundingMode == DecimalFormat::kRoundUnnecessary); - fEffPrecision.fMantissa.fRoundingMode = mode; -} -DecimalFormat::ERoundingMode getRoundingMode() const { - return fRoundingMode; -} -void setFailIfMoreThanMaxDigits(UBool b) { - fEffPrecision.fMantissa.fFailIfOverMax = b; -} -UBool isFailIfMoreThanMaxDigits() const { return fEffPrecision.fMantissa.fFailIfOverMax; } -void setMinimumSignificantDigits(int32_t newValue); -void setMaximumSignificantDigits(int32_t newValue); -void setMinMaxSignificantDigits(int32_t min, int32_t max); -void setScientificNotation(UBool newValue); -void setSignificantDigitsUsed(UBool newValue); - -int32_t getMinimumSignificantDigits() const { - return fMinSigDigits; } -int32_t getMaximumSignificantDigits() const { - return fMaxSigDigits; } -UBool isScientificNotation() const { return fUseScientific; } -UBool areSignificantDigitsUsed() const { return fUseSigDigits; } -void setGroupingSize(int32_t newValue); -void setSecondaryGroupingSize(int32_t newValue); -void setMinimumGroupingDigits(int32_t newValue); -int32_t getGroupingSize() const { return fGrouping.fGrouping; } -int32_t getSecondaryGroupingSize() const { return fGrouping.fGrouping2; } -int32_t getMinimumGroupingDigits() const { return fGrouping.fMinGrouping; } -void applyPattern(const UnicodeString &pattern, UErrorCode &status); -void applyPatternFavorCurrencyPrecision( - const UnicodeString &pattern, UErrorCode &status); -void applyPattern( - const UnicodeString &pattern, UParseError &perror, UErrorCode &status); -void applyLocalizedPattern(const UnicodeString &pattern, UErrorCode &status); -void applyLocalizedPattern( - const UnicodeString &pattern, UParseError &perror, UErrorCode &status); -void setCurrencyUsage(UCurrencyUsage usage, UErrorCode &status); -UCurrencyUsage getCurrencyUsage() const { return fCurrencyUsage; } -void setRoundingIncrement(double d); -double getRoundingIncrement() const; -int32_t getMultiplier() const; -void setMultiplier(int32_t m); -UChar32 getPadCharacter() const { return fAffixes.fPadChar; } -void setPadCharacter(UChar32 c) { fAffixes.fPadChar = c; } -int32_t getFormatWidth() const { return fAffixes.fWidth; } -void setFormatWidth(int32_t x) { fAffixes.fWidth = x; } -DigitAffixesAndPadding::EPadPosition getPadPosition() const { - return fAffixes.fPadPosition; -} -void setPadPosition(DigitAffixesAndPadding::EPadPosition x) { - fAffixes.fPadPosition = x; -} -int32_t getMinimumExponentDigits() const { - return fEffPrecision.fMinExponentDigits; -} -void setMinimumExponentDigits(int32_t x) { - fEffPrecision.fMinExponentDigits = x; -} -UBool isExponentSignAlwaysShown() const { - return fOptions.fExponent.fAlwaysShowSign; -} -void setExponentSignAlwaysShown(UBool x) { - fOptions.fExponent.fAlwaysShowSign = x; -} -UBool isDecimalSeparatorAlwaysShown() const { - return fOptions.fMantissa.fAlwaysShowDecimal; -} -void setDecimalSeparatorAlwaysShown(UBool x) { - fOptions.fMantissa.fAlwaysShowDecimal = x; -} -UnicodeString &getPositivePrefix(UnicodeString &result) const; -UnicodeString &getPositiveSuffix(UnicodeString &result) const; -UnicodeString &getNegativePrefix(UnicodeString &result) const; -UnicodeString &getNegativeSuffix(UnicodeString &result) const; -void setPositivePrefix(const UnicodeString &str); -void setPositiveSuffix(const UnicodeString &str); -void setNegativePrefix(const UnicodeString &str); -void setNegativeSuffix(const UnicodeString &str); -UnicodeString &toPattern(UnicodeString& result) const; -FixedDecimal &getFixedDecimal(double value, FixedDecimal &result, UErrorCode &status) const; -FixedDecimal &getFixedDecimal(DigitList &number, FixedDecimal &result, UErrorCode &status) const; -DigitList &round(DigitList &number, UErrorCode &status) const; - -VisibleDigitsWithExponent & -initVisibleDigitsWithExponent( - int64_t number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; -VisibleDigitsWithExponent & -initVisibleDigitsWithExponent( - double number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; -VisibleDigitsWithExponent & -initVisibleDigitsWithExponent( - DigitList &number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - -void updatePrecision(); -void updateGrouping(); -void updateCurrency(UErrorCode &status); - - -private: -// Disallow copy and assign -DecimalFormatImpl(const DecimalFormatImpl &other); -DecimalFormatImpl &operator=(const DecimalFormatImpl &other); -NumberFormat *fSuper; -DigitList fMultiplier; -int32_t fScale; - -DecimalFormat::ERoundingMode fRoundingMode; - -// These fields include what the user can see and set. -// When the user updates these fields, it triggers automatic updates of -// other fields that may be invisible to user - -// Updating any of the following fields triggers an update to -// fEffPrecision.fMantissa.fMin, -// fEffPrecision.fMantissa.fMax, -// fEffPrecision.fMantissa.fSignificant fields -// We have this two phase update because of backward compatibility. -// DecimalFormat has to remember all settings even if those settings are -// invalid or disabled. -int32_t fMinSigDigits; -int32_t fMaxSigDigits; -UBool fUseScientific; -UBool fUseSigDigits; -// In addition to these listed above, changes to min/max int digits and -// min/max frac digits from fSuper also trigger an update. - -// Updating any of the following fields triggers an update to -// fEffGrouping field Again we do it this way because original -// grouping settings have to be retained if grouping is turned off. -DigitGrouping fGrouping; -// In addition to these listed above, changes to isGroupingUsed in -// fSuper also triggers an update to fEffGrouping. - -// Updating any of the following fields triggers updates on the following: -// fMonetary, fRules, fAffixParser, fCurrencyAffixInfo, -// fFormatter, fAffixes.fPositivePrefiix, fAffixes.fPositiveSuffix, -// fAffixes.fNegativePrefiix, fAffixes.fNegativeSuffix -// We do this two phase update because localizing the affix patterns -// and formatters can be expensive. Better to do it once with the setters -// than each time within format. -AffixPattern fPositivePrefixPattern; -AffixPattern fNegativePrefixPattern; -AffixPattern fPositiveSuffixPattern; -AffixPattern fNegativeSuffixPattern; -DecimalFormatSymbols *fSymbols; -UCurrencyUsage fCurrencyUsage; -// In addition to these listed above, changes to getCurrency() in -// fSuper also triggers an update. - -// Optional may be NULL -PluralRules *fRules; - -// These fields are totally hidden from user and are used to derive the affixes -// in fAffixes below from the four affix patterns above. -UBool fMonetary; -AffixPatternParser fAffixParser; -CurrencyAffixInfo fCurrencyAffixInfo; - -// The actual precision used when formatting -ScientificPrecision fEffPrecision; - -// The actual grouping used when formatting -DigitGrouping fEffGrouping; -SciFormatterOptions fOptions; // Encapsulates fixed precision options -DigitFormatter fFormatter; -DigitAffixesAndPadding fAffixes; - -UnicodeString &formatInt32( - int32_t number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const; - -UnicodeString &formatInt64( - int64_t number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const; - -UnicodeString &formatDouble( - double number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const; - -// Scales for precent or permille symbols -UnicodeString &formatDigitList( - DigitList &number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const; - -// Does not scale for precent or permille symbols -UnicodeString &formatAdjustedDigitList( - DigitList &number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const; - -UnicodeString &formatVisibleDigitsWithExponent( - const VisibleDigitsWithExponent &number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const; - -VisibleDigitsWithExponent & -initVisibleDigitsFromAdjusted( - DigitList &number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - -template -UBool maybeFormatWithDigitList( - T number, - UnicodeString &appendTo, - FieldPositionHandler &handler, - UErrorCode &status) const; - -template -UBool maybeInitVisibleDigitsFromDigitList( - T number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - -DigitList &adjustDigitList(DigitList &number, UErrorCode &status) const; - -void applyPattern( - const UnicodeString &pattern, - UBool localized, UParseError &perror, UErrorCode &status); - -ValueFormatter &prepareValueFormatter(ValueFormatter &vf) const; -void setMultiplierScale(int32_t s); -int32_t getPatternScale() const; -void setScale(int32_t s) { fScale = s; } -int32_t getScale() const { return fScale; } - -// Updates everything -void updateAll(UErrorCode &status); -void updateAll( - int32_t formattingFlags, - UBool updatePrecisionBasedOnCurrency, - UErrorCode &status); - -// Updates from formatting pattern changes -void updateForApplyPattern(UErrorCode &status); -void updateForApplyPatternFavorCurrencyPrecision(UErrorCode &status); - -// Updates from changes to third group of attributes -void updateFormatting(int32_t changedFormattingFields, UErrorCode &status); -void updateFormatting( - int32_t changedFormattingFields, - UBool updatePrecisionBasedOnCurrency, - UErrorCode &status); - -// Helper functions for updatePrecision -void updatePrecisionForScientific(); -void updatePrecisionForFixed(); -void extractMinMaxDigits(DigitInterval &min, DigitInterval &max) const; -void extractSigDigits(SignificantDigitInterval &sig) const; - -// Helper functions for updateFormatting -void updateFormattingUsesCurrency(int32_t &changedFormattingFields); -void updateFormattingPluralRules( - int32_t &changedFormattingFields, UErrorCode &status); -void updateFormattingAffixParser(int32_t &changedFormattingFields); -void updateFormattingCurrencyAffixInfo( - int32_t &changedFormattingFields, - UBool updatePrecisionBasedOnCurrency, - UErrorCode &status); -void updateFormattingFixedPointFormatter( - int32_t &changedFormattingFields); -void updateFormattingLocalizedPositivePrefix( - int32_t &changedFormattingFields, UErrorCode &status); -void updateFormattingLocalizedPositiveSuffix( - int32_t &changedFormattingFields, UErrorCode &status); -void updateFormattingLocalizedNegativePrefix( - int32_t &changedFormattingFields, UErrorCode &status); -void updateFormattingLocalizedNegativeSuffix( - int32_t &changedFormattingFields, UErrorCode &status); - -int32_t computeExponentPatternLength() const; -int32_t countFractionDigitAndDecimalPatternLength(int32_t fracDigitCount) const; -UnicodeString &toNumberPattern( - UBool hasPadding, int32_t minimumLength, UnicodeString& result) const; - -int32_t getOldFormatWidth() const; -const UnicodeString &getConstSymbol( - DecimalFormatSymbols::ENumberFormatSymbol symbol) const; -UBool isParseFastpath() const; - -friend class DecimalFormat; - -}; - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ -#endif // DECIMFMTIMPL_H -//eof diff --git a/deps/icu-small/source/i18n/digitaffix.cpp b/deps/icu-small/source/i18n/digitaffix.cpp deleted file mode 100644 index 396df2cf1d..0000000000 --- a/deps/icu-small/source/i18n/digitaffix.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: digitaffix.cpp - */ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "digitaffix.h" -#include "fphdlimp.h" -#include "uassert.h" -#include "unistrappender.h" - -U_NAMESPACE_BEGIN - -DigitAffix::DigitAffix() : fAffix(), fAnnotations() { -} - -DigitAffix::DigitAffix( - const UChar *value, int32_t charCount, int32_t fieldId) - : fAffix(value, charCount), - fAnnotations(charCount, (UChar) fieldId, charCount) { -} - -void -DigitAffix::remove() { - fAffix.remove(); - fAnnotations.remove(); -} - -void -DigitAffix::appendUChar(UChar value, int32_t fieldId) { - fAffix.append(value); - fAnnotations.append((UChar) fieldId); -} - -void -DigitAffix::append(const UnicodeString &value, int32_t fieldId) { - fAffix.append(value); - { - UnicodeStringAppender appender(fAnnotations); - int32_t len = value.length(); - for (int32_t i = 0; i < len; ++i) { - appender.append((UChar) fieldId); - } - } -} - -void -DigitAffix::setTo(const UnicodeString &value, int32_t fieldId) { - fAffix = value; - fAnnotations.remove(); - { - UnicodeStringAppender appender(fAnnotations); - int32_t len = value.length(); - for (int32_t i = 0; i < len; ++i) { - appender.append((UChar) fieldId); - } - } -} - -void -DigitAffix::append(const UChar *value, int32_t charCount, int32_t fieldId) { - fAffix.append(value, charCount); - { - UnicodeStringAppender appender(fAnnotations); - for (int32_t i = 0; i < charCount; ++i) { - appender.append((UChar) fieldId); - } - } -} - -UnicodeString & -DigitAffix::format(FieldPositionHandler &handler, UnicodeString &appendTo) const { - int32_t len = fAffix.length(); - if (len == 0) { - return appendTo; - } - if (!handler.isRecording()) { - return appendTo.append(fAffix); - } - U_ASSERT(fAffix.length() == fAnnotations.length()); - int32_t appendToStart = appendTo.length(); - int32_t lastId = (int32_t) fAnnotations.charAt(0); - int32_t lastIdStart = 0; - for (int32_t i = 1; i < len; ++i) { - int32_t id = (int32_t) fAnnotations.charAt(i); - if (id != lastId) { - if (lastId != UNUM_FIELD_COUNT) { - handler.addAttribute(lastId, appendToStart + lastIdStart, appendToStart + i); - } - lastId = id; - lastIdStart = i; - } - } - if (lastId != UNUM_FIELD_COUNT) { - handler.addAttribute(lastId, appendToStart + lastIdStart, appendToStart + len); - } - return appendTo.append(fAffix); -} - -U_NAMESPACE_END - -#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/digitaffix.h b/deps/icu-small/source/i18n/digitaffix.h deleted file mode 100644 index 005c36f848..0000000000 --- a/deps/icu-small/source/i18n/digitaffix.h +++ /dev/null @@ -1,104 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* digitaffix.h -* -* created on: 2015jan06 -* created by: Travis Keep -*/ - -#ifndef __DIGITAFFIX_H__ -#define __DIGITAFFIX_H__ - -#include "unicode/uobject.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/unistr.h" -#include "unicode/unum.h" -#include "unicode/utypes.h" - -U_NAMESPACE_BEGIN - -class FieldPositionHandler; - -/** - * A prefix or suffix of a formatted number. - */ -class U_I18N_API DigitAffix : public UMemory { -public: - - /** - * Creates an empty DigitAffix. - */ - DigitAffix(); - - /** - * Creates a DigitAffix containing given UChars where all of it has - * a field type of fieldId. - */ - DigitAffix( - const UChar *value, - int32_t charCount, - int32_t fieldId=UNUM_FIELD_COUNT); - - /** - * Makes this affix be the empty string. - */ - void remove(); - - /** - * Append value to this affix. If fieldId is present, the appended - * string is considered to be the type fieldId. - */ - void appendUChar(UChar value, int32_t fieldId=UNUM_FIELD_COUNT); - - /** - * Append value to this affix. If fieldId is present, the appended - * string is considered to be the type fieldId. - */ - void append(const UnicodeString &value, int32_t fieldId=UNUM_FIELD_COUNT); - - /** - * Sets this affix to given string. The entire string - * is considered to be the type fieldId. - */ - void setTo(const UnicodeString &value, int32_t fieldId=UNUM_FIELD_COUNT); - - /** - * Append value to this affix. If fieldId is present, the appended - * string is considered to be the type fieldId. - */ - void append(const UChar *value, int32_t charCount, int32_t fieldId=UNUM_FIELD_COUNT); - - /** - * Formats this affix. - */ - UnicodeString &format( - FieldPositionHandler &handler, UnicodeString &appendTo) const; - int32_t countChar32() const { return fAffix.countChar32(); } - - /** - * Returns this affix as a unicode string. - */ - const UnicodeString & toString() const { return fAffix; } - - /** - * Returns TRUE if this object equals rhs. - */ - UBool equals(const DigitAffix &rhs) const { - return ((fAffix == rhs.fAffix) && (fAnnotations == rhs.fAnnotations)); - } -private: - UnicodeString fAffix; - UnicodeString fAnnotations; -}; - - -U_NAMESPACE_END -#endif // #if !UCONFIG_NO_FORMATTING -#endif // __DIGITAFFIX_H__ diff --git a/deps/icu-small/source/i18n/digitaffixesandpadding.cpp b/deps/icu-small/source/i18n/digitaffixesandpadding.cpp deleted file mode 100644 index 487d9a345d..0000000000 --- a/deps/icu-small/source/i18n/digitaffixesandpadding.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: digitaffixesandpadding.cpp - */ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/plurrule.h" -#include "charstr.h" -#include "digitaffix.h" -#include "digitaffixesandpadding.h" -#include "digitlst.h" -#include "uassert.h" -#include "valueformatter.h" -#include "visibledigits.h" - -U_NAMESPACE_BEGIN - -UBool -DigitAffixesAndPadding::needsPluralRules() const { - return ( - fPositivePrefix.hasMultipleVariants() || - fPositiveSuffix.hasMultipleVariants() || - fNegativePrefix.hasMultipleVariants() || - fNegativeSuffix.hasMultipleVariants()); -} - -UnicodeString & -DigitAffixesAndPadding::formatInt32( - int32_t value, - const ValueFormatter &formatter, - FieldPositionHandler &handler, - const PluralRules *optPluralRules, - UnicodeString &appendTo, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return appendTo; - } - if (optPluralRules != NULL || fWidth > 0 || !formatter.isFastFormattable(value)) { - VisibleDigitsWithExponent digits; - formatter.toVisibleDigitsWithExponent( - (int64_t) value, digits, status); - return format( - digits, - formatter, - handler, - optPluralRules, - appendTo, - status); - } - UBool bPositive = value >= 0; - const DigitAffix *prefix = bPositive ? &fPositivePrefix.getOtherVariant() : &fNegativePrefix.getOtherVariant(); - const DigitAffix *suffix = bPositive ? &fPositiveSuffix.getOtherVariant() : &fNegativeSuffix.getOtherVariant(); - if (value < 0) { - value = -value; - } - prefix->format(handler, appendTo); - formatter.formatInt32(value, handler, appendTo); - return suffix->format(handler, appendTo); -} - -static UnicodeString & -formatAffix( - const DigitAffix *affix, - FieldPositionHandler &handler, - UnicodeString &appendTo) { - if (affix) { - affix->format(handler, appendTo); - } - return appendTo; -} - -static int32_t -countAffixChar32(const DigitAffix *affix) { - if (affix) { - return affix->countChar32(); - } - return 0; -} - -UnicodeString & -DigitAffixesAndPadding::format( - const VisibleDigitsWithExponent &digits, - const ValueFormatter &formatter, - FieldPositionHandler &handler, - const PluralRules *optPluralRules, - UnicodeString &appendTo, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return appendTo; - } - const DigitAffix *prefix = NULL; - const DigitAffix *suffix = NULL; - if (!digits.isNaN()) { - UBool bPositive = !digits.isNegative(); - const PluralAffix *pluralPrefix = bPositive ? &fPositivePrefix : &fNegativePrefix; - const PluralAffix *pluralSuffix = bPositive ? &fPositiveSuffix : &fNegativeSuffix; - if (optPluralRules == NULL || digits.isInfinite()) { - prefix = &pluralPrefix->getOtherVariant(); - suffix = &pluralSuffix->getOtherVariant(); - } else { - UnicodeString count(optPluralRules->select(digits)); - prefix = &pluralPrefix->getByCategory(count); - suffix = &pluralSuffix->getByCategory(count); - } - } - if (fWidth <= 0) { - formatAffix(prefix, handler, appendTo); - formatter.format(digits, handler, appendTo); - return formatAffix(suffix, handler, appendTo); - } - int32_t codePointCount = countAffixChar32(prefix) + formatter.countChar32(digits) + countAffixChar32(suffix); - int32_t paddingCount = fWidth - codePointCount; - switch (fPadPosition) { - case kPadBeforePrefix: - appendPadding(paddingCount, appendTo); - formatAffix(prefix, handler, appendTo); - formatter.format(digits, handler, appendTo); - return formatAffix(suffix, handler, appendTo); - case kPadAfterPrefix: - formatAffix(prefix, handler, appendTo); - appendPadding(paddingCount, appendTo); - formatter.format(digits, handler, appendTo); - return formatAffix(suffix, handler, appendTo); - case kPadBeforeSuffix: - formatAffix(prefix, handler, appendTo); - formatter.format(digits, handler, appendTo); - appendPadding(paddingCount, appendTo); - return formatAffix(suffix, handler, appendTo); - case kPadAfterSuffix: - formatAffix(prefix, handler, appendTo); - formatter.format(digits, handler, appendTo); - formatAffix(suffix, handler, appendTo); - return appendPadding(paddingCount, appendTo); - default: - U_ASSERT(FALSE); - return appendTo; - } -} - -UnicodeString & -DigitAffixesAndPadding::format( - DigitList &value, - const ValueFormatter &formatter, - FieldPositionHandler &handler, - const PluralRules *optPluralRules, - UnicodeString &appendTo, - UErrorCode &status) const { - VisibleDigitsWithExponent digits; - formatter.toVisibleDigitsWithExponent( - value, digits, status); - if (U_FAILURE(status)) { - return appendTo; - } - return format( - digits, formatter, handler, optPluralRules, appendTo, status); -} - -UnicodeString & -DigitAffixesAndPadding::appendPadding(int32_t paddingCount, UnicodeString &appendTo) const { - for (int32_t i = 0; i < paddingCount; ++i) { - appendTo.append(fPadChar); - } - return appendTo; -} - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/digitaffixesandpadding.h b/deps/icu-small/source/i18n/digitaffixesandpadding.h deleted file mode 100644 index d570599d18..0000000000 --- a/deps/icu-small/source/i18n/digitaffixesandpadding.h +++ /dev/null @@ -1,179 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* digitaffixesandpadding.h -* -* created on: 2015jan06 -* created by: Travis Keep -*/ - -#ifndef __DIGITAFFIXESANDPADDING_H__ -#define __DIGITAFFIXESANDPADDING_H__ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/uobject.h" -#include "pluralaffix.h" - -U_NAMESPACE_BEGIN - -class DigitList; -class ValueFormatter; -class UnicodeString; -class FieldPositionHandler; -class PluralRules; -class VisibleDigitsWithExponent; - -/** - * A formatter of numbers. This class can format any numerical value - * except for not a number (NaN), positive infinity, and negative infinity. - * This class manages prefixes, suffixes, and padding but delegates the - * formatting of actual positive values to a ValueFormatter. - */ -class U_I18N_API DigitAffixesAndPadding : public UMemory { -public: - -/** - * Equivalent to DecimalFormat EPadPosition, but redeclared here to prevent - * depending on DecimalFormat which would cause a circular dependency. - */ -enum EPadPosition { - kPadBeforePrefix, - kPadAfterPrefix, - kPadBeforeSuffix, - kPadAfterSuffix -}; - -/** - * The positive prefix - */ -PluralAffix fPositivePrefix; - -/** - * The positive suffix - */ -PluralAffix fPositiveSuffix; - -/** - * The negative suffix - */ -PluralAffix fNegativePrefix; - -/** - * The negative suffix - */ -PluralAffix fNegativeSuffix; - -/** - * The padding position - */ -EPadPosition fPadPosition; - -/** - * The padding character. - */ -UChar32 fPadChar; - -/** - * The field width in code points. The format method inserts instances of - * the padding character as needed in the desired padding position so that - * the entire formatted string contains this many code points. If the - * formatted string already exceeds this many code points, the format method - * inserts no padding. - */ -int32_t fWidth; - -/** - * Pad position is before prefix; padding character is '*' field width is 0. - * The affixes are all the empty string with no annotated fields with just - * the 'other' plural variation. - */ -DigitAffixesAndPadding() - : fPadPosition(kPadBeforePrefix), fPadChar(0x2a), fWidth(0) { } - -/** - * Returns TRUE if this object is equal to rhs. - */ -UBool equals(const DigitAffixesAndPadding &rhs) const { - return (fPositivePrefix.equals(rhs.fPositivePrefix) && - fPositiveSuffix.equals(rhs.fPositiveSuffix) && - fNegativePrefix.equals(rhs.fNegativePrefix) && - fNegativeSuffix.equals(rhs.fNegativeSuffix) && - fPadPosition == rhs.fPadPosition && - fWidth == rhs.fWidth && - fPadChar == rhs.fPadChar); -} - -/** - * Returns TRUE if a plural rules instance is needed to complete the - * formatting by detecting if any of the affixes have multiple plural - * variations. - */ -UBool needsPluralRules() const; - -/** - * Formats value and appends to appendTo. - * - * @param value the value to format. May be NaN or ininite. - * @param formatter handles the details of formatting the actual value. - * @param handler records field positions - * @param optPluralRules the plural rules, but may be NULL if - * needsPluralRules returns FALSE. - * @appendTo formatted string appended here. - * @status any error returned here. - */ -UnicodeString &format( - const VisibleDigitsWithExponent &value, - const ValueFormatter &formatter, - FieldPositionHandler &handler, - const PluralRules *optPluralRules, - UnicodeString &appendTo, - UErrorCode &status) const; - -/** - * For testing only. - */ -UnicodeString &format( - DigitList &value, - const ValueFormatter &formatter, - FieldPositionHandler &handler, - const PluralRules *optPluralRules, - UnicodeString &appendTo, - UErrorCode &status) const; - -/** - * Formats a 32-bit integer and appends to appendTo. When formatting an - * integer, this method is preferred to plain format as it can run - * several times faster under certain conditions. - * - * @param value the value to format. - * @param formatter handles the details of formatting the actual value. - * @param handler records field positions - * @param optPluralRules the plural rules, but may be NULL if - * needsPluralRules returns FALSE. - * @appendTo formatted string appended here. - * @status any error returned here. - */ -UnicodeString &formatInt32( - int32_t value, - const ValueFormatter &formatter, - FieldPositionHandler &handler, - const PluralRules *optPluralRules, - UnicodeString &appendTo, - UErrorCode &status) const; - -private: -UnicodeString &appendPadding(int32_t paddingCount, UnicodeString &appendTo) const; - -}; - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ -#endif // __DIGITAFFIXANDPADDING_H__ diff --git a/deps/icu-small/source/i18n/digitformatter.cpp b/deps/icu-small/source/i18n/digitformatter.cpp deleted file mode 100644 index 0d857f8f68..0000000000 --- a/deps/icu-small/source/i18n/digitformatter.cpp +++ /dev/null @@ -1,417 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: digitformatter.cpp - */ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/dcfmtsym.h" -#include "unicode/unum.h" - -#include "digitformatter.h" -#include "digitgrouping.h" -#include "digitinterval.h" -#include "digitlst.h" -#include "fphdlimp.h" -#include "smallintformatter.h" -#include "unistrappender.h" -#include "visibledigits.h" - -U_NAMESPACE_BEGIN - -DigitFormatter::DigitFormatter() - : fGroupingSeparator(",", -1, US_INV), fDecimal(".", -1, US_INV), - fNegativeSign("-", -1, US_INV), fPositiveSign("+", -1, US_INV), - fIsStandardDigits(TRUE), fExponent("E", -1, US_INV) { - for (int32_t i = 0; i < 10; ++i) { - fLocalizedDigits[i] = (UChar32) (0x30 + i); - } - fInfinity.setTo(UnicodeString("Inf", -1, US_INV), UNUM_INTEGER_FIELD); - fNan.setTo(UnicodeString("Nan", -1, US_INV), UNUM_INTEGER_FIELD); -} - -DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) { - setDecimalFormatSymbols(symbols); -} - -void -DigitFormatter::setOtherDecimalFormatSymbols( - const DecimalFormatSymbols &symbols) { - fLocalizedDigits[0] = symbols.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0); - fLocalizedDigits[1] = symbols.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0); - fLocalizedDigits[2] = symbols.getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0); - fLocalizedDigits[3] = symbols.getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0); - fLocalizedDigits[4] = symbols.getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0); - fLocalizedDigits[5] = symbols.getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0); - fLocalizedDigits[6] = symbols.getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0); - fLocalizedDigits[7] = symbols.getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0); - fLocalizedDigits[8] = symbols.getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0); - fLocalizedDigits[9] = symbols.getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0); - fIsStandardDigits = isStandardDigits(); - fNegativeSign = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); - fPositiveSign = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); - fInfinity.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), UNUM_INTEGER_FIELD); - fNan.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), UNUM_INTEGER_FIELD); - fExponent = symbols.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); -} - -void -DigitFormatter::setDecimalFormatSymbolsForMonetary( - const DecimalFormatSymbols &symbols) { - setOtherDecimalFormatSymbols(symbols); - fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); - fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); -} - -void -DigitFormatter::setDecimalFormatSymbols( - const DecimalFormatSymbols &symbols) { - setOtherDecimalFormatSymbols(symbols); - fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); - fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); -} - -static void appendField( - int32_t fieldId, - const UnicodeString &value, - FieldPositionHandler &handler, - UnicodeString &appendTo) { - int32_t currentLength = appendTo.length(); - appendTo.append(value); - handler.addAttribute( - fieldId, - currentLength, - appendTo.length()); -} - -int32_t DigitFormatter::countChar32( - const DigitGrouping &grouping, - const DigitInterval &interval, - const DigitFormatterOptions &options) const { - int32_t result = interval.length(); - - // We always emit '0' in lieu of no digits. - if (result == 0) { - result = 1; - } - if (options.fAlwaysShowDecimal || interval.getLeastSignificantInclusive() < 0) { - result += fDecimal.countChar32(); - } - result += grouping.getSeparatorCount(interval.getIntDigitCount()) * fGroupingSeparator.countChar32(); - return result; -} - -int32_t -DigitFormatter::countChar32( - const VisibleDigits &digits, - const DigitGrouping &grouping, - const DigitFormatterOptions &options) const { - if (digits.isNaN()) { - return countChar32ForNaN(); - } - if (digits.isInfinite()) { - return countChar32ForInfinity(); - } - return countChar32( - grouping, - digits.getInterval(), - options); -} - -int32_t -DigitFormatter::countChar32( - const VisibleDigitsWithExponent &digits, - const SciFormatterOptions &options) const { - if (digits.isNaN()) { - return countChar32ForNaN(); - } - if (digits.isInfinite()) { - return countChar32ForInfinity(); - } - const VisibleDigits *exponent = digits.getExponent(); - if (exponent == NULL) { - DigitGrouping grouping; - return countChar32( - grouping, - digits.getMantissa().getInterval(), - options.fMantissa); - } - return countChar32( - *exponent, digits.getMantissa().getInterval(), options); -} - -int32_t -DigitFormatter::countChar32( - const VisibleDigits &exponent, - const DigitInterval &mantissaInterval, - const SciFormatterOptions &options) const { - DigitGrouping grouping; - int32_t count = countChar32( - grouping, mantissaInterval, options.fMantissa); - count += fExponent.countChar32(); - count += countChar32ForExponent( - exponent, options.fExponent); - return count; -} - -UnicodeString &DigitFormatter::format( - const VisibleDigits &digits, - const DigitGrouping &grouping, - const DigitFormatterOptions &options, - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - if (digits.isNaN()) { - return formatNaN(handler, appendTo); - } - if (digits.isInfinite()) { - return formatInfinity(handler, appendTo); - } - - const DigitInterval &interval = digits.getInterval(); - int32_t digitsLeftOfDecimal = interval.getMostSignificantExclusive(); - int32_t lastDigitPos = interval.getLeastSignificantInclusive(); - int32_t intBegin = appendTo.length(); - int32_t fracBegin = 0; /* initialize to avoid compiler warning */ - - // Emit "0" instead of empty string. - if (digitsLeftOfDecimal == 0 && lastDigitPos == 0) { - appendTo.append(fLocalizedDigits[0]); - handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length()); - if (options.fAlwaysShowDecimal) { - appendField( - UNUM_DECIMAL_SEPARATOR_FIELD, - fDecimal, - handler, - appendTo); - } - return appendTo; - } - { - UnicodeStringAppender appender(appendTo); - for (int32_t i = interval.getMostSignificantExclusive() - 1; - i >= interval.getLeastSignificantInclusive(); --i) { - if (i == -1) { - appender.flush(); - appendField( - UNUM_DECIMAL_SEPARATOR_FIELD, - fDecimal, - handler, - appendTo); - fracBegin = appendTo.length(); - } - appender.append(fLocalizedDigits[digits.getDigitByExponent(i)]); - if (grouping.isSeparatorAt(digitsLeftOfDecimal, i)) { - appender.flush(); - appendField( - UNUM_GROUPING_SEPARATOR_FIELD, - fGroupingSeparator, - handler, - appendTo); - } - if (i == 0) { - appender.flush(); - if (digitsLeftOfDecimal > 0) { - handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length()); - } - } - } - if (options.fAlwaysShowDecimal && lastDigitPos == 0) { - appender.flush(); - appendField( - UNUM_DECIMAL_SEPARATOR_FIELD, - fDecimal, - handler, - appendTo); - } - } - // lastDigitPos is never > 0 so we are guaranteed that kIntegerField - // is already added. - if (lastDigitPos < 0) { - handler.addAttribute(UNUM_FRACTION_FIELD, fracBegin, appendTo.length()); - } - return appendTo; -} - -UnicodeString & -DigitFormatter::format( - const VisibleDigitsWithExponent &digits, - const SciFormatterOptions &options, - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - DigitGrouping grouping; - format( - digits.getMantissa(), - grouping, - options.fMantissa, - handler, - appendTo); - const VisibleDigits *exponent = digits.getExponent(); - if (exponent == NULL) { - return appendTo; - } - int32_t expBegin = appendTo.length(); - appendTo.append(fExponent); - handler.addAttribute( - UNUM_EXPONENT_SYMBOL_FIELD, expBegin, appendTo.length()); - return formatExponent( - *exponent, - options.fExponent, - UNUM_EXPONENT_SIGN_FIELD, - UNUM_EXPONENT_FIELD, - handler, - appendTo); -} - -static int32_t formatInt( - int32_t value, uint8_t *digits) { - int32_t idx = 0; - while (value > 0) { - digits[idx++] = (uint8_t) (value % 10); - value /= 10; - } - return idx; -} - -UnicodeString & -DigitFormatter::formatDigits( - const uint8_t *digits, - int32_t count, - const IntDigitCountRange &range, - int32_t intField, - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - int32_t i = range.pin(count) - 1; - int32_t begin = appendTo.length(); - - // Always emit '0' as placeholder for empty string. - if (i == -1) { - appendTo.append(fLocalizedDigits[0]); - handler.addAttribute(intField, begin, appendTo.length()); - return appendTo; - } - { - UnicodeStringAppender appender(appendTo); - for (; i >= count; --i) { - appender.append(fLocalizedDigits[0]); - } - for (; i >= 0; --i) { - appender.append(fLocalizedDigits[digits[i]]); - } - } - handler.addAttribute(intField, begin, appendTo.length()); - return appendTo; -} - -UnicodeString & -DigitFormatter::formatExponent( - const VisibleDigits &digits, - const DigitFormatterIntOptions &options, - int32_t signField, - int32_t intField, - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - UBool neg = digits.isNegative(); - if (neg || options.fAlwaysShowSign) { - appendField( - signField, - neg ? fNegativeSign : fPositiveSign, - handler, - appendTo); - } - int32_t begin = appendTo.length(); - DigitGrouping grouping; - DigitFormatterOptions expOptions; - FieldPosition fpos(FieldPosition::DONT_CARE); - FieldPositionOnlyHandler noHandler(fpos); - format( - digits, - grouping, - expOptions, - noHandler, - appendTo); - handler.addAttribute(intField, begin, appendTo.length()); - return appendTo; -} - -int32_t -DigitFormatter::countChar32ForExponent( - const VisibleDigits &exponent, - const DigitFormatterIntOptions &options) const { - int32_t result = 0; - UBool neg = exponent.isNegative(); - if (neg || options.fAlwaysShowSign) { - result += neg ? fNegativeSign.countChar32() : fPositiveSign.countChar32(); - } - DigitGrouping grouping; - DigitFormatterOptions expOptions; - result += countChar32(grouping, exponent.getInterval(), expOptions); - return result; -} - -UnicodeString & -DigitFormatter::formatPositiveInt32( - int32_t positiveValue, - const IntDigitCountRange &range, - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - // super fast path - if (fIsStandardDigits && SmallIntFormatter::canFormat(positiveValue, range)) { - int32_t begin = appendTo.length(); - SmallIntFormatter::format(positiveValue, range, appendTo); - handler.addAttribute(UNUM_INTEGER_FIELD, begin, appendTo.length()); - return appendTo; - } - uint8_t digits[10]; - int32_t count = formatInt(positiveValue, digits); - return formatDigits( - digits, - count, - range, - UNUM_INTEGER_FIELD, - handler, - appendTo); -} - -UBool DigitFormatter::isStandardDigits() const { - UChar32 cdigit = 0x30; - for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) { - if (fLocalizedDigits[i] != cdigit) { - return FALSE; - } - ++cdigit; - } - return TRUE; -} - -UBool -DigitFormatter::equals(const DigitFormatter &rhs) const { - UBool result = (fGroupingSeparator == rhs.fGroupingSeparator) && - (fDecimal == rhs.fDecimal) && - (fNegativeSign == rhs.fNegativeSign) && - (fPositiveSign == rhs.fPositiveSign) && - (fInfinity.equals(rhs.fInfinity)) && - (fNan.equals(rhs.fNan)) && - (fIsStandardDigits == rhs.fIsStandardDigits) && - (fExponent == rhs.fExponent); - - if (!result) { - return FALSE; - } - for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) { - if (fLocalizedDigits[i] != rhs.fLocalizedDigits[i]) { - return FALSE; - } - } - return TRUE; -} - - -U_NAMESPACE_END - -#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/digitformatter.h b/deps/icu-small/source/i18n/digitformatter.h deleted file mode 100644 index 54a54c3639..0000000000 --- a/deps/icu-small/source/i18n/digitformatter.h +++ /dev/null @@ -1,288 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* digitformatter.h -* -* created on: 2015jan06 -* created by: Travis Keep -*/ - -#ifndef __DIGITFORMATTER_H__ -#define __DIGITFORMATTER_H__ - -#include "unicode/uobject.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/utypes.h" -#include "unicode/unistr.h" -#include "digitaffix.h" - -U_NAMESPACE_BEGIN - -class DecimalFormatSymbols; -class DigitList; -class DigitGrouping; -class DigitInterval; -class UnicodeString; -class FieldPositionHandler; -class IntDigitCountRange; -class VisibleDigits; -class VisibleDigitsWithExponent; - -/** - * Various options for formatting in fixed point. - */ -class U_I18N_API DigitFormatterOptions : public UMemory { - public: - DigitFormatterOptions() : fAlwaysShowDecimal(FALSE) { } - - /** - * Returns TRUE if this object equals rhs. - */ - UBool equals(const DigitFormatterOptions &rhs) const { - return ( - fAlwaysShowDecimal == rhs.fAlwaysShowDecimal); - } - - /** - * Returns TRUE if these options allow for fast formatting of - * integers. - */ - UBool isFastFormattable() const { - return (fAlwaysShowDecimal == FALSE); - } - - /** - * If TRUE, show the decimal separator even when there are no fraction - * digits. default is FALSE. - */ - UBool fAlwaysShowDecimal; -}; - -/** - * Various options for formatting an integer. - */ -class U_I18N_API DigitFormatterIntOptions : public UMemory { - public: - DigitFormatterIntOptions() : fAlwaysShowSign(FALSE) { } - - /** - * Returns TRUE if this object equals rhs. - */ - UBool equals(const DigitFormatterIntOptions &rhs) const { - return (fAlwaysShowSign == rhs.fAlwaysShowSign); - } - - /** - * If TRUE, always prefix the integer with its sign even if the number is - * positive. Default is FALSE. - */ - UBool fAlwaysShowSign; -}; - -/** - * Options for formatting in scientific notation. - */ -class U_I18N_API SciFormatterOptions : public UMemory { - public: - - /** - * Returns TRUE if this object equals rhs. - */ - UBool equals(const SciFormatterOptions &rhs) const { - return (fMantissa.equals(rhs.fMantissa) && - fExponent.equals(rhs.fExponent)); - } - - /** - * Options for formatting the mantissa. - */ - DigitFormatterOptions fMantissa; - - /** - * Options for formatting the exponent. - */ - DigitFormatterIntOptions fExponent; -}; - - -/** - * Does fixed point formatting. - * - * This class only does fixed point formatting. It does no rounding before - * formatting. - */ -class U_I18N_API DigitFormatter : public UMemory { -public: - -/** - * Decimal separator is period (.), Plus sign is plus (+), - * minus sign is minus (-), grouping separator is comma (,), digits are 0-9. - */ -DigitFormatter(); - -/** - * Let symbols determine the digits, decimal separator, - * plus and mius sign, grouping separator, and possibly other settings. - */ -DigitFormatter(const DecimalFormatSymbols &symbols); - -/** - * Change what this instance uses for digits, decimal separator, - * plus and mius sign, grouping separator, and possibly other settings - * according to symbols. - */ -void setDecimalFormatSymbols(const DecimalFormatSymbols &symbols); - -/** - * Change what this instance uses for digits, decimal separator, - * plus and mius sign, grouping separator, and possibly other settings - * according to symbols in the context of monetary amounts. - */ -void setDecimalFormatSymbolsForMonetary(const DecimalFormatSymbols &symbols); - -/** - * Fixed point formatting. - * - * @param positiveDigits the value to format - * Negative sign can be present, but it won't show. - * @param grouping controls how digit grouping is done - * @param options formatting options - * @param handler records field positions - * @param appendTo formatted value appended here. - * @return appendTo - */ -UnicodeString &format( - const VisibleDigits &positiveDigits, - const DigitGrouping &grouping, - const DigitFormatterOptions &options, - FieldPositionHandler &handler, - UnicodeString &appendTo) const; - -/** - * formats in scientifc notation. - * @param positiveDigits the value to format. - * Negative sign can be present, but it won't show. - * @param options formatting options - * @param handler records field positions. - * @param appendTo formatted value appended here. - */ -UnicodeString &format( - const VisibleDigitsWithExponent &positiveDigits, - const SciFormatterOptions &options, - FieldPositionHandler &handler, - UnicodeString &appendTo) const; - -/** - * Fixed point formatting of integers. - * Always performed with no grouping and no decimal point. - * - * @param positiveValue the value to format must be positive. - * @param range specifies minimum and maximum number of digits. - * @param handler records field positions - * @param appendTo formatted value appended here. - * @return appendTo - */ -UnicodeString &formatPositiveInt32( - int32_t positiveValue, - const IntDigitCountRange &range, - FieldPositionHandler &handler, - UnicodeString &appendTo) const; - -/** - * Counts how many code points are needed for fixed formatting. - * If digits is negative, the negative sign is not included in the count. - */ -int32_t countChar32( - const VisibleDigits &digits, - const DigitGrouping &grouping, - const DigitFormatterOptions &options) const; - -/** - * Counts how many code points are needed for scientific formatting. - * If digits is negative, the negative sign is not included in the count. - */ -int32_t countChar32( - const VisibleDigitsWithExponent &digits, - const SciFormatterOptions &options) const; - -/** - * Returns TRUE if this object equals rhs. - */ -UBool equals(const DigitFormatter &rhs) const; - -private: -UChar32 fLocalizedDigits[10]; -UnicodeString fGroupingSeparator; -UnicodeString fDecimal; -UnicodeString fNegativeSign; -UnicodeString fPositiveSign; -DigitAffix fInfinity; -DigitAffix fNan; -UBool fIsStandardDigits; -UnicodeString fExponent; -UBool isStandardDigits() const; - -UnicodeString &formatDigits( - const uint8_t *digits, - int32_t count, - const IntDigitCountRange &range, - int32_t intField, - FieldPositionHandler &handler, - UnicodeString &appendTo) const; - -void setOtherDecimalFormatSymbols(const DecimalFormatSymbols &symbols); - -int32_t countChar32( - const VisibleDigits &exponent, - const DigitInterval &mantissaInterval, - const SciFormatterOptions &options) const; - -UnicodeString &formatNaN( - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - return fNan.format(handler, appendTo); -} - -int32_t countChar32ForNaN() const { - return fNan.toString().countChar32(); -} - -UnicodeString &formatInfinity( - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - return fInfinity.format(handler, appendTo); -} - -int32_t countChar32ForInfinity() const { - return fInfinity.toString().countChar32(); -} - -UnicodeString &formatExponent( - const VisibleDigits &digits, - const DigitFormatterIntOptions &options, - int32_t signField, - int32_t intField, - FieldPositionHandler &handler, - UnicodeString &appendTo) const; - -int32_t countChar32( - const DigitGrouping &grouping, - const DigitInterval &interval, - const DigitFormatterOptions &options) const; - -int32_t countChar32ForExponent( - const VisibleDigits &exponent, - const DigitFormatterIntOptions &options) const; - -}; - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ -#endif // __DIGITFORMATTER_H__ diff --git a/deps/icu-small/source/i18n/digitgrouping.cpp b/deps/icu-small/source/i18n/digitgrouping.cpp deleted file mode 100644 index cffa122b6c..0000000000 --- a/deps/icu-small/source/i18n/digitgrouping.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: digitgrouping.cpp - */ - -#include "unicode/utypes.h" - -#include "digitgrouping.h" -#include "smallintformatter.h" - -U_NAMESPACE_BEGIN - -UBool DigitGrouping::isSeparatorAt( - int32_t digitsLeftOfDecimal, int32_t digitPos) const { - if (!isGroupingEnabled(digitsLeftOfDecimal) || digitPos < fGrouping) { - return FALSE; - } - return ((digitPos - fGrouping) % getGrouping2() == 0); -} - -int32_t DigitGrouping::getSeparatorCount(int32_t digitsLeftOfDecimal) const { - if (!isGroupingEnabled(digitsLeftOfDecimal)) { - return 0; - } - return (digitsLeftOfDecimal - 1 - fGrouping) / getGrouping2() + 1; -} - -UBool DigitGrouping::isGroupingEnabled(int32_t digitsLeftOfDecimal) const { - return (isGroupingUsed() - && digitsLeftOfDecimal >= fGrouping + getMinGrouping()); -} - -UBool DigitGrouping::isNoGrouping( - int32_t positiveValue, const IntDigitCountRange &range) const { - return getSeparatorCount( - SmallIntFormatter::estimateDigitCount(positiveValue, range)) == 0; -} - -int32_t DigitGrouping::getGrouping2() const { - return (fGrouping2 > 0 ? fGrouping2 : fGrouping); -} - -int32_t DigitGrouping::getMinGrouping() const { - return (fMinGrouping > 0 ? fMinGrouping : 1); -} - -void -DigitGrouping::clear() { - fMinGrouping = 0; - fGrouping = 0; - fGrouping2 = 0; -} - -U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/digitgrouping.h b/deps/icu-small/source/i18n/digitgrouping.h deleted file mode 100644 index f3f8679b87..0000000000 --- a/deps/icu-small/source/i18n/digitgrouping.h +++ /dev/null @@ -1,112 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* digitgrouping.h -* -* created on: 2015jan6 -* created by: Travis Keep -*/ - -#ifndef __DIGITGROUPING_H__ -#define __DIGITGROUPING_H__ - -#include "unicode/uobject.h" -#include "unicode/utypes.h" - -U_NAMESPACE_BEGIN - -class IntDigitCountRange; - -/** - * The digit grouping policy. - */ -class U_I18N_API DigitGrouping : public UMemory { -public: - /** - * Default is no digit grouping. - */ - DigitGrouping() : fGrouping(0), fGrouping2(0), fMinGrouping(0) { } - - /** - * Returns TRUE if this object is equal to rhs. - */ - UBool equals(const DigitGrouping &rhs) const { - return ((fGrouping == rhs.fGrouping) && - (fGrouping2 == rhs.fGrouping2) && - (fMinGrouping == rhs.fMinGrouping)); - } - - /** - * Returns true if a separator is needed after a particular digit. - * @param digitsLeftOfDecimal the total count of digits left of the - * decimal. - * @param digitPos 0 is the one's place; 1 is the 10's place; -1 is the - * 1/10's place etc. - */ - UBool isSeparatorAt(int32_t digitsLeftOfDecimal, int32_t digitPos) const; - - /** - * Returns the total number of separators to be used to format a particular - * number. - * @param digitsLeftOfDecimal the total number of digits to the left of - * the decimal. - */ - int32_t getSeparatorCount(int32_t digitsLeftOfDecimal) const; - - /** - * Returns true if grouping is used FALSE otherwise. When - * isGroupingUsed() returns FALSE; isSeparatorAt always returns FALSE - * and getSeparatorCount always returns 0. - */ - UBool isGroupingUsed() const { return fGrouping > 0; } - - /** - * Returns TRUE if this instance would not add grouping separators - * when formatting value using the given constraint on digit count. - * - * @param value the value to format. - * @param range the minimum and maximum digits for formatting value. - */ - UBool isNoGrouping( - int32_t positiveValue, const IntDigitCountRange &range) const; - - /** - * Clears this instance so that digit grouping is not in effect. - */ - void clear(); - -public: - - /** - * Primary grouping size. A value of 0, the default, or a negative - * number causes isGroupingUsed() to return FALSE. - */ - int32_t fGrouping; - - /** - * Secondary grouping size. If > 0, this size is used instead of - * 'fGrouping' for all but the group just to the left of the decimal - * point. The default value of 0, or a negative value indicates that - * there is no secondary grouping size. - */ - int32_t fGrouping2; - - /** - * If set (that is > 0), uses no grouping separators if fewer than - * (fGrouping + fMinGrouping) digits appear left of the decimal place. - * The default value for this field is 0. - */ - int32_t fMinGrouping; -private: - UBool isGroupingEnabled(int32_t digitsLeftOfDecimal) const; - int32_t getGrouping2() const; - int32_t getMinGrouping() const; -}; - -U_NAMESPACE_END - -#endif // __DIGITGROUPING_H__ diff --git a/deps/icu-small/source/i18n/digitinterval.cpp b/deps/icu-small/source/i18n/digitinterval.cpp deleted file mode 100644 index 32d952e026..0000000000 --- a/deps/icu-small/source/i18n/digitinterval.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: digitinterval.cpp - */ - -#include "unicode/utypes.h" - -#include "digitinterval.h" - -U_NAMESPACE_BEGIN - -void DigitInterval::expandToContain(const DigitInterval &rhs) { - if (fSmallestInclusive > rhs.fSmallestInclusive) { - fSmallestInclusive = rhs.fSmallestInclusive; - } - if (fLargestExclusive < rhs.fLargestExclusive) { - fLargestExclusive = rhs.fLargestExclusive; - } -} - -void DigitInterval::shrinkToFitWithin(const DigitInterval &rhs) { - if (fSmallestInclusive < rhs.fSmallestInclusive) { - fSmallestInclusive = rhs.fSmallestInclusive; - } - if (fLargestExclusive > rhs.fLargestExclusive) { - fLargestExclusive = rhs.fLargestExclusive; - } -} - -void DigitInterval::setIntDigitCount(int32_t count) { - fLargestExclusive = count < 0 ? INT32_MAX : count; -} - -void DigitInterval::setFracDigitCount(int32_t count) { - fSmallestInclusive = count < 0 ? INT32_MIN : -count; -} - -void DigitInterval::expandToContainDigit(int32_t digitExponent) { - if (fLargestExclusive <= digitExponent) { - fLargestExclusive = digitExponent + 1; - } else if (fSmallestInclusive > digitExponent) { - fSmallestInclusive = digitExponent; - } -} - -UBool DigitInterval::contains(int32_t x) const { - return (x < fLargestExclusive && x >= fSmallestInclusive); -} - - -U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/digitinterval.h b/deps/icu-small/source/i18n/digitinterval.h deleted file mode 100644 index 95d406da20..0000000000 --- a/deps/icu-small/source/i18n/digitinterval.h +++ /dev/null @@ -1,159 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* digitinterval.h -* -* created on: 2015jan6 -* created by: Travis Keep -*/ - -#ifndef __DIGITINTERVAL_H__ -#define __DIGITINTERVAL_H__ - -#include "unicode/uobject.h" -#include "unicode/utypes.h" - -U_NAMESPACE_BEGIN - -/** - * An interval of digits. - * DigitIntervals are for fixed point formatting. A DigitInterval specifies - * zero or more integer digits and zero or more fractional digits. This class - * specifies particular digits in a number by their power of 10. For example, - * the digit position just to the left of the decimal is 0, and the digit - * position just left of that is 1. The digit position just to the right of - * the decimal is -1. The digit position just to the right of that is -2. - */ -class U_I18N_API DigitInterval : public UMemory { -public: - - /** - * Spans all integer and fraction digits - */ - DigitInterval() - : fLargestExclusive(INT32_MAX), fSmallestInclusive(INT32_MIN) { } - - - /** - * Makes this instance span all digits. - */ - void clear() { - fLargestExclusive = INT32_MAX; - fSmallestInclusive = INT32_MIN; - } - - /** - * Returns TRUE if this interval contains this digit position. - */ - UBool contains(int32_t digitPosition) const; - - /** - * Returns true if this object is the same as rhs. - */ - UBool equals(const DigitInterval &rhs) const { - return ((fLargestExclusive == rhs.fLargestExclusive) && - (fSmallestInclusive == rhs.fSmallestInclusive)); - } - - /** - * Expand this interval so that it contains all of rhs. - */ - void expandToContain(const DigitInterval &rhs); - - /** - * Shrink this interval so that it contains no more than rhs. - */ - void shrinkToFitWithin(const DigitInterval &rhs); - - /** - * Expand this interval as necessary to contain digit with given exponent - * After this method returns, this interval is guaranteed to contain - * digitExponent. - */ - void expandToContainDigit(int32_t digitExponent); - - /** - * Changes the number of digits to the left of the decimal point that - * this interval spans. If count is negative, it means span all digits - * to the left of the decimal point. - */ - void setIntDigitCount(int32_t count); - - /** - * Changes the number of digits to the right of the decimal point that - * this interval spans. If count is negative, it means span all digits - * to the right of the decimal point. - */ - void setFracDigitCount(int32_t count); - - /** - * Sets the least significant inclusive value to smallest. If smallest >= 0 - * then least significant inclusive value becomes 0. - */ - void setLeastSignificantInclusive(int32_t smallest) { - fSmallestInclusive = smallest < 0 ? smallest : 0; - } - - /** - * Sets the most significant exclusive value to largest. - * If largest <= 0 then most significant exclusive value becomes 0. - */ - void setMostSignificantExclusive(int32_t largest) { - fLargestExclusive = largest > 0 ? largest : 0; - } - - /** - * If returns 8, the most significant digit in interval is the 10^7 digit. - * Returns INT32_MAX if this interval spans all digits to left of - * decimal point. - */ - int32_t getMostSignificantExclusive() const { - return fLargestExclusive; - } - - /** - * Returns number of digits to the left of the decimal that this - * interval includes. This is a synonym for getMostSignificantExclusive(). - */ - int32_t getIntDigitCount() const { - return fLargestExclusive; - } - - /** - * Returns number of digits to the right of the decimal that this - * interval includes. - */ - int32_t getFracDigitCount() const { - return fSmallestInclusive == INT32_MIN ? INT32_MAX : -fSmallestInclusive; - } - - /** - * Returns the total number of digits that this interval spans. - * Caution: If this interval spans all digits to the left or right of - * decimal point instead of some fixed number, then what length() - * returns is undefined. - */ - int32_t length() const { - return fLargestExclusive - fSmallestInclusive; - } - - /** - * If returns -3, the least significant digit in interval is the 10^-3 - * digit. Returns INT32_MIN if this interval spans all digits to right of - * decimal point. - */ - int32_t getLeastSignificantInclusive() const { - return fSmallestInclusive; - } -private: - int32_t fLargestExclusive; - int32_t fSmallestInclusive; -}; - -U_NAMESPACE_END - -#endif // __DIGITINTERVAL_H__ diff --git a/deps/icu-small/source/i18n/digitlst.cpp b/deps/icu-small/source/i18n/digitlst.cpp deleted file mode 100644 index 37760defd7..0000000000 --- a/deps/icu-small/source/i18n/digitlst.cpp +++ /dev/null @@ -1,1143 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -********************************************************************** -* Copyright (C) 1997-2015, International Business Machines -* Corporation and others. All Rights Reserved. -********************************************************************** -* -* File DIGITLST.CPP -* -* Modification History: -* -* Date Name Description -* 03/21/97 clhuang Converted from java. -* 03/21/97 clhuang Implemented with new APIs. -* 03/27/97 helena Updated to pass the simple test after code review. -* 03/31/97 aliu Moved isLONG_MIN to here, and fixed it. -* 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char. -* Reworked representation by replacing fDecimalAt -* with fExponent. -* 04/16/97 aliu Rewrote set() and getDouble() to use sprintf/atof -* to do digit conversion. -* 09/09/97 aliu Modified for exponential notation support. -* 08/02/98 stephen Added nearest/even rounding -* Fixed bug in fitsIntoLong -****************************************************************************** -*/ - -#if defined(__CYGWIN__) && !defined(_GNU_SOURCE) -#define _GNU_SOURCE -#endif - -#include "digitlst.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/putil.h" -#include "charstr.h" -#include "cmemory.h" -#include "cstring.h" -#include "mutex.h" -#include "putilimp.h" -#include "uassert.h" -#include "digitinterval.h" -#include "ucln_in.h" -#include "umutex.h" -#include "double-conversion.h" -#include -#include -#include -#include -#include - -using icu::double_conversion::DoubleToStringConverter; - -#if !defined(U_USE_STRTOD_L) -# if U_PLATFORM_USES_ONLY_WIN32_API -# define U_USE_STRTOD_L 1 -# define U_HAVE_XLOCALE_H 0 -# elif defined(U_HAVE_STRTOD_L) -# define U_USE_STRTOD_L U_HAVE_STRTOD_L -# else -# define U_USE_STRTOD_L 0 -# endif -#endif - -#if U_USE_STRTOD_L -# if U_HAVE_XLOCALE_H -# include -# else -# include -# endif -#endif - -// *************************************************************************** -// class DigitList -// A wrapper onto decNumber. -// Used to be standalone. -// *************************************************************************** - -/** - * This is the zero digit. The base for the digits returned by getDigit() - * Note that it is the platform invariant digit, and is not Unicode. - */ -#define kZero '0' - - -/* Only for 32 bit numbers. Ignore the negative sign. */ -//static const char LONG_MIN_REP[] = "2147483648"; -//static const char I64_MIN_REP[] = "9223372036854775808"; - - -U_NAMESPACE_BEGIN - -// ------------------------------------- -// default constructor - -DigitList::DigitList() -{ - uprv_decContextDefault(&fContext, DEC_INIT_BASE); - fContext.traps = 0; - uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN); - fContext.digits = fStorage.getCapacity(); - - fDecNumber = fStorage.getAlias(); - uprv_decNumberZero(fDecNumber); - - internalSetDouble(0.0); -} - -// ------------------------------------- - -DigitList::~DigitList() -{ -} - -// ------------------------------------- -// copy constructor - -DigitList::DigitList(const DigitList &other) -{ - fDecNumber = fStorage.getAlias(); - *this = other; -} - - -// ------------------------------------- -// assignment operator - -DigitList& -DigitList::operator=(const DigitList& other) -{ - if (this != &other) - { - uprv_memcpy(&fContext, &other.fContext, sizeof(decContext)); - - if (other.fStorage.getCapacity() > fStorage.getCapacity()) { - fDecNumber = fStorage.resize(other.fStorage.getCapacity()); - } - // Always reset the fContext.digits, even if fDecNumber was not reallocated, - // because above we copied fContext from other.fContext. - fContext.digits = fStorage.getCapacity(); - uprv_decNumberCopy(fDecNumber, other.fDecNumber); - - { - // fDouble is lazily created and cached. - // Avoid potential races with that happening with other.fDouble - // while we are doing the assignment. - Mutex mutex; - - if(other.fHave==kDouble) { - fUnion.fDouble = other.fUnion.fDouble; - } - fHave = other.fHave; - } - } - return *this; -} - -// ------------------------------------- -// operator == (does not exactly match the old DigitList function) - -UBool -DigitList::operator==(const DigitList& that) const -{ - if (this == &that) { - return TRUE; - } - decNumber n; // Has space for only a none digit value. - decContext c; - uprv_decContextDefault(&c, DEC_INIT_BASE); - c.digits = 1; - c.traps = 0; - - uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c); - UBool result = decNumberIsZero(&n); - return result; -} - -// ------------------------------------- -// comparison function. Returns -// Not Comparable : -2 -// < : -1 -// == : 0 -// > : +1 -int32_t DigitList::compare(const DigitList &other) { - decNumber result; - int32_t savedDigits = fContext.digits; - fContext.digits = 1; - uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext); - fContext.digits = savedDigits; - if (decNumberIsZero(&result)) { - return 0; - } else if (decNumberIsSpecial(&result)) { - return -2; - } else if (result.bits & DECNEG) { - return -1; - } else { - return 1; - } -} - - -// ------------------------------------- -// Reduce - remove trailing zero digits. -void -DigitList::reduce() { - uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext); -} - - -// ------------------------------------- -// trim - remove trailing fraction zero digits. -void -DigitList::trim() { - uprv_decNumberTrim(fDecNumber); -} - -// ------------------------------------- -// Resets the digit list; sets all the digits to zero. - -void -DigitList::clear() -{ - uprv_decNumberZero(fDecNumber); - uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN); - internalSetDouble(0.0); -} - - -/** - * Formats a int64_t number into a base 10 string representation, and NULL terminates it. - * @param number The number to format - * @param outputStr The string to output to. Must be at least MAX_DIGITS+2 in length (21), - * to hold the longest int64_t value. - * @return the number of digits written, not including the sign. - */ -static int32_t -formatBase10(int64_t number, char *outputStr) { - // The number is output backwards, starting with the LSD. - // Fill the buffer from the far end. After the number is complete, - // slide the string contents to the front. - - const int32_t MAX_IDX = MAX_DIGITS+2; - int32_t destIdx = MAX_IDX; - outputStr[--destIdx] = 0; - - int64_t n = number; - if (number < 0) { // Negative numbers are slightly larger than a postive - outputStr[--destIdx] = (char)(-(n % 10) + kZero); - n /= -10; - } - do { - outputStr[--destIdx] = (char)(n % 10 + kZero); - n /= 10; - } while (n > 0); - - if (number < 0) { - outputStr[--destIdx] = '-'; - } - - // Slide the number to the start of the output str - U_ASSERT(destIdx >= 0); - int32_t length = MAX_IDX - destIdx; - uprv_memmove(outputStr, outputStr+MAX_IDX-length, length); - - return length; -} - - -// ------------------------------------- -// -// setRoundingMode() -// For most modes, the meaning and names are the same between the decNumber library -// (which DigitList follows) and the ICU Formatting Rounding Mode values. -// The flag constants are different, however. -// -// Note that ICU's kRoundingUnnecessary is not implemented directly by DigitList. -// This mode, inherited from Java, means that numbers that would not format exactly -// will return an error when formatting is attempted. - -void -DigitList::setRoundingMode(DecimalFormat::ERoundingMode m) { - enum rounding r; - - switch (m) { - case DecimalFormat::kRoundCeiling: r = DEC_ROUND_CEILING; break; - case DecimalFormat::kRoundFloor: r = DEC_ROUND_FLOOR; break; - case DecimalFormat::kRoundDown: r = DEC_ROUND_DOWN; break; - case DecimalFormat::kRoundUp: r = DEC_ROUND_UP; break; - case DecimalFormat::kRoundHalfEven: r = DEC_ROUND_HALF_EVEN; break; - case DecimalFormat::kRoundHalfDown: r = DEC_ROUND_HALF_DOWN; break; - case DecimalFormat::kRoundHalfUp: r = DEC_ROUND_HALF_UP; break; - case DecimalFormat::kRoundUnnecessary: r = DEC_ROUND_HALF_EVEN; break; - default: - // TODO: how to report the problem? - // Leave existing mode unchanged. - r = uprv_decContextGetRounding(&fContext); - } - uprv_decContextSetRounding(&fContext, r); - -} - - -// ------------------------------------- - -void -DigitList::setPositive(UBool s) { - if (s) { - fDecNumber->bits &= ~DECNEG; - } else { - fDecNumber->bits |= DECNEG; - } - internalClear(); -} -// ------------------------------------- - -void -DigitList::setDecimalAt(int32_t d) { - U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN - U_ASSERT(d-1>-999999999); - U_ASSERT(d-1< 999999999); - int32_t adjustedDigits = fDecNumber->digits; - if (decNumberIsZero(fDecNumber)) { - // Account for difference in how zero is represented between DigitList & decNumber. - adjustedDigits = 0; - } - fDecNumber->exponent = d - adjustedDigits; - internalClear(); -} - -int32_t -DigitList::getDecimalAt() { - U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN - if (decNumberIsZero(fDecNumber) || ((fDecNumber->bits & DECSPECIAL) != 0)) { - return fDecNumber->exponent; // Exponent should be zero for these cases. - } - return fDecNumber->exponent + fDecNumber->digits; -} - -void -DigitList::setCount(int32_t c) { - U_ASSERT(c <= fContext.digits); - if (c == 0) { - // For a value of zero, DigitList sets all fields to zero, while - // decNumber keeps one digit (with that digit being a zero) - c = 1; - fDecNumber->lsu[0] = 0; - } - fDecNumber->digits = c; - internalClear(); -} - -int32_t -DigitList::getCount() const { - if (decNumberIsZero(fDecNumber) && fDecNumber->exponent==0) { - // The extra test for exponent==0 is needed because parsing sometimes appends - // zero digits. It's bogus, decimalFormatter parsing needs to be cleaned up. - return 0; - } else { - return fDecNumber->digits; - } -} - -void -DigitList::setDigit(int32_t i, char v) { - int32_t count = fDecNumber->digits; - U_ASSERT(i='0' && v<='9'); - v &= 0x0f; - fDecNumber->lsu[count-i-1] = v; - internalClear(); -} - -char -DigitList::getDigit(int32_t i) { - int32_t count = fDecNumber->digits; - U_ASSERT(ilsu[count-i-1] + '0'; -} - -// copied from DigitList::getDigit() -uint8_t -DigitList::getDigitValue(int32_t i) { - int32_t count = fDecNumber->digits; - U_ASSERT(ilsu[count-i-1]; -} - -// ------------------------------------- -// Appends the digit to the digit list if it's not out of scope. -// Ignores the digit, otherwise. -// -// This function is horribly inefficient to implement with decNumber because -// the digits are stored least significant first, which requires moving all -// existing digits down one to make space for the new one to be appended. -// -void -DigitList::append(char digit) -{ - U_ASSERT(digit>='0' && digit<='9'); - // Ignore digits which exceed the precision we can represent - // And don't fix for larger precision. Fix callers instead. - if (decNumberIsZero(fDecNumber)) { - // Zero needs to be special cased because of the difference in the way - // that the old DigitList and decNumber represent it. - // digit cout was zero for digitList, is one for decNumber - fDecNumber->lsu[0] = digit & 0x0f; - fDecNumber->digits = 1; - fDecNumber->exponent--; // To match the old digit list implementation. - } else { - int32_t nDigits = fDecNumber->digits; - if (nDigits < fContext.digits) { - int i; - for (i=nDigits; i>0; i--) { - fDecNumber->lsu[i] = fDecNumber->lsu[i-1]; - } - fDecNumber->lsu[0] = digit & 0x0f; - fDecNumber->digits++; - // DigitList emulation - appending doesn't change the magnitude of existing - // digits. With decNumber's decimal being after the - // least signficant digit, we need to adjust the exponent. - fDecNumber->exponent--; - } - } - internalClear(); -} - -// ------------------------------------- - -/** - * Currently, getDouble() depends on strtod() to do its conversion. - * - * WARNING!! - * This is an extremely costly function. ~1/2 of the conversion time - * can be linked to this function. - */ -double -DigitList::getDouble() const -{ - { - Mutex mutex; - if (fHave == kDouble) { - return fUnion.fDouble; - } - } - - double tDouble = 0.0; - if (isZero()) { - tDouble = 0.0; - if (decNumberIsNegative(fDecNumber)) { - tDouble /= -1; - } - } else if (isInfinite()) { - if (std::numeric_limits::has_infinity) { - tDouble = std::numeric_limits::infinity(); - } else { - tDouble = std::numeric_limits::max(); - } - if (!isPositive()) { - tDouble = -tDouble; //this was incorrectly "-fDouble" originally. - } - } else { - MaybeStackArray s; - // Note: 14 is a magic constant from the decNumber library documentation, - // the max number of extra characters beyond the number of digits - // needed to represent the number in string form. Add a few more - // for the additional digits we retain. - - // Round down to appx. double precision, if the number is longer than that. - // Copy the number first, so that we don't modify the original. - if (getCount() > MAX_DBL_DIGITS + 3) { - DigitList numToConvert(*this); - numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good. - numToConvert.round(MAX_DBL_DIGITS+3); - uprv_decNumberToString(numToConvert.fDecNumber, s.getAlias()); - // TODO: how many extra digits should be included for an accurate conversion? - } else { - uprv_decNumberToString(this->fDecNumber, s.getAlias()); - } - U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18); - - char *end = NULL; - tDouble = decimalStrToDouble(s.getAlias(), &end); - } - { - Mutex mutex; - DigitList *nonConstThis = const_cast(this); - nonConstThis->internalSetDouble(tDouble); - } - return tDouble; -} - -#if U_USE_STRTOD_L && U_PLATFORM_USES_ONLY_WIN32_API -# define locale_t _locale_t -# define freelocale _free_locale -# define strtod_l _strtod_l -#endif - -#if U_USE_STRTOD_L -static locale_t gCLocale = (locale_t)0; -#endif -static icu::UInitOnce gCLocaleInitOnce = U_INITONCE_INITIALIZER; - -U_CDECL_BEGIN -// Cleanup callback func -static UBool U_CALLCONV digitList_cleanup(void) -{ -#if U_USE_STRTOD_L - if (gCLocale != (locale_t)0) { - freelocale(gCLocale); - } -#endif - return TRUE; -} -// C Locale initialization func -static void U_CALLCONV initCLocale(void) { - ucln_i18n_registerCleanup(UCLN_I18N_DIGITLIST, digitList_cleanup); -#if U_USE_STRTOD_L -# if U_PLATFORM_USES_ONLY_WIN32_API - gCLocale = _create_locale(LC_ALL, "C"); -# else - gCLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0); -# endif -#endif -} -U_CDECL_END - -double -DigitList::decimalStrToDouble(char *decstr, char **end) { - umtx_initOnce(gCLocaleInitOnce, &initCLocale); -#if U_USE_STRTOD_L - return strtod_l(decstr, end, gCLocale); -#else - char *decimalPt = strchr(decstr, '.'); - if (decimalPt) { - // We need to know the decimal separator character that will be used with strtod(). - // Depends on the C runtime global locale. - // Most commonly is '.' - char rep[MAX_DIGITS]; - sprintf(rep, "%+1.1f", 1.0); - *decimalPt = rep[2]; - } - return uprv_strtod(decstr, end); -#endif -} - -// ------------------------------------- - -/** - * convert this number to an int32_t. Round if there is a fractional part. - * Return zero if the number cannot be represented. - */ -int32_t DigitList::getLong() /*const*/ -{ - int32_t result = 0; - if (getUpperExponent() > 10) { - // Overflow, absolute value too big. - return result; - } - if (fDecNumber->exponent != 0) { - // Force to an integer, with zero exponent, rounding if necessary. - // (decNumberToInt32 will only work if the exponent is exactly zero.) - DigitList copy(*this); - DigitList zero; - uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext); - result = uprv_decNumberToInt32(copy.fDecNumber, &fContext); - } else { - result = uprv_decNumberToInt32(fDecNumber, &fContext); - } - return result; -} - - -/** - * convert this number to an int64_t. Truncate if there is a fractional part. - * Return zero if the number cannot be represented. - */ -int64_t DigitList::getInt64() /*const*/ { - // TODO: fast conversion if fHave == fDouble - - // Truncate if non-integer. - // Return 0 if out of range. - // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits) - // - if (getUpperExponent() > 19) { - // Overflow, absolute value too big. - return 0; - } - - // The number of integer digits may differ from the number of digits stored - // in the decimal number. - // for 12.345 numIntDigits = 2, number->digits = 5 - // for 12E4 numIntDigits = 6, number->digits = 2 - // The conversion ignores the fraction digits in the first case, - // and fakes up extra zero digits in the second. - // TODO: It would be faster to store a table of powers of ten to multiply by - // instead of looping over zero digits, multiplying each time. - - int32_t numIntDigits = getUpperExponent(); - uint64_t value = 0; - for (int32_t i = 0; i < numIntDigits; i++) { - // Loop is iterating over digits starting with the most significant. - // Numbers are stored with the least significant digit at index zero. - int32_t digitIndex = fDecNumber->digits - i - 1; - int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0; - value = value * (uint64_t)10 + (uint64_t)v; - } - - if (decNumberIsNegative(fDecNumber)) { - value = ~value; - value += 1; - } - int64_t svalue = (int64_t)value; - - // Check overflow. It's convenient that the MSD is 9 only on overflow, the amount of - // overflow can't wrap too far. The test will also fail -0, but - // that does no harm; the right answer is 0. - if (numIntDigits == 19) { - if (( decNumberIsNegative(fDecNumber) && svalue>0) || - (!decNumberIsNegative(fDecNumber) && svalue<0)) { - svalue = 0; - } - } - - return svalue; -} - - -/** - * Return a string form of this number. - * Format is as defined by the decNumber library, for interchange of - * decimal numbers. - */ -void DigitList::getDecimal(CharString &str, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - - // A decimal number in string form can, worst case, be 14 characters longer - // than the number of digits. So says the decNumber library doc. - int32_t maxLength = fDecNumber->digits + 14; - int32_t capacity = 0; - char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status); - if (U_FAILURE(status)) { - return; // Memory allocation error on growing the string. - } - U_ASSERT(capacity >= maxLength); - uprv_decNumberToString(this->fDecNumber, buffer); - U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength); - str.append(buffer, -1, status); -} - -/** - * Return true if this is an integer value that can be held - * by an int32_t type. - */ -UBool -DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/ -{ - if (decNumberIsSpecial(this->fDecNumber)) { - // NaN or Infinity. Does not fit in int32. - return FALSE; - } - uprv_decNumberTrim(this->fDecNumber); - if (fDecNumber->exponent < 0) { - // Number contains fraction digits. - return FALSE; - } - if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero && - (fDecNumber->bits & DECNEG) != 0) { - // Negative Zero, not ingored. Cannot represent as a long. - return FALSE; - } - if (getUpperExponent() < 10) { - // The number is 9 or fewer digits. - // The max and min int32 are 10 digts, so this number fits. - // This is the common case. - return TRUE; - } - - // TODO: Should cache these constants; construction is relatively costly. - // But not of huge consequence; they're only needed for 10 digit ints. - UErrorCode status = U_ZERO_ERROR; - DigitList min32; min32.set("-2147483648", status); - if (this->compare(min32) < 0) { - return FALSE; - } - DigitList max32; max32.set("2147483647", status); - if (this->compare(max32) > 0) { - return FALSE; - } - if (U_FAILURE(status)) { - return FALSE; - } - return true; -} - - - -/** - * Return true if the number represented by this object can fit into - * a long. - */ -UBool -DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/ -{ - if (decNumberIsSpecial(this->fDecNumber)) { - // NaN or Infinity. Does not fit in int32. - return FALSE; - } - uprv_decNumberTrim(this->fDecNumber); - if (fDecNumber->exponent < 0) { - // Number contains fraction digits. - return FALSE; - } - if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero && - (fDecNumber->bits & DECNEG) != 0) { - // Negative Zero, not ingored. Cannot represent as a long. - return FALSE; - } - if (getUpperExponent() < 19) { - // The number is 18 or fewer digits. - // The max and min int64 are 19 digts, so this number fits. - // This is the common case. - return TRUE; - } - - // TODO: Should cache these constants; construction is relatively costly. - // But not of huge consequence; they're only needed for 19 digit ints. - UErrorCode status = U_ZERO_ERROR; - DigitList min64; min64.set("-9223372036854775808", status); - if (this->compare(min64) < 0) { - return FALSE; - } - DigitList max64; max64.set("9223372036854775807", status); - if (this->compare(max64) > 0) { - return FALSE; - } - if (U_FAILURE(status)) { - return FALSE; - } - return true; -} - - -// ------------------------------------- - -void -DigitList::set(int32_t source) -{ - set((int64_t)source); - internalSetDouble(source); -} - -// ------------------------------------- -/** - * Set an int64, via decnumber - */ -void -DigitList::set(int64_t source) -{ - char str[MAX_DIGITS+2]; // Leave room for sign and trailing nul. - formatBase10(source, str); - U_ASSERT(uprv_strlen(str) < sizeof(str)); - - uprv_decNumberFromString(fDecNumber, str, &fContext); - internalSetDouble(static_cast(source)); -} - -// ------------------------------------- -/** - * Set the DigitList from a decimal number string. - * - * The incoming string _must_ be nul terminated, even though it is arriving - * as a StringPiece because that is what the decNumber library wants. - * We can get away with this for an internal function; it would not - * be acceptable for a public API. - */ -void -DigitList::set(StringPiece source, UErrorCode &status, uint32_t /*fastpathBits*/) { - if (U_FAILURE(status)) { - return; - } - -#if 0 - if(fastpathBits==(kFastpathOk|kNoDecimal)) { - int32_t size = source.size(); - const char *data = source.data(); - int64_t r = 0; - int64_t m = 1; - // fast parse - while(size>0) { - char ch = data[--size]; - if(ch=='+') { - break; - } else if(ch=='-') { - r = -r; - break; - } else { - int64_t d = ch-'0'; - //printf("CH[%d]=%c, %d, *=%d\n", size,ch, (int)d, (int)m); - r+=(d)*m; - m *= 10; - } - } - //printf("R=%d\n", r); - set(r); - } else -#endif - { - // Figure out a max number of digits to use during the conversion, and - // resize the number up if necessary. - int32_t numDigits = source.length(); - if (numDigits > fContext.digits) { - // fContext.digits == fStorage.getCapacity() - decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity()); - if (t == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - fDecNumber = t; - fContext.digits = numDigits; - } - - fContext.status = 0; - uprv_decNumberFromString(fDecNumber, source.data(), &fContext); - if ((fContext.status & DEC_Conversion_syntax) != 0) { - status = U_DECIMAL_NUMBER_SYNTAX_ERROR; - } - } - internalClear(); -} - -/** - * Set the digit list to a representation of the given double value. - * This method supports both fixed-point and exponential notation. - * @param source Value to be converted. - */ -void -DigitList::set(double source) -{ - // for now, simple implementation; later, do proper IEEE stuff - char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough) - - // Generate a representation of the form /[+-][0-9].[0-9]+e[+-][0-9]+/ - // Can also generate /[+-]nan/ or /[+-]inf/ - // TODO: Use something other than sprintf() here, since it's behavior is somewhat platform specific. - // That is why infinity is special cased here. - if (uprv_isInfinite(source)) { - if (uprv_isNegativeInfinity(source)) { - uprv_strcpy(rep,"-inf"); // Handle negative infinity - } else { - uprv_strcpy(rep,"inf"); - } - } else if (uprv_isNaN(source)) { - uprv_strcpy(rep, "NaN"); - } else { - bool sign; - int32_t length; - int32_t point; - DoubleToStringConverter::DoubleToAscii( - source, - DoubleToStringConverter::DtoaMode::SHORTEST, - 0, - rep + 1, - sizeof(rep), - &sign, - &length, - &point - ); - - // Convert the raw buffer into a string for decNumber - int32_t power = point - length; - if (sign) { - rep[0] = '-'; - } else { - rep[0] = '0'; - } - length++; - rep[length++] = 'E'; - if (power < 0) { - rep[length++] = '-'; - power = -power; - } else { - rep[length++] = '+'; - } - if (power < 10) { - rep[length++] = power + '0'; - } else if (power < 100) { - rep[length++] = (power / 10) + '0'; - rep[length++] = (power % 10) + '0'; - } else { - U_ASSERT(power < 1000); - rep[length + 2] = (power % 10) + '0'; - power /= 10; - rep[length + 1] = (power % 10) + '0'; - power /= 10; - rep[length] = power + '0'; - length += 3; - } - rep[length++] = 0; - } - U_ASSERT(uprv_strlen(rep) < sizeof(rep)); - - // uprv_decNumberFromString() will parse the string expecting '.' as a - // decimal separator, however sprintf() can use ',' in certain locales. - // Overwrite a ',' with '.' here before proceeding. - char *decimalSeparator = strchr(rep, ','); - if (decimalSeparator != NULL) { - *decimalSeparator = '.'; - } - - // Create a decNumber from the string. - uprv_decNumberFromString(fDecNumber, rep, &fContext); - uprv_decNumberTrim(fDecNumber); - internalSetDouble(source); -} - -// ------------------------------------- - -/* - * Multiply - * The number will be expanded if need be to retain full precision. - * In practice, for formatting, multiply is by 10, 100 or 1000, so more digits - * will not be required for this use. - */ -void -DigitList::mult(const DigitList &other, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - fContext.status = 0; - int32_t requiredDigits = this->digits() + other.digits(); - if (requiredDigits > fContext.digits) { - reduce(); // Remove any trailing zeros - int32_t requiredDigits = this->digits() + other.digits(); - ensureCapacity(requiredDigits, status); - } - uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext); - internalClear(); -} - -// ------------------------------------- - -/* - * Divide - * The number will _not_ be expanded for inexact results. - * TODO: probably should expand some, for rounding increments that - * could add a few digits, e.g. .25, but not expand arbitrarily. - */ -void -DigitList::div(const DigitList &other, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext); - internalClear(); -} - -// ------------------------------------- - -/* - * ensureCapacity. Grow the digit storage for the number if it's less than the requested - * amount. Never reduce it. Available size is kept in fContext.digits. - */ -void -DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - if (requestedCapacity <= 0) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - if (requestedCapacity > DEC_MAX_DIGITS) { - // Don't report an error for requesting too much. - // Arithemetic Results will be rounded to what can be supported. - // At 999,999,999 max digits, exceeding the limit is not too likely! - requestedCapacity = DEC_MAX_DIGITS; - } - if (requestedCapacity > fContext.digits) { - decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity()); - if (newBuffer == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - fContext.digits = requestedCapacity; - fDecNumber = newBuffer; - } -} - -// ------------------------------------- - -/** - * Round the representation to the given number of digits. - * @param maximumDigits The maximum number of digits to be shown. - * Upon return, count will be less than or equal to maximumDigits. - */ -void -DigitList::round(int32_t maximumDigits) -{ - reduce(); - if (maximumDigits >= fDecNumber->digits) { - return; - } - int32_t savedDigits = fContext.digits; - fContext.digits = maximumDigits; - uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext); - fContext.digits = savedDigits; - uprv_decNumberTrim(fDecNumber); - reduce(); - internalClear(); -} - - -void -DigitList::roundFixedPoint(int32_t maximumFractionDigits) { - reduce(); // Remove trailing zeros. - if (fDecNumber->exponent >= -maximumFractionDigits) { - return; - } - decNumber scale; // Dummy decimal number, but with the desired number of - uprv_decNumberZero(&scale); // fraction digits. - scale.exponent = -maximumFractionDigits; - scale.lsu[0] = 1; - - uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext); - reduce(); - internalClear(); -} - -// ------------------------------------- - -void -DigitList::toIntegralValue() { - uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext); -} - - -// ------------------------------------- -UBool -DigitList::isZero() const -{ - return decNumberIsZero(fDecNumber); -} - -// ------------------------------------- -int32_t -DigitList::getUpperExponent() const { - return fDecNumber->digits + fDecNumber->exponent; -} - -DigitInterval & -DigitList::getSmallestInterval(DigitInterval &result) const { - result.setLeastSignificantInclusive(fDecNumber->exponent); - result.setMostSignificantExclusive(getUpperExponent()); - return result; -} - -uint8_t -DigitList::getDigitByExponent(int32_t exponent) const { - int32_t idx = exponent - fDecNumber->exponent; - if (idx < 0 || idx >= fDecNumber->digits) { - return 0; - } - return fDecNumber->lsu[idx]; -} - -void -DigitList::appendDigitsTo(CharString &str, UErrorCode &status) const { - str.append((const char *) fDecNumber->lsu, fDecNumber->digits, status); -} - -void -DigitList::roundAtExponent(int32_t exponent, int32_t maxSigDigits) { - reduce(); - if (maxSigDigits < fDecNumber->digits) { - int32_t minExponent = getUpperExponent() - maxSigDigits; - if (exponent < minExponent) { - exponent = minExponent; - } - } - if (exponent <= fDecNumber->exponent) { - return; - } - int32_t digits = getUpperExponent() - exponent; - if (digits > 0) { - round(digits); - } else { - roundFixedPoint(-exponent); - } -} - -void -DigitList::quantize(const DigitList &quantity, UErrorCode &status) { - if (U_FAILURE(status)) { - return; - } - div(quantity, status); - roundAtExponent(0); - mult(quantity, status); - reduce(); -} - -int32_t -DigitList::getScientificExponent( - int32_t minIntDigitCount, int32_t exponentMultiplier) const { - // The exponent for zero is always zero. - if (isZero()) { - return 0; - } - int32_t intDigitCount = getUpperExponent(); - int32_t exponent; - if (intDigitCount >= minIntDigitCount) { - int32_t maxAdjustment = intDigitCount - minIntDigitCount; - exponent = (maxAdjustment / exponentMultiplier) * exponentMultiplier; - } else { - int32_t minAdjustment = minIntDigitCount - intDigitCount; - exponent = ((minAdjustment + exponentMultiplier - 1) / exponentMultiplier) * -exponentMultiplier; - } - return exponent; -} - -int32_t -DigitList::toScientific( - int32_t minIntDigitCount, int32_t exponentMultiplier) { - int32_t exponent = getScientificExponent( - minIntDigitCount, exponentMultiplier); - shiftDecimalRight(-exponent); - return exponent; -} - -void -DigitList::shiftDecimalRight(int32_t n) { - fDecNumber->exponent += n; - internalClear(); -} - -U_NAMESPACE_END -#endif // #if !UCONFIG_NO_FORMATTING - -//eof diff --git a/deps/icu-small/source/i18n/digitlst.h b/deps/icu-small/source/i18n/digitlst.h deleted file mode 100644 index 6befaf32e6..0000000000 --- a/deps/icu-small/source/i18n/digitlst.h +++ /dev/null @@ -1,529 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -****************************************************************************** -* -* Copyright (C) 1997-2015, International Business Machines -* Corporation and others. All Rights Reserved. -* -****************************************************************************** -* -* File DIGITLST.H -* -* Modification History: -* -* Date Name Description -* 02/25/97 aliu Converted from java. -* 03/21/97 clhuang Updated per C++ implementation. -* 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char. -* 09/09/97 aliu Adapted for exponential notation support. -* 08/02/98 stephen Added nearest/even rounding -* 06/29/99 stephen Made LONG_DIGITS a macro to satisfy SUN compiler -* 07/09/99 stephen Removed kMaxCount (unused, for HP compiler) -****************************************************************************** -*/ - -#ifndef DIGITLST_H -#define DIGITLST_H - -#include "unicode/uobject.h" - -#if !UCONFIG_NO_FORMATTING -#include "unicode/decimfmt.h" -#include -#include "decContext.h" -#include "decNumber.h" -#include "cmemory.h" - -// Decimal digits in a 64-bit int -#define INT64_DIGITS 19 - -typedef enum EDigitListValues { - MAX_DBL_DIGITS = DBL_DIG, - MAX_I64_DIGITS = INT64_DIGITS, - MAX_DIGITS = MAX_I64_DIGITS, - MAX_EXPONENT = DBL_DIG, - DIGIT_PADDING = 3, - DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed. - - // "+." + fDigits + "e" + fDecimalAt - MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT -} EDigitListValues; - -U_NAMESPACE_BEGIN - -class CharString; -class DigitInterval; - -// Export an explicit template instantiation of the MaybeStackHeaderAndArray that -// is used as a data member of DigitList. -// -// MSVC requires this, even though it should not be necessary. -// No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library. -// -// Macintosh produces duplicate definition linker errors with the explicit template -// instantiation. -// -#if !U_PLATFORM_IS_DARWIN_BASED -template class U_I18N_API MaybeStackHeaderAndArray; -#endif - - -enum EStackMode { kOnStack }; - -enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 }; - -/** - * Digit List is actually a Decimal Floating Point number. - * The original implementation has been replaced by a thin wrapper onto a - * decimal number from the decNumber library. - * - * The original DigitList API has been retained, to minimize the impact of - * the change on the rest of the ICU formatting code. - * - * The change to decNumber enables support for big decimal numbers, and - * allows rounding computations to be done directly in decimal, avoiding - * extra, and inaccurate, conversions to and from doubles. - * - * Original DigitList comments: - * - * Digit List utility class. Private to DecimalFormat. Handles the transcoding - * between numeric values and strings of characters. Only handles - * non-negative numbers. The division of labor between DigitList and - * DecimalFormat is that DigitList handles the radix 10 representation - * issues; DecimalFormat handles the locale-specific issues such as - * positive/negative, grouping, decimal point, currency, and so on. - *

- * A DigitList is really a representation of a floating point value. - * It may be an integer value; we assume that a double has sufficient - * precision to represent all digits of a long. - *

- * The DigitList representation consists of a string of characters, - * which are the digits radix 10, from '0' to '9'. It also has a radix - * 10 exponent associated with it. The value represented by a DigitList - * object can be computed by mulitplying the fraction f, where 0 <= f < 1, - * derived by placing all the digits of the list to the right of the - * decimal point, by 10^exponent. - * - * -------- - * - * DigitList vs. decimalNumber: - * - * DigitList stores digits with the most significant first. - * decNumber stores digits with the least significant first. - * - * DigitList, decimal point is before the most significant. - * decNumber, decimal point is after the least signficant digit. - * - * digitList: 0.ddddd * 10 ^ exp - * decNumber: ddddd. * 10 ^ exp - * - * digitList exponent = decNumber exponent + digit count - * - * digitList, digits are platform invariant chars, '0' - '9' - * decNumber, digits are binary, one per byte, 0 - 9. - * - * (decNumber library is configurable in how digits are stored, ICU has configured - * it this way for convenience in replacing the old DigitList implementation.) - */ -class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy -public: - - DigitList(); - ~DigitList(); - - /* copy constructor - * @param DigitList The object to be copied. - * @return the newly created object. - */ - DigitList(const DigitList&); // copy constructor - - /* assignment operator - * @param DigitList The object to be copied. - * @return the newly created object. - */ - DigitList& operator=(const DigitList&); // assignment operator - - /** - * Return true if another object is semantically equal to this one. - * @param other The DigitList to be compared for equality - * @return true if another object is semantically equal to this one. - * return false otherwise. - */ - UBool operator==(const DigitList& other) const; - - int32_t compare(const DigitList& other); - - - inline UBool operator!=(const DigitList& other) const { return !operator==(other); } - - /** - * Clears out the digits. - * Use before appending them. - * Typically, you set a series of digits with append, then at the point - * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount; - * then go on appending digits. - */ - void clear(void); - - /** - * Remove, by rounding, any fractional part of the decimal number, - * leaving an integer value. - */ - void toIntegralValue(); - - /** - * Appends digits to the list. - * CAUTION: this function is not recommended for new code. - * In the original DigitList implementation, decimal numbers were - * parsed by appending them to a digit list as they were encountered. - * With the revamped DigitList based on decNumber, append is very - * inefficient, and the interaction with the exponent value is confusing. - * Best avoided. - * TODO: remove this function once all use has been replaced. - * TODO: describe alternative to append() - * @param digit The digit to be appended. - */ - void append(char digit); - - /** - * Utility routine to get the value of the digit list - * Returns 0.0 if zero length. - * @return the value of the digit list. - */ - double getDouble(void) const; - - /** - * Utility routine to get the value of the digit list - * Make sure that fitsIntoLong() is called before calling this function. - * Returns 0 if zero length. - * @return the value of the digit list, return 0 if it is zero length - */ - int32_t getLong(void) /*const*/; - - /** - * Utility routine to get the value of the digit list - * Make sure that fitsIntoInt64() is called before calling this function. - * Returns 0 if zero length. - * @return the value of the digit list, return 0 if it is zero length - */ - int64_t getInt64(void) /*const*/; - - /** - * Utility routine to get the value of the digit list as a decimal string. - */ - void getDecimal(CharString &str, UErrorCode &status); - - /** - * Return true if the number represented by this object can fit into - * a long. - * @param ignoreNegativeZero True if negative zero is ignored. - * @return true if the number represented by this object can fit into - * a long, return false otherwise. - */ - UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/; - - /** - * Return true if the number represented by this object can fit into - * an int64_t. - * @param ignoreNegativeZero True if negative zero is ignored. - * @return true if the number represented by this object can fit into - * a long, return false otherwise. - */ - UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/; - - /** - * Utility routine to set the value of the digit list from a double. - * @param source The value to be set - */ - void set(double source); - - /** - * Utility routine to set the value of the digit list from a long. - * If a non-zero maximumDigits is specified, no more than that number of - * significant digits will be produced. - * @param source The value to be set - */ - void set(int32_t source); - - /** - * Utility routine to set the value of the digit list from an int64. - * If a non-zero maximumDigits is specified, no more than that number of - * significant digits will be produced. - * @param source The value to be set - */ - void set(int64_t source); - - /** - * Utility routine to set the value of the digit list from an int64. - * Does not set the decnumber unless requested later - * If a non-zero maximumDigits is specified, no more than that number of - * significant digits will be produced. - * @param source The value to be set - */ - void setInteger(int64_t source); - - /** - * Utility routine to set the value of the digit list from a decimal number - * string. - * @param source The value to be set. The string must be nul-terminated. - * @param fastpathBits special flags for fast parsing - */ - void set(StringPiece source, UErrorCode &status, uint32_t fastpathBits = 0); - - /** - * Multiply this = this * arg - * This digitlist will be expanded if necessary to accomodate the result. - * @param arg the number to multiply by. - */ - void mult(const DigitList &arg, UErrorCode &status); - - /** - * Divide this = this / arg - */ - void div(const DigitList &arg, UErrorCode &status); - - // The following functions replace direct access to the original DigitList implmentation - // data structures. - - void setRoundingMode(DecimalFormat::ERoundingMode m); - - /** Test a number for zero. - * @return TRUE if the number is zero - */ - UBool isZero(void) const; - - /** Test for a Nan - * @return TRUE if the number is a NaN - */ - UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);} - - UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);} - - /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */ - void reduce(); - - /** Remove trailing fraction zeros, adjust exponent accordingly. */ - void trim(); - - /** Set to zero */ - void setToZero() {uprv_decNumberZero(fDecNumber);} - - /** get the number of digits in the decimal number */ - int32_t digits() const {return fDecNumber->digits;} - - /** - * Round the number to the given number of digits. - * @param maximumDigits The maximum number of digits to be shown. - * Upon return, count will be less than or equal to maximumDigits. - * result is guaranteed to be trimmed. - */ - void round(int32_t maximumDigits); - - void roundFixedPoint(int32_t maximumFractionDigits); - - /** Ensure capacity for digits. Grow the storage if it is currently less than - * the requested size. Capacity is not reduced if it is already greater - * than requested. - */ - void ensureCapacity(int32_t requestedSize, UErrorCode &status); - - UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;} - void setPositive(UBool s); - - void setDecimalAt(int32_t d); - int32_t getDecimalAt(); - - void setCount(int32_t c); - int32_t getCount() const; - - /** - * Set the digit in platform (invariant) format, from '0'..'9' - * @param i index of digit - * @param v digit value, from '0' to '9' in platform invariant format - */ - void setDigit(int32_t i, char v); - - /** - * Get the digit in platform (invariant) format, from '0'..'9' inclusive - * @param i index of digit - * @return invariant format of the digit - */ - char getDigit(int32_t i); - - - /** - * Get the digit's value, as an integer from 0..9 inclusive. - * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t. - * @param i index of digit - * @return value of that digit - */ - uint8_t getDigitValue(int32_t i); - - /** - * Gets the upper bound exponent for this value. For 987, returns 3 - * because 10^3 is the smallest power of 10 that is just greater than - * 987. - */ - int32_t getUpperExponent() const; - - /** - * Gets the lower bound exponent for this value. For 98.7, returns -1 - * because the right most digit, is the 10^-1 place. - */ - int32_t getLowerExponent() const { return fDecNumber->exponent; } - - /** - * Sets result to the smallest DigitInterval needed to display this - * DigitList in fixed point form and returns result. - */ - DigitInterval& getSmallestInterval(DigitInterval &result) const; - - /** - * Like getDigitValue, but the digit is identified by exponent. - * For example, getDigitByExponent(7) returns the 10^7 place of this - * DigitList. Unlike getDigitValue, there are no upper or lower bounds - * for passed parameter. Instead, getDigitByExponent returns 0 if - * the exponent falls outside the interval for this DigitList. - */ - uint8_t getDigitByExponent(int32_t exponent) const; - - /** - * Appends the digits in this object to a CharString. - * 3 is appended as (char) 3, not '3' - */ - void appendDigitsTo(CharString &str, UErrorCode &status) const; - - /** - * Equivalent to roundFixedPoint(-digitExponent) except unlike - * roundFixedPoint, this works for any digitExponent value. - * If maxSigDigits is set then this instance is rounded to have no more - * than maxSigDigits. The end result is guaranteed to be trimmed. - */ - void roundAtExponent(int32_t digitExponent, int32_t maxSigDigits=INT32_MAX); - - /** - * Quantizes according to some amount and rounds according to the - * context of this instance. Quantizing 3.233 with 0.05 gives 3.25. - */ - void quantize(const DigitList &amount, UErrorCode &status); - - /** - * Like toScientific but only returns the exponent - * leaving this instance unchanged. - */ - int32_t getScientificExponent( - int32_t minIntDigitCount, int32_t exponentMultiplier) const; - - /** - * Converts this instance to scientific notation. This instance - * becomes the mantissa and the exponent is returned. - * @param minIntDigitCount minimum integer digits in mantissa - * Exponent is set so that the actual number of integer digits - * in mantissa is as close to the minimum as possible. - * @param exponentMultiplier The exponent is always a multiple of - * This number. Usually 1, but set to 3 for engineering notation. - * @return exponent - */ - int32_t toScientific( - int32_t minIntDigitCount, int32_t exponentMultiplier); - - /** - * Shifts decimal to the right. - */ - void shiftDecimalRight(int32_t numPlaces); - -private: - /* - * These data members are intentionally public and can be set directly. - *

- * The value represented is given by placing the decimal point before - * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between - * the decimal point and the first nonzero digit are implied. If fDecimalAt - * is > fCount, then trailing zeros between the fDigits[fCount-1] and the - * decimal point are implied. - *

- * Equivalently, the represented value is given by f * 10^fDecimalAt. Here - * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to - * the right of the decimal. - *

- * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We - * don't allow denormalized numbers because our exponent is effectively of - * unlimited magnitude. The fCount value contains the number of significant - * digits present in fDigits[]. - *

- * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i] - * for all i <= fCount == '0'. - * - * int32_t fDecimalAt; - * int32_t fCount; - * UBool fIsPositive; - * char *fDigits; - * DecimalFormat::ERoundingMode fRoundingMode; - */ - -public: - decContext fContext; // public access to status flags. - -private: - decNumber *fDecNumber; - MaybeStackHeaderAndArray fStorage; - - /* Cached double value corresponding to this decimal number. - * This is an optimization for the formatting implementation, which may - * ask for the double value multiple times. - */ - union DoubleOrInt64 { - double fDouble; - int64_t fInt64; - } fUnion; - enum EHave { - kNone=0, - kDouble - } fHave; - - - - UBool shouldRoundUp(int32_t maximumDigits) const; - - public: - -#if U_OVERRIDE_CXX_ALLOCATION - using UMemory::operator new; - using UMemory::operator delete; -#else - static inline void * U_EXPORT2 operator new(size_t size) U_NO_THROW { return ::operator new(size); }; - static inline void U_EXPORT2 operator delete(void *ptr ) U_NO_THROW { ::operator delete(ptr); }; -#endif - - static double U_EXPORT2 decimalStrToDouble(char *decstr, char **end); - - /** - * Placement new for stack usage - * @internal - */ - static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; } - - /** - * Placement delete for stack usage - * @internal - */ - static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {} - - private: - inline void internalSetDouble(double d) { - fHave = kDouble; - fUnion.fDouble=d; - } - inline void internalClear() { - fHave = kNone; - } -}; - - -U_NAMESPACE_END - -#endif // #if !UCONFIG_NO_FORMATTING -#endif // _DIGITLST - -//eof diff --git a/deps/icu-small/source/i18n/double-conversion-strtod.cpp b/deps/icu-small/source/i18n/double-conversion-strtod.cpp new file mode 100644 index 0000000000..be9b0b3bce --- /dev/null +++ b/deps/icu-small/source/i18n/double-conversion-strtod.cpp @@ -0,0 +1,574 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +// +// From the double-conversion library. Original license: +// +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ICU PATCH: ifdef around UCONFIG_NO_FORMATTING +#include "unicode/utypes.h" +#if !UCONFIG_NO_FORMATTING + +#include +#include + +// ICU PATCH: Customize header file paths for ICU. +// The file fixed-dtoa.h is not needed. + +#include "double-conversion-strtod.h" +#include "double-conversion-bignum.h" +#include "double-conversion-cached-powers.h" +#include "double-conversion-ieee.h" + +// ICU PATCH: Wrap in ICU namespace +U_NAMESPACE_BEGIN + +namespace double_conversion { + +// 2^53 = 9007199254740992. +// Any integer with at most 15 decimal digits will hence fit into a double +// (which has a 53bit significand) without loss of precision. +static const int kMaxExactDoubleIntegerDecimalDigits = 15; +// 2^64 = 18446744073709551616 > 10^19 +static const int kMaxUint64DecimalDigits = 19; + +// Max double: 1.7976931348623157 x 10^308 +// Min non-zero double: 4.9406564584124654 x 10^-324 +// Any x >= 10^309 is interpreted as +infinity. +// Any x <= 10^-324 is interpreted as 0. +// Note that 2.5e-324 (despite being smaller than the min double) will be read +// as non-zero (equal to the min non-zero double). +static const int kMaxDecimalPower = 309; +static const int kMinDecimalPower = -324; + +// 2^64 = 18446744073709551616 +static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); + + +static const double exact_powers_of_ten[] = { + 1.0, // 10^0 + 10.0, + 100.0, + 1000.0, + 10000.0, + 100000.0, + 1000000.0, + 10000000.0, + 100000000.0, + 1000000000.0, + 10000000000.0, // 10^10 + 100000000000.0, + 1000000000000.0, + 10000000000000.0, + 100000000000000.0, + 1000000000000000.0, + 10000000000000000.0, + 100000000000000000.0, + 1000000000000000000.0, + 10000000000000000000.0, + 100000000000000000000.0, // 10^20 + 1000000000000000000000.0, + // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22 + 10000000000000000000000.0 +}; +static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten); + +// Maximum number of significant digits in the decimal representation. +// In fact the value is 772 (see conversions.cc), but to give us some margin +// we round up to 780. +static const int kMaxSignificantDecimalDigits = 780; + +static Vector TrimLeadingZeros(Vector buffer) { + for (int i = 0; i < buffer.length(); i++) { + if (buffer[i] != '0') { + return buffer.SubVector(i, buffer.length()); + } + } + return Vector(buffer.start(), 0); +} + + +static Vector TrimTrailingZeros(Vector buffer) { + for (int i = buffer.length() - 1; i >= 0; --i) { + if (buffer[i] != '0') { + return buffer.SubVector(0, i + 1); + } + } + return Vector(buffer.start(), 0); +} + + +static void CutToMaxSignificantDigits(Vector buffer, + int exponent, + char* significant_buffer, + int* significant_exponent) { + for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) { + significant_buffer[i] = buffer[i]; + } + // The input buffer has been trimmed. Therefore the last digit must be + // different from '0'. + ASSERT(buffer[buffer.length() - 1] != '0'); + // Set the last digit to be non-zero. This is sufficient to guarantee + // correct rounding. + significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; + *significant_exponent = + exponent + (buffer.length() - kMaxSignificantDecimalDigits); +} + + +// Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits. +// If possible the input-buffer is reused, but if the buffer needs to be +// modified (due to cutting), then the input needs to be copied into the +// buffer_copy_space. +static void TrimAndCut(Vector buffer, int exponent, + char* buffer_copy_space, int space_size, + Vector* trimmed, int* updated_exponent) { + Vector left_trimmed = TrimLeadingZeros(buffer); + Vector right_trimmed = TrimTrailingZeros(left_trimmed); + exponent += left_trimmed.length() - right_trimmed.length(); + if (right_trimmed.length() > kMaxSignificantDecimalDigits) { + (void) space_size; // Mark variable as used. + ASSERT(space_size >= kMaxSignificantDecimalDigits); + CutToMaxSignificantDigits(right_trimmed, exponent, + buffer_copy_space, updated_exponent); + *trimmed = Vector(buffer_copy_space, + kMaxSignificantDecimalDigits); + } else { + *trimmed = right_trimmed; + *updated_exponent = exponent; + } +} + + +// Reads digits from the buffer and converts them to a uint64. +// Reads in as many digits as fit into a uint64. +// When the string starts with "1844674407370955161" no further digit is read. +// Since 2^64 = 18446744073709551616 it would still be possible read another +// digit if it was less or equal than 6, but this would complicate the code. +static uint64_t ReadUint64(Vector buffer, + int* number_of_read_digits) { + uint64_t result = 0; + int i = 0; + while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { + int digit = buffer[i++] - '0'; + ASSERT(0 <= digit && digit <= 9); + result = 10 * result + digit; + } + *number_of_read_digits = i; + return result; +} + + +// Reads a DiyFp from the buffer. +// The returned DiyFp is not necessarily normalized. +// If remaining_decimals is zero then the returned DiyFp is accurate. +// Otherwise it has been rounded and has error of at most 1/2 ulp. +static void ReadDiyFp(Vector buffer, + DiyFp* result, + int* remaining_decimals) { + int read_digits; + uint64_t significand = ReadUint64(buffer, &read_digits); + if (buffer.length() == read_digits) { + *result = DiyFp(significand, 0); + *remaining_decimals = 0; + } else { + // Round the significand. + if (buffer[read_digits] >= '5') { + significand++; + } + // Compute the binary exponent. + int exponent = 0; + *result = DiyFp(significand, exponent); + *remaining_decimals = buffer.length() - read_digits; + } +} + + +static bool DoubleStrtod(Vector trimmed, + int exponent, + double* result) { +#if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) + // On x86 the floating-point stack can be 64 or 80 bits wide. If it is + // 80 bits wide (as is the case on Linux) then double-rounding occurs and the + // result is not accurate. + // We know that Windows32 uses 64 bits and is therefore accurate. + // Note that the ARM simulator is compiled for 32bits. It therefore exhibits + // the same problem. + return false; +#endif + if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { + int read_digits; + // The trimmed input fits into a double. + // If the 10^exponent (resp. 10^-exponent) fits into a double too then we + // can compute the result-double simply by multiplying (resp. dividing) the + // two numbers. + // This is possible because IEEE guarantees that floating-point operations + // return the best possible approximation. + if (exponent < 0 && -exponent < kExactPowersOfTenSize) { + // 10^-exponent fits into a double. + *result = static_cast(ReadUint64(trimmed, &read_digits)); + ASSERT(read_digits == trimmed.length()); + *result /= exact_powers_of_ten[-exponent]; + return true; + } + if (0 <= exponent && exponent < kExactPowersOfTenSize) { + // 10^exponent fits into a double. + *result = static_cast(ReadUint64(trimmed, &read_digits)); + ASSERT(read_digits == trimmed.length()); + *result *= exact_powers_of_ten[exponent]; + return true; + } + int remaining_digits = + kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); + if ((0 <= exponent) && + (exponent - remaining_digits < kExactPowersOfTenSize)) { + // The trimmed string was short and we can multiply it with + // 10^remaining_digits. As a result the remaining exponent now fits + // into a double too. + *result = static_cast(ReadUint64(trimmed, &read_digits)); + ASSERT(read_digits == trimmed.length()); + *result *= exact_powers_of_ten[remaining_digits]; + *result *= exact_powers_of_ten[exponent - remaining_digits]; + return true; + } + } + return false; +} + + +// Returns 10^exponent as an exact DiyFp. +// The given exponent must be in the range [1; kDecimalExponentDistance[. +static DiyFp AdjustmentPowerOfTen(int exponent) { + ASSERT(0 < exponent); + ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance); + // Simply hardcode the remaining powers for the given decimal exponent + // distance. + ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8); + switch (exponent) { + case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60); + case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57); + case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54); + case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50); + case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47); + case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44); + case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40); + default: + UNREACHABLE(); + } +} + + +// If the function returns true then the result is the correct double. +// Otherwise it is either the correct double or the double that is just below +// the correct double. +static bool DiyFpStrtod(Vector buffer, + int exponent, + double* result) { + DiyFp input; + int remaining_decimals; + ReadDiyFp(buffer, &input, &remaining_decimals); + // Since we may have dropped some digits the input is not accurate. + // If remaining_decimals is different than 0 than the error is at most + // .5 ulp (unit in the last place). + // We don't want to deal with fractions and therefore keep a common + // denominator. + const int kDenominatorLog = 3; + const int kDenominator = 1 << kDenominatorLog; + // Move the remaining decimals into the exponent. + exponent += remaining_decimals; + uint64_t error = (remaining_decimals == 0 ? 0 : kDenominator / 2); + + int old_e = input.e(); + input.Normalize(); + error <<= old_e - input.e(); + + ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent); + if (exponent < PowersOfTenCache::kMinDecimalExponent) { + *result = 0.0; + return true; + } + DiyFp cached_power; + int cached_decimal_exponent; + PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent, + &cached_power, + &cached_decimal_exponent); + + if (cached_decimal_exponent != exponent) { + int adjustment_exponent = exponent - cached_decimal_exponent; + DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent); + input.Multiply(adjustment_power); + if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) { + // The product of input with the adjustment power fits into a 64 bit + // integer. + ASSERT(DiyFp::kSignificandSize == 64); + } else { + // The adjustment power is exact. There is hence only an error of 0.5. + error += kDenominator / 2; + } + } + + input.Multiply(cached_power); + // The error introduced by a multiplication of a*b equals + // error_a + error_b + error_a*error_b/2^64 + 0.5 + // Substituting a with 'input' and b with 'cached_power' we have + // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp), + // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64 + int error_b = kDenominator / 2; + int error_ab = (error == 0 ? 0 : 1); // We round up to 1. + int fixed_error = kDenominator / 2; + error += error_b + error_ab + fixed_error; + + old_e = input.e(); + input.Normalize(); + error <<= old_e - input.e(); + + // See if the double's significand changes if we add/subtract the error. + int order_of_magnitude = DiyFp::kSignificandSize + input.e(); + int effective_significand_size = + Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude); + int precision_digits_count = + DiyFp::kSignificandSize - effective_significand_size; + if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) { + // This can only happen for very small denormals. In this case the + // half-way multiplied by the denominator exceeds the range of an uint64. + // Simply shift everything to the right. + int shift_amount = (precision_digits_count + kDenominatorLog) - + DiyFp::kSignificandSize + 1; + input.set_f(input.f() >> shift_amount); + input.set_e(input.e() + shift_amount); + // We add 1 for the lost precision of error, and kDenominator for + // the lost precision of input.f(). + error = (error >> shift_amount) + 1 + kDenominator; + precision_digits_count -= shift_amount; + } + // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too. + ASSERT(DiyFp::kSignificandSize == 64); + ASSERT(precision_digits_count < 64); + uint64_t one64 = 1; + uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1; + uint64_t precision_bits = input.f() & precision_bits_mask; + uint64_t half_way = one64 << (precision_digits_count - 1); + precision_bits *= kDenominator; + half_way *= kDenominator; + DiyFp rounded_input(input.f() >> precision_digits_count, + input.e() + precision_digits_count); + if (precision_bits >= half_way + error) { + rounded_input.set_f(rounded_input.f() + 1); + } + // If the last_bits are too close to the half-way case than we are too + // inaccurate and round down. In this case we return false so that we can + // fall back to a more precise algorithm. + + *result = Double(rounded_input).value(); + if (half_way - error < precision_bits && precision_bits < half_way + error) { + // Too imprecise. The caller will have to fall back to a slower version. + // However the returned number is guaranteed to be either the correct + // double, or the next-lower double. + return false; + } else { + return true; + } +} + + +// Returns +// - -1 if buffer*10^exponent < diy_fp. +// - 0 if buffer*10^exponent == diy_fp. +// - +1 if buffer*10^exponent > diy_fp. +// Preconditions: +// buffer.length() + exponent <= kMaxDecimalPower + 1 +// buffer.length() + exponent > kMinDecimalPower +// buffer.length() <= kMaxDecimalSignificantDigits +static int CompareBufferWithDiyFp(Vector buffer, + int exponent, + DiyFp diy_fp) { + ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); + ASSERT(buffer.length() + exponent > kMinDecimalPower); + ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); + // Make sure that the Bignum will be able to hold all our numbers. + // Our Bignum implementation has a separate field for exponents. Shifts will + // consume at most one bigit (< 64 bits). + // ln(10) == 3.3219... + ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); + Bignum buffer_bignum; + Bignum diy_fp_bignum; + buffer_bignum.AssignDecimalString(buffer); + diy_fp_bignum.AssignUInt64(diy_fp.f()); + if (exponent >= 0) { + buffer_bignum.MultiplyByPowerOfTen(exponent); + } else { + diy_fp_bignum.MultiplyByPowerOfTen(-exponent); + } + if (diy_fp.e() > 0) { + diy_fp_bignum.ShiftLeft(diy_fp.e()); + } else { + buffer_bignum.ShiftLeft(-diy_fp.e()); + } + return Bignum::Compare(buffer_bignum, diy_fp_bignum); +} + + +// Returns true if the guess is the correct double. +// Returns false, when guess is either correct or the next-lower double. +static bool ComputeGuess(Vector trimmed, int exponent, + double* guess) { + if (trimmed.length() == 0) { + *guess = 0.0; + return true; + } + if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) { + *guess = Double::Infinity(); + return true; + } + if (exponent + trimmed.length() <= kMinDecimalPower) { + *guess = 0.0; + return true; + } + + if (DoubleStrtod(trimmed, exponent, guess) || + DiyFpStrtod(trimmed, exponent, guess)) { + return true; + } + if (*guess == Double::Infinity()) { + return true; + } + return false; +} + +double Strtod(Vector buffer, int exponent) { + char copy_buffer[kMaxSignificantDecimalDigits]; + Vector trimmed; + int updated_exponent; + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, + &trimmed, &updated_exponent); + exponent = updated_exponent; + + double guess; + bool is_correct = ComputeGuess(trimmed, exponent, &guess); + if (is_correct) return guess; + + DiyFp upper_boundary = Double(guess).UpperBoundary(); + int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); + if (comparison < 0) { + return guess; + } else if (comparison > 0) { + return Double(guess).NextDouble(); + } else if ((Double(guess).Significand() & 1) == 0) { + // Round towards even. + return guess; + } else { + return Double(guess).NextDouble(); + } +} + +float Strtof(Vector buffer, int exponent) { + char copy_buffer[kMaxSignificantDecimalDigits]; + Vector trimmed; + int updated_exponent; + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, + &trimmed, &updated_exponent); + exponent = updated_exponent; + + double double_guess; + bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); + + float float_guess = static_cast(double_guess); + if (float_guess == double_guess) { + // This shortcut triggers for integer values. + return float_guess; + } + + // We must catch double-rounding. Say the double has been rounded up, and is + // now a boundary of a float, and rounds up again. This is why we have to + // look at previous too. + // Example (in decimal numbers): + // input: 12349 + // high-precision (4 digits): 1235 + // low-precision (3 digits): + // when read from input: 123 + // when rounded from high precision: 124. + // To do this we simply look at the neigbors of the correct result and see + // if they would round to the same float. If the guess is not correct we have + // to look at four values (since two different doubles could be the correct + // double). + + double double_next = Double(double_guess).NextDouble(); + double double_previous = Double(double_guess).PreviousDouble(); + + float f1 = static_cast(double_previous); + float f2 = float_guess; + float f3 = static_cast(double_next); + float f4; + if (is_correct) { + f4 = f3; + } else { + double double_next2 = Double(double_next).NextDouble(); + f4 = static_cast(double_next2); + } + (void) f2; // Mark variable as used. + ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4); + + // If the guess doesn't lie near a single-precision boundary we can simply + // return its float-value. + if (f1 == f4) { + return float_guess; + } + + ASSERT((f1 != f2 && f2 == f3 && f3 == f4) || + (f1 == f2 && f2 != f3 && f3 == f4) || + (f1 == f2 && f2 == f3 && f3 != f4)); + + // guess and next are the two possible canditates (in the same way that + // double_guess was the lower candidate for a double-precision guess). + float guess = f1; + float next = f4; + DiyFp upper_boundary; + if (guess == 0.0f) { + float min_float = 1e-45f; + upper_boundary = Double(static_cast(min_float) / 2).AsDiyFp(); + } else { + upper_boundary = Single(guess).UpperBoundary(); + } + int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); + if (comparison < 0) { + return guess; + } else if (comparison > 0) { + return next; + } else if ((Single(guess).Significand() & 1) == 0) { + // Round towards even. + return guess; + } else { + return next; + } +} + +} // namespace double_conversion + +// ICU PATCH: Close ICU namespace +U_NAMESPACE_END +#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING diff --git a/deps/icu-small/source/i18n/double-conversion-strtod.h b/deps/icu-small/source/i18n/double-conversion-strtod.h new file mode 100644 index 0000000000..e2d6d3c2fe --- /dev/null +++ b/deps/icu-small/source/i18n/double-conversion-strtod.h @@ -0,0 +1,63 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +// +// From the double-conversion library. Original license: +// +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ICU PATCH: ifdef around UCONFIG_NO_FORMATTING +#include "unicode/utypes.h" +#if !UCONFIG_NO_FORMATTING + +#ifndef DOUBLE_CONVERSION_STRTOD_H_ +#define DOUBLE_CONVERSION_STRTOD_H_ + +// ICU PATCH: Customize header file paths for ICU. + +#include "double-conversion-utils.h" + +// ICU PATCH: Wrap in ICU namespace +U_NAMESPACE_BEGIN + +namespace double_conversion { + +// The buffer must only contain digits in the range [0-9]. It must not +// contain a dot or a sign. It must not start with '0', and must not be empty. +double Strtod(Vector buffer, int exponent); + +// The buffer must only contain digits in the range [0-9]. It must not +// contain a dot or a sign. It must not start with '0', and must not be empty. +float Strtof(Vector buffer, int exponent); + +} // namespace double_conversion + +// ICU PATCH: Close ICU namespace +U_NAMESPACE_END + +#endif // DOUBLE_CONVERSION_STRTOD_H_ +#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING diff --git a/deps/icu-small/source/i18n/double-conversion-utils.h b/deps/icu-small/source/i18n/double-conversion-utils.h index 02795b4bc5..57fc49b231 100644 --- a/deps/icu-small/source/i18n/double-conversion-utils.h +++ b/deps/icu-small/source/i18n/double-conversion-utils.h @@ -75,9 +75,9 @@ inline void abort_noreturn() { abort(); } // the output of the division with the expected result. (Inlining must be // disabled.) // On Linux,x86 89255e-22 != Div_double(89255.0/1e22) -// ICU PATCH: Enable ARM builds for Windows with 'defined(_M_ARM)'. +// ICU PATCH: Enable ARM32 & ARM64 builds for Windows with 'defined(_M_ARM) || defined(_M_ARM64)'. #if defined(_M_X64) || defined(__x86_64__) || \ - defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || \ + defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \ defined(__hppa__) || defined(__ia64__) || \ defined(__mips__) || \ defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ diff --git a/deps/icu-small/source/i18n/double-conversion.cpp b/deps/icu-small/source/i18n/double-conversion.cpp index 8629284aa0..570a05bc42 100644 --- a/deps/icu-small/source/i18n/double-conversion.cpp +++ b/deps/icu-small/source/i18n/double-conversion.cpp @@ -38,13 +38,14 @@ #include // ICU PATCH: Customize header file paths for ICU. -// The files fixed-dtoa.h and strtod.h are not needed. +// The file fixed-dtoa.h is not needed. #include "double-conversion.h" #include "double-conversion-bignum-dtoa.h" #include "double-conversion-fast-dtoa.h" #include "double-conversion-ieee.h" +#include "double-conversion-strtod.h" #include "double-conversion-utils.h" // ICU PATCH: Wrap in ICU namespace @@ -431,7 +432,6 @@ void DoubleToStringConverter::DoubleToAscii(double v, } -#if 0 // not needed for ICU // Consumes the given substring from the iterator. // Returns false, if the substring does not match. template @@ -469,6 +469,7 @@ static const uc16 kWhitespaceTable16[] = { static const int kWhitespaceTable16Length = ARRAY_SIZE(kWhitespaceTable16); + static bool isWhitespace(int x) { if (x < 128) { for (int i = 0; i < kWhitespaceTable7Length; i++) { @@ -647,7 +648,6 @@ static double RadixStringToIeee(Iterator* current, return Double(DiyFp(number, exponent)).value(); } - template double StringToDoubleConverter::StringToIeee( Iterator input, @@ -996,7 +996,6 @@ float StringToDoubleConverter::StringToFloat( return static_cast(StringToIeee(buffer, length, false, processed_characters_count)); } -#endif // not needed for ICU } // namespace double_conversion diff --git a/deps/icu-small/source/i18n/double-conversion.h b/deps/icu-small/source/i18n/double-conversion.h index 0939412734..200537a360 100644 --- a/deps/icu-small/source/i18n/double-conversion.h +++ b/deps/icu-small/source/i18n/double-conversion.h @@ -391,6 +391,7 @@ class DoubleToStringConverter { const int decimal_in_shortest_high_; const int max_leading_padding_zeroes_in_precision_mode_; const int max_trailing_padding_zeroes_in_precision_mode_; +#endif // not needed for ICU DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); }; @@ -554,7 +555,6 @@ class StringToDoubleConverter { int* processed_characters_count) const; DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); -#endif // not needed for ICU }; } // namespace double_conversion diff --git a/deps/icu-small/source/i18n/fmtable.cpp b/deps/icu-small/source/i18n/fmtable.cpp index 73f9b66ab6..cb6134cb4b 100644 --- a/deps/icu-small/source/i18n/fmtable.cpp +++ b/deps/icu-small/source/i18n/fmtable.cpp @@ -19,6 +19,7 @@ #if !UCONFIG_NO_FORMATTING +#include #include #include "unicode/fmtable.h" #include "unicode/ustring.h" @@ -28,9 +29,8 @@ #include "charstr.h" #include "cmemory.h" #include "cstring.h" -#include "decNumber.h" -#include "digitlst.h" #include "fmtableimp.h" +#include "number_decimalquantity.h" // ***************************************************************************** // class Formattable @@ -40,6 +40,8 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable) +using number::impl::DecimalQuantity; + //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. @@ -103,7 +105,7 @@ void Formattable::init() { fValue.fInt64 = 0; fType = kLong; fDecimalStr = NULL; - fDecimalNum = NULL; + fDecimalQuantity = NULL; fBogus.setToBogus(); } @@ -257,8 +259,8 @@ Formattable::operator=(const Formattable& source) } UErrorCode status = U_ZERO_ERROR; - if (source.fDecimalNum != NULL) { - fDecimalNum = new DigitList(*source.fDecimalNum); // TODO: use internal digit list + if (source.fDecimalQuantity != NULL) { + fDecimalQuantity = new DecimalQuantity(*source.fDecimalQuantity); } if (source.fDecimalStr != NULL) { fDecimalStr = new CharString(*source.fDecimalStr, status); @@ -357,13 +359,8 @@ void Formattable::dispose() delete fDecimalStr; fDecimalStr = NULL; - FmtStackData *stackData = (FmtStackData*)fStackData; - if(fDecimalNum != &(stackData->stackDecimalNum)) { - delete fDecimalNum; - } else { - fDecimalNum->~DigitList(); // destruct, don't deallocate - } - fDecimalNum = NULL; + delete fDecimalQuantity; + fDecimalQuantity = NULL; } Formattable * @@ -465,13 +462,13 @@ Formattable::getInt64(UErrorCode& status) const } else if (fValue.fDouble < (double)U_INT64_MIN) { status = U_INVALID_FORMAT_ERROR; return U_INT64_MIN; - } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) { - int64_t val = fDecimalNum->getInt64(); - if (val != 0) { - return val; + } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalQuantity != NULL) { + if (fDecimalQuantity->fitsInLong(true)) { + return fDecimalQuantity->toLong(); } else { + // Unexpected status = U_INVALID_FORMAT_ERROR; - return fValue.fDouble > 0 ? U_INT64_MAX : U_INT64_MIN; + return fDecimalQuantity->isNegative() ? U_INT64_MIN : U_INT64_MAX; } } else { return (int64_t)fValue.fDouble; @@ -714,84 +711,85 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) { CharString *Formattable::internalGetCharString(UErrorCode &status) { if(fDecimalStr == NULL) { - if (fDecimalNum == NULL) { + if (fDecimalQuantity == NULL) { // No decimal number for the formattable yet. Which means the value was // set directly by the user as an int, int64 or double. If the value came // from parsing, or from the user setting a decimal number, fDecimalNum // would already be set. // - fDecimalNum = new DigitList; // TODO: use internal digit list - if (fDecimalNum == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - - switch (fType) { - case kDouble: - fDecimalNum->set(this->getDouble()); - break; - case kLong: - fDecimalNum->set(this->getLong()); - break; - case kInt64: - fDecimalNum->set(this->getInt64()); - break; - default: - // The formattable's value is not a numeric type. - status = U_INVALID_STATE_ERROR; - return NULL; - } + LocalPointer dq(new DecimalQuantity(), status); + if (U_FAILURE(status)) { return nullptr; } + populateDecimalQuantity(*dq, status); + if (U_FAILURE(status)) { return nullptr; } + fDecimalQuantity = dq.orphan(); } - fDecimalStr = new CharString; + fDecimalStr = new CharString(); if (fDecimalStr == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } - fDecimalNum->getDecimal(*fDecimalStr, status); + // Older ICUs called uprv_decNumberToString here, which is not exactly the same as + // DecimalQuantity::toScientificString(). The biggest difference is that uprv_decNumberToString does + // not print scientific notation for magnitudes greater than -5 and smaller than some amount (+5?). + if (fDecimalQuantity->isZero()) { + fDecimalStr->append("0", -1, status); + } else if (std::abs(fDecimalQuantity->getMagnitude()) < 5) { + fDecimalStr->appendInvariantChars(fDecimalQuantity->toPlainString(), status); + } else { + fDecimalStr->appendInvariantChars(fDecimalQuantity->toScientificString(), status); + } } return fDecimalStr; } +void +Formattable::populateDecimalQuantity(number::impl::DecimalQuantity& output, UErrorCode& status) const { + if (fDecimalQuantity != nullptr) { + output = *fDecimalQuantity; + return; + } -DigitList * -Formattable::getInternalDigitList() { - FmtStackData *stackData = (FmtStackData*)fStackData; - if(fDecimalNum != &(stackData->stackDecimalNum)) { - delete fDecimalNum; - fDecimalNum = new (&(stackData->stackDecimalNum), kOnStack) DigitList(); - } else { - fDecimalNum->clear(); - } - return fDecimalNum; + switch (fType) { + case kDouble: + output.setToDouble(this->getDouble()); + output.roundToInfinity(); + break; + case kLong: + output.setToInt(this->getLong()); + break; + case kInt64: + output.setToLong(this->getInt64()); + break; + default: + // The formattable's value is not a numeric type. + status = U_INVALID_STATE_ERROR; + } } // --------------------------------------- void -Formattable::adoptDigitList(DigitList *dl) { - if(fDecimalNum==dl) { - fDecimalNum = NULL; // don't delete - } - dispose(); - - fDecimalNum = dl; - - if(dl==NULL) { // allow adoptDigitList(NULL) to clear - return; - } +Formattable::adoptDecimalQuantity(DecimalQuantity *dq) { + if (fDecimalQuantity != NULL) { + delete fDecimalQuantity; + } + fDecimalQuantity = dq; + if (dq == NULL) { // allow adoptDigitList(NULL) to clear + return; + } // Set the value into the Union of simple type values. - // Cannot use the set() functions because they would delete the fDecimalNum value, - - if (fDecimalNum->fitsIntoLong(FALSE)) { - fType = kLong; - fValue.fInt64 = fDecimalNum->getLong(); - } else if (fDecimalNum->fitsIntoInt64(FALSE)) { - fType = kInt64; - fValue.fInt64 = fDecimalNum->getInt64(); + // Cannot use the set() functions because they would delete the fDecimalNum value. + if (fDecimalQuantity->fitsInLong()) { + fValue.fInt64 = fDecimalQuantity->toLong(); + if (fValue.fInt64 <= INT32_MAX && fValue.fInt64 >= INT32_MIN) { + fType = kLong; + } else { + fType = kInt64; + } } else { fType = kDouble; - fValue.fDouble = fDecimalNum->getDouble(); + fValue.fDouble = fDecimalQuantity->toDouble(); } } @@ -804,24 +802,12 @@ Formattable::setDecimalNumber(StringPiece numberString, UErrorCode &status) { } dispose(); - // Copy the input string and nul-terminate it. - // The decNumber library requires nul-terminated input. StringPiece input - // is not guaranteed nul-terminated. Too bad. - // CharString automatically adds the nul. - DigitList *dnum = new DigitList(); // TODO: use getInternalDigitList - if (dnum == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - dnum->set(CharString(numberString, status).toStringPiece(), status); - if (U_FAILURE(status)) { - delete dnum; - return; // String didn't contain a decimal number. - } - adoptDigitList(dnum); + auto* dq = new DecimalQuantity(); + dq->setToDecNumber(numberString, status); + adoptDecimalQuantity(dq); // Note that we do not hang on to the caller's input string. - // If we are asked for the string, we will regenerate one from fDecimalNum. + // If we are asked for the string, we will regenerate one from fDecimalQuantity. } #if 0 diff --git a/deps/icu-small/source/i18n/fmtableimp.h b/deps/icu-small/source/i18n/fmtableimp.h index 0e6ccd24da..78b7caff54 100644 --- a/deps/icu-small/source/i18n/fmtableimp.h +++ b/deps/icu-small/source/i18n/fmtableimp.h @@ -10,22 +10,12 @@ #ifndef FMTABLEIMP_H #define FMTABLEIMP_H -#include "digitlst.h" +#include "number_decimalquantity.h" #if !UCONFIG_NO_FORMATTING U_NAMESPACE_BEGIN -/** - * @internal - */ -struct FmtStackData { - DigitList stackDecimalNum; // 128 - //CharString stackDecimalStr; // 64 - // ----- - // 192 total -}; - /** * Maximum int64_t value that can be stored in a double without chancing losing precision. * IEEE doubles have 53 bits of mantissa, 10 bits exponent, 1 bit sign. diff --git a/deps/icu-small/source/i18n/fphdlimp.cpp b/deps/icu-small/source/i18n/fphdlimp.cpp index abcec97ee3..c4015fae1b 100644 --- a/deps/icu-small/source/i18n/fphdlimp.cpp +++ b/deps/icu-small/source/i18n/fphdlimp.cpp @@ -22,17 +22,8 @@ U_NAMESPACE_BEGIN FieldPositionHandler::~FieldPositionHandler() { } -void -FieldPositionHandler::addAttribute(int32_t, int32_t, int32_t) { -} - -void -FieldPositionHandler::shiftLast(int32_t) { -} - -UBool -FieldPositionHandler::isRecording(void) const { - return FALSE; +void FieldPositionHandler::setShift(int32_t delta) { + fShift = delta; } @@ -48,8 +39,8 @@ FieldPositionOnlyHandler::~FieldPositionOnlyHandler() { void FieldPositionOnlyHandler::addAttribute(int32_t id, int32_t start, int32_t limit) { if (pos.getField() == id) { - pos.setBeginIndex(start); - pos.setEndIndex(limit); + pos.setBeginIndex(start + fShift); + pos.setEndIndex(limit + fShift); } } @@ -91,8 +82,8 @@ FieldPositionIteratorHandler::addAttribute(int32_t id, int32_t start, int32_t li if (iter && U_SUCCESS(status) && start < limit) { int32_t size = vec->size(); vec->addElement(id, status); - vec->addElement(start, status); - vec->addElement(limit, status); + vec->addElement(start + fShift, status); + vec->addElement(limit + fShift, status); if (!U_SUCCESS(status)) { vec->setSize(size); } diff --git a/deps/icu-small/source/i18n/fphdlimp.h b/deps/icu-small/source/i18n/fphdlimp.h index f3ac12c2ba..2e9d5622b1 100644 --- a/deps/icu-small/source/i18n/fphdlimp.h +++ b/deps/icu-small/source/i18n/fphdlimp.h @@ -22,11 +22,16 @@ U_NAMESPACE_BEGIN // base class, null implementation class U_I18N_API FieldPositionHandler: public UMemory { + protected: + int32_t fShift = 0; + public: virtual ~FieldPositionHandler(); - virtual void addAttribute(int32_t id, int32_t start, int32_t limit); - virtual void shiftLast(int32_t delta); - virtual UBool isRecording(void) const; + virtual void addAttribute(int32_t id, int32_t start, int32_t limit) = 0; + virtual void shiftLast(int32_t delta) = 0; + virtual UBool isRecording(void) const = 0; + + void setShift(int32_t delta); }; @@ -39,9 +44,9 @@ class FieldPositionOnlyHandler : public FieldPositionHandler { FieldPositionOnlyHandler(FieldPosition& pos); virtual ~FieldPositionOnlyHandler(); - virtual void addAttribute(int32_t id, int32_t start, int32_t limit); - virtual void shiftLast(int32_t delta); - virtual UBool isRecording(void) const; + void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE; + void shiftLast(int32_t delta) U_OVERRIDE; + UBool isRecording(void) const U_OVERRIDE; }; @@ -63,9 +68,9 @@ class FieldPositionIteratorHandler : public FieldPositionHandler { FieldPositionIteratorHandler(FieldPositionIterator* posIter, UErrorCode& status); ~FieldPositionIteratorHandler(); - virtual void addAttribute(int32_t id, int32_t start, int32_t limit); - virtual void shiftLast(int32_t delta); - virtual UBool isRecording(void) const; + void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE; + void shiftLast(int32_t delta) U_OVERRIDE; + UBool isRecording(void) const U_OVERRIDE; }; U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/measunit.cpp b/deps/icu-small/source/i18n/measunit.cpp index e21afcba02..dc156aa720 100644 --- a/deps/icu-small/source/i18n/measunit.cpp +++ b/deps/icu-small/source/i18n/measunit.cpp @@ -41,21 +41,21 @@ static const int32_t gOffsets[] = { 16, 20, 24, - 285, - 295, - 306, - 310, - 316, - 320, - 340, - 341, + 321, + 331, + 342, + 346, 352, - 355, - 361, - 366, - 370, - 374, - 399 + 356, + 376, + 377, + 388, + 391, + 397, + 402, + 406, + 410, + 435 }; static const int32_t gIndexes[] = { @@ -136,15 +136,18 @@ static const char * const gSubTypes[] = { "AED", "AFA", "AFN", + "ALK", "ALL", "AMD", "ANG", "AOA", + "AOK", "AON", "AOR", "ARA", "ARP", "ARS", + "ARY", "ATS", "AUD", "AWG", @@ -158,6 +161,8 @@ static const char * const gSubTypes[] = { "BEC", "BEF", "BEL", + "BGJ", + "BGK", "BGL", "BGN", "BHD", @@ -165,7 +170,9 @@ static const char * const gSubTypes[] = { "BMD", "BND", "BOB", + "BOP", "BOV", + "BRB", "BRC", "BRE", "BRL", @@ -173,6 +180,7 @@ static const char * const gSubTypes[] = { "BRR", "BSD", "BTN", + "BUK", "BWP", "BYB", "BYN", @@ -191,6 +199,7 @@ static const char * const gSubTypes[] = { "COU", "CRC", "CSD", + "CSJ", "CSK", "CUC", "CUP", @@ -225,10 +234,13 @@ static const char * const gSubTypes[] = { "GHS", "GIP", "GMD", + "GNE", "GNF", + "GNS", "GQE", "GRD", "GTQ", + "GWE", "GWP", "GYD", "HKD", @@ -239,10 +251,13 @@ static const char * const gSubTypes[] = { "HUF", "IDR", "IEP", + "ILP", + "ILR", "ILS", "INR", "IQD", "IRR", + "ISJ", "ISK", "ITL", "JMD", @@ -257,11 +272,13 @@ static const char * const gSubTypes[] = { "KWD", "KYD", "KZT", + "LAJ", "LAK", "LBP", "LKR", "LRD", "LSL", + "LSM", "LTL", "LTT", "LUC", @@ -280,17 +297,23 @@ static const char * const gSubTypes[] = { "MNT", "MOP", "MRO", + "MRU", "MTL", + "MTP", "MUR", + "MVQ", "MVR", "MWK", "MXN", + "MXP", "MXV", "MYR", + "MZE", "MZM", "MZN", "NAD", "NGN", + "NIC", "NIO", "NLG", "NOK", @@ -298,6 +321,7 @@ static const char * const gSubTypes[] = { "NZD", "OMR", "PAB", + "PEH", "PEI", "PEN", "PES", @@ -309,6 +333,8 @@ static const char * const gSubTypes[] = { "PTE", "PYG", "QAR", + "RHD", + "ROK", "ROL", "RON", "RSD", @@ -320,6 +346,7 @@ static const char * const gSubTypes[] = { "SCR", "SDD", "SDG", + "SDP", "SEK", "SGD", "SHP", @@ -331,6 +358,8 @@ static const char * const gSubTypes[] = { "SRG", "SSP", "STD", + "STN", + "SUR", "SVC", "SYP", "SZL", @@ -349,15 +378,20 @@ static const char * const gSubTypes[] = { "TZS", "UAH", "UAK", + "UGS", + "UGW", "UGX", "USD", "USN", "USS", "UYI", + "UYN", + "UYP", "UYU", "UZS", "VEB", "VEF", + "VNC", "VND", "VUV", "WST", @@ -381,6 +415,7 @@ static const char * const gSubTypes[] = { "XXX", "YDD", "YER", + "YUD", "YUM", "YUN", "ZAL", @@ -389,6 +424,7 @@ static const char * const gSubTypes[] = { "ZMW", "ZRN", "ZRZ", + "ZWC", "ZWD", "ZWL", "ZWN", @@ -511,16 +547,20 @@ static const char * const gSubTypes[] = { // Must be sorted by first value and then second value. static int32_t unitPerUnitToSingleUnit[][4] = { - {327, 297, 17, 0}, - {329, 303, 17, 2}, - {331, 297, 17, 3}, - {331, 388, 4, 2}, - {331, 389, 4, 3}, - {346, 386, 3, 1}, - {349, 11, 16, 4}, - {391, 327, 4, 1} + {363, 333, 17, 0}, + {365, 339, 17, 2}, + {367, 333, 17, 3}, + {367, 424, 4, 2}, + {367, 425, 4, 3}, + {382, 422, 3, 1}, + {385, 11, 16, 4}, + {427, 363, 4, 1} }; +// Shortcuts to the base unit in order to make the default constructor fast +static const int32_t kBaseTypeIdx = 14; +static const int32_t kBaseSubTypeIdx = 0; + MeasureUnit *MeasureUnit::createGForce(UErrorCode &status) { return MeasureUnit::create(0, 0, status); } @@ -1082,7 +1122,8 @@ static int32_t binarySearch( MeasureUnit::MeasureUnit() { fCurrency[0] = 0; - initNoUnit("base"); + fTypeId = kBaseTypeIdx; + fSubTypeId = kBaseSubTypeIdx; } MeasureUnit::MeasureUnit(const MeasureUnit &other) diff --git a/deps/icu-small/source/i18n/msgfmt.cpp b/deps/icu-small/source/i18n/msgfmt.cpp index 064585665a..8b3807e671 100644 --- a/deps/icu-small/source/i18n/msgfmt.cpp +++ b/deps/icu-small/source/i18n/msgfmt.cpp @@ -31,6 +31,7 @@ #include "unicode/decimfmt.h" #include "unicode/localpointer.h" #include "unicode/msgfmt.h" +#include "unicode/numberformatter.h" #include "unicode/plurfmt.h" #include "unicode/rbnf.h" #include "unicode/selfmt.h" @@ -48,7 +49,7 @@ #include "ustrfmt.h" #include "util.h" #include "uvector.h" -#include "visibledigits.h" +#include "number_decimalquantity.h" // ***************************************************************************** // class MessageFormat @@ -1700,12 +1701,21 @@ Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeStrin formattableType = Formattable::kLong; fmt = createIntegerFormat(fLocale, ec); break; - default: // pattern - fmt = NumberFormat::createInstance(fLocale, ec); - if (fmt) { - DecimalFormat* decfmt = dynamic_cast(fmt); - if (decfmt != NULL) { - decfmt->applyPattern(style,parseError,ec); + default: // pattern or skeleton + int32_t i = 0; + for (; PatternProps::isWhiteSpace(style.charAt(i)); i++); + if (style.compare(i, 2, u"::", 0, 2) == 0) { + // Skeleton + UnicodeString skeleton = style.tempSubString(i + 2); + fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec); + } else { + // Pattern + fmt = NumberFormat::createInstance(fLocale, ec); + if (fmt) { + auto* decfmt = dynamic_cast(fmt); + if (decfmt != nullptr) { + decfmt->applyPattern(style, parseError, ec); + } } } break; @@ -1959,14 +1969,14 @@ UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double nu return UnicodeString(FALSE, OTHER_STRING, 5); } context.formatter->format(context.number, context.numberString, ec); - const DecimalFormat *decFmt = dynamic_cast(context.formatter); + auto* decFmt = dynamic_cast(context.formatter); if(decFmt != NULL) { - VisibleDigitsWithExponent digits; - decFmt->initVisibleDigitsWithExponent(context.number, digits, ec); + number::impl::DecimalQuantity dq; + decFmt->formatToDecimalQuantity(context.number, dq, ec); if (U_FAILURE(ec)) { return UnicodeString(FALSE, OTHER_STRING, 5); } - return rules->select(digits); + return rules->select(dq); } else { return rules->select(number); } diff --git a/deps/icu-small/source/i18n/nfsubs.cpp b/deps/icu-small/source/i18n/nfsubs.cpp index ea817453d8..3733f0ca74 100644 --- a/deps/icu-small/source/i18n/nfsubs.cpp +++ b/deps/icu-small/source/i18n/nfsubs.cpp @@ -19,8 +19,9 @@ #include "utypeinfo.h" // for 'typeid' to work #include "nfsubs.h" -#include "digitlst.h" #include "fmtableimp.h" +#include "putilimp.h" +#include "number_decimalquantity.h" #if U_HAVE_RBNF @@ -47,6 +48,8 @@ static const UChar gGreaterGreaterThan[] = U_NAMESPACE_BEGIN +using number::impl::DecimalQuantity; + class SameValueSubstitution : public NFSubstitution { public: SameValueSubstitution(int32_t pos, @@ -1069,13 +1072,12 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser // numberToFormat /= 10; // } - DigitList dl; - dl.set(number); - dl.roundFixedPoint(20); // round to 20 fraction digits. - dl.reduce(); // Removes any trailing zeros. + DecimalQuantity dl; + dl.setToDouble(number); + dl.roundToMagnitude(-20, UNUM_ROUND_HALFEVEN, status); // round to 20 fraction digits. UBool pad = FALSE; - for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) { + for (int32_t didx = dl.getLowerDisplayMagnitude(); didx<0; didx++) { // Loop iterates over fraction digits, starting with the LSD. // include both real digits from the number, and zeros // to the left of the MSD but to the right of the decimal point. @@ -1084,7 +1086,7 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser } else { pad = TRUE; } - int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0; + int64_t digit = dl.getDigit(didx); getRuleSet()->format(digit, toInsertInto, _pos + getPos(), recursionCount, status); } @@ -1142,7 +1144,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text, int32_t digit; // double p10 = 0.1; - DigitList dl; + DecimalQuantity dl; + int32_t totalDigits = 0; NumberFormat* fmt = NULL; while (workText.length() > 0 && workPos.getIndex() != 0) { workPos.setIndex(0); @@ -1170,7 +1173,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text, } if (workPos.getIndex() != 0) { - dl.append((char)('0' + digit)); + dl.appendDigit(static_cast(digit), 0, true); + totalDigits++; // result += digit * p10; // p10 /= 10; parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex()); @@ -1183,7 +1187,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text, } delete fmt; - result = dl.getCount() == 0 ? 0 : dl.getDouble(); + dl.adjustMagnitude(-totalDigits); + result = dl.toDouble(); result = composeRuleValue(result, baseValue); resVal.setDouble(result); return TRUE; diff --git a/deps/icu-small/source/i18n/number_affixutils.cpp b/deps/icu-small/source/i18n/number_affixutils.cpp index df4b267af5..8da29a03d5 100644 --- a/deps/icu-small/source/i18n/number_affixutils.cpp +++ b/deps/icu-small/source/i18n/number_affixutils.cpp @@ -3,21 +3,25 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "number_affixutils.h" #include "unicode/utf16.h" +#include "unicode/uniset.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; -int32_t AffixUtils::estimateLength(const CharSequence &patternString, UErrorCode &status) { +TokenConsumer::~TokenConsumer() = default; +SymbolProvider::~SymbolProvider() = default; + +int32_t AffixUtils::estimateLength(const UnicodeString &patternString, UErrorCode &status) { AffixPatternState state = STATE_BASE; int32_t offset = 0; int32_t length = 0; for (; offset < patternString.length();) { - UChar32 cp = patternString.codePointAt(offset); + UChar32 cp = patternString.char32At(offset); switch (state) { case STATE_BASE: @@ -78,12 +82,12 @@ int32_t AffixUtils::estimateLength(const CharSequence &patternString, UErrorCode return length; } -UnicodeString AffixUtils::escape(const CharSequence &input) { +UnicodeString AffixUtils::escape(const UnicodeString &input) { AffixPatternState state = STATE_BASE; int32_t offset = 0; UnicodeString output; for (; offset < input.length();) { - UChar32 cp = input.codePointAt(offset); + UChar32 cp = input.char32At(offset); switch (cp) { case u'\'': @@ -153,7 +157,7 @@ Field AffixUtils::getFieldForType(AffixPatternType type) { } int32_t -AffixUtils::unescape(const CharSequence &affixPattern, NumberStringBuilder &output, int32_t position, +AffixUtils::unescape(const UnicodeString &affixPattern, NumberStringBuilder &output, int32_t position, const SymbolProvider &provider, UErrorCode &status) { int32_t length = 0; AffixTag tag; @@ -173,7 +177,7 @@ AffixUtils::unescape(const CharSequence &affixPattern, NumberStringBuilder &outp return length; } -int32_t AffixUtils::unescapedCodePointCount(const CharSequence &affixPattern, +int32_t AffixUtils::unescapedCodePointCount(const UnicodeString &affixPattern, const SymbolProvider &provider, UErrorCode &status) { int32_t length = 0; AffixTag tag; @@ -192,7 +196,7 @@ int32_t AffixUtils::unescapedCodePointCount(const CharSequence &affixPattern, } bool -AffixUtils::containsType(const CharSequence &affixPattern, AffixPatternType type, UErrorCode &status) { +AffixUtils::containsType(const UnicodeString &affixPattern, AffixPatternType type, UErrorCode &status) { if (affixPattern.length() == 0) { return false; } @@ -207,7 +211,7 @@ AffixUtils::containsType(const CharSequence &affixPattern, AffixPatternType type return false; } -bool AffixUtils::hasCurrencySymbols(const CharSequence &affixPattern, UErrorCode &status) { +bool AffixUtils::hasCurrencySymbols(const UnicodeString &affixPattern, UErrorCode &status) { if (affixPattern.length() == 0) { return false; } @@ -222,9 +226,9 @@ bool AffixUtils::hasCurrencySymbols(const CharSequence &affixPattern, UErrorCode return false; } -UnicodeString AffixUtils::replaceType(const CharSequence &affixPattern, AffixPatternType type, +UnicodeString AffixUtils::replaceType(const UnicodeString &affixPattern, AffixPatternType type, char16_t replacementChar, UErrorCode &status) { - UnicodeString output = affixPattern.toUnicodeString(); + UnicodeString output(affixPattern); // copy if (affixPattern.length() == 0) { return output; }; @@ -239,11 +243,41 @@ UnicodeString AffixUtils::replaceType(const CharSequence &affixPattern, AffixPat return output; } -AffixTag AffixUtils::nextToken(AffixTag tag, const CharSequence &patternString, UErrorCode &status) { +bool AffixUtils::containsOnlySymbolsAndIgnorables(const UnicodeString& affixPattern, + const UnicodeSet& ignorables, UErrorCode& status) { + if (affixPattern.length() == 0) { + return true; + }; + AffixTag tag; + while (hasNext(tag, affixPattern)) { + tag = nextToken(tag, affixPattern, status); + if (U_FAILURE(status)) { return false; } + if (tag.type == TYPE_CODEPOINT && !ignorables.contains(tag.codePoint)) { + return false; + } + } + return true; +} + +void AffixUtils::iterateWithConsumer(const UnicodeString& affixPattern, TokenConsumer& consumer, + UErrorCode& status) { + if (affixPattern.length() == 0) { + return; + }; + AffixTag tag; + while (hasNext(tag, affixPattern)) { + tag = nextToken(tag, affixPattern, status); + if (U_FAILURE(status)) { return; } + consumer.consumeToken(tag.type, tag.codePoint, status); + if (U_FAILURE(status)) { return; } + } +} + +AffixTag AffixUtils::nextToken(AffixTag tag, const UnicodeString &patternString, UErrorCode &status) { int32_t offset = tag.offset; int32_t state = tag.state; for (; offset < patternString.length();) { - UChar32 cp = patternString.codePointAt(offset); + UChar32 cp = patternString.char32At(offset); int32_t count = U16_LENGTH(cp); switch (state) { @@ -382,7 +416,7 @@ AffixTag AffixUtils::nextToken(AffixTag tag, const CharSequence &patternString, } } -bool AffixUtils::hasNext(const AffixTag &tag, const CharSequence &string) { +bool AffixUtils::hasNext(const AffixTag &tag, const UnicodeString &string) { // First check for the {-1} and default initializer syntax. if (tag.offset < 0) { return false; diff --git a/deps/icu-small/source/i18n/number_affixutils.h b/deps/icu-small/source/i18n/number_affixutils.h index fd76c99b97..1d7e1a115e 100644 --- a/deps/icu-small/source/i18n/number_affixutils.h +++ b/deps/icu-small/source/i18n/number_affixutils.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_AFFIXUTILS_H__ #define __NUMBER_AFFIXUTILS_H__ @@ -12,6 +12,7 @@ #include "unicode/stringpiece.h" #include "unicode/unistr.h" #include "number_stringbuilder.h" +#include "unicode/uniset.h" U_NAMESPACE_BEGIN namespace number { namespace impl { @@ -37,19 +38,27 @@ struct AffixTag { AffixPatternState state; AffixPatternType type; - AffixTag() : offset(0), state(STATE_BASE) {} + AffixTag() + : offset(0), state(STATE_BASE) {} - AffixTag(int32_t offset) : offset(offset) {} + AffixTag(int32_t offset) + : offset(offset) {} AffixTag(int32_t offset, UChar32 codePoint, AffixPatternState state, AffixPatternType type) - : offset(offset), codePoint(codePoint), state(state), type(type) - {} + : offset(offset), codePoint(codePoint), state(state), type(type) {} +}; + +class TokenConsumer { + public: + virtual ~TokenConsumer(); + + virtual void consumeToken(AffixPatternType type, UChar32 cp, UErrorCode& status) = 0; }; // Exported as U_I18N_API because it is a base class for other exported types class U_I18N_API SymbolProvider { public: - virtual ~SymbolProvider() = default; + virtual ~SymbolProvider(); // TODO: Could this be more efficient if it returned by reference? virtual UnicodeString getSymbol(AffixPatternType type) const = 0; @@ -107,7 +116,7 @@ class U_I18N_API AffixUtils { * @param patternString The original string whose width will be estimated. * @return The length of the unescaped string. */ - static int32_t estimateLength(const CharSequence &patternString, UErrorCode &status); + static int32_t estimateLength(const UnicodeString& patternString, UErrorCode& status); /** * Takes a string and escapes (quotes) characters that have special meaning in the affix pattern @@ -118,7 +127,7 @@ class U_I18N_API AffixUtils { * @param input The string to be escaped. * @return The resulting UnicodeString. */ - static UnicodeString escape(const CharSequence &input); + static UnicodeString escape(const UnicodeString& input); static Field getFieldForType(AffixPatternType type); @@ -134,9 +143,8 @@ class U_I18N_API AffixUtils { * @param position The index into the NumberStringBuilder to insert the string. * @param provider An object to generate locale symbols. */ - static int32_t - unescape(const CharSequence &affixPattern, NumberStringBuilder &output, int32_t position, - const SymbolProvider &provider, UErrorCode &status); + static int32_t unescape(const UnicodeString& affixPattern, NumberStringBuilder& output, + int32_t position, const SymbolProvider& provider, UErrorCode& status); /** * Sames as {@link #unescape}, but only calculates the code point count. More efficient than {@link #unescape} @@ -146,8 +154,8 @@ class U_I18N_API AffixUtils { * @param provider An object to generate locale symbols. * @return The same return value as if you called {@link #unescape}. */ - static int32_t unescapedCodePointCount(const CharSequence &affixPattern, - const SymbolProvider &provider, UErrorCode &status); + static int32_t unescapedCodePointCount(const UnicodeString& affixPattern, + const SymbolProvider& provider, UErrorCode& status); /** * Checks whether the given affix pattern contains at least one token of the given type, which is @@ -157,8 +165,7 @@ class U_I18N_API AffixUtils { * @param type The token type. * @return true if the affix pattern contains the given token type; false otherwise. */ - static bool - containsType(const CharSequence &affixPattern, AffixPatternType type, UErrorCode &status); + static bool containsType(const UnicodeString& affixPattern, AffixPatternType type, UErrorCode& status); /** * Checks whether the specified affix pattern has any unquoted currency symbols ("¤"). @@ -166,7 +173,7 @@ class U_I18N_API AffixUtils { * @param affixPattern The string to check for currency symbols. * @return true if the literal has at least one unquoted currency symbol; false otherwise. */ - static bool hasCurrencySymbols(const CharSequence &affixPattern, UErrorCode &status); + static bool hasCurrencySymbols(const UnicodeString& affixPattern, UErrorCode& status); /** * Replaces all occurrences of tokens with the given type with the given replacement char. @@ -176,9 +183,21 @@ class U_I18N_API AffixUtils { * @param replacementChar The char to substitute in place of chars of the given token type. * @return A string containing the new affix pattern. */ - static UnicodeString - replaceType(const CharSequence &affixPattern, AffixPatternType type, char16_t replacementChar, - UErrorCode &status); + static UnicodeString replaceType(const UnicodeString& affixPattern, AffixPatternType type, + char16_t replacementChar, UErrorCode& status); + + /** + * Returns whether the given affix pattern contains only symbols and ignorables as defined by the + * given ignorables set. + */ + static bool containsOnlySymbolsAndIgnorables(const UnicodeString& affixPattern, + const UnicodeSet& ignorables, UErrorCode& status); + + /** + * Iterates over the affix pattern, calling the TokenConsumer for each token. + */ + static void iterateWithConsumer(const UnicodeString& affixPattern, TokenConsumer& consumer, + UErrorCode& status); /** * Returns the next token from the affix pattern. @@ -190,7 +209,7 @@ class U_I18N_API AffixUtils { * (never negative), or -1 if there were no more tokens in the affix pattern. * @see #hasNext */ - static AffixTag nextToken(AffixTag tag, const CharSequence &patternString, UErrorCode &status); + static AffixTag nextToken(AffixTag tag, const UnicodeString& patternString, UErrorCode& status); /** * Returns whether the affix pattern string has any more tokens to be retrieved from a call to @@ -200,7 +219,7 @@ class U_I18N_API AffixUtils { * @param string The affix pattern. * @return true if there are more tokens to consume; false otherwise. */ - static bool hasNext(const AffixTag &tag, const CharSequence &string); + static bool hasNext(const AffixTag& tag, const UnicodeString& string); private: /** @@ -208,8 +227,8 @@ class U_I18N_API AffixUtils { * The order of the arguments is consistent with Java, but the order of the stored * fields is not necessarily the same. */ - static inline AffixTag - makeTag(int32_t offset, AffixPatternType type, AffixPatternState state, UChar32 cp) { + static inline AffixTag makeTag(int32_t offset, AffixPatternType type, AffixPatternState state, + UChar32 cp) { return {offset, cp, state, type}; } }; diff --git a/deps/icu-small/source/i18n/number_asformat.cpp b/deps/icu-small/source/i18n/number_asformat.cpp new file mode 100644 index 0000000000..c6bb538932 --- /dev/null +++ b/deps/icu-small/source/i18n/number_asformat.cpp @@ -0,0 +1,105 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include +#include +#include "number_asformat.h" +#include "number_types.h" +#include "number_utils.h" +#include "fphdlimp.h" +#include "number_utypes.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LocalizedNumberFormatterAsFormat) + +LocalizedNumberFormatterAsFormat::LocalizedNumberFormatterAsFormat( + const LocalizedNumberFormatter& formatter, const Locale& locale) + : fFormatter(formatter), fLocale(locale) { + const char* localeName = locale.getName(); + setLocaleIDs(localeName, localeName); +} + +LocalizedNumberFormatterAsFormat::~LocalizedNumberFormatterAsFormat() = default; + +UBool LocalizedNumberFormatterAsFormat::operator==(const Format& other) const { + auto* _other = dynamic_cast(&other); + if (_other == nullptr) { + return false; + } + // TODO: Change this to use LocalizedNumberFormatter::operator== if it is ever proposed. + // This implementation is fine, but not particularly efficient. + UErrorCode localStatus = U_ZERO_ERROR; + return fFormatter.toSkeleton(localStatus) == _other->fFormatter.toSkeleton(localStatus); +} + +Format* LocalizedNumberFormatterAsFormat::clone() const { + return new LocalizedNumberFormatterAsFormat(*this); +} + +UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo, + FieldPosition& pos, UErrorCode& status) const { + if (U_FAILURE(status)) { return appendTo; } + UFormattedNumberData data; + obj.populateDecimalQuantity(data.quantity, status); + if (U_FAILURE(status)) { + return appendTo; + } + fFormatter.formatImpl(&data, status); + if (U_FAILURE(status)) { + return appendTo; + } + // always return first occurrence: + pos.setBeginIndex(0); + pos.setEndIndex(0); + bool found = data.string.nextFieldPosition(pos, status); + if (found && appendTo.length() != 0) { + pos.setBeginIndex(pos.getBeginIndex() + appendTo.length()); + pos.setEndIndex(pos.getEndIndex() + appendTo.length()); + } + appendTo.append(data.string.toTempUnicodeString()); + return appendTo; +} + +UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo, + FieldPositionIterator* posIter, + UErrorCode& status) const { + if (U_FAILURE(status)) { return appendTo; } + UFormattedNumberData data; + obj.populateDecimalQuantity(data.quantity, status); + if (U_FAILURE(status)) { + return appendTo; + } + fFormatter.formatImpl(&data, status); + if (U_FAILURE(status)) { + return appendTo; + } + appendTo.append(data.string.toTempUnicodeString()); + if (posIter != nullptr) { + FieldPositionIteratorHandler fpih(posIter, status); + data.string.getAllFieldPositions(fpih, status); + } + return appendTo; +} + +void LocalizedNumberFormatterAsFormat::parseObject(const UnicodeString&, Formattable&, + ParsePosition& parse_pos) const { + // Not supported. + parse_pos.setErrorIndex(0); +} + +const LocalizedNumberFormatter& LocalizedNumberFormatterAsFormat::getNumberFormatter() const { + return fFormatter; +} + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_asformat.h b/deps/icu-small/source/i18n/number_asformat.h new file mode 100644 index 0000000000..bf82d72ae3 --- /dev/null +++ b/deps/icu-small/source/i18n/number_asformat.h @@ -0,0 +1,107 @@ +// © 2017 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMBER_ASFORMAT_H__ +#define __NUMBER_ASFORMAT_H__ + +#include "unicode/numberformatter.h" +#include "number_types.h" +#include "number_decimalquantity.h" +#include "number_scientific.h" +#include "number_patternstring.h" +#include "number_modifiers.h" +#include "number_multiplier.h" +#include "number_roundingutils.h" +#include "decNumber.h" +#include "charstr.h" + +U_NAMESPACE_BEGIN namespace number { +namespace impl { + +/** + * A wrapper around LocalizedNumberFormatter implementing the Format interface, enabling improved + * compatibility with other APIs. + * + * @draft ICU 62 + * @see NumberFormatter + */ +class U_I18N_API LocalizedNumberFormatterAsFormat : public Format { + public: + LocalizedNumberFormatterAsFormat(const LocalizedNumberFormatter& formatter, const Locale& locale); + + /** + * Destructor. + */ + ~LocalizedNumberFormatterAsFormat() U_OVERRIDE; + + /** + * Equals operator. + */ + UBool operator==(const Format& other) const U_OVERRIDE; + + /** + * Creates a copy of this object. + */ + Format* clone() const U_OVERRIDE; + + /** + * Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a + * number type. + */ + UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const U_OVERRIDE; + + /** + * Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a + * number type. + */ + UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const U_OVERRIDE; + + /** + * Not supported: sets an error index and returns. + */ + void parseObject(const UnicodeString& source, Formattable& result, + ParsePosition& parse_pos) const U_OVERRIDE; + + /** + * Gets the LocalizedNumberFormatter that this wrapper class uses to format numbers. + * + * For maximum efficiency, this function returns by const reference. You must copy the return value + * into a local variable if you want to use it beyond the lifetime of the current object: + * + *

+     * LocalizedNumberFormatter localFormatter = fmt->getNumberFormatter();
+     * 
+ * + * You can however use the return value directly when chaining: + * + *
+     * FormattedNumber result = fmt->getNumberFormatter().formatDouble(514.23, status);
+     * 
+ * + * @return The unwrapped LocalizedNumberFormatter. + */ + const LocalizedNumberFormatter& getNumberFormatter() const; + + UClassID getDynamicClassID() const U_OVERRIDE; + static UClassID U_EXPORT2 getStaticClassID(); + + private: + LocalizedNumberFormatter fFormatter; + + // Even though the locale is inside the LocalizedNumberFormatter, we have to keep it here, too, because + // LocalizedNumberFormatter doesn't have a getLocale() method, and ICU-TC didn't want to add one. + Locale fLocale; +}; + +} // namespace impl +} // namespace number +U_NAMESPACE_END + +#endif // __NUMBER_ASFORMAT_H__ + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_capi.cpp b/deps/icu-small/source/i18n/number_capi.cpp new file mode 100644 index 0000000000..37ad8bd76f --- /dev/null +++ b/deps/icu-small/source/i18n/number_capi.cpp @@ -0,0 +1,213 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "fphdlimp.h" +#include "number_utypes.h" +#include "numparse_types.h" +#include "unicode/numberformatter.h" +#include "unicode/unumberformatter.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + + +////////////////////////////////// +/// C API CONVERSION FUNCTIONS /// +////////////////////////////////// + +UNumberFormatterData* UNumberFormatterData::validate(UNumberFormatter* input, UErrorCode& status) { + auto* constInput = static_cast(input); + auto* validated = validate(constInput, status); + return const_cast(validated); +} + +const UNumberFormatterData* +UNumberFormatterData::validate(const UNumberFormatter* input, UErrorCode& status) { + if (U_FAILURE(status)) { + return nullptr; + } + if (input == nullptr) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return nullptr; + } + auto* impl = reinterpret_cast(input); + if (impl->fMagic != UNumberFormatterData::kMagic) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + return impl; +} + +UNumberFormatter* UNumberFormatterData::exportForC() { + return reinterpret_cast(this); +} + +UFormattedNumberData* UFormattedNumberData::validate(UFormattedNumber* input, UErrorCode& status) { + auto* constInput = static_cast(input); + auto* validated = validate(constInput, status); + return const_cast(validated); +} + +const UFormattedNumberData* +UFormattedNumberData::validate(const UFormattedNumber* input, UErrorCode& status) { + if (U_FAILURE(status)) { + return nullptr; + } + if (input == nullptr) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return nullptr; + } + auto* impl = reinterpret_cast(input); + if (impl->fMagic != UFormattedNumberData::kMagic) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + return impl; +} + +UFormattedNumber* UFormattedNumberData::exportForC() { + return reinterpret_cast(this); +} + +///////////////////////////////////// +/// END CAPI CONVERSION FUNCTIONS /// +///////////////////////////////////// + + +U_CAPI UNumberFormatter* U_EXPORT2 +unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale, + UErrorCode* ec) { + auto* impl = new UNumberFormatterData(); + if (impl == nullptr) { + *ec = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + // Readonly-alias constructor (first argument is whether we are NUL-terminated) + UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen); + impl->fFormatter = NumberFormatter::forSkeleton(skeletonString, *ec).locale(locale); + return impl->exportForC(); +} + +U_CAPI UFormattedNumber* U_EXPORT2 +unumf_openResult(UErrorCode* ec) { + auto* impl = new UFormattedNumberData(); + if (impl == nullptr) { + *ec = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return impl->exportForC(); +} + +U_CAPI void U_EXPORT2 +unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult, + UErrorCode* ec) { + const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); + UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return; } + + result->string.clear(); + result->quantity.setToLong(value); + formatter->fFormatter.formatImpl(result, *ec); +} + +U_CAPI void U_EXPORT2 +unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult, + UErrorCode* ec) { + const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); + UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return; } + + result->string.clear(); + result->quantity.setToDouble(value); + formatter->fFormatter.formatImpl(result, *ec); +} + +U_CAPI void U_EXPORT2 +unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen, + UFormattedNumber* uresult, UErrorCode* ec) { + const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); + UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return; } + + result->string.clear(); + result->quantity.setToDecNumber({value, valueLen}, *ec); + if (U_FAILURE(*ec)) { return; } + formatter->fFormatter.formatImpl(result, *ec); +} + +U_CAPI int32_t U_EXPORT2 +unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity, + UErrorCode* ec) { + const UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return 0; } + + if (buffer == nullptr ? bufferCapacity != 0 : bufferCapacity < 0) { + *ec = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + return result->string.toTempUnicodeString().extract(buffer, bufferCapacity, *ec); +} + +U_CAPI UBool U_EXPORT2 +unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec) { + const UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return FALSE; } + + if (ufpos == nullptr) { + *ec = U_ILLEGAL_ARGUMENT_ERROR; + return FALSE; + } + + FieldPosition fp; + fp.setField(ufpos->field); + fp.setBeginIndex(ufpos->beginIndex); + fp.setEndIndex(ufpos->endIndex); + bool retval = result->string.nextFieldPosition(fp, *ec); + ufpos->beginIndex = fp.getBeginIndex(); + ufpos->endIndex = fp.getEndIndex(); + // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool + return retval ? TRUE : FALSE; +} + +U_CAPI void U_EXPORT2 +unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer, + UErrorCode* ec) { + const UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return; } + + if (ufpositer == nullptr) { + *ec = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + + auto* fpi = reinterpret_cast(ufpositer); + FieldPositionIteratorHandler fpih(fpi, *ec); + result->string.getAllFieldPositions(fpih, *ec); +} + +U_CAPI void U_EXPORT2 +unumf_closeResult(UFormattedNumber* uresult) { + UErrorCode localStatus = U_ZERO_ERROR; + const UFormattedNumberData* impl = UFormattedNumberData::validate(uresult, localStatus); + delete impl; +} + +U_CAPI void U_EXPORT2 +unumf_close(UNumberFormatter* f) { + UErrorCode localStatus = U_ZERO_ERROR; + const UNumberFormatterData* impl = UNumberFormatterData::validate(f, localStatus); + delete impl; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_compact.cpp b/deps/icu-small/source/i18n/number_compact.cpp index cc0d8fd2a2..40278e1a01 100644 --- a/deps/icu-small/source/i18n/number_compact.cpp +++ b/deps/icu-small/source/i18n/number_compact.cpp @@ -3,14 +3,15 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING -#include "resource.h" -#include "number_compact.h" #include "unicode/ustring.h" #include "unicode/ures.h" #include "cstring.h" #include "charstr.h" +#include "resource.h" +#include "number_compact.h" +#include "number_microprops.h" #include "uresimp.h" using namespace icu; @@ -275,15 +276,15 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr int magnitude; if (quantity.isZero()) { magnitude = 0; - micros.rounding.apply(quantity, status); + micros.rounder.apply(quantity, status); } else { // TODO: Revisit chooseMultiplierAndApply - int multiplier = micros.rounding.chooseMultiplierAndApply(quantity, data, status); + int multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status); magnitude = quantity.isZero() ? 0 : quantity.getMagnitude(); magnitude -= multiplier; } - StandardPlural::Form plural = quantity.getStandardPlural(rules); + StandardPlural::Form plural = utils::getStandardPlural(rules, quantity); const UChar *patternString = data.getPattern(magnitude, plural); if (patternString == nullptr) { // Use the default (non-compact) modifier. @@ -313,7 +314,7 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr } // We already performed rounding. Do not perform it again. - micros.rounding = Rounder::constructPassThrough(); + micros.rounder = RoundingImpl::passThrough(); } #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_compact.h b/deps/icu-small/source/i18n/number_compact.h index f7adf36416..dda5f9f9b2 100644 --- a/deps/icu-small/source/i18n/number_compact.h +++ b/deps/icu-small/source/i18n/number_compact.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_COMPACT_H__ #define __NUMBER_COMPACT_H__ diff --git a/deps/icu-small/source/i18n/number_currencysymbols.cpp b/deps/icu-small/source/i18n/number_currencysymbols.cpp new file mode 100644 index 0000000000..0b79d6596f --- /dev/null +++ b/deps/icu-small/source/i18n/number_currencysymbols.cpp @@ -0,0 +1,123 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "number_currencysymbols.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + + +CurrencySymbols::CurrencySymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status) + : fCurrency(currency), fLocaleName(locale.getName(), status) { + fCurrencySymbol.setToBogus(); + fIntlCurrencySymbol.setToBogus(); +} + +CurrencySymbols::CurrencySymbols(CurrencyUnit currency, const Locale& locale, + const DecimalFormatSymbols& symbols, UErrorCode& status) + : CurrencySymbols(currency, locale, status) { + // If either of the overrides is present, save it in the local UnicodeString. + if (symbols.isCustomCurrencySymbol()) { + fCurrencySymbol = symbols.getConstSymbol(DecimalFormatSymbols::kCurrencySymbol); + } + if (symbols.isCustomIntlCurrencySymbol()) { + fIntlCurrencySymbol = symbols.getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); + } +} + +const char16_t* CurrencySymbols::getIsoCode() const { + return fCurrency.getISOCurrency(); +} + +UnicodeString CurrencySymbols::getNarrowCurrencySymbol(UErrorCode& status) const { + // Note: currently no override is available for narrow currency symbol + return loadSymbol(UCURR_NARROW_SYMBOL_NAME, status); +} + +UnicodeString CurrencySymbols::getCurrencySymbol(UErrorCode& status) const { + if (!fCurrencySymbol.isBogus()) { + return fCurrencySymbol; + } + return loadSymbol(UCURR_SYMBOL_NAME, status); +} + +UnicodeString CurrencySymbols::loadSymbol(UCurrNameStyle selector, UErrorCode& status) const { + const char16_t* isoCode = fCurrency.getISOCurrency(); + UBool ignoredIsChoiceFormatFillIn = FALSE; + int32_t symbolLen = 0; + const char16_t* symbol = ucurr_getName( + isoCode, + fLocaleName.data(), + selector, + &ignoredIsChoiceFormatFillIn, + &symbolLen, + &status); + // If given an unknown currency, ucurr_getName returns the input string, which we can't alias safely! + // Otherwise, symbol points to a resource bundle, and we can use readonly-aliasing constructor. + if (symbol == isoCode) { + return UnicodeString(isoCode, 3); + } else { + return UnicodeString(TRUE, symbol, symbolLen); + } +} + +UnicodeString CurrencySymbols::getIntlCurrencySymbol(UErrorCode&) const { + if (!fIntlCurrencySymbol.isBogus()) { + return fIntlCurrencySymbol; + } + // Note: Not safe to use readonly-aliasing constructor here because the buffer belongs to this object, + // which could be destructed or moved during the lifetime of the return value. + return UnicodeString(fCurrency.getISOCurrency(), 3); +} + +UnicodeString CurrencySymbols::getPluralName(StandardPlural::Form plural, UErrorCode& status) const { + const char16_t* isoCode = fCurrency.getISOCurrency(); + UBool isChoiceFormat = FALSE; + int32_t symbolLen = 0; + const char16_t* symbol = ucurr_getPluralName( + isoCode, + fLocaleName.data(), + &isChoiceFormat, + StandardPlural::getKeyword(plural), + &symbolLen, + &status); + // If given an unknown currency, ucurr_getName returns the input string, which we can't alias safely! + // Otherwise, symbol points to a resource bundle, and we can use readonly-aliasing constructor. + if (symbol == isoCode) { + return UnicodeString(isoCode, 3); + } else { + return UnicodeString(TRUE, symbol, symbolLen); + } +} + + +CurrencyUnit +icu::number::impl::resolveCurrency(const DecimalFormatProperties& properties, const Locale& locale, + UErrorCode& status) { + if (!properties.currency.isNull()) { + return properties.currency.getNoError(); + } else { + UErrorCode localStatus = U_ZERO_ERROR; + char16_t buf[4] = {}; + ucurr_forLocale(locale.getName(), buf, 4, &localStatus); + if (U_SUCCESS(localStatus)) { + return CurrencyUnit(buf, status); + } else { + // Default currency (XXX) + return CurrencyUnit(); + } + } +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_currencysymbols.h b/deps/icu-small/source/i18n/number_currencysymbols.h new file mode 100644 index 0000000000..9996bf96ae --- /dev/null +++ b/deps/icu-small/source/i18n/number_currencysymbols.h @@ -0,0 +1,65 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __SOURCE_NUMBER_CURRENCYSYMBOLS_H__ +#define __SOURCE_NUMBER_CURRENCYSYMBOLS_H__ + +#include "numparse_types.h" +#include "charstr.h" +#include "number_decimfmtprops.h" + +U_NAMESPACE_BEGIN namespace number { +namespace impl { + + +// Exported as U_I18N_API for tests +class U_I18N_API CurrencySymbols : public UMemory { + public: + CurrencySymbols() = default; // default constructor: leaves class in valid but undefined state + + /** Creates an instance in which all symbols are loaded from data. */ + CurrencySymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status); + + /** Creates an instance in which some symbols might be pre-populated. */ + CurrencySymbols(CurrencyUnit currency, const Locale& locale, const DecimalFormatSymbols& symbols, + UErrorCode& status); + + const char16_t* getIsoCode() const; + + UnicodeString getNarrowCurrencySymbol(UErrorCode& status) const; + + UnicodeString getCurrencySymbol(UErrorCode& status) const; + + UnicodeString getIntlCurrencySymbol(UErrorCode& status) const; + + UnicodeString getPluralName(StandardPlural::Form plural, UErrorCode& status) const; + + protected: + // Required fields: + CurrencyUnit fCurrency; + CharString fLocaleName; + + // Optional fields: + UnicodeString fCurrencySymbol; + UnicodeString fIntlCurrencySymbol; + + UnicodeString loadSymbol(UCurrNameStyle selector, UErrorCode& status) const; +}; + + +/** + * Resolves the effective currency from the property bag. + */ +CurrencyUnit +resolveCurrency(const DecimalFormatProperties& properties, const Locale& locale, UErrorCode& status); + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__SOURCE_NUMBER_CURRENCYSYMBOLS_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_decimalquantity.cpp b/deps/icu-small/source/i18n/number_decimalquantity.cpp index b68df26ba2..9d80e3349c 100644 --- a/deps/icu-small/source/i18n/number_decimalquantity.cpp +++ b/deps/icu-small/source/i18n/number_decimalquantity.cpp @@ -3,25 +3,30 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING -#include "uassert.h" +#include #include -#include "cmemory.h" -#include "decNumber.h" #include +#include + +#include "unicode/plurrule.h" +#include "cmemory.h" +#include "number_decnum.h" +#include "putilimp.h" #include "number_decimalquantity.h" -#include "decContext.h" -#include "decNumber.h" #include "number_roundingutils.h" #include "double-conversion.h" -#include "unicode/plurrule.h" +#include "charstr.h" +#include "number_utils.h" +#include "uassert.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; using icu::double_conversion::DoubleToStringConverter; +using icu::double_conversion::StringToDoubleConverter; namespace { @@ -29,25 +34,6 @@ int8_t NEGATIVE_FLAG = 1; int8_t INFINITY_FLAG = 2; int8_t NAN_FLAG = 4; -static constexpr int32_t DEFAULT_DIGITS = 34; -typedef MaybeStackHeaderAndArray DecNumberWithStorage; - -/** Helper function to convert a decNumber-compatible string into a decNumber. */ -void stringToDecNumber(StringPiece n, DecNumberWithStorage &dn) { - decContext set; - uprv_decContextDefault(&set, DEC_INIT_BASE); - uprv_decContextSetRounding(&set, DEC_ROUND_HALF_EVEN); - set.traps = 0; // no traps, thank you - if (n.length() > DEFAULT_DIGITS) { - dn.resize(n.length(), 0); - set.digits = n.length(); - } else { - set.digits = DEFAULT_DIGITS; - } - uprv_decNumberFromString(dn.getAlias(), n.data(), &set); - U_ASSERT(DECDPUN == 1); -} - /** Helper function for safe subtraction (no overflow). */ inline int32_t safeSubtract(int32_t a, int32_t b) { // Note: In C++, signed integer subtraction is undefined behavior. @@ -83,6 +69,7 @@ static double DOUBLE_MULTIPLIERS[] = { } // namespace +icu::IFixedDecimal::~IFixedDecimal() = default; DecimalQuantity::DecimalQuantity() { setBcdToZero(); @@ -101,11 +88,30 @@ DecimalQuantity::DecimalQuantity(const DecimalQuantity &other) { *this = other; } +DecimalQuantity::DecimalQuantity(DecimalQuantity&& src) U_NOEXCEPT { + *this = std::move(src); +} + DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) { if (this == &other) { return *this; } copyBcdFrom(other); + copyFieldsFrom(other); + return *this; +} + +DecimalQuantity& DecimalQuantity::operator=(DecimalQuantity&& src) U_NOEXCEPT { + if (this == &src) { + return *this; + } + moveBcdFrom(src); + copyFieldsFrom(src); + return *this; +} + +void DecimalQuantity::copyFieldsFrom(const DecimalQuantity& other) { + bogus = other.bogus; lOptPos = other.lOptPos; lReqPos = other.lReqPos; rReqPos = other.rReqPos; @@ -116,7 +122,6 @@ DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) { origDouble = other.origDouble; origDelta = other.origDelta; isApproximate = other.isApproximate; - return *this; } void DecimalQuantity::clear() { @@ -129,10 +134,16 @@ void DecimalQuantity::clear() { } void DecimalQuantity::setIntegerLength(int32_t minInt, int32_t maxInt) { - // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class. + // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. U_ASSERT(minInt >= 0); U_ASSERT(maxInt >= minInt); + // Special behavior: do not set minInt to be less than what is already set. + // This is so significant digits rounding can set the integer length. + if (minInt < lReqPos) { + minInt = lReqPos; + } + // Save values into internal state // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE lOptPos = maxInt; @@ -140,7 +151,7 @@ void DecimalQuantity::setIntegerLength(int32_t minInt, int32_t maxInt) { } void DecimalQuantity::setFractionLength(int32_t minFrac, int32_t maxFrac) { - // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class. + // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. U_ASSERT(minFrac >= 0); U_ASSERT(maxFrac >= minFrac); @@ -160,29 +171,53 @@ uint64_t DecimalQuantity::getPositionFingerprint() const { } void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode roundingMode, - int32_t minMaxFrac, UErrorCode& status) { - // TODO: This is innefficient. Improve? - // TODO: Should we convert to decNumber instead? + int32_t maxFrac, UErrorCode& status) { + // TODO(13701): This is innefficient. Improve? + // TODO(13701): Should we convert to decNumber instead? + roundToInfinity(); double temp = toDouble(); temp /= roundingIncrement; - setToDouble(temp); - roundToMagnitude(0, roundingMode, status); - temp = toDouble(); + // Use another DecimalQuantity to perform the actual rounding... + DecimalQuantity dq; + dq.setToDouble(temp); + dq.roundToMagnitude(0, roundingMode, status); + temp = dq.toDouble(); temp *= roundingIncrement; setToDouble(temp); // Since we reset the value to a double, we need to specify the rounding boundary // in order to get the DecimalQuantity out of approximation mode. - roundToMagnitude(-minMaxFrac, roundingMode, status); + // NOTE: In Java, we have minMaxFrac, but in C++, the two are differentiated. + roundToMagnitude(-maxFrac, roundingMode, status); } -void DecimalQuantity::multiplyBy(int32_t multiplicand) { +void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) { if (isInfinite() || isZero() || isNaN()) { return; } - // TODO: Should we convert to decNumber instead? - double temp = toDouble(); - temp *= multiplicand; - setToDouble(temp); + // Convert to DecNum, multiply, and convert back. + DecNum decnum; + toDecNum(decnum, status); + if (U_FAILURE(status)) { return; } + decnum.multiplyBy(multiplicand, status); + if (U_FAILURE(status)) { return; } + setToDecNum(decnum, status); +} + +void DecimalQuantity::divideBy(const DecNum& divisor, UErrorCode& status) { + if (isInfinite() || isZero() || isNaN()) { + return; + } + // Convert to DecNum, multiply, and convert back. + DecNum decnum; + toDecNum(decnum, status); + if (U_FAILURE(status)) { return; } + decnum.divideBy(divisor, status); + if (U_FAILURE(status)) { return; } + setToDecNum(decnum, status); +} + +void DecimalQuantity::negate() { + flags ^= NEGATIVE_FLAG; } int32_t DecimalQuantity::getMagnitude() const { @@ -190,21 +225,17 @@ int32_t DecimalQuantity::getMagnitude() const { return scale + precision - 1; } -void DecimalQuantity::adjustMagnitude(int32_t delta) { +bool DecimalQuantity::adjustMagnitude(int32_t delta) { if (precision != 0) { - scale += delta; - origDelta += delta; - } -} - -StandardPlural::Form DecimalQuantity::getStandardPlural(const PluralRules *rules) const { - if (rules == nullptr) { - // Fail gracefully if the user didn't provide a PluralRules - return StandardPlural::Form::OTHER; - } else { - UnicodeString ruleString = rules->select(*this); - return StandardPlural::orOtherFromString(ruleString); + // i.e., scale += delta; origDelta += delta + bool overflow = uprv_add32_overflow(scale, delta, &scale); + overflow = uprv_add32_overflow(origDelta, delta, &origDelta) || overflow; + // Make sure that precision + scale won't overflow, either + int32_t dummy; + overflow = overflow || uprv_add32_overflow(scale, precision, &dummy); + return overflow; } + return false; } double DecimalQuantity::getPluralOperand(PluralOperand operand) const { @@ -214,7 +245,8 @@ double DecimalQuantity::getPluralOperand(PluralOperand operand) const { switch (operand) { case PLURAL_OPERAND_I: - return static_cast(toLong()); + // Invert the negative sign if necessary + return static_cast(isNegative() ? -toLong(true) : toLong(true)); case PLURAL_OPERAND_F: return static_cast(toFractionLong(true)); case PLURAL_OPERAND_T: @@ -228,6 +260,10 @@ double DecimalQuantity::getPluralOperand(PluralOperand operand) const { } } +bool DecimalQuantity::hasIntegerValue() const { + return scale >= 0; +} + int32_t DecimalQuantity::getUpperDisplayMagnitude() const { // If this assertion fails, you need to call roundToInfinity() or some other rounding method. // See the comment in the header file explaining the "isApproximate" field. @@ -287,7 +323,10 @@ bool DecimalQuantity::isZero() const { DecimalQuantity &DecimalQuantity::setToInt(int32_t n) { setBcdToZero(); flags = 0; - if (n < 0) { + if (n == INT32_MIN) { + flags |= NEGATIVE_FLAG; + // leave as INT32_MIN; handled below in _setToInt() + } else if (n < 0) { flags |= NEGATIVE_FLAG; n = -n; } @@ -309,7 +348,7 @@ void DecimalQuantity::_setToInt(int32_t n) { DecimalQuantity &DecimalQuantity::setToLong(int64_t n) { setBcdToZero(); flags = 0; - if (n < 0) { + if (n < 0 && n > INT64_MIN) { flags |= NEGATIVE_FLAG; n = -n; } @@ -322,10 +361,12 @@ DecimalQuantity &DecimalQuantity::setToLong(int64_t n) { void DecimalQuantity::_setToLong(int64_t n) { if (n == INT64_MIN) { - static const char *int64minStr = "9.223372036854775808E+18"; - DecNumberWithStorage dn; - stringToDecNumber(int64minStr, dn); - readDecNumberToBcd(dn.getAlias()); + DecNum decnum; + UErrorCode localStatus = U_ZERO_ERROR; + decnum.setTo("9.223372036854775808E+18", localStatus); + if (U_FAILURE(localStatus)) { return; } // unexpected + flags |= NEGATIVE_FLAG; + readDecNumberToBcd(decnum); } else if (n <= INT32_MAX) { readIntToBcd(static_cast(n)); } else { @@ -337,7 +378,7 @@ DecimalQuantity &DecimalQuantity::setToDouble(double n) { setBcdToZero(); flags = 0; // signbit() from handles +0.0 vs -0.0 - if (std::signbit(n) != 0) { + if (std::signbit(n)) { flags |= NEGATIVE_FLAG; n = -n; } @@ -424,51 +465,107 @@ void DecimalQuantity::convertToAccurateDouble() { explicitExactDouble = true; } -DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n) { +DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n, UErrorCode& status) { setBcdToZero(); flags = 0; - DecNumberWithStorage dn; - stringToDecNumber(n, dn); + // Compute the decNumber representation + DecNum decnum; + decnum.setTo(n, status); - // The code path for decNumber is modeled after BigDecimal in Java. - if (decNumberIsNegative(dn.getAlias())) { - flags |= NEGATIVE_FLAG; - } - if (!decNumberIsZero(dn.getAlias())) { - _setToDecNumber(dn.getAlias()); - } + _setToDecNum(decnum, status); return *this; } -void DecimalQuantity::_setToDecNumber(decNumber *n) { - // Java fastpaths for ints here. In C++, just always read directly from the decNumber. - readDecNumberToBcd(n); - compact(); +DecimalQuantity& DecimalQuantity::setToDecNum(const DecNum& decnum, UErrorCode& status) { + setBcdToZero(); + flags = 0; + + _setToDecNum(decnum, status); + return *this; } -int64_t DecimalQuantity::toLong() const { - int64_t result = 0L; - for (int32_t magnitude = scale + precision - 1; magnitude >= 0; magnitude--) { +void DecimalQuantity::_setToDecNum(const DecNum& decnum, UErrorCode& status) { + if (U_FAILURE(status)) { return; } + if (decnum.isNegative()) { + flags |= NEGATIVE_FLAG; + } + if (!decnum.isZero()) { + readDecNumberToBcd(decnum); + compact(); + } +} + +int64_t DecimalQuantity::toLong(bool truncateIfOverflow) const { + // NOTE: Call sites should be guarded by fitsInLong(), like this: + // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ } + // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits. + uint64_t result = 0L; + int32_t upperMagnitude = std::min(scale + precision, lOptPos) - 1; + if (truncateIfOverflow) { + upperMagnitude = std::min(upperMagnitude, 17); + } + for (int32_t magnitude = upperMagnitude; magnitude >= 0; magnitude--) { result = result * 10 + getDigitPos(magnitude - scale); } - return result; + if (isNegative()) { + return static_cast(0LL - result); // i.e., -result + } + return static_cast(result); } -int64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const { - int64_t result = 0L; +uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const { + uint64_t result = 0L; int32_t magnitude = -1; - for (; (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos)) && - magnitude >= rOptPos; magnitude--) { + int32_t lowerMagnitude = std::max(scale, rOptPos); + if (includeTrailingZeros) { + lowerMagnitude = std::min(lowerMagnitude, rReqPos); + } + for (; magnitude >= lowerMagnitude && result <= 1e18L; magnitude--) { result = result * 10 + getDigitPos(magnitude - scale); } + // Remove trailing zeros; this can happen during integer overflow cases. + if (!includeTrailingZeros) { + while (result > 0 && (result % 10) == 0) { + result /= 10; + } + } return result; } -double DecimalQuantity::toDouble() const { - if (isApproximate) { - return toDoubleFromOriginal(); +bool DecimalQuantity::fitsInLong(bool ignoreFraction) const { + if (isZero()) { + return true; + } + if (scale < 0 && !ignoreFraction) { + return false; } + int magnitude = getMagnitude(); + if (magnitude < 18) { + return true; + } + if (magnitude > 18) { + return false; + } + // Hard case: the magnitude is 10^18. + // The largest int64 is: 9,223,372,036,854,775,807 + for (int p = 0; p < precision; p++) { + int8_t digit = getDigit(18 - p); + static int8_t INT64_BCD[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 }; + if (digit < INT64_BCD[p]) { + return true; + } else if (digit > INT64_BCD[p]) { + return false; + } + } + // Exactly equal to max long plus one. + return isNegative(); +} + +double DecimalQuantity::toDouble() const { + // If this assertion fails, you need to call roundToInfinity() or some other rounding method. + // See the comment in the header file explaining the "isApproximate" field. + U_ASSERT(!isApproximate); if (isNaN()) { return NAN; @@ -476,42 +573,37 @@ double DecimalQuantity::toDouble() const { return isNegative() ? -INFINITY : INFINITY; } - int64_t tempLong = 0L; - int32_t lostDigits = precision - (precision < 17 ? precision : 17); - for (int shift = precision - 1; shift >= lostDigits; shift--) { - tempLong = tempLong * 10 + getDigitPos(shift); + // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter. + StringToDoubleConverter converter(0, 0, 0, "", ""); + UnicodeString numberString = this->toScientificString(); + int32_t count; + return converter.StringToDouble( + reinterpret_cast(numberString.getBuffer()), + numberString.length(), + &count); +} + +void DecimalQuantity::toDecNum(DecNum& output, UErrorCode& status) const { + // Special handling for zero + if (precision == 0) { + output.setTo("0", status); } - double result = static_cast(tempLong); - int32_t _scale = scale + lostDigits; - if (_scale >= 0) { - // 1e22 is the largest exact double. - int32_t i = _scale; - for (; i >= 22; i -= 22) result *= 1e22; - result *= DOUBLE_MULTIPLIERS[i]; - } else { - // 1e22 is the largest exact double. - int32_t i = _scale; - for (; i <= -22; i += 22) result /= 1e22; - result /= DOUBLE_MULTIPLIERS[-i]; + + // Use the BCD constructor. We need to do a little bit of work to convert, though. + // The decNumber constructor expects most-significant first, but we store least-significant first. + MaybeStackArray ubcd(precision); + for (int32_t m = 0; m < precision; m++) { + ubcd[precision - m - 1] = static_cast(getDigitPos(m)); } - if (isNegative()) { result = -result; } - return result; + output.setTo(ubcd.getAlias(), precision, scale, isNegative(), status); } -double DecimalQuantity::toDoubleFromOriginal() const { - double result = origDouble; - int32_t delta = origDelta; - if (delta >= 0) { - // 1e22 is the largest exact double. - for (; delta >= 22; delta -= 22) result *= 1e22; - result *= DOUBLE_MULTIPLIERS[delta]; - } else { - // 1e22 is the largest exact double. - for (; delta <= -22; delta += 22) result /= 1e22; - result /= DOUBLE_MULTIPLIERS[-delta]; +void DecimalQuantity::truncate() { + if (scale < 0) { + shiftRight(-scale); + scale = 0; + compact(); } - if (isNegative()) { result *= -1; } - return result; } void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) { @@ -689,17 +781,63 @@ void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appen } UnicodeString DecimalQuantity::toPlainString() const { + U_ASSERT(!isApproximate); UnicodeString sb; if (isNegative()) { sb.append(u'-'); } + if (precision == 0 || getMagnitude() < 0) { + sb.append(u'0'); + } for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) { + if (m == -1) { sb.append(u'.'); } sb.append(getDigit(m) + u'0'); - if (m == 0) { sb.append(u'.'); } } return sb; } +UnicodeString DecimalQuantity::toScientificString() const { + U_ASSERT(!isApproximate); + UnicodeString result; + if (isNegative()) { + result.append(u'-'); + } + if (precision == 0) { + result.append(u"0E+0", -1); + return result; + } + // NOTE: It is not safe to add to lOptPos (aka maxInt) or subtract from + // rOptPos (aka -maxFrac) due to overflow. + int32_t upperPos = std::min(precision + scale, lOptPos) - scale - 1; + int32_t lowerPos = std::max(scale, rOptPos) - scale; + int32_t p = upperPos; + result.append(u'0' + getDigitPos(p)); + if ((--p) >= lowerPos) { + result.append(u'.'); + for (; p >= lowerPos; p--) { + result.append(u'0' + getDigitPos(p)); + } + } + result.append(u'E'); + int32_t _scale = upperPos + scale; + if (_scale < 0) { + _scale *= -1; + result.append(u'-'); + } else { + result.append(u'+'); + } + if (_scale == 0) { + result.append(u'0'); + } + int32_t insertIndex = result.length(); + while (_scale > 0) { + std::div_t res = std::div(_scale, 10); + result.insert(insertIndex, u'0' + res.rem); + _scale = res.quot; + } + return result; +} + //////////////////////////////////////////////////// /// End of DecimalQuantity_AbstractBCD.java /// /// Start of DecimalQuantity_DualStorageBCD.java /// @@ -707,7 +845,7 @@ UnicodeString DecimalQuantity::toPlainString() const { int8_t DecimalQuantity::getDigitPos(int32_t position) const { if (usingBytes) { - if (position < 0 || position > precision) { return 0; } + if (position < 0 || position >= precision) { return 0; } return fBCD.bcdBytes.ptr[position]; } else { if (position < 0 || position >= 16) { return 0; } @@ -819,7 +957,8 @@ void DecimalQuantity::readLongToBcd(int64_t n) { } } -void DecimalQuantity::readDecNumberToBcd(decNumber *dn) { +void DecimalQuantity::readDecNumberToBcd(const DecNum& decnum) { + const decNumber* dn = decnum.getRawDecNumber(); if (dn->digits > 16) { ensureCapacity(dn->digits); for (int32_t i = 0; i < dn->digits; i++) { @@ -919,7 +1058,7 @@ void DecimalQuantity::ensureCapacity(int32_t capacity) { auto bcd1 = static_cast(uprv_malloc(capacity * 2 * sizeof(int8_t))); uprv_memcpy(bcd1, fBCD.bcdBytes.ptr, oldCapacity * sizeof(int8_t)); // Initialize the rest of the byte array to zeros (this is done automatically in Java) - uprv_memset(fBCD.bcdBytes.ptr + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t)); + uprv_memset(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t)); uprv_free(fBCD.bcdBytes.ptr); fBCD.bcdBytes.ptr = bcd1; fBCD.bcdBytes.len = capacity * 2; @@ -962,6 +1101,20 @@ void DecimalQuantity::copyBcdFrom(const DecimalQuantity &other) { } } +void DecimalQuantity::moveBcdFrom(DecimalQuantity &other) { + setBcdToZero(); + if (other.usingBytes) { + usingBytes = true; + fBCD.bcdBytes.ptr = other.fBCD.bcdBytes.ptr; + fBCD.bcdBytes.len = other.fBCD.bcdBytes.len; + // Take ownership away from the old instance: + other.fBCD.bcdBytes.ptr = nullptr; + other.usingBytes = false; + } else { + fBCD.bcdLong = other.fBCD.bcdLong; + } +} + const char16_t* DecimalQuantity::checkHealth() const { if (usingBytes) { if (precision == 0) { return u"Zero precision but we are in byte mode"; } @@ -1000,6 +1153,11 @@ const char16_t* DecimalQuantity::checkHealth() const { return nullptr; } +bool DecimalQuantity::operator==(const DecimalQuantity& other) const { + // FIXME: Make a faster implementation. + return toString() == other.toString(); +} + UnicodeString DecimalQuantity::toString() const { MaybeStackArray digits(precision + 1); for (int32_t i = 0; i < precision; i++) { @@ -1010,25 +1168,17 @@ UnicodeString DecimalQuantity::toString() const { snprintf( buffer8, sizeof(buffer8), - "", + "", (lOptPos > 999 ? 999 : lOptPos), lReqPos, rReqPos, (rOptPos < -999 ? -999 : rOptPos), (usingBytes ? "bytes" : "long"), + (isNegative() ? "-" : ""), (precision == 0 ? "0" : digits.getAlias()), "E", scale); return UnicodeString(buffer8, -1, US_INV); } -UnicodeString DecimalQuantity::toNumberString() const { - MaybeStackArray digits(precision + 11); - for (int32_t i = 0; i < precision; i++) { - digits[i] = getDigitPos(precision - i - 1) + '0'; - } - snprintf(digits.getAlias() + precision, 11, "E%d", scale); - return UnicodeString(digits.getAlias(), -1, US_INV); -} - #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_decimalquantity.h b/deps/icu-small/source/i18n/number_decimalquantity.h index 4309c3c638..8e04dea7eb 100644 --- a/deps/icu-small/source/i18n/number_decimalquantity.h +++ b/deps/icu-small/source/i18n/number_decimalquantity.h @@ -3,13 +3,12 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_DECIMALQUANTITY_H__ #define __NUMBER_DECIMALQUANTITY_H__ #include #include "unicode/umachine.h" -#include "decNumber.h" #include "standardplural.h" #include "plurrule_impl.h" #include "number_types.h" @@ -17,6 +16,9 @@ U_NAMESPACE_BEGIN namespace number { namespace impl { +// Forward-declare (maybe don't want number_utils.h included here): +class DecNum; + /** * An class for representing a number to be processed by the decimal formatting pipeline. Includes * methods for rounding, plural rules, and decimal digit extraction. @@ -33,9 +35,12 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { /** Copy constructor. */ DecimalQuantity(const DecimalQuantity &other); + /** Move constructor. */ + DecimalQuantity(DecimalQuantity &&src) U_NOEXCEPT; + DecimalQuantity(); - ~DecimalQuantity(); + ~DecimalQuantity() override; /** * Sets this instance to be equal to another instance. @@ -44,6 +49,9 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { */ DecimalQuantity &operator=(const DecimalQuantity &other); + /** Move assignment */ + DecimalQuantity &operator=(DecimalQuantity&& src) U_NOEXCEPT; + /** * Sets the minimum and maximum integer digits that this {@link DecimalQuantity} should generate. * This method does not perform rounding. @@ -71,7 +79,10 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { * @param mathContext The {@link RoundingMode} to use if rounding is necessary. */ void roundToIncrement(double roundingIncrement, RoundingMode roundingMode, - int32_t minMaxFrac, UErrorCode& status); + int32_t maxFrac, UErrorCode& status); + + /** Removes all fraction digits. */ + void truncate(); /** * Rounds the number to a specified magnitude (power of ten). @@ -89,19 +100,30 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { void roundToInfinity(); /** - * Multiply the internal value. + * Multiply the internal value. Uses decNumber. + * + * @param multiplicand The value by which to multiply. + */ + void multiplyBy(const DecNum& multiplicand, UErrorCode& status); + + /** + * Divide the internal value. Uses decNumber. * * @param multiplicand The value by which to multiply. */ - void multiplyBy(int32_t multiplicand); + void divideBy(const DecNum& divisor, UErrorCode& status); + + /** Flips the sign from positive to negative and back. */ + void negate(); /** * Scales the number by a power of ten. For example, if the value is currently "1234.56", calling * this method with delta=-3 will change the value to "1.23456". * * @param delta The number of magnitudes of ten to change by. + * @return true if integer overflow occured; false otherwise. */ - void adjustMagnitude(int32_t delta); + bool adjustMagnitude(int32_t delta); /** * @return The power of ten corresponding to the most significant nonzero digit. @@ -124,13 +146,23 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { /** @return Whether the value represented by this {@link DecimalQuantity} is not a number. */ bool isNaN() const U_OVERRIDE; - int64_t toLong() const; + /** @param truncateIfOverflow if false and the number does NOT fit, fails with an assertion error. */ + int64_t toLong(bool truncateIfOverflow = false) const; - int64_t toFractionLong(bool includeTrailingZeros) const; + uint64_t toFractionLong(bool includeTrailingZeros) const; + + /** + * Returns whether or not a Long can fully represent the value stored in this DecimalQuantity. + * @param ignoreFraction if true, silently ignore digits after the decimal place. + */ + bool fitsInLong(bool ignoreFraction = false) const; /** @return The value contained in this {@link DecimalQuantity} approximated as a double. */ double toDouble() const; + /** Computes a DecNum representation of this DecimalQuantity, saving it to the output parameter. */ + void toDecNum(DecNum& output, UErrorCode& status) const; + DecimalQuantity &setToInt(int32_t n); DecimalQuantity &setToLong(int64_t n); @@ -138,8 +170,10 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { DecimalQuantity &setToDouble(double n); /** decNumber is similar to BigDecimal in Java. */ + DecimalQuantity &setToDecNumber(StringPiece n, UErrorCode& status); - DecimalQuantity &setToDecNumber(StringPiece n); + /** Internal method if the caller already has a DecNum. */ + DecimalQuantity &setToDecNum(const DecNum& n, UErrorCode& status); /** * Appends a digit, optionally with one or more leading zeros, to the end of the value represented @@ -160,17 +194,10 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { */ void appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger); - /** - * Computes the plural form for this number based on the specified set of rules. - * - * @param rules A {@link PluralRules} object representing the set of rules. - * @return The {@link StandardPlural} according to the PluralRules. If the plural form is not in - * the set of standard plurals, {@link StandardPlural#OTHER} is returned instead. - */ - StandardPlural::Form getStandardPlural(const PluralRules *rules) const; - double getPluralOperand(PluralOperand operand) const U_OVERRIDE; + bool hasIntegerValue() const U_OVERRIDE; + /** * Gets the digit at the specified magnitude. For example, if the represented number is 12.3, * getDigit(-1) returns 3, since 3 is the digit corresponding to 10^-1. @@ -223,10 +250,10 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { UnicodeString toString() const; - /* Returns the string in exponential notation. */ - UnicodeString toNumberString() const; + /** Returns the string in standard exponential notation. */ + UnicodeString toScientificString() const; - /* Returns the string without exponential notation. Slightly slower than toNumberString(). */ + /** Returns the string without exponential notation. Slightly slower than toScientificString(). */ UnicodeString toPlainString() const; /** Visible for testing */ @@ -235,6 +262,17 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { /** Visible for testing */ inline bool isExplicitExactDouble() { return explicitExactDouble; }; + bool operator==(const DecimalQuantity& other) const; + + inline bool operator!=(const DecimalQuantity& other) const { + return !(*this == other); + } + + /** + * Bogus flag for when a DecimalQuantity is stored on the stack. + */ + bool bogus = false; + private: /** * The power of ten corresponding to the least significant digit in the BCD. For example, if this @@ -396,12 +434,16 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { */ void readLongToBcd(int64_t n); - void readDecNumberToBcd(decNumber *dn); + void readDecNumberToBcd(const DecNum& dn); void readDoubleConversionToBcd(const char* buffer, int32_t length, int32_t point); + void copyFieldsFrom(const DecimalQuantity& other); + void copyBcdFrom(const DecimalQuantity &other); + void moveBcdFrom(DecimalQuantity& src); + /** * Removes trailing zeros from the BCD (adjusting the scale as required) and then computes the * precision. The precision is the number of digits in the number up through the greatest nonzero @@ -418,12 +460,10 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { void _setToDoubleFast(double n); - void _setToDecNumber(decNumber *n); + void _setToDecNum(const DecNum& dn, UErrorCode& status); void convertToAccurateDouble(); - double toDoubleFromOriginal() const; - /** Ensure that a byte array of at least 40 digits is allocated. */ void ensureCapacity(); diff --git a/deps/icu-small/source/i18n/number_decimfmtprops.cpp b/deps/icu-small/source/i18n/number_decimfmtprops.cpp index cc57cfce6a..6754fe19ec 100644 --- a/deps/icu-small/source/i18n/number_decimfmtprops.cpp +++ b/deps/icu-small/source/i18n/number_decimfmtprops.cpp @@ -3,14 +3,29 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "number_decimfmtprops.h" +#include "umutex.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; + +namespace { + +char kRawDefaultProperties[sizeof(DecimalFormatProperties)]; + +icu::UInitOnce gDefaultPropertiesInitOnce = U_INITONCE_INITIALIZER; + +void U_CALLCONV initDefaultProperties(UErrorCode&) { + new(kRawDefaultProperties) DecimalFormatProperties(); // set to the default instance +} + +} + + DecimalFormatProperties::DecimalFormatProperties() { clear(); } @@ -23,8 +38,10 @@ void DecimalFormatProperties::clear() { decimalPatternMatchRequired = false; decimalSeparatorAlwaysShown = false; exponentSignAlwaysShown = false; + formatFailIfMoreThanMaxDigits = false; formatWidth = -1; groupingSize = -1; + groupingUsed = true; magnitudeMultiplier = 0; maximumFractionDigits = -1; maximumIntegerDigits = -1; @@ -34,7 +51,8 @@ void DecimalFormatProperties::clear() { minimumGroupingDigits = -1; minimumIntegerDigits = -1; minimumSignificantDigits = -1; - multiplier = 0; + multiplier = 1; + multiplierScale = 0; negativePrefix.setToBogus(); negativePrefixPattern.setToBogus(); negativeSuffix.setToBogus(); @@ -43,9 +61,10 @@ void DecimalFormatProperties::clear() { padString.setToBogus(); parseCaseSensitive = false; parseIntegerOnly = false; - parseLenient = false; + parseMode.nullify(); parseNoExponent = false; parseToBigDecimal = false; + parseAllInput = UNUM_MAYBE; positivePrefix.setToBogus(); positivePrefixPattern.setToBogus(); positiveSuffix.setToBogus(); @@ -56,47 +75,70 @@ void DecimalFormatProperties::clear() { signAlwaysShown = false; } -bool DecimalFormatProperties::operator==(const DecimalFormatProperties &other) const { +bool +DecimalFormatProperties::_equals(const DecimalFormatProperties& other, bool ignoreForFastFormat) const { bool eq = true; + + // Properties that must be equal both normally and for fast-path formatting eq = eq && compactStyle == other.compactStyle; eq = eq && currency == other.currency; eq = eq && currencyPluralInfo.fPtr.getAlias() == other.currencyPluralInfo.fPtr.getAlias(); eq = eq && currencyUsage == other.currencyUsage; - eq = eq && decimalPatternMatchRequired == other.decimalPatternMatchRequired; eq = eq && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown; eq = eq && exponentSignAlwaysShown == other.exponentSignAlwaysShown; + eq = eq && formatFailIfMoreThanMaxDigits == other.formatFailIfMoreThanMaxDigits; eq = eq && formatWidth == other.formatWidth; - eq = eq && groupingSize == other.groupingSize; eq = eq && magnitudeMultiplier == other.magnitudeMultiplier; - eq = eq && maximumFractionDigits == other.maximumFractionDigits; - eq = eq && maximumIntegerDigits == other.maximumIntegerDigits; eq = eq && maximumSignificantDigits == other.maximumSignificantDigits; eq = eq && minimumExponentDigits == other.minimumExponentDigits; - eq = eq && minimumFractionDigits == other.minimumFractionDigits; eq = eq && minimumGroupingDigits == other.minimumGroupingDigits; - eq = eq && minimumIntegerDigits == other.minimumIntegerDigits; eq = eq && minimumSignificantDigits == other.minimumSignificantDigits; eq = eq && multiplier == other.multiplier; + eq = eq && multiplierScale == other.multiplierScale; eq = eq && negativePrefix == other.negativePrefix; - eq = eq && negativePrefixPattern == other.negativePrefixPattern; eq = eq && negativeSuffix == other.negativeSuffix; - eq = eq && negativeSuffixPattern == other.negativeSuffixPattern; eq = eq && padPosition == other.padPosition; eq = eq && padString == other.padString; - eq = eq && parseCaseSensitive == other.parseCaseSensitive; - eq = eq && parseIntegerOnly == other.parseIntegerOnly; - eq = eq && parseLenient == other.parseLenient; - eq = eq && parseNoExponent == other.parseNoExponent; - eq = eq && parseToBigDecimal == other.parseToBigDecimal; eq = eq && positivePrefix == other.positivePrefix; - eq = eq && positivePrefixPattern == other.positivePrefixPattern; eq = eq && positiveSuffix == other.positiveSuffix; - eq = eq && positiveSuffixPattern == other.positiveSuffixPattern; eq = eq && roundingIncrement == other.roundingIncrement; eq = eq && roundingMode == other.roundingMode; eq = eq && secondaryGroupingSize == other.secondaryGroupingSize; eq = eq && signAlwaysShown == other.signAlwaysShown; + + if (ignoreForFastFormat) { + return eq; + } + + // Properties ignored by fast-path formatting + // Formatting (special handling required): + eq = eq && groupingSize == other.groupingSize; + eq = eq && groupingUsed == other.groupingUsed; + eq = eq && minimumFractionDigits == other.minimumFractionDigits; + eq = eq && maximumFractionDigits == other.maximumFractionDigits; + eq = eq && maximumIntegerDigits == other.maximumIntegerDigits; + eq = eq && minimumIntegerDigits == other.minimumIntegerDigits; + eq = eq && negativePrefixPattern == other.negativePrefixPattern; + eq = eq && negativeSuffixPattern == other.negativeSuffixPattern; + eq = eq && positivePrefixPattern == other.positivePrefixPattern; + eq = eq && positiveSuffixPattern == other.positiveSuffixPattern; + + // Parsing (always safe to ignore): + eq = eq && decimalPatternMatchRequired == other.decimalPatternMatchRequired; + eq = eq && parseCaseSensitive == other.parseCaseSensitive; + eq = eq && parseIntegerOnly == other.parseIntegerOnly; + eq = eq && parseMode == other.parseMode; + eq = eq && parseNoExponent == other.parseNoExponent; + eq = eq && parseToBigDecimal == other.parseToBigDecimal; + eq = eq && parseAllInput == other.parseAllInput; + return eq; } +bool DecimalFormatProperties::equalsDefaultExceptFastFormat() const { + UErrorCode localStatus = U_ZERO_ERROR; + umtx_initOnce(gDefaultPropertiesInitOnce, &initDefaultProperties, localStatus); + return _equals(*reinterpret_cast(kRawDefaultProperties), true); +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_decimfmtprops.h b/deps/icu-small/source/i18n/number_decimfmtprops.h index 96356cad45..f288b6e0d9 100644 --- a/deps/icu-small/source/i18n/number_decimfmtprops.h +++ b/deps/icu-small/source/i18n/number_decimfmtprops.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_DECIMFMTPROPS_H__ #define __NUMBER_DECIMFMTPROPS_H__ @@ -30,21 +30,65 @@ template class U_I18N_API LocalPointer; namespace number { namespace impl { -// TODO: Figure out a nicer way to deal with CurrencyPluralInfo. // Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties -struct U_I18N_API CurrencyPluralInfoWrapper { +// Using this wrapper is rather unfortunate, but is needed on Windows platforms in order to allow +// for DLL-exporting an fully specified template instantiation. +class U_I18N_API CurrencyPluralInfoWrapper { +public: LocalPointer fPtr; - CurrencyPluralInfoWrapper() {} + CurrencyPluralInfoWrapper() = default; + CurrencyPluralInfoWrapper(const CurrencyPluralInfoWrapper& other) { if (!other.fPtr.isNull()) { fPtr.adoptInstead(new CurrencyPluralInfo(*other.fPtr)); } } + + CurrencyPluralInfoWrapper& operator=(const CurrencyPluralInfoWrapper& other) { + if (!other.fPtr.isNull()) { + fPtr.adoptInstead(new CurrencyPluralInfo(*other.fPtr)); + } + return *this; + } +}; + +/** Controls the set of rules for parsing a string from the old DecimalFormat API. */ +enum ParseMode { + /** + * Lenient mode should be used if you want to accept malformed user input. It will use heuristics + * to attempt to parse through typographical errors in the string. + */ + PARSE_MODE_LENIENT, + + /** + * Strict mode should be used if you want to require that the input is well-formed. More + * specifically, it differs from lenient mode in the following ways: + * + *
    + *
  • Grouping widths must match the grouping settings. For example, "12,3,45" will fail if the + * grouping width is 3, as in the pattern "#,##0". + *
  • The string must contain a complete prefix and suffix. For example, if the pattern is + * "{#};(#)", then "{123}" or "(123)" would match, but "{123", "123}", and "123" would all fail. + * (The latter strings would be accepted in lenient mode.) + *
  • Whitespace may not appear at arbitrary places in the string. In lenient mode, whitespace + * is allowed to occur arbitrarily before and after prefixes and exponent separators. + *
  • Leading grouping separators are not allowed, as in ",123". + *
  • Minus and plus signs can only appear if specified in the pattern. In lenient mode, a plus + * or minus sign can always precede a number. + *
  • The set of characters that can be interpreted as a decimal or grouping separator is + * smaller. + *
  • If currency parsing is enabled, currencies must only appear where + * specified in either the current pattern string or in a valid pattern string for the current + * locale. For example, if the pattern is "¤0.00", then "$1.23" would match, but "1.23$" would + * fail to match. + *
+ */ + PARSE_MODE_STRICT, }; // Exported as U_I18N_API because it is needed for the unit test PatternStringTest -struct U_I18N_API DecimalFormatProperties { +struct U_I18N_API DecimalFormatProperties : public UMemory { public: NullableValue compactStyle; @@ -54,9 +98,11 @@ struct U_I18N_API DecimalFormatProperties { bool decimalPatternMatchRequired; bool decimalSeparatorAlwaysShown; bool exponentSignAlwaysShown; + bool formatFailIfMoreThanMaxDigits; // ICU4C-only int32_t formatWidth; int32_t groupingSize; - int32_t magnitudeMultiplier; + bool groupingUsed; + int32_t magnitudeMultiplier; // internal field like multiplierScale but separate to avoid conflict int32_t maximumFractionDigits; int32_t maximumIntegerDigits; int32_t maximumSignificantDigits; @@ -66,6 +112,7 @@ struct U_I18N_API DecimalFormatProperties { int32_t minimumIntegerDigits; int32_t minimumSignificantDigits; int32_t multiplier; + int32_t multiplierScale; // ICU4C-only UnicodeString negativePrefix; UnicodeString negativePrefixPattern; UnicodeString negativeSuffix; @@ -74,9 +121,10 @@ struct U_I18N_API DecimalFormatProperties { UnicodeString padString; bool parseCaseSensitive; bool parseIntegerOnly; - bool parseLenient; + NullableValue parseMode; bool parseNoExponent; - bool parseToBigDecimal; + bool parseToBigDecimal; // TODO: Not needed in ICU4C? + UNumberFormatAttributeValue parseAllInput; // ICU4C-only //PluralRules pluralRules; UnicodeString positivePrefix; UnicodeString positivePrefixPattern; @@ -89,13 +137,20 @@ struct U_I18N_API DecimalFormatProperties { DecimalFormatProperties(); - //DecimalFormatProperties(const DecimalFormatProperties &other) = default; + inline bool operator==(const DecimalFormatProperties& other) const { + return _equals(other, false); + } - DecimalFormatProperties &operator=(const DecimalFormatProperties &other) = default; + void clear(); - bool operator==(const DecimalFormatProperties &other) const; + /** + * Checks for equality to the default DecimalFormatProperties, but ignores the prescribed set of + * options for fast-path formatting. + */ + bool equalsDefaultExceptFastFormat() const; - void clear(); + private: + bool _equals(const DecimalFormatProperties& other, bool ignoreForFastFormat) const; }; } // namespace impl diff --git a/deps/icu-small/source/i18n/number_decnum.h b/deps/icu-small/source/i18n/number_decnum.h new file mode 100644 index 0000000000..a7793470b5 --- /dev/null +++ b/deps/icu-small/source/i18n/number_decnum.h @@ -0,0 +1,77 @@ +// © 2017 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMBER_DECNUM_H__ +#define __NUMBER_DECNUM_H__ + +#include "decNumber.h" +#include "charstr.h" + +U_NAMESPACE_BEGIN + +#define DECNUM_INITIAL_CAPACITY 34 + +// Export an explicit template instantiation of the MaybeStackHeaderAndArray that is used as a data member of DecNum. +// When building DLLs for Windows this is required even though no direct access to the MaybeStackHeaderAndArray leaks out of the i18n library. +// (See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.) +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +template class U_I18N_API MaybeStackHeaderAndArray; +#endif + +namespace number { +namespace impl { + +/** A very thin C++ wrapper around decNumber.h */ +// Exported as U_I18N_API for tests +class U_I18N_API DecNum : public UMemory { + public: + DecNum(); // leaves object in valid but undefined state + + // Copy-like constructor; use the default move operators. + DecNum(const DecNum& other, UErrorCode& status); + + /** Sets the decNumber to the StringPiece. */ + void setTo(StringPiece str, UErrorCode& status); + + /** Sets the decNumber to the NUL-terminated char string. */ + void setTo(const char* str, UErrorCode& status); + + /** Uses double_conversion to set this decNumber to the given double. */ + void setTo(double d, UErrorCode& status); + + /** Sets the decNumber to the BCD representation. */ + void setTo(const uint8_t* bcd, int32_t length, int32_t scale, bool isNegative, UErrorCode& status); + + void normalize(); + + void multiplyBy(const DecNum& rhs, UErrorCode& status); + + void divideBy(const DecNum& rhs, UErrorCode& status); + + bool isNegative() const; + + bool isZero() const; + + inline const decNumber* getRawDecNumber() const { + return fData.getAlias(); + } + + private: + static constexpr int32_t kDefaultDigits = DECNUM_INITIAL_CAPACITY; + MaybeStackHeaderAndArray fData; + decContext fContext; + + void _setTo(const char* str, int32_t maxDigits, UErrorCode& status); +}; + +} // namespace impl +} // namespace number + +U_NAMESPACE_END + +#endif // __NUMBER_DECNUM_H__ + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_fluent.cpp b/deps/icu-small/source/i18n/number_fluent.cpp index 27113106c5..687adb6b5b 100644 --- a/deps/icu-small/source/i18n/number_fluent.cpp +++ b/deps/icu-small/source/i18n/number_fluent.cpp @@ -3,20 +3,26 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "uassert.h" #include "unicode/numberformatter.h" #include "number_decimalquantity.h" #include "number_formatimpl.h" #include "umutex.h" +#include "number_asformat.h" +#include "number_skeletons.h" +#include "number_utils.h" +#include "number_utypes.h" +#include "util.h" +#include "fphdlimp.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; template -Derived NumberFormatterSettings::notation(const Notation ¬ation) const { +Derived NumberFormatterSettings::notation(const Notation& notation) const& { Derived copy(*this); // NOTE: Slicing is OK. copy.fMacros.notation = notation; @@ -24,7 +30,15 @@ Derived NumberFormatterSettings::notation(const Notation ¬ation) con } template -Derived NumberFormatterSettings::unit(const icu::MeasureUnit &unit) const { +Derived NumberFormatterSettings::notation(const Notation& notation)&& { + Derived move(std::move(*this)); + // NOTE: Slicing is OK. + move.fMacros.notation = notation; + return move; +} + +template +Derived NumberFormatterSettings::unit(const icu::MeasureUnit& unit) const& { Derived copy(*this); // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. @@ -33,21 +47,41 @@ Derived NumberFormatterSettings::unit(const icu::MeasureUnit &unit) con } template -Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit *unit) const { +Derived NumberFormatterSettings::unit(const icu::MeasureUnit& unit)&& { + Derived move(std::move(*this)); + // See comments above about slicing. + move.fMacros.unit = unit; + return move; +} + +template +Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit* unit) const& { Derived copy(*this); - // Just copy the unit into the MacroProps by value, and delete it since we have ownership. + // Just move the unit into the MacroProps by value, and delete it since we have ownership. // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. if (unit != nullptr) { - // TODO: On nullptr, reset to default value? - copy.fMacros.unit = *unit; + // TODO: On nullptr, reset to default value? + copy.fMacros.unit = std::move(*unit); delete unit; } return copy; } template -Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit &perUnit) const { +Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit* unit)&& { + Derived move(std::move(*this)); + // See comments above about slicing and ownership. + if (unit != nullptr) { + // TODO: On nullptr, reset to default value? + move.fMacros.unit = std::move(*unit); + delete unit; + } + return move; +} + +template +Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit& perUnit) const& { Derived copy(*this); // See comments above about slicing. copy.fMacros.perUnit = perUnit; @@ -55,27 +89,69 @@ Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit &perUni } template -Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit *perUnit) const { +Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit& perUnit)&& { + Derived move(std::move(*this)); + // See comments above about slicing. + move.fMacros.perUnit = perUnit; + return move; +} + +template +Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit* perUnit) const& { Derived copy(*this); // See comments above about slicing and ownership. if (perUnit != nullptr) { - // TODO: On nullptr, reset to default value? - copy.fMacros.perUnit = *perUnit; + // TODO: On nullptr, reset to default value? + copy.fMacros.perUnit = std::move(*perUnit); delete perUnit; } return copy; } template -Derived NumberFormatterSettings::rounding(const Rounder &rounder) const { +Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit* perUnit)&& { + Derived move(std::move(*this)); + // See comments above about slicing and ownership. + if (perUnit != nullptr) { + // TODO: On nullptr, reset to default value? + move.fMacros.perUnit = std::move(*perUnit); + delete perUnit; + } + return move; +} + +template +Derived NumberFormatterSettings::precision(const Precision& precision) const& { Derived copy(*this); // NOTE: Slicing is OK. - copy.fMacros.rounder = rounder; + copy.fMacros.precision = precision; return copy; } template -Derived NumberFormatterSettings::grouping(const UGroupingStrategy &strategy) const { +Derived NumberFormatterSettings::precision(const Precision& precision)&& { + Derived move(std::move(*this)); + // NOTE: Slicing is OK. + move.fMacros.precision = precision; + return move; +} + +template +Derived NumberFormatterSettings::roundingMode(UNumberFormatRoundingMode roundingMode) const& { + Derived copy(*this); + copy.fMacros.roundingMode = roundingMode; + return copy; +} + +template +Derived NumberFormatterSettings::roundingMode(UNumberFormatRoundingMode roundingMode)&& { + Derived move(std::move(*this)); + move.fMacros.roundingMode = roundingMode; + return move; +} + +template +Derived NumberFormatterSettings::grouping(UGroupingStrategy strategy) const& { Derived copy(*this); // NOTE: This is slightly different than how the setting is stored in Java // because we want to put it on the stack. @@ -84,61 +160,174 @@ Derived NumberFormatterSettings::grouping(const UGroupingStrategy &stra } template -Derived NumberFormatterSettings::integerWidth(const IntegerWidth &style) const { +Derived NumberFormatterSettings::grouping(UGroupingStrategy strategy)&& { + Derived move(std::move(*this)); + move.fMacros.grouper = Grouper::forStrategy(strategy); + return move; +} + +template +Derived NumberFormatterSettings::integerWidth(const IntegerWidth& style) const& { Derived copy(*this); copy.fMacros.integerWidth = style; return copy; } template -Derived NumberFormatterSettings::symbols(const DecimalFormatSymbols &symbols) const { +Derived NumberFormatterSettings::integerWidth(const IntegerWidth& style)&& { + Derived move(std::move(*this)); + move.fMacros.integerWidth = style; + return move; +} + +template +Derived NumberFormatterSettings::symbols(const DecimalFormatSymbols& symbols) const& { Derived copy(*this); copy.fMacros.symbols.setTo(symbols); return copy; } template -Derived NumberFormatterSettings::adoptSymbols(NumberingSystem *ns) const { +Derived NumberFormatterSettings::symbols(const DecimalFormatSymbols& symbols)&& { + Derived move(std::move(*this)); + move.fMacros.symbols.setTo(symbols); + return move; +} + +template +Derived NumberFormatterSettings::adoptSymbols(NumberingSystem* ns) const& { Derived copy(*this); copy.fMacros.symbols.setTo(ns); return copy; } template -Derived NumberFormatterSettings::unitWidth(const UNumberUnitWidth &width) const { +Derived NumberFormatterSettings::adoptSymbols(NumberingSystem* ns)&& { + Derived move(std::move(*this)); + move.fMacros.symbols.setTo(ns); + return move; +} + +template +Derived NumberFormatterSettings::unitWidth(UNumberUnitWidth width) const& { Derived copy(*this); copy.fMacros.unitWidth = width; return copy; } template -Derived NumberFormatterSettings::sign(const UNumberSignDisplay &style) const { +Derived NumberFormatterSettings::unitWidth(UNumberUnitWidth width)&& { + Derived move(std::move(*this)); + move.fMacros.unitWidth = width; + return move; +} + +template +Derived NumberFormatterSettings::sign(UNumberSignDisplay style) const& { Derived copy(*this); copy.fMacros.sign = style; return copy; } template -Derived NumberFormatterSettings::decimal(const UNumberDecimalSeparatorDisplay &style) const { +Derived NumberFormatterSettings::sign(UNumberSignDisplay style)&& { + Derived move(std::move(*this)); + move.fMacros.sign = style; + return move; +} + +template +Derived NumberFormatterSettings::decimal(UNumberDecimalSeparatorDisplay style) const& { Derived copy(*this); copy.fMacros.decimal = style; return copy; } template -Derived NumberFormatterSettings::padding(const Padder &padder) const { +Derived NumberFormatterSettings::decimal(UNumberDecimalSeparatorDisplay style)&& { + Derived move(std::move(*this)); + move.fMacros.decimal = style; + return move; +} + +template +Derived NumberFormatterSettings::scale(const Scale& scale) const& { + Derived copy(*this); + copy.fMacros.scale = scale; + return copy; +} + +template +Derived NumberFormatterSettings::scale(const Scale& scale)&& { + Derived move(std::move(*this)); + move.fMacros.scale = scale; + return move; +} + +template +Derived NumberFormatterSettings::padding(const Padder& padder) const& { Derived copy(*this); copy.fMacros.padder = padder; return copy; } template -Derived NumberFormatterSettings::threshold(int32_t threshold) const { +Derived NumberFormatterSettings::padding(const Padder& padder)&& { + Derived move(std::move(*this)); + move.fMacros.padder = padder; + return move; +} + +template +Derived NumberFormatterSettings::threshold(int32_t threshold) const& { Derived copy(*this); copy.fMacros.threshold = threshold; return copy; } +template +Derived NumberFormatterSettings::threshold(int32_t threshold)&& { + Derived move(std::move(*this)); + move.fMacros.threshold = threshold; + return move; +} + +template +Derived NumberFormatterSettings::macros(const impl::MacroProps& macros) const& { + Derived copy(*this); + copy.fMacros = macros; + return copy; +} + +template +Derived NumberFormatterSettings::macros(const impl::MacroProps& macros)&& { + Derived move(std::move(*this)); + move.fMacros = macros; + return move; +} + +template +Derived NumberFormatterSettings::macros(impl::MacroProps&& macros) const& { + Derived copy(*this); + copy.fMacros = std::move(macros); + return copy; +} + +template +Derived NumberFormatterSettings::macros(impl::MacroProps&& macros)&& { + Derived move(std::move(*this)); + move.fMacros = std::move(macros); + return move; +} + +template +UnicodeString NumberFormatterSettings::toSkeleton(UErrorCode& status) const { + if (fMacros.copyErrorTo(status)) { + return ICU_Utility::makeBogusString(); + } + return skeleton::generate(fMacros, status); +} + // Declare all classes that implement NumberFormatterSettings // See https://stackoverflow.com/a/495056/1407170 template @@ -152,38 +341,135 @@ UnlocalizedNumberFormatter NumberFormatter::with() { return result; } -LocalizedNumberFormatter NumberFormatter::withLocale(const Locale &locale) { +LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) { return with().locale(locale); } -// Make the child class constructor that takes the parent class call the parent class's copy constructor -UnlocalizedNumberFormatter::UnlocalizedNumberFormatter( - const NumberFormatterSettings &other) - : NumberFormatterSettings(other) { +UnlocalizedNumberFormatter +NumberFormatter::forSkeleton(const UnicodeString& skeleton, UErrorCode& status) { + return skeleton::create(skeleton, status); +} + + +template using NFS = NumberFormatterSettings; +using LNF = LocalizedNumberFormatter; +using UNF = UnlocalizedNumberFormatter; + +UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF& other) + : UNF(static_cast&>(other)) {} + +UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS& other) + : NFS(other) { + // No additional fields to assign +} + +UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT + : UNF(static_cast&&>(src)) {} + +UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS&& src) U_NOEXCEPT + : NFS(std::move(src)) { + // No additional fields to assign +} + +UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) { + NFS::operator=(static_cast&>(other)); + // No additional fields to assign + return *this; +} + +UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_NOEXCEPT { + NFS::operator=(static_cast&&>(src)); + // No additional fields to assign + return *this; +} + +LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other) + : LNF(static_cast&>(other)) {} + +LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS& other) + : NFS(other) { + // No additional fields to assign (let call count and compiled formatter reset to defaults) +} + +LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) U_NOEXCEPT + : LNF(static_cast&&>(src)) {} + +LocalizedNumberFormatter::LocalizedNumberFormatter(NFS&& src) U_NOEXCEPT + : NFS(std::move(src)) { + // For the move operators, copy over the compiled formatter. + // Note: if the formatter is not compiled, call count information is lost. + if (static_cast(src).fCompiled != nullptr) { + lnfMoveHelper(static_cast(src)); + } +} + +LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) { + NFS::operator=(static_cast&>(other)); + // No additional fields to assign (let call count and compiled formatter reset to defaults) + return *this; +} + +LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXCEPT { + NFS::operator=(static_cast&&>(src)); + // For the move operators, copy over the compiled formatter. + // Note: if the formatter is not compiled, call count information is lost. + if (static_cast(src).fCompiled != nullptr) { + // Formatter is compiled + lnfMoveHelper(static_cast(src)); + } else { + // Reset to default values. + auto* callCount = reinterpret_cast(fUnsafeCallCount); + umtx_storeRelease(*callCount, 0); + fCompiled = nullptr; + } + return *this; +} + +void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) { + // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled(). + // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease. + // The bits themselves appear to be platform-dependent, so copying them might not be safe. + auto* callCount = reinterpret_cast(fUnsafeCallCount); + umtx_storeRelease(*callCount, INT32_MIN); + fCompiled = src.fCompiled; + // Reset the source object to leave it in a safe state. + auto* srcCallCount = reinterpret_cast(src.fUnsafeCallCount); + umtx_storeRelease(*srcCallCount, 0); + src.fCompiled = nullptr; } -// Make the child class constructor that takes the parent class call the parent class's copy constructor -// For LocalizedNumberFormatter, also copy over the extra fields -LocalizedNumberFormatter::LocalizedNumberFormatter( - const NumberFormatterSettings &other) - : NumberFormatterSettings(other) { - // No additional copies required + +LocalizedNumberFormatter::~LocalizedNumberFormatter() { + delete fCompiled; } -LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps ¯os, const Locale &locale) { +LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) { fMacros = macros; fMacros.locale = locale; } -LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale &locale) const { +LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps&& macros, const Locale& locale) { + fMacros = std::move(macros); + fMacros.locale = locale; +} + +LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const& { return LocalizedNumberFormatter(fMacros, locale); } -SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper &other) { +LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& { + return LocalizedNumberFormatter(std::move(fMacros), locale); +} + +SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) { doCopyFrom(other); } -SymbolsWrapper &SymbolsWrapper::operator=(const SymbolsWrapper &other) { +SymbolsWrapper::SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT { + doMoveFrom(std::move(src)); +} + +SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) { if (this == &other) { return *this; } @@ -192,23 +478,32 @@ SymbolsWrapper &SymbolsWrapper::operator=(const SymbolsWrapper &other) { return *this; } +SymbolsWrapper& SymbolsWrapper::operator=(SymbolsWrapper&& src) U_NOEXCEPT { + if (this == &src) { + return *this; + } + doCleanup(); + doMoveFrom(std::move(src)); + return *this; +} + SymbolsWrapper::~SymbolsWrapper() { doCleanup(); } -void SymbolsWrapper::setTo(const DecimalFormatSymbols &dfs) { +void SymbolsWrapper::setTo(const DecimalFormatSymbols& dfs) { doCleanup(); fType = SYMPTR_DFS; fPtr.dfs = new DecimalFormatSymbols(dfs); } -void SymbolsWrapper::setTo(const NumberingSystem *ns) { +void SymbolsWrapper::setTo(const NumberingSystem* ns) { doCleanup(); fType = SYMPTR_NS; fPtr.ns = ns; } -void SymbolsWrapper::doCopyFrom(const SymbolsWrapper &other) { +void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) { fType = other.fType; switch (fType) { case SYMPTR_NONE: @@ -233,6 +528,23 @@ void SymbolsWrapper::doCopyFrom(const SymbolsWrapper &other) { } } +void SymbolsWrapper::doMoveFrom(SymbolsWrapper&& src) { + fType = src.fType; + switch (fType) { + case SYMPTR_NONE: + // No action necessary + break; + case SYMPTR_DFS: + fPtr.dfs = src.fPtr.dfs; + src.fPtr.dfs = nullptr; + break; + case SYMPTR_NS: + fPtr.ns = src.fPtr.ns; + src.fPtr.ns = nullptr; + break; + } +} + void SymbolsWrapper::doCleanup() { switch (fType) { case SYMPTR_NONE: @@ -265,53 +577,122 @@ const NumberingSystem* SymbolsWrapper::getNumberingSystem() const { return fPtr.ns; } -LocalizedNumberFormatter::~LocalizedNumberFormatter() { - delete fCompiled; -} -FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode &status) const { +FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const { if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } - auto results = new NumberFormatterResults(); + auto results = new UFormattedNumberData(); if (results == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return FormattedNumber(status); } results->quantity.setToLong(value); - return formatImpl(results, status); + formatImpl(results, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumber(results); + } else { + delete results; + return FormattedNumber(status); + } } -FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode &status) const { +FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const { if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } - auto results = new NumberFormatterResults(); + auto results = new UFormattedNumberData(); if (results == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return FormattedNumber(status); } results->quantity.setToDouble(value); - return formatImpl(results, status); + formatImpl(results, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumber(results); + } else { + delete results; + return FormattedNumber(status); + } } -FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode &status) const { +FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const { if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } - auto results = new NumberFormatterResults(); + auto results = new UFormattedNumberData(); if (results == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return FormattedNumber(status); } - results->quantity.setToDecNumber(value); - return formatImpl(results, status); + results->quantity.setToDecNumber(value, status); + formatImpl(results, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumber(results); + } else { + delete results; + return FormattedNumber(status); + } } FormattedNumber -LocalizedNumberFormatter::formatImpl(impl::NumberFormatterResults *results, UErrorCode &status) const { +LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const { + if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } + auto results = new UFormattedNumberData(); + if (results == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return FormattedNumber(status); + } + results->quantity = dq; + formatImpl(results, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumber(results); + } else { + delete results; + return FormattedNumber(status); + } +} + +void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const { + if (computeCompiled(status)) { + fCompiled->apply(results->quantity, results->string, status); + } else { + NumberFormatterImpl::applyStatic(fMacros, results->quantity, results->string, status); + } +} + +void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result, + UErrorCode& status) const { + NumberStringBuilder string; + auto signum = static_cast(isNegative ? -1 : 1); + // Always return affixes for plural form OTHER. + static const StandardPlural::Form plural = StandardPlural::OTHER; + int32_t prefixLength; + if (computeCompiled(status)) { + prefixLength = fCompiled->getPrefixSuffix(signum, plural, string, status); + } else { + prefixLength = NumberFormatterImpl::getPrefixSuffixStatic(fMacros, signum, plural, string, status); + } + result.remove(); + if (isPrefix) { + result.append(string.toTempUnicodeString().tempSubStringBetween(0, prefixLength)); + } else { + result.append(string.toTempUnicodeString().tempSubStringBetween(prefixLength, string.length())); + } +} + +bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const { // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly // std::atomic. Since the type of atomic int is platform-dependent, we cast the // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent // atomic int type defined in umutex.h. - static_assert(sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount), - "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount"); - u_atomic_int32_t* callCount = reinterpret_cast( - const_cast(this)->fUnsafeCallCount); + static_assert( + sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount), + "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount"); + auto* callCount = reinterpret_cast( + const_cast(this)->fUnsafeCallCount); // A positive value in the atomic int indicates that the data structure is not yet ready; // a negative value indicates that it is ready. If, after the increment, the atomic int @@ -325,64 +706,144 @@ LocalizedNumberFormatter::formatImpl(impl::NumberFormatterResults *results, UErr if (currentCount == fMacros.threshold && fMacros.threshold > 0) { // Build the data structure and then use it (slow to fast path). - const NumberFormatterImpl* compiled = - NumberFormatterImpl::fromMacros(fMacros, status); + const NumberFormatterImpl* compiled = NumberFormatterImpl::fromMacros(fMacros, status); U_ASSERT(fCompiled == nullptr); - const_cast(this)->fCompiled = compiled; + const_cast(this)->fCompiled = compiled; umtx_storeRelease(*callCount, INT32_MIN); - compiled->apply(results->quantity, results->string, status); + return true; } else if (currentCount < 0) { // The data structure is already built; use it (fast path). U_ASSERT(fCompiled != nullptr); - fCompiled->apply(results->quantity, results->string, status); + return true; } else { // Format the number without building the data structure (slow path). - NumberFormatterImpl::applyStatic(fMacros, results->quantity, results->string, status); + return false; } +} - // Do not save the results object if we encountered a failure. - if (U_SUCCESS(status)) { - return FormattedNumber(results); - } else { - delete results; - return FormattedNumber(status); - } +const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const { + return fCompiled; +} + +int32_t LocalizedNumberFormatter::getCallCount() const { + auto* callCount = reinterpret_cast( + const_cast(this)->fUnsafeCallCount); + return umtx_loadAcquire(*callCount); +} + +Format* LocalizedNumberFormatter::toFormat(UErrorCode& status) const { + LocalPointer retval( + new LocalizedNumberFormatterAsFormat(*this, fMacros.locale), status); + return retval.orphan(); +} + + +FormattedNumber::FormattedNumber(FormattedNumber&& src) U_NOEXCEPT + : fResults(src.fResults), fErrorCode(src.fErrorCode) { + // Disown src.fResults to prevent double-deletion + src.fResults = nullptr; + src.fErrorCode = U_INVALID_STATE_ERROR; +} + +FormattedNumber& FormattedNumber::operator=(FormattedNumber&& src) U_NOEXCEPT { + delete fResults; + fResults = src.fResults; + fErrorCode = src.fErrorCode; + // Disown src.fResults to prevent double-deletion + src.fResults = nullptr; + src.fErrorCode = U_INVALID_STATE_ERROR; + return *this; } UnicodeString FormattedNumber::toString() const { + UErrorCode localStatus = U_ZERO_ERROR; + return toString(localStatus); +} + +UnicodeString FormattedNumber::toString(UErrorCode& status) const { + if (U_FAILURE(status)) { + return ICU_Utility::makeBogusString(); + } if (fResults == nullptr) { - // TODO: http://bugs.icu-project.org/trac/ticket/13437 - return {}; + status = fErrorCode; + return ICU_Utility::makeBogusString(); } return fResults->string.toUnicodeString(); } -Appendable &FormattedNumber::appendTo(Appendable &appendable) { +Appendable& FormattedNumber::appendTo(Appendable& appendable) { + UErrorCode localStatus = U_ZERO_ERROR; + return appendTo(appendable, localStatus); +} + +Appendable& FormattedNumber::appendTo(Appendable& appendable, UErrorCode& status) { + if (U_FAILURE(status)) { + return appendable; + } if (fResults == nullptr) { - // TODO: http://bugs.icu-project.org/trac/ticket/13437 + status = fErrorCode; return appendable; } appendable.appendString(fResults->string.chars(), fResults->string.length()); return appendable; } -void FormattedNumber::populateFieldPosition(FieldPosition &fieldPosition, UErrorCode &status) { - if (U_FAILURE(status)) { return; } +void FormattedNumber::populateFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) { + if (U_FAILURE(status)) { + return; + } + if (fResults == nullptr) { + status = fErrorCode; + return; + } + // in case any users were depending on the old behavior: + fieldPosition.setBeginIndex(0); + fieldPosition.setEndIndex(0); + fResults->string.nextFieldPosition(fieldPosition, status); +} + +UBool FormattedNumber::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const { + if (U_FAILURE(status)) { + return FALSE; + } + if (fResults == nullptr) { + status = fErrorCode; + return FALSE; + } + // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool + return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE; +} + +void FormattedNumber::populateFieldPositionIterator(FieldPositionIterator& iterator, UErrorCode& status) { + getAllFieldPositions(iterator, status); +} + +void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const { + FieldPositionIteratorHandler fpih(&iterator, status); + getAllFieldPositionsImpl(fpih, status); +} + +void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, + UErrorCode& status) const { + if (U_FAILURE(status)) { + return; + } if (fResults == nullptr) { status = fErrorCode; return; } - fResults->string.populateFieldPosition(fieldPosition, 0, status); + fResults->string.getAllFieldPositions(fpih, status); } -void -FormattedNumber::populateFieldPositionIterator(FieldPositionIterator &iterator, UErrorCode &status) { - if (U_FAILURE(status)) { return; } +void FormattedNumber::getDecimalQuantity(DecimalQuantity& output, UErrorCode& status) const { + if (U_FAILURE(status)) { + return; + } if (fResults == nullptr) { status = fErrorCode; return; } - fResults->string.populateFieldPositionIterator(iterator, status); + output = fResults->quantity; } FormattedNumber::~FormattedNumber() { diff --git a/deps/icu-small/source/i18n/number_formatimpl.cpp b/deps/icu-small/source/i18n/number_formatimpl.cpp index bc96cb15da..3f887128bc 100644 --- a/deps/icu-small/source/i18n/number_formatimpl.cpp +++ b/deps/icu-small/source/i18n/number_formatimpl.cpp @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "cstring.h" #include "unicode/ures.h" @@ -26,88 +26,28 @@ using namespace icu::number::impl; namespace { -// NOTE: In Java, the method to get a pattern from the resource bundle exists in NumberFormat. -// In C++, we have to implement that logic here. -// TODO: Make Java and C++ consistent? - -enum CldrPatternStyle { - CLDR_PATTERN_STYLE_DECIMAL, - CLDR_PATTERN_STYLE_CURRENCY, - CLDR_PATTERN_STYLE_ACCOUNTING, - CLDR_PATTERN_STYLE_PERCENT - // TODO: Consider scientific format. -}; - -const char16_t * -doGetPattern(UResourceBundle *res, const char *nsName, const char *patternKey, UErrorCode &publicStatus, - UErrorCode &localStatus) { - // Construct the path into the resource bundle - CharString key; - key.append("NumberElements/", publicStatus); - key.append(nsName, publicStatus); - key.append("/patterns/", publicStatus); - key.append(patternKey, publicStatus); - if (U_FAILURE(publicStatus)) { - return u""; - } - return ures_getStringByKeyWithFallback(res, key.data(), nullptr, &localStatus); -} - -const char16_t *getPatternForStyle(const Locale &locale, const char *nsName, CldrPatternStyle style, - UErrorCode &status) { - const char *patternKey; - switch (style) { - case CLDR_PATTERN_STYLE_DECIMAL: - patternKey = "decimalFormat"; - break; - case CLDR_PATTERN_STYLE_CURRENCY: - patternKey = "currencyFormat"; - break; - case CLDR_PATTERN_STYLE_ACCOUNTING: - patternKey = "accountingFormat"; - break; - case CLDR_PATTERN_STYLE_PERCENT: - default: - patternKey = "percentFormat"; - break; - } - LocalUResourceBundlePointer res(ures_open(nullptr, locale.getName(), &status)); - if (U_FAILURE(status)) { return u""; } - - // Attempt to get the pattern with the native numbering system. - UErrorCode localStatus = U_ZERO_ERROR; - const char16_t *pattern; - pattern = doGetPattern(res.getAlias(), nsName, patternKey, status, localStatus); - if (U_FAILURE(status)) { return u""; } - - // Fall back to latn if native numbering system does not have the right pattern - if (U_FAILURE(localStatus) && uprv_strcmp("latn", nsName) != 0) { - localStatus = U_ZERO_ERROR; - pattern = doGetPattern(res.getAlias(), "latn", patternKey, status, localStatus); - if (U_FAILURE(status)) { return u""; } - } - - return pattern; -} - struct CurrencyFormatInfoResult { bool exists; const char16_t* pattern; const char16_t* decimalSeparator; const char16_t* groupingSeparator; }; -CurrencyFormatInfoResult getCurrencyFormatInfo(const Locale& locale, const char* isoCode, UErrorCode& status) { + +CurrencyFormatInfoResult +getCurrencyFormatInfo(const Locale& locale, const char* isoCode, UErrorCode& status) { // TODO: Load this data in a centralized location like ICU4J? + // TODO: Move this into the CurrencySymbols class? // TODO: Parts of this same data are loaded in dcfmtsym.cpp; should clean up. - CurrencyFormatInfoResult result = { false, nullptr, nullptr, nullptr }; - if (U_FAILURE(status)) return result; + CurrencyFormatInfoResult result = {false, nullptr, nullptr, nullptr}; + if (U_FAILURE(status)) { return result; } CharString key; key.append("Currencies/", status); key.append(isoCode, status); UErrorCode localStatus = status; LocalUResourceBundlePointer bundle(ures_open(U_ICUDATA_CURR, locale.getName(), &localStatus)); ures_getByKeyWithFallback(bundle.getAlias(), key.data(), bundle.getAlias(), &localStatus); - if (U_SUCCESS(localStatus) && ures_getSize(bundle.getAlias())>2) { // the length is 3 if more data is present + if (U_SUCCESS(localStatus) && + ures_getSize(bundle.getAlias()) > 2) { // the length is 3 if more data is present ures_getByIndex(bundle.getAlias(), 2, bundle.getAlias(), &localStatus); int32_t dummy; result.exists = true; @@ -121,65 +61,84 @@ CurrencyFormatInfoResult getCurrencyFormatInfo(const Locale& locale, const char* return result; } -inline bool unitIsCurrency(const MeasureUnit &unit) { - return uprv_strcmp("currency", unit.getType()) == 0; -} - -inline bool unitIsNoUnit(const MeasureUnit &unit) { - return uprv_strcmp("none", unit.getType()) == 0; -} +} // namespace -inline bool unitIsPercent(const MeasureUnit &unit) { - return uprv_strcmp("percent", unit.getSubtype()) == 0; -} -inline bool unitIsPermille(const MeasureUnit &unit) { - return uprv_strcmp("permille", unit.getSubtype()) == 0; -} +MicroPropsGenerator::~MicroPropsGenerator() = default; -} // namespace -NumberFormatterImpl *NumberFormatterImpl::fromMacros(const MacroProps ¯os, UErrorCode &status) { +NumberFormatterImpl* NumberFormatterImpl::fromMacros(const MacroProps& macros, UErrorCode& status) { return new NumberFormatterImpl(macros, true, status); } -void NumberFormatterImpl::applyStatic(const MacroProps ¯os, DecimalQuantity &inValue, - NumberStringBuilder &outString, UErrorCode &status) { +void NumberFormatterImpl::applyStatic(const MacroProps& macros, DecimalQuantity& inValue, + NumberStringBuilder& outString, UErrorCode& status) { NumberFormatterImpl impl(macros, false, status); impl.applyUnsafe(inValue, outString, status); } +int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int8_t signum, + StandardPlural::Form plural, + NumberStringBuilder& outString, UErrorCode& status) { + NumberFormatterImpl impl(macros, false, status); + return impl.getPrefixSuffixUnsafe(signum, plural, outString, status); +} + // NOTE: C++ SPECIFIC DIFFERENCE FROM JAVA: // The "safe" apply method uses a new MicroProps. In the MicroPropsGenerator, fMicros is copied into the new instance. // The "unsafe" method simply re-uses fMicros, eliminating the extra copy operation. // See MicroProps::processQuantity() for details. -void NumberFormatterImpl::apply(DecimalQuantity &inValue, NumberStringBuilder &outString, - UErrorCode &status) const { +void NumberFormatterImpl::apply(DecimalQuantity& inValue, NumberStringBuilder& outString, + UErrorCode& status) const { if (U_FAILURE(status)) { return; } MicroProps micros; + if (!fMicroPropsGenerator) { return; } fMicroPropsGenerator->processQuantity(inValue, micros, status); if (U_FAILURE(status)) { return; } microsToString(micros, inValue, outString, status); } -void NumberFormatterImpl::applyUnsafe(DecimalQuantity &inValue, NumberStringBuilder &outString, - UErrorCode &status) { +void NumberFormatterImpl::applyUnsafe(DecimalQuantity& inValue, NumberStringBuilder& outString, + UErrorCode& status) { if (U_FAILURE(status)) { return; } fMicroPropsGenerator->processQuantity(inValue, fMicros, status); if (U_FAILURE(status)) { return; } microsToString(fMicros, inValue, outString, status); } -NumberFormatterImpl::NumberFormatterImpl(const MacroProps ¯os, bool safe, UErrorCode &status) { +int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form plural, + NumberStringBuilder& outString, UErrorCode& status) const { + if (U_FAILURE(status)) { return 0; } + // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle, aka pattern modifier). + // Safe path: use fImmutablePatternModifier. + const Modifier* modifier = fImmutablePatternModifier->getModifier(signum, plural); + modifier->apply(outString, 0, 0, status); + if (U_FAILURE(status)) { return 0; } + return modifier->getPrefixLength(status); +} + +int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural, + NumberStringBuilder& outString, UErrorCode& status) { + if (U_FAILURE(status)) { return 0; } + // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle, aka pattern modifier). + // Unsafe path: use fPatternModifier. + fPatternModifier->setNumberProperties(signum, plural); + fPatternModifier->apply(outString, 0, 0, status); + if (U_FAILURE(status)) { return 0; } + return fPatternModifier->getPrefixLength(status); +} + +NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, bool safe, UErrorCode& status) { fMicroPropsGenerator = macrosToMicroGenerator(macros, safe, status); } ////////// -const MicroPropsGenerator * -NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, UErrorCode &status) { - const MicroPropsGenerator *chain = &fMicros; +const MicroPropsGenerator* +NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe, UErrorCode& status) { + if (U_FAILURE(status)) { return nullptr; } + const MicroPropsGenerator* chain = &fMicros; // Check that macros is error-free before continuing. if (macros.copyErrorTo(status)) { @@ -189,18 +148,26 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, // TODO: Accept currency symbols from DecimalFormatSymbols? // Pre-compute a few values for efficiency. - bool isCurrency = unitIsCurrency(macros.unit); - bool isNoUnit = unitIsNoUnit(macros.unit); - bool isPercent = isNoUnit && unitIsPercent(macros.unit); - bool isPermille = isNoUnit && unitIsPermille(macros.unit); + bool isCurrency = utils::unitIsCurrency(macros.unit); + bool isNoUnit = utils::unitIsNoUnit(macros.unit); + bool isPercent = isNoUnit && utils::unitIsPercent(macros.unit); + bool isPermille = isNoUnit && utils::unitIsPermille(macros.unit); bool isCldrUnit = !isCurrency && !isNoUnit; - bool isAccounting = macros.sign == UNUM_SIGN_ACCOUNTING - || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS - || macros.sign == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO; - CurrencyUnit currency(kDefaultCurrency, status); + bool isAccounting = + macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS || + macros.sign == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO; + CurrencyUnit currency(nullptr, status); if (isCurrency) { currency = CurrencyUnit(macros.unit, status); // Restore CurrencyUnit from MeasureUnit } + const CurrencySymbols* currencySymbols; + if (macros.currencySymbols != nullptr) { + // Used by the DecimalFormat code path + currencySymbols = macros.currencySymbols; + } else { + fWarehouse.fCurrencySymbols = {currency, macros.locale, status}; + currencySymbols = &fWarehouse.fCurrencySymbols; + } UNumberUnitWidth unitWidth = UNUM_UNIT_WIDTH_SHORT; if (macros.unitWidth != UNUM_UNIT_WIDTH_COUNT) { unitWidth = macros.unitWidth; @@ -208,7 +175,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, // Select the numbering system. LocalPointer nsLocal; - const NumberingSystem *ns; + const NumberingSystem* ns; if (macros.symbols.isNumberingSystem()) { ns = macros.symbols.getNumberingSystem(); } else { @@ -217,7 +184,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, // Give ownership to the function scope. nsLocal.adoptInstead(ns); } - const char *nsName = U_SUCCESS(status) ? ns->getName() : "latn"; + const char* nsName = U_SUCCESS(status) ? ns->getName() : "latn"; // Resolve the symbols. Do this here because currency may need to customize them. if (macros.symbols.isDecimalFormatSymbols()) { @@ -232,21 +199,22 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, // If we are formatting currency, check for a currency-specific pattern. const char16_t* pattern = nullptr; if (isCurrency) { - CurrencyFormatInfoResult info = getCurrencyFormatInfo(macros.locale, currency.getSubtype(), status); + CurrencyFormatInfoResult info = getCurrencyFormatInfo( + macros.locale, currency.getSubtype(), status); if (info.exists) { pattern = info.pattern; // It's clunky to clone an object here, but this code is not frequently executed. - DecimalFormatSymbols* symbols = new DecimalFormatSymbols(*fMicros.symbols); + auto* symbols = new DecimalFormatSymbols(*fMicros.symbols); fMicros.symbols = symbols; fSymbols.adoptInstead(symbols); symbols->setSymbol( - DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol, - UnicodeString(info.decimalSeparator), - FALSE); + DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol, + UnicodeString(info.decimalSeparator), + FALSE); symbols->setSymbol( - DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol, - UnicodeString(info.groupingSeparator), - FALSE); + DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol, + UnicodeString(info.groupingSeparator), + FALSE); } } if (pattern == nullptr) { @@ -262,7 +230,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, } else { patternStyle = CLDR_PATTERN_STYLE_CURRENCY; } - pattern = getPatternForStyle(macros.locale, nsName, patternStyle, status); + pattern = utils::getPatternForStyle(macros.locale, nsName, patternStyle, status); } auto patternInfo = new ParsedPatternInfo(); fPatternInfo.adoptInstead(patternInfo); @@ -272,17 +240,31 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, /// START POPULATING THE DEFAULT MICROPROPS AND BUILDING THE MICROPROPS GENERATOR /// ///////////////////////////////////////////////////////////////////////////////////// + // Multiplier + if (macros.scale.isValid()) { + fMicros.helpers.multiplier.setAndChain(macros.scale, chain); + chain = &fMicros.helpers.multiplier; + } + // Rounding strategy - if (!macros.rounder.isBogus()) { - fMicros.rounding = macros.rounder; + Precision precision; + if (!macros.precision.isBogus()) { + precision = macros.precision; } else if (macros.notation.fType == Notation::NTN_COMPACT) { - fMicros.rounding = Rounder::integer().withMinDigits(2); + precision = Precision::integer().withMinDigits(2); } else if (isCurrency) { - fMicros.rounding = Rounder::currency(UCURR_USAGE_STANDARD); + precision = Precision::currency(UCURR_USAGE_STANDARD); + } else { + precision = Precision::maxFraction(6); + } + UNumberFormatRoundingMode roundingMode; + if (macros.roundingMode != kDefaultMode) { + roundingMode = macros.roundingMode; } else { - fMicros.rounding = Rounder::maxFraction(6); + // Temporary until ICU 64 + roundingMode = precision.fRoundingMode; } - fMicros.rounding.setLocaleData(currency, status); + fMicros.rounder = {precision, roundingMode, currency, status}; // Grouping strategy if (!macros.grouper.isBogus()) { @@ -306,7 +288,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, if (!macros.integerWidth.isBogus()) { fMicros.integerWidth = macros.integerWidth; } else { - fMicros.integerWidth = IntegerWidth::zeroFillTo(1); + fMicros.integerWidth = IntegerWidth::standard(); } // Sign display @@ -338,16 +320,18 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, // Middle modifier (patterns, positive/negative, currency symbols, percent) auto patternModifier = new MutablePatternModifier(false); fPatternModifier.adoptInstead(patternModifier); - patternModifier->setPatternInfo(fPatternInfo.getAlias()); + patternModifier->setPatternInfo( + macros.affixProvider != nullptr ? macros.affixProvider + : static_cast(fPatternInfo.getAlias())); patternModifier->setPatternAttributes(fMicros.sign, isPermille); if (patternModifier->needsPlurals()) { patternModifier->setSymbols( fMicros.symbols, - currency, + currencySymbols, unitWidth, resolvePluralRules(macros.rules, macros.locale, status)); } else { - patternModifier->setSymbols(fMicros.symbols, currency, unitWidth, nullptr); + patternModifier->setSymbols(fMicros.symbols, currencySymbols, unitWidth, nullptr); } if (safe) { fImmutablePatternModifier.adoptInstead(patternModifier->createImmutableAndChain(chain, status)); @@ -407,9 +391,9 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe, return chain; } -const PluralRules * -NumberFormatterImpl::resolvePluralRules(const PluralRules *rulesPtr, const Locale &locale, - UErrorCode &status) { +const PluralRules* +NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Locale& locale, + UErrorCode& status) { if (rulesPtr != nullptr) { return rulesPtr; } @@ -420,9 +404,9 @@ NumberFormatterImpl::resolvePluralRules(const PluralRules *rulesPtr, const Local return fRules.getAlias(); } -int32_t NumberFormatterImpl::microsToString(const MicroProps µs, DecimalQuantity &quantity, - NumberStringBuilder &string, UErrorCode &status) { - micros.rounding.apply(quantity, status); +int32_t NumberFormatterImpl::microsToString(const MicroProps& micros, DecimalQuantity& quantity, + NumberStringBuilder& string, UErrorCode& status) { + micros.rounder.apply(quantity, status); micros.integerWidth.apply(quantity, status); int32_t length = writeNumber(micros, quantity, string, status); // NOTE: When range formatting is added, these modifiers can bubble up. @@ -439,8 +423,8 @@ int32_t NumberFormatterImpl::microsToString(const MicroProps µs, DecimalQua return length; } -int32_t NumberFormatterImpl::writeNumber(const MicroProps µs, DecimalQuantity &quantity, - NumberStringBuilder &string, UErrorCode &status) { +int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity, + NumberStringBuilder& string, UErrorCode& status) { int32_t length = 0; if (quantity.isInfinite()) { length += string.insert( @@ -480,8 +464,8 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps µs, DecimalQuanti return length; } -int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps µs, DecimalQuantity &quantity, - NumberStringBuilder &string, UErrorCode &status) { +int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity, + NumberStringBuilder& string, UErrorCode& status) { int length = 0; int integerCount = quantity.getUpperDisplayMagnitude() + 1; for (int i = 0; i < integerCount; i++) { @@ -499,21 +483,21 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps µs, Decima // Get and append the next digit value int8_t nextDigit = quantity.getDigit(i); - length += string.insert( - 0, getDigitFromSymbols(nextDigit, *micros.symbols), UNUM_INTEGER_FIELD, status); + length += utils::insertDigitFromSymbols( + string, 0, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status); } return length; } -int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps µs, DecimalQuantity &quantity, - NumberStringBuilder &string, UErrorCode &status) { +int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity, + NumberStringBuilder& string, UErrorCode& status) { int length = 0; int fractionCount = -quantity.getLowerDisplayMagnitude(); for (int i = 0; i < fractionCount; i++) { // Get and append the next digit value int8_t nextDigit = quantity.getDigit(-i - 1); - length += string.append( - getDigitFromSymbols(nextDigit, *micros.symbols), UNUM_FRACTION_FIELD, status); + length += utils::insertDigitFromSymbols( + string, string.length(), nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status); } return length; } diff --git a/deps/icu-small/source/i18n/number_formatimpl.h b/deps/icu-small/source/i18n/number_formatimpl.h index cbc04ba30d..744fecec13 100644 --- a/deps/icu-small/source/i18n/number_formatimpl.h +++ b/deps/icu-small/source/i18n/number_formatimpl.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_FORMATIMPL_H__ #define __NUMBER_FORMATIMPL_H__ @@ -14,6 +14,7 @@ #include "number_patternmodifier.h" #include "number_longnames.h" #include "number_compact.h" +#include "number_microprops.h" U_NAMESPACE_BEGIN namespace number { namespace impl { @@ -37,10 +38,26 @@ class NumberFormatterImpl : public UMemory { applyStatic(const MacroProps ¯os, DecimalQuantity &inValue, NumberStringBuilder &outString, UErrorCode &status); + /** + * Prints only the prefix and suffix; used for DecimalFormat getters. + * + * @return The index into the output at which the prefix ends and the suffix starts; in other words, + * the prefix length. + */ + static int32_t getPrefixSuffixStatic(const MacroProps& macros, int8_t signum, + StandardPlural::Form plural, NumberStringBuilder& outString, + UErrorCode& status); + /** * Evaluates the "safe" MicroPropsGenerator created by "fromMacros". */ - void apply(DecimalQuantity &inValue, NumberStringBuilder &outString, UErrorCode &status) const; + void apply(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const; + + /** + * Like getPrefixSuffixStatic() but uses the safe compiled object. + */ + int32_t getPrefixSuffix(int8_t signum, StandardPlural::Form plural, NumberStringBuilder& outString, + UErrorCode& status) const; private: // Head of the MicroPropsGenerator linked list: @@ -50,21 +67,29 @@ class NumberFormatterImpl : public UMemory { MicroProps fMicros; // Other fields possibly used by the number formatting pipeline: - // TODO: Convert some of these LocalPointers to value objects to reduce the number of news? + // TODO: Convert more of these LocalPointers to value objects to reduce the number of news? LocalPointer fSymbols; LocalPointer fRules; LocalPointer fPatternInfo; LocalPointer fScientificHandler; - LocalPointer fPatternModifier; + LocalPointer fPatternModifier; LocalPointer fImmutablePatternModifier; LocalPointer fLongNameHandler; LocalPointer fCompactHandler; + // Value objects possibly used by the number formatting pipeline: + struct Warehouse { + CurrencySymbols fCurrencySymbols; + } fWarehouse; + NumberFormatterImpl(const MacroProps ¯os, bool safe, UErrorCode &status); void applyUnsafe(DecimalQuantity &inValue, NumberStringBuilder &outString, UErrorCode &status); + int32_t getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural, + NumberStringBuilder& outString, UErrorCode& status); + /** * If rulesPtr is non-null, return it. Otherwise, return a PluralRules owned by this object for the * specified locale, creating it if necessary. diff --git a/deps/icu-small/source/i18n/number_grouping.cpp b/deps/icu-small/source/i18n/number_grouping.cpp index a2b1bbd6b3..4a1cceb499 100644 --- a/deps/icu-small/source/i18n/number_grouping.cpp +++ b/deps/icu-small/source/i18n/number_grouping.cpp @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "unicode/numberformatter.h" #include "number_patternstring.h" @@ -37,20 +37,33 @@ int16_t getMinGroupingForLocale(const Locale& locale) { Grouper Grouper::forStrategy(UGroupingStrategy grouping) { switch (grouping) { case UNUM_GROUPING_OFF: - return {-1, -1, -2}; + return {-1, -1, -2, grouping}; case UNUM_GROUPING_AUTO: - return {-2, -2, -2}; + return {-2, -2, -2, grouping}; case UNUM_GROUPING_MIN2: - return {-2, -2, -3}; + return {-2, -2, -3, grouping}; case UNUM_GROUPING_ON_ALIGNED: - return {-4, -4, 1}; + return {-4, -4, 1, grouping}; case UNUM_GROUPING_THOUSANDS: - return {3, 3, 1}; + return {3, 3, 1, grouping}; default: U_ASSERT(FALSE); + return {}; // return a value: silence compiler warning } } +Grouper Grouper::forProperties(const DecimalFormatProperties& properties) { + if (!properties.groupingUsed) { + return forStrategy(UNUM_GROUPING_OFF); + } + auto grouping1 = static_cast(properties.groupingSize); + auto grouping2 = static_cast(properties.secondaryGroupingSize); + auto minGrouping = static_cast(properties.minimumGroupingDigits); + grouping1 = grouping1 > 0 ? grouping1 : grouping2 > 0 ? grouping2 : grouping1; + grouping2 = grouping2 > 0 ? grouping2 : grouping1; + return {grouping1, grouping2, minGrouping, UNUM_GROUPING_COUNT}; +} + void Grouper::setLocaleData(const impl::ParsedPatternInfo &patternInfo, const Locale& locale) { if (fGrouping1 != -2 && fGrouping2 != -4) { return; @@ -86,4 +99,12 @@ bool Grouper::groupAtPosition(int32_t position, const impl::DecimalQuantity &val && value.getUpperDisplayMagnitude() - fGrouping1 + 1 >= fMinGrouping; } +int16_t Grouper::getPrimary() const { + return fGrouping1; +} + +int16_t Grouper::getSecondary() const { + return fGrouping2; +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_integerwidth.cpp b/deps/icu-small/source/i18n/number_integerwidth.cpp index 4a612273f5..6416b29298 100644 --- a/deps/icu-small/source/i18n/number_integerwidth.cpp +++ b/deps/icu-small/source/i18n/number_integerwidth.cpp @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "unicode/numberformatter.h" #include "number_types.h" @@ -13,14 +13,15 @@ using namespace icu; using namespace icu::number; using namespace icu::number::impl; -IntegerWidth::IntegerWidth(digits_t minInt, digits_t maxInt) { +IntegerWidth::IntegerWidth(digits_t minInt, digits_t maxInt, bool formatFailIfMoreThanMaxDigits) { fUnion.minMaxInt.fMinInt = minInt; fUnion.minMaxInt.fMaxInt = maxInt; + fUnion.minMaxInt.fFormatFailIfMoreThanMaxDigits = formatFailIfMoreThanMaxDigits; } IntegerWidth IntegerWidth::zeroFillTo(int32_t minInt) { if (minInt >= 0 && minInt <= kMaxIntFracSig) { - return {static_cast(minInt), -1}; + return {static_cast(minInt), -1, false}; } else { return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR}; } @@ -30,22 +31,37 @@ IntegerWidth IntegerWidth::truncateAt(int32_t maxInt) { if (fHasError) { return *this; } // No-op on error digits_t minInt = fUnion.minMaxInt.fMinInt; if (maxInt >= 0 && maxInt <= kMaxIntFracSig && minInt <= maxInt) { - return {minInt, static_cast(maxInt)}; + return {minInt, static_cast(maxInt), false}; } else if (maxInt == -1) { - return {minInt, -1}; + return {minInt, -1, false}; } else { return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR}; } } -void IntegerWidth::apply(impl::DecimalQuantity &quantity, UErrorCode &status) const { +void IntegerWidth::apply(impl::DecimalQuantity& quantity, UErrorCode& status) const { if (fHasError) { status = U_ILLEGAL_ARGUMENT_ERROR; } else if (fUnion.minMaxInt.fMaxInt == -1) { quantity.setIntegerLength(fUnion.minMaxInt.fMinInt, INT32_MAX); } else { + // Enforce the backwards-compatibility feature "FormatFailIfMoreThanMaxDigits" + if (fUnion.minMaxInt.fFormatFailIfMoreThanMaxDigits && + fUnion.minMaxInt.fMaxInt < quantity.getMagnitude()) { + status = U_ILLEGAL_ARGUMENT_ERROR; + } quantity.setIntegerLength(fUnion.minMaxInt.fMinInt, fUnion.minMaxInt.fMaxInt); } } +bool IntegerWidth::operator==(const IntegerWidth& other) const { + // Private operator==; do error and bogus checking first! + U_ASSERT(!fHasError); + U_ASSERT(!other.fHasError); + U_ASSERT(!isBogus()); + U_ASSERT(!other.isBogus()); + return fUnion.minMaxInt.fMinInt == other.fUnion.minMaxInt.fMinInt && + fUnion.minMaxInt.fMaxInt == other.fUnion.minMaxInt.fMaxInt; +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_longnames.cpp b/deps/icu-small/source/i18n/number_longnames.cpp index 5c363442e7..26f9af4c9b 100644 --- a/deps/icu-small/source/i18n/number_longnames.cpp +++ b/deps/icu-small/source/i18n/number_longnames.cpp @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "unicode/simpleformatter.h" #include "unicode/ures.h" @@ -11,6 +11,7 @@ #include "charstr.h" #include "uresimp.h" #include "number_longnames.h" +#include "number_microprops.h" #include #include "cstring.h" @@ -260,8 +261,8 @@ void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &mic parent->processQuantity(quantity, micros, status); // TODO: Avoid the copy here? DecimalQuantity copy(quantity); - micros.rounding.apply(copy, status); - micros.modOuter = &fModifiers[copy.getStandardPlural(rules)]; + micros.rounder.apply(copy, status); + micros.modOuter = &fModifiers[utils::getStandardPlural(rules, copy)]; } #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_longnames.h b/deps/icu-small/source/i18n/number_longnames.h index 8738bb99e7..1d1e7dd3e8 100644 --- a/deps/icu-small/source/i18n/number_longnames.h +++ b/deps/icu-small/source/i18n/number_longnames.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_LONGNAMES_H__ #define __NUMBER_LONGNAMES_H__ diff --git a/deps/icu-small/source/i18n/number_mapper.cpp b/deps/icu-small/source/i18n/number_mapper.cpp new file mode 100644 index 0000000000..d260632f93 --- /dev/null +++ b/deps/icu-small/source/i18n/number_mapper.cpp @@ -0,0 +1,502 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "number_mapper.h" +#include "number_patternstring.h" +#include "unicode/errorcode.h" +#include "number_utils.h" +#include "number_currencysymbols.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + + +UnlocalizedNumberFormatter NumberPropertyMapper::create(const DecimalFormatProperties& properties, + const DecimalFormatSymbols& symbols, + DecimalFormatWarehouse& warehouse, + UErrorCode& status) { + return NumberFormatter::with().macros(oldToNew(properties, symbols, warehouse, nullptr, status)); +} + +UnlocalizedNumberFormatter NumberPropertyMapper::create(const DecimalFormatProperties& properties, + const DecimalFormatSymbols& symbols, + DecimalFormatWarehouse& warehouse, + DecimalFormatProperties& exportedProperties, + UErrorCode& status) { + return NumberFormatter::with().macros( + oldToNew( + properties, symbols, warehouse, &exportedProperties, status)); +} + +MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& properties, + const DecimalFormatSymbols& symbols, + DecimalFormatWarehouse& warehouse, + DecimalFormatProperties* exportedProperties, + UErrorCode& status) { + MacroProps macros; + Locale locale = symbols.getLocale(); + + ///////////// + // SYMBOLS // + ///////////// + + macros.symbols.setTo(symbols); + + ////////////////// + // PLURAL RULES // + ////////////////// + + if (!properties.currencyPluralInfo.fPtr.isNull()) { + macros.rules = properties.currencyPluralInfo.fPtr->getPluralRules(); + } + + ///////////// + // AFFIXES // + ///////////// + + AffixPatternProvider* affixProvider; + if (properties.currencyPluralInfo.fPtr.isNull()) { + warehouse.currencyPluralInfoAPP.setToBogus(); + warehouse.propertiesAPP.setTo(properties, status); + affixProvider = &warehouse.propertiesAPP; + } else { + warehouse.currencyPluralInfoAPP.setTo(*properties.currencyPluralInfo.fPtr, properties, status); + warehouse.propertiesAPP.setToBogus(); + affixProvider = &warehouse.currencyPluralInfoAPP; + } + macros.affixProvider = affixProvider; + + /////////// + // UNITS // + /////////// + + bool useCurrency = ( + !properties.currency.isNull() || !properties.currencyPluralInfo.fPtr.isNull() || + !properties.currencyUsage.isNull() || affixProvider->hasCurrencySign()); + CurrencyUnit currency = resolveCurrency(properties, locale, status); + UCurrencyUsage currencyUsage = properties.currencyUsage.getOrDefault(UCURR_USAGE_STANDARD); + if (useCurrency) { + // NOTE: Slicing is OK. + macros.unit = currency; // NOLINT + } + warehouse.currencySymbols = {currency, locale, symbols, status}; + macros.currencySymbols = &warehouse.currencySymbols; + + /////////////////////// + // ROUNDING STRATEGY // + /////////////////////// + + int32_t maxInt = properties.maximumIntegerDigits; + int32_t minInt = properties.minimumIntegerDigits; + int32_t maxFrac = properties.maximumFractionDigits; + int32_t minFrac = properties.minimumFractionDigits; + int32_t minSig = properties.minimumSignificantDigits; + int32_t maxSig = properties.maximumSignificantDigits; + double roundingIncrement = properties.roundingIncrement; + RoundingMode roundingMode = properties.roundingMode.getOrDefault(UNUM_ROUND_HALFEVEN); + bool explicitMinMaxFrac = minFrac != -1 || maxFrac != -1; + bool explicitMinMaxSig = minSig != -1 || maxSig != -1; + // Resolve min/max frac for currencies, required for the validation logic and for when minFrac or + // maxFrac was + // set (but not both) on a currency instance. + // NOTE: Increments are handled in "Precision.constructCurrency()". + if (useCurrency && (minFrac == -1 || maxFrac == -1)) { + int32_t digits = ucurr_getDefaultFractionDigitsForUsage( + currency.getISOCurrency(), currencyUsage, &status); + if (minFrac == -1 && maxFrac == -1) { + minFrac = digits; + maxFrac = digits; + } else if (minFrac == -1) { + minFrac = std::min(maxFrac, digits); + } else /* if (maxFrac == -1) */ { + maxFrac = std::max(minFrac, digits); + } + } + // Validate min/max int/frac. + // For backwards compatibility, minimum overrides maximum if the two conflict. + // The following logic ensures that there is always a minimum of at least one digit. + if (minInt == 0 && maxFrac != 0) { + // Force a digit after the decimal point. + minFrac = minFrac <= 0 ? 1 : minFrac; + maxFrac = maxFrac < 0 ? -1 : maxFrac < minFrac ? minFrac : maxFrac; + minInt = 0; + maxInt = maxInt < 0 ? -1 : maxInt > kMaxIntFracSig ? -1 : maxInt; + } else { + // Force a digit before the decimal point. + minFrac = minFrac < 0 ? 0 : minFrac; + maxFrac = maxFrac < 0 ? -1 : maxFrac < minFrac ? minFrac : maxFrac; + minInt = minInt <= 0 ? 1 : minInt > kMaxIntFracSig ? 1 : minInt; + maxInt = maxInt < 0 ? -1 : maxInt < minInt ? minInt : maxInt > kMaxIntFracSig ? -1 : maxInt; + } + Precision precision; + if (!properties.currencyUsage.isNull()) { + precision = Precision::constructCurrency(currencyUsage).withCurrency(currency); + } else if (roundingIncrement != 0.0) { + precision = Precision::constructIncrement(roundingIncrement, minFrac); + } else if (explicitMinMaxSig) { + minSig = minSig < 1 ? 1 : minSig > kMaxIntFracSig ? kMaxIntFracSig : minSig; + maxSig = maxSig < 0 ? kMaxIntFracSig : maxSig < minSig ? minSig : maxSig > kMaxIntFracSig + ? kMaxIntFracSig : maxSig; + precision = Precision::constructSignificant(minSig, maxSig); + } else if (explicitMinMaxFrac) { + precision = Precision::constructFraction(minFrac, maxFrac); + } else if (useCurrency) { + precision = Precision::constructCurrency(currencyUsage); + } + if (!precision.isBogus()) { + precision = precision.withMode(roundingMode); + macros.precision = precision; + } + + /////////////////// + // INTEGER WIDTH // + /////////////////// + + macros.integerWidth = IntegerWidth( + static_cast(minInt), + static_cast(maxInt), + properties.formatFailIfMoreThanMaxDigits); + + /////////////////////// + // GROUPING STRATEGY // + /////////////////////// + + macros.grouper = Grouper::forProperties(properties); + + ///////////// + // PADDING // + ///////////// + + if (properties.formatWidth != -1) { + macros.padder = Padder::forProperties(properties); + } + + /////////////////////////////// + // DECIMAL MARK ALWAYS SHOWN // + /////////////////////////////// + + macros.decimal = properties.decimalSeparatorAlwaysShown ? UNUM_DECIMAL_SEPARATOR_ALWAYS + : UNUM_DECIMAL_SEPARATOR_AUTO; + + /////////////////////// + // SIGN ALWAYS SHOWN // + /////////////////////// + + macros.sign = properties.signAlwaysShown ? UNUM_SIGN_ALWAYS : UNUM_SIGN_AUTO; + + ///////////////////////// + // SCIENTIFIC NOTATION // + ///////////////////////// + + if (properties.minimumExponentDigits != -1) { + // Scientific notation is required. + // This whole section feels like a hack, but it is needed for regression tests. + // The mapping from property bag to scientific notation is nontrivial due to LDML rules. + if (maxInt > 8) { + // But #13110: The maximum of 8 digits has unknown origins and is not in the spec. + // If maxInt is greater than 8, it is set to minInt, even if minInt is greater than 8. + maxInt = minInt; + macros.integerWidth = IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt); + } else if (maxInt > minInt && minInt > 1) { + // Bug #13289: if maxInt > minInt > 1, then minInt should be 1. + minInt = 1; + macros.integerWidth = IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt); + } + int engineering = maxInt < 0 ? -1 : maxInt; + macros.notation = ScientificNotation( + // Engineering interval: + static_cast(engineering), + // Enforce minimum integer digits (for patterns like "000.00E0"): + (engineering == minInt), + // Minimum exponent digits: + static_cast(properties.minimumExponentDigits), + // Exponent sign always shown: + properties.exponentSignAlwaysShown ? UNUM_SIGN_ALWAYS : UNUM_SIGN_AUTO); + // Scientific notation also involves overriding the rounding mode. + // TODO: Overriding here is a bit of a hack. Should this logic go earlier? + if (macros.precision.fType == Precision::PrecisionType::RND_FRACTION) { + // For the purposes of rounding, get the original min/max int/frac, since the local + // variables + // have been manipulated for display purposes. + int minInt_ = properties.minimumIntegerDigits; + int minFrac_ = properties.minimumFractionDigits; + int maxFrac_ = properties.maximumFractionDigits; + if (minInt_ == 0 && maxFrac_ == 0) { + // Patterns like "#E0" and "##E0", which mean no rounding! + macros.precision = Precision::unlimited().withMode(roundingMode); + } else if (minInt_ == 0 && minFrac_ == 0) { + // Patterns like "#.##E0" (no zeros in the mantissa), which mean round to maxFrac+1 + macros.precision = Precision::constructSignificant(1, maxFrac_ + 1).withMode(roundingMode); + } else { + // All other scientific patterns, which mean round to minInt+maxFrac + macros.precision = Precision::constructSignificant( + minInt_ + minFrac_, minInt_ + maxFrac_).withMode(roundingMode); + } + } + } + + ////////////////////// + // COMPACT NOTATION // + ////////////////////// + + if (!properties.compactStyle.isNull()) { + if (properties.compactStyle.getNoError() == UNumberCompactStyle::UNUM_LONG) { + macros.notation = Notation::compactLong(); + } else { + macros.notation = Notation::compactShort(); + } + // Do not forward the affix provider. + macros.affixProvider = nullptr; + } + + ///////////////// + // MULTIPLIERS // + ///////////////// + + macros.scale = scaleFromProperties(properties); + + ////////////////////// + // PROPERTY EXPORTS // + ////////////////////// + + if (exportedProperties != nullptr) { + + exportedProperties->currency = currency; + exportedProperties->roundingMode = roundingMode; + exportedProperties->minimumIntegerDigits = minInt; + exportedProperties->maximumIntegerDigits = maxInt == -1 ? INT32_MAX : maxInt; + + Precision rounding_; + if (precision.fType == Precision::PrecisionType::RND_CURRENCY) { + rounding_ = precision.withCurrency(currency, status); + } else { + rounding_ = precision; + } + int minFrac_ = minFrac; + int maxFrac_ = maxFrac; + int minSig_ = minSig; + int maxSig_ = maxSig; + double increment_ = 0.0; + if (rounding_.fType == Precision::PrecisionType::RND_FRACTION) { + minFrac_ = rounding_.fUnion.fracSig.fMinFrac; + maxFrac_ = rounding_.fUnion.fracSig.fMaxFrac; + } else if (rounding_.fType == Precision::PrecisionType::RND_INCREMENT) { + increment_ = rounding_.fUnion.increment.fIncrement; + minFrac_ = rounding_.fUnion.increment.fMinFrac; + maxFrac_ = rounding_.fUnion.increment.fMinFrac; + } else if (rounding_.fType == Precision::PrecisionType::RND_SIGNIFICANT) { + minSig_ = rounding_.fUnion.fracSig.fMinSig; + maxSig_ = rounding_.fUnion.fracSig.fMaxSig; + } + + exportedProperties->minimumFractionDigits = minFrac_; + exportedProperties->maximumFractionDigits = maxFrac_; + exportedProperties->minimumSignificantDigits = minSig_; + exportedProperties->maximumSignificantDigits = maxSig_; + exportedProperties->roundingIncrement = increment_; + } + + return macros; +} + + +void PropertiesAffixPatternProvider::setTo(const DecimalFormatProperties& properties, UErrorCode&) { + fBogus = false; + + // There are two ways to set affixes in DecimalFormat: via the pattern string (applyPattern), and via the + // explicit setters (setPositivePrefix and friends). The way to resolve the settings is as follows: + // + // 1) If the explicit setting is present for the field, use it. + // 2) Otherwise, follows UTS 35 rules based on the pattern string. + // + // Importantly, the explicit setters affect only the one field they override. If you set the positive + // prefix, that should not affect the negative prefix. Since it is impossible for the user of this class + // to know whether the origin for a string was the override or the pattern, we have to say that we always + // have a negative subpattern and perform all resolution logic here. + + // Convenience: Extract the properties into local variables. + // Variables are named with three chars: [p/n][p/s][o/p] + // [p/n] => p for positive, n for negative + // [p/s] => p for prefix, s for suffix + // [o/p] => o for escaped custom override string, p for pattern string + UnicodeString ppo = AffixUtils::escape(properties.positivePrefix); + UnicodeString pso = AffixUtils::escape(properties.positiveSuffix); + UnicodeString npo = AffixUtils::escape(properties.negativePrefix); + UnicodeString nso = AffixUtils::escape(properties.negativeSuffix); + const UnicodeString& ppp = properties.positivePrefixPattern; + const UnicodeString& psp = properties.positiveSuffixPattern; + const UnicodeString& npp = properties.negativePrefixPattern; + const UnicodeString& nsp = properties.negativeSuffixPattern; + + if (!properties.positivePrefix.isBogus()) { + posPrefix = ppo; + } else if (!ppp.isBogus()) { + posPrefix = ppp; + } else { + // UTS 35: Default positive prefix is empty string. + posPrefix = u""; + } + + if (!properties.positiveSuffix.isBogus()) { + posSuffix = pso; + } else if (!psp.isBogus()) { + posSuffix = psp; + } else { + // UTS 35: Default positive suffix is empty string. + posSuffix = u""; + } + + if (!properties.negativePrefix.isBogus()) { + negPrefix = npo; + } else if (!npp.isBogus()) { + negPrefix = npp; + } else { + // UTS 35: Default negative prefix is "-" with positive prefix. + // Important: We prepend the "-" to the pattern, not the override! + negPrefix = ppp.isBogus() ? u"-" : u"-" + ppp; + } + + if (!properties.negativeSuffix.isBogus()) { + negSuffix = nso; + } else if (!nsp.isBogus()) { + negSuffix = nsp; + } else { + // UTS 35: Default negative prefix is the positive prefix. + negSuffix = psp.isBogus() ? u"" : psp; + } +} + +char16_t PropertiesAffixPatternProvider::charAt(int flags, int i) const { + return getStringInternal(flags).charAt(i); +} + +int PropertiesAffixPatternProvider::length(int flags) const { + return getStringInternal(flags).length(); +} + +UnicodeString PropertiesAffixPatternProvider::getString(int32_t flags) const { + return getStringInternal(flags); +} + +const UnicodeString& PropertiesAffixPatternProvider::getStringInternal(int32_t flags) const { + bool prefix = (flags & AFFIX_PREFIX) != 0; + bool negative = (flags & AFFIX_NEGATIVE_SUBPATTERN) != 0; + if (prefix && negative) { + return negPrefix; + } else if (prefix) { + return posPrefix; + } else if (negative) { + return negSuffix; + } else { + return posSuffix; + } +} + +bool PropertiesAffixPatternProvider::positiveHasPlusSign() const { + // TODO: Change the internal APIs to propagate out the error? + ErrorCode localStatus; + return AffixUtils::containsType(posPrefix, TYPE_PLUS_SIGN, localStatus) || + AffixUtils::containsType(posSuffix, TYPE_PLUS_SIGN, localStatus); +} + +bool PropertiesAffixPatternProvider::hasNegativeSubpattern() const { + // See comments in the constructor for more information on why this is always true. + return true; +} + +bool PropertiesAffixPatternProvider::negativeHasMinusSign() const { + ErrorCode localStatus; + return AffixUtils::containsType(negPrefix, TYPE_MINUS_SIGN, localStatus) || + AffixUtils::containsType(negSuffix, TYPE_MINUS_SIGN, localStatus); +} + +bool PropertiesAffixPatternProvider::hasCurrencySign() const { + ErrorCode localStatus; + return AffixUtils::hasCurrencySymbols(posPrefix, localStatus) || + AffixUtils::hasCurrencySymbols(posSuffix, localStatus) || + AffixUtils::hasCurrencySymbols(negPrefix, localStatus) || + AffixUtils::hasCurrencySymbols(negSuffix, localStatus); +} + +bool PropertiesAffixPatternProvider::containsSymbolType(AffixPatternType type, UErrorCode& status) const { + return AffixUtils::containsType(posPrefix, type, status) || + AffixUtils::containsType(posSuffix, type, status) || + AffixUtils::containsType(negPrefix, type, status) || + AffixUtils::containsType(negSuffix, type, status); +} + +bool PropertiesAffixPatternProvider::hasBody() const { + return true; +} + + +void CurrencyPluralInfoAffixProvider::setTo(const CurrencyPluralInfo& cpi, + const DecimalFormatProperties& properties, + UErrorCode& status) { + // We need to use a PropertiesAffixPatternProvider, not the simpler version ParsedPatternInfo, + // because user-specified affix overrides still need to work. + fBogus = false; + DecimalFormatProperties pluralProperties(properties); + for (int32_t plural = 0; plural < StandardPlural::COUNT; plural++) { + const char* keyword = StandardPlural::getKeyword(static_cast(plural)); + UnicodeString patternString; + patternString = cpi.getCurrencyPluralPattern(keyword, patternString); + PatternParser::parseToExistingProperties( + patternString, + pluralProperties, + IGNORE_ROUNDING_NEVER, + status); + affixesByPlural[plural].setTo(pluralProperties, status); + } +} + +char16_t CurrencyPluralInfoAffixProvider::charAt(int32_t flags, int32_t i) const { + int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK); + return affixesByPlural[pluralOrdinal].charAt(flags, i); +} + +int32_t CurrencyPluralInfoAffixProvider::length(int32_t flags) const { + int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK); + return affixesByPlural[pluralOrdinal].length(flags); +} + +UnicodeString CurrencyPluralInfoAffixProvider::getString(int32_t flags) const { + int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK); + return affixesByPlural[pluralOrdinal].getString(flags); +} + +bool CurrencyPluralInfoAffixProvider::positiveHasPlusSign() const { + return affixesByPlural[StandardPlural::OTHER].positiveHasPlusSign(); +} + +bool CurrencyPluralInfoAffixProvider::hasNegativeSubpattern() const { + return affixesByPlural[StandardPlural::OTHER].hasNegativeSubpattern(); +} + +bool CurrencyPluralInfoAffixProvider::negativeHasMinusSign() const { + return affixesByPlural[StandardPlural::OTHER].negativeHasMinusSign(); +} + +bool CurrencyPluralInfoAffixProvider::hasCurrencySign() const { + return affixesByPlural[StandardPlural::OTHER].hasCurrencySign(); +} + +bool CurrencyPluralInfoAffixProvider::containsSymbolType(AffixPatternType type, UErrorCode& status) const { + return affixesByPlural[StandardPlural::OTHER].containsSymbolType(type, status); +} + +bool CurrencyPluralInfoAffixProvider::hasBody() const { + return affixesByPlural[StandardPlural::OTHER].hasBody(); +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_mapper.h b/deps/icu-small/source/i18n/number_mapper.h new file mode 100644 index 0000000000..82c5711c8d --- /dev/null +++ b/deps/icu-small/source/i18n/number_mapper.h @@ -0,0 +1,206 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMBER_MAPPER_H__ +#define __NUMBER_MAPPER_H__ + +#include +#include "number_types.h" +#include "unicode/currpinf.h" +#include "standardplural.h" +#include "number_patternstring.h" +#include "number_currencysymbols.h" +#include "numparse_impl.h" + +U_NAMESPACE_BEGIN +namespace number { +namespace impl { + + +class PropertiesAffixPatternProvider : public AffixPatternProvider, public UMemory { + public: + bool isBogus() const { + return fBogus; + } + + void setToBogus() { + fBogus = true; + } + + void setTo(const DecimalFormatProperties& properties, UErrorCode& status); + + PropertiesAffixPatternProvider() = default; // puts instance in valid but undefined state + + PropertiesAffixPatternProvider(const DecimalFormatProperties& properties, UErrorCode& status) { + setTo(properties, status); + } + + // AffixPatternProvider Methods: + + char16_t charAt(int32_t flags, int32_t i) const U_OVERRIDE; + + int32_t length(int32_t flags) const U_OVERRIDE; + + UnicodeString getString(int32_t flags) const U_OVERRIDE; + + bool hasCurrencySign() const U_OVERRIDE; + + bool positiveHasPlusSign() const U_OVERRIDE; + + bool hasNegativeSubpattern() const U_OVERRIDE; + + bool negativeHasMinusSign() const U_OVERRIDE; + + bool containsSymbolType(AffixPatternType, UErrorCode&) const U_OVERRIDE; + + bool hasBody() const U_OVERRIDE; + + private: + UnicodeString posPrefix; + UnicodeString posSuffix; + UnicodeString negPrefix; + UnicodeString negSuffix; + + const UnicodeString& getStringInternal(int32_t flags) const; + + bool fBogus{true}; +}; + + +class CurrencyPluralInfoAffixProvider : public AffixPatternProvider, public UMemory { + public: + bool isBogus() const { + return fBogus; + } + + void setToBogus() { + fBogus = true; + } + + void setTo(const CurrencyPluralInfo& cpi, const DecimalFormatProperties& properties, + UErrorCode& status); + + // AffixPatternProvider Methods: + + char16_t charAt(int32_t flags, int32_t i) const U_OVERRIDE; + + int32_t length(int32_t flags) const U_OVERRIDE; + + UnicodeString getString(int32_t flags) const U_OVERRIDE; + + bool hasCurrencySign() const U_OVERRIDE; + + bool positiveHasPlusSign() const U_OVERRIDE; + + bool hasNegativeSubpattern() const U_OVERRIDE; + + bool negativeHasMinusSign() const U_OVERRIDE; + + bool containsSymbolType(AffixPatternType, UErrorCode&) const U_OVERRIDE; + + bool hasBody() const U_OVERRIDE; + + private: + PropertiesAffixPatternProvider affixesByPlural[StandardPlural::COUNT]; + + bool fBogus{true}; +}; + + +/** + * A struct for ownership of a few objects needed for formatting. + */ +struct DecimalFormatWarehouse { + PropertiesAffixPatternProvider propertiesAPP; + CurrencyPluralInfoAffixProvider currencyPluralInfoAPP; + CurrencySymbols currencySymbols; +}; + + +/** +* Internal fields for DecimalFormat. +* TODO: Make some of these fields by value instead of by LocalPointer? +*/ +struct DecimalFormatFields : public UMemory { + /** The property bag corresponding to user-specified settings and settings from the pattern string. */ + LocalPointer properties; + + /** The symbols for the current locale. */ + LocalPointer symbols; + + /** + * The pre-computed formatter object. Setters cause this to be re-computed atomically. The {@link + * #format} method uses the formatter directly without needing to synchronize. + */ + LocalPointer formatter; + + /** The lazy-computed parser for .parse() */ + std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicParser = {}; + + /** The lazy-computed parser for .parseCurrency() */ + std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicCurrencyParser = {}; + + /** Small object ownership warehouse for the formatter and parser */ + DecimalFormatWarehouse warehouse; + + /** The effective properties as exported from the formatter object. Used by some getters. */ + LocalPointer exportedProperties; + + // Data for fastpath + bool canUseFastFormat = false; + struct FastFormatData { + char16_t cpZero; + char16_t cpGroupingSeparator; + char16_t cpMinusSign; + int8_t minInt; + int8_t maxInt; + } fastData; +}; + + +/** + * Utilities for converting between a DecimalFormatProperties and a MacroProps. + */ +class NumberPropertyMapper { + public: + /** Convenience method to create a NumberFormatter directly from Properties. */ + static UnlocalizedNumberFormatter create(const DecimalFormatProperties& properties, + const DecimalFormatSymbols& symbols, + DecimalFormatWarehouse& warehouse, UErrorCode& status); + + /** Convenience method to create a NumberFormatter directly from Properties. */ + static UnlocalizedNumberFormatter create(const DecimalFormatProperties& properties, + const DecimalFormatSymbols& symbols, + DecimalFormatWarehouse& warehouse, + DecimalFormatProperties& exportedProperties, + UErrorCode& status); + + /** + * Creates a new {@link MacroProps} object based on the content of a {@link DecimalFormatProperties} + * object. In other words, maps Properties to MacroProps. This function is used by the + * JDK-compatibility API to call into the ICU 60 fluent number formatting pipeline. + * + * @param properties + * The property bag to be mapped. + * @param symbols + * The symbols associated with the property bag. + * @param exportedProperties + * A property bag in which to store validated properties. Used by some DecimalFormat + * getters. + * @return A new MacroProps containing all of the information in the Properties. + */ + static MacroProps oldToNew(const DecimalFormatProperties& properties, + const DecimalFormatSymbols& symbols, DecimalFormatWarehouse& warehouse, + DecimalFormatProperties* exportedProperties, UErrorCode& status); +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMBER_MAPPER_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_microprops.h b/deps/icu-small/source/i18n/number_microprops.h new file mode 100644 index 0000000000..daa887bb0d --- /dev/null +++ b/deps/icu-small/source/i18n/number_microprops.h @@ -0,0 +1,82 @@ +// © 2017 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMBER_MICROPROPS_H__ +#define __NUMBER_MICROPROPS_H__ + +// TODO: minimize includes +#include "unicode/numberformatter.h" +#include "number_types.h" +#include "number_decimalquantity.h" +#include "number_scientific.h" +#include "number_patternstring.h" +#include "number_modifiers.h" +#include "number_multiplier.h" +#include "number_roundingutils.h" +#include "decNumber.h" +#include "charstr.h" + +U_NAMESPACE_BEGIN namespace number { +namespace impl { + +struct MicroProps : public MicroPropsGenerator { + + // NOTE: All of these fields are properly initialized in NumberFormatterImpl. + RoundingImpl rounder; + Grouper grouping; + Padder padding; + IntegerWidth integerWidth; + UNumberSignDisplay sign; + UNumberDecimalSeparatorDisplay decimal; + bool useCurrency; + + // Note: This struct has no direct ownership of the following pointers. + const DecimalFormatSymbols* symbols; + const Modifier* modOuter; + const Modifier* modMiddle; + const Modifier* modInner; + + // The following "helper" fields may optionally be used during the MicroPropsGenerator. + // They live here to retain memory. + struct { + ScientificModifier scientificModifier; + EmptyModifier emptyWeakModifier{false}; + EmptyModifier emptyStrongModifier{true}; + MultiplierFormatHandler multiplier; + } helpers; + + + MicroProps() = default; + + MicroProps(const MicroProps& other) = default; + + MicroProps& operator=(const MicroProps& other) = default; + + void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE { + (void) status; + if (this == µs) { + // Unsafe path: no need to perform a copy. + U_ASSERT(!exhausted); + micros.exhausted = true; + U_ASSERT(exhausted); + } else { + // Safe path: copy self into the output micros. + micros = *this; + } + } + + private: + // Internal fields: + bool exhausted = false; +}; + +} // namespace impl +} // namespace number +U_NAMESPACE_END + +#endif // __NUMBER_MICROPROPS_H__ + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_modifiers.cpp b/deps/icu-small/source/i18n/number_modifiers.cpp index 872b97010d..4385499b54 100644 --- a/deps/icu-small/source/i18n/number_modifiers.cpp +++ b/deps/icu-small/source/i18n/number_modifiers.cpp @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "umutex.h" #include "ucln_cmn.h" @@ -32,6 +32,7 @@ UBool U_CALLCONV cleanupDefaultCurrencySpacing() { UNISET_DIGIT = nullptr; delete UNISET_NOTS; UNISET_NOTS = nullptr; + gDefaultCurrencySpacingInitOnce.reset(); return TRUE; } @@ -50,6 +51,9 @@ void U_CALLCONV initDefaultCurrencySpacing(UErrorCode &status) { } // namespace +Modifier::~Modifier() = default; + + int32_t ConstantAffixModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex, UErrorCode &status) const { // Insert the suffix first since inserting the prefix will change the rightIndex diff --git a/deps/icu-small/source/i18n/number_modifiers.h b/deps/icu-small/source/i18n/number_modifiers.h index 4762a6f6d3..a553100cd9 100644 --- a/deps/icu-small/source/i18n/number_modifiers.h +++ b/deps/icu-small/source/i18n/number_modifiers.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_MODIFIERS_H__ #define __NUMBER_MODIFIERS_H__ diff --git a/deps/icu-small/source/i18n/number_multiplier.cpp b/deps/icu-small/source/i18n/number_multiplier.cpp new file mode 100644 index 0000000000..a27142c9bd --- /dev/null +++ b/deps/icu-small/source/i18n/number_multiplier.cpp @@ -0,0 +1,156 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "number_decnum.h" +#include "number_types.h" +#include "number_multiplier.h" +#include "numparse_validators.h" +#include "number_utils.h" +#include "decNumber.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; +using namespace icu::numparse::impl; + + +Scale::Scale(int32_t magnitude, DecNum* arbitraryToAdopt) + : fMagnitude(magnitude), fArbitrary(arbitraryToAdopt), fError(U_ZERO_ERROR) { + if (fArbitrary != nullptr) { + // Attempt to convert the DecNum to a magnitude multiplier. + fArbitrary->normalize(); + if (fArbitrary->getRawDecNumber()->digits == 1 && fArbitrary->getRawDecNumber()->lsu[0] == 1 && + !fArbitrary->isNegative()) { + // Success! + fMagnitude += fArbitrary->getRawDecNumber()->exponent; + delete fArbitrary; + fArbitrary = nullptr; + } + } +} + +Scale::Scale(const Scale& other) + : fMagnitude(other.fMagnitude), fArbitrary(nullptr), fError(other.fError) { + if (other.fArbitrary != nullptr) { + UErrorCode localStatus = U_ZERO_ERROR; + fArbitrary = new DecNum(*other.fArbitrary, localStatus); + } +} + +Scale& Scale::operator=(const Scale& other) { + fMagnitude = other.fMagnitude; + if (other.fArbitrary != nullptr) { + UErrorCode localStatus = U_ZERO_ERROR; + fArbitrary = new DecNum(*other.fArbitrary, localStatus); + } else { + fArbitrary = nullptr; + } + fError = other.fError; + return *this; +} + +Scale::Scale(Scale&& src) U_NOEXCEPT + : fMagnitude(src.fMagnitude), fArbitrary(src.fArbitrary), fError(src.fError) { + // Take ownership away from src if necessary + src.fArbitrary = nullptr; +} + +Scale& Scale::operator=(Scale&& src) U_NOEXCEPT { + fMagnitude = src.fMagnitude; + fArbitrary = src.fArbitrary; + fError = src.fError; + // Take ownership away from src if necessary + src.fArbitrary = nullptr; + return *this; +} + +Scale::~Scale() { + delete fArbitrary; +} + + +Scale Scale::none() { + return {0, nullptr}; +} + +Scale Scale::powerOfTen(int32_t power) { + return {power, nullptr}; +} + +Scale Scale::byDecimal(StringPiece multiplicand) { + UErrorCode localError = U_ZERO_ERROR; + LocalPointer decnum(new DecNum(), localError); + if (U_FAILURE(localError)) { + return {localError}; + } + decnum->setTo(multiplicand, localError); + if (U_FAILURE(localError)) { + return {localError}; + } + return {0, decnum.orphan()}; +} + +Scale Scale::byDouble(double multiplicand) { + UErrorCode localError = U_ZERO_ERROR; + LocalPointer decnum(new DecNum(), localError); + if (U_FAILURE(localError)) { + return {localError}; + } + decnum->setTo(multiplicand, localError); + if (U_FAILURE(localError)) { + return {localError}; + } + return {0, decnum.orphan()}; +} + +Scale Scale::byDoubleAndPowerOfTen(double multiplicand, int32_t power) { + UErrorCode localError = U_ZERO_ERROR; + LocalPointer decnum(new DecNum(), localError); + if (U_FAILURE(localError)) { + return {localError}; + } + decnum->setTo(multiplicand, localError); + if (U_FAILURE(localError)) { + return {localError}; + } + return {power, decnum.orphan()}; +} + +void Scale::applyTo(impl::DecimalQuantity& quantity) const { + quantity.adjustMagnitude(fMagnitude); + if (fArbitrary != nullptr) { + UErrorCode localStatus = U_ZERO_ERROR; + quantity.multiplyBy(*fArbitrary, localStatus); + } +} + +void Scale::applyReciprocalTo(impl::DecimalQuantity& quantity) const { + quantity.adjustMagnitude(-fMagnitude); + if (fArbitrary != nullptr) { + UErrorCode localStatus = U_ZERO_ERROR; + quantity.divideBy(*fArbitrary, localStatus); + } +} + + +void +MultiplierFormatHandler::setAndChain(const Scale& multiplier, const MicroPropsGenerator* parent) { + this->multiplier = multiplier; + this->parent = parent; +} + +void MultiplierFormatHandler::processQuantity(DecimalQuantity& quantity, MicroProps& micros, + UErrorCode& status) const { + parent->processQuantity(quantity, micros, status); + multiplier.applyTo(quantity); +} + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_multiplier.h b/deps/icu-small/source/i18n/number_multiplier.h new file mode 100644 index 0000000000..82c30c7842 --- /dev/null +++ b/deps/icu-small/source/i18n/number_multiplier.h @@ -0,0 +1,57 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __SOURCE_NUMBER_MULTIPLIER_H__ +#define __SOURCE_NUMBER_MULTIPLIER_H__ + +#include "numparse_types.h" +#include "number_decimfmtprops.h" + +U_NAMESPACE_BEGIN namespace number { +namespace impl { + + +/** + * Wraps a {@link Multiplier} for use in the number formatting pipeline. + */ +// Exported as U_I18N_API for tests +class U_I18N_API MultiplierFormatHandler : public MicroPropsGenerator, public UMemory { + public: + MultiplierFormatHandler() = default; // WARNING: Leaves object in an unusable state; call setAndChain() + + void setAndChain(const Scale& multiplier, const MicroPropsGenerator* parent); + + void processQuantity(DecimalQuantity& quantity, MicroProps& micros, + UErrorCode& status) const U_OVERRIDE; + + private: + Scale multiplier; + const MicroPropsGenerator *parent; +}; + + +/** Gets a Scale from a DecimalFormatProperties. In Java, defined in RoundingUtils.java */ +static inline Scale scaleFromProperties(const DecimalFormatProperties& properties) { + int32_t magnitudeMultiplier = properties.magnitudeMultiplier + properties.multiplierScale; + int32_t arbitraryMultiplier = properties.multiplier; + if (magnitudeMultiplier != 0 && arbitraryMultiplier != 1) { + return Scale::byDoubleAndPowerOfTen(arbitraryMultiplier, magnitudeMultiplier); + } else if (magnitudeMultiplier != 0) { + return Scale::powerOfTen(magnitudeMultiplier); + } else if (arbitraryMultiplier != 1) { + return Scale::byDouble(arbitraryMultiplier); + } else { + return Scale::none(); + } +} + + +} // namespace impl +} // namespace number +U_NAMESPACE_END + +#endif //__SOURCE_NUMBER_MULTIPLIER_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_notation.cpp b/deps/icu-small/source/i18n/number_notation.cpp index f4ad333354..b3cabb57a5 100644 --- a/deps/icu-small/source/i18n/number_notation.cpp +++ b/deps/icu-small/source/i18n/number_notation.cpp @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "unicode/numberformatter.h" #include "number_types.h" @@ -36,6 +36,19 @@ ScientificNotation Notation::engineering() { return {NTN_SCIENTIFIC, union_}; } +ScientificNotation::ScientificNotation(int8_t fEngineeringInterval, bool fRequireMinInt, + impl::digits_t fMinExponentDigits, + UNumberSignDisplay fExponentSignDisplay) { + ScientificSettings settings; + settings.fEngineeringInterval = fEngineeringInterval; + settings.fRequireMinInt = fRequireMinInt; + settings.fMinExponentDigits = fMinExponentDigits; + settings.fExponentSignDisplay = fExponentSignDisplay; + NotationUnion union_; + union_.scientific = settings; + *this = {NTN_SCIENTIFIC, union_}; +} + Notation Notation::compactShort() { NotationUnion union_; union_.compactStyle = CompactStyle::UNUM_SHORT; diff --git a/deps/icu-small/source/i18n/number_padding.cpp b/deps/icu-small/source/i18n/number_padding.cpp index b1db3490cd..97e7b6014f 100644 --- a/deps/icu-small/source/i18n/number_padding.cpp +++ b/deps/icu-small/source/i18n/number_padding.cpp @@ -3,11 +3,12 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "unicode/numberformatter.h" #include "number_types.h" #include "number_stringbuilder.h" +#include "number_decimfmtprops.h" using namespace icu; using namespace icu::number; @@ -28,6 +29,7 @@ addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, NumberStringBuilder } Padder::Padder(UChar32 cp, int32_t width, UNumberFormatPadPosition position) : fWidth(width) { + // TODO(13034): Consider making this a string instead of code point. fUnion.padding.fCp = cp; fUnion.padding.fPosition = position; } @@ -47,6 +49,16 @@ Padder Padder::codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosit } } +Padder Padder::forProperties(const DecimalFormatProperties& properties) { + UChar32 padCp; + if (properties.padString.length() > 0) { + padCp = properties.padString.char32At(0); + } else { + padCp = kFallbackPaddingString[0]; + } + return {padCp, properties.formatWidth, properties.padPosition.getOrDefault(UNUM_PAD_BEFORE_PREFIX)}; +} + int32_t Padder::padAndApply(const Modifier &mod1, const Modifier &mod2, NumberStringBuilder &string, int32_t leftIndex, int32_t rightIndex, UErrorCode &status) const { diff --git a/deps/icu-small/source/i18n/number_patternmodifier.cpp b/deps/icu-small/source/i18n/number_patternmodifier.cpp index e182104c91..6417e14378 100644 --- a/deps/icu-small/source/i18n/number_patternmodifier.cpp +++ b/deps/icu-small/source/i18n/number_patternmodifier.cpp @@ -3,21 +3,27 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "cstring.h" #include "number_patternmodifier.h" #include "unicode/dcfmtsym.h" #include "unicode/ucurr.h" #include "unicode/unistr.h" +#include "number_microprops.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; -MutablePatternModifier::MutablePatternModifier(bool isStrong) : fStrong(isStrong) {} -void MutablePatternModifier::setPatternInfo(const AffixPatternProvider *patternInfo) { +AffixPatternProvider::~AffixPatternProvider() = default; + + +MutablePatternModifier::MutablePatternModifier(bool isStrong) + : fStrong(isStrong) {} + +void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo) { this->patternInfo = patternInfo; } @@ -26,14 +32,12 @@ void MutablePatternModifier::setPatternAttributes(UNumberSignDisplay signDisplay this->perMilleReplacesPercent = perMille; } -void -MutablePatternModifier::setSymbols(const DecimalFormatSymbols *symbols, const CurrencyUnit ¤cy, - const UNumberUnitWidth unitWidth, const PluralRules *rules) { +void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols, + const CurrencySymbols* currencySymbols, + const UNumberUnitWidth unitWidth, const PluralRules* rules) { U_ASSERT((rules != nullptr) == needsPlurals()); this->symbols = symbols; - uprv_memcpy(static_cast(this->currencyCode), - currency.getISOCurrency(), - sizeof(char16_t) * 4); + this->currencySymbols = currencySymbols; this->unitWidth = unitWidth; this->rules = rules; } @@ -49,12 +53,12 @@ bool MutablePatternModifier::needsPlurals() const { // Silently ignore any error codes. } -ImmutablePatternModifier *MutablePatternModifier::createImmutable(UErrorCode &status) { +ImmutablePatternModifier* MutablePatternModifier::createImmutable(UErrorCode& status) { return createImmutableAndChain(nullptr, status); } -ImmutablePatternModifier * -MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator *parent, UErrorCode &status) { +ImmutablePatternModifier* +MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator* parent, UErrorCode& status) { // TODO: Move StandardPlural VALUES to standardplural.h static const StandardPlural::Form STANDARD_PLURAL_VALUES[] = { @@ -89,11 +93,11 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator *paren } else { // Faster path when plural keyword is not needed. setNumberProperties(1, StandardPlural::Form::COUNT); - Modifier *positive = createConstantModifier(status); + Modifier* positive = createConstantModifier(status); setNumberProperties(0, StandardPlural::Form::COUNT); - Modifier *zero = createConstantModifier(status); + Modifier* zero = createConstantModifier(status); setNumberProperties(-1, StandardPlural::Form::COUNT); - Modifier *negative = createConstantModifier(status); + Modifier* negative = createConstantModifier(status); pm->adoptPositiveNegativeModifiers(positive, zero, negative); if (U_FAILURE(status)) { delete pm; @@ -103,77 +107,91 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator *paren } } -ConstantMultiFieldModifier *MutablePatternModifier::createConstantModifier(UErrorCode &status) { +ConstantMultiFieldModifier* MutablePatternModifier::createConstantModifier(UErrorCode& status) { NumberStringBuilder a; NumberStringBuilder b; insertPrefix(a, 0, status); insertSuffix(b, 0, status); if (patternInfo->hasCurrencySign()) { - return new CurrencySpacingEnabledModifier(a, b, !patternInfo->hasBody(), fStrong, *symbols, status); + return new CurrencySpacingEnabledModifier( + a, b, !patternInfo->hasBody(), fStrong, *symbols, status); } else { return new ConstantMultiFieldModifier(a, b, !patternInfo->hasBody(), fStrong); } } -ImmutablePatternModifier::ImmutablePatternModifier(ParameterizedModifier *pm, const PluralRules *rules, - const MicroPropsGenerator *parent) +ImmutablePatternModifier::ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules, + const MicroPropsGenerator* parent) : pm(pm), rules(rules), parent(parent) {} -void ImmutablePatternModifier::processQuantity(DecimalQuantity &quantity, MicroProps µs, - UErrorCode &status) const { +void ImmutablePatternModifier::processQuantity(DecimalQuantity& quantity, MicroProps& micros, + UErrorCode& status) const { parent->processQuantity(quantity, micros, status); applyToMicros(micros, quantity); } -void ImmutablePatternModifier::applyToMicros(MicroProps µs, DecimalQuantity &quantity) const { +void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity& quantity) const { if (rules == nullptr) { micros.modMiddle = pm->getModifier(quantity.signum()); } else { // TODO: Fix this. Avoid the copy. DecimalQuantity copy(quantity); copy.roundToInfinity(); - StandardPlural::Form plural = copy.getStandardPlural(rules); + StandardPlural::Form plural = utils::getStandardPlural(rules, copy); micros.modMiddle = pm->getModifier(quantity.signum(), plural); } } +const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlural::Form plural) const { + if (rules == nullptr) { + return pm->getModifier(signum); + } else { + return pm->getModifier(signum, plural); + } +} + + /** Used by the unsafe code path. */ -MicroPropsGenerator &MutablePatternModifier::addToChain(const MicroPropsGenerator *parent) { +MicroPropsGenerator& MutablePatternModifier::addToChain(const MicroPropsGenerator* parent) { this->parent = parent; return *this; } -void MutablePatternModifier::processQuantity(DecimalQuantity &fq, MicroProps µs, - UErrorCode &status) const { +void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& micros, + UErrorCode& status) const { parent->processQuantity(fq, micros, status); // The unsafe code path performs self-mutation, so we need a const_cast. // This method needs to be const because it overrides a const method in the parent class. - auto nonConstThis = const_cast(this); + auto nonConstThis = const_cast(this); if (needsPlurals()) { // TODO: Fix this. Avoid the copy. DecimalQuantity copy(fq); - micros.rounding.apply(copy, status); - nonConstThis->setNumberProperties(fq.signum(), copy.getStandardPlural(rules)); + micros.rounder.apply(copy, status); + nonConstThis->setNumberProperties(fq.signum(), utils::getStandardPlural(rules, copy)); } else { nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT); } micros.modMiddle = this; } -int32_t MutablePatternModifier::apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, - UErrorCode &status) const { +int32_t MutablePatternModifier::apply(NumberStringBuilder& output, int32_t leftIndex, int32_t rightIndex, + UErrorCode& status) const { // The unsafe code path performs self-mutation, so we need a const_cast. // This method needs to be const because it overrides a const method in the parent class. - auto nonConstThis = const_cast(this); + auto nonConstThis = const_cast(this); int32_t prefixLen = nonConstThis->insertPrefix(output, leftIndex, status); int32_t suffixLen = nonConstThis->insertSuffix(output, rightIndex + prefixLen, status); // If the pattern had no decimal stem body (like #,##0.00), overwrite the value. int32_t overwriteLen = 0; if (!patternInfo->hasBody()) { overwriteLen = output.splice( - leftIndex + prefixLen, rightIndex + prefixLen, - UnicodeString(), 0, 0, UNUM_FIELD_COUNT, - status); + leftIndex + prefixLen, + rightIndex + prefixLen, + UnicodeString(), + 0, + 0, + UNUM_FIELD_COUNT, + status); } CurrencySpacingEnabledModifier::applyCurrencySpacing( output, @@ -186,30 +204,27 @@ int32_t MutablePatternModifier::apply(NumberStringBuilder &output, int32_t leftI return prefixLen + overwriteLen + suffixLen; } -int32_t MutablePatternModifier::getPrefixLength(UErrorCode &status) const { +int32_t MutablePatternModifier::getPrefixLength(UErrorCode& status) const { // The unsafe code path performs self-mutation, so we need a const_cast. // This method needs to be const because it overrides a const method in the parent class. - auto nonConstThis = const_cast(this); + auto nonConstThis = const_cast(this); // Enter and exit CharSequence Mode to get the length. - nonConstThis->enterCharSequenceMode(true); - int result = AffixUtils::unescapedCodePointCount(*this, *this, status); // prefix length - nonConstThis->exitCharSequenceMode(); + nonConstThis->prepareAffix(true); + int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // prefix length return result; } -int32_t MutablePatternModifier::getCodePointCount(UErrorCode &status) const { +int32_t MutablePatternModifier::getCodePointCount(UErrorCode& status) const { // The unsafe code path performs self-mutation, so we need a const_cast. // This method needs to be const because it overrides a const method in the parent class. - auto nonConstThis = const_cast(this); + auto nonConstThis = const_cast(this); - // Enter and exit CharSequence Mode to get the length. - nonConstThis->enterCharSequenceMode(true); - int result = AffixUtils::unescapedCodePointCount(*this, *this, status); // prefix length - nonConstThis->exitCharSequenceMode(); - nonConstThis->enterCharSequenceMode(false); - result += AffixUtils::unescapedCodePointCount(*this, *this, status); // suffix length - nonConstThis->exitCharSequenceMode(); + // Render the affixes to get the length + nonConstThis->prepareAffix(true); + int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // prefix length + nonConstThis->prepareAffix(false); + result += AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // suffix length return result; } @@ -217,21 +232,26 @@ bool MutablePatternModifier::isStrong() const { return fStrong; } -int32_t MutablePatternModifier::insertPrefix(NumberStringBuilder &sb, int position, UErrorCode &status) { - enterCharSequenceMode(true); - int length = AffixUtils::unescape(*this, sb, position, *this, status); - exitCharSequenceMode(); +int32_t MutablePatternModifier::insertPrefix(NumberStringBuilder& sb, int position, UErrorCode& status) { + prepareAffix(true); + int length = AffixUtils::unescape(currentAffix, sb, position, *this, status); return length; } -int32_t MutablePatternModifier::insertSuffix(NumberStringBuilder &sb, int position, UErrorCode &status) { - enterCharSequenceMode(false); - int length = AffixUtils::unescape(*this, sb, position, *this, status); - exitCharSequenceMode(); +int32_t MutablePatternModifier::insertSuffix(NumberStringBuilder& sb, int position, UErrorCode& status) { + prepareAffix(false); + int length = AffixUtils::unescape(currentAffix, sb, position, *this, status); return length; } +/** This method contains the heart of the logic for rendering LDML affix strings. */ +void MutablePatternModifier::prepareAffix(bool isPrefix) { + PatternStringUtils::patternInfoToStringBuilder( + *patternInfo, isPrefix, signum, signDisplay, plural, perMilleReplacesPercent, currentAffix); +} + UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const { + UErrorCode localStatus = U_ZERO_ERROR; switch (type) { case AffixPatternType::TYPE_MINUS_SIGN: return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol); @@ -244,45 +264,23 @@ UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const { case AffixPatternType::TYPE_CURRENCY_SINGLE: { // UnitWidth ISO and HIDDEN overrides the singular currency symbol. if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) { - return UnicodeString(currencyCode, 3); + return currencySymbols->getIntlCurrencySymbol(localStatus); } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) { return UnicodeString(); + } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) { + return currencySymbols->getNarrowCurrencySymbol(localStatus); } else { - UCurrNameStyle selector = (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) - ? UCurrNameStyle::UCURR_NARROW_SYMBOL_NAME - : UCurrNameStyle::UCURR_SYMBOL_NAME; - UErrorCode status = U_ZERO_ERROR; - UBool isChoiceFormat = FALSE; - int32_t symbolLen = 0; - const char16_t *symbol = ucurr_getName( - currencyCode, - symbols->getLocale().getName(), - selector, - &isChoiceFormat, - &symbolLen, - &status); - return UnicodeString(symbol, symbolLen); + return currencySymbols->getCurrencySymbol(localStatus); } } case AffixPatternType::TYPE_CURRENCY_DOUBLE: - return UnicodeString(currencyCode, 3); - case AffixPatternType::TYPE_CURRENCY_TRIPLE: { + return currencySymbols->getIntlCurrencySymbol(localStatus); + case AffixPatternType::TYPE_CURRENCY_TRIPLE: // NOTE: This is the code path only for patterns containing "¤¤¤". // Plural currencies set via the API are formatted in LongNameHandler. // This code path is used by DecimalFormat via CurrencyPluralInfo. U_ASSERT(plural != StandardPlural::Form::COUNT); - UErrorCode status = U_ZERO_ERROR; - UBool isChoiceFormat = FALSE; - int32_t symbolLen = 0; - const char16_t *symbol = ucurr_getPluralName( - currencyCode, - symbols->getLocale().getName(), - &isChoiceFormat, - StandardPlural::getKeyword(plural), - &symbolLen, - &status); - return UnicodeString(symbol, symbolLen); - } + return currencySymbols->getPluralName(plural, localStatus); case AffixPatternType::TYPE_CURRENCY_QUAD: return UnicodeString(u"\uFFFD"); case AffixPatternType::TYPE_CURRENCY_QUINT: @@ -293,79 +291,6 @@ UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const { } } -/** This method contains the heart of the logic for rendering LDML affix strings. */ -void MutablePatternModifier::enterCharSequenceMode(bool isPrefix) { - U_ASSERT(!inCharSequenceMode); - inCharSequenceMode = true; - - // Should the output render '+' where '-' would normally appear in the pattern? - plusReplacesMinusSign = signum != -1 - && (signDisplay == UNUM_SIGN_ALWAYS - || signDisplay == UNUM_SIGN_ACCOUNTING_ALWAYS - || (signum == 1 - && (signDisplay == UNUM_SIGN_EXCEPT_ZERO - || signDisplay == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO))) - && patternInfo->positiveHasPlusSign() == false; - - // Should we use the affix from the negative subpattern? (If not, we will use the positive subpattern.) - bool useNegativeAffixPattern = patternInfo->hasNegativeSubpattern() && ( - signum == -1 || (patternInfo->negativeHasMinusSign() && plusReplacesMinusSign)); - - // Resolve the flags for the affix pattern. - fFlags = 0; - if (useNegativeAffixPattern) { - fFlags |= AffixPatternProvider::AFFIX_NEGATIVE_SUBPATTERN; - } - if (isPrefix) { - fFlags |= AffixPatternProvider::AFFIX_PREFIX; - } - if (plural != StandardPlural::Form::COUNT) { - U_ASSERT(plural == (AffixPatternProvider::AFFIX_PLURAL_MASK & plural)); - fFlags |= plural; - } - - // Should we prepend a sign to the pattern? - if (!isPrefix || useNegativeAffixPattern) { - prependSign = false; - } else if (signum == -1) { - prependSign = signDisplay != UNUM_SIGN_NEVER; - } else { - prependSign = plusReplacesMinusSign; - } - - // Finally, compute the length of the affix pattern. - fLength = patternInfo->length(fFlags) + (prependSign ? 1 : 0); -} - -void MutablePatternModifier::exitCharSequenceMode() { - U_ASSERT(inCharSequenceMode); - inCharSequenceMode = false; -} - -int32_t MutablePatternModifier::length() const { - U_ASSERT(inCharSequenceMode); - return fLength; -} - -char16_t MutablePatternModifier::charAt(int32_t index) const { - U_ASSERT(inCharSequenceMode); - char16_t candidate; - if (prependSign && index == 0) { - candidate = u'-'; - } else if (prependSign) { - candidate = patternInfo->charAt(fFlags, index - 1); - } else { - candidate = patternInfo->charAt(fFlags, index); - } - if (plusReplacesMinusSign && candidate == u'-') { - return u'+'; - } - if (perMilleReplacesPercent && candidate == u'%') { - return u'‰'; - } - return candidate; -} - UnicodeString MutablePatternModifier::toUnicodeString() const { // Never called by AffixUtils U_ASSERT(false); diff --git a/deps/icu-small/source/i18n/number_patternmodifier.h b/deps/icu-small/source/i18n/number_patternmodifier.h index 9c8b95f776..f1359bd574 100644 --- a/deps/icu-small/source/i18n/number_patternmodifier.h +++ b/deps/icu-small/source/i18n/number_patternmodifier.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_PATTERNMODIFIER_H__ #define __NUMBER_PATTERNMODIFIER_H__ @@ -13,6 +13,7 @@ #include "number_types.h" #include "number_modifiers.h" #include "number_utils.h" +#include "number_currencysymbols.h" U_NAMESPACE_BEGIN @@ -35,20 +36,23 @@ class MutablePatternModifier; // Exported as U_I18N_API because it is needed for the unit test PatternModifierTest class U_I18N_API ImmutablePatternModifier : public MicroPropsGenerator, public UMemory { public: - ~ImmutablePatternModifier() U_OVERRIDE = default; + ~ImmutablePatternModifier() U_OVERRIDE = default; - void processQuantity(DecimalQuantity &, MicroProps µs, UErrorCode &status) const U_OVERRIDE; + void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE; + + void applyToMicros(MicroProps& micros, DecimalQuantity& quantity) const; - void applyToMicros(MicroProps µs, DecimalQuantity &quantity) const; + const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const; private: - ImmutablePatternModifier(ParameterizedModifier *pm, const PluralRules *rules, const MicroPropsGenerator *parent); + ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules, + const MicroPropsGenerator* parent); const LocalPointer pm; - const PluralRules *rules; - const MicroPropsGenerator *parent; + const PluralRules* rules; + const MicroPropsGenerator* parent; - friend class MutablePatternModifier; + friend class MutablePatternModifier; }; /** @@ -74,7 +78,6 @@ class U_I18N_API MutablePatternModifier : public MicroPropsGenerator, public Modifier, public SymbolProvider, - public CharSequence, public UMemory { public: @@ -110,17 +113,16 @@ class U_I18N_API MutablePatternModifier * * @param symbols * The desired instance of DecimalFormatSymbols. - * @param currency - * The currency to be used when substituting currency values into the affixes. + * @param currencySymbols + * The currency symbols to be used when substituting currency values into the affixes. * @param unitWidth * The width used to render currencies. * @param rules * Required if the triple currency sign, "¤¤¤", appears in the pattern, which can be determined from the * convenience method {@link #needsPlurals()}. */ - void - setSymbols(const DecimalFormatSymbols *symbols, const CurrencyUnit ¤cy, UNumberUnitWidth unitWidth, - const PluralRules *rules); + void setSymbols(const DecimalFormatSymbols* symbols, const CurrencySymbols* currencySymbols, + UNumberUnitWidth unitWidth, const PluralRules* rules); /** * Sets attributes of the current number being processed. @@ -187,13 +189,7 @@ class U_I18N_API MutablePatternModifier */ UnicodeString getSymbol(AffixPatternType type) const U_OVERRIDE; - int32_t length() const U_OVERRIDE; - - char16_t charAt(int32_t index) const U_OVERRIDE; - - // Use default implementation of codePointAt - - UnicodeString toUnicodeString() const U_OVERRIDE; + UnicodeString toUnicodeString() const; private: // Modifier details (initialized in constructor) @@ -207,7 +203,7 @@ class U_I18N_API MutablePatternModifier // Symbol details (initialized in setSymbols) const DecimalFormatSymbols *symbols; UNumberUnitWidth unitWidth; - char16_t currencyCode[4]; + const CurrencySymbols *currencySymbols; const PluralRules *rules; // Number details (initialized in setNumberProperties) @@ -217,12 +213,8 @@ class U_I18N_API MutablePatternModifier // QuantityChain details (initialized in addToChain) const MicroPropsGenerator *parent; - // Transient CharSequence fields (initialized in enterCharSequenceMode) - bool inCharSequenceMode = false; - int32_t fFlags; - int32_t fLength; - bool prependSign; - bool plusReplacesMinusSign; + // Transient fields for rendering + UnicodeString currentAffix; /** * Uses the current properties to create a single {@link ConstantMultiFieldModifier} with currency spacing support @@ -244,9 +236,7 @@ class U_I18N_API MutablePatternModifier int32_t insertSuffix(NumberStringBuilder &sb, int position, UErrorCode &status); - void enterCharSequenceMode(bool isPrefix); - - void exitCharSequenceMode(); + void prepareAffix(bool isPrefix); }; diff --git a/deps/icu-small/source/i18n/number_patternstring.cpp b/deps/icu-small/source/i18n/number_patternstring.cpp index 20178824b0..63195eed98 100644 --- a/deps/icu-small/source/i18n/number_patternstring.cpp +++ b/deps/icu-small/source/i18n/number_patternstring.cpp @@ -3,36 +3,51 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT +#define UNISTR_FROM_CHAR_EXPLICIT #include "uassert.h" #include "number_patternstring.h" #include "unicode/utf16.h" #include "number_utils.h" +#include "number_roundingutils.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; -void PatternParser::parseToPatternInfo(const UnicodeString& patternString, ParsedPatternInfo& patternInfo, UErrorCode &status) { + +void PatternParser::parseToPatternInfo(const UnicodeString& patternString, ParsedPatternInfo& patternInfo, + UErrorCode& status) { patternInfo.consumePattern(patternString, status); } DecimalFormatProperties PatternParser::parseToProperties(const UnicodeString& pattern, IgnoreRounding ignoreRounding, - UErrorCode &status) { + UErrorCode& status) { DecimalFormatProperties properties; parseToExistingPropertiesImpl(pattern, properties, ignoreRounding, status); return properties; } -void PatternParser::parseToExistingProperties(const UnicodeString& pattern, DecimalFormatProperties& properties, - IgnoreRounding ignoreRounding, UErrorCode &status) { +DecimalFormatProperties PatternParser::parseToProperties(const UnicodeString& pattern, + UErrorCode& status) { + return parseToProperties(pattern, IGNORE_ROUNDING_NEVER, status); +} + +void +PatternParser::parseToExistingProperties(const UnicodeString& pattern, DecimalFormatProperties& properties, + IgnoreRounding ignoreRounding, UErrorCode& status) { parseToExistingPropertiesImpl(pattern, properties, ignoreRounding, status); } + char16_t ParsedPatternInfo::charAt(int32_t flags, int32_t index) const { - const Endpoints &endpoints = getEndpoints(flags); + const Endpoints& endpoints = getEndpoints(flags); if (index < 0 || index >= endpoints.end - endpoints.start) { U_ASSERT(false); } @@ -43,12 +58,12 @@ int32_t ParsedPatternInfo::length(int32_t flags) const { return getLengthFromEndpoints(getEndpoints(flags)); } -int32_t ParsedPatternInfo::getLengthFromEndpoints(const Endpoints &endpoints) { +int32_t ParsedPatternInfo::getLengthFromEndpoints(const Endpoints& endpoints) { return endpoints.end - endpoints.start; } UnicodeString ParsedPatternInfo::getString(int32_t flags) const { - const Endpoints &endpoints = getEndpoints(flags); + const Endpoints& endpoints = getEndpoints(flags); if (endpoints.start == endpoints.end) { return UnicodeString(); } @@ -56,7 +71,7 @@ UnicodeString ParsedPatternInfo::getString(int32_t flags) const { return UnicodeString(pattern, endpoints.start, endpoints.end - endpoints.start); } -const Endpoints &ParsedPatternInfo::getEndpoints(int32_t flags) const { +const Endpoints& ParsedPatternInfo::getEndpoints(int32_t flags) const { bool prefix = (flags & AFFIX_PREFIX) != 0; bool isNegative = (flags & AFFIX_NEGATIVE_SUBPATTERN) != 0; bool padding = (flags & AFFIX_PADDING) != 0; @@ -91,8 +106,8 @@ bool ParsedPatternInfo::hasCurrencySign() const { return positive.hasCurrencySign || (fHasNegativeSubpattern && negative.hasCurrencySign); } -bool ParsedPatternInfo::containsSymbolType(AffixPatternType type, UErrorCode &status) const { - return AffixUtils::containsType(UnicodeStringCharSequence(pattern), type, status); +bool ParsedPatternInfo::containsSymbolType(AffixPatternType type, UErrorCode& status) const { + return AffixUtils::containsType(pattern, type, status); } bool ParsedPatternInfo::hasBody() const { @@ -117,10 +132,14 @@ UChar32 ParsedPatternInfo::ParserState::next() { return codePoint; } -void ParsedPatternInfo::consumePattern(const UnicodeString& patternString, UErrorCode &status) { +void ParsedPatternInfo::consumePattern(const UnicodeString& patternString, UErrorCode& status) { if (U_FAILURE(status)) { return; } this->pattern = patternString; + // This class is not intended for writing twice! + // Use move assignment to overwrite instead. + U_ASSERT(state.offset == 0); + // pattern := subpattern (';' subpattern)? currentSubpattern = &positive; consumeSubpattern(status); @@ -141,7 +160,7 @@ void ParsedPatternInfo::consumePattern(const UnicodeString& patternString, UErro } } -void ParsedPatternInfo::consumeSubpattern(UErrorCode &status) { +void ParsedPatternInfo::consumeSubpattern(UErrorCode& status) { // subpattern := literals? number exponent? literals? consumePadding(PadPosition::UNUM_PAD_BEFORE_PREFIX, status); if (U_FAILURE(status)) { return; } @@ -161,23 +180,24 @@ void ParsedPatternInfo::consumeSubpattern(UErrorCode &status) { if (U_FAILURE(status)) { return; } } -void ParsedPatternInfo::consumePadding(PadPosition paddingLocation, UErrorCode &status) { +void ParsedPatternInfo::consumePadding(PadPosition paddingLocation, UErrorCode& status) { if (state.peek() != u'*') { return; } - if (!currentSubpattern->paddingLocation.isNull()) { + if (currentSubpattern->hasPadding) { state.toParseException(u"Cannot have multiple pad specifiers"); status = U_MULTIPLE_PAD_SPECIFIERS; return; } currentSubpattern->paddingLocation = paddingLocation; + currentSubpattern->hasPadding = true; state.next(); // consume the '*' currentSubpattern->paddingEndpoints.start = state.offset; consumeLiteral(status); currentSubpattern->paddingEndpoints.end = state.offset; } -void ParsedPatternInfo::consumeAffix(Endpoints &endpoints, UErrorCode &status) { +void ParsedPatternInfo::consumeAffix(Endpoints& endpoints, UErrorCode& status) { // literals := { literal } endpoints.start = state.offset; while (true) { @@ -233,7 +253,7 @@ void ParsedPatternInfo::consumeAffix(Endpoints &endpoints, UErrorCode &status) { endpoints.end = state.offset; } -void ParsedPatternInfo::consumeLiteral(UErrorCode &status) { +void ParsedPatternInfo::consumeLiteral(UErrorCode& status) { if (state.peek() == -1) { state.toParseException(u"Expected unquoted literal but found EOL"); status = U_PATTERN_SYNTAX_ERROR; @@ -256,7 +276,7 @@ void ParsedPatternInfo::consumeLiteral(UErrorCode &status) { } } -void ParsedPatternInfo::consumeFormat(UErrorCode &status) { +void ParsedPatternInfo::consumeFormat(UErrorCode& status) { consumeIntegerFormat(status); if (U_FAILURE(status)) { return; } if (state.peek() == u'.') { @@ -268,9 +288,9 @@ void ParsedPatternInfo::consumeFormat(UErrorCode &status) { } } -void ParsedPatternInfo::consumeIntegerFormat(UErrorCode &status) { +void ParsedPatternInfo::consumeIntegerFormat(UErrorCode& status) { // Convenience reference: - ParsedSubpatternInfo &result = *currentSubpattern; + ParsedSubpatternInfo& result = *currentSubpattern; while (true) { switch (state.peek()) { @@ -359,9 +379,9 @@ void ParsedPatternInfo::consumeIntegerFormat(UErrorCode &status) { } } -void ParsedPatternInfo::consumeFractionFormat(UErrorCode &status) { +void ParsedPatternInfo::consumeFractionFormat(UErrorCode& status) { // Convenience reference: - ParsedSubpatternInfo &result = *currentSubpattern; + ParsedSubpatternInfo& result = *currentSubpattern; int32_t zeroCounter = 0; while (true) { @@ -407,9 +427,9 @@ void ParsedPatternInfo::consumeFractionFormat(UErrorCode &status) { } } -void ParsedPatternInfo::consumeExponent(UErrorCode &status) { +void ParsedPatternInfo::consumeExponent(UErrorCode& status) { // Convenience reference: - ParsedSubpatternInfo &result = *currentSubpattern; + ParsedSubpatternInfo& result = *currentSubpattern; if (state.peek() != u'E') { return; @@ -437,9 +457,9 @@ void ParsedPatternInfo::consumeExponent(UErrorCode &status) { /// END RECURSIVE DESCENT PARSER IMPLEMENTATION /// /////////////////////////////////////////////////// -void -PatternParser::parseToExistingPropertiesImpl(const UnicodeString& pattern, DecimalFormatProperties &properties, - IgnoreRounding ignoreRounding, UErrorCode &status) { +void PatternParser::parseToExistingPropertiesImpl(const UnicodeString& pattern, + DecimalFormatProperties& properties, + IgnoreRounding ignoreRounding, UErrorCode& status) { if (pattern.length() == 0) { // Backwards compatibility requires that we reset to the default values. // TODO: Only overwrite the properties that "saveToProperties" normally touches? @@ -453,13 +473,13 @@ PatternParser::parseToExistingPropertiesImpl(const UnicodeString& pattern, Decim patternInfoToProperties(properties, patternInfo, ignoreRounding, status); } -void PatternParser::patternInfoToProperties(DecimalFormatProperties &properties, - ParsedPatternInfo& patternInfo, - IgnoreRounding _ignoreRounding, UErrorCode &status) { +void +PatternParser::patternInfoToProperties(DecimalFormatProperties& properties, ParsedPatternInfo& patternInfo, + IgnoreRounding _ignoreRounding, UErrorCode& status) { // Translate from PatternParseResult to Properties. // Note that most data from "negative" is ignored per the specification of DecimalFormat. - const ParsedSubpatternInfo &positive = patternInfo.positive; + const ParsedSubpatternInfo& positive = patternInfo.positive; bool ignoreRounding; if (_ignoreRounding == IGNORE_ROUNDING_NEVER) { @@ -477,8 +497,10 @@ void PatternParser::patternInfoToProperties(DecimalFormatProperties &properties, auto grouping3 = static_cast ((positive.groupingSizes >> 32) & 0xffff); if (grouping2 != -1) { properties.groupingSize = grouping1; + properties.groupingUsed = true; } else { properties.groupingSize = -1; + properties.groupingUsed = false; } if (grouping3 != -1) { properties.secondaryGroupingSize = grouping2; @@ -508,8 +530,7 @@ void PatternParser::patternInfoToProperties(DecimalFormatProperties &properties, properties.maximumFractionDigits = -1; properties.roundingIncrement = 0.0; properties.minimumSignificantDigits = positive.integerAtSigns; - properties.maximumSignificantDigits = - positive.integerAtSigns + positive.integerTrailingHashSigns; + properties.maximumSignificantDigits = positive.integerAtSigns + positive.integerTrailingHashSigns; } else if (!positive.rounding.isZero()) { if (!ignoreRounding) { properties.minimumFractionDigits = minFrac; @@ -568,11 +589,11 @@ void PatternParser::patternInfoToProperties(DecimalFormatProperties &properties, UnicodeString posSuffix = patternInfo.getString(0); // Padding settings - if (!positive.paddingLocation.isNull()) { + if (positive.hasPadding) { // The width of the positive prefix and suffix templates are included in the padding - int paddingWidth = - positive.widthExceptAffixes + AffixUtils::estimateLength(UnicodeStringCharSequence(posPrefix), status) + - AffixUtils::estimateLength(UnicodeStringCharSequence(posSuffix), status); + int paddingWidth = positive.widthExceptAffixes + + AffixUtils::estimateLength(posPrefix, status) + + AffixUtils::estimateLength(posSuffix, status); properties.formatWidth = paddingWidth; UnicodeString rawPaddingString = patternInfo.getString(AffixPatternProvider::AFFIX_PADDING); if (rawPaddingString.length() == 1) { @@ -622,8 +643,8 @@ void PatternParser::patternInfoToProperties(DecimalFormatProperties &properties, /// End PatternStringParser.java; begin PatternStringUtils.java /// /////////////////////////////////////////////////////////////////// -UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatProperties &properties, - UErrorCode &status) { +UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatProperties& properties, + UErrorCode& status) { UnicodeString sb; // Convenience references @@ -656,7 +677,7 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP if (!ppp.isBogus()) { sb.append(ppp); } - sb.append(AffixUtils::escape(UnicodeStringCharSequence(pp))); + sb.append(AffixUtils::escape(pp)); int afterPrefixPos = sb.length(); // Figure out the grouping sizes. @@ -695,11 +716,11 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP } } else if (roundingInterval != 0.0) { // Rounding Interval. - digitsStringScale = minFrac; + digitsStringScale = -roundingutils::doubleFractionLength(roundingInterval); // TODO: Check for DoS here? DecimalQuantity incrementQuantity; incrementQuantity.setToDouble(roundingInterval); - incrementQuantity.adjustMagnitude(minFrac); + incrementQuantity.adjustMagnitude(-digitsStringScale); incrementQuantity.roundToMagnitude(0, kDefaultMode, status); UnicodeString str = incrementQuantity.toPlainString(); if (str.charAt(0) == u'-') { @@ -753,7 +774,7 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP if (!psp.isBogus()) { sb.append(psp); } - sb.append(AffixUtils::escape(UnicodeStringCharSequence(ps))); + sb.append(AffixUtils::escape(ps)); // Resolve Padding if (paddingWidth != -1 && !paddingLocation.isNull()) { @@ -795,22 +816,25 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP if (!npp.isBogus()) { sb.append(npp); } - sb.append(AffixUtils::escape(UnicodeStringCharSequence(np))); + sb.append(AffixUtils::escape(np)); // Copy the positive digit format into the negative. // This is optional; the pattern is the same as if '#' were appended here instead. - sb.append(sb, afterPrefixPos, beforeSuffixPos); + // NOTE: It is not safe to append the UnicodeString to itself, so we need to copy. + // See http://bugs.icu-project.org/trac/ticket/13707 + UnicodeString copy(sb); + sb.append(copy, afterPrefixPos, beforeSuffixPos - afterPrefixPos); if (!nsp.isBogus()) { sb.append(nsp); } - sb.append(AffixUtils::escape(UnicodeStringCharSequence(ns))); + sb.append(AffixUtils::escape(ns)); } return sb; } int PatternStringUtils::escapePaddingString(UnicodeString input, UnicodeString& output, int startIndex, - UErrorCode &status) { - (void)status; + UErrorCode& status) { + (void) status; if (input.length() == 0) { input.setTo(kFallbackPaddingString, -1); } @@ -840,4 +864,207 @@ int PatternStringUtils::escapePaddingString(UnicodeString input, UnicodeString& return output.length() - startLength; } +UnicodeString +PatternStringUtils::convertLocalized(const UnicodeString& input, const DecimalFormatSymbols& symbols, + bool toLocalized, UErrorCode& status) { + // Construct a table of strings to be converted between localized and standard. + static constexpr int32_t LEN = 21; + UnicodeString table[LEN][2]; + int standIdx = toLocalized ? 0 : 1; + int localIdx = toLocalized ? 1 : 0; + table[0][standIdx] = u"%"; + table[0][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPercentSymbol); + table[1][standIdx] = u"‰"; + table[1][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); + table[2][standIdx] = u"."; + table[2][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); + table[3][standIdx] = u","; + table[3][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); + table[4][standIdx] = u"-"; + table[4][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); + table[5][standIdx] = u"+"; + table[5][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); + table[6][standIdx] = u";"; + table[6][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); + table[7][standIdx] = u"@"; + table[7][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol); + table[8][standIdx] = u"E"; + table[8][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); + table[9][standIdx] = u"*"; + table[9][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol); + table[10][standIdx] = u"#"; + table[10][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kDigitSymbol); + for (int i = 0; i < 10; i++) { + table[11 + i][standIdx] = u'0' + i; + table[11 + i][localIdx] = symbols.getConstDigitSymbol(i); + } + + // Special case: quotes are NOT allowed to be in any localIdx strings. + // Substitute them with '’' instead. + for (int32_t i = 0; i < LEN; i++) { + table[i][localIdx].findAndReplace(u'\'', u'’'); + } + + // Iterate through the string and convert. + // State table: + // 0 => base state + // 1 => first char inside a quoted sequence in input and output string + // 2 => inside a quoted sequence in input and output string + // 3 => first char after a close quote in input string; + // close quote still needs to be written to output string + // 4 => base state in input string; inside quoted sequence in output string + // 5 => first char inside a quoted sequence in input string; + // inside quoted sequence in output string + UnicodeString result; + int state = 0; + for (int offset = 0; offset < input.length(); offset++) { + UChar ch = input.charAt(offset); + + // Handle a quote character (state shift) + if (ch == u'\'') { + if (state == 0) { + result.append(u'\''); + state = 1; + continue; + } else if (state == 1) { + result.append(u'\''); + state = 0; + continue; + } else if (state == 2) { + state = 3; + continue; + } else if (state == 3) { + result.append(u'\''); + result.append(u'\''); + state = 1; + continue; + } else if (state == 4) { + state = 5; + continue; + } else { + U_ASSERT(state == 5); + result.append(u'\''); + result.append(u'\''); + state = 4; + continue; + } + } + + if (state == 0 || state == 3 || state == 4) { + for (auto& pair : table) { + // Perform a greedy match on this symbol string + UnicodeString temp = input.tempSubString(offset, pair[0].length()); + if (temp == pair[0]) { + // Skip ahead past this region for the next iteration + offset += pair[0].length() - 1; + if (state == 3 || state == 4) { + result.append(u'\''); + state = 0; + } + result.append(pair[1]); + goto continue_outer; + } + } + // No replacement found. Check if a special quote is necessary + for (auto& pair : table) { + UnicodeString temp = input.tempSubString(offset, pair[1].length()); + if (temp == pair[1]) { + if (state == 0) { + result.append(u'\''); + state = 4; + } + result.append(ch); + goto continue_outer; + } + } + // Still nothing. Copy the char verbatim. (Add a close quote if necessary) + if (state == 3 || state == 4) { + result.append(u'\''); + state = 0; + } + result.append(ch); + } else { + U_ASSERT(state == 1 || state == 2 || state == 5); + result.append(ch); + state = 2; + } + continue_outer:; + } + // Resolve final quotes + if (state == 3 || state == 4) { + result.append(u'\''); + state = 0; + } + if (state != 0) { + // Malformed localized pattern: unterminated quote + status = U_PATTERN_SYNTAX_ERROR; + } + return result; +} + +void PatternStringUtils::patternInfoToStringBuilder(const AffixPatternProvider& patternInfo, bool isPrefix, + int8_t signum, UNumberSignDisplay signDisplay, + StandardPlural::Form plural, + bool perMilleReplacesPercent, UnicodeString& output) { + + // Should the output render '+' where '-' would normally appear in the pattern? + bool plusReplacesMinusSign = signum != -1 && ( + signDisplay == UNUM_SIGN_ALWAYS || signDisplay == UNUM_SIGN_ACCOUNTING_ALWAYS || ( + signum == 1 && ( + signDisplay == UNUM_SIGN_EXCEPT_ZERO || + signDisplay == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO))) && + patternInfo.positiveHasPlusSign() == false; + + // Should we use the affix from the negative subpattern? (If not, we will use the positive + // subpattern.) + bool useNegativeAffixPattern = patternInfo.hasNegativeSubpattern() && ( + signum == -1 || (patternInfo.negativeHasMinusSign() && plusReplacesMinusSign)); + + // Resolve the flags for the affix pattern. + int flags = 0; + if (useNegativeAffixPattern) { + flags |= AffixPatternProvider::AFFIX_NEGATIVE_SUBPATTERN; + } + if (isPrefix) { + flags |= AffixPatternProvider::AFFIX_PREFIX; + } + if (plural != StandardPlural::Form::COUNT) { + U_ASSERT(plural == (AffixPatternProvider::AFFIX_PLURAL_MASK & plural)); + flags |= plural; + } + + // Should we prepend a sign to the pattern? + bool prependSign; + if (!isPrefix || useNegativeAffixPattern) { + prependSign = false; + } else if (signum == -1) { + prependSign = signDisplay != UNUM_SIGN_NEVER; + } else { + prependSign = plusReplacesMinusSign; + } + + // Compute the length of the affix pattern. + int length = patternInfo.length(flags) + (prependSign ? 1 : 0); + + // Finally, set the result into the StringBuilder. + output.remove(); + for (int index = 0; index < length; index++) { + char16_t candidate; + if (prependSign && index == 0) { + candidate = u'-'; + } else if (prependSign) { + candidate = patternInfo.charAt(flags, index - 1); + } else { + candidate = patternInfo.charAt(flags, index); + } + if (plusReplacesMinusSign && candidate == u'-') { + candidate = u'+'; + } + if (perMilleReplacesPercent && candidate == u'%') { + candidate = u'‰'; + } + output.append(candidate); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_patternstring.h b/deps/icu-small/source/i18n/number_patternstring.h index ec44290d66..91e120c16a 100644 --- a/deps/icu-small/source/i18n/number_patternstring.h +++ b/deps/icu-small/source/i18n/number_patternstring.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_PATTERNSTRING_H__ #define __NUMBER_PATTERNSTRING_H__ @@ -30,7 +30,7 @@ struct U_I18N_API Endpoints { // Exported as U_I18N_API because it is a public member field of exported ParsedPatternInfo struct U_I18N_API ParsedSubpatternInfo { - int64_t groupingSizes = 0x0000ffffffff0000L; + uint64_t groupingSizes = 0x0000ffffffff0000L; int32_t integerLeadingHashSigns = 0; int32_t integerTrailingHashSigns = 0; int32_t integerNumerals = 0; @@ -41,7 +41,9 @@ struct U_I18N_API ParsedSubpatternInfo { int32_t fractionTotal = 0; // for convenience bool hasDecimal = false; int32_t widthExceptAffixes = 0; - NullableValue paddingLocation; + // Note: NullableValue causes issues here with std::move. + bool hasPadding = false; + UNumberFormatPadPosition paddingLocation = UNUM_PAD_BEFORE_PREFIX; DecimalQuantity rounding; bool exponentHasPlusSign = false; int32_t exponentZeros = 0; @@ -62,17 +64,21 @@ struct U_I18N_API ParsedPatternInfo : public AffixPatternProvider, public UMemor ParsedSubpatternInfo positive; ParsedSubpatternInfo negative; - ParsedPatternInfo() : state(this->pattern), currentSubpattern(nullptr) {} + ParsedPatternInfo() + : state(this->pattern), currentSubpattern(nullptr) {} ~ParsedPatternInfo() U_OVERRIDE = default; - static int32_t getLengthFromEndpoints(const Endpoints &endpoints); + // Need to declare this explicitly because of the destructor + ParsedPatternInfo& operator=(ParsedPatternInfo&& src) U_NOEXCEPT = default; + + static int32_t getLengthFromEndpoints(const Endpoints& endpoints); char16_t charAt(int32_t flags, int32_t index) const U_OVERRIDE; int32_t length(int32_t flags) const U_OVERRIDE; - UnicodeString getString(int32_t flags) const; + UnicodeString getString(int32_t flags) const U_OVERRIDE; bool positiveHasPlusSign() const U_OVERRIDE; @@ -82,16 +88,24 @@ struct U_I18N_API ParsedPatternInfo : public AffixPatternProvider, public UMemor bool hasCurrencySign() const U_OVERRIDE; - bool containsSymbolType(AffixPatternType type, UErrorCode &status) const U_OVERRIDE; + bool containsSymbolType(AffixPatternType type, UErrorCode& status) const U_OVERRIDE; bool hasBody() const U_OVERRIDE; private: struct U_I18N_API ParserState { - const UnicodeString &pattern; // reference to the parent + const UnicodeString& pattern; // reference to the parent int32_t offset = 0; - explicit ParserState(const UnicodeString &_pattern) : pattern(_pattern) {}; + explicit ParserState(const UnicodeString& _pattern) + : pattern(_pattern) {}; + + ParserState& operator=(ParserState&& src) U_NOEXCEPT { + // Leave pattern reference alone; it will continue to point to the same place in memory, + // which gets overwritten by ParsedPatternInfo's implicit move assignment. + offset = src.offset; + return *this; + } UChar32 peek(); @@ -99,45 +113,48 @@ struct U_I18N_API ParsedPatternInfo : public AffixPatternProvider, public UMemor // TODO: We don't currently do anything with the message string. // This method is here as a shell for Java compatibility. - inline void toParseException(const char16_t *message) { (void)message; } - } - state; + inline void toParseException(const char16_t* message) { (void) message; } + } state; // NOTE: In Java, these are written as pure functions. // In C++, they're written as methods. // The behavior is the same. // Mutable transient pointer: - ParsedSubpatternInfo *currentSubpattern; + ParsedSubpatternInfo* currentSubpattern; // In Java, "negative == null" tells us whether or not we had a negative subpattern. // In C++, we need to remember in another boolean. bool fHasNegativeSubpattern = false; - const Endpoints &getEndpoints(int32_t flags) const; + const Endpoints& getEndpoints(int32_t flags) const; /** Run the recursive descent parser. */ - void consumePattern(const UnicodeString &patternString, UErrorCode &status); + void consumePattern(const UnicodeString& patternString, UErrorCode& status); - void consumeSubpattern(UErrorCode &status); + void consumeSubpattern(UErrorCode& status); - void consumePadding(PadPosition paddingLocation, UErrorCode &status); + void consumePadding(PadPosition paddingLocation, UErrorCode& status); - void consumeAffix(Endpoints &endpoints, UErrorCode &status); + void consumeAffix(Endpoints& endpoints, UErrorCode& status); - void consumeLiteral(UErrorCode &status); + void consumeLiteral(UErrorCode& status); - void consumeFormat(UErrorCode &status); + void consumeFormat(UErrorCode& status); - void consumeIntegerFormat(UErrorCode &status); + void consumeIntegerFormat(UErrorCode& status); - void consumeFractionFormat(UErrorCode &status); + void consumeFractionFormat(UErrorCode& status); - void consumeExponent(UErrorCode &status); + void consumeExponent(UErrorCode& status); friend class PatternParser; }; +enum IgnoreRounding { + IGNORE_ROUNDING_NEVER = 0, IGNORE_ROUNDING_IF_CURRENCY = 1, IGNORE_ROUNDING_ALWAYS = 2 +}; + class U_I18N_API PatternParser { public: /** @@ -153,12 +170,8 @@ class U_I18N_API PatternParser { * The LDML decimal format pattern (Excel-style pattern) to parse. * @return The results of the parse. */ - static void - parseToPatternInfo(const UnicodeString& patternString, ParsedPatternInfo &patternInfo, UErrorCode &status); - - enum IgnoreRounding { - IGNORE_ROUNDING_NEVER = 0, IGNORE_ROUNDING_IF_CURRENCY = 1, IGNORE_ROUNDING_ALWAYS = 2 - }; + static void parseToPatternInfo(const UnicodeString& patternString, ParsedPatternInfo& patternInfo, + UErrorCode& status); /** * Parses a pattern string into a new property bag. @@ -173,8 +186,10 @@ class U_I18N_API PatternParser { * @throws IllegalArgumentException * If there is a syntax error in the pattern string. */ - static DecimalFormatProperties - parseToProperties(const UnicodeString& pattern, IgnoreRounding ignoreRounding, UErrorCode &status); + static DecimalFormatProperties parseToProperties(const UnicodeString& pattern, + IgnoreRounding ignoreRounding, UErrorCode& status); + + static DecimalFormatProperties parseToProperties(const UnicodeString& pattern, UErrorCode& status); /** * Parses a pattern string into an existing property bag. All properties that can be encoded into a pattern string @@ -190,18 +205,19 @@ class U_I18N_API PatternParser { * @throws IllegalArgumentException * If there was a syntax error in the pattern string. */ - static void parseToExistingProperties(const UnicodeString& pattern, DecimalFormatProperties& properties, - IgnoreRounding ignoreRounding, UErrorCode &status); + static void parseToExistingProperties(const UnicodeString& pattern, + DecimalFormatProperties& properties, + IgnoreRounding ignoreRounding, UErrorCode& status); private: - static void - parseToExistingPropertiesImpl(const UnicodeString& pattern, DecimalFormatProperties &properties, - IgnoreRounding ignoreRounding, UErrorCode &status); + static void parseToExistingPropertiesImpl(const UnicodeString& pattern, + DecimalFormatProperties& properties, + IgnoreRounding ignoreRounding, UErrorCode& status); /** Finalizes the temporary data stored in the ParsedPatternInfo to the Properties. */ - static void - patternInfoToProperties(DecimalFormatProperties &properties, ParsedPatternInfo& patternInfo, - IgnoreRounding _ignoreRounding, UErrorCode &status); + static void patternInfoToProperties(DecimalFormatProperties& properties, + ParsedPatternInfo& patternInfo, IgnoreRounding _ignoreRounding, + UErrorCode& status); }; class U_I18N_API PatternStringUtils { @@ -217,8 +233,8 @@ class U_I18N_API PatternStringUtils { * The property bag to serialize. * @return A pattern string approximately serializing the property bag. */ - static UnicodeString - propertiesToPatternString(const DecimalFormatProperties &properties, UErrorCode &status); + static UnicodeString propertiesToPatternString(const DecimalFormatProperties& properties, + UErrorCode& status); /** @@ -248,14 +264,23 @@ class U_I18N_API PatternStringUtils { * notation. * @return The pattern expressed in the other notation. */ - static UnicodeString - convertLocalized(UnicodeString input, DecimalFormatSymbols symbols, bool toLocalized, - UErrorCode &status); + static UnicodeString convertLocalized(const UnicodeString& input, const DecimalFormatSymbols& symbols, + bool toLocalized, UErrorCode& status); + + /** + * This method contains the heart of the logic for rendering LDML affix strings. It handles + * sign-always-shown resolution, whether to use the positive or negative subpattern, permille + * substitution, and plural forms for CurrencyPluralInfo. + */ + static void patternInfoToStringBuilder(const AffixPatternProvider& patternInfo, bool isPrefix, + int8_t signum, UNumberSignDisplay signDisplay, + StandardPlural::Form plural, bool perMilleReplacesPercent, + UnicodeString& output); private: /** @return The number of chars inserted. */ - static int - escapePaddingString(UnicodeString input, UnicodeString &output, int startIndex, UErrorCode &status); + static int escapePaddingString(UnicodeString input, UnicodeString& output, int startIndex, + UErrorCode& status); }; } // namespace impl diff --git a/deps/icu-small/source/i18n/number_rounding.cpp b/deps/icu-small/source/i18n/number_rounding.cpp index fd4dafdf98..ae4b8849fb 100644 --- a/deps/icu-small/source/i18n/number_rounding.cpp +++ b/deps/icu-small/source/i18n/number_rounding.cpp @@ -3,17 +3,23 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "uassert.h" #include "unicode/numberformatter.h" #include "number_types.h" #include "number_decimalquantity.h" +#include "double-conversion.h" +#include "number_roundingutils.h" +#include "putilimp.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; + +using double_conversion::DoubleToStringConverter; + namespace { int32_t getRoundingMagnitudeFraction(int maxFrac) { @@ -46,15 +52,38 @@ int32_t getDisplayMagnitudeSignificant(const DecimalQuantity &value, int minSig) } -Rounder Rounder::unlimited() { - return Rounder(RND_NONE, {}, kDefaultMode); +MultiplierProducer::~MultiplierProducer() = default; + + +digits_t roundingutils::doubleFractionLength(double input) { + char buffer[DoubleToStringConverter::kBase10MaximalLength + 1]; + bool sign; // unused; always positive + int32_t length; + int32_t point; + DoubleToStringConverter::DoubleToAscii( + input, + DoubleToStringConverter::DtoaMode::SHORTEST, + 0, + buffer, + sizeof(buffer), + &sign, + &length, + &point + ); + + return static_cast(length - point); } -FractionRounder Rounder::integer() { + +Precision Precision::unlimited() { + return Precision(RND_NONE, {}, kDefaultMode); +} + +FractionPrecision Precision::integer() { return constructFraction(0, 0); } -FractionRounder Rounder::fixedFraction(int32_t minMaxFractionPlaces) { +FractionPrecision Precision::fixedFraction(int32_t minMaxFractionPlaces) { if (minMaxFractionPlaces >= 0 && minMaxFractionPlaces <= kMaxIntFracSig) { return constructFraction(minMaxFractionPlaces, minMaxFractionPlaces); } else { @@ -62,7 +91,7 @@ FractionRounder Rounder::fixedFraction(int32_t minMaxFractionPlaces) { } } -FractionRounder Rounder::minFraction(int32_t minFractionPlaces) { +FractionPrecision Precision::minFraction(int32_t minFractionPlaces) { if (minFractionPlaces >= 0 && minFractionPlaces <= kMaxIntFracSig) { return constructFraction(minFractionPlaces, -1); } else { @@ -70,7 +99,7 @@ FractionRounder Rounder::minFraction(int32_t minFractionPlaces) { } } -FractionRounder Rounder::maxFraction(int32_t maxFractionPlaces) { +FractionPrecision Precision::maxFraction(int32_t maxFractionPlaces) { if (maxFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig) { return constructFraction(0, maxFractionPlaces); } else { @@ -78,7 +107,7 @@ FractionRounder Rounder::maxFraction(int32_t maxFractionPlaces) { } } -FractionRounder Rounder::minMaxFraction(int32_t minFractionPlaces, int32_t maxFractionPlaces) { +FractionPrecision Precision::minMaxFraction(int32_t minFractionPlaces, int32_t maxFractionPlaces) { if (minFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig && minFractionPlaces <= maxFractionPlaces) { return constructFraction(minFractionPlaces, maxFractionPlaces); @@ -87,7 +116,7 @@ FractionRounder Rounder::minMaxFraction(int32_t minFractionPlaces, int32_t maxFr } } -Rounder Rounder::fixedDigits(int32_t minMaxSignificantDigits) { +Precision Precision::fixedSignificantDigits(int32_t minMaxSignificantDigits) { if (minMaxSignificantDigits >= 1 && minMaxSignificantDigits <= kMaxIntFracSig) { return constructSignificant(minMaxSignificantDigits, minMaxSignificantDigits); } else { @@ -95,7 +124,7 @@ Rounder Rounder::fixedDigits(int32_t minMaxSignificantDigits) { } } -Rounder Rounder::minDigits(int32_t minSignificantDigits) { +Precision Precision::minSignificantDigits(int32_t minSignificantDigits) { if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) { return constructSignificant(minSignificantDigits, -1); } else { @@ -103,7 +132,7 @@ Rounder Rounder::minDigits(int32_t minSignificantDigits) { } } -Rounder Rounder::maxDigits(int32_t maxSignificantDigits) { +Precision Precision::maxSignificantDigits(int32_t maxSignificantDigits) { if (maxSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig) { return constructSignificant(1, maxSignificantDigits); } else { @@ -111,7 +140,7 @@ Rounder Rounder::maxDigits(int32_t maxSignificantDigits) { } } -Rounder Rounder::minMaxDigits(int32_t minSignificantDigits, int32_t maxSignificantDigits) { +Precision Precision::minMaxSignificantDigits(int32_t minSignificantDigits, int32_t maxSignificantDigits) { if (minSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig && minSignificantDigits <= maxSignificantDigits) { return constructSignificant(minSignificantDigits, maxSignificantDigits); @@ -120,7 +149,7 @@ Rounder Rounder::minMaxDigits(int32_t minSignificantDigits, int32_t maxSignifica } } -IncrementRounder Rounder::increment(double roundingIncrement) { +IncrementPrecision Precision::increment(double roundingIncrement) { if (roundingIncrement > 0.0) { return constructIncrement(roundingIncrement, 0); } else { @@ -128,16 +157,18 @@ IncrementRounder Rounder::increment(double roundingIncrement) { } } -CurrencyRounder Rounder::currency(UCurrencyUsage currencyUsage) { +CurrencyPrecision Precision::currency(UCurrencyUsage currencyUsage) { return constructCurrency(currencyUsage); } -Rounder Rounder::withMode(RoundingMode roundingMode) const { +Precision Precision::withMode(RoundingMode roundingMode) const { if (fType == RND_ERROR) { return *this; } // no-op in error state - return {fType, fUnion, roundingMode}; + Precision retval = *this; + retval.fRoundingMode = roundingMode; + return retval; } -Rounder FractionRounder::withMinDigits(int32_t minSignificantDigits) const { +Precision FractionPrecision::withMinDigits(int32_t minSignificantDigits) const { if (fType == RND_ERROR) { return *this; } // no-op in error state if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) { return constructFractionSignificant(*this, minSignificantDigits, -1); @@ -146,7 +177,7 @@ Rounder FractionRounder::withMinDigits(int32_t minSignificantDigits) const { } } -Rounder FractionRounder::withMaxDigits(int32_t maxSignificantDigits) const { +Precision FractionPrecision::withMaxDigits(int32_t maxSignificantDigits) const { if (fType == RND_ERROR) { return *this; } // no-op in error state if (maxSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig) { return constructFractionSignificant(*this, -1, maxSignificantDigits); @@ -156,7 +187,7 @@ Rounder FractionRounder::withMaxDigits(int32_t maxSignificantDigits) const { } // Private method on base class -Rounder Rounder::withCurrency(const CurrencyUnit ¤cy, UErrorCode &status) const { +Precision Precision::withCurrency(const CurrencyUnit ¤cy, UErrorCode &status) const { if (fType == RND_ERROR) { return *this; } // no-op in error state U_ASSERT(fType == RND_CURRENCY); const char16_t *isoCode = currency.getISOCurrency(); @@ -170,17 +201,17 @@ Rounder Rounder::withCurrency(const CurrencyUnit ¤cy, UErrorCode &status) } } -// Public method on CurrencyRounder subclass -Rounder CurrencyRounder::withCurrency(const CurrencyUnit ¤cy) const { +// Public method on CurrencyPrecision subclass +Precision CurrencyPrecision::withCurrency(const CurrencyUnit ¤cy) const { UErrorCode localStatus = U_ZERO_ERROR; - Rounder result = Rounder::withCurrency(currency, localStatus); + Precision result = Precision::withCurrency(currency, localStatus); if (U_FAILURE(localStatus)) { return {localStatus}; } return result; } -Rounder IncrementRounder::withMinFraction(int32_t minFrac) const { +Precision IncrementPrecision::withMinFraction(int32_t minFrac) const { if (fType == RND_ERROR) { return *this; } // no-op in error state if (minFrac >= 0 && minFrac <= kMaxIntFracSig) { return constructIncrement(fUnion.increment.fIncrement, minFrac); @@ -189,67 +220,77 @@ Rounder IncrementRounder::withMinFraction(int32_t minFrac) const { } } -FractionRounder Rounder::constructFraction(int32_t minFrac, int32_t maxFrac) { +FractionPrecision Precision::constructFraction(int32_t minFrac, int32_t maxFrac) { FractionSignificantSettings settings; settings.fMinFrac = static_cast(minFrac); settings.fMaxFrac = static_cast(maxFrac); settings.fMinSig = -1; settings.fMaxSig = -1; - RounderUnion union_; + PrecisionUnion union_; union_.fracSig = settings; return {RND_FRACTION, union_, kDefaultMode}; } -Rounder Rounder::constructSignificant(int32_t minSig, int32_t maxSig) { +Precision Precision::constructSignificant(int32_t minSig, int32_t maxSig) { FractionSignificantSettings settings; settings.fMinFrac = -1; settings.fMaxFrac = -1; settings.fMinSig = static_cast(minSig); settings.fMaxSig = static_cast(maxSig); - RounderUnion union_; + PrecisionUnion union_; union_.fracSig = settings; return {RND_SIGNIFICANT, union_, kDefaultMode}; } -Rounder -Rounder::constructFractionSignificant(const FractionRounder &base, int32_t minSig, int32_t maxSig) { +Precision +Precision::constructFractionSignificant(const FractionPrecision &base, int32_t minSig, int32_t maxSig) { FractionSignificantSettings settings = base.fUnion.fracSig; settings.fMinSig = static_cast(minSig); settings.fMaxSig = static_cast(maxSig); - RounderUnion union_; + PrecisionUnion union_; union_.fracSig = settings; return {RND_FRACTION_SIGNIFICANT, union_, kDefaultMode}; } -IncrementRounder Rounder::constructIncrement(double increment, int32_t minFrac) { +IncrementPrecision Precision::constructIncrement(double increment, int32_t minFrac) { IncrementSettings settings; settings.fIncrement = increment; settings.fMinFrac = static_cast(minFrac); - RounderUnion union_; + // One of the few pre-computed quantities: + // Note: it is possible for minFrac to be more than maxFrac... (misleading) + settings.fMaxFrac = roundingutils::doubleFractionLength(increment); + PrecisionUnion union_; union_.increment = settings; return {RND_INCREMENT, union_, kDefaultMode}; } -CurrencyRounder Rounder::constructCurrency(UCurrencyUsage usage) { - RounderUnion union_; +CurrencyPrecision Precision::constructCurrency(UCurrencyUsage usage) { + PrecisionUnion union_; union_.currencyUsage = usage; return {RND_CURRENCY, union_, kDefaultMode}; } -Rounder Rounder::constructPassThrough() { - RounderUnion union_; - union_.errorCode = U_ZERO_ERROR; // initialize the variable - return {RND_PASS_THROUGH, union_, kDefaultMode}; -} -void Rounder::setLocaleData(const CurrencyUnit ¤cy, UErrorCode &status) { - if (fType == RND_CURRENCY) { - *this = withCurrency(currency, status); +RoundingImpl::RoundingImpl(const Precision& precision, UNumberFormatRoundingMode roundingMode, + const CurrencyUnit& currency, UErrorCode& status) + : fPrecision(precision), fRoundingMode(roundingMode), fPassThrough(false) { + if (precision.fType == Precision::RND_CURRENCY) { + fPrecision = precision.withCurrency(currency, status); } } +RoundingImpl RoundingImpl::passThrough() { + RoundingImpl retval; + retval.fPassThrough = true; + return retval; +} + +bool RoundingImpl::isSignificantDigits() const { + return fPrecision.fType == Precision::RND_SIGNIFICANT; +} + int32_t -Rounder::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer, +RoundingImpl::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer, UErrorCode &status) { // Do not call this method with zero. U_ASSERT(!input.isZero()); @@ -287,45 +328,59 @@ Rounder::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::Mult } /** This is the method that contains the actual rounding logic. */ -void Rounder::apply(impl::DecimalQuantity &value, UErrorCode& status) const { - switch (fType) { - case RND_BOGUS: - case RND_ERROR: +void RoundingImpl::apply(impl::DecimalQuantity &value, UErrorCode& status) const { + if (fPassThrough) { + return; + } + switch (fPrecision.fType) { + case Precision::RND_BOGUS: + case Precision::RND_ERROR: // Errors should be caught before the apply() method is called status = U_INTERNAL_PROGRAM_ERROR; break; - case RND_NONE: + case Precision::RND_NONE: value.roundToInfinity(); break; - case RND_FRACTION: + case Precision::RND_FRACTION: value.roundToMagnitude( - getRoundingMagnitudeFraction(fUnion.fracSig.fMaxFrac), fRoundingMode, status); + getRoundingMagnitudeFraction(fPrecision.fUnion.fracSig.fMaxFrac), + fRoundingMode, + status); value.setFractionLength( - uprv_max(0, -getDisplayMagnitudeFraction(fUnion.fracSig.fMinFrac)), INT32_MAX); + uprv_max(0, -getDisplayMagnitudeFraction(fPrecision.fUnion.fracSig.fMinFrac)), + INT32_MAX); break; - case RND_SIGNIFICANT: + case Precision::RND_SIGNIFICANT: value.roundToMagnitude( - getRoundingMagnitudeSignificant(value, fUnion.fracSig.fMaxSig), + getRoundingMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMaxSig), fRoundingMode, status); value.setFractionLength( - uprv_max(0, -getDisplayMagnitudeSignificant(value, fUnion.fracSig.fMinSig)), + uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig)), INT32_MAX); + // Make sure that digits are displayed on zero. + if (value.isZero() && fPrecision.fUnion.fracSig.fMinSig > 0) { + value.setIntegerLength(1, INT32_MAX); + } break; - case RND_FRACTION_SIGNIFICANT: { - int32_t displayMag = getDisplayMagnitudeFraction(fUnion.fracSig.fMinFrac); - int32_t roundingMag = getRoundingMagnitudeFraction(fUnion.fracSig.fMaxFrac); - if (fUnion.fracSig.fMinSig == -1) { + case Precision::RND_FRACTION_SIGNIFICANT: { + int32_t displayMag = getDisplayMagnitudeFraction(fPrecision.fUnion.fracSig.fMinFrac); + int32_t roundingMag = getRoundingMagnitudeFraction(fPrecision.fUnion.fracSig.fMaxFrac); + if (fPrecision.fUnion.fracSig.fMinSig == -1) { // Max Sig override - int32_t candidate = getRoundingMagnitudeSignificant(value, fUnion.fracSig.fMaxSig); + int32_t candidate = getRoundingMagnitudeSignificant( + value, + fPrecision.fUnion.fracSig.fMaxSig); roundingMag = uprv_max(roundingMag, candidate); } else { // Min Sig override - int32_t candidate = getDisplayMagnitudeSignificant(value, fUnion.fracSig.fMinSig); + int32_t candidate = getDisplayMagnitudeSignificant( + value, + fPrecision.fUnion.fracSig.fMinSig); roundingMag = uprv_min(roundingMag, candidate); } value.roundToMagnitude(roundingMag, fRoundingMode, status); @@ -333,27 +388,27 @@ void Rounder::apply(impl::DecimalQuantity &value, UErrorCode& status) const { break; } - case RND_INCREMENT: + case Precision::RND_INCREMENT: value.roundToIncrement( - fUnion.increment.fIncrement, fRoundingMode, fUnion.increment.fMinFrac, status); - value.setFractionLength(fUnion.increment.fMinFrac, fUnion.increment.fMinFrac); + fPrecision.fUnion.increment.fIncrement, + fRoundingMode, + fPrecision.fUnion.increment.fMaxFrac, + status); + value.setFractionLength(fPrecision.fUnion.increment.fMinFrac, INT32_MAX); break; - case RND_CURRENCY: + case Precision::RND_CURRENCY: // Call .withCurrency() before .apply()! U_ASSERT(false); break; - - case RND_PASS_THROUGH: - break; } } -void Rounder::apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode /*status*/) { +void RoundingImpl::apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode /*status*/) { // This method is intended for the one specific purpose of helping print "00.000E0". - U_ASSERT(fType == RND_SIGNIFICANT); + U_ASSERT(isSignificantDigits()); U_ASSERT(value.isZero()); - value.setFractionLength(fUnion.fracSig.fMinSig - minInt, INT32_MAX); + value.setFractionLength(fPrecision.fUnion.fracSig.fMinSig - minInt, INT32_MAX); } #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_roundingutils.h b/deps/icu-small/source/i18n/number_roundingutils.h index 6868ee0b86..66d58bb775 100644 --- a/deps/icu-small/source/i18n/number_roundingutils.h +++ b/deps/icu-small/source/i18n/number_roundingutils.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_ROUNDINGUTILS_H__ #define __NUMBER_ROUNDINGUTILS_H__ @@ -131,7 +131,62 @@ inline bool roundsAtMidpoint(int roundingMode) { } } +/** + * Computes the number of fraction digits in a double. Used for computing maxFrac for an increment. + * Calls into the DoubleToStringConverter library to do so. + */ +digits_t doubleFractionLength(double input); + } // namespace roundingutils + + +/** + * Encapsulates a Precision and a RoundingMode and performs rounding on a DecimalQuantity. + * + * This class does not exist in Java: instead, the base Precision class is used. + */ +class RoundingImpl { + public: + RoundingImpl() = default; // default constructor: leaves object in undefined state + + RoundingImpl(const Precision& precision, UNumberFormatRoundingMode roundingMode, + const CurrencyUnit& currency, UErrorCode& status); + + static RoundingImpl passThrough(); + + /** Required for ScientificFormatter */ + bool isSignificantDigits() const; + + /** + * Rounding endpoint used by Engineering and Compact notation. Chooses the most appropriate multiplier (magnitude + * adjustment), applies the adjustment, rounds, and returns the chosen multiplier. + * + *

+ * In most cases, this is simple. However, when rounding the number causes it to cross a multiplier boundary, we + * need to re-do the rounding. For example, to display 999,999 in Engineering notation with 2 sigfigs, first you + * guess the multiplier to be -3. However, then you end up getting 1000E3, which is not the correct output. You then + * change your multiplier to be -6, and you get 1.0E6, which is correct. + * + * @param input The quantity to process. + * @param producer Function to call to return a multiplier based on a magnitude. + * @return The number of orders of magnitude the input was adjusted by this method. + */ + int32_t + chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer, + UErrorCode &status); + + void apply(impl::DecimalQuantity &value, UErrorCode &status) const; + + /** Version of {@link #apply} that obeys minInt constraints. Used for scientific notation compatibility mode. */ + void apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode status); + + private: + Precision fPrecision; + UNumberFormatRoundingMode fRoundingMode; + bool fPassThrough; +}; + + } // namespace impl } // namespace number U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/number_scientific.cpp b/deps/icu-small/source/i18n/number_scientific.cpp index a2f2bf85a1..40952024e9 100644 --- a/deps/icu-small/source/i18n/number_scientific.cpp +++ b/deps/icu-small/source/i18n/number_scientific.cpp @@ -3,13 +3,14 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include #include "number_scientific.h" #include "number_utils.h" #include "number_stringbuilder.h" #include "unicode/unum.h" +#include "number_microprops.h" using namespace icu; using namespace icu::number; @@ -64,8 +65,13 @@ int32_t ScientificModifier::apply(NumberStringBuilder &output, int32_t /*leftInd int32_t disp = std::abs(fExponent); for (int j = 0; j < fHandler->fSettings.fMinExponentDigits || disp > 0; j++, disp /= 10) { auto d = static_cast(disp % 10); - const UnicodeString &digitString = getDigitFromSymbols(d, *fHandler->fSymbols); - i += output.insert(i - j, digitString, UNUM_EXPONENT_FIELD, status); + i += utils::insertDigitFromSymbols( + output, + i - j, + d, + *fHandler->fSymbols, + UNUM_EXPONENT_FIELD, + status); } return i - rightIndex; } @@ -101,22 +107,25 @@ void ScientificHandler::processQuantity(DecimalQuantity &quantity, MicroProps &m // Treat zero as if it had magnitude 0 int32_t exponent; if (quantity.isZero()) { - if (fSettings.fRequireMinInt && micros.rounding.fType == Rounder::RND_SIGNIFICANT) { + if (fSettings.fRequireMinInt && micros.rounder.isSignificantDigits()) { // Show "00.000E0" on pattern "00.000E0" - micros.rounding.apply(quantity, fSettings.fEngineeringInterval, status); + micros.rounder.apply(quantity, fSettings.fEngineeringInterval, status); exponent = 0; } else { - micros.rounding.apply(quantity, status); + micros.rounder.apply(quantity, status); exponent = 0; } } else { - exponent = -micros.rounding.chooseMultiplierAndApply(quantity, *this, status); + exponent = -micros.rounder.chooseMultiplierAndApply(quantity, *this, status); } // Use MicroProps's helper ScientificModifier and save it as the modInner. ScientificModifier &mod = micros.helpers.scientificModifier; mod.set(exponent, this); micros.modInner = &mod; + + // We already performed rounding. Do not perform it again. + micros.rounder = RoundingImpl::passThrough(); } int32_t ScientificHandler::getMultiplier(int32_t magnitude) const { diff --git a/deps/icu-small/source/i18n/number_scientific.h b/deps/icu-small/source/i18n/number_scientific.h index f5e4d30e6a..974ab3adb6 100644 --- a/deps/icu-small/source/i18n/number_scientific.h +++ b/deps/icu-small/source/i18n/number_scientific.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_SCIENTIFIC_H__ #define __NUMBER_SCIENTIFIC_H__ diff --git a/deps/icu-small/source/i18n/number_skeletons.cpp b/deps/icu-small/source/i18n/number_skeletons.cpp new file mode 100644 index 0000000000..c7bb18b5f3 --- /dev/null +++ b/deps/icu-small/source/i18n/number_skeletons.cpp @@ -0,0 +1,1510 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "number_decnum.h" +#include "number_skeletons.h" +#include "umutex.h" +#include "ucln_in.h" +#include "patternprops.h" +#include "unicode/ucharstriebuilder.h" +#include "number_utils.h" +#include "number_decimalquantity.h" +#include "unicode/numberformatter.h" +#include "uinvchar.h" +#include "charstr.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; +using namespace icu::number::impl::skeleton; + +namespace { + +icu::UInitOnce gNumberSkeletonsInitOnce = U_INITONCE_INITIALIZER; + +char16_t* kSerializedStemTrie = nullptr; + +UBool U_CALLCONV cleanupNumberSkeletons() { + uprv_free(kSerializedStemTrie); + kSerializedStemTrie = nullptr; + gNumberSkeletonsInitOnce.reset(); + return TRUE; +} + +void U_CALLCONV initNumberSkeletons(UErrorCode& status) { + ucln_i18n_registerCleanup(UCLN_I18N_NUMBER_SKELETONS, cleanupNumberSkeletons); + + UCharsTrieBuilder b(status); + if (U_FAILURE(status)) { return; } + + // Section 1: + b.add(u"compact-short", STEM_COMPACT_SHORT, status); + b.add(u"compact-long", STEM_COMPACT_LONG, status); + b.add(u"scientific", STEM_SCIENTIFIC, status); + b.add(u"engineering", STEM_ENGINEERING, status); + b.add(u"notation-simple", STEM_NOTATION_SIMPLE, status); + b.add(u"base-unit", STEM_BASE_UNIT, status); + b.add(u"percent", STEM_PERCENT, status); + b.add(u"permille", STEM_PERMILLE, status); + b.add(u"precision-integer", STEM_PRECISION_INTEGER, status); + b.add(u"precision-unlimited", STEM_PRECISION_UNLIMITED, status); + b.add(u"precision-currency-standard", STEM_PRECISION_CURRENCY_STANDARD, status); + b.add(u"precision-currency-cash", STEM_PRECISION_CURRENCY_CASH, status); + b.add(u"rounding-mode-ceiling", STEM_ROUNDING_MODE_CEILING, status); + b.add(u"rounding-mode-floor", STEM_ROUNDING_MODE_FLOOR, status); + b.add(u"rounding-mode-down", STEM_ROUNDING_MODE_DOWN, status); + b.add(u"rounding-mode-up", STEM_ROUNDING_MODE_UP, status); + b.add(u"rounding-mode-half-even", STEM_ROUNDING_MODE_HALF_EVEN, status); + b.add(u"rounding-mode-half-down", STEM_ROUNDING_MODE_HALF_DOWN, status); + b.add(u"rounding-mode-half-up", STEM_ROUNDING_MODE_HALF_UP, status); + b.add(u"rounding-mode-unnecessary", STEM_ROUNDING_MODE_UNNECESSARY, status); + b.add(u"group-off", STEM_GROUP_OFF, status); + b.add(u"group-min2", STEM_GROUP_MIN2, status); + b.add(u"group-auto", STEM_GROUP_AUTO, status); + b.add(u"group-on-aligned", STEM_GROUP_ON_ALIGNED, status); + b.add(u"group-thousands", STEM_GROUP_THOUSANDS, status); + b.add(u"latin", STEM_LATIN, status); + b.add(u"unit-width-narrow", STEM_UNIT_WIDTH_NARROW, status); + b.add(u"unit-width-short", STEM_UNIT_WIDTH_SHORT, status); + b.add(u"unit-width-full-name", STEM_UNIT_WIDTH_FULL_NAME, status); + b.add(u"unit-width-iso-code", STEM_UNIT_WIDTH_ISO_CODE, status); + b.add(u"unit-width-hidden", STEM_UNIT_WIDTH_HIDDEN, status); + b.add(u"sign-auto", STEM_SIGN_AUTO, status); + b.add(u"sign-always", STEM_SIGN_ALWAYS, status); + b.add(u"sign-never", STEM_SIGN_NEVER, status); + b.add(u"sign-accounting", STEM_SIGN_ACCOUNTING, status); + b.add(u"sign-accounting-always", STEM_SIGN_ACCOUNTING_ALWAYS, status); + b.add(u"sign-except-zero", STEM_SIGN_EXCEPT_ZERO, status); + b.add(u"sign-accounting-except-zero", STEM_SIGN_ACCOUNTING_EXCEPT_ZERO, status); + b.add(u"decimal-auto", STEM_DECIMAL_AUTO, status); + b.add(u"decimal-always", STEM_DECIMAL_ALWAYS, status); + if (U_FAILURE(status)) { return; } + + // Section 2: + b.add(u"precision-increment", STEM_PRECISION_INCREMENT, status); + b.add(u"measure-unit", STEM_MEASURE_UNIT, status); + b.add(u"per-measure-unit", STEM_PER_MEASURE_UNIT, status); + b.add(u"currency", STEM_CURRENCY, status); + b.add(u"integer-width", STEM_INTEGER_WIDTH, status); + b.add(u"numbering-system", STEM_NUMBERING_SYSTEM, status); + b.add(u"scale", STEM_SCALE, status); + if (U_FAILURE(status)) { return; } + + // Build the CharsTrie + // TODO: Use SLOW or FAST here? + UnicodeString result; + b.buildUnicodeString(USTRINGTRIE_BUILD_FAST, result, status); + if (U_FAILURE(status)) { return; } + + // Copy the result into the global constant pointer + size_t numBytes = result.length() * sizeof(char16_t); + kSerializedStemTrie = static_cast(uprv_malloc(numBytes)); + uprv_memcpy(kSerializedStemTrie, result.getBuffer(), numBytes); +} + + +inline void appendMultiple(UnicodeString& sb, UChar32 cp, int32_t count) { + for (int i = 0; i < count; i++) { + sb.append(cp); + } +} + + +#define CHECK_NULL(seen, field, status) (void)(seen); /* for auto-format line wrapping */ \ +{ \ + if ((seen).field) { \ + (status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \ + return STATE_NULL; \ + } \ + (seen).field = true; \ +} + + +#define SKELETON_UCHAR_TO_CHAR(dest, src, start, end, status) (void)(dest); \ +{ \ + UErrorCode conversionStatus = U_ZERO_ERROR; \ + (dest).appendInvariantChars({FALSE, (src).getBuffer() + (start), (end) - (start)}, conversionStatus); \ + if (conversionStatus == U_INVARIANT_CONVERSION_ERROR) { \ + /* Don't propagate the invariant conversion error; it is a skeleton syntax error */ \ + (status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \ + return; \ + } else if (U_FAILURE(conversionStatus)) { \ + (status) = conversionStatus; \ + return; \ + } \ +} + + +} // anonymous namespace + + +Notation stem_to_object::notation(skeleton::StemEnum stem) { + switch (stem) { + case STEM_COMPACT_SHORT: + return Notation::compactShort(); + case STEM_COMPACT_LONG: + return Notation::compactLong(); + case STEM_SCIENTIFIC: + return Notation::scientific(); + case STEM_ENGINEERING: + return Notation::engineering(); + case STEM_NOTATION_SIMPLE: + return Notation::simple(); + default: + U_ASSERT(false); + return Notation::simple(); // return a value: silence compiler warning + } +} + +MeasureUnit stem_to_object::unit(skeleton::StemEnum stem) { + switch (stem) { + case STEM_BASE_UNIT: + // Slicing is okay + return NoUnit::base(); // NOLINT + case STEM_PERCENT: + // Slicing is okay + return NoUnit::percent(); // NOLINT + case STEM_PERMILLE: + // Slicing is okay + return NoUnit::permille(); // NOLINT + default: + U_ASSERT(false); + return {}; // return a value: silence compiler warning + } +} + +Precision stem_to_object::precision(skeleton::StemEnum stem) { + switch (stem) { + case STEM_PRECISION_INTEGER: + return Precision::integer(); + case STEM_PRECISION_UNLIMITED: + return Precision::unlimited(); + case STEM_PRECISION_CURRENCY_STANDARD: + return Precision::currency(UCURR_USAGE_STANDARD); + case STEM_PRECISION_CURRENCY_CASH: + return Precision::currency(UCURR_USAGE_CASH); + default: + U_ASSERT(false); + return Precision::integer(); // return a value: silence compiler warning + } +} + +UNumberFormatRoundingMode stem_to_object::roundingMode(skeleton::StemEnum stem) { + switch (stem) { + case STEM_ROUNDING_MODE_CEILING: + return UNUM_ROUND_CEILING; + case STEM_ROUNDING_MODE_FLOOR: + return UNUM_ROUND_FLOOR; + case STEM_ROUNDING_MODE_DOWN: + return UNUM_ROUND_DOWN; + case STEM_ROUNDING_MODE_UP: + return UNUM_ROUND_UP; + case STEM_ROUNDING_MODE_HALF_EVEN: + return UNUM_ROUND_HALFEVEN; + case STEM_ROUNDING_MODE_HALF_DOWN: + return UNUM_ROUND_HALFDOWN; + case STEM_ROUNDING_MODE_HALF_UP: + return UNUM_ROUND_HALFUP; + case STEM_ROUNDING_MODE_UNNECESSARY: + return UNUM_ROUND_UNNECESSARY; + default: + U_ASSERT(false); + return UNUM_ROUND_UNNECESSARY; + } +} + +UGroupingStrategy stem_to_object::groupingStrategy(skeleton::StemEnum stem) { + switch (stem) { + case STEM_GROUP_OFF: + return UNUM_GROUPING_OFF; + case STEM_GROUP_MIN2: + return UNUM_GROUPING_MIN2; + case STEM_GROUP_AUTO: + return UNUM_GROUPING_AUTO; + case STEM_GROUP_ON_ALIGNED: + return UNUM_GROUPING_ON_ALIGNED; + case STEM_GROUP_THOUSANDS: + return UNUM_GROUPING_THOUSANDS; + default: + return UNUM_GROUPING_COUNT; // for objects, throw; for enums, return COUNT + } +} + +UNumberUnitWidth stem_to_object::unitWidth(skeleton::StemEnum stem) { + switch (stem) { + case STEM_UNIT_WIDTH_NARROW: + return UNUM_UNIT_WIDTH_NARROW; + case STEM_UNIT_WIDTH_SHORT: + return UNUM_UNIT_WIDTH_SHORT; + case STEM_UNIT_WIDTH_FULL_NAME: + return UNUM_UNIT_WIDTH_FULL_NAME; + case STEM_UNIT_WIDTH_ISO_CODE: + return UNUM_UNIT_WIDTH_ISO_CODE; + case STEM_UNIT_WIDTH_HIDDEN: + return UNUM_UNIT_WIDTH_HIDDEN; + default: + return UNUM_UNIT_WIDTH_COUNT; // for objects, throw; for enums, return COUNT + } +} + +UNumberSignDisplay stem_to_object::signDisplay(skeleton::StemEnum stem) { + switch (stem) { + case STEM_SIGN_AUTO: + return UNUM_SIGN_AUTO; + case STEM_SIGN_ALWAYS: + return UNUM_SIGN_ALWAYS; + case STEM_SIGN_NEVER: + return UNUM_SIGN_NEVER; + case STEM_SIGN_ACCOUNTING: + return UNUM_SIGN_ACCOUNTING; + case STEM_SIGN_ACCOUNTING_ALWAYS: + return UNUM_SIGN_ACCOUNTING_ALWAYS; + case STEM_SIGN_EXCEPT_ZERO: + return UNUM_SIGN_EXCEPT_ZERO; + case STEM_SIGN_ACCOUNTING_EXCEPT_ZERO: + return UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO; + default: + return UNUM_SIGN_COUNT; // for objects, throw; for enums, return COUNT + } +} + +UNumberDecimalSeparatorDisplay stem_to_object::decimalSeparatorDisplay(skeleton::StemEnum stem) { + switch (stem) { + case STEM_DECIMAL_AUTO: + return UNUM_DECIMAL_SEPARATOR_AUTO; + case STEM_DECIMAL_ALWAYS: + return UNUM_DECIMAL_SEPARATOR_ALWAYS; + default: + return UNUM_DECIMAL_SEPARATOR_COUNT; // for objects, throw; for enums, return COUNT + } +} + + +void enum_to_stem_string::roundingMode(UNumberFormatRoundingMode value, UnicodeString& sb) { + switch (value) { + case UNUM_ROUND_CEILING: + sb.append(u"rounding-mode-ceiling", -1); + break; + case UNUM_ROUND_FLOOR: + sb.append(u"rounding-mode-floor", -1); + break; + case UNUM_ROUND_DOWN: + sb.append(u"rounding-mode-down", -1); + break; + case UNUM_ROUND_UP: + sb.append(u"rounding-mode-up", -1); + break; + case UNUM_ROUND_HALFEVEN: + sb.append(u"rounding-mode-half-even", -1); + break; + case UNUM_ROUND_HALFDOWN: + sb.append(u"rounding-mode-half-down", -1); + break; + case UNUM_ROUND_HALFUP: + sb.append(u"rounding-mode-half-up", -1); + break; + case UNUM_ROUND_UNNECESSARY: + sb.append(u"rounding-mode-unnecessary", -1); + break; + default: + U_ASSERT(false); + } +} + +void enum_to_stem_string::groupingStrategy(UGroupingStrategy value, UnicodeString& sb) { + switch (value) { + case UNUM_GROUPING_OFF: + sb.append(u"group-off", -1); + break; + case UNUM_GROUPING_MIN2: + sb.append(u"group-min2", -1); + break; + case UNUM_GROUPING_AUTO: + sb.append(u"group-auto", -1); + break; + case UNUM_GROUPING_ON_ALIGNED: + sb.append(u"group-on-aligned", -1); + break; + case UNUM_GROUPING_THOUSANDS: + sb.append(u"group-thousands", -1); + break; + default: + U_ASSERT(false); + } +} + +void enum_to_stem_string::unitWidth(UNumberUnitWidth value, UnicodeString& sb) { + switch (value) { + case UNUM_UNIT_WIDTH_NARROW: + sb.append(u"unit-width-narrow", -1); + break; + case UNUM_UNIT_WIDTH_SHORT: + sb.append(u"unit-width-short", -1); + break; + case UNUM_UNIT_WIDTH_FULL_NAME: + sb.append(u"unit-width-full-name", -1); + break; + case UNUM_UNIT_WIDTH_ISO_CODE: + sb.append(u"unit-width-iso-code", -1); + break; + case UNUM_UNIT_WIDTH_HIDDEN: + sb.append(u"unit-width-hidden", -1); + break; + default: + U_ASSERT(false); + } +} + +void enum_to_stem_string::signDisplay(UNumberSignDisplay value, UnicodeString& sb) { + switch (value) { + case UNUM_SIGN_AUTO: + sb.append(u"sign-auto", -1); + break; + case UNUM_SIGN_ALWAYS: + sb.append(u"sign-always", -1); + break; + case UNUM_SIGN_NEVER: + sb.append(u"sign-never", -1); + break; + case UNUM_SIGN_ACCOUNTING: + sb.append(u"sign-accounting", -1); + break; + case UNUM_SIGN_ACCOUNTING_ALWAYS: + sb.append(u"sign-accounting-always", -1); + break; + case UNUM_SIGN_EXCEPT_ZERO: + sb.append(u"sign-except-zero", -1); + break; + case UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO: + sb.append(u"sign-accounting-except-zero", -1); + break; + default: + U_ASSERT(false); + } +} + +void +enum_to_stem_string::decimalSeparatorDisplay(UNumberDecimalSeparatorDisplay value, UnicodeString& sb) { + switch (value) { + case UNUM_DECIMAL_SEPARATOR_AUTO: + sb.append(u"decimal-auto", -1); + break; + case UNUM_DECIMAL_SEPARATOR_ALWAYS: + sb.append(u"decimal-always", -1); + break; + default: + U_ASSERT(false); + } +} + + +UnlocalizedNumberFormatter skeleton::create(const UnicodeString& skeletonString, UErrorCode& status) { + umtx_initOnce(gNumberSkeletonsInitOnce, &initNumberSkeletons, status); + MacroProps macros = parseSkeleton(skeletonString, status); + return NumberFormatter::with().macros(macros); +} + +UnicodeString skeleton::generate(const MacroProps& macros, UErrorCode& status) { + umtx_initOnce(gNumberSkeletonsInitOnce, &initNumberSkeletons, status); + UnicodeString sb; + GeneratorHelpers::generateSkeleton(macros, sb, status); + return sb; +} + +MacroProps skeleton::parseSkeleton(const UnicodeString& skeletonString, UErrorCode& status) { + if (U_FAILURE(status)) { return MacroProps(); } + + // Add a trailing whitespace to the end of the skeleton string to make code cleaner. + UnicodeString tempSkeletonString(skeletonString); + tempSkeletonString.append(u' '); + + SeenMacroProps seen; + MacroProps macros; + StringSegment segment(tempSkeletonString, false); + UCharsTrie stemTrie(kSerializedStemTrie); + ParseState stem = STATE_NULL; + int32_t offset = 0; + + // Primary skeleton parse loop: + while (offset < segment.length()) { + UChar32 cp = segment.codePointAt(offset); + bool isTokenSeparator = PatternProps::isWhiteSpace(cp); + bool isOptionSeparator = (cp == u'/'); + + if (!isTokenSeparator && !isOptionSeparator) { + // Non-separator token; consume it. + offset += U16_LENGTH(cp); + if (stem == STATE_NULL) { + // We are currently consuming a stem. + // Go to the next state in the stem trie. + stemTrie.nextForCodePoint(cp); + } + continue; + } + + // We are looking at a token or option separator. + // If the segment is nonempty, parse it and reset the segment. + // Otherwise, make sure it is a valid repeating separator. + if (offset != 0) { + segment.setLength(offset); + if (stem == STATE_NULL) { + // The first separator after the start of a token. Parse it as a stem. + stem = parseStem(segment, stemTrie, seen, macros, status); + stemTrie.reset(); + } else { + // A separator after the first separator of a token. Parse it as an option. + stem = parseOption(stem, segment, macros, status); + } + segment.resetLength(); + if (U_FAILURE(status)) { return macros; } + + // Consume the segment: + segment.adjustOffset(offset); + offset = 0; + + } else if (stem != STATE_NULL) { + // A separator ('/' or whitespace) following an option separator ('/') + // segment.setLength(U16_LENGTH(cp)); // for error message + // throw new SkeletonSyntaxException("Unexpected separator character", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return macros; + + } else { + // Two spaces in a row; this is OK. + } + + // Does the current stem forbid options? + if (isOptionSeparator && stem == STATE_NULL) { + // segment.setLength(U16_LENGTH(cp)); // for error message + // throw new SkeletonSyntaxException("Unexpected option separator", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return macros; + } + + // Does the current stem require an option? + if (isTokenSeparator && stem != STATE_NULL) { + switch (stem) { + case STATE_INCREMENT_PRECISION: + case STATE_MEASURE_UNIT: + case STATE_PER_MEASURE_UNIT: + case STATE_CURRENCY_UNIT: + case STATE_INTEGER_WIDTH: + case STATE_NUMBERING_SYSTEM: + case STATE_SCALE: + // segment.setLength(U16_LENGTH(cp)); // for error message + // throw new SkeletonSyntaxException("Stem requires an option", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return macros; + default: + break; + } + stem = STATE_NULL; + } + + // Consume the separator: + segment.adjustOffset(U16_LENGTH(cp)); + } + U_ASSERT(stem == STATE_NULL); + return macros; +} + +ParseState +skeleton::parseStem(const StringSegment& segment, const UCharsTrie& stemTrie, SeenMacroProps& seen, + MacroProps& macros, UErrorCode& status) { + // First check for "blueprint" stems, which start with a "signal char" + switch (segment.charAt(0)) { + case u'.': + CHECK_NULL(seen, precision, status); + blueprint_helpers::parseFractionStem(segment, macros, status); + return STATE_FRACTION_PRECISION; + case u'@': + CHECK_NULL(seen, precision, status); + blueprint_helpers::parseDigitsStem(segment, macros, status); + return STATE_NULL; + default: + break; + } + + // Now look at the stemsTrie, which is already be pointing at our stem. + UStringTrieResult stemResult = stemTrie.current(); + + if (stemResult != USTRINGTRIE_INTERMEDIATE_VALUE && stemResult != USTRINGTRIE_FINAL_VALUE) { + // throw new SkeletonSyntaxException("Unknown stem", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return STATE_NULL; + } + + auto stem = static_cast(stemTrie.getValue()); + switch (stem) { + + // Stems with meaning on their own, not requiring an option: + + case STEM_COMPACT_SHORT: + case STEM_COMPACT_LONG: + case STEM_SCIENTIFIC: + case STEM_ENGINEERING: + case STEM_NOTATION_SIMPLE: + CHECK_NULL(seen, notation, status); + macros.notation = stem_to_object::notation(stem); + switch (stem) { + case STEM_SCIENTIFIC: + case STEM_ENGINEERING: + return STATE_SCIENTIFIC; // allows for scientific options + default: + return STATE_NULL; + } + + case STEM_BASE_UNIT: + case STEM_PERCENT: + case STEM_PERMILLE: + CHECK_NULL(seen, unit, status); + macros.unit = stem_to_object::unit(stem); + return STATE_NULL; + + case STEM_PRECISION_INTEGER: + case STEM_PRECISION_UNLIMITED: + case STEM_PRECISION_CURRENCY_STANDARD: + case STEM_PRECISION_CURRENCY_CASH: + CHECK_NULL(seen, precision, status); + macros.precision = stem_to_object::precision(stem); + switch (stem) { + case STEM_PRECISION_INTEGER: + return STATE_FRACTION_PRECISION; // allows for "precision-integer/@##" + default: + return STATE_NULL; + } + + case STEM_ROUNDING_MODE_CEILING: + case STEM_ROUNDING_MODE_FLOOR: + case STEM_ROUNDING_MODE_DOWN: + case STEM_ROUNDING_MODE_UP: + case STEM_ROUNDING_MODE_HALF_EVEN: + case STEM_ROUNDING_MODE_HALF_DOWN: + case STEM_ROUNDING_MODE_HALF_UP: + case STEM_ROUNDING_MODE_UNNECESSARY: + CHECK_NULL(seen, roundingMode, status); + macros.roundingMode = stem_to_object::roundingMode(stem); + return STATE_NULL; + + case STEM_GROUP_OFF: + case STEM_GROUP_MIN2: + case STEM_GROUP_AUTO: + case STEM_GROUP_ON_ALIGNED: + case STEM_GROUP_THOUSANDS: + CHECK_NULL(seen, grouper, status); + macros.grouper = Grouper::forStrategy(stem_to_object::groupingStrategy(stem)); + return STATE_NULL; + + case STEM_LATIN: + CHECK_NULL(seen, symbols, status); + macros.symbols.setTo(NumberingSystem::createInstanceByName("latn", status)); + return STATE_NULL; + + case STEM_UNIT_WIDTH_NARROW: + case STEM_UNIT_WIDTH_SHORT: + case STEM_UNIT_WIDTH_FULL_NAME: + case STEM_UNIT_WIDTH_ISO_CODE: + case STEM_UNIT_WIDTH_HIDDEN: + CHECK_NULL(seen, unitWidth, status); + macros.unitWidth = stem_to_object::unitWidth(stem); + return STATE_NULL; + + case STEM_SIGN_AUTO: + case STEM_SIGN_ALWAYS: + case STEM_SIGN_NEVER: + case STEM_SIGN_ACCOUNTING: + case STEM_SIGN_ACCOUNTING_ALWAYS: + case STEM_SIGN_EXCEPT_ZERO: + case STEM_SIGN_ACCOUNTING_EXCEPT_ZERO: + CHECK_NULL(seen, sign, status); + macros.sign = stem_to_object::signDisplay(stem); + return STATE_NULL; + + case STEM_DECIMAL_AUTO: + case STEM_DECIMAL_ALWAYS: + CHECK_NULL(seen, decimal, status); + macros.decimal = stem_to_object::decimalSeparatorDisplay(stem); + return STATE_NULL; + + // Stems requiring an option: + + case STEM_PRECISION_INCREMENT: + CHECK_NULL(seen, precision, status); + return STATE_INCREMENT_PRECISION; + + case STEM_MEASURE_UNIT: + CHECK_NULL(seen, unit, status); + return STATE_MEASURE_UNIT; + + case STEM_PER_MEASURE_UNIT: + CHECK_NULL(seen, perUnit, status); + return STATE_PER_MEASURE_UNIT; + + case STEM_CURRENCY: + CHECK_NULL(seen, unit, status); + return STATE_CURRENCY_UNIT; + + case STEM_INTEGER_WIDTH: + CHECK_NULL(seen, integerWidth, status); + return STATE_INTEGER_WIDTH; + + case STEM_NUMBERING_SYSTEM: + CHECK_NULL(seen, symbols, status); + return STATE_NUMBERING_SYSTEM; + + case STEM_SCALE: + CHECK_NULL(seen, scale, status); + return STATE_SCALE; + + default: + U_ASSERT(false); + return STATE_NULL; // return a value: silence compiler warning + } +} + +ParseState skeleton::parseOption(ParseState stem, const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + + ///// Required options: ///// + + switch (stem) { + case STATE_CURRENCY_UNIT: + blueprint_helpers::parseCurrencyOption(segment, macros, status); + return STATE_NULL; + case STATE_MEASURE_UNIT: + blueprint_helpers::parseMeasureUnitOption(segment, macros, status); + return STATE_NULL; + case STATE_PER_MEASURE_UNIT: + blueprint_helpers::parseMeasurePerUnitOption(segment, macros, status); + return STATE_NULL; + case STATE_INCREMENT_PRECISION: + blueprint_helpers::parseIncrementOption(segment, macros, status); + return STATE_NULL; + case STATE_INTEGER_WIDTH: + blueprint_helpers::parseIntegerWidthOption(segment, macros, status); + return STATE_NULL; + case STATE_NUMBERING_SYSTEM: + blueprint_helpers::parseNumberingSystemOption(segment, macros, status); + return STATE_NULL; + case STATE_SCALE: + blueprint_helpers::parseScaleOption(segment, macros, status); + return STATE_NULL; + default: + break; + } + + ///// Non-required options: ///// + + // Scientific options + switch (stem) { + case STATE_SCIENTIFIC: + if (blueprint_helpers::parseExponentWidthOption(segment, macros, status)) { + return STATE_SCIENTIFIC; + } + if (U_FAILURE(status)) { + return {}; + } + if (blueprint_helpers::parseExponentSignOption(segment, macros, status)) { + return STATE_SCIENTIFIC; + } + if (U_FAILURE(status)) { + return {}; + } + break; + default: + break; + } + + // Frac-sig option + switch (stem) { + case STATE_FRACTION_PRECISION: + if (blueprint_helpers::parseFracSigOption(segment, macros, status)) { + return STATE_NULL; + } + if (U_FAILURE(status)) { + return {}; + } + break; + default: + break; + } + + // Unknown option + // throw new SkeletonSyntaxException("Invalid option", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return STATE_NULL; +} + +void GeneratorHelpers::generateSkeleton(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + if (U_FAILURE(status)) { return; } + + // Supported options + if (GeneratorHelpers::notation(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::unit(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::perUnit(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::precision(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::roundingMode(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::grouping(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::integerWidth(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::symbols(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::unitWidth(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::sign(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::decimal(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + if (GeneratorHelpers::scale(macros, sb, status)) { + sb.append(u' '); + } + if (U_FAILURE(status)) { return; } + + // Unsupported options + if (!macros.padder.isBogus()) { + status = U_UNSUPPORTED_ERROR; + return; + } + if (macros.affixProvider != nullptr) { + status = U_UNSUPPORTED_ERROR; + return; + } + if (macros.rules != nullptr) { + status = U_UNSUPPORTED_ERROR; + return; + } + if (macros.currencySymbols != nullptr) { + status = U_UNSUPPORTED_ERROR; + return; + } + + // Remove the trailing space + if (sb.length() > 0) { + sb.truncate(sb.length() - 1); + } +} + + +bool blueprint_helpers::parseExponentWidthOption(const StringSegment& segment, MacroProps& macros, + UErrorCode&) { + if (segment.charAt(0) != u'+') { + return false; + } + int32_t offset = 1; + int32_t minExp = 0; + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'e') { + minExp++; + } else { + break; + } + } + if (offset < segment.length()) { + return false; + } + // Use the public APIs to enforce bounds checking + macros.notation = static_cast(macros.notation).withMinExponentDigits(minExp); + return true; +} + +void +blueprint_helpers::generateExponentWidthOption(int32_t minExponentDigits, UnicodeString& sb, UErrorCode&) { + sb.append(u'+'); + appendMultiple(sb, u'e', minExponentDigits); +} + +bool +blueprint_helpers::parseExponentSignOption(const StringSegment& segment, MacroProps& macros, UErrorCode&) { + // Get the sign display type out of the CharsTrie data structure. + UCharsTrie tempStemTrie(kSerializedStemTrie); + UStringTrieResult result = tempStemTrie.next( + segment.toTempUnicodeString().getBuffer(), + segment.length()); + if (result != USTRINGTRIE_INTERMEDIATE_VALUE && result != USTRINGTRIE_FINAL_VALUE) { + return false; + } + auto sign = stem_to_object::signDisplay(static_cast(tempStemTrie.getValue())); + if (sign == UNUM_SIGN_COUNT) { + return false; + } + macros.notation = static_cast(macros.notation).withExponentSignDisplay(sign); + return true; +} + +void blueprint_helpers::parseCurrencyOption(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + // Unlike ICU4J, have to check length manually because ICU4C CurrencyUnit does not check it for us + if (segment.length() != 3) { + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + const UChar* currencyCode = segment.toTempUnicodeString().getBuffer(); + UErrorCode localStatus = U_ZERO_ERROR; + CurrencyUnit currency(currencyCode, localStatus); + if (U_FAILURE(localStatus)) { + // Not 3 ascii chars + // throw new SkeletonSyntaxException("Invalid currency", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + // Slicing is OK + macros.unit = currency; // NOLINT +} + +void +blueprint_helpers::generateCurrencyOption(const CurrencyUnit& currency, UnicodeString& sb, UErrorCode&) { + sb.append(currency.getISOCurrency(), -1); +} + +void blueprint_helpers::parseMeasureUnitOption(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + const UnicodeString stemString = segment.toTempUnicodeString(); + + // NOTE: The category (type) of the unit is guaranteed to be a valid subtag (alphanumeric) + // http://unicode.org/reports/tr35/#Validity_Data + int firstHyphen = 0; + while (firstHyphen < stemString.length() && stemString.charAt(firstHyphen) != '-') { + firstHyphen++; + } + if (firstHyphen == stemString.length()) { + // throw new SkeletonSyntaxException("Invalid measure unit option", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + + // Need to do char <-> UChar conversion... + U_ASSERT(U_SUCCESS(status)); + CharString type; + SKELETON_UCHAR_TO_CHAR(type, stemString, 0, firstHyphen, status); + CharString subType; + SKELETON_UCHAR_TO_CHAR(subType, stemString, firstHyphen + 1, stemString.length(), status); + + // Note: the largest type as of this writing (March 2018) is "volume", which has 24 units. + static constexpr int32_t CAPACITY = 30; + MeasureUnit units[CAPACITY]; + UErrorCode localStatus = U_ZERO_ERROR; + int32_t numUnits = MeasureUnit::getAvailable(type.data(), units, CAPACITY, localStatus); + if (U_FAILURE(localStatus)) { + // More than 30 units in this type? + status = U_INTERNAL_PROGRAM_ERROR; + return; + } + for (int32_t i = 0; i < numUnits; i++) { + auto& unit = units[i]; + if (uprv_strcmp(subType.data(), unit.getSubtype()) == 0) { + macros.unit = unit; + return; + } + } + + // throw new SkeletonSyntaxException("Unknown measure unit", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; +} + +void blueprint_helpers::generateMeasureUnitOption(const MeasureUnit& measureUnit, UnicodeString& sb, + UErrorCode&) { + // Need to do char <-> UChar conversion... + sb.append(UnicodeString(measureUnit.getType(), -1, US_INV)); + sb.append(u'-'); + sb.append(UnicodeString(measureUnit.getSubtype(), -1, US_INV)); +} + +void blueprint_helpers::parseMeasurePerUnitOption(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + // A little bit of a hack: safe the current unit (numerator), call the main measure unit + // parsing code, put back the numerator unit, and put the new unit into per-unit. + MeasureUnit numerator = macros.unit; + parseMeasureUnitOption(segment, macros, status); + if (U_FAILURE(status)) { return; } + macros.perUnit = macros.unit; + macros.unit = numerator; +} + +void blueprint_helpers::parseFractionStem(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + U_ASSERT(segment.charAt(0) == u'.'); + int32_t offset = 1; + int32_t minFrac = 0; + int32_t maxFrac; + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'0') { + minFrac++; + } else { + break; + } + } + if (offset < segment.length()) { + if (segment.charAt(offset) == u'+') { + maxFrac = -1; + offset++; + } else { + maxFrac = minFrac; + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'#') { + maxFrac++; + } else { + break; + } + } + } + } else { + maxFrac = minFrac; + } + if (offset < segment.length()) { + // throw new SkeletonSyntaxException("Invalid fraction stem", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + // Use the public APIs to enforce bounds checking + if (maxFrac == -1) { + macros.precision = Precision::minFraction(minFrac); + } else { + macros.precision = Precision::minMaxFraction(minFrac, maxFrac); + } +} + +void +blueprint_helpers::generateFractionStem(int32_t minFrac, int32_t maxFrac, UnicodeString& sb, UErrorCode&) { + if (minFrac == 0 && maxFrac == 0) { + sb.append(u"precision-integer", -1); + return; + } + sb.append(u'.'); + appendMultiple(sb, u'0', minFrac); + if (maxFrac == -1) { + sb.append(u'+'); + } else { + appendMultiple(sb, u'#', maxFrac - minFrac); + } +} + +void +blueprint_helpers::parseDigitsStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status) { + U_ASSERT(segment.charAt(0) == u'@'); + int offset = 0; + int minSig = 0; + int maxSig; + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'@') { + minSig++; + } else { + break; + } + } + if (offset < segment.length()) { + if (segment.charAt(offset) == u'+') { + maxSig = -1; + offset++; + } else { + maxSig = minSig; + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'#') { + maxSig++; + } else { + break; + } + } + } + } else { + maxSig = minSig; + } + if (offset < segment.length()) { + // throw new SkeletonSyntaxException("Invalid significant digits stem", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + // Use the public APIs to enforce bounds checking + if (maxSig == -1) { + macros.precision = Precision::minSignificantDigits(minSig); + } else { + macros.precision = Precision::minMaxSignificantDigits(minSig, maxSig); + } +} + +void +blueprint_helpers::generateDigitsStem(int32_t minSig, int32_t maxSig, UnicodeString& sb, UErrorCode&) { + appendMultiple(sb, u'@', minSig); + if (maxSig == -1) { + sb.append(u'+'); + } else { + appendMultiple(sb, u'#', maxSig - minSig); + } +} + +bool blueprint_helpers::parseFracSigOption(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + if (segment.charAt(0) != u'@') { + return false; + } + int offset = 0; + int minSig = 0; + int maxSig; + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'@') { + minSig++; + } else { + break; + } + } + // For the frac-sig option, there must be minSig or maxSig but not both. + // Valid: @+, @@+, @@@+ + // Valid: @#, @##, @### + // Invalid: @, @@, @@@ + // Invalid: @@#, @@##, @@@# + if (offset < segment.length()) { + if (segment.charAt(offset) == u'+') { + maxSig = -1; + offset++; + } else if (minSig > 1) { + // @@#, @@##, @@@# + // throw new SkeletonSyntaxException("Invalid digits option for fraction rounder", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return false; + } else { + maxSig = minSig; + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'#') { + maxSig++; + } else { + break; + } + } + } + } else { + // @, @@, @@@ + // throw new SkeletonSyntaxException("Invalid digits option for fraction rounder", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return false; + } + if (offset < segment.length()) { + // throw new SkeletonSyntaxException("Invalid digits option for fraction rounder", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return false; + } + + auto& oldPrecision = static_cast(macros.precision); + if (maxSig == -1) { + macros.precision = oldPrecision.withMinDigits(minSig); + } else { + macros.precision = oldPrecision.withMaxDigits(maxSig); + } + return true; +} + +void blueprint_helpers::parseIncrementOption(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + // Need to do char <-> UChar conversion... + U_ASSERT(U_SUCCESS(status)); + CharString buffer; + SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status); + + // Utilize DecimalQuantity/decNumber to parse this for us. + DecimalQuantity dq; + UErrorCode localStatus = U_ZERO_ERROR; + dq.setToDecNumber({buffer.data(), buffer.length()}, localStatus); + if (U_FAILURE(localStatus)) { + // throw new SkeletonSyntaxException("Invalid rounding increment", segment, e); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + double increment = dq.toDouble(); + + // We also need to figure out how many digits. Do a brute force string operation. + int decimalOffset = 0; + while (decimalOffset < segment.length() && segment.charAt(decimalOffset) != '.') { + decimalOffset++; + } + if (decimalOffset == segment.length()) { + macros.precision = Precision::increment(increment); + } else { + int32_t fractionLength = segment.length() - decimalOffset - 1; + macros.precision = Precision::increment(increment).withMinFraction(fractionLength); + } +} + +void blueprint_helpers::generateIncrementOption(double increment, int32_t trailingZeros, UnicodeString& sb, + UErrorCode&) { + // Utilize DecimalQuantity/double_conversion to format this for us. + DecimalQuantity dq; + dq.setToDouble(increment); + dq.roundToInfinity(); + sb.append(dq.toPlainString()); + + // We might need to append extra trailing zeros for min fraction... + if (trailingZeros > 0) { + appendMultiple(sb, u'0', trailingZeros); + } +} + +void blueprint_helpers::parseIntegerWidthOption(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + int32_t offset = 0; + int32_t minInt = 0; + int32_t maxInt; + if (segment.charAt(0) == u'+') { + maxInt = -1; + offset++; + } else { + maxInt = 0; + } + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'#') { + maxInt++; + } else { + break; + } + } + if (offset < segment.length()) { + for (; offset < segment.length(); offset++) { + if (segment.charAt(offset) == u'0') { + minInt++; + } else { + break; + } + } + } + if (maxInt != -1) { + maxInt += minInt; + } + if (offset < segment.length()) { + // throw new SkeletonSyntaxException("Invalid integer width stem", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + // Use the public APIs to enforce bounds checking + if (maxInt == -1) { + macros.integerWidth = IntegerWidth::zeroFillTo(minInt); + } else { + macros.integerWidth = IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt); + } +} + +void blueprint_helpers::generateIntegerWidthOption(int32_t minInt, int32_t maxInt, UnicodeString& sb, + UErrorCode&) { + if (maxInt == -1) { + sb.append(u'+'); + } else { + appendMultiple(sb, u'#', maxInt - minInt); + } + appendMultiple(sb, u'0', minInt); +} + +void blueprint_helpers::parseNumberingSystemOption(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + // Need to do char <-> UChar conversion... + U_ASSERT(U_SUCCESS(status)); + CharString buffer; + SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status); + + NumberingSystem* ns = NumberingSystem::createInstanceByName(buffer.data(), status); + if (ns == nullptr || U_FAILURE(status)) { + // This is a skeleton syntax error; don't bubble up the low-level NumberingSystem error + // throw new SkeletonSyntaxException("Unknown numbering system", segment); + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + macros.symbols.setTo(ns); +} + +void blueprint_helpers::generateNumberingSystemOption(const NumberingSystem& ns, UnicodeString& sb, + UErrorCode&) { + // Need to do char <-> UChar conversion... + sb.append(UnicodeString(ns.getName(), -1, US_INV)); +} + +void blueprint_helpers::parseScaleOption(const StringSegment& segment, MacroProps& macros, + UErrorCode& status) { + // Need to do char <-> UChar conversion... + U_ASSERT(U_SUCCESS(status)); + CharString buffer; + SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status); + + LocalPointer decnum(new DecNum(), status); + if (U_FAILURE(status)) { return; } + decnum->setTo({buffer.data(), buffer.length()}, status); + if (U_FAILURE(status)) { + // This is a skeleton syntax error; don't let the low-level decnum error bubble up + status = U_NUMBER_SKELETON_SYNTAX_ERROR; + return; + } + + // NOTE: The constructor will optimize the decnum for us if possible. + macros.scale = {0, decnum.orphan()}; +} + +void blueprint_helpers::generateScaleOption(int32_t magnitude, const DecNum* arbitrary, UnicodeString& sb, + UErrorCode& status) { + // Utilize DecimalQuantity/double_conversion to format this for us. + DecimalQuantity dq; + if (arbitrary != nullptr) { + dq.setToDecNum(*arbitrary, status); + if (U_FAILURE(status)) { return; } + } else { + dq.setToInt(1); + } + dq.adjustMagnitude(magnitude); + dq.roundToInfinity(); + sb.append(dq.toPlainString()); +} + + +bool GeneratorHelpers::notation(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + if (macros.notation.fType == Notation::NTN_COMPACT) { + UNumberCompactStyle style = macros.notation.fUnion.compactStyle; + if (style == UNumberCompactStyle::UNUM_LONG) { + sb.append(u"compact-long", -1); + return true; + } else if (style == UNumberCompactStyle::UNUM_SHORT) { + sb.append(u"compact-short", -1); + return true; + } else { + // Compact notation generated from custom data (not supported in skeleton) + // The other compact notations are literals + status = U_UNSUPPORTED_ERROR; + return false; + } + } else if (macros.notation.fType == Notation::NTN_SCIENTIFIC) { + const Notation::ScientificSettings& impl = macros.notation.fUnion.scientific; + if (impl.fEngineeringInterval == 3) { + sb.append(u"engineering", -1); + } else { + sb.append(u"scientific", -1); + } + if (impl.fMinExponentDigits > 1) { + sb.append(u'/'); + blueprint_helpers::generateExponentWidthOption(impl.fMinExponentDigits, sb, status); + if (U_FAILURE(status)) { + return false; + } + } + if (impl.fExponentSignDisplay != UNUM_SIGN_AUTO) { + sb.append(u'/'); + enum_to_stem_string::signDisplay(impl.fExponentSignDisplay, sb); + } + return true; + } else { + // Default value is not shown in normalized form + return false; + } +} + +bool GeneratorHelpers::unit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + if (utils::unitIsCurrency(macros.unit)) { + sb.append(u"currency/", -1); + CurrencyUnit currency(macros.unit, status); + if (U_FAILURE(status)) { + return false; + } + blueprint_helpers::generateCurrencyOption(currency, sb, status); + return true; + } else if (utils::unitIsNoUnit(macros.unit)) { + if (utils::unitIsPercent(macros.unit)) { + sb.append(u"percent", -1); + return true; + } else if (utils::unitIsPermille(macros.unit)) { + sb.append(u"permille", -1); + return true; + } else { + // Default value is not shown in normalized form + return false; + } + } else { + sb.append(u"measure-unit/", -1); + blueprint_helpers::generateMeasureUnitOption(macros.unit, sb, status); + return true; + } +} + +bool GeneratorHelpers::perUnit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + // Per-units are currently expected to be only MeasureUnits. + if (utils::unitIsNoUnit(macros.perUnit)) { + if (utils::unitIsPercent(macros.perUnit) || utils::unitIsPermille(macros.perUnit)) { + status = U_UNSUPPORTED_ERROR; + return false; + } else { + // Default value: ok to ignore + return false; + } + } else if (utils::unitIsCurrency(macros.perUnit)) { + status = U_UNSUPPORTED_ERROR; + return false; + } else { + sb.append(u"per-measure-unit/", -1); + blueprint_helpers::generateMeasureUnitOption(macros.perUnit, sb, status); + return true; + } +} + +bool GeneratorHelpers::precision(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + if (macros.precision.fType == Precision::RND_NONE) { + sb.append(u"precision-unlimited", -1); + } else if (macros.precision.fType == Precision::RND_FRACTION) { + const Precision::FractionSignificantSettings& impl = macros.precision.fUnion.fracSig; + blueprint_helpers::generateFractionStem(impl.fMinFrac, impl.fMaxFrac, sb, status); + } else if (macros.precision.fType == Precision::RND_SIGNIFICANT) { + const Precision::FractionSignificantSettings& impl = macros.precision.fUnion.fracSig; + blueprint_helpers::generateDigitsStem(impl.fMinSig, impl.fMaxSig, sb, status); + } else if (macros.precision.fType == Precision::RND_FRACTION_SIGNIFICANT) { + const Precision::FractionSignificantSettings& impl = macros.precision.fUnion.fracSig; + blueprint_helpers::generateFractionStem(impl.fMinFrac, impl.fMaxFrac, sb, status); + sb.append(u'/'); + if (impl.fMinSig == -1) { + blueprint_helpers::generateDigitsStem(1, impl.fMaxSig, sb, status); + } else { + blueprint_helpers::generateDigitsStem(impl.fMinSig, -1, sb, status); + } + } else if (macros.precision.fType == Precision::RND_INCREMENT) { + const Precision::IncrementSettings& impl = macros.precision.fUnion.increment; + sb.append(u"precision-increment/", -1); + blueprint_helpers::generateIncrementOption( + impl.fIncrement, + impl.fMinFrac - impl.fMaxFrac, + sb, + status); + } else if (macros.precision.fType == Precision::RND_CURRENCY) { + UCurrencyUsage usage = macros.precision.fUnion.currencyUsage; + if (usage == UCURR_USAGE_STANDARD) { + sb.append(u"precision-currency-standard", -1); + } else { + sb.append(u"precision-currency-cash", -1); + } + } else { + // Bogus or Error + return false; + } + + // NOTE: Always return true for rounding because the default value depends on other options. + return true; +} + +bool GeneratorHelpers::roundingMode(const MacroProps& macros, UnicodeString& sb, UErrorCode&) { + if (macros.roundingMode == kDefaultMode) { + return false; // Default + } + enum_to_stem_string::roundingMode(macros.roundingMode, sb); + return true; +} + +bool GeneratorHelpers::grouping(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + if (macros.grouper.isBogus()) { + return false; // No value + } else if (macros.grouper.fStrategy == UNUM_GROUPING_COUNT) { + status = U_UNSUPPORTED_ERROR; + return false; + } else if (macros.grouper.fStrategy == UNUM_GROUPING_AUTO) { + return false; // Default value + } else { + enum_to_stem_string::groupingStrategy(macros.grouper.fStrategy, sb); + return true; + } +} + +bool GeneratorHelpers::integerWidth(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + if (macros.integerWidth.fHasError || macros.integerWidth.isBogus() || + macros.integerWidth == IntegerWidth::standard()) { + // Error or Default + return false; + } + sb.append(u"integer-width/", -1); + blueprint_helpers::generateIntegerWidthOption( + macros.integerWidth.fUnion.minMaxInt.fMinInt, + macros.integerWidth.fUnion.minMaxInt.fMaxInt, + sb, + status); + return true; +} + +bool GeneratorHelpers::symbols(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + if (macros.symbols.isNumberingSystem()) { + const NumberingSystem& ns = *macros.symbols.getNumberingSystem(); + if (uprv_strcmp(ns.getName(), "latn") == 0) { + sb.append(u"latin", -1); + } else { + sb.append(u"numbering-system/", -1); + blueprint_helpers::generateNumberingSystemOption(ns, sb, status); + } + return true; + } else if (macros.symbols.isDecimalFormatSymbols()) { + status = U_UNSUPPORTED_ERROR; + return false; + } else { + // No custom symbols + return false; + } +} + +bool GeneratorHelpers::unitWidth(const MacroProps& macros, UnicodeString& sb, UErrorCode&) { + if (macros.unitWidth == UNUM_UNIT_WIDTH_SHORT || macros.unitWidth == UNUM_UNIT_WIDTH_COUNT) { + return false; // Default or Bogus + } + enum_to_stem_string::unitWidth(macros.unitWidth, sb); + return true; +} + +bool GeneratorHelpers::sign(const MacroProps& macros, UnicodeString& sb, UErrorCode&) { + if (macros.sign == UNUM_SIGN_AUTO || macros.sign == UNUM_SIGN_COUNT) { + return false; // Default or Bogus + } + enum_to_stem_string::signDisplay(macros.sign, sb); + return true; +} + +bool GeneratorHelpers::decimal(const MacroProps& macros, UnicodeString& sb, UErrorCode&) { + if (macros.decimal == UNUM_DECIMAL_SEPARATOR_AUTO || macros.decimal == UNUM_DECIMAL_SEPARATOR_COUNT) { + return false; // Default or Bogus + } + enum_to_stem_string::decimalSeparatorDisplay(macros.decimal, sb); + return true; +} + +bool GeneratorHelpers::scale(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) { + if (!macros.scale.isValid()) { + return false; // Default or Bogus + } + sb.append(u"scale/", -1); + blueprint_helpers::generateScaleOption( + macros.scale.fMagnitude, + macros.scale.fArbitrary, + sb, + status); + return true; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_skeletons.h b/deps/icu-small/source/i18n/number_skeletons.h new file mode 100644 index 0000000000..0161f5f0ba --- /dev/null +++ b/deps/icu-small/source/i18n/number_skeletons.h @@ -0,0 +1,327 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __SOURCE_NUMBER_SKELETONS_H__ +#define __SOURCE_NUMBER_SKELETONS_H__ + +#include "number_types.h" +#include "numparse_types.h" +#include "unicode/ucharstrie.h" + +using icu::numparse::impl::StringSegment; + +U_NAMESPACE_BEGIN namespace number { +namespace impl { + +// Forward-declaration +struct SeenMacroProps; + +// namespace for enums and entrypoint functions +namespace skeleton { + +/////////////////////////////////////////////////////////////////////////////////////// +// NOTE: For an example of how to add a new stem to the number skeleton parser, see: // +// http://bugs.icu-project.org/trac/changeset/41193 // +/////////////////////////////////////////////////////////////////////////////////////// + +/** + * While parsing a skeleton, this enum records what type of option we expect to find next. + */ +enum ParseState { + + // Section 0: We expect whitespace or a stem, but not an option: + + STATE_NULL, + + // Section 1: We might accept an option, but it is not required: + + STATE_SCIENTIFIC, + STATE_FRACTION_PRECISION, + + // Section 2: An option is required: + + STATE_INCREMENT_PRECISION, + STATE_MEASURE_UNIT, + STATE_PER_MEASURE_UNIT, + STATE_CURRENCY_UNIT, + STATE_INTEGER_WIDTH, + STATE_NUMBERING_SYSTEM, + STATE_SCALE, +}; + +/** + * All possible stem literals have an entry in the StemEnum. The enum name is the kebab case stem + * string literal written in upper snake case. + * + * @see StemToObject + * @see #SERIALIZED_STEM_TRIE + */ +enum StemEnum { + + // Section 1: Stems that do not require an option: + + STEM_COMPACT_SHORT, + STEM_COMPACT_LONG, + STEM_SCIENTIFIC, + STEM_ENGINEERING, + STEM_NOTATION_SIMPLE, + STEM_BASE_UNIT, + STEM_PERCENT, + STEM_PERMILLE, + STEM_PRECISION_INTEGER, + STEM_PRECISION_UNLIMITED, + STEM_PRECISION_CURRENCY_STANDARD, + STEM_PRECISION_CURRENCY_CASH, + STEM_ROUNDING_MODE_CEILING, + STEM_ROUNDING_MODE_FLOOR, + STEM_ROUNDING_MODE_DOWN, + STEM_ROUNDING_MODE_UP, + STEM_ROUNDING_MODE_HALF_EVEN, + STEM_ROUNDING_MODE_HALF_DOWN, + STEM_ROUNDING_MODE_HALF_UP, + STEM_ROUNDING_MODE_UNNECESSARY, + STEM_GROUP_OFF, + STEM_GROUP_MIN2, + STEM_GROUP_AUTO, + STEM_GROUP_ON_ALIGNED, + STEM_GROUP_THOUSANDS, + STEM_LATIN, + STEM_UNIT_WIDTH_NARROW, + STEM_UNIT_WIDTH_SHORT, + STEM_UNIT_WIDTH_FULL_NAME, + STEM_UNIT_WIDTH_ISO_CODE, + STEM_UNIT_WIDTH_HIDDEN, + STEM_SIGN_AUTO, + STEM_SIGN_ALWAYS, + STEM_SIGN_NEVER, + STEM_SIGN_ACCOUNTING, + STEM_SIGN_ACCOUNTING_ALWAYS, + STEM_SIGN_EXCEPT_ZERO, + STEM_SIGN_ACCOUNTING_EXCEPT_ZERO, + STEM_DECIMAL_AUTO, + STEM_DECIMAL_ALWAYS, + + // Section 2: Stems that DO require an option: + + STEM_PRECISION_INCREMENT, + STEM_MEASURE_UNIT, + STEM_PER_MEASURE_UNIT, + STEM_CURRENCY, + STEM_INTEGER_WIDTH, + STEM_NUMBERING_SYSTEM, + STEM_SCALE, +}; + +/** + * Creates a NumberFormatter corresponding to the given skeleton string. + * + * @param skeletonString + * A number skeleton string, possibly not in its shortest form. + * @return An UnlocalizedNumberFormatter with behavior defined by the given skeleton string. + */ +UnlocalizedNumberFormatter create(const UnicodeString& skeletonString, UErrorCode& status); + +/** + * Create a skeleton string corresponding to the given NumberFormatter. + * + * @param macros + * The NumberFormatter options object. + * @return A skeleton string in normalized form. + */ +UnicodeString generate(const MacroProps& macros, UErrorCode& status); + +/** + * Converts from a skeleton string to a MacroProps. This method contains the primary parse loop. + * + * Internal: use the create() endpoint instead of this function. + */ +MacroProps parseSkeleton(const UnicodeString& skeletonString, UErrorCode& status); + +/** + * Given that the current segment represents a stem, parse it and save the result. + * + * @return The next state after parsing this stem, corresponding to what subset of options to expect. + */ +ParseState parseStem(const StringSegment& segment, const UCharsTrie& stemTrie, SeenMacroProps& seen, + MacroProps& macros, UErrorCode& status); + +/** + * Given that the current segment represents an option, parse it and save the result. + * + * @return The next state after parsing this option, corresponding to what subset of options to + * expect next. + */ +ParseState +parseOption(ParseState stem, const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +} // namespace skeleton + + +/** + * Namespace for utility methods that convert from StemEnum to corresponding objects or enums. This + * applies to only the "Section 1" stems, those that are well-defined without an option. + */ +namespace stem_to_object { + +Notation notation(skeleton::StemEnum stem); + +MeasureUnit unit(skeleton::StemEnum stem); + +Precision precision(skeleton::StemEnum stem); + +UNumberFormatRoundingMode roundingMode(skeleton::StemEnum stem); + +UGroupingStrategy groupingStrategy(skeleton::StemEnum stem); + +UNumberUnitWidth unitWidth(skeleton::StemEnum stem); + +UNumberSignDisplay signDisplay(skeleton::StemEnum stem); + +UNumberDecimalSeparatorDisplay decimalSeparatorDisplay(skeleton::StemEnum stem); + +} // namespace stem_to_object + +/** + * Namespace for utility methods that convert from enums to stem strings. More complex object conversions + * take place in the object_to_stem_string namespace. + */ +namespace enum_to_stem_string { + +void roundingMode(UNumberFormatRoundingMode value, UnicodeString& sb); + +void groupingStrategy(UGroupingStrategy value, UnicodeString& sb); + +void unitWidth(UNumberUnitWidth value, UnicodeString& sb); + +void signDisplay(UNumberSignDisplay value, UnicodeString& sb); + +void decimalSeparatorDisplay(UNumberDecimalSeparatorDisplay value, UnicodeString& sb); + +} // namespace enum_to_stem_string + +/** + * Namespace for utility methods for processing stems and options that cannot be interpreted literally. + */ +namespace blueprint_helpers { + +/** @return Whether we successfully found and parsed an exponent width option. */ +bool parseExponentWidthOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void generateExponentWidthOption(int32_t minExponentDigits, UnicodeString& sb, UErrorCode& status); + +/** @return Whether we successfully found and parsed an exponent sign option. */ +bool parseExponentSignOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void parseCurrencyOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void generateCurrencyOption(const CurrencyUnit& currency, UnicodeString& sb, UErrorCode& status); + +void parseMeasureUnitOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void generateMeasureUnitOption(const MeasureUnit& measureUnit, UnicodeString& sb, UErrorCode& status); + +void parseMeasurePerUnitOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void parseFractionStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void generateFractionStem(int32_t minFrac, int32_t maxFrac, UnicodeString& sb, UErrorCode& status); + +void parseDigitsStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void generateDigitsStem(int32_t minSig, int32_t maxSig, UnicodeString& sb, UErrorCode& status); + +/** @return Whether we successfully found and parsed a frac-sig option. */ +bool parseFracSigOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void parseIncrementOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void +generateIncrementOption(double increment, int32_t trailingZeros, UnicodeString& sb, UErrorCode& status); + +void parseIntegerWidthOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void generateIntegerWidthOption(int32_t minInt, int32_t maxInt, UnicodeString& sb, UErrorCode& status); + +void parseNumberingSystemOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void generateNumberingSystemOption(const NumberingSystem& ns, UnicodeString& sb, UErrorCode& status); + +void parseScaleOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status); + +void generateScaleOption(int32_t magnitude, const DecNum* arbitrary, UnicodeString& sb, + UErrorCode& status); + +} // namespace blueprint_helpers + +/** + * Class for utility methods for generating a token corresponding to each macro-prop. Each method + * returns whether or not a token was written to the string builder. + * + * This needs to be a class, not a namespace, so it can be friended. + */ +class GeneratorHelpers { + public: + /** + * Main skeleton generator function. Appends the normalized skeleton for the MacroProps to the given + * StringBuilder. + * + * Internal: use the create() endpoint instead of this function. + */ + static void generateSkeleton(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + private: + static bool notation(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool unit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool perUnit(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool precision(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool roundingMode(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool grouping(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool integerWidth(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool symbols(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool unitWidth(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool sign(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool decimal(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + + static bool scale(const MacroProps& macros, UnicodeString& sb, UErrorCode& status); + +}; + +/** + * Struct for null-checking. + * In Java, we can just check the object reference. In C++, we need a different method. + */ +struct SeenMacroProps { + bool notation = false; + bool unit = false; + bool perUnit = false; + bool precision = false; + bool roundingMode = false; + bool grouper = false; + bool padder = false; + bool integerWidth = false; + bool symbols = false; + bool unitWidth = false; + bool sign = false; + bool decimal = false; + bool scale = false; +}; + +} // namespace impl +} // namespace number +U_NAMESPACE_END + +#endif //__SOURCE_NUMBER_SKELETONS_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_stringbuilder.cpp b/deps/icu-small/source/i18n/number_stringbuilder.cpp index 37159d7e53..37770d11d5 100644 --- a/deps/icu-small/source/i18n/number_stringbuilder.cpp +++ b/deps/icu-small/source/i18n/number_stringbuilder.cpp @@ -3,11 +3,10 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #include "number_stringbuilder.h" #include "unicode/utf16.h" -#include "uvectr32.h" using namespace icu; using namespace icu::number; @@ -337,6 +336,11 @@ UnicodeString NumberStringBuilder::toUnicodeString() const { return UnicodeString(getCharPtr() + fZero, fLength); } +const UnicodeString NumberStringBuilder::toTempUnicodeString() const { + // Readonly-alias constructor: + return UnicodeString(FALSE, getCharPtr() + fZero, fLength); +} + UnicodeString NumberStringBuilder::toDebugString() const { UnicodeString sb; sb.append(u"= UNUM_FIELD_COUNT) { status = U_ILLEGAL_ARGUMENT_ERROR; - return; + return FALSE; } auto field = static_cast(rawField); bool seenStart = false; int32_t fractionStart = -1; - for (int i = fZero; i <= fZero + fLength; i++) { + int32_t startIndex = fp.getEndIndex(); + for (int i = fZero + startIndex; i <= fZero + fLength; i++) { Field _field = UNUM_FIELD_COUNT; if (i < fZero + fLength) { _field = getFieldPtr()[i]; @@ -434,10 +439,10 @@ void NumberStringBuilder::populateFieldPosition(FieldPosition &fp, int32_t offse if (field == UNUM_INTEGER_FIELD && _field == UNUM_GROUPING_SEPARATOR_FIELD) { continue; } - fp.setEndIndex(i - fZero + offset); + fp.setEndIndex(i - fZero); break; } else if (!seenStart && field == _field) { - fp.setBeginIndex(i - fZero + offset); + fp.setBeginIndex(i - fZero); seenStart = true; } if (_field == UNUM_INTEGER_FIELD || _field == UNUM_DECIMAL_SEPARATOR_FIELD) { @@ -445,36 +450,28 @@ void NumberStringBuilder::populateFieldPosition(FieldPosition &fp, int32_t offse } } - // Backwards compatibility: FRACTION needs to start after INTEGER if empty - if (field == UNUM_FRACTION_FIELD && !seenStart) { - fp.setBeginIndex(fractionStart + offset); - fp.setEndIndex(fractionStart + offset); + // Backwards compatibility: FRACTION needs to start after INTEGER if empty. + // Do not return that a field was found, though, since there is not actually a fraction part. + if (field == UNUM_FRACTION_FIELD && !seenStart && fractionStart != -1) { + fp.setBeginIndex(fractionStart); + fp.setEndIndex(fractionStart); } -} -void NumberStringBuilder::populateFieldPositionIterator(FieldPositionIterator &fpi, UErrorCode &status) const { - // TODO: Set an initial capacity on uvec? - LocalPointer uvec(new UVector32(status)); - if (U_FAILURE(status)) { - return; - } + return seenStart; +} +void NumberStringBuilder::getAllFieldPositions(FieldPositionIteratorHandler& fpih, + UErrorCode& status) const { Field current = UNUM_FIELD_COUNT; int32_t currentStart = -1; for (int32_t i = 0; i < fLength; i++) { Field field = fieldAt(i); if (current == UNUM_INTEGER_FIELD && field == UNUM_GROUPING_SEPARATOR_FIELD) { // Special case: GROUPING_SEPARATOR counts as an INTEGER. - // Add the field, followed by the start index, followed by the end index to uvec. - uvec->addElement(UNUM_GROUPING_SEPARATOR_FIELD, status); - uvec->addElement(i, status); - uvec->addElement(i + 1, status); + fpih.addAttribute(UNUM_GROUPING_SEPARATOR_FIELD, i, i + 1); } else if (current != field) { if (current != UNUM_FIELD_COUNT) { - // Add the field, followed by the start index, followed by the end index to uvec. - uvec->addElement(current, status); - uvec->addElement(currentStart, status); - uvec->addElement(i, status); + fpih.addAttribute(current, currentStart, i); } current = field; currentStart = i; @@ -484,14 +481,8 @@ void NumberStringBuilder::populateFieldPositionIterator(FieldPositionIterator &f } } if (current != UNUM_FIELD_COUNT) { - // Add the field, followed by the start index, followed by the end index to uvec. - uvec->addElement(current, status); - uvec->addElement(currentStart, status); - uvec->addElement(fLength, status); + fpih.addAttribute(current, currentStart, fLength); } - - // Give uvec to the FieldPositionIterator, which adopts it. - fpi.setData(uvec.orphan(), status); } #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_stringbuilder.h b/deps/icu-small/source/i18n/number_stringbuilder.h index a97cc9ca02..cd8ce2f805 100644 --- a/deps/icu-small/source/i18n/number_stringbuilder.h +++ b/deps/icu-small/source/i18n/number_stringbuilder.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_STRINGBUILDER_H__ #define __NUMBER_STRINGBUILDER_H__ @@ -14,6 +14,7 @@ #include "cstring.h" #include "uassert.h" #include "number_types.h" +#include "fphdlimp.h" U_NAMESPACE_BEGIN namespace number { namespace impl { @@ -84,17 +85,26 @@ class U_I18N_API NumberStringBuilder : public UMemory { int32_t insert(int32_t index, const NumberStringBuilder &other, UErrorCode &status); + /** + * Gets a "safe" UnicodeString that can be used even after the NumberStringBuilder is destructed. + * */ UnicodeString toUnicodeString() const; + /** + * Gets an "unsafe" UnicodeString that is valid only as long as the NumberStringBuilder is alive and + * unchanged. Slightly faster than toUnicodeString(). + */ + const UnicodeString toTempUnicodeString() const; + UnicodeString toDebugString() const; const char16_t *chars() const; bool contentEquals(const NumberStringBuilder &other) const; - void populateFieldPosition(FieldPosition &fp, int32_t offset, UErrorCode &status) const; + bool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const; - void populateFieldPositionIterator(FieldPositionIterator &fpi, UErrorCode &status) const; + void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const; private: bool fUsingHeap = false; diff --git a/deps/icu-small/source/i18n/number_types.h b/deps/icu-small/source/i18n/number_types.h index c01765e2ce..57da72f8aa 100644 --- a/deps/icu-small/source/i18n/number_types.h +++ b/deps/icu-small/source/i18n/number_types.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_TYPES_H__ #define __NUMBER_TYPES_H__ @@ -15,9 +15,9 @@ #include "unicode/utf16.h" #include "uassert.h" #include "unicode/platform.h" +#include "unicode/uniset.h" -U_NAMESPACE_BEGIN -namespace number { +U_NAMESPACE_BEGIN namespace number { namespace impl { // Typedef several enums for brevity and for easier comparison to Java. @@ -39,9 +39,6 @@ static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN; // ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING static constexpr char16_t kFallbackPaddingString[] = u" "; -// ICU4J Equivalent: NumberFormatterImpl.DEFAULT_CURRENCY -static constexpr char16_t kDefaultCurrency[] = u"XXX"; - // Forward declarations: class Modifier; @@ -87,35 +84,10 @@ enum AffixPatternType { }; enum CompactType { - TYPE_DECIMAL, - TYPE_CURRENCY + TYPE_DECIMAL, TYPE_CURRENCY }; -// TODO: Should this be moved somewhere else, maybe where other ICU classes can use it? -// Exported as U_I18N_API because it is a base class for other exported types -class U_I18N_API CharSequence { -public: - virtual ~CharSequence() = default; - - virtual int32_t length() const = 0; - - virtual char16_t charAt(int32_t index) const = 0; - - virtual UChar32 codePointAt(int32_t index) const { - // Default implementation; can be overridden with a more efficient version - char16_t leading = charAt(index); - if (U16_IS_LEAD(leading) && length() > index + 1) { - char16_t trailing = charAt(index + 1); - return U16_GET_SUPPLEMENTARY(leading, trailing); - } else { - return leading; - } - } - - virtual UnicodeString toUnicodeString() const = 0; -}; - class U_I18N_API AffixPatternProvider { public: static const int32_t AFFIX_PLURAL_MASK = 0xff; @@ -123,12 +95,20 @@ class U_I18N_API AffixPatternProvider { static const int32_t AFFIX_NEGATIVE_SUBPATTERN = 0x200; static const int32_t AFFIX_PADDING = 0x400; - virtual ~AffixPatternProvider() = default; + // Convenience compound flags + static const int32_t AFFIX_POS_PREFIX = AFFIX_PREFIX; + static const int32_t AFFIX_POS_SUFFIX = 0; + static const int32_t AFFIX_NEG_PREFIX = AFFIX_PREFIX | AFFIX_NEGATIVE_SUBPATTERN; + static const int32_t AFFIX_NEG_SUFFIX = AFFIX_NEGATIVE_SUBPATTERN; + + virtual ~AffixPatternProvider(); virtual char16_t charAt(int flags, int i) const = 0; virtual int length(int flags) const = 0; + virtual UnicodeString getString(int flags) const = 0; + virtual bool hasCurrencySign() const = 0; virtual bool positiveHasPlusSign() const = 0; @@ -137,7 +117,7 @@ class U_I18N_API AffixPatternProvider { virtual bool negativeHasMinusSign() const = 0; - virtual bool containsSymbolType(AffixPatternType, UErrorCode &) const = 0; + virtual bool containsSymbolType(AffixPatternType, UErrorCode&) const = 0; /** * True if the pattern has a number placeholder like "0" or "#,##0.00"; false if the pattern does not @@ -159,7 +139,7 @@ class U_I18N_API AffixPatternProvider { */ class U_I18N_API Modifier { public: - virtual ~Modifier() = default; + virtual ~Modifier(); /** * Apply this Modifier to the string builder. @@ -173,8 +153,8 @@ class U_I18N_API Modifier { * formatted. * @return The number of characters (UTF-16 code units) that were added to the string builder. */ - virtual int32_t - apply(NumberStringBuilder &output, int leftIndex, int rightIndex, UErrorCode &status) const = 0; + virtual int32_t apply(NumberStringBuilder& output, int leftIndex, int rightIndex, + UErrorCode& status) const = 0; /** * Gets the length of the prefix. This information can be used in combination with {@link #apply} to extract the @@ -187,7 +167,7 @@ class U_I18N_API Modifier { /** * Returns the number of code points in the modifier, prefix plus suffix. */ - virtual int32_t getCodePointCount(UErrorCode &status) const = 0; + virtual int32_t getCodePointCount(UErrorCode& status) const = 0; /** * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed @@ -219,7 +199,7 @@ class U_I18N_API Modifier { */ class U_I18N_API MicroPropsGenerator { public: - virtual ~MicroPropsGenerator() = default; + virtual ~MicroPropsGenerator(); /** * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}. @@ -230,7 +210,8 @@ class U_I18N_API MicroPropsGenerator { * The MicroProps instance to populate. * @return A MicroProps instance resolved for the quantity. */ - virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros, UErrorCode& status) const = 0; + virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros, + UErrorCode& status) const = 0; }; /** @@ -238,7 +219,7 @@ class U_I18N_API MicroPropsGenerator { */ class MultiplierProducer { public: - virtual ~MultiplierProducer() = default; + virtual ~MultiplierProducer(); /** * Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a magnitude of 5 @@ -255,24 +236,31 @@ class MultiplierProducer { template class U_I18N_API NullableValue { public: - NullableValue() : fNull(true) {} + NullableValue() + : fNull(true) {} - NullableValue(const NullableValue &other) = default; + NullableValue(const NullableValue& other) = default; - explicit NullableValue(const T &other) { + explicit NullableValue(const T& other) { fValue = other; fNull = false; } - NullableValue &operator=(const NullableValue &other) = default; + NullableValue& operator=(const NullableValue& other) { + fNull = other.fNull; + if (!fNull) { + fValue = other.fValue; + } + return *this; + } - NullableValue &operator=(const T &other) { + NullableValue& operator=(const T& other) { fValue = other; fNull = false; return *this; } - bool operator==(const NullableValue &other) const { + bool operator==(const NullableValue& other) const { // "fValue == other.fValue" returns UBool, not bool (causes compiler warnings) return fNull ? other.fNull : (other.fNull ? false : static_cast(fValue == other.fValue)); } @@ -286,13 +274,21 @@ class U_I18N_API NullableValue { return fNull; } - T get(UErrorCode &status) const { + T get(UErrorCode& status) const { if (fNull) { status = U_UNDEFINED_VARIABLE; } return fValue; } + T getNoError() const { + return fValue; + } + + T getOrDefault(T defaultValue) const { + return fNull ? defaultValue : fValue; + } + private: bool fNull; T fValue; diff --git a/deps/icu-small/source/i18n/number_utils.cpp b/deps/icu-small/source/i18n/number_utils.cpp new file mode 100644 index 0000000000..c79d2de9fa --- /dev/null +++ b/deps/icu-small/source/i18n/number_utils.cpp @@ -0,0 +1,253 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include +#include +#include "number_decnum.h" +#include "number_types.h" +#include "number_utils.h" +#include "charstr.h" +#include "decContext.h" +#include "decNumber.h" +#include "double-conversion.h" +#include "fphdlimp.h" +#include "uresimp.h" +#include "ureslocs.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + +using icu::double_conversion::DoubleToStringConverter; + + +namespace { + +const char16_t* +doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus, + UErrorCode& localStatus) { + // Construct the path into the resource bundle + CharString key; + key.append("NumberElements/", publicStatus); + key.append(nsName, publicStatus); + key.append("/patterns/", publicStatus); + key.append(patternKey, publicStatus); + if (U_FAILURE(publicStatus)) { + return u""; + } + return ures_getStringByKeyWithFallback(res, key.data(), nullptr, &localStatus); +} + +} + + +const char16_t* utils::getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, + UErrorCode& status) { + const char* patternKey; + switch (style) { + case CLDR_PATTERN_STYLE_DECIMAL: + patternKey = "decimalFormat"; + break; + case CLDR_PATTERN_STYLE_CURRENCY: + patternKey = "currencyFormat"; + break; + case CLDR_PATTERN_STYLE_ACCOUNTING: + patternKey = "accountingFormat"; + break; + case CLDR_PATTERN_STYLE_PERCENT: + patternKey = "percentFormat"; + break; + case CLDR_PATTERN_STYLE_SCIENTIFIC: + patternKey = "scientificFormat"; + break; + default: + patternKey = "decimalFormat"; // silence compiler error + U_ASSERT(false); + } + LocalUResourceBundlePointer res(ures_open(nullptr, locale.getName(), &status)); + if (U_FAILURE(status)) { return u""; } + + // Attempt to get the pattern with the native numbering system. + UErrorCode localStatus = U_ZERO_ERROR; + const char16_t* pattern; + pattern = doGetPattern(res.getAlias(), nsName, patternKey, status, localStatus); + if (U_FAILURE(status)) { return u""; } + + // Fall back to latn if native numbering system does not have the right pattern + if (U_FAILURE(localStatus) && uprv_strcmp("latn", nsName) != 0) { + localStatus = U_ZERO_ERROR; + pattern = doGetPattern(res.getAlias(), "latn", patternKey, status, localStatus); + if (U_FAILURE(status)) { return u""; } + } + + return pattern; +} + + +DecNum::DecNum() { + uprv_decContextDefault(&fContext, DEC_INIT_BASE); + uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN); + fContext.traps = 0; // no traps, thank you (what does this even mean?) +} + +DecNum::DecNum(const DecNum& other, UErrorCode& status) + : fContext(other.fContext) { + // Allocate memory for the new DecNum. + U_ASSERT(fContext.digits == other.fData.getCapacity()); + if (fContext.digits > kDefaultDigits) { + void* p = fData.resize(fContext.digits, 0); + if (p == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + } + + // Copy the data from the old DecNum to the new one. + uprv_memcpy(fData.getAlias(), other.fData.getAlias(), sizeof(decNumber)); + uprv_memcpy(fData.getArrayStart(), + other.fData.getArrayStart(), + other.fData.getArrayLimit() - other.fData.getArrayStart()); +} + +void DecNum::setTo(StringPiece str, UErrorCode& status) { + // We need NUL-terminated for decNumber; CharString guarantees this, but not StringPiece. + CharString cstr(str, status); + if (U_FAILURE(status)) { return; } + _setTo(cstr.data(), str.length(), status); +} + +void DecNum::setTo(const char* str, UErrorCode& status) { + _setTo(str, static_cast(uprv_strlen(str)), status); +} + +void DecNum::setTo(double d, UErrorCode& status) { + // Need to check for NaN and Infinity before going into DoubleToStringConverter + if (std::isnan(d) != 0 || std::isfinite(d) == 0) { + status = U_UNSUPPORTED_ERROR; + return; + } + + // First convert from double to string, then string to DecNum. + // Allocate enough room for: all digits, "E-324", and NUL-terminator. + char buffer[DoubleToStringConverter::kBase10MaximalLength + 6]; + bool sign; // unused; always positive + int32_t length; + int32_t point; + DoubleToStringConverter::DoubleToAscii( + d, + DoubleToStringConverter::DtoaMode::SHORTEST, + 0, + buffer, + sizeof(buffer), + &sign, + &length, + &point + ); + + // Read initial result as a string. + _setTo(buffer, length, status); + + // Set exponent and bitmask. Note that DoubleToStringConverter does not do negatives. + fData.getAlias()->exponent += point - length; + fData.getAlias()->bits |= static_cast(std::signbit(d) ? DECNEG : 0); +} + +void DecNum::_setTo(const char* str, int32_t maxDigits, UErrorCode& status) { + if (maxDigits > kDefaultDigits) { + fData.resize(maxDigits, 0); + fContext.digits = maxDigits; + } else { + fContext.digits = kDefaultDigits; + } + + static_assert(DECDPUN == 1, "Assumes that DECDPUN is set to 1"); + uprv_decNumberFromString(fData.getAlias(), str, &fContext); + + // Check for invalid syntax and set the corresponding error code. + if ((fContext.status & DEC_Conversion_syntax) != 0) { + status = U_DECIMAL_NUMBER_SYNTAX_ERROR; + return; + } else if (fContext.status != 0) { + // Not a syntax error, but some other error, like an exponent that is too large. + status = U_UNSUPPORTED_ERROR; + return; + } + + // For consistency with Java BigDecimal, no support for DecNum that is NaN or Infinity! + if (decNumberIsSpecial(fData.getAlias())) { + status = U_UNSUPPORTED_ERROR; + return; + } +} + +void +DecNum::setTo(const uint8_t* bcd, int32_t length, int32_t scale, bool isNegative, UErrorCode& status) { + if (length > kDefaultDigits) { + fData.resize(length, 0); + fContext.digits = length; + } else { + fContext.digits = kDefaultDigits; + } + + // "digits is of type int32_t, and must have a value in the range 1 through 999,999,999." + if (length < 1 || length > 999999999) { + // Too large for decNumber + status = U_UNSUPPORTED_ERROR; + return; + } + // "The exponent field holds the exponent of the number. Its range is limited by the requirement that + // "the range of the adjusted exponent of the number be balanced and fit within a whole number of + // "decimal digits (in this implementation, be –999,999,999 through +999,999,999). The adjusted + // "exponent is the exponent that would result if the number were expressed with a single digit before + // "the decimal point, and is therefore given by exponent+digits-1." + if (scale > 999999999 - length + 1 || scale < -999999999 - length + 1) { + // Too large for decNumber + status = U_UNSUPPORTED_ERROR; + return; + } + + fData.getAlias()->digits = length; + fData.getAlias()->exponent = scale; + fData.getAlias()->bits = static_cast(isNegative ? DECNEG : 0); + uprv_decNumberSetBCD(fData, bcd, static_cast(length)); + if (fContext.status != 0) { + // Some error occurred while constructing the decNumber. + status = U_INTERNAL_PROGRAM_ERROR; + } +} + +void DecNum::normalize() { + uprv_decNumberReduce(fData, fData, &fContext); +} + +void DecNum::multiplyBy(const DecNum& rhs, UErrorCode& status) { + uprv_decNumberMultiply(fData, fData, rhs.fData, &fContext); + if (fContext.status != 0) { + status = U_INTERNAL_PROGRAM_ERROR; + } +} + +void DecNum::divideBy(const DecNum& rhs, UErrorCode& status) { + uprv_decNumberDivide(fData, fData, rhs.fData, &fContext); + if (fContext.status != 0) { + status = U_INTERNAL_PROGRAM_ERROR; + } +} + +bool DecNum::isNegative() const { + return decNumberIsNegative(fData.getAlias()); +} + +bool DecNum::isZero() const { + return decNumberIsZero(fData.getAlias()); +} + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/number_utils.h b/deps/icu-small/source/i18n/number_utils.h index 3a408d6007..c367166009 100644 --- a/deps/icu-small/source/i18n/number_utils.h +++ b/deps/icu-small/source/i18n/number_utils.h @@ -3,7 +3,7 @@ #include "unicode/utypes.h" -#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_UTILS_H__ #define __NUMBER_UTILS_H__ @@ -13,116 +13,80 @@ #include "number_scientific.h" #include "number_patternstring.h" #include "number_modifiers.h" +#include "number_multiplier.h" +#include "number_roundingutils.h" +#include "decNumber.h" +#include "charstr.h" -U_NAMESPACE_BEGIN namespace number { -namespace impl { +U_NAMESPACE_BEGIN -class UnicodeStringCharSequence : public CharSequence { - public: - explicit UnicodeStringCharSequence(const UnicodeString &other) { - fStr = other; - } +namespace number { +namespace impl { - ~UnicodeStringCharSequence() U_OVERRIDE = default; +enum CldrPatternStyle { + CLDR_PATTERN_STYLE_DECIMAL, + CLDR_PATTERN_STYLE_CURRENCY, + CLDR_PATTERN_STYLE_ACCOUNTING, + CLDR_PATTERN_STYLE_PERCENT, + CLDR_PATTERN_STYLE_SCIENTIFIC, + CLDR_PATTERN_STYLE_COUNT, +}; - int32_t length() const U_OVERRIDE { - return fStr.length(); - } +// Namespace for naked functions +namespace utils { - char16_t charAt(int32_t index) const U_OVERRIDE { - return fStr.charAt(index); +inline int32_t insertDigitFromSymbols(NumberStringBuilder& output, int32_t index, int8_t digit, + const DecimalFormatSymbols& symbols, Field field, + UErrorCode& status) { + if (symbols.getCodePointZero() != -1) { + return output.insertCodePoint(index, symbols.getCodePointZero() + digit, field, status); } + return output.insert(index, symbols.getConstDigitSymbol(digit), field, status); +} - UChar32 codePointAt(int32_t index) const U_OVERRIDE { - return fStr.char32At(index); - } +inline bool unitIsCurrency(const MeasureUnit& unit) { + return uprv_strcmp("currency", unit.getType()) == 0; +} - UnicodeString toUnicodeString() const U_OVERRIDE { - // Allocate a UnicodeString of the correct length - UnicodeString output(length(), 0, -1); - for (int32_t i = 0; i < length(); i++) { - output.append(charAt(i)); - } - return output; - } +inline bool unitIsNoUnit(const MeasureUnit& unit) { + return uprv_strcmp("none", unit.getType()) == 0; +} - private: - UnicodeString fStr; -}; +inline bool unitIsPercent(const MeasureUnit& unit) { + return uprv_strcmp("percent", unit.getSubtype()) == 0; +} -struct MicroProps : public MicroPropsGenerator { - - // NOTE: All of these fields are properly initialized in NumberFormatterImpl. - Rounder rounding; - Grouper grouping; - Padder padding; - IntegerWidth integerWidth; - UNumberSignDisplay sign; - UNumberDecimalSeparatorDisplay decimal; - bool useCurrency; - - // Note: This struct has no direct ownership of the following pointers. - const DecimalFormatSymbols *symbols; - const Modifier *modOuter; - const Modifier *modMiddle; - const Modifier *modInner; - - // The following "helper" fields may optionally be used during the MicroPropsGenerator. - // They live here to retain memory. - struct { - ScientificModifier scientificModifier; - EmptyModifier emptyWeakModifier{false}; - EmptyModifier emptyStrongModifier{true}; - } helpers; - - - MicroProps() = default; - - MicroProps(const MicroProps &other) = default; - - MicroProps &operator=(const MicroProps &other) = default; - - void processQuantity(DecimalQuantity &, MicroProps µs, UErrorCode &status) const U_OVERRIDE { - (void)status; - if (this == µs) { - // Unsafe path: no need to perform a copy. - U_ASSERT(!exhausted); - micros.exhausted = true; - U_ASSERT(exhausted); - } else { - // Safe path: copy self into the output micros. - micros = *this; - } - } +inline bool unitIsPermille(const MeasureUnit& unit) { + return uprv_strcmp("permille", unit.getSubtype()) == 0; +} - private: - // Internal fields: - bool exhausted = false; -}; +// NOTE: In Java, this method is in NumberFormat.java +const char16_t* +getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, UErrorCode& status); /** - * This struct provides the result of the number formatting pipeline to FormattedNumber. + * Computes the plural form for this number based on the specified set of rules. * - * The DecimalQuantity is not currently being used by FormattedNumber, but at some point it could be used - * to add a toDecNumber() or similar method. + * @param rules A {@link PluralRules} object representing the set of rules. + * @return The {@link StandardPlural} according to the PluralRules. If the plural form is not in + * the set of standard plurals, {@link StandardPlural#OTHER} is returned instead. */ -struct NumberFormatterResults : public UMemory { - DecimalQuantity quantity; - NumberStringBuilder string; -}; - -inline const UnicodeString getDigitFromSymbols(int8_t digit, const DecimalFormatSymbols &symbols) { - // TODO: Implement DecimalFormatSymbols.getCodePointZero()? - if (digit == 0) { - return symbols.getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kZeroDigitSymbol); +inline StandardPlural::Form getStandardPlural(const PluralRules *rules, + const IFixedDecimal &fdec) { + if (rules == nullptr) { + // Fail gracefully if the user didn't provide a PluralRules + return StandardPlural::Form::OTHER; } else { - return symbols.getSymbol(static_cast( - DecimalFormatSymbols::ENumberFormatSymbol::kOneDigitSymbol + digit - 1)); + UnicodeString ruleString = rules->select(fdec); + return StandardPlural::orOtherFromString(ruleString); } } +} // namespace utils + } // namespace impl } // namespace number + U_NAMESPACE_END #endif //__NUMBER_UTILS_H__ diff --git a/deps/icu-small/source/i18n/number_utypes.h b/deps/icu-small/source/i18n/number_utypes.h new file mode 100644 index 0000000000..48bfce1969 --- /dev/null +++ b/deps/icu-small/source/i18n/number_utypes.h @@ -0,0 +1,79 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __SOURCE_NUMBER_UTYPES_H__ +#define __SOURCE_NUMBER_UTYPES_H__ + +#include "unicode/numberformatter.h" +#include "number_types.h" +#include "number_decimalquantity.h" +#include "number_stringbuilder.h" + +U_NAMESPACE_BEGIN namespace number { +namespace impl { + + +/** + * Implementation class for UNumberFormatter with a magic number for safety. + * + * Wraps a LocalizedNumberFormatter by value. + */ +struct UNumberFormatterData : public UMemory { + // The magic number to identify incoming objects. + // Reads in ASCII as "NFR" (NumberFormatteR with room at the end) + static constexpr int32_t kMagic = 0x4E465200; + + // Data members: + int32_t fMagic = kMagic; + LocalizedNumberFormatter fFormatter; + + /** Convert from UNumberFormatter -> UNumberFormatterData. */ + static UNumberFormatterData* validate(UNumberFormatter* input, UErrorCode& status); + + /** Convert from UNumberFormatter -> UNumberFormatterData (const version). */ + static const UNumberFormatterData* validate(const UNumberFormatter* input, UErrorCode& status); + + /** Convert from UNumberFormatterData -> UNumberFormatter. */ + UNumberFormatter* exportForC(); +}; + + +/** + * Implementation class for UFormattedNumber with magic number for safety. + * + * This struct is also held internally by the C++ version FormattedNumber since the member types are not + * declared in the public header file. + * + * The DecimalQuantity is not currently being used by FormattedNumber, but at some point it could be used + * to add a toDecNumber() or similar method. + */ +struct UFormattedNumberData : public UMemory { + // The magic number to identify incoming objects. + // Reads in ASCII as "FDN" (FormatteDNumber with room at the end) + static constexpr int32_t kMagic = 0x46444E00; + + // Data members: + int32_t fMagic = kMagic; + DecimalQuantity quantity; + NumberStringBuilder string; + + /** Convert from UFormattedNumber -> UFormattedNumberData. */ + static UFormattedNumberData* validate(UFormattedNumber* input, UErrorCode& status); + + /** Convert from UFormattedNumber -> UFormattedNumberData (const version). */ + static const UFormattedNumberData* validate(const UFormattedNumber* input, UErrorCode& status); + + /** Convert from UFormattedNumberData -> UFormattedNumber. */ + UFormattedNumber* exportForC(); +}; + + +} // namespace impl +} // namespace number +U_NAMESPACE_END + +#endif //__SOURCE_NUMBER_UTYPES_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numfmt.cpp b/deps/icu-small/source/i18n/numfmt.cpp index fee3bed8bf..13f23131b1 100644 --- a/deps/icu-small/source/i18n/numfmt.cpp +++ b/deps/icu-small/source/i18n/numfmt.cpp @@ -51,10 +51,11 @@ #include "uassert.h" #include "umutex.h" #include "mutex.h" -#include "digitlst.h" #include #include "sharednumberformat.h" #include "unifiedcache.h" +#include "number_decimalquantity.h" +#include "number_utils.h" //#define FMT_DEBUG @@ -129,31 +130,28 @@ static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] = // Keys used for accessing resource bundles -static const char *gNumberElements = "NumberElements"; -static const char *gLatn = "latn"; -static const char *gPatterns = "patterns"; -static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = { - NULL, // UNUM_PATTERN_DECIMAL - "decimalFormat", // UNUM_DECIMAL - "currencyFormat", // UNUM_CURRENCY - "percentFormat", // UNUM_PERCENT - "scientificFormat", // UNUM_SCIENTIFIC - NULL, // UNUM_SPELLOUT - NULL, // UNUM_ORDINAL - NULL, // UNUM_DURATION - NULL, // UNUM_NUMBERING_SYSTEM - NULL, // UNUM_PATTERN_RULEBASED +static const icu::number::impl::CldrPatternStyle gFormatCldrStyles[UNUM_FORMAT_STYLE_COUNT] = { + /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_PATTERN_DECIMAL + icu::number::impl::CLDR_PATTERN_STYLE_DECIMAL, // UNUM_DECIMAL + icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY + icu::number::impl::CLDR_PATTERN_STYLE_PERCENT, // UNUM_PERCENT + icu::number::impl::CLDR_PATTERN_STYLE_SCIENTIFIC, // UNUM_SCIENTIFIC + /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_SPELLOUT + /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_ORDINAL + /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DURATION + /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_NUMBERING_SYSTEM + /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_PATTERN_RULEBASED // For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL, // the pattern is the same as the pattern of UNUM_CURRENCY // except for replacing the single currency sign with // double currency sign or triple currency sign. - "currencyFormat", // UNUM_CURRENCY_ISO - "currencyFormat", // UNUM_CURRENCY_PLURAL - "accountingFormat", // UNUM_CURRENCY_ACCOUNTING - "currencyFormat", // UNUM_CASH_CURRENCY - NULL, // UNUM_DECIMAL_COMPACT_SHORT - NULL, // UNUM_DECIMAL_COMPACT_LONG - "currencyFormat", // UNUM_CURRENCY_STANDARD + icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_ISO + icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_PLURAL + icu::number::impl::CLDR_PATTERN_STYLE_ACCOUNTING, // UNUM_CURRENCY_ACCOUNTING + icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CASH_CURRENCY + /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DECIMAL_COMPACT_SHORT + /* NULL */ icu::number::impl::CLDR_PATTERN_STYLE_COUNT, // UNUM_DECIMAL_COMPACT_LONG + icu::number::impl::CLDR_PATTERN_STYLE_CURRENCY, // UNUM_CURRENCY_STANDARD }; // Static hashtable cache of NumberingSystem objects used by NumberFormat @@ -524,7 +522,7 @@ ArgExtractor::ArgExtractor(const NumberFormat& /*nf*/, const Formattable& obj, U ArgExtractor::~ArgExtractor() { } -UnicodeString& NumberFormat::format(const DigitList &number, +UnicodeString& NumberFormat::format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPositionIterator* posIter, UErrorCode& status) const { @@ -534,7 +532,7 @@ UnicodeString& NumberFormat::format(const DigitList &number, if (U_FAILURE(status)) { return appendTo; } - double dnum = number.getDouble(); + double dnum = number.toDouble(); format(dnum, appendTo, posIter, status); return appendTo; } @@ -542,7 +540,7 @@ UnicodeString& NumberFormat::format(const DigitList &number, UnicodeString& -NumberFormat::format(const DigitList &number, +NumberFormat::format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode &status) const { @@ -552,7 +550,7 @@ NumberFormat::format(const DigitList &number, if (U_FAILURE(status)) { return appendTo; } - double dnum = number.getDouble(); + double dnum = number.toDouble(); format(dnum, appendTo, pos, status); return appendTo; } @@ -578,7 +576,7 @@ NumberFormat::format(const Formattable& obj, return cloneFmt->format(*n, appendTo, pos, status); } - if (n->isNumeric() && n->getDigitList() != NULL) { + if (n->isNumeric() && n->getDecimalQuantity() != NULL) { // Decimal Number. We will have a DigitList available if the value was // set to a decimal number, or if the value originated with a parse. // @@ -587,17 +585,17 @@ NumberFormat::format(const Formattable& obj, // know about DigitList to continue to operate as they had. // // DecimalFormat overrides the DigitList formatting functions. - format(*n->getDigitList(), appendTo, pos, status); + format(*n->getDecimalQuantity(), appendTo, pos, status); } else { switch (n->getType()) { case Formattable::kDouble: - format(n->getDouble(), appendTo, pos); + format(n->getDouble(), appendTo, pos, status); break; case Formattable::kLong: - format(n->getLong(), appendTo, pos); + format(n->getLong(), appendTo, pos, status); break; case Formattable::kInt64: - format(n->getInt64(), appendTo, pos); + format(n->getInt64(), appendTo, pos, status); break; default: status = U_INVALID_FORMAT_ERROR; @@ -633,9 +631,9 @@ NumberFormat::format(const Formattable& obj, return cloneFmt->format(*n, appendTo, posIter, status); } - if (n->isNumeric() && n->getDigitList() != NULL) { + if (n->isNumeric() && n->getDecimalQuantity() != NULL) { // Decimal Number - format(*n->getDigitList(), appendTo, posIter, status); + format(*n->getDecimalQuantity(), appendTo, posIter, status); } else { switch (n->getType()) { case Formattable::kDouble: @@ -1400,27 +1398,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale, return NULL; } - UResourceBundle *resource = ownedResource.orphan(); - UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status); - resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status); - resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); - ownedResource.adoptInstead(resource); - - int32_t patLen = 0; - const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); - - // Didn't find a pattern specific to the numbering system, so fall back to "latn" - if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) { - status = U_ZERO_ERROR; - resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status); - resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); - patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); - } - - ures_close(numElements); - - // Creates the specified decimal format style of the desired locale. - pattern.setTo(TRUE, patResStr, patLen); + // Load the pattern from data using the common library function + const char16_t* patternPtr = number::impl::utils::getPatternForStyle( + desiredLocale, + ns->getName(), + gFormatCldrStyles[style], + status); + pattern = UnicodeString(TRUE, patternPtr, -1); } if (U_FAILURE(status)) { return NULL; diff --git a/deps/icu-small/source/i18n/numparse_affixes.cpp b/deps/icu-small/source/i18n/numparse_affixes.cpp new file mode 100644 index 0000000000..c30d241693 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_affixes.cpp @@ -0,0 +1,470 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "numparse_affixes.h" +#include "numparse_utils.h" +#include "number_utils.h" + +using namespace icu; +using namespace icu::numparse; +using namespace icu::numparse::impl; +using namespace icu::number; +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) + : fMatchersLen(0), + fLastTypeOrCp(0), + fPattern(pattern), + fWarehouse(warehouse), + fIgnorables(ignorables) {} + +void AffixPatternMatcherBuilder::consumeToken(AffixPatternType type, UChar32 cp, UErrorCode& status) { + // This is called by AffixUtils.iterateWithConsumer() for each token. + + // Add an ignorables matcher between tokens except between two literals, and don't put two + // ignorables matchers in a row. + if (fIgnorables != nullptr && fMatchersLen > 0 && + (fLastTypeOrCp < 0 || !fIgnorables->getSet()->contains(fLastTypeOrCp))) { + addMatcher(*fIgnorables); + } + + if (type != TYPE_CODEPOINT) { + // Case 1: the token is a symbol. + switch (type) { + case TYPE_MINUS_SIGN: + addMatcher(fWarehouse.minusSign()); + break; + case TYPE_PLUS_SIGN: + addMatcher(fWarehouse.plusSign()); + break; + case TYPE_PERCENT: + addMatcher(fWarehouse.percent()); + break; + case TYPE_PERMILLE: + addMatcher(fWarehouse.permille()); + break; + case TYPE_CURRENCY_SINGLE: + case TYPE_CURRENCY_DOUBLE: + case TYPE_CURRENCY_TRIPLE: + case TYPE_CURRENCY_QUAD: + case TYPE_CURRENCY_QUINT: + // All currency symbols use the same matcher + addMatcher(fWarehouse.currency(status)); + break; + default: + U_ASSERT(FALSE); + } + + } else if (fIgnorables != nullptr && fIgnorables->getSet()->contains(cp)) { + // Case 2: the token is an ignorable literal. + // No action necessary: the ignorables matcher has already been added. + + } else { + // Case 3: the token is a non-ignorable literal. + addMatcher(fWarehouse.nextCodePointMatcher(cp)); + } + fLastTypeOrCp = type != TYPE_CODEPOINT ? type : cp; +} + +void AffixPatternMatcherBuilder::addMatcher(NumberParseMatcher& matcher) { + if (fMatchersLen >= fMatchers.getCapacity()) { + fMatchers.resize(fMatchersLen * 2, fMatchersLen); + } + fMatchers[fMatchersLen++] = &matcher; +} + +AffixPatternMatcher AffixPatternMatcherBuilder::build() { + return AffixPatternMatcher(fMatchers, fMatchersLen, fPattern); +} + + +CodePointMatcherWarehouse::CodePointMatcherWarehouse() + : codePointCount(0), codePointNumBatches(0) {} + +CodePointMatcherWarehouse::~CodePointMatcherWarehouse() { + // Delete the variable number of batches of code point matchers + for (int32_t i = 0; i < codePointNumBatches; i++) { + delete[] codePointsOverflow[i]; + } +} + +CodePointMatcherWarehouse::CodePointMatcherWarehouse(CodePointMatcherWarehouse&& src) U_NOEXCEPT + : codePoints(std::move(src.codePoints)), + codePointsOverflow(std::move(src.codePointsOverflow)), + codePointCount(src.codePointCount), + codePointNumBatches(src.codePointNumBatches) {} + +CodePointMatcherWarehouse& +CodePointMatcherWarehouse::operator=(CodePointMatcherWarehouse&& src) U_NOEXCEPT { + codePoints = std::move(src.codePoints); + codePointsOverflow = std::move(src.codePointsOverflow); + codePointCount = src.codePointCount; + codePointNumBatches = src.codePointNumBatches; + return *this; +} + +NumberParseMatcher& CodePointMatcherWarehouse::nextCodePointMatcher(UChar32 cp) { + if (codePointCount < CODE_POINT_STACK_CAPACITY) { + return codePoints[codePointCount++] = {cp}; + } + int32_t totalCapacity = CODE_POINT_STACK_CAPACITY + codePointNumBatches * CODE_POINT_BATCH_SIZE; + if (codePointCount >= totalCapacity) { + // Need a new batch + auto* nextBatch = new CodePointMatcher[CODE_POINT_BATCH_SIZE]; + if (codePointNumBatches >= codePointsOverflow.getCapacity()) { + // Need more room for storing pointers to batches + codePointsOverflow.resize(codePointNumBatches * 2, codePointNumBatches); + } + codePointsOverflow[codePointNumBatches++] = nextBatch; + } + return codePointsOverflow[codePointNumBatches - 1][(codePointCount++ - CODE_POINT_STACK_CAPACITY) % + CODE_POINT_BATCH_SIZE] = {cp}; +} + + +AffixTokenMatcherWarehouse::AffixTokenMatcherWarehouse(const AffixTokenMatcherSetupData* setupData) + : fSetupData(setupData) {} + +NumberParseMatcher& AffixTokenMatcherWarehouse::minusSign() { + return fMinusSign = {fSetupData->dfs, true}; +} + +NumberParseMatcher& AffixTokenMatcherWarehouse::plusSign() { + return fPlusSign = {fSetupData->dfs, true}; +} + +NumberParseMatcher& AffixTokenMatcherWarehouse::percent() { + return fPercent = {fSetupData->dfs}; +} + +NumberParseMatcher& AffixTokenMatcherWarehouse::permille() { + return fPermille = {fSetupData->dfs}; +} + +NumberParseMatcher& AffixTokenMatcherWarehouse::currency(UErrorCode& status) { + return fCurrency = {fSetupData->currencySymbols, fSetupData->dfs, fSetupData->parseFlags, status}; +} + +IgnorablesMatcher& AffixTokenMatcherWarehouse::ignorables() { + return fSetupData->ignorables; +} + +NumberParseMatcher& AffixTokenMatcherWarehouse::nextCodePointMatcher(UChar32 cp) { + return fCodePoints.nextCodePointMatcher(cp); +} + + +CodePointMatcher::CodePointMatcher(UChar32 cp) + : fCp(cp) {} + +bool CodePointMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode&) const { + if (segment.startsWith(fCp)) { + segment.adjustOffsetByCodePoint(); + result.setCharsConsumed(segment); + } + return false; +} + +bool CodePointMatcher::smokeTest(const StringSegment& segment) const { + return segment.startsWith(fCp); +} + +UnicodeString CodePointMatcher::toString() const { + return u""; +} + + +AffixPatternMatcher AffixPatternMatcher::fromAffixPattern(const UnicodeString& affixPattern, + AffixTokenMatcherWarehouse& tokenWarehouse, + parse_flags_t parseFlags, bool* success, + UErrorCode& status) { + if (affixPattern.isEmpty()) { + *success = false; + return {}; + } + *success = true; + + IgnorablesMatcher* ignorables; + if (0 != (parseFlags & PARSE_FLAG_EXACT_AFFIX)) { + ignorables = nullptr; + } else { + ignorables = &tokenWarehouse.ignorables(); + } + + AffixPatternMatcherBuilder builder(affixPattern, tokenWarehouse, ignorables); + AffixUtils::iterateWithConsumer(affixPattern, builder, status); + return builder.build(); +} + +AffixPatternMatcher::AffixPatternMatcher(MatcherArray& matchers, int32_t matchersLen, + const UnicodeString& pattern) + : ArraySeriesMatcher(matchers, matchersLen), fPattern(pattern) {} + +UnicodeString AffixPatternMatcher::getPattern() const { + return fPattern.toAliasedUnicodeString(); +} + +bool AffixPatternMatcher::operator==(const AffixPatternMatcher& other) const { + return fPattern == other.fPattern; +} + + +AffixMatcherWarehouse::AffixMatcherWarehouse(AffixTokenMatcherWarehouse* tokenWarehouse) + : fTokenWarehouse(tokenWarehouse) { +} + +bool AffixMatcherWarehouse::isInteresting(const AffixPatternProvider& patternInfo, + const IgnorablesMatcher& ignorables, parse_flags_t parseFlags, + UErrorCode& status) { + UnicodeString posPrefixString = patternInfo.getString(AffixPatternProvider::AFFIX_POS_PREFIX); + UnicodeString posSuffixString = patternInfo.getString(AffixPatternProvider::AFFIX_POS_SUFFIX); + UnicodeString negPrefixString; + UnicodeString negSuffixString; + if (patternInfo.hasNegativeSubpattern()) { + negPrefixString = patternInfo.getString(AffixPatternProvider::AFFIX_NEG_PREFIX); + negSuffixString = 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; +} + +void AffixMatcherWarehouse::createAffixMatchers(const AffixPatternProvider& patternInfo, + MutableMatcherCollection& output, + const IgnorablesMatcher& ignorables, + parse_flags_t parseFlags, UErrorCode& status) { + if (!isInteresting(patternInfo, ignorables, parseFlags, status)) { + return; + } + + // 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 includeUnpaired = 0 != (parseFlags & PARSE_FLAG_INCLUDE_UNPAIRED_AFFIXES); + UNumberSignDisplay signDisplay = (0 != (parseFlags & PARSE_FLAG_PLUS_SIGN_ALLOWED)) ? UNUM_SIGN_ALWAYS + : UNUM_SIGN_AUTO; + + int32_t numAffixMatchers = 0; + int32_t numAffixPatternMatchers = 0; + + AffixPatternMatcher* posPrefix = nullptr; + AffixPatternMatcher* posSuffix = nullptr; + + // Pre-process the affix strings to resolve LDML rules like sign display. + for (int8_t signum = 1; signum >= -1; signum--) { + // Generate Prefix + bool hasPrefix = false; + PatternStringUtils::patternInfoToStringBuilder( + patternInfo, true, signum, signDisplay, StandardPlural::OTHER, false, sb); + fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern( + sb, *fTokenWarehouse, parseFlags, &hasPrefix, status); + AffixPatternMatcher* prefix = hasPrefix ? &fAffixPatternMatchers[numAffixPatternMatchers++] + : nullptr; + + // Generate Suffix + bool hasSuffix = false; + PatternStringUtils::patternInfoToStringBuilder( + patternInfo, false, signum, signDisplay, StandardPlural::OTHER, false, sb); + fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern( + sb, *fTokenWarehouse, parseFlags, &hasSuffix, status); + AffixPatternMatcher* suffix = hasSuffix ? &fAffixPatternMatchers[numAffixPatternMatchers++] + : nullptr; + + if (signum == 1) { + posPrefix = prefix; + posSuffix = suffix; + } else if (equals(prefix, posPrefix) && equals(suffix, posSuffix)) { + // Skip adding these matchers (we already have equivalents) + continue; + } + + // Flags for setting in the ParsedNumber; the token matchers may add more. + int flags = (signum == -1) ? FLAG_NEGATIVE : 0; + + // 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}; + 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}; + } + if (signum == 1 || !equals(suffix, posSuffix)) { + fAffixMatchers[numAffixMatchers++] = {nullptr, suffix, flags}; + } + } + } + + // Put the AffixMatchers in order, and then add them to the output. + // 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 (fAffixMatchers[i - 1].compareTo(fAffixMatchers[i]) > 0) { + madeChanges = true; + AffixMatcher temp = std::move(fAffixMatchers[i - 1]); + fAffixMatchers[i - 1] = std::move(fAffixMatchers[i]); + fAffixMatchers[i] = std::move(temp); + } + } + } while (madeChanges); + + for (int32_t i = 0; i < numAffixMatchers; i++) { + // Enable the following line to debug affixes + //std::cout << "Adding affix matcher: " << CStr(fAffixMatchers[i].toString())() << std::endl; + output.addMatcher(fAffixMatchers[i]); + } +} + + +AffixMatcher::AffixMatcher(AffixPatternMatcher* prefix, AffixPatternMatcher* suffix, result_flags_t flags) + : fPrefix(prefix), fSuffix(suffix), fFlags(flags) {} + +bool AffixMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const { + if (!result.seenNumber()) { + // Prefix + // Do not match if: + // 1. We have already seen a prefix (result.prefix != null) + // 2. The prefix in this AffixMatcher is empty (prefix == null) + if (!result.prefix.isBogus() || fPrefix == nullptr) { + return false; + } + + // Attempt to match the prefix. + int initialOffset = segment.getOffset(); + bool maybeMore = fPrefix->match(segment, result, status); + if (initialOffset != segment.getOffset()) { + result.prefix = fPrefix->getPattern(); + } + return maybeMore; + + } else { + // Suffix + // Do not match if: + // 1. We have already seen a suffix (result.suffix != null) + // 2. The suffix in this AffixMatcher is empty (suffix == null) + // 3. The matched prefix does not equal this AffixMatcher's prefix + if (!result.suffix.isBogus() || fSuffix == nullptr || !matched(fPrefix, result.prefix)) { + return false; + } + + // Attempt to match the suffix. + int initialOffset = segment.getOffset(); + bool maybeMore = fSuffix->match(segment, result, status); + if (initialOffset != segment.getOffset()) { + result.suffix = fSuffix->getPattern(); + } + return maybeMore; + } +} + +bool AffixMatcher::smokeTest(const StringSegment& segment) const { + return (fPrefix != nullptr && fPrefix->smokeTest(segment)) || + (fSuffix != nullptr && fSuffix->smokeTest(segment)); +} + +void AffixMatcher::postProcess(ParsedNumber& result) const { + // Check to see if our affix is the one that was matched. If so, set the flags in the result. + if (matched(fPrefix, result.prefix) && matched(fSuffix, result.suffix)) { + // Fill in the result prefix and suffix with non-null values (empty string). + // Used by strict mode to determine whether an entire affix pair was matched. + if (result.prefix.isBogus()) { + result.prefix = UnicodeString(); + } + if (result.suffix.isBogus()) { + result.suffix = UnicodeString(); + } + result.flags |= fFlags; + if (fPrefix != nullptr) { + fPrefix->postProcess(result); + } + if (fSuffix != nullptr) { + fSuffix->postProcess(result); + } + } +} + +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; + } +} + +UnicodeString AffixMatcher::toString() const { + bool isNegative = 0 != (fFlags & FLAG_NEGATIVE); + return UnicodeString(u"getPattern() : u"null") + u"#" + + (fSuffix ? fSuffix->getPattern() : u"null") + u">"; + +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_affixes.h b/deps/icu-small/source/i18n/numparse_affixes.h new file mode 100644 index 0000000000..be8c4fb564 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_affixes.h @@ -0,0 +1,255 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_AFFIXES_H__ +#define __NUMPARSE_AFFIXES_H__ + +#include "numparse_types.h" +#include "numparse_symbols.h" +#include "numparse_currency.h" +#include "number_affixutils.h" +#include "number_currencysymbols.h" + +#include + +U_NAMESPACE_BEGIN +namespace numparse { +namespace impl { + +// Forward-declaration of implementation classes for friending +class AffixPatternMatcherBuilder; +class AffixPatternMatcher; + +using ::icu::number::impl::AffixPatternProvider; +using ::icu::number::impl::TokenConsumer; +using ::icu::number::impl::CurrencySymbols; + + +class CodePointMatcher : public NumberParseMatcher, public UMemory { + public: + CodePointMatcher() = default; // WARNING: Leaves the object in an unusable state + + CodePointMatcher(UChar32 cp); + + bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override; + + bool smokeTest(const StringSegment& segment) const override; + + UnicodeString toString() const override; + + private: + UChar32 fCp; +}; + +} // namespace impl +} // namespace numparse + +// Export a explicit template instantiations of MaybeStackArray and CompactUnicodeString. +// When building DLLs for Windows this is required even though no direct access leaks out of the i18n library. +// (See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.) +// Note: These need to be outside of the impl::numparse namespace, or Clang will generate a compile error. +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +template class U_I18N_API MaybeStackArray; +template class U_I18N_API MaybeStackArray; +template class U_I18N_API numparse::impl::CompactUnicodeString<4>; +#endif + +namespace numparse { +namespace impl { + +/** + * A warehouse to retain ownership of CodePointMatchers. + */ +// Exported as U_I18N_API for tests +class U_I18N_API CodePointMatcherWarehouse : public UMemory { + private: + static constexpr int32_t CODE_POINT_STACK_CAPACITY = 5; // Number of entries directly on the stack + static constexpr int32_t CODE_POINT_BATCH_SIZE = 10; // Number of entries per heap allocation + + public: + CodePointMatcherWarehouse(); + + // A custom destructor is needed to free the memory from MaybeStackArray. + // A custom move constructor and move assignment seem to be needed because of the custom destructor. + + ~CodePointMatcherWarehouse(); + + CodePointMatcherWarehouse(CodePointMatcherWarehouse&& src) U_NOEXCEPT; + + CodePointMatcherWarehouse& operator=(CodePointMatcherWarehouse&& src) U_NOEXCEPT; + + NumberParseMatcher& nextCodePointMatcher(UChar32 cp); + + private: + std::array codePoints; // By value + MaybeStackArray codePointsOverflow; // On heap in "batches" + int32_t codePointCount; // Total for both the ones by value and on heap + int32_t codePointNumBatches; // Number of batches in codePointsOverflow +}; + + +struct AffixTokenMatcherSetupData { + const CurrencySymbols& currencySymbols; + const DecimalFormatSymbols& dfs; + IgnorablesMatcher& ignorables; + const Locale& locale; + parse_flags_t parseFlags; +}; + + +/** + * Small helper class that generates matchers for individual tokens for AffixPatternMatcher. + * + * In Java, this is called AffixTokenMatcherFactory (a "factory"). However, in C++, it is called a + * "warehouse", because in addition to generating the matchers, it also retains ownership of them. The + * warehouse must stay in scope for the whole lifespan of the AffixPatternMatcher that uses matchers from + * the warehouse. + * + * @author sffc + */ +// Exported as U_I18N_API for tests +class U_I18N_API AffixTokenMatcherWarehouse : public UMemory { + public: + AffixTokenMatcherWarehouse() = default; // WARNING: Leaves the object in an unusable state + + AffixTokenMatcherWarehouse(const AffixTokenMatcherSetupData* setupData); + + NumberParseMatcher& minusSign(); + + NumberParseMatcher& plusSign(); + + NumberParseMatcher& percent(); + + NumberParseMatcher& permille(); + + NumberParseMatcher& currency(UErrorCode& status); + + IgnorablesMatcher& ignorables(); + + NumberParseMatcher& nextCodePointMatcher(UChar32 cp); + + private: + // NOTE: The following field may be unsafe to access after construction is done! + const AffixTokenMatcherSetupData* fSetupData; + + // NOTE: These are default-constructed and should not be used until initialized. + MinusSignMatcher fMinusSign; + PlusSignMatcher fPlusSign; + PercentMatcher fPercent; + PermilleMatcher fPermille; + CombinedCurrencyMatcher fCurrency; + + // Use a child class for code point matchers, since it requires non-default operators. + CodePointMatcherWarehouse fCodePoints; + + friend class AffixPatternMatcherBuilder; + friend class AffixPatternMatcher; +}; + + +class AffixPatternMatcherBuilder : public TokenConsumer, public MutableMatcherCollection { + public: + AffixPatternMatcherBuilder(const UnicodeString& pattern, AffixTokenMatcherWarehouse& warehouse, + IgnorablesMatcher* ignorables); + + void consumeToken(::icu::number::impl::AffixPatternType type, UChar32 cp, UErrorCode& status) override; + + /** NOTE: You can build only once! */ + AffixPatternMatcher build(); + + private: + ArraySeriesMatcher::MatcherArray fMatchers; + int32_t fMatchersLen; + int32_t fLastTypeOrCp; + + const UnicodeString& fPattern; + AffixTokenMatcherWarehouse& fWarehouse; + IgnorablesMatcher* fIgnorables; + + void addMatcher(NumberParseMatcher& matcher) override; +}; + + +// Exported as U_I18N_API for tests +class U_I18N_API AffixPatternMatcher : public ArraySeriesMatcher { + public: + AffixPatternMatcher() = default; // WARNING: Leaves the object in an unusable state + + static AffixPatternMatcher fromAffixPattern(const UnicodeString& affixPattern, + AffixTokenMatcherWarehouse& warehouse, + parse_flags_t parseFlags, bool* success, + UErrorCode& status); + + UnicodeString getPattern() const; + + bool operator==(const AffixPatternMatcher& other) const; + + private: + CompactUnicodeString<4> fPattern; + + AffixPatternMatcher(MatcherArray& matchers, int32_t matchersLen, const UnicodeString& pattern); + + friend class AffixPatternMatcherBuilder; +}; + + +class AffixMatcher : public NumberParseMatcher, public UMemory { + public: + AffixMatcher() = default; // WARNING: Leaves the object in an unusable state + + AffixMatcher(AffixPatternMatcher* prefix, AffixPatternMatcher* suffix, result_flags_t flags); + + bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override; + + void postProcess(ParsedNumber& result) const override; + + bool smokeTest(const StringSegment& segment) const override; + + int8_t compareTo(const AffixMatcher& rhs) const; + + UnicodeString toString() const override; + + private: + AffixPatternMatcher* fPrefix; + AffixPatternMatcher* fSuffix; + result_flags_t fFlags; +}; + + +/** + * A C++-only class to retain ownership of the AffixMatchers needed for parsing. + */ +class AffixMatcherWarehouse { + public: + AffixMatcherWarehouse() = default; // WARNING: Leaves the object in an unusable state + + AffixMatcherWarehouse(AffixTokenMatcherWarehouse* tokenWarehouse); + + void createAffixMatchers(const AffixPatternProvider& patternInfo, MutableMatcherCollection& output, + 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 + AffixMatcher fAffixMatchers[9]; + // 6 is the limit: positive, zero, and negative, a prefix and a suffix for each + AffixPatternMatcher fAffixPatternMatchers[6]; + // Reference to the warehouse for tokens used by the AffixPatternMatchers + AffixTokenMatcherWarehouse* fTokenWarehouse; + + friend class AffixMatcher; + + static bool isInteresting(const AffixPatternProvider& patternInfo, const IgnorablesMatcher& ignorables, + parse_flags_t parseFlags, UErrorCode& status); +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_AFFIXES_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_compositions.cpp b/deps/icu-small/source/i18n/numparse_compositions.cpp new file mode 100644 index 0000000000..19253da805 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_compositions.cpp @@ -0,0 +1,107 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "numparse_compositions.h" +#include "unicode/uniset.h" + +using namespace icu; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +bool SeriesMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const { + ParsedNumber backup(result); + + int32_t initialOffset = segment.getOffset(); + bool maybeMore = true; + for (auto* it = begin(); it < end();) { + const NumberParseMatcher* matcher = *it; + int matcherOffset = segment.getOffset(); + if (segment.length() != 0) { + maybeMore = matcher->match(segment, result, status); + } else { + // Nothing for this matcher to match; ask for more. + maybeMore = true; + } + + bool success = (segment.getOffset() != matcherOffset); + bool isFlexible = matcher->isFlexible(); + if (success && isFlexible) { + // Match succeeded, and this is a flexible matcher. Re-run it. + } else if (success) { + // Match succeeded, and this is NOT a flexible matcher. Proceed to the next matcher. + it++; + // Small hack: if there is another matcher coming, do not accept trailing weak chars. + // Needed for proper handling of currency spacing. + if (it < end() && segment.getOffset() != result.charEnd && result.charEnd > matcherOffset) { + segment.setOffset(result.charEnd); + } + } else if (isFlexible) { + // Match failed, and this is a flexible matcher. Try again with the next matcher. + it++; + } else { + // Match failed, and this is NOT a flexible matcher. Exit. + segment.setOffset(initialOffset); + result = backup; + return maybeMore; + } + } + + // All matchers in the series succeeded. + return maybeMore; +} + +bool SeriesMatcher::smokeTest(const StringSegment& segment) const { + // NOTE: The range-based for loop calls the virtual begin() and end() methods. + // NOTE: We only want the first element. Use the for loop for boundary checking. + for (auto& matcher : *this) { + // SeriesMatchers are never allowed to start with a Flexible matcher. + U_ASSERT(!matcher->isFlexible()); + return matcher->smokeTest(segment); + } + return false; +} + +void SeriesMatcher::postProcess(ParsedNumber& result) const { + // NOTE: The range-based for loop calls the virtual begin() and end() methods. + for (auto* matcher : *this) { + matcher->postProcess(result); + } +} + + +ArraySeriesMatcher::ArraySeriesMatcher() + : fMatchersLen(0) { +} + +ArraySeriesMatcher::ArraySeriesMatcher(MatcherArray& matchers, int32_t matchersLen) + : fMatchers(std::move(matchers)), fMatchersLen(matchersLen) { +} + +int32_t ArraySeriesMatcher::length() const { + return fMatchersLen; +} + +const NumberParseMatcher* const* ArraySeriesMatcher::begin() const { + return fMatchers.getAlias(); +} + +const NumberParseMatcher* const* ArraySeriesMatcher::end() const { + return fMatchers.getAlias() + fMatchersLen; +} + +UnicodeString ArraySeriesMatcher::toString() const { + return u""; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_compositions.h b/deps/icu-small/source/i18n/numparse_compositions.h new file mode 100644 index 0000000000..f085912def --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_compositions.h @@ -0,0 +1,124 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __SOURCE_NUMPARSE_COMPOSITIONS__ +#define __SOURCE_NUMPARSE_COMPOSITIONS__ + +#include "numparse_types.h" + +U_NAMESPACE_BEGIN + +// Export an explicit template instantiation of the MaybeStackArray that is used as a data member of ArraySeriesMatcher. +// When building DLLs for Windows this is required even though no direct access to the MaybeStackArray leaks out of the i18n library. +// (See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.) +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +template class U_I18N_API MaybeStackArray; +#endif + +namespace numparse { +namespace impl { + +/** + * Base class for AnyMatcher and SeriesMatcher. + */ +// Exported as U_I18N_API for tests +class U_I18N_API CompositionMatcher : public NumberParseMatcher { + protected: + // No construction except by subclasses! + CompositionMatcher() = default; + + // To be overridden by subclasses (used for iteration): + virtual const NumberParseMatcher* const* begin() const = 0; + + // To be overridden by subclasses (used for iteration): + virtual const NumberParseMatcher* const* end() const = 0; +}; + + +// NOTE: AnyMatcher is no longer being used. The previous definition is shown below. +// The implementation can be found in SVN source control, deleted around March 30, 2018. +///** +// * Composes a number of matchers, and succeeds if any of the matchers succeed. Always greedily chooses +// * the first matcher in the list to succeed. +// * +// * NOTE: In C++, this is a base class, unlike ICU4J, which uses a factory-style interface. +// * +// * @author sffc +// * @see SeriesMatcher +// */ +//class AnyMatcher : public CompositionMatcher { +// public: +// bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override; +// +// bool smokeTest(const StringSegment& segment) const override; +// +// void postProcess(ParsedNumber& result) const override; +// +// protected: +// // No construction except by subclasses! +// AnyMatcher() = default; +//}; + + +/** + * Composes a number of matchers, running one after another. Matches the input string only if all of the + * matchers in the series succeed. Performs greedy matches within the context of the series. + * + * @author sffc + * @see AnyMatcher + */ +// Exported as U_I18N_API for tests +class U_I18N_API SeriesMatcher : public CompositionMatcher { + public: + bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override; + + bool smokeTest(const StringSegment& segment) const override; + + void postProcess(ParsedNumber& result) const override; + + virtual int32_t length() const = 0; + + protected: + // No construction except by subclasses! + SeriesMatcher() = default; +}; + +/** + * An implementation of SeriesMatcher that references an array of matchers. + * + * The object adopts the array, but NOT the matchers contained inside the array. + */ +// Exported as U_I18N_API for tests +class U_I18N_API ArraySeriesMatcher : public SeriesMatcher { + public: + ArraySeriesMatcher(); // WARNING: Leaves the object in an unusable state + + typedef MaybeStackArray MatcherArray; + + /** The array is std::move'd */ + ArraySeriesMatcher(MatcherArray& matchers, int32_t matchersLen); + + UnicodeString toString() const override; + + int32_t length() const override; + + protected: + const NumberParseMatcher* const* begin() const override; + + const NumberParseMatcher* const* end() const override; + + private: + MatcherArray fMatchers; + int32_t fMatchersLen; +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__SOURCE_NUMPARSE_COMPOSITIONS__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_currency.cpp b/deps/icu-small/source/i18n/numparse_currency.cpp new file mode 100644 index 0000000000..ae8196ec48 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_currency.cpp @@ -0,0 +1,186 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "numparse_currency.h" +#include "ucurrimp.h" +#include "unicode/errorcode.h" +#include "numparse_utils.h" + +using namespace icu; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +CombinedCurrencyMatcher::CombinedCurrencyMatcher(const CurrencySymbols& currencySymbols, const DecimalFormatSymbols& dfs, + parse_flags_t parseFlags, UErrorCode& status) + : fCurrency1(currencySymbols.getCurrencySymbol(status)), + fCurrency2(currencySymbols.getIntlCurrencySymbol(status)), + fUseFullCurrencyData(0 == (parseFlags & PARSE_FLAG_NO_FOREIGN_CURRENCY)), + afterPrefixInsert(dfs.getPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, false, status)), + beforeSuffixInsert(dfs.getPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, true, status)), + fLocaleName(dfs.getLocale().getName(), -1, status) { + utils::copyCurrencyCode(fCurrencyCode, currencySymbols.getIsoCode()); + + // Pre-load the long names for the current locale and currency + // if we are parsing without the full currency data. + if (!fUseFullCurrencyData) { + for (int32_t i=0; i(i); + fLocalLongNames[i] = currencySymbols.getPluralName(plural, status); + } + } + + // TODO: Figure out how to make this faster and re-enable. + // Computing the "lead code points" set for fastpathing is too slow to use in production. + // See http://bugs.icu-project.org/trac/ticket/13584 +// // Compute the full set of characters that could be the first in a currency to allow for +// // efficient smoke test. +// fLeadCodePoints.add(fCurrency1.char32At(0)); +// fLeadCodePoints.add(fCurrency2.char32At(0)); +// fLeadCodePoints.add(beforeSuffixInsert.char32At(0)); +// uprv_currencyLeads(fLocaleName.data(), fLeadCodePoints, status); +// // Always apply case mapping closure for currencies +// fLeadCodePoints.closeOver(USET_ADD_CASE_MAPPINGS); +// fLeadCodePoints.freeze(); +} + +bool +CombinedCurrencyMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const { + if (result.currencyCode[0] != 0) { + return false; + } + + // Try to match a currency spacing separator. + int32_t initialOffset = segment.getOffset(); + bool maybeMore = false; + if (result.seenNumber() && !beforeSuffixInsert.isEmpty()) { + int32_t overlap = segment.getCommonPrefixLength(beforeSuffixInsert); + if (overlap == beforeSuffixInsert.length()) { + segment.adjustOffset(overlap); + // Note: let currency spacing be a weak match. Don't update chars consumed. + } + maybeMore = maybeMore || overlap == segment.length(); + } + + // Match the currency string, and reset if we didn't find one. + maybeMore = maybeMore || matchCurrency(segment, result, status); + if (result.currencyCode[0] == 0) { + segment.setOffset(initialOffset); + return maybeMore; + } + + // Try to match a currency spacing separator. + if (!result.seenNumber() && !afterPrefixInsert.isEmpty()) { + int32_t overlap = segment.getCommonPrefixLength(afterPrefixInsert); + if (overlap == afterPrefixInsert.length()) { + segment.adjustOffset(overlap); + // Note: let currency spacing be a weak match. Don't update chars consumed. + } + maybeMore = maybeMore || overlap == segment.length(); + } + + return maybeMore; +} + +bool CombinedCurrencyMatcher::matchCurrency(StringSegment& segment, ParsedNumber& result, + UErrorCode& status) const { + bool maybeMore = false; + + int32_t overlap1; + if (!fCurrency1.isEmpty()) { + overlap1 = segment.getCaseSensitivePrefixLength(fCurrency1); + } else { + overlap1 = -1; + } + maybeMore = maybeMore || overlap1 == segment.length(); + if (overlap1 == fCurrency1.length()) { + utils::copyCurrencyCode(result.currencyCode, fCurrencyCode); + segment.adjustOffset(overlap1); + result.setCharsConsumed(segment); + return maybeMore; + } + + int32_t overlap2; + if (!fCurrency2.isEmpty()) { + overlap2 = segment.getCaseSensitivePrefixLength(fCurrency2); + } else { + overlap2 = -1; + } + maybeMore = maybeMore || overlap2 == segment.length(); + if (overlap2 == fCurrency2.length()) { + utils::copyCurrencyCode(result.currencyCode, fCurrencyCode); + segment.adjustOffset(overlap2); + result.setCharsConsumed(segment); + return maybeMore; + } + + if (fUseFullCurrencyData) { + // Use the full currency data. + // NOTE: This call site should be improved with #13584. + const UnicodeString segmentString = segment.toTempUnicodeString(); + + // Try to parse the currency + ParsePosition ppos(0); + int32_t partialMatchLen = 0; + uprv_parseCurrency( + fLocaleName.data(), + segmentString, + ppos, + UCURR_SYMBOL_NAME, // checks for both UCURR_SYMBOL_NAME and UCURR_LONG_NAME + &partialMatchLen, + result.currencyCode, + status); + maybeMore = maybeMore || partialMatchLen == segment.length(); + + if (U_SUCCESS(status) && ppos.getIndex() != 0) { + // Complete match. + // NOTE: The currency code should already be saved in the ParsedNumber. + segment.adjustOffset(ppos.getIndex()); + result.setCharsConsumed(segment); + return maybeMore; + } + + } else { + // Use the locale long names. + int32_t longestFullMatch = 0; + for (int32_t i=0; i longestFullMatch) { + longestFullMatch = name.length(); + } + maybeMore = maybeMore || overlap > 0; + } + if (longestFullMatch > 0) { + utils::copyCurrencyCode(result.currencyCode, fCurrencyCode); + segment.adjustOffset(longestFullMatch); + result.setCharsConsumed(segment); + return maybeMore; + } + } + + // No match found. + return maybeMore; +} + +bool CombinedCurrencyMatcher::smokeTest(const StringSegment&) const { + // TODO: See constructor + return true; + //return segment.startsWith(fLeadCodePoints); +} + +UnicodeString CombinedCurrencyMatcher::toString() const { + return u""; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_currency.h b/deps/icu-small/source/i18n/numparse_currency.h new file mode 100644 index 0000000000..a94943312f --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_currency.h @@ -0,0 +1,74 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_CURRENCY_H__ +#define __NUMPARSE_CURRENCY_H__ + +#include "numparse_types.h" +#include "numparse_compositions.h" +#include "charstr.h" +#include "number_currencysymbols.h" +#include "unicode/uniset.h" + +U_NAMESPACE_BEGIN namespace numparse { +namespace impl { + +using ::icu::number::impl::CurrencySymbols; + +/** + * Matches a currency, either a custom currency or one from the data bundle. The class is called + * "combined" to emphasize that the currency string may come from one of multiple sources. + * + * Will match currency spacing either before or after the number depending on whether we are currently in + * the prefix or suffix. + * + * The implementation of this class is slightly different between J and C. See #13584 for a follow-up. + * + * @author sffc + */ +// Exported as U_I18N_API for tests +class U_I18N_API CombinedCurrencyMatcher : public NumberParseMatcher, public UMemory { + public: + CombinedCurrencyMatcher() = default; // WARNING: Leaves the object in an unusable state + + CombinedCurrencyMatcher(const CurrencySymbols& currencySymbols, const DecimalFormatSymbols& dfs, + parse_flags_t parseFlags, UErrorCode& status); + + bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override; + + bool smokeTest(const StringSegment& segment) const override; + + UnicodeString toString() const override; + + private: + UChar fCurrencyCode[4]; + UnicodeString fCurrency1; + UnicodeString fCurrency2; + + bool fUseFullCurrencyData; + UnicodeString fLocalLongNames[StandardPlural::COUNT]; + + UnicodeString afterPrefixInsert; + UnicodeString beforeSuffixInsert; + + // We could use Locale instead of CharString here, but + // Locale has a non-trivial default constructor. + CharString fLocaleName; + + // TODO: See comments in constructor in numparse_currency.cpp + // UnicodeSet fLeadCodePoints; + + /** Matches the currency string without concern for currency spacing. */ + bool matchCurrency(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const; +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_CURRENCY_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_decimal.cpp b/deps/icu-small/source/i18n/numparse_decimal.cpp new file mode 100644 index 0000000000..b120c5c6ad --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_decimal.cpp @@ -0,0 +1,458 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "numparse_decimal.h" +#include "static_unicode_sets.h" +#include "numparse_utils.h" +#include "unicode/uchar.h" +#include "putilimp.h" +#include "number_decimalquantity.h" + +using namespace icu; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +DecimalMatcher::DecimalMatcher(const DecimalFormatSymbols& symbols, const Grouper& grouper, + parse_flags_t parseFlags) { + if (0 != (parseFlags & PARSE_FLAG_MONETARY_SEPARATORS)) { + groupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); + decimalSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); + } else { + groupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); + decimalSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); + } + bool strictSeparators = 0 != (parseFlags & PARSE_FLAG_STRICT_SEPARATORS); + unisets::Key groupingKey = strictSeparators ? unisets::STRICT_ALL_SEPARATORS + : unisets::ALL_SEPARATORS; + + // Attempt to find separators in the static cache + + groupingUniSet = unisets::get(groupingKey); + unisets::Key decimalKey = unisets::chooseFrom( + decimalSeparator, + strictSeparators ? unisets::STRICT_COMMA : unisets::COMMA, + strictSeparators ? unisets::STRICT_PERIOD : unisets::PERIOD); + if (decimalKey >= 0) { + decimalUniSet = unisets::get(decimalKey); + } else if (!decimalSeparator.isEmpty()) { + auto* set = new UnicodeSet(); + set->add(decimalSeparator.char32At(0)); + set->freeze(); + decimalUniSet = set; + fLocalDecimalUniSet.adoptInstead(set); + } else { + decimalUniSet = unisets::get(unisets::EMPTY); + } + + if (groupingKey >= 0 && decimalKey >= 0) { + // Everything is available in the static cache + separatorSet = groupingUniSet; + leadSet = unisets::get( + strictSeparators ? unisets::DIGITS_OR_ALL_SEPARATORS + : unisets::DIGITS_OR_STRICT_ALL_SEPARATORS); + } else { + auto* set = new UnicodeSet(); + set->addAll(*groupingUniSet); + set->addAll(*decimalUniSet); + set->freeze(); + separatorSet = set; + fLocalSeparatorSet.adoptInstead(set); + leadSet = nullptr; + } + + UChar32 cpZero = symbols.getCodePointZero(); + if (cpZero == -1 || !u_isdigit(cpZero) || u_digit(cpZero, 10) != 0) { + // Uncommon case: okay to allocate. + auto digitStrings = new UnicodeString[10]; + fLocalDigitStrings.adoptInstead(digitStrings); + for (int32_t i = 0; i <= 9; i++) { + digitStrings[i] = symbols.getConstDigitSymbol(i); + } + } + + requireGroupingMatch = 0 != (parseFlags & PARSE_FLAG_STRICT_GROUPING_SIZE); + groupingDisabled = 0 != (parseFlags & PARSE_FLAG_GROUPING_DISABLED); + integerOnly = 0 != (parseFlags & PARSE_FLAG_INTEGER_ONLY); + grouping1 = grouper.getPrimary(); + grouping2 = grouper.getSecondary(); + + // Fraction grouping parsing is disabled for now but could be enabled later. + // See http://bugs.icu-project.org/trac/ticket/10794 + // fractionGrouping = 0 != (parseFlags & PARSE_FLAG_FRACTION_GROUPING_ENABLED); +} + +bool DecimalMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const { + return match(segment, result, 0, status); +} + +bool DecimalMatcher::match(StringSegment& segment, ParsedNumber& result, int8_t exponentSign, + UErrorCode&) const { + if (result.seenNumber() && exponentSign == 0) { + // A number has already been consumed. + return false; + } else if (exponentSign != 0) { + // scientific notation always comes after the number + U_ASSERT(!result.quantity.bogus); + } + + // Initial offset before any character consumption. + int32_t initialOffset = segment.getOffset(); + + // Return value: whether to ask for more characters. + bool maybeMore = false; + + // All digits consumed so far. + number::impl::DecimalQuantity digitsConsumed; + digitsConsumed.bogus = true; + + // The total number of digits after the decimal place, used for scaling the result. + int32_t digitsAfterDecimalPlace = 0; + + // The actual grouping and decimal separators used in the string. + // If non-null, we have seen that token. + UnicodeString actualGroupingString; + UnicodeString actualDecimalString; + actualGroupingString.setToBogus(); + actualDecimalString.setToBogus(); + + // Information for two groups: the previous group and the current group. + // + // Each group has three pieces of information: + // + // Offset: the string position of the beginning of the group, including a leading separator + // if there was a leading separator. This is needed in case we need to rewind the parse to + // that position. + // + // Separator type: + // 0 => beginning of string + // 1 => lead separator is a grouping separator + // 2 => lead separator is a decimal separator + // + // Count: the number of digits in the group. If -1, the group has been validated. + int32_t currGroupOffset = 0; + int32_t currGroupSepType = 0; + int32_t currGroupCount = 0; + int32_t prevGroupOffset = -1; + int32_t prevGroupSepType = -1; + int32_t prevGroupCount = -1; + + while (segment.length() > 0) { + maybeMore = false; + + // Attempt to match a digit. + int8_t digit = -1; + + // Try by code point digit value. + UChar32 cp = segment.getCodePoint(); + if (u_isdigit(cp)) { + segment.adjustOffset(U16_LENGTH(cp)); + digit = static_cast(u_digit(cp, 10)); + } + + // Try by digit string. + if (digit == -1 && !fLocalDigitStrings.isNull()) { + for (int32_t i = 0; i < 10; i++) { + const UnicodeString& str = fLocalDigitStrings[i]; + if (str.isEmpty()) { + continue; + } + int32_t overlap = segment.getCommonPrefixLength(str); + if (overlap == str.length()) { + segment.adjustOffset(overlap); + digit = static_cast(i); + break; + } + maybeMore = maybeMore || (overlap == segment.length()); + } + } + + if (digit >= 0) { + // Digit was found. + if (digitsConsumed.bogus) { + digitsConsumed.bogus = false; + digitsConsumed.clear(); + } + digitsConsumed.appendDigit(digit, 0, true); + currGroupCount++; + if (!actualDecimalString.isBogus()) { + digitsAfterDecimalPlace++; + } + continue; + } + + // Attempt to match a literal grouping or decimal separator. + bool isDecimal = false; + bool isGrouping = false; + + // 1) Attempt the decimal separator string literal. + // if (we have not seen a decimal separator yet) { ... } + if (actualDecimalString.isBogus() && !decimalSeparator.isEmpty()) { + int32_t overlap = segment.getCommonPrefixLength(decimalSeparator); + maybeMore = maybeMore || (overlap == segment.length()); + if (overlap == decimalSeparator.length()) { + isDecimal = true; + actualDecimalString = decimalSeparator; + } + } + + // 2) Attempt to match the actual grouping string literal. + if (!actualGroupingString.isBogus()) { + int32_t overlap = segment.getCommonPrefixLength(actualGroupingString); + maybeMore = maybeMore || (overlap == segment.length()); + if (overlap == actualGroupingString.length()) { + isGrouping = true; + } + } + + // 2.5) Attempt to match a new the grouping separator string literal. + // if (we have not seen a grouping or decimal separator yet) { ... } + if (!groupingDisabled && actualGroupingString.isBogus() && actualDecimalString.isBogus() && + !groupingSeparator.isEmpty()) { + int32_t overlap = segment.getCommonPrefixLength(groupingSeparator); + maybeMore = maybeMore || (overlap == segment.length()); + if (overlap == groupingSeparator.length()) { + isGrouping = true; + actualGroupingString = groupingSeparator; + } + } + + // 3) Attempt to match a decimal separator from the equivalence set. + // if (we have not seen a decimal separator yet) { ... } + // The !isGrouping is to confirm that we haven't yet matched the current character. + if (!isGrouping && actualDecimalString.isBogus()) { + if (decimalUniSet->contains(cp)) { + isDecimal = true; + actualDecimalString = UnicodeString(cp); + } + } + + // 4) Attempt to match a grouping separator from the equivalence set. + // if (we have not seen a grouping or decimal separator yet) { ... } + if (!groupingDisabled && actualGroupingString.isBogus() && actualDecimalString.isBogus()) { + if (groupingUniSet->contains(cp)) { + isGrouping = true; + actualGroupingString = UnicodeString(cp); + } + } + + // Leave if we failed to match this as a separator. + if (!isDecimal && !isGrouping) { + break; + } + + // Check for conditions when we don't want to accept the separator. + if (isDecimal && integerOnly) { + break; + } else if (currGroupSepType == 2 && isGrouping) { + // Fraction grouping + break; + } + + // Validate intermediate grouping sizes. + bool prevValidSecondary = validateGroup(prevGroupSepType, prevGroupCount, false); + bool currValidPrimary = validateGroup(currGroupSepType, currGroupCount, true); + if (!prevValidSecondary || (isDecimal && !currValidPrimary)) { + // Invalid grouping sizes. + if (isGrouping && currGroupCount == 0) { + // Trailing grouping separators: these are taken care of below + U_ASSERT(currGroupSepType == 1); + } else if (requireGroupingMatch) { + // Strict mode: reject the parse + digitsConsumed.clear(); + digitsConsumed.bogus = true; + } + break; + } else if (requireGroupingMatch && currGroupCount == 0 && currGroupSepType == 1) { + break; + } else { + // Grouping sizes OK so far. + prevGroupOffset = currGroupOffset; + prevGroupCount = currGroupCount; + if (isDecimal) { + // Do not validate this group any more. + prevGroupSepType = -1; + } else { + prevGroupSepType = currGroupSepType; + } + } + + // OK to accept the separator. + // Special case: don't update currGroup if it is empty; this allows two grouping + // separators in a row in lenient mode. + if (currGroupCount != 0) { + currGroupOffset = segment.getOffset(); + } + currGroupSepType = isGrouping ? 1 : 2; + currGroupCount = 0; + if (isGrouping) { + segment.adjustOffset(actualGroupingString.length()); + } else { + segment.adjustOffset(actualDecimalString.length()); + } + } + + // End of main loop. + // Back up if there was a trailing grouping separator. + // Shift prev -> curr so we can check it as a final group. + if (currGroupSepType != 2 && currGroupCount == 0) { + maybeMore = true; + segment.setOffset(currGroupOffset); + currGroupOffset = prevGroupOffset; + currGroupSepType = prevGroupSepType; + currGroupCount = prevGroupCount; + prevGroupOffset = -1; + prevGroupSepType = 0; + prevGroupCount = 1; + } + + // Validate final grouping sizes. + bool prevValidSecondary = validateGroup(prevGroupSepType, prevGroupCount, false); + bool currValidPrimary = validateGroup(currGroupSepType, currGroupCount, true); + if (!requireGroupingMatch) { + // The cases we need to handle here are lone digits. + // Examples: "1,1" "1,1," "1,1,1" "1,1,1," ",1" (all parse as 1) + // See more examples in numberformattestspecification.txt + int32_t digitsToRemove = 0; + if (!prevValidSecondary) { + segment.setOffset(prevGroupOffset); + digitsToRemove += prevGroupCount; + digitsToRemove += currGroupCount; + } else if (!currValidPrimary && (prevGroupSepType != 0 || prevGroupCount != 0)) { + maybeMore = true; + segment.setOffset(currGroupOffset); + digitsToRemove += currGroupCount; + } + if (digitsToRemove != 0) { + digitsConsumed.adjustMagnitude(-digitsToRemove); + digitsConsumed.truncate(); + } + prevValidSecondary = true; + currValidPrimary = true; + } + if (currGroupSepType != 2 && (!prevValidSecondary || !currValidPrimary)) { + // Grouping failure. + digitsConsumed.bogus = true; + } + + // Strings that start with a separator but have no digits, + // or strings that failed a grouping size check. + if (digitsConsumed.bogus) { + maybeMore = maybeMore || (segment.length() == 0); + segment.setOffset(initialOffset); + return maybeMore; + } + + // We passed all inspections. Start post-processing. + + // Adjust for fraction part. + digitsConsumed.adjustMagnitude(-digitsAfterDecimalPlace); + + // Set the digits, either normal or exponent. + if (exponentSign != 0 && segment.getOffset() != initialOffset) { + bool overflow = false; + if (digitsConsumed.fitsInLong()) { + int64_t exponentLong = digitsConsumed.toLong(false); + U_ASSERT(exponentLong >= 0); + if (exponentLong <= INT32_MAX) { + auto exponentInt = static_cast(exponentLong); + if (result.quantity.adjustMagnitude(exponentSign * exponentInt)) { + overflow = true; + } + } else { + overflow = true; + } + } else { + overflow = true; + } + if (overflow) { + if (exponentSign == -1) { + // Set to zero + result.quantity.clear(); + } else { + // Set to infinity + result.quantity.bogus = true; + result.flags |= FLAG_INFINITY; + } + } + } else { + result.quantity = digitsConsumed; + } + + // Set other information into the result and return. + if (!actualDecimalString.isBogus()) { + result.flags |= FLAG_HAS_DECIMAL_SEPARATOR; + } + result.setCharsConsumed(segment); + return segment.length() == 0 || maybeMore; +} + +bool DecimalMatcher::validateGroup(int32_t sepType, int32_t count, bool isPrimary) const { + if (requireGroupingMatch) { + if (sepType == -1) { + // No such group (prevGroup before first shift). + return true; + } else if (sepType == 0) { + // First group. + if (isPrimary) { + // No grouping separators is OK. + return true; + } else { + return count != 0 && count <= grouping2; + } + } else if (sepType == 1) { + // Middle group. + if (isPrimary) { + return count == grouping1; + } else { + return count == grouping2; + } + } else { + U_ASSERT(sepType == 2); + // After the decimal separator. + return true; + } + } else { + if (sepType == 1) { + // #11230: don't accept middle groups with only 1 digit. + return count != 1; + } else { + return true; + } + } +} + +bool DecimalMatcher::smokeTest(const StringSegment& segment) const { + // The common case uses a static leadSet for efficiency. + if (fLocalDigitStrings.isNull() && leadSet != nullptr) { + return segment.startsWith(*leadSet); + } + if (segment.startsWith(*separatorSet) || u_isdigit(segment.getCodePoint())) { + return true; + } + if (fLocalDigitStrings.isNull()) { + return false; + } + for (int32_t i = 0; i < 10; i++) { + if (segment.startsWith(fLocalDigitStrings[i])) { + return true; + } + } + return false; +} + +UnicodeString DecimalMatcher::toString() const { + return u""; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_decimal.h b/deps/icu-small/source/i18n/numparse_decimal.h new file mode 100644 index 0000000000..ec6c76487e --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_decimal.h @@ -0,0 +1,76 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_DECIMAL_H__ +#define __NUMPARSE_DECIMAL_H__ + +#include "unicode/uniset.h" +#include "numparse_types.h" + +U_NAMESPACE_BEGIN namespace numparse { +namespace impl { + +using ::icu::number::impl::Grouper; + +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); + + bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override; + + bool + match(StringSegment& segment, ParsedNumber& result, int8_t exponentSign, UErrorCode& status) const; + + bool smokeTest(const StringSegment& segment) const override; + + UnicodeString toString() const override; + + private: + /** If true, only accept strings whose grouping sizes match the locale */ + bool requireGroupingMatch; + + /** If true, do not accept grouping separators at all */ + bool groupingDisabled; + + // Fraction grouping parsing is disabled for now but could be enabled later. + // See http://bugs.icu-project.org/trac/ticket/10794 + // bool fractionGrouping; + + /** If true, do not accept numbers in the fraction */ + bool integerOnly; + + int16_t grouping1; + int16_t grouping2; + + UnicodeString groupingSeparator; + UnicodeString decimalSeparator; + + // Assumption: these sets all consist of single code points. If this assumption needs to be broken, + // fix getLeadCodePoints() as well as matching logic. Be careful of the performance impact. + const UnicodeSet* groupingUniSet; + const UnicodeSet* decimalUniSet; + const UnicodeSet* separatorSet; + const UnicodeSet* leadSet; + + // Make this class the owner of a few objects that could be allocated. + // The first three LocalPointers are used for assigning ownership only. + LocalPointer fLocalDecimalUniSet; + LocalPointer fLocalSeparatorSet; + LocalArray fLocalDigitStrings; + + bool validateGroup(int32_t sepType, int32_t count, bool isPrimary) const; +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_DECIMAL_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_impl.cpp b/deps/icu-small/source/i18n/numparse_impl.cpp new file mode 100644 index 0000000000..5fa52f6335 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_impl.cpp @@ -0,0 +1,361 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include +#include +#include "number_types.h" +#include "number_patternstring.h" +#include "numparse_types.h" +#include "numparse_impl.h" +#include "numparse_symbols.h" +#include "numparse_decimal.h" +#include "unicode/numberformatter.h" +#include "cstr.h" +#include "number_mapper.h" +#include "static_unicode_sets.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +NumberParseMatcher::~NumberParseMatcher() = default; + + +NumberParserImpl* +NumberParserImpl::createSimpleParser(const Locale& locale, const UnicodeString& patternString, + parse_flags_t parseFlags, UErrorCode& status) { + + LocalPointer parser(new NumberParserImpl(parseFlags)); + DecimalFormatSymbols symbols(locale, status); + + parser->fLocalMatchers.ignorables = {unisets::DEFAULT_IGNORABLES}; + IgnorablesMatcher& ignorables = parser->fLocalMatchers.ignorables; + + DecimalFormatSymbols dfs(locale, status); + dfs.setSymbol(DecimalFormatSymbols::kCurrencySymbol, u"IU$"); + dfs.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, u"ICU"); + CurrencySymbols currencySymbols({u"ICU", status}, locale, dfs, status); + + ParsedPatternInfo patternInfo; + PatternParser::parseToPatternInfo(patternString, patternInfo, status); + + // The following statements set up the affix matchers. + AffixTokenMatcherSetupData affixSetupData = { + currencySymbols, symbols, ignorables, locale, parseFlags}; + parser->fLocalMatchers.affixTokenMatcherWarehouse = {&affixSetupData}; + parser->fLocalMatchers.affixMatcherWarehouse = {&parser->fLocalMatchers.affixTokenMatcherWarehouse}; + parser->fLocalMatchers.affixMatcherWarehouse.createAffixMatchers( + patternInfo, *parser, ignorables, parseFlags, status); + + Grouper grouper = Grouper::forStrategy(UNUM_GROUPING_AUTO); + grouper.setLocaleData(patternInfo, locale); + + 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(parser->fLocalMatchers.infinity = {symbols}); + parser->addMatcher(parser->fLocalMatchers.padding = {u"@"}); + parser->addMatcher(parser->fLocalMatchers.scientific = {symbols, grouper}); + parser->addMatcher(parser->fLocalMatchers.currency = {currencySymbols, symbols, parseFlags, status}); +// parser.addMatcher(new RequireNumberMatcher()); + + parser->freeze(); + return parser.orphan(); +} + +NumberParserImpl* +NumberParserImpl::createParserFromProperties(const number::impl::DecimalFormatProperties& properties, + const DecimalFormatSymbols& symbols, bool parseCurrency, + UErrorCode& status) { + Locale locale = symbols.getLocale(); + PropertiesAffixPatternProvider localPAPP; + CurrencyPluralInfoAffixProvider localCPIAP; + AffixPatternProvider* affixProvider; + if (properties.currencyPluralInfo.fPtr.isNull()) { + localPAPP.setTo(properties, status); + affixProvider = &localPAPP; + } else { + localCPIAP.setTo(*properties.currencyPluralInfo.fPtr, properties, status); + affixProvider = &localCPIAP; + } + if (affixProvider == nullptr || U_FAILURE(status)) { return nullptr; } + CurrencyUnit currency = resolveCurrency(properties, locale, status); + CurrencySymbols currencySymbols(currency, locale, symbols, status); + bool isStrict = properties.parseMode.getOrDefault(PARSE_MODE_STRICT) == PARSE_MODE_STRICT; + Grouper grouper = Grouper::forProperties(properties); + int parseFlags = 0; + if (affixProvider == nullptr || U_FAILURE(status)) { return nullptr; } + if (!properties.parseCaseSensitive) { + parseFlags |= PARSE_FLAG_IGNORE_CASE; + } + if (properties.parseIntegerOnly) { + parseFlags |= PARSE_FLAG_INTEGER_ONLY; + } + if (properties.signAlwaysShown) { + parseFlags |= PARSE_FLAG_PLUS_SIGN_ALLOWED; + } + if (isStrict) { + parseFlags |= PARSE_FLAG_STRICT_GROUPING_SIZE; + parseFlags |= PARSE_FLAG_STRICT_SEPARATORS; + parseFlags |= PARSE_FLAG_USE_FULL_AFFIXES; + parseFlags |= PARSE_FLAG_EXACT_AFFIX; + } else { + parseFlags |= PARSE_FLAG_INCLUDE_UNPAIRED_AFFIXES; + } + if (grouper.getPrimary() <= 0) { + parseFlags |= PARSE_FLAG_GROUPING_DISABLED; + } + if (parseCurrency || affixProvider->hasCurrencySign()) { + parseFlags |= PARSE_FLAG_MONETARY_SEPARATORS; + } + if (!parseCurrency) { + parseFlags |= PARSE_FLAG_NO_FOREIGN_CURRENCY; + } + + LocalPointer parser(new NumberParserImpl(parseFlags)); + + parser->fLocalMatchers.ignorables = { + isStrict ? unisets::STRICT_IGNORABLES : unisets::DEFAULT_IGNORABLES}; + IgnorablesMatcher& ignorables = parser->fLocalMatchers.ignorables; + + ////////////////////// + /// AFFIX MATCHERS /// + ////////////////////// + + // The following statements set up the affix matchers. + AffixTokenMatcherSetupData affixSetupData = { + currencySymbols, symbols, ignorables, locale, parseFlags}; + parser->fLocalMatchers.affixTokenMatcherWarehouse = {&affixSetupData}; + parser->fLocalMatchers.affixMatcherWarehouse = {&parser->fLocalMatchers.affixTokenMatcherWarehouse}; + parser->fLocalMatchers.affixMatcherWarehouse.createAffixMatchers( + *affixProvider, *parser, ignorables, parseFlags, status); + + //////////////////////// + /// CURRENCY MATCHER /// + //////////////////////// + + if (parseCurrency || affixProvider->hasCurrencySign()) { + parser->addMatcher(parser->fLocalMatchers.currency = {currencySymbols, symbols, parseFlags, status}); + } + + /////////////// + /// PERCENT /// + /////////////// + + // ICU-TC meeting, April 11, 2018: accept percent/permille only if it is in the pattern, + // and to maintain regressive behavior, divide by 100 even if no percent sign is present. + if (affixProvider->containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) { + parser->addMatcher(parser->fLocalMatchers.percent = {symbols}); + } + if (affixProvider->containsSymbolType(AffixPatternType::TYPE_PERMILLE, status)) { + parser->addMatcher(parser->fLocalMatchers.permille = {symbols}); + } + + /////////////////////////////// + /// OTHER STANDARD MATCHERS /// + /////////////////////////////// + + if (!isStrict) { + parser->addMatcher(parser->fLocalMatchers.plusSign = {symbols, false}); + parser->addMatcher(parser->fLocalMatchers.minusSign = {symbols, false}); + } + parser->addMatcher(parser->fLocalMatchers.nan = {symbols}); + parser->addMatcher(parser->fLocalMatchers.infinity = {symbols}); + UnicodeString padString = properties.padString; + if (!padString.isBogus() && !ignorables.getSet()->contains(padString)) { + parser->addMatcher(parser->fLocalMatchers.padding = {padString}); + } + parser->addMatcher(parser->fLocalMatchers.ignorables); + parser->addMatcher(parser->fLocalMatchers.decimal = {symbols, grouper, parseFlags}); + // NOTE: parseNoExponent doesn't disable scientific parsing if we have a scientific formatter + if (!properties.parseNoExponent || properties.minimumExponentDigits > 0) { + parser->addMatcher(parser->fLocalMatchers.scientific = {symbols, grouper}); + } + + ////////////////// + /// VALIDATORS /// + ////////////////// + + parser->addMatcher(parser->fLocalValidators.number = {}); + if (isStrict) { + parser->addMatcher(parser->fLocalValidators.affix = {}); + } + if (parseCurrency) { + parser->addMatcher(parser->fLocalValidators.currency = {}); + } + if (properties.decimalPatternMatchRequired) { + bool patternHasDecimalSeparator = + properties.decimalSeparatorAlwaysShown || properties.maximumFractionDigits != 0; + parser->addMatcher(parser->fLocalValidators.decimalSeparator = {patternHasDecimalSeparator}); + } + // The multiplier takes care of scaling percentages. + Scale multiplier = scaleFromProperties(properties); + if (multiplier.isValid()) { + parser->addMatcher(parser->fLocalValidators.multiplier = {multiplier}); + } + + parser->freeze(); + return parser.orphan(); +} + +NumberParserImpl::NumberParserImpl(parse_flags_t parseFlags) + : fParseFlags(parseFlags) { +} + +NumberParserImpl::~NumberParserImpl() { + fNumMatchers = 0; +} + +void NumberParserImpl::addMatcher(NumberParseMatcher& matcher) { + if (fNumMatchers + 1 > fMatchers.getCapacity()) { + fMatchers.resize(fNumMatchers * 2, fNumMatchers); + } + fMatchers[fNumMatchers] = &matcher; + fNumMatchers++; +} + +void NumberParserImpl::freeze() { + fFrozen = true; +} + +parse_flags_t NumberParserImpl::getParseFlags() const { + return fParseFlags; +} + +void NumberParserImpl::parse(const UnicodeString& input, bool greedy, ParsedNumber& result, + UErrorCode& status) const { + return parse(input, 0, greedy, result, status); +} + +void NumberParserImpl::parse(const UnicodeString& input, int32_t start, bool greedy, ParsedNumber& result, + UErrorCode& status) const { + if (U_FAILURE(status)) { + return; + } + U_ASSERT(fFrozen); + // TODO: Check start >= 0 and start < input.length() + StringSegment segment(input, 0 != (fParseFlags & PARSE_FLAG_IGNORE_CASE)); + segment.adjustOffset(start); + if (greedy) { + parseGreedyRecursive(segment, result, status); + } else { + parseLongestRecursive(segment, result, status); + } + for (int32_t i = 0; i < fNumMatchers; i++) { + fMatchers[i]->postProcess(result); + } + result.postProcess(); +} + +void NumberParserImpl::parseGreedyRecursive(StringSegment& segment, ParsedNumber& result, + UErrorCode& status) const { + // Base Case + if (segment.length() == 0) { + return; + } + + int initialOffset = segment.getOffset(); + for (int32_t i = 0; i < fNumMatchers; i++) { + const NumberParseMatcher* matcher = fMatchers[i]; + if (!matcher->smokeTest(segment)) { + continue; + } + matcher->match(segment, result, status); + if (U_FAILURE(status)) { + return; + } + if (segment.getOffset() != initialOffset) { + // In a greedy parse, recurse on only the first match. + parseGreedyRecursive(segment, result, status); + // The following line resets the offset so that the StringSegment says the same across + // the function + // call boundary. Since we recurse only once, this line is not strictly necessary. + segment.setOffset(initialOffset); + return; + } + } + + // NOTE: If we get here, the greedy parse completed without consuming the entire string. +} + +void NumberParserImpl::parseLongestRecursive(StringSegment& segment, ParsedNumber& result, + UErrorCode& status) const { + // Base Case + if (segment.length() == 0) { + return; + } + + // TODO: Give a nice way for the matcher to reset the ParsedNumber? + ParsedNumber initial(result); + ParsedNumber candidate; + + int initialOffset = segment.getOffset(); + for (int32_t i = 0; i < fNumMatchers; i++) { + const NumberParseMatcher* matcher = fMatchers[i]; + if (!matcher->smokeTest(segment)) { + continue; + } + + // In a non-greedy parse, we attempt all possible matches and pick the best. + for (int32_t charsToConsume = 0; charsToConsume < segment.length();) { + charsToConsume += U16_LENGTH(segment.codePointAt(charsToConsume)); + + // Run the matcher on a segment of the current length. + candidate = initial; + segment.setLength(charsToConsume); + bool maybeMore = matcher->match(segment, candidate, status); + segment.resetLength(); + if (U_FAILURE(status)) { + return; + } + + // If the entire segment was consumed, recurse. + if (segment.getOffset() - initialOffset == charsToConsume) { + parseLongestRecursive(segment, candidate, status); + if (U_FAILURE(status)) { + return; + } + if (candidate.isBetterThan(result)) { + result = candidate; + } + } + + // Since the segment can be re-used, reset the offset. + // This does not have an effect if the matcher did not consume any chars. + segment.setOffset(initialOffset); + + // Unless the matcher wants to see the next char, continue to the next matcher. + if (!maybeMore) { + break; + } + } + } +} + +UnicodeString NumberParserImpl::toString() const { + UnicodeString result(u"toString()); + } + result.append(u" ]>", -1); + return result; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_impl.h b/deps/icu-small/source/i18n/numparse_impl.h new file mode 100644 index 0000000000..992114c7ed --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_impl.h @@ -0,0 +1,109 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_IMPL_H__ +#define __NUMPARSE_IMPL_H__ + +#include "numparse_types.h" +#include "numparse_decimal.h" +#include "numparse_symbols.h" +#include "numparse_scientific.h" +#include "unicode/uniset.h" +#include "numparse_currency.h" +#include "numparse_affixes.h" +#include "number_decimfmtprops.h" +#include "unicode/localpointer.h" +#include "numparse_validators.h" +#include "number_multiplier.h" + +U_NAMESPACE_BEGIN + +// Export an explicit template instantiation of the MaybeStackArray that is used as a data member of NumberParserImpl. +// When building DLLs for Windows this is required even though no direct access to the MaybeStackArray leaks out of the i18n library. +// (See numparse_compositions.h, numparse_affixes.h, datefmt.h, and others for similar examples.) +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +template class U_I18N_API MaybeStackArray; +#endif + +namespace numparse { +namespace impl { + +// Exported as U_I18N_API for tests +class U_I18N_API NumberParserImpl : public MutableMatcherCollection, public UMemory { + public: + virtual ~NumberParserImpl(); + + static NumberParserImpl* createSimpleParser(const Locale& locale, const UnicodeString& patternString, + parse_flags_t parseFlags, UErrorCode& status); + + static NumberParserImpl* createParserFromProperties( + const number::impl::DecimalFormatProperties& properties, const DecimalFormatSymbols& symbols, + bool parseCurrency, UErrorCode& status); + + /** + * Does NOT take ownership of the matcher. The matcher MUST remain valid for the lifespan of the + * NumberParserImpl. + * @param matcher The matcher to reference. + */ + void addMatcher(NumberParseMatcher& matcher) override; + + void freeze(); + + parse_flags_t getParseFlags() const; + + void parse(const UnicodeString& input, bool greedy, ParsedNumber& result, UErrorCode& status) const; + + void parse(const UnicodeString& input, int32_t start, bool greedy, ParsedNumber& result, + UErrorCode& status) const; + + UnicodeString toString() const; + + private: + parse_flags_t fParseFlags; + int32_t fNumMatchers = 0; + // NOTE: The stack capacity for fMatchers and fLeads should be the same + MaybeStackArray fMatchers; + bool fFrozen = false; + + // WARNING: All of these matchers start in an undefined state (default-constructed). + // You must use an assignment operator on them before using. + struct { + IgnorablesMatcher ignorables; + InfinityMatcher infinity; + MinusSignMatcher minusSign; + NanMatcher nan; + PaddingMatcher padding; + PercentMatcher percent; + PermilleMatcher permille; + PlusSignMatcher plusSign; + DecimalMatcher decimal; + ScientificMatcher scientific; + CombinedCurrencyMatcher currency; + AffixMatcherWarehouse affixMatcherWarehouse; + AffixTokenMatcherWarehouse affixTokenMatcherWarehouse; + } fLocalMatchers; + struct { + RequireAffixValidator affix; + RequireCurrencyValidator currency; + RequireDecimalSeparatorValidator decimalSeparator; + RequireNumberValidator number; + MultiplierParseHandler multiplier; + } fLocalValidators; + + explicit NumberParserImpl(parse_flags_t parseFlags); + + void parseGreedyRecursive(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const; + + void parseLongestRecursive(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const; +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_IMPL_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_parsednumber.cpp b/deps/icu-small/source/i18n/numparse_parsednumber.cpp new file mode 100644 index 0000000000..98da4e8319 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_parsednumber.cpp @@ -0,0 +1,122 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "number_decimalquantity.h" +#include "putilimp.h" +#include + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +ParsedNumber::ParsedNumber() { + clear(); +} + +void ParsedNumber::clear() { + quantity.bogus = true; + charEnd = 0; + flags = 0; + prefix.setToBogus(); + suffix.setToBogus(); + currencyCode[0] = 0; +} + +void ParsedNumber::setCharsConsumed(const StringSegment& segment) { + charEnd = segment.getOffset(); +} + +void ParsedNumber::postProcess() { + if (!quantity.bogus && 0 != (flags & FLAG_NEGATIVE)) { + quantity.negate(); + } +} + +bool ParsedNumber::success() const { + return charEnd > 0 && 0 == (flags & FLAG_FAIL); +} + +bool ParsedNumber::seenNumber() const { + return !quantity.bogus || 0 != (flags & FLAG_NAN) || 0 != (flags & FLAG_INFINITY); +} + +double ParsedNumber::getDouble() const { + bool sawNaN = 0 != (flags & FLAG_NAN); + bool sawInfinity = 0 != (flags & FLAG_INFINITY); + + // Check for NaN, infinity, and -0.0 + if (sawNaN) { + // Can't use NAN or std::nan because the byte pattern is platform-dependent; + // MSVC sets the sign bit, but Clang and GCC do not + return uprv_getNaN(); + } + if (sawInfinity) { + if (0 != (flags & FLAG_NEGATIVE)) { + return -INFINITY; + } else { + return INFINITY; + } + } + U_ASSERT(!quantity.bogus); + if (quantity.isZero() && quantity.isNegative()) { + return -0.0; + } + + if (quantity.fitsInLong()) { + return static_cast(quantity.toLong()); + } else { + return quantity.toDouble(); + } +} + +void ParsedNumber::populateFormattable(Formattable& output, parse_flags_t parseFlags) const { + bool sawNaN = 0 != (flags & FLAG_NAN); + bool sawInfinity = 0 != (flags & FLAG_INFINITY); + bool integerOnly = 0 != (parseFlags & PARSE_FLAG_INTEGER_ONLY); + + // Check for NaN, infinity, and -0.0 + if (sawNaN) { + // Can't use NAN or std::nan because the byte pattern is platform-dependent; + // MSVC sets the sign bit, but Clang and GCC do not + output.setDouble(uprv_getNaN()); + return; + } + if (sawInfinity) { + if (0 != (flags & FLAG_NEGATIVE)) { + output.setDouble(-INFINITY); + return; + } else { + output.setDouble(INFINITY); + return; + } + } + U_ASSERT(!quantity.bogus); + if (quantity.isZero() && quantity.isNegative() && !integerOnly) { + output.setDouble(-0.0); + return; + } + + // All other numbers + output.adoptDecimalQuantity(new DecimalQuantity(quantity)); +} + +bool ParsedNumber::isBetterThan(const ParsedNumber& other) { + // Favor results with strictly more characters consumed. + return charEnd > other.charEnd; +} + + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_scientific.cpp b/deps/icu-small/source/i18n/numparse_scientific.cpp new file mode 100644 index 0000000000..611695e57d --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_scientific.cpp @@ -0,0 +1,133 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "numparse_scientific.h" +#include "static_unicode_sets.h" + +using namespace icu; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +namespace { + +inline const UnicodeSet& minusSignSet() { + return *unisets::get(unisets::MINUS_SIGN); +} + +inline const UnicodeSet& plusSignSet() { + return *unisets::get(unisets::PLUS_SIGN); +} + +} // namespace + + +ScientificMatcher::ScientificMatcher(const DecimalFormatSymbols& dfs, const Grouper& grouper) + : fExponentSeparatorString(dfs.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol)), + fExponentMatcher(dfs, grouper, PARSE_FLAG_INTEGER_ONLY | PARSE_FLAG_GROUPING_DISABLED) { + + const UnicodeString& minusSign = dfs.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); + if (minusSignSet().contains(minusSign)) { + fCustomMinusSign.setToBogus(); + } else { + fCustomMinusSign = minusSign; + } + + const UnicodeString& plusSign = dfs.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); + if (plusSignSet().contains(plusSign)) { + fCustomPlusSign.setToBogus(); + } else { + fCustomPlusSign = plusSign; + } +} + +bool ScientificMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const { + // Only accept scientific notation after the mantissa. + if (!result.seenNumber()) { + return false; + } + + // First match the scientific separator, and then match another number after it. + // NOTE: This is guarded by the smoke test; no need to check fExponentSeparatorString length again. + int overlap1 = segment.getCommonPrefixLength(fExponentSeparatorString); + if (overlap1 == fExponentSeparatorString.length()) { + // Full exponent separator match. + + // First attempt to get a code point, returning true if we can't get one. + if (segment.length() == overlap1) { + return true; + } + segment.adjustOffset(overlap1); + + // Allow a sign, and then try to match digits. + int8_t exponentSign = 1; + if (segment.startsWith(minusSignSet())) { + exponentSign = -1; + segment.adjustOffsetByCodePoint(); + } else if (segment.startsWith(plusSignSet())) { + segment.adjustOffsetByCodePoint(); + } else if (segment.startsWith(fCustomMinusSign)) { + // Note: call site is guarded with startsWith, which returns false on empty string + int32_t overlap2 = segment.getCommonPrefixLength(fCustomMinusSign); + if (overlap2 != fCustomMinusSign.length()) { + // Partial custom sign match; un-match the exponent separator. + segment.adjustOffset(-overlap1); + return true; + } + exponentSign = -1; + segment.adjustOffset(overlap2); + } else if (segment.startsWith(fCustomPlusSign)) { + // Note: call site is guarded with startsWith, which returns false on empty string + int32_t overlap2 = segment.getCommonPrefixLength(fCustomPlusSign); + if (overlap2 != fCustomPlusSign.length()) { + // Partial custom sign match; un-match the exponent separator. + segment.adjustOffset(-overlap1); + return true; + } + segment.adjustOffset(overlap2); + } + + // We are supposed to accept E0 after NaN, so we need to make sure result.quantity is available. + bool wasBogus = result.quantity.bogus; + result.quantity.bogus = false; + int digitsOffset = segment.getOffset(); + bool digitsReturnValue = fExponentMatcher.match(segment, result, exponentSign, status); + result.quantity.bogus = wasBogus; + + if (segment.getOffset() != digitsOffset) { + // At least one exponent digit was matched. + result.flags |= FLAG_HAS_EXPONENT; + } else { + // No exponent digits were matched; un-match the exponent separator. + segment.adjustOffset(-overlap1); + } + return digitsReturnValue; + + } else if (overlap1 == segment.length()) { + // Partial exponent separator match + return true; + } + + // No match + return false; +} + +bool ScientificMatcher::smokeTest(const StringSegment& segment) const { + return segment.startsWith(fExponentSeparatorString); +} + +UnicodeString ScientificMatcher::toString() const { + return u""; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_scientific.h b/deps/icu-small/source/i18n/numparse_scientific.h new file mode 100644 index 0000000000..ddecf858af --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_scientific.h @@ -0,0 +1,45 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_SCIENTIFIC_H__ +#define __NUMPARSE_SCIENTIFIC_H__ + +#include "numparse_types.h" +#include "numparse_decimal.h" +#include "unicode/numberformatter.h" + +using icu::number::impl::Grouper; + +U_NAMESPACE_BEGIN namespace numparse { +namespace impl { + + +class ScientificMatcher : public NumberParseMatcher, public UMemory { + public: + ScientificMatcher() = default; // WARNING: Leaves the object in an unusable state + + ScientificMatcher(const DecimalFormatSymbols& dfs, const Grouper& grouper); + + bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override; + + bool smokeTest(const StringSegment& segment) const override; + + UnicodeString toString() const override; + + private: + UnicodeString fExponentSeparatorString; + DecimalMatcher fExponentMatcher; + UnicodeString fCustomMinusSign; + UnicodeString fCustomPlusSign; +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_SCIENTIFIC_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_stringsegment.cpp b/deps/icu-small/source/i18n/numparse_stringsegment.cpp new file mode 100644 index 0000000000..3db4fe618a --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_stringsegment.cpp @@ -0,0 +1,146 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "numparse_stringsegment.h" +#include "putilimp.h" +#include "unicode/utf16.h" +#include "unicode/uniset.h" + +using namespace icu; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +StringSegment::StringSegment(const UnicodeString& str, bool ignoreCase) + : fStr(str), fStart(0), fEnd(str.length()), + fFoldCase(ignoreCase) {} + +int32_t StringSegment::getOffset() const { + return fStart; +} + +void StringSegment::setOffset(int32_t start) { + fStart = start; +} + +void StringSegment::adjustOffset(int32_t delta) { + fStart += delta; +} + +void StringSegment::adjustOffsetByCodePoint() { + fStart += U16_LENGTH(getCodePoint()); +} + +void StringSegment::setLength(int32_t length) { + fEnd = fStart + length; +} + +void StringSegment::resetLength() { + fEnd = fStr.length(); +} + +int32_t StringSegment::length() const { + return fEnd - fStart; +} + +char16_t StringSegment::charAt(int32_t index) const { + return fStr.charAt(index + fStart); +} + +UChar32 StringSegment::codePointAt(int32_t index) const { + return fStr.char32At(index + fStart); +} + +UnicodeString StringSegment::toUnicodeString() const { + return UnicodeString(fStr.getBuffer() + fStart, fEnd - fStart); +} + +const UnicodeString StringSegment::toTempUnicodeString() const { + // Use the readonly-aliasing constructor for efficiency. + return UnicodeString(FALSE, fStr.getBuffer() + fStart, fEnd - fStart); +} + +UChar32 StringSegment::getCodePoint() const { + char16_t lead = fStr.charAt(fStart); + if (U16_IS_LEAD(lead) && fStart + 1 < fEnd) { + return fStr.char32At(fStart); + } else if (U16_IS_SURROGATE(lead)) { + return -1; + } else { + return lead; + } +} + +bool StringSegment::startsWith(UChar32 otherCp) const { + return codePointsEqual(getCodePoint(), otherCp, fFoldCase); +} + +bool StringSegment::startsWith(const UnicodeSet& uniset) const { + // TODO: Move UnicodeSet case-folding logic here. + // TODO: Handle string matches here instead of separately. + UChar32 cp = getCodePoint(); + if (cp == -1) { + return false; + } + return uniset.contains(cp); +} + +bool StringSegment::startsWith(const UnicodeString& other) const { + if (other.isBogus() || other.length() == 0 || length() == 0) { + return false; + } + int cp1 = getCodePoint(); + int cp2 = other.char32At(0); + return codePointsEqual(cp1, cp2, fFoldCase); +} + +int32_t StringSegment::getCommonPrefixLength(const UnicodeString& other) { + return getPrefixLengthInternal(other, fFoldCase); +} + +int32_t StringSegment::getCaseSensitivePrefixLength(const UnicodeString& other) { + return getPrefixLengthInternal(other, false); +} + +int32_t StringSegment::getPrefixLengthInternal(const UnicodeString& other, bool foldCase) { + U_ASSERT(other.length() > 0); + int32_t offset = 0; + for (; offset < uprv_min(length(), other.length());) { + // TODO: case-fold code points, not chars + char16_t c1 = charAt(offset); + char16_t c2 = other.charAt(offset); + if (!codePointsEqual(c1, c2, foldCase)) { + break; + } + offset++; + } + return offset; +} + +bool StringSegment::codePointsEqual(UChar32 cp1, UChar32 cp2, bool foldCase) { + if (cp1 == cp2) { + return true; + } + if (!foldCase) { + return false; + } + cp1 = u_foldCase(cp1, TRUE); + cp2 = u_foldCase(cp2, TRUE); + return cp1 == cp2; +} + +bool StringSegment::operator==(const UnicodeString& other) const { + return toTempUnicodeString() == other; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_stringsegment.h b/deps/icu-small/source/i18n/numparse_stringsegment.h new file mode 100644 index 0000000000..7a84444d41 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_stringsegment.h @@ -0,0 +1,24 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_STRINGSEGMENT_H__ +#define __NUMPARSE_STRINGSEGMENT_H__ + +#include "numparse_types.h" +#include "number_types.h" +#include "unicode/unistr.h" + +U_NAMESPACE_BEGIN +namespace numparse { +namespace impl { + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_STRINGSEGMENT_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_symbols.cpp b/deps/icu-small/source/i18n/numparse_symbols.cpp new file mode 100644 index 0000000000..9ccceec847 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_symbols.cpp @@ -0,0 +1,193 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "numparse_symbols.h" +#include "numparse_utils.h" + +using namespace icu; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +SymbolMatcher::SymbolMatcher(const UnicodeString& symbolString, unisets::Key key) { + fUniSet = unisets::get(key); + if (fUniSet->contains(symbolString)) { + fString.setToBogus(); + } else { + fString = symbolString; + } +} + +const UnicodeSet* SymbolMatcher::getSet() const { + return fUniSet; +} + +bool SymbolMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode&) const { + // Smoke test first; this matcher might be disabled. + if (isDisabled(result)) { + return false; + } + + // Test the string first in order to consume trailing chars greedily. + int overlap = 0; + if (!fString.isEmpty()) { + overlap = segment.getCommonPrefixLength(fString); + if (overlap == fString.length()) { + segment.adjustOffset(fString.length()); + accept(segment, result); + return false; + } + } + + int cp = segment.getCodePoint(); + if (cp != -1 && fUniSet->contains(cp)) { + segment.adjustOffset(U16_LENGTH(cp)); + accept(segment, result); + return false; + } + + return overlap == segment.length(); +} + +bool SymbolMatcher::smokeTest(const StringSegment& segment) const { + return segment.startsWith(*fUniSet) || segment.startsWith(fString); +} + +UnicodeString SymbolMatcher::toString() const { + // TODO: Customize output for each symbol + return u""; +} + + +IgnorablesMatcher::IgnorablesMatcher(unisets::Key key) + : SymbolMatcher({}, key) { +} + +bool IgnorablesMatcher::isFlexible() const { + return true; +} + +UnicodeString IgnorablesMatcher::toString() const { + return u""; +} + +bool IgnorablesMatcher::isDisabled(const ParsedNumber&) const { + return false; +} + +void IgnorablesMatcher::accept(StringSegment&, ParsedNumber&) const { + // No-op +} + + +InfinityMatcher::InfinityMatcher(const DecimalFormatSymbols& dfs) + : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), unisets::INFINITY_KEY) { +} + +bool InfinityMatcher::isDisabled(const ParsedNumber& result) const { + return 0 != (result.flags & FLAG_INFINITY); +} + +void InfinityMatcher::accept(StringSegment& segment, ParsedNumber& result) const { + result.flags |= FLAG_INFINITY; + result.setCharsConsumed(segment); +} + + +MinusSignMatcher::MinusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing) + : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol), unisets::MINUS_SIGN), + fAllowTrailing(allowTrailing) { +} + +bool MinusSignMatcher::isDisabled(const ParsedNumber& result) const { + return !fAllowTrailing && result.seenNumber(); +} + +void MinusSignMatcher::accept(StringSegment& segment, ParsedNumber& result) const { + result.flags |= FLAG_NEGATIVE; + result.setCharsConsumed(segment); +} + + +NanMatcher::NanMatcher(const DecimalFormatSymbols& dfs) + : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), unisets::EMPTY) { +} + +bool NanMatcher::isDisabled(const ParsedNumber& result) const { + return result.seenNumber(); +} + +void NanMatcher::accept(StringSegment& segment, ParsedNumber& result) const { + result.flags |= FLAG_NAN; + result.setCharsConsumed(segment); +} + + +PaddingMatcher::PaddingMatcher(const UnicodeString& padString) + : SymbolMatcher(padString, unisets::EMPTY) {} + +bool PaddingMatcher::isFlexible() const { + return true; +} + +bool PaddingMatcher::isDisabled(const ParsedNumber&) const { + return false; +} + +void PaddingMatcher::accept(StringSegment&, ParsedNumber&) const { + // No-op +} + + +PercentMatcher::PercentMatcher(const DecimalFormatSymbols& dfs) + : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPercentSymbol), unisets::PERCENT_SIGN) { +} + +bool PercentMatcher::isDisabled(const ParsedNumber& result) const { + return 0 != (result.flags & FLAG_PERCENT); +} + +void PercentMatcher::accept(StringSegment& segment, ParsedNumber& result) const { + result.flags |= FLAG_PERCENT; + result.setCharsConsumed(segment); +} + + +PermilleMatcher::PermilleMatcher(const DecimalFormatSymbols& dfs) + : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPerMillSymbol), unisets::PERMILLE_SIGN) { +} + +bool PermilleMatcher::isDisabled(const ParsedNumber& result) const { + return 0 != (result.flags & FLAG_PERMILLE); +} + +void PermilleMatcher::accept(StringSegment& segment, ParsedNumber& result) const { + result.flags |= FLAG_PERMILLE; + result.setCharsConsumed(segment); +} + + +PlusSignMatcher::PlusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing) + : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol), unisets::PLUS_SIGN), + fAllowTrailing(allowTrailing) { +} + +bool PlusSignMatcher::isDisabled(const ParsedNumber& result) const { + return !fAllowTrailing && result.seenNumber(); +} + +void PlusSignMatcher::accept(StringSegment& segment, ParsedNumber& result) const { + result.setCharsConsumed(segment); +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_symbols.h b/deps/icu-small/source/i18n/numparse_symbols.h new file mode 100644 index 0000000000..8912ee95b0 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_symbols.h @@ -0,0 +1,173 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_SYMBOLS_H__ +#define __NUMPARSE_SYMBOLS_H__ + +#include "numparse_types.h" +#include "unicode/uniset.h" +#include "static_unicode_sets.h" + +U_NAMESPACE_BEGIN namespace numparse { +namespace impl { + + +/** + * A base class for many matchers that performs a simple match against a UnicodeString and/or UnicodeSet. + * + * @author sffc + */ +// Exported as U_I18N_API for tests +class U_I18N_API SymbolMatcher : public NumberParseMatcher, public UMemory { + public: + SymbolMatcher() = default; // WARNING: Leaves the object in an unusable state + + const UnicodeSet* getSet() const; + + bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const override; + + bool smokeTest(const StringSegment& segment) const override; + + UnicodeString toString() const override; + + virtual bool isDisabled(const ParsedNumber& result) const = 0; + + virtual void accept(StringSegment& segment, ParsedNumber& result) const = 0; + + protected: + UnicodeString fString; + const UnicodeSet* fUniSet; // a reference from numparse_unisets.h; never owned + + SymbolMatcher(const UnicodeString& symbolString, unisets::Key key); +}; + + +// Exported as U_I18N_API for tests +class U_I18N_API IgnorablesMatcher : public SymbolMatcher { + public: + IgnorablesMatcher() = default; // WARNING: Leaves the object in an unusable state + + IgnorablesMatcher(unisets::Key key); + + bool isFlexible() const override; + + UnicodeString toString() const override; + + protected: + bool isDisabled(const ParsedNumber& result) const override; + + void accept(StringSegment& segment, ParsedNumber& result) const override; +}; + + +class InfinityMatcher : public SymbolMatcher { + public: + InfinityMatcher() = default; // WARNING: Leaves the object in an unusable state + + InfinityMatcher(const DecimalFormatSymbols& dfs); + + protected: + bool isDisabled(const ParsedNumber& result) const override; + + void accept(StringSegment& segment, ParsedNumber& result) const override; +}; + + +// Exported as U_I18N_API for tests +class U_I18N_API MinusSignMatcher : public SymbolMatcher { + public: + MinusSignMatcher() = default; // WARNING: Leaves the object in an unusable state + + MinusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing); + + protected: + bool isDisabled(const ParsedNumber& result) const override; + + void accept(StringSegment& segment, ParsedNumber& result) const override; + + private: + bool fAllowTrailing; +}; + + +class NanMatcher : public SymbolMatcher { + public: + NanMatcher() = default; // WARNING: Leaves the object in an unusable state + + NanMatcher(const DecimalFormatSymbols& dfs); + + protected: + bool isDisabled(const ParsedNumber& result) const override; + + void accept(StringSegment& segment, ParsedNumber& result) const override; +}; + + +class PaddingMatcher : public SymbolMatcher { + public: + PaddingMatcher() = default; // WARNING: Leaves the object in an unusable state + + PaddingMatcher(const UnicodeString& padString); + + bool isFlexible() const override; + + protected: + bool isDisabled(const ParsedNumber& result) const override; + + void accept(StringSegment& segment, ParsedNumber& result) const override; +}; + + +// Exported as U_I18N_API for tests +class U_I18N_API PercentMatcher : public SymbolMatcher { + public: + PercentMatcher() = default; // WARNING: Leaves the object in an unusable state + + PercentMatcher(const DecimalFormatSymbols& dfs); + + protected: + bool isDisabled(const ParsedNumber& result) const override; + + void accept(StringSegment& segment, ParsedNumber& result) const override; +}; + +// Exported as U_I18N_API for tests +class U_I18N_API PermilleMatcher : public SymbolMatcher { + public: + PermilleMatcher() = default; // WARNING: Leaves the object in an unusable state + + PermilleMatcher(const DecimalFormatSymbols& dfs); + + protected: + bool isDisabled(const ParsedNumber& result) const override; + + void accept(StringSegment& segment, ParsedNumber& result) const override; +}; + + +// Exported as U_I18N_API for tests +class U_I18N_API PlusSignMatcher : public SymbolMatcher { + public: + PlusSignMatcher() = default; // WARNING: Leaves the object in an unusable state + + PlusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing); + + protected: + bool isDisabled(const ParsedNumber& result) const override; + + void accept(StringSegment& segment, ParsedNumber& result) const override; + + private: + bool fAllowTrailing; +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_SYMBOLS_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_types.h b/deps/icu-small/source/i18n/numparse_types.h new file mode 100644 index 0000000000..ab591eaba8 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_types.h @@ -0,0 +1,377 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_TYPES_H__ +#define __NUMPARSE_TYPES_H__ + +#include "unicode/uobject.h" +#include "number_decimalquantity.h" + +U_NAMESPACE_BEGIN namespace numparse { +namespace impl { + +// Forward-declarations +class StringSegment; +class ParsedNumber; + +typedef int32_t result_flags_t; +typedef int32_t parse_flags_t; + +/** Flags for the type result_flags_t */ +enum ResultFlags { + FLAG_NEGATIVE = 0x0001, + FLAG_PERCENT = 0x0002, + FLAG_PERMILLE = 0x0004, + FLAG_HAS_EXPONENT = 0x0008, + // FLAG_HAS_DEFAULT_CURRENCY = 0x0010, // no longer used + FLAG_HAS_DECIMAL_SEPARATOR = 0x0020, + FLAG_NAN = 0x0040, + FLAG_INFINITY = 0x0080, + FLAG_FAIL = 0x0100, +}; + +/** Flags for the type parse_flags_t */ +enum ParseFlags { + PARSE_FLAG_IGNORE_CASE = 0x0001, + PARSE_FLAG_MONETARY_SEPARATORS = 0x0002, + PARSE_FLAG_STRICT_SEPARATORS = 0x0004, + PARSE_FLAG_STRICT_GROUPING_SIZE = 0x0008, + PARSE_FLAG_INTEGER_ONLY = 0x0010, + PARSE_FLAG_GROUPING_DISABLED = 0x0020, + // PARSE_FLAG_FRACTION_GROUPING_ENABLED = 0x0040, // see #10794 + PARSE_FLAG_INCLUDE_UNPAIRED_AFFIXES = 0x0080, + PARSE_FLAG_USE_FULL_AFFIXES = 0x0100, + PARSE_FLAG_EXACT_AFFIX = 0x0200, + PARSE_FLAG_PLUS_SIGN_ALLOWED = 0x0400, + // PARSE_FLAG_OPTIMIZE = 0x0800, // no longer used + // PARSE_FLAG_FORCE_BIG_DECIMAL = 0x1000, // not used in ICU4C + PARSE_FLAG_NO_FOREIGN_CURRENCY = 0x2000, +}; + + +// TODO: Is this class worthwhile? +template +class CompactUnicodeString { + public: + CompactUnicodeString() { + static_assert(stackCapacity > 0, "cannot have zero space on stack"); + fBuffer[0] = 0; + } + + CompactUnicodeString(const UnicodeString& text) + : fBuffer(text.length() + 1) { + memcpy(fBuffer.getAlias(), text.getBuffer(), sizeof(UChar) * text.length()); + fBuffer[text.length()] = 0; + } + + inline UnicodeString toAliasedUnicodeString() const { + return UnicodeString(TRUE, fBuffer.getAlias(), -1); + } + + bool operator==(const CompactUnicodeString& other) const { + // Use the alias-only constructor and then call UnicodeString operator== + return toAliasedUnicodeString() == other.toAliasedUnicodeString(); + } + + private: + MaybeStackArray fBuffer; +}; + + +/** + * Struct-like class to hold the results of a parsing routine. + * + * @author sffc + */ +// Exported as U_I18N_API for tests +class U_I18N_API ParsedNumber { + public: + + /** + * The numerical value that was parsed. + */ + ::icu::number::impl::DecimalQuantity quantity; + + /** + * The index of the last char consumed during parsing. If parsing started at index 0, this is equal + * to the number of chars consumed. This is NOT necessarily the same as the StringSegment offset; + * "weak" chars, like whitespace, change the offset, but the charsConsumed is not touched until a + * "strong" char is encountered. + */ + int32_t charEnd; + + /** + * Boolean flags (see constants above). + */ + result_flags_t flags; + + /** + * The pattern string corresponding to the prefix that got consumed. + */ + UnicodeString prefix; + + /** + * The pattern string corresponding to the suffix that got consumed. + */ + UnicodeString suffix; + + /** + * The currency that got consumed. + */ + UChar currencyCode[4]; + + ParsedNumber(); + + ParsedNumber(const ParsedNumber& other) = default; + + ParsedNumber& operator=(const ParsedNumber& other) = default; + + void clear(); + + /** + * Call this method to register that a "strong" char was consumed. This should be done after calling + * {@link StringSegment#setOffset} or {@link StringSegment#adjustOffset} except when the char is + * "weak", like whitespace. + * + *

+ * What is a strong versus weak char? The behavior of number parsing is to "stop" + * after reading the number, even if there is other content following the number. For example, after + * parsing the string "123 " (123 followed by a space), the cursor should be set to 3, not 4, even + * though there are matchers that accept whitespace. In this example, the digits are strong, whereas + * the whitespace is weak. Grouping separators are weak, whereas decimal separators are strong. Most + * other chars are strong. + * + * @param segment + * The current StringSegment, usually immediately following a call to setOffset. + */ + void setCharsConsumed(const StringSegment& segment); + + /** Apply certain number-related flags to the DecimalQuantity. */ + void postProcess(); + + /** + * Returns whether this the parse was successful. To be successful, at least one char must have been + * consumed, and the failure flag must not be set. + */ + bool success() const; + + bool seenNumber() const; + + double getDouble() const; + + void populateFormattable(Formattable& output, parse_flags_t parseFlags) const; + + bool isBetterThan(const ParsedNumber& other); +}; + + +/** + * 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. + * + * @author sffc + */ +// Exported as U_I18N_API for tests +class U_I18N_API StringSegment : public UMemory { + public: + StringSegment(const UnicodeString& str, bool ignoreCase); + + int32_t getOffset() const; + + void setOffset(int32_t start); + + /** + * 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. + */ + void adjustOffset(int32_t delta); + + /** + * Adjusts the offset by the width of the current code point, either 1 or 2 chars. + */ + void adjustOffsetByCodePoint(); + + void setLength(int32_t length); + + void resetLength(); + + int32_t length() const; + + char16_t charAt(int32_t index) const; + + UChar32 codePointAt(int32_t index) const; + + UnicodeString toUnicodeString() const; + + const UnicodeString toTempUnicodeString() const; + + /** + * Returns the first code point in the string segment, or -1 if the string starts with an invalid + * code point. + * + *

+ * Important: Most of the time, you should use {@link #matches}, which handles case + * folding logic, instead of this method. + */ + UChar32 getCodePoint() const; + + /** + * Returns true if the first code point of this StringSegment equals the given code point. + * + *

+ * This method will perform case folding if case folding is enabled for the parser. + */ + bool startsWith(UChar32 otherCp) const; + + /** + * Returns true if the first code point of this StringSegment is in the given UnicodeSet. + */ + bool startsWith(const UnicodeSet& uniset) const; + + /** + * Returns true if there is at least one code point of overlap between this StringSegment and the + * given UnicodeString. + */ + bool startsWith(const UnicodeString& other) const; + + /** + * Returns the length of the prefix shared by this StringSegment and the given CharSequence. For + * example, if this string segment is "aab", and the char sequence is "aac", this method returns 2, + * since the first 2 characters are the same. + * + *

+ * This method only returns offsets along code point boundaries. + * + *

+ * This method will perform case folding if case folding was enabled in the constructor. + * + *

+ * IMPORTANT: The given UnicodeString must not be empty! It is the caller's responsibility to check. + */ + int32_t getCommonPrefixLength(const UnicodeString& other); + + /** + * Like {@link #getCommonPrefixLength}, but never performs case folding, even if case folding is + * enabled for the parser. + */ + int32_t getCaseSensitivePrefixLength(const UnicodeString& other); + + bool operator==(const UnicodeString& other) const; + + private: + const UnicodeString fStr; + int32_t fStart; + int32_t fEnd; + bool fFoldCase; + + int32_t getPrefixLengthInternal(const UnicodeString& other, bool foldCase); + + static bool codePointsEqual(UChar32 cp1, UChar32 cp2, bool foldCase); +}; + + +/** + * The core interface implemented by all matchers used for number parsing. + * + * Given a string, there should NOT be more than one way to consume the string with the same matcher + * applied multiple times. If there is, the non-greedy parsing algorithm will be unhappy and may enter an + * exponential-time loop. For example, consider the "A Matcher" that accepts "any number of As". Given + * the string "AAAA", there are 2^N = 8 ways to apply the A Matcher to this string: you could have the A + * Matcher apply 4 times to each character; you could have it apply just once to all the characters; you + * could have it apply to the first 2 characters and the second 2 characters; and so on. A better version + * of the "A Matcher" would be for it to accept exactly one A, and allow the algorithm to run it + * repeatedly to consume a string of multiple As. The A Matcher can implement the Flexible interface + * below to signal that it can be applied multiple times in a row. + * + * @author sffc + */ +// Exported as U_I18N_API for tests +class U_I18N_API NumberParseMatcher { + public: + virtual ~NumberParseMatcher(); + + /** + * Matchers can override this method to return true to indicate that they are optional and can be run + * repeatedly. Used by SeriesMatcher, primarily in the context of IgnorablesMatcher. + */ + virtual bool isFlexible() const { + return false; + } + + /** + * Runs this matcher starting at the beginning of the given StringSegment. If this matcher finds + * something interesting in the StringSegment, it should update the offset of the StringSegment + * corresponding to how many chars were matched. + * + * This method is thread-safe. + * + * @param segment + * The StringSegment to match against. Matches always start at the beginning of the + * segment. The segment is guaranteed to contain at least one char. + * @param result + * The data structure to store results if the match succeeds. + * @return Whether this matcher thinks there may be more interesting chars beyond the end of the + * string segment. + */ + virtual bool match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const = 0; + + /** + * Performs a fast "smoke check" for whether or not this matcher could possibly match against the + * given string segment. The test should be as fast as possible but also as restrictive as possible. + * For example, matchers can maintain a UnicodeSet of all code points that count possibly start a + * match. Matchers should use the {@link StringSegment#startsWith} method in order to correctly + * handle case folding. + * + * @param segment + * The segment to check against. + * @return true if the matcher might be able to match against this segment; false if it definitely + * will not be able to match. + */ + virtual bool smokeTest(const StringSegment& segment) const = 0; + + /** + * Method called at the end of a parse, after all matchers have failed to consume any more chars. + * Allows a matcher to make final modifications to the result given the knowledge that no more + * matches are possible. + * + * @param result + * The data structure to store results. + */ + virtual void postProcess(ParsedNumber&) const { + // Default implementation: no-op + }; + + // String for debugging + virtual UnicodeString toString() const = 0; + + protected: + // No construction except by subclasses! + NumberParseMatcher() = default; +}; + + +/** + * Interface for use in arguments. + */ +// Exported as U_I18N_API for tests +class U_I18N_API MutableMatcherCollection { + public: + virtual ~MutableMatcherCollection() = default; + + virtual void addMatcher(NumberParseMatcher& matcher) = 0; +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_TYPES_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_utils.h b/deps/icu-small/source/i18n/numparse_utils.h new file mode 100644 index 0000000000..162954bae0 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_utils.h @@ -0,0 +1,43 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __NUMPARSE_UTILS_H__ +#define __NUMPARSE_UTILS_H__ + +#include "numparse_types.h" +#include "unicode/uniset.h" + +U_NAMESPACE_BEGIN namespace numparse { +namespace impl { +namespace utils { + + +inline static void putLeadCodePoints(const UnicodeSet* input, UnicodeSet* output) { + for (int32_t i = 0; i < input->getRangeCount(); i++) { + output->add(input->getRangeStart(i), input->getRangeEnd(i)); + } + // TODO: ANDY: How to iterate over the strings in ICU4C UnicodeSet? +} + +inline static void putLeadCodePoint(const UnicodeString& input, UnicodeSet* output) { + if (!input.isEmpty()) { + output->add(input.char32At(0)); + } +} + +inline static void copyCurrencyCode(UChar* dest, const UChar* src) { + uprv_memcpy(dest, src, sizeof(UChar) * 3); + dest[3] = 0; +} + + +} // namespace utils +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__NUMPARSE_UTILS_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_validators.cpp b/deps/icu-small/source/i18n/numparse_validators.cpp new file mode 100644 index 0000000000..12d3465c4e --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_validators.cpp @@ -0,0 +1,85 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "numparse_validators.h" +#include "static_unicode_sets.h" + +using namespace icu; +using namespace icu::numparse; +using namespace icu::numparse::impl; + + +void RequireAffixValidator::postProcess(ParsedNumber& result) const { + if (result.prefix.isBogus() || result.suffix.isBogus()) { + // We saw a prefix or a suffix but not both. Fail the parse. + result.flags |= FLAG_FAIL; + } +} + +UnicodeString RequireAffixValidator::toString() const { + return u""; +} + + +void RequireCurrencyValidator::postProcess(ParsedNumber& result) const { + if (result.currencyCode[0] == 0) { + result.flags |= FLAG_FAIL; + } +} + +UnicodeString RequireCurrencyValidator::toString() const { + return u""; +} + + +RequireDecimalSeparatorValidator::RequireDecimalSeparatorValidator(bool patternHasDecimalSeparator) + : fPatternHasDecimalSeparator(patternHasDecimalSeparator) { +} + +void RequireDecimalSeparatorValidator::postProcess(ParsedNumber& result) const { + bool parseHasDecimalSeparator = 0 != (result.flags & FLAG_HAS_DECIMAL_SEPARATOR); + if (parseHasDecimalSeparator != fPatternHasDecimalSeparator) { + result.flags |= FLAG_FAIL; + } +} + +UnicodeString RequireDecimalSeparatorValidator::toString() const { + return u""; +} + + +void RequireNumberValidator::postProcess(ParsedNumber& result) const { + // Require that a number is matched. + if (!result.seenNumber()) { + result.flags |= FLAG_FAIL; + } +} + +UnicodeString RequireNumberValidator::toString() const { + return u""; +} + +MultiplierParseHandler::MultiplierParseHandler(::icu::number::Scale multiplier) + : fMultiplier(std::move(multiplier)) {} + +void MultiplierParseHandler::postProcess(ParsedNumber& result) const { + if (!result.quantity.bogus) { + fMultiplier.applyReciprocalTo(result.quantity); + // NOTE: It is okay if the multiplier was negative. + } +} + +UnicodeString MultiplierParseHandler::toString() const { + return u""; +} + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/numparse_validators.h b/deps/icu-small/source/i18n/numparse_validators.h new file mode 100644 index 0000000000..5d43b779d0 --- /dev/null +++ b/deps/icu-small/source/i18n/numparse_validators.h @@ -0,0 +1,95 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __SOURCE_NUMPARSE_VALIDATORS_H__ +#define __SOURCE_NUMPARSE_VALIDATORS_H__ + +#include "numparse_types.h" +#include "static_unicode_sets.h" + +U_NAMESPACE_BEGIN namespace numparse { +namespace impl { + + +class ValidationMatcher : public NumberParseMatcher { + public: + bool match(StringSegment&, ParsedNumber&, UErrorCode&) const U_OVERRIDE { + // No-op + return false; + } + + bool smokeTest(const StringSegment&) const U_OVERRIDE { + // No-op + return false; + } + + void postProcess(ParsedNumber& result) const U_OVERRIDE = 0; +}; + + +class RequireAffixValidator : public ValidationMatcher, public UMemory { + public: + void postProcess(ParsedNumber& result) const U_OVERRIDE; + + UnicodeString toString() const U_OVERRIDE; +}; + + +class RequireCurrencyValidator : public ValidationMatcher, public UMemory { + public: + void postProcess(ParsedNumber& result) const U_OVERRIDE; + + UnicodeString toString() const U_OVERRIDE; +}; + + +class RequireDecimalSeparatorValidator : public ValidationMatcher, public UMemory { + public: + RequireDecimalSeparatorValidator() = default; // leaves instance in valid but undefined state + + RequireDecimalSeparatorValidator(bool patternHasDecimalSeparator); + + void postProcess(ParsedNumber& result) const U_OVERRIDE; + + UnicodeString toString() const U_OVERRIDE; + + private: + bool fPatternHasDecimalSeparator; +}; + + +class RequireNumberValidator : public ValidationMatcher, public UMemory { + public: + void postProcess(ParsedNumber& result) const U_OVERRIDE; + + UnicodeString toString() const U_OVERRIDE; +}; + + +/** + * Wraps a {@link Multiplier} for use in the number parsing pipeline. + */ +class MultiplierParseHandler : public ValidationMatcher, public UMemory { + public: + MultiplierParseHandler() = default; // leaves instance in valid but undefined state + + MultiplierParseHandler(::icu::number::Scale multiplier); + + void postProcess(ParsedNumber& result) const U_OVERRIDE; + + UnicodeString toString() const U_OVERRIDE; + + private: + ::icu::number::Scale fMultiplier; +}; + + +} // namespace impl +} // namespace numparse +U_NAMESPACE_END + +#endif //__SOURCE_NUMPARSE_VALIDATORS_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/pluralaffix.cpp b/deps/icu-small/source/i18n/pluralaffix.cpp deleted file mode 100644 index ea400206b3..0000000000 --- a/deps/icu-small/source/i18n/pluralaffix.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: pluralaffix.cpp - */ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "cstring.h" -#include "digitaffix.h" -#include "pluralaffix.h" - -U_NAMESPACE_BEGIN - -UBool -PluralAffix::setVariant( - const char *variant, const UnicodeString &value, UErrorCode &status) { - DigitAffix *current = affixes.getMutable(variant, status); - if (U_FAILURE(status)) { - return FALSE; - } - current->remove(); - current->append(value); - return TRUE; -} - -void -PluralAffix::remove() { - affixes.clear(); -} - -void -PluralAffix::appendUChar( - const UChar value, int32_t fieldId) { - PluralMapBase::Category index = PluralMapBase::NONE; - for (DigitAffix *current = affixes.nextMutable(index); - current != NULL; current = affixes.nextMutable(index)) { - current->appendUChar(value, fieldId); - } -} - -void -PluralAffix::append( - const UnicodeString &value, int32_t fieldId) { - PluralMapBase::Category index = PluralMapBase::NONE; - for (DigitAffix *current = affixes.nextMutable(index); - current != NULL; current = affixes.nextMutable(index)) { - current->append(value, fieldId); - } -} - -void -PluralAffix::append( - const UChar *value, int32_t charCount, int32_t fieldId) { - PluralMapBase::Category index = PluralMapBase::NONE; - for (DigitAffix *current = affixes.nextMutable(index); - current != NULL; current = affixes.nextMutable(index)) { - current->append(value, charCount, fieldId); - } -} - -UBool -PluralAffix::append( - const PluralAffix &rhs, int32_t fieldId, UErrorCode &status) { - if (U_FAILURE(status)) { - return FALSE; - } - PluralMapBase::Category index = PluralMapBase::NONE; - while(rhs.affixes.next(index) != NULL) { - affixes.getMutableWithDefault(index, affixes.getOther(), status); - } - index = PluralMapBase::NONE; - for (DigitAffix *current = affixes.nextMutable(index); - current != NULL; current = affixes.nextMutable(index)) { - current->append(rhs.affixes.get(index).toString(), fieldId); - } - return TRUE; -} - -const DigitAffix & -PluralAffix::getByCategory(const char *category) const { - return affixes.get(category); -} - -const DigitAffix & -PluralAffix::getByCategory(const UnicodeString &category) const { - return affixes.get(category); -} - -UBool -PluralAffix::hasMultipleVariants() const { - // This works because OTHER is guaranteed to be the first enum value - PluralMapBase::Category index = PluralMapBase::OTHER; - return (affixes.next(index) != NULL); -} - -U_NAMESPACE_END - -#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/pluralaffix.h b/deps/icu-small/source/i18n/pluralaffix.h deleted file mode 100644 index 94366ce4cf..0000000000 --- a/deps/icu-small/source/i18n/pluralaffix.h +++ /dev/null @@ -1,177 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* pluralaffix.h -* -* created on: 2015jan06 -* created by: Travis Keep -*/ - -#ifndef __PLURALAFFIX_H__ -#define __PLURALAFFIX_H__ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/unum.h" -#include "unicode/uobject.h" - -#include "digitaffix.h" -#include "pluralmap.h" - -U_NAMESPACE_BEGIN - -class FieldPositionHandler; - -// Export an explicit template instantiation. -// -// MSVC requires this, even though it should not be necessary. -// No direct access leaks out of the i18n library. -// -// Macintosh produces duplicate definition linker errors with the explicit template -// instantiation. -// -#if !U_PLATFORM_IS_DARWIN_BASED -template class U_I18N_API PluralMap; -#endif - - -/** - * A plural aware prefix or suffix of a formatted number. - * - * PluralAffix is essentially a map of DigitAffix objects keyed by plural - * category. The 'other' category is the default and always has some - * value. The rest of the categories are optional. Querying for a category that - * is not set always returns the DigitAffix stored in the 'other' category. - * - * To use one of these objects, build it up first using append() and - * setVariant() methods. Once built, leave unchanged and let multiple threads - * safely access. - * - * The following code is sample code for building up: - * one: US Dollar - - * other: US Dollars - - * - * and storing it in "negativeCurrencyPrefix" - * - * UErrorCode status = U_ZERO_ERROR; - * - * PluralAffix negativeCurrencyPrefix; - * - * PluralAffix currencyName; - * currencyName.setVariant("one", "US Dollar", status); - * currencyName.setVariant("other", "US Dollars", status); - * - * negativeCurrencyPrefix.append(currencyName, UNUM_CURRENCY_FIELD, status); - * negativeCurrencyPrefix.append(" "); - * negativeCurrencyPrefix.append("-", UNUM_SIGN_FIELD, status); - */ -class U_I18N_API PluralAffix : public UMemory { -public: - - /** - * Create empty PluralAffix. - */ - PluralAffix() : affixes() { } - - /** - * Create a PluralAffix where the 'other' variant is otherVariant. - */ - PluralAffix(const DigitAffix &otherVariant) : affixes(otherVariant) { } - - /** - * Sets a particular variant for a plural category while overwriting - * anything that may have been previously stored for that plural - * category. The set value has no field annotations. - * @param category "one", "two", "few", ... - * @param variant the variant to store under the particular category - * @param status Any error returned here. - */ - UBool setVariant( - const char *category, - const UnicodeString &variant, - UErrorCode &status); - /** - * Make the 'other' variant be the empty string with no field annotations - * and remove the variants for the rest of the plural categories. - */ - void remove(); - - /** - * Append value to all set plural categories. If fieldId present, value - * is that field type. - */ - void appendUChar(UChar value, int32_t fieldId=UNUM_FIELD_COUNT); - - /** - * Append value to all set plural categories. If fieldId present, value - * is that field type. - */ - void append(const UnicodeString &value, int32_t fieldId=UNUM_FIELD_COUNT); - - /** - * Append value to all set plural categories. If fieldId present, value - * is that field type. - */ - void append(const UChar *value, int32_t charCount, int32_t fieldId=UNUM_FIELD_COUNT); - - /** - * Append the value for each plural category in rhs to the corresponding - * plural category in this instance. Each value appended from rhs is - * of type fieldId. - */ - UBool append( - const PluralAffix &rhs, - int32_t fieldId, - UErrorCode &status); - /** - * Get the DigitAffix for a paricular category such as "zero", "one", ... - * If the particular category is not set, returns the 'other' category - * which is always set. - */ - const DigitAffix &getByCategory(const char *category) const; - - /** - * Get the DigitAffix for a paricular category such as "zero", "one", ... - * If the particular category is not set, returns the 'other' category - * which is always set. - */ - const DigitAffix &getByCategory(const UnicodeString &category) const; - - /** - * Get the DigitAffix for the other category which is always set. - */ - const DigitAffix &getOtherVariant() const { - return affixes.getOther(); - } - - /** - * Returns TRUE if this instance has variants stored besides the "other" - * variant. - */ - UBool hasMultipleVariants() const; - - /** - * Returns TRUE if this instance equals rhs. - */ - UBool equals(const PluralAffix &rhs) const { - return affixes.equals(rhs.affixes, &eq); - } - -private: - PluralMap affixes; - - static UBool eq(const DigitAffix &x, const DigitAffix &y) { - return x.equals(y); - } -}; - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ -#endif // __PLURALAFFIX_H__ diff --git a/deps/icu-small/source/i18n/plurfmt.cpp b/deps/icu-small/source/i18n/plurfmt.cpp index e14ef6d831..2775766d32 100644 --- a/deps/icu-small/source/i18n/plurfmt.cpp +++ b/deps/icu-small/source/i18n/plurfmt.cpp @@ -21,13 +21,16 @@ #include "plurrule_impl.h" #include "uassert.h" #include "uhash.h" -#include "precision.h" -#include "visibledigits.h" +#include "number_decimalquantity.h" +#include "number_utils.h" +#include "number_utypes.h" #if !UCONFIG_NO_FORMATTING U_NAMESPACE_BEGIN +using number::impl::DecimalQuantity; + static const UChar OTHER_STRING[] = { 0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other" }; @@ -258,45 +261,33 @@ PluralFormat::format(const Formattable& numberObject, double number, if (msgPattern.countParts() == 0) { return numberFormat->format(numberObject, appendTo, pos, status); } + // Get the appropriate sub-message. // Select it based on the formatted number-offset. double numberMinusOffset = number - offset; - UnicodeString numberString; - FieldPosition ignorePos; - FixedPrecision fp; - VisibleDigitsWithExponent dec; - fp.initVisibleDigitsWithExponent(numberMinusOffset, dec, status); - if (U_FAILURE(status)) { - return appendTo; - } + // Call NumberFormatter to get both the DecimalQuantity and the string. + // This call site needs to use more internal APIs than the Java equivalent. + number::impl::UFormattedNumberData data; if (offset == 0) { - DecimalFormat *decFmt = dynamic_cast(numberFormat); - if(decFmt != NULL) { - decFmt->initVisibleDigitsWithExponent( - numberObject, dec, status); - if (U_FAILURE(status)) { - return appendTo; - } - decFmt->format(dec, numberString, ignorePos, status); - } else { - numberFormat->format( - numberObject, numberString, ignorePos, status); // could be BigDecimal etc. - } + // could be BigDecimal etc. + numberObject.populateDecimalQuantity(data.quantity, status); } else { - DecimalFormat *decFmt = dynamic_cast(numberFormat); - if(decFmt != NULL) { - decFmt->initVisibleDigitsWithExponent( - numberMinusOffset, dec, status); - if (U_FAILURE(status)) { - return appendTo; - } - decFmt->format(dec, numberString, ignorePos, status); + data.quantity.setToDouble(numberMinusOffset); + } + UnicodeString numberString; + auto *decFmt = dynamic_cast(numberFormat); + if(decFmt != nullptr) { + decFmt->toNumberFormatter().formatImpl(&data, status); // mutates &data + numberString = data.string.toUnicodeString(); + } else { + if (offset == 0) { + numberFormat->format(numberObject, numberString, status); } else { - numberFormat->format( - numberMinusOffset, numberString, ignorePos, status); + numberFormat->format(numberMinusOffset, numberString, status); } } - int32_t partIndex = findSubMessage(msgPattern, 0, pluralRulesWrapper, &dec, number, status); + + int32_t partIndex = findSubMessage(msgPattern, 0, pluralRulesWrapper, &data.quantity, number, status); if (U_FAILURE(status)) { return appendTo; } // Replace syntactic # signs in the top level of this sub-message // (not in nested arguments) with the formatted number-offset. @@ -585,7 +576,7 @@ PluralFormat::PluralSelectorAdapter::~PluralSelectorAdapter() { UnicodeString PluralFormat::PluralSelectorAdapter::select(void *context, double number, UErrorCode& /*ec*/) const { (void)number; // unused except in the assertion - VisibleDigitsWithExponent *dec=static_cast(context); + IFixedDecimal *dec=static_cast(context); return pluralRules->select(*dec); } diff --git a/deps/icu-small/source/i18n/plurrule.cpp b/deps/icu-small/source/i18n/plurrule.cpp index 6733a23e00..9597e8eb00 100644 --- a/deps/icu-small/source/i18n/plurrule.cpp +++ b/deps/icu-small/source/i18n/plurrule.cpp @@ -22,7 +22,6 @@ #include "charstr.h" #include "cmemory.h" #include "cstring.h" -#include "digitlst.h" #include "hash.h" #include "locutil.h" #include "mutex.h" @@ -35,13 +34,15 @@ #include "uvectr32.h" #include "sharedpluralrules.h" #include "unifiedcache.h" -#include "digitinterval.h" -#include "visibledigits.h" +#include "number_decimalquantity.h" #if !UCONFIG_NO_FORMATTING U_NAMESPACE_BEGIN +using namespace icu::pluralimpl; +using icu::number::impl::DecimalQuantity; + static const UChar PLURAL_KEYWORD_OTHER[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,0}; static const UChar PLURAL_DEFAULT_RULE[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,COLON,SPACE,LOW_N,0}; static const UChar PK_IN[]={LOW_I,LOW_N,0}; @@ -247,26 +248,6 @@ PluralRules::select(double number) const { return select(FixedDecimal(number)); } -UnicodeString -PluralRules::select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) const { - if (U_SUCCESS(status)) { - const DecimalFormat *decFmt = dynamic_cast(&fmt); - if (decFmt != NULL) { - VisibleDigitsWithExponent digits; - decFmt->initVisibleDigitsWithExponent(obj, digits, status); - if (U_SUCCESS(status)) { - return select(digits); - } - } else { - double number = obj.getDouble(status); - if (U_SUCCESS(status)) { - return select(number); - } - } - } - return UnicodeString(); -} - UnicodeString PluralRules::select(const IFixedDecimal &number) const { if (mRules == NULL) { @@ -277,14 +258,6 @@ PluralRules::select(const IFixedDecimal &number) const { } } -UnicodeString -PluralRules::select(const VisibleDigitsWithExponent &number) const { - if (number.getExponent() != NULL) { - return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1); - } - return select(FixedDecimal(number.getMantissa())); -} - StringEnumeration* @@ -1425,18 +1398,6 @@ PluralOperand tokenTypeToPluralOperand(tokenType tt) { } } -IFixedDecimal::~IFixedDecimal() = default; - -FixedDecimal::FixedDecimal(const VisibleDigits &digits) { - digits.getFixedDecimal( - source, intValue, decimalDigits, - decimalDigitsWithoutTrailingZeros, - visibleDecimalDigitCount, hasIntegerValue); - isNegative = digits.isNegative(); - _isNaN = digits.isNaN(); - _isInfinite = digits.isInfinite(); -} - FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f) { init(n, v, f); // check values. TODO make into unit test. @@ -1474,14 +1435,14 @@ FixedDecimal::FixedDecimal() { FixedDecimal::FixedDecimal(const UnicodeString &num, UErrorCode &status) { CharString cs; cs.appendInvariantChars(num, status); - DigitList dl; - dl.set(cs.toStringPiece(), status); + DecimalQuantity dl; + dl.setToDecNumber(cs.toStringPiece(), status); if (U_FAILURE(status)) { init(0, 0, 0); return; } int32_t decimalPoint = num.indexOf(DOT); - double n = dl.getDouble(); + double n = dl.toDouble(); if (decimalPoint == -1) { init(n, 0, 0); } else { @@ -1497,7 +1458,7 @@ FixedDecimal::FixedDecimal(const FixedDecimal &other) { decimalDigits = other.decimalDigits; decimalDigitsWithoutTrailingZeros = other.decimalDigitsWithoutTrailingZeros; intValue = other.intValue; - hasIntegerValue = other.hasIntegerValue; + _hasIntegerValue = other._hasIntegerValue; isNegative = other.isNegative; _isNaN = other._isNaN; _isInfinite = other._isInfinite; @@ -1521,10 +1482,10 @@ void FixedDecimal::init(double n, int32_t v, int64_t f) { v = 0; f = 0; intValue = 0; - hasIntegerValue = FALSE; + _hasIntegerValue = FALSE; } else { intValue = (int64_t)source; - hasIntegerValue = (source == intValue); + _hasIntegerValue = (source == intValue); } visibleDecimalDigitCount = v; @@ -1658,6 +1619,10 @@ bool FixedDecimal::isInfinite() const { return _isInfinite; } +bool FixedDecimal::hasIntegerValue() const { + return _hasIntegerValue; +} + bool FixedDecimal::isNanOrInfinity() const { return _isNaN || _isInfinite; } diff --git a/deps/icu-small/source/i18n/plurrule_impl.h b/deps/icu-small/source/i18n/plurrule_impl.h index b93fc501ba..3ab445d584 100644 --- a/deps/icu-small/source/i18n/plurrule_impl.h +++ b/deps/icu-small/source/i18n/plurrule_impl.h @@ -40,67 +40,73 @@ class DigitInterval; class PluralRules; class VisibleDigits; -static const UChar DOT = ((UChar)0x002E); -static const UChar SINGLE_QUOTE = ((UChar)0x0027); -static const UChar SLASH = ((UChar)0x002F); -static const UChar BACKSLASH = ((UChar)0x005C); -static const UChar SPACE = ((UChar)0x0020); -static const UChar EXCLAMATION = ((UChar)0x0021); -static const UChar QUOTATION_MARK = ((UChar)0x0022); -static const UChar NUMBER_SIGN = ((UChar)0x0023); -static const UChar PERCENT_SIGN = ((UChar)0x0025); -static const UChar ASTERISK = ((UChar)0x002A); -static const UChar COMMA = ((UChar)0x002C); -static const UChar HYPHEN = ((UChar)0x002D); -static const UChar U_ZERO = ((UChar)0x0030); -static const UChar U_ONE = ((UChar)0x0031); -static const UChar U_TWO = ((UChar)0x0032); -static const UChar U_THREE = ((UChar)0x0033); -static const UChar U_FOUR = ((UChar)0x0034); -static const UChar U_FIVE = ((UChar)0x0035); -static const UChar U_SIX = ((UChar)0x0036); -static const UChar U_SEVEN = ((UChar)0x0037); -static const UChar U_EIGHT = ((UChar)0x0038); -static const UChar U_NINE = ((UChar)0x0039); -static const UChar COLON = ((UChar)0x003A); -static const UChar SEMI_COLON = ((UChar)0x003B); -static const UChar EQUALS = ((UChar)0x003D); -static const UChar AT = ((UChar)0x0040); -static const UChar CAP_A = ((UChar)0x0041); -static const UChar CAP_B = ((UChar)0x0042); -static const UChar CAP_R = ((UChar)0x0052); -static const UChar CAP_Z = ((UChar)0x005A); -static const UChar LOWLINE = ((UChar)0x005F); -static const UChar LEFTBRACE = ((UChar)0x007B); -static const UChar RIGHTBRACE = ((UChar)0x007D); -static const UChar TILDE = ((UChar)0x007E); -static const UChar ELLIPSIS = ((UChar)0x2026); - -static const UChar LOW_A = ((UChar)0x0061); -static const UChar LOW_B = ((UChar)0x0062); -static const UChar LOW_C = ((UChar)0x0063); -static const UChar LOW_D = ((UChar)0x0064); -static const UChar LOW_E = ((UChar)0x0065); -static const UChar LOW_F = ((UChar)0x0066); -static const UChar LOW_G = ((UChar)0x0067); -static const UChar LOW_H = ((UChar)0x0068); -static const UChar LOW_I = ((UChar)0x0069); -static const UChar LOW_J = ((UChar)0x006a); -static const UChar LOW_K = ((UChar)0x006B); -static const UChar LOW_L = ((UChar)0x006C); -static const UChar LOW_M = ((UChar)0x006D); -static const UChar LOW_N = ((UChar)0x006E); -static const UChar LOW_O = ((UChar)0x006F); -static const UChar LOW_P = ((UChar)0x0070); -static const UChar LOW_Q = ((UChar)0x0071); -static const UChar LOW_R = ((UChar)0x0072); -static const UChar LOW_S = ((UChar)0x0073); -static const UChar LOW_T = ((UChar)0x0074); -static const UChar LOW_U = ((UChar)0x0075); -static const UChar LOW_V = ((UChar)0x0076); -static const UChar LOW_W = ((UChar)0x0077); -static const UChar LOW_Y = ((UChar)0x0079); -static const UChar LOW_Z = ((UChar)0x007A); +namespace pluralimpl { + +// TODO: Remove this and replace with u"" literals. Was for EBCDIC compatibility. + +static const UChar DOT = ((UChar) 0x002E); +static const UChar SINGLE_QUOTE = ((UChar) 0x0027); +static const UChar SLASH = ((UChar) 0x002F); +static const UChar BACKSLASH = ((UChar) 0x005C); +static const UChar SPACE = ((UChar) 0x0020); +static const UChar EXCLAMATION = ((UChar) 0x0021); +static const UChar QUOTATION_MARK = ((UChar) 0x0022); +static const UChar NUMBER_SIGN = ((UChar) 0x0023); +static const UChar PERCENT_SIGN = ((UChar) 0x0025); +static const UChar ASTERISK = ((UChar) 0x002A); +static const UChar COMMA = ((UChar) 0x002C); +static const UChar HYPHEN = ((UChar) 0x002D); +static const UChar U_ZERO = ((UChar) 0x0030); +static const UChar U_ONE = ((UChar) 0x0031); +static const UChar U_TWO = ((UChar) 0x0032); +static const UChar U_THREE = ((UChar) 0x0033); +static const UChar U_FOUR = ((UChar) 0x0034); +static const UChar U_FIVE = ((UChar) 0x0035); +static const UChar U_SIX = ((UChar) 0x0036); +static const UChar U_SEVEN = ((UChar) 0x0037); +static const UChar U_EIGHT = ((UChar) 0x0038); +static const UChar U_NINE = ((UChar) 0x0039); +static const UChar COLON = ((UChar) 0x003A); +static const UChar SEMI_COLON = ((UChar) 0x003B); +static const UChar EQUALS = ((UChar) 0x003D); +static const UChar AT = ((UChar) 0x0040); +static const UChar CAP_A = ((UChar) 0x0041); +static const UChar CAP_B = ((UChar) 0x0042); +static const UChar CAP_R = ((UChar) 0x0052); +static const UChar CAP_Z = ((UChar) 0x005A); +static const UChar LOWLINE = ((UChar) 0x005F); +static const UChar LEFTBRACE = ((UChar) 0x007B); +static const UChar RIGHTBRACE = ((UChar) 0x007D); +static const UChar TILDE = ((UChar) 0x007E); +static const UChar ELLIPSIS = ((UChar) 0x2026); + +static const UChar LOW_A = ((UChar) 0x0061); +static const UChar LOW_B = ((UChar) 0x0062); +static const UChar LOW_C = ((UChar) 0x0063); +static const UChar LOW_D = ((UChar) 0x0064); +static const UChar LOW_E = ((UChar) 0x0065); +static const UChar LOW_F = ((UChar) 0x0066); +static const UChar LOW_G = ((UChar) 0x0067); +static const UChar LOW_H = ((UChar) 0x0068); +static const UChar LOW_I = ((UChar) 0x0069); +static const UChar LOW_J = ((UChar) 0x006a); +static const UChar LOW_K = ((UChar) 0x006B); +static const UChar LOW_L = ((UChar) 0x006C); +static const UChar LOW_M = ((UChar) 0x006D); +static const UChar LOW_N = ((UChar) 0x006E); +static const UChar LOW_O = ((UChar) 0x006F); +static const UChar LOW_P = ((UChar) 0x0070); +static const UChar LOW_Q = ((UChar) 0x0071); +static const UChar LOW_R = ((UChar) 0x0072); +static const UChar LOW_S = ((UChar) 0x0073); +static const UChar LOW_T = ((UChar) 0x0074); +static const UChar LOW_U = ((UChar) 0x0075); +static const UChar LOW_V = ((UChar) 0x0076); +static const UChar LOW_W = ((UChar) 0x0077); +static const UChar LOW_Y = ((UChar) 0x0079); +static const UChar LOW_Z = ((UChar) 0x007A); + +} static const int32_t PLURAL_RANGE_HIGH = 0x7fffffff; @@ -244,6 +250,9 @@ class U_I18N_API IFixedDecimal { virtual bool isNaN() const = 0; virtual bool isInfinite() const = 0; + + /** Whether the number has no nonzero fraction digits. */ + virtual bool hasIntegerValue() const = 0; }; /** @@ -263,7 +272,6 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject { FixedDecimal(double n, int32_t v, int64_t f); FixedDecimal(double n, int32_t); explicit FixedDecimal(double n); - explicit FixedDecimal(const VisibleDigits &n); FixedDecimal(); ~FixedDecimal() U_OVERRIDE; FixedDecimal(const UnicodeString &s, UErrorCode &ec); @@ -272,6 +280,7 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject { double getPluralOperand(PluralOperand operand) const U_OVERRIDE; bool isNaN() const U_OVERRIDE; bool isInfinite() const U_OVERRIDE; + bool hasIntegerValue() const U_OVERRIDE; bool isNanOrInfinity() const; // used in decimfmtimpl.cpp @@ -290,7 +299,7 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject { int64_t decimalDigits; int64_t decimalDigitsWithoutTrailingZeros; int64_t intValue; - UBool hasIntegerValue; + UBool _hasIntegerValue; UBool isNegative; UBool _isNaN; UBool _isInfinite; diff --git a/deps/icu-small/source/i18n/precision.cpp b/deps/icu-small/source/i18n/precision.cpp deleted file mode 100644 index 97dc13dc38..0000000000 --- a/deps/icu-small/source/i18n/precision.cpp +++ /dev/null @@ -1,444 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: precisison.cpp - */ - -#include - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "digitlst.h" -#include "fmtableimp.h" -#include "precision.h" -#include "putilimp.h" -#include "visibledigits.h" - -U_NAMESPACE_BEGIN - -static const int32_t gPower10[] = {1, 10, 100, 1000}; - -FixedPrecision::FixedPrecision() - : fExactOnly(FALSE), fFailIfOverMax(FALSE), fRoundingMode(DecimalFormat::kRoundHalfEven) { - fMin.setIntDigitCount(1); - fMin.setFracDigitCount(0); -} - -UBool -FixedPrecision::isRoundingRequired( - int32_t upperExponent, int32_t lowerExponent) const { - int32_t leastSigAllowed = fMax.getLeastSignificantInclusive(); - int32_t maxSignificantDigits = fSignificant.getMax(); - int32_t roundDigit; - if (maxSignificantDigits == INT32_MAX) { - roundDigit = leastSigAllowed; - } else { - int32_t limitDigit = upperExponent - maxSignificantDigits; - roundDigit = - limitDigit > leastSigAllowed ? limitDigit : leastSigAllowed; - } - return (roundDigit > lowerExponent); -} - -DigitList & -FixedPrecision::round( - DigitList &value, int32_t exponent, UErrorCode &status) const { - if (U_FAILURE(status)) { - return value; - } - value .fContext.status &= ~DEC_Inexact; - if (!fRoundingIncrement.isZero()) { - if (exponent == 0) { - value.quantize(fRoundingIncrement, status); - } else { - DigitList adjustedIncrement(fRoundingIncrement); - adjustedIncrement.shiftDecimalRight(exponent); - value.quantize(adjustedIncrement, status); - } - if (U_FAILURE(status)) { - return value; - } - } - int32_t leastSig = fMax.getLeastSignificantInclusive(); - if (leastSig == INT32_MIN) { - value.round(fSignificant.getMax()); - } else { - value.roundAtExponent( - exponent + leastSig, - fSignificant.getMax()); - } - if (fExactOnly && (value.fContext.status & DEC_Inexact)) { - status = U_FORMAT_INEXACT_ERROR; - } else if (fFailIfOverMax) { - // Smallest interval for value stored in interval - DigitInterval interval; - value.getSmallestInterval(interval); - if (fMax.getIntDigitCount() < interval.getIntDigitCount()) { - status = U_ILLEGAL_ARGUMENT_ERROR; - } - } - return value; -} - -DigitInterval & -FixedPrecision::getIntervalForZero(DigitInterval &interval) const { - interval = fMin; - if (fSignificant.getMin() > 0) { - interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin()); - } - interval.shrinkToFitWithin(fMax); - return interval; -} - -DigitInterval & -FixedPrecision::getInterval( - int32_t upperExponent, DigitInterval &interval) const { - if (fSignificant.getMin() > 0) { - interval.expandToContainDigit( - upperExponent - fSignificant.getMin()); - } - interval.expandToContain(fMin); - interval.shrinkToFitWithin(fMax); - return interval; -} - -DigitInterval & -FixedPrecision::getInterval( - const DigitList &value, DigitInterval &interval) const { - if (value.isZero()) { - interval = fMin; - if (fSignificant.getMin() > 0) { - interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin()); - } - } else { - value.getSmallestInterval(interval); - if (fSignificant.getMin() > 0) { - interval.expandToContainDigit( - value.getUpperExponent() - fSignificant.getMin()); - } - interval.expandToContain(fMin); - } - interval.shrinkToFitWithin(fMax); - return interval; -} - -UBool -FixedPrecision::isFastFormattable() const { - return (fMin.getFracDigitCount() == 0 && fSignificant.isNoConstraints() && fRoundingIncrement.isZero() && !fFailIfOverMax); -} - -UBool -FixedPrecision::handleNonNumeric(DigitList &value, VisibleDigits &digits) { - if (value.isNaN()) { - digits.setNaN(); - return TRUE; - } - if (value.isInfinite()) { - digits.setInfinite(); - if (!value.isPositive()) { - digits.setNegative(); - } - return TRUE; - } - return FALSE; -} - -VisibleDigits & -FixedPrecision::initVisibleDigits( - DigitList &value, - VisibleDigits &digits, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return digits; - } - digits.clear(); - if (handleNonNumeric(value, digits)) { - return digits; - } - if (!value.isPositive()) { - digits.setNegative(); - } - value.setRoundingMode(fRoundingMode); - round(value, 0, status); - getInterval(value, digits.fInterval); - digits.fExponent = value.getLowerExponent(); - value.appendDigitsTo(digits.fDigits, status); - return digits; -} - -VisibleDigits & -FixedPrecision::initVisibleDigits( - int64_t value, - VisibleDigits &digits, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return digits; - } - if (!fRoundingIncrement.isZero()) { - // If we have round increment, use digit list. - DigitList digitList; - digitList.set(value); - return initVisibleDigits(digitList, digits, status); - } - // Try fast path - if (initVisibleDigits(value, 0, digits, status)) { - digits.fAbsDoubleValue = fabs((double) value); - digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits(); - return digits; - } - // Oops have to use digit list - DigitList digitList; - digitList.set(value); - return initVisibleDigits(digitList, digits, status); -} - -VisibleDigits & -FixedPrecision::initVisibleDigits( - double value, - VisibleDigits &digits, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return digits; - } - digits.clear(); - if (uprv_isNaN(value)) { - digits.setNaN(); - return digits; - } - if (uprv_isPositiveInfinity(value)) { - digits.setInfinite(); - return digits; - } - if (uprv_isNegativeInfinity(value)) { - digits.setInfinite(); - digits.setNegative(); - return digits; - } - if (!fRoundingIncrement.isZero()) { - // If we have round increment, use digit list. - DigitList digitList; - digitList.set(value); - return initVisibleDigits(digitList, digits, status); - } - // Try to find n such that value * 10^n is an integer - int32_t n = -1; - double scaled; - for (int32_t i = 0; i < UPRV_LENGTHOF(gPower10); ++i) { - scaled = value * gPower10[i]; - if (scaled > MAX_INT64_IN_DOUBLE || scaled < -MAX_INT64_IN_DOUBLE) { - break; - } - if (scaled == floor(scaled)) { - n = i; - break; - } - } - // Try fast path - if (n >= 0 && initVisibleDigits(static_cast(scaled), -n, digits, status)) { - digits.fAbsDoubleValue = fabs(value); - digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits(); - // Adjust for negative 0 because when we cast to an int64, - // negative 0 becomes positive 0. - if (scaled == 0.0 && uprv_isNegative(scaled)) { - digits.setNegative(); - } - return digits; - } - - // Oops have to use digit list - DigitList digitList; - digitList.set(value); - return initVisibleDigits(digitList, digits, status); -} - -UBool -FixedPrecision::initVisibleDigits( - int64_t mantissa, - int32_t exponent, - VisibleDigits &digits, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return TRUE; - } - digits.clear(); - - // Precompute fAbsIntValue if it is small enough, but we don't know yet - // if it will be valid. - UBool absIntValueComputed = FALSE; - if (mantissa > -1000000000000000000LL /* -1e18 */ - && mantissa < 1000000000000000000LL /* 1e18 */) { - digits.fAbsIntValue = mantissa; - if (digits.fAbsIntValue < 0) { - digits.fAbsIntValue = -digits.fAbsIntValue; - } - int32_t i = 0; - int32_t maxPower10Exp = UPRV_LENGTHOF(gPower10) - 1; - for (; i > exponent + maxPower10Exp; i -= maxPower10Exp) { - digits.fAbsIntValue /= gPower10[maxPower10Exp]; - } - digits.fAbsIntValue /= gPower10[i - exponent]; - absIntValueComputed = TRUE; - } - if (mantissa == 0) { - getIntervalForZero(digits.fInterval); - digits.fAbsIntValueSet = absIntValueComputed; - return TRUE; - } - // be sure least significant digit is non zero - while (mantissa % 10 == 0) { - mantissa /= 10; - ++exponent; - } - if (mantissa < 0) { - digits.fDigits.append((char) -(mantissa % -10), status); - mantissa /= -10; - digits.setNegative(); - } - while (mantissa) { - digits.fDigits.append((char) (mantissa % 10), status); - mantissa /= 10; - } - if (U_FAILURE(status)) { - return TRUE; - } - digits.fExponent = exponent; - int32_t upperExponent = exponent + digits.fDigits.length(); - if (fFailIfOverMax && upperExponent > fMax.getIntDigitCount()) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return TRUE; - } - UBool roundingRequired = - isRoundingRequired(upperExponent, exponent); - if (roundingRequired) { - if (fExactOnly) { - status = U_FORMAT_INEXACT_ERROR; - return TRUE; - } - return FALSE; - } - digits.fInterval.setLeastSignificantInclusive(exponent); - digits.fInterval.setMostSignificantExclusive(upperExponent); - getInterval(upperExponent, digits.fInterval); - - // The intValue we computed above is only valid if our visible digits - // doesn't exceed the maximum integer digits allowed. - digits.fAbsIntValueSet = absIntValueComputed && !digits.isOverMaxDigits(); - return TRUE; -} - -VisibleDigitsWithExponent & -FixedPrecision::initVisibleDigitsWithExponent( - DigitList &value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - digits.clear(); - initVisibleDigits(value, digits.fMantissa, status); - return digits; -} - -VisibleDigitsWithExponent & -FixedPrecision::initVisibleDigitsWithExponent( - double value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - digits.clear(); - initVisibleDigits(value, digits.fMantissa, status); - return digits; -} - -VisibleDigitsWithExponent & -FixedPrecision::initVisibleDigitsWithExponent( - int64_t value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - digits.clear(); - initVisibleDigits(value, digits.fMantissa, status); - return digits; -} - -ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) { -} - -DigitList & -ScientificPrecision::round(DigitList &value, UErrorCode &status) const { - if (U_FAILURE(status)) { - return value; - } - int32_t exponent = value.getScientificExponent( - fMantissa.fMin.getIntDigitCount(), getMultiplier()); - return fMantissa.round(value, exponent, status); -} - -int32_t -ScientificPrecision::toScientific(DigitList &value) const { - return value.toScientific( - fMantissa.fMin.getIntDigitCount(), getMultiplier()); -} - -int32_t -ScientificPrecision::getMultiplier() const { - int32_t maxIntDigitCount = fMantissa.fMax.getIntDigitCount(); - if (maxIntDigitCount == INT32_MAX) { - return 1; - } - int32_t multiplier = - maxIntDigitCount - fMantissa.fMin.getIntDigitCount() + 1; - return (multiplier < 1 ? 1 : multiplier); -} - -VisibleDigitsWithExponent & -ScientificPrecision::initVisibleDigitsWithExponent( - DigitList &value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return digits; - } - digits.clear(); - if (FixedPrecision::handleNonNumeric(value, digits.fMantissa)) { - return digits; - } - value.setRoundingMode(fMantissa.fRoundingMode); - int64_t exponent = toScientific(round(value, status)); - fMantissa.initVisibleDigits(value, digits.fMantissa, status); - FixedPrecision exponentPrecision; - exponentPrecision.fMin.setIntDigitCount(fMinExponentDigits); - exponentPrecision.initVisibleDigits(exponent, digits.fExponent, status); - digits.fHasExponent = TRUE; - return digits; -} - -VisibleDigitsWithExponent & -ScientificPrecision::initVisibleDigitsWithExponent( - double value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return digits; - } - DigitList digitList; - digitList.set(value); - return initVisibleDigitsWithExponent(digitList, digits, status); -} - -VisibleDigitsWithExponent & -ScientificPrecision::initVisibleDigitsWithExponent( - int64_t value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - if (U_FAILURE(status)) { - return digits; - } - DigitList digitList; - digitList.set(value); - return initVisibleDigitsWithExponent(digitList, digits, status); -} - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/precision.h b/deps/icu-small/source/i18n/precision.h deleted file mode 100644 index 0598fa17d6..0000000000 --- a/deps/icu-small/source/i18n/precision.h +++ /dev/null @@ -1,323 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* precision.h -* -* created on: 2015jan06 -* created by: Travis Keep -*/ - -#ifndef __PRECISION_H__ -#define __PRECISION_H__ - -#include "unicode/uobject.h" - -#if !UCONFIG_NO_FORMATTING -#include "unicode/utypes.h" - -#include "digitinterval.h" -#include "digitlst.h" -#include "significantdigitinterval.h" - -U_NAMESPACE_BEGIN - -class VisibleDigits; -class VisibleDigitsWithExponent; - - -/** - * A precision manager for values to be formatted as fixed point. - * Handles rounding of number to prepare it for formatting. - */ -class U_I18N_API FixedPrecision : public UMemory { -public: - - /** - * The smallest format interval allowed. Default is 1 integer digit and no - * fraction digits. - */ - DigitInterval fMin; - - /** - * The largest format interval allowed. Must contain fMin. - * Default is all digits. - */ - DigitInterval fMax; - - /** - * Min and max significant digits allowed. The default is no constraints. - */ - SignificantDigitInterval fSignificant; - - /** - * The rounding increment or zero if there is no rounding increment. - * Default is zero. - */ - DigitList fRoundingIncrement; - - /** - * If set, causes round() to set status to U_FORMAT_INEXACT_ERROR if - * any rounding is done. Default is FALSE. - */ - UBool fExactOnly; - - /** - * If set, causes round() to set status to U_ILLEGAL_ARGUMENT_ERROR if - * rounded number has more than maximum integer digits. Default is FALSE. - */ - UBool fFailIfOverMax; - - /** - * Controls the rounding mode that initVisibleDigits uses. - * Default is DecimalFormat::kRoundHalfEven - */ - DecimalFormat::ERoundingMode fRoundingMode; - - FixedPrecision(); - - /** - * Returns TRUE if this object equals rhs. - */ - UBool equals(const FixedPrecision &rhs) const { - return (fMin.equals(rhs.fMin) && - fMax.equals(rhs.fMax) && - fSignificant.equals(rhs.fSignificant) && - (fRoundingIncrement == rhs.fRoundingIncrement) && - fExactOnly == rhs.fExactOnly && - fFailIfOverMax == rhs.fFailIfOverMax && - fRoundingMode == rhs.fRoundingMode); - } - - /** - * Rounds value in place to prepare it for formatting. - * @param value The value to be rounded. It is rounded in place. - * @param exponent Always pass 0 for fixed decimal formatting. scientific - * precision passes the exponent value. Essentially, it divides value by - * 10^exponent, rounds and then multiplies by 10^exponent. - * @param status error returned here. - * @return reference to value. - */ - DigitList &round(DigitList &value, int32_t exponent, UErrorCode &status) const; - - /** - * Returns the interval to use to format the rounded value. - * @param roundedValue the already rounded value to format. - * @param interval modified in place to be the interval to use to format - * the rounded value. - * @return a reference to interval. - */ - DigitInterval &getInterval( - const DigitList &roundedValue, DigitInterval &interval) const; - - /** - * Returns TRUE if this instance allows for fast formatting of integers. - */ - UBool isFastFormattable() const; - - /** - * Initializes a VisibleDigits. - * @param value value for VisibleDigits - * Caller must not assume that the value of this parameter will remain - * unchanged. - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigits &initVisibleDigits( - DigitList &value, - VisibleDigits &digits, - UErrorCode &status) const; - - /** - * Initializes a VisibleDigits. - * @param value value for VisibleDigits - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigits &initVisibleDigits( - double value, - VisibleDigits &digits, - UErrorCode &status) const; - - /** - * Initializes a VisibleDigits. - * @param value value for VisibleDigits - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigits &initVisibleDigits( - int64_t value, - VisibleDigits &digits, - UErrorCode &status) const; - - /** - * Initializes a VisibleDigitsWithExponent. - * @param value value for VisibleDigits - * Caller must not assume that the value of this parameter will remain - * unchanged. - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - DigitList &value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - - /** - * Initializes a VisibleDigitsWithExponent. - * @param value value for VisibleDigits - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - double value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - - /** - * Initializes a VisibleDigitsWithExponent. - * @param value value for VisibleDigits - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - int64_t value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - -private: - /** - * Attempts to initialize 'digits' using simple mod 10 arithmetic. - * Returns FALSE if this is not possible such as when rounding - * would change the value. Otherwise returns TRUE. - * - * If the method returns FALSE, caller should create a DigitList - * and use it to initialize 'digits'. If this method returns TRUE, - * caller should accept the value stored in 'digits'. If this - * method returns TRUE along with a non zero error, caller must accept - * the error and not try again with a DigitList. - * - * Before calling this method, caller must verify that this object - * has no rounding increment set. - * - * The value that 'digits' is initialized to is mantissa * 10^exponent. - * For example mantissa = 54700 and exponent = -3 means 54.7. The - * properties of this object (such as min and max fraction digits), - * not the number of trailing zeros in the mantissa, determine whether or - * not the result contains any trailing 0's after the decimal point. - * - * @param mantissa the digits. May be positive or negative. May contain - * trailing zeros. - * @param exponent must always be zero or negative. An exponent > 0 - * yields undefined results! - * @param digits result stored here. - * @param status any error returned here. - */ - UBool - initVisibleDigits( - int64_t mantissa, - int32_t exponent, - VisibleDigits &digits, - UErrorCode &status) const; - UBool isRoundingRequired( - int32_t upperExponent, int32_t lowerExponent) const; - DigitInterval &getIntervalForZero(DigitInterval &interval) const; - DigitInterval &getInterval( - int32_t upperExponent, DigitInterval &interval) const; - static UBool handleNonNumeric(DigitList &value, VisibleDigits &digits); - - friend class ScientificPrecision; -}; - -/** - * A precision manager for values to be expressed as scientific notation. - */ -class U_I18N_API ScientificPrecision : public UMemory { -public: - FixedPrecision fMantissa; - int32_t fMinExponentDigits; - - ScientificPrecision(); - - /** - * rounds value in place to prepare it for formatting. - * @param value The value to be rounded. It is rounded in place. - * @param status error returned here. - * @return reference to value. - */ - DigitList &round(DigitList &value, UErrorCode &status) const; - - /** - * Converts value to a mantissa and exponent. - * - * @param value modified in place to be the mantissa. Depending on - * the precision settings, the resulting mantissa may not fall - * between 1.0 and 10.0. - * @return the exponent of value. - */ - int32_t toScientific(DigitList &value) const; - - /** - * Returns TRUE if this object equals rhs. - */ - UBool equals(const ScientificPrecision &rhs) const { - return fMantissa.equals(rhs.fMantissa) && fMinExponentDigits == rhs.fMinExponentDigits; - } - - /** - * Initializes a VisibleDigitsWithExponent. - * @param value the value - * Caller must not assume that the value of this parameter will remain - * unchanged. - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - DigitList &value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - - /** - * Initializes a VisibleDigitsWithExponent. - * @param value the value - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - double value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - - /** - * Initializes a VisibleDigitsWithExponent. - * @param value the value - * @param digits This is the value that is initialized. - * @param status any error returned here. - * @return digits - */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - int64_t value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - -private: - int32_t getMultiplier() const; - -}; - - - -U_NAMESPACE_END -#endif // #if !UCONFIG_NO_FORMATTING -#endif // __PRECISION_H__ diff --git a/deps/icu-small/source/i18n/quantityformatter.cpp b/deps/icu-small/source/i18n/quantityformatter.cpp index 208e064700..ba06ba06b9 100644 --- a/deps/icu-small/source/i18n/quantityformatter.cpp +++ b/deps/icu-small/source/i18n/quantityformatter.cpp @@ -23,8 +23,8 @@ #include "unicode/fmtable.h" #include "unicode/fieldpos.h" #include "standardplural.h" -#include "visibledigits.h" #include "uassert.h" +#include "number_decimalquantity.h" U_NAMESPACE_BEGIN @@ -149,15 +149,15 @@ StandardPlural::Form QuantityFormatter::selectPlural( return StandardPlural::OTHER; } UnicodeString pluralKeyword; - VisibleDigitsWithExponent digits; const DecimalFormat *decFmt = dynamic_cast(&fmt); if (decFmt != NULL) { - decFmt->initVisibleDigitsWithExponent(number, digits, status); + number::impl::DecimalQuantity dq; + decFmt->formatToDecimalQuantity(number, dq, status); if (U_FAILURE(status)) { return StandardPlural::OTHER; } - pluralKeyword = rules.select(digits); - decFmt->format(digits, formattedNumber, pos, status); + pluralKeyword = rules.select(dq); + decFmt->format(number, formattedNumber, pos, status); } else { if (number.getType() == Formattable::kDouble) { pluralKeyword = rules.select(number.getDouble()); diff --git a/deps/icu-small/source/i18n/rbnf.cpp b/deps/icu-small/source/i18n/rbnf.cpp index 3385f300b1..ab9ad15e8c 100644 --- a/deps/icu-small/source/i18n/rbnf.cpp +++ b/deps/icu-small/source/i18n/rbnf.cpp @@ -34,7 +34,7 @@ #include "patternprops.h" #include "uresimp.h" #include "nfrs.h" -#include "digitlst.h" +#include "number_decimalquantity.h" // debugging // #define RBNF_DEBUG @@ -68,6 +68,8 @@ static const UChar gSemiPercent[] = U_NAMESPACE_BEGIN +using number::impl::DecimalQuantity; + UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedNumberFormat) /* @@ -1109,21 +1111,21 @@ RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status } UnicodeString& -RuleBasedNumberFormat::format(const DigitList &number, +RuleBasedNumberFormat::format(const DecimalQuantity &number, UnicodeString &appendTo, FieldPositionIterator *posIter, UErrorCode &status) const { if (U_FAILURE(status)) { return appendTo; } - DigitList copy(number); - if (copy.fitsIntoInt64(false)) { - format(((DigitList &)number).getInt64(), appendTo, posIter, status); + DecimalQuantity copy(number); + if (copy.fitsInLong()) { + format(number.toLong(), appendTo, posIter, status); } else { - copy.roundAtExponent(0); - if (copy.fitsIntoInt64(false)) { - format(number.getDouble(), appendTo, posIter, status); + copy.roundToMagnitude(0, number::impl::RoundingMode::UNUM_ROUND_HALFEVEN, status); + if (copy.fitsInLong()) { + format(number.toDouble(), appendTo, posIter, status); } else { // We're outside of our normal range that this framework can handle. @@ -1132,7 +1134,7 @@ RuleBasedNumberFormat::format(const DigitList &number, // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J. NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); Formattable f; - f.adoptDigitList(new DigitList(number)); + f.adoptDecimalQuantity(new DecimalQuantity(number)); decimalFormat->format(f, appendTo, posIter, status); delete decimalFormat; } @@ -1142,21 +1144,21 @@ RuleBasedNumberFormat::format(const DigitList &number, UnicodeString& -RuleBasedNumberFormat::format(const DigitList &number, +RuleBasedNumberFormat::format(const DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode &status) const { if (U_FAILURE(status)) { return appendTo; } - DigitList copy(number); - if (copy.fitsIntoInt64(false)) { - format(((DigitList &)number).getInt64(), appendTo, pos, status); + DecimalQuantity copy(number); + if (copy.fitsInLong()) { + format(number.toLong(), appendTo, pos, status); } else { - copy.roundAtExponent(0); - if (copy.fitsIntoInt64(false)) { - format(number.getDouble(), appendTo, pos, status); + copy.roundToMagnitude(0, number::impl::RoundingMode::UNUM_ROUND_HALFEVEN, status); + if (copy.fitsInLong()) { + format(number.toDouble(), appendTo, pos, status); } else { // We're outside of our normal range that this framework can handle. @@ -1165,7 +1167,7 @@ RuleBasedNumberFormat::format(const DigitList &number, // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J. NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); Formattable f; - f.adoptDigitList(new DigitList(number)); + f.adoptDecimalQuantity(new DecimalQuantity(number)); decimalFormat->format(f, appendTo, pos, status); delete decimalFormat; } @@ -1270,11 +1272,13 @@ RuleBasedNumberFormat::format(double number, { int32_t startPos = toAppendTo.length(); if (getRoundingMode() != DecimalFormat::ERoundingMode::kRoundUnnecessary && !uprv_isNaN(number) && !uprv_isInfinite(number)) { - DigitList digitList; - digitList.set(number); - digitList.setRoundingMode(getRoundingMode()); - digitList.roundFixedPoint(getMaximumFractionDigits()); - number = digitList.getDouble(); + DecimalQuantity digitList; + digitList.setToDouble(number); + digitList.roundToMagnitude( + -getMaximumFractionDigits(), + static_cast(getRoundingMode()), + status); + number = digitList.toDouble(); } rs.format(number, toAppendTo, toAppendTo.length(), 0, status); adjustForCapitalizationContext(startPos, toAppendTo, status); @@ -1310,9 +1314,9 @@ RuleBasedNumberFormat::format(int64_t number, NFRuleSet *ruleSet, UnicodeString& NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); Formattable f; FieldPosition pos(FieldPosition::DONT_CARE); - DigitList *digitList = new DigitList(); - digitList->set(number); - f.adoptDigitList(digitList); + DecimalQuantity *digitList = new DecimalQuantity(); + digitList->setToLong(number); + f.adoptDecimalQuantity(digitList); decimalFormat->format(f, toAppendTo, pos, status); delete decimalFormat; } diff --git a/deps/icu-small/source/i18n/reldatefmt.cpp b/deps/icu-small/source/i18n/reldatefmt.cpp index 5cf053db9a..42ede7ae4d 100644 --- a/deps/icu-small/source/i18n/reldatefmt.cpp +++ b/deps/icu-small/source/i18n/reldatefmt.cpp @@ -14,6 +14,7 @@ #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION +#include #include "unicode/dtfmtsym.h" #include "unicode/ucasemap.h" #include "unicode/ureldatefmt.h" @@ -849,7 +850,7 @@ UnicodeString& RelativeDateTimeFormatter::formatNumeric( return appendTo; } UDateDirection direction = UDAT_DIRECTION_NEXT; - if (offset < 0) { + if (std::signbit(offset)) { // needed to handle -0.0 direction = UDAT_DIRECTION_LAST; offset = -offset; } diff --git a/deps/icu-small/source/i18n/scientificnumberformatter.cpp b/deps/icu-small/source/i18n/scientificnumberformatter.cpp index adf032d989..03d98dd6e1 100644 --- a/deps/icu-small/source/i18n/scientificnumberformatter.cpp +++ b/deps/icu-small/source/i18n/scientificnumberformatter.cpp @@ -15,8 +15,8 @@ #include "unicode/fpositer.h" #include "unicode/utf16.h" #include "unicode/uniset.h" -#include "decfmtst.h" #include "unicode/decimfmt.h" +#include "static_unicode_sets.h" U_NAMESPACE_BEGIN @@ -129,7 +129,6 @@ UnicodeString &ScientificNumberFormatter::SuperscriptStyle::format( const UnicodeString &original, FieldPositionIterator &fpi, const UnicodeString &preExponent, - const DecimalFormatStaticSets &staticSets, UnicodeString &appendTo, UErrorCode &status) const { if (U_FAILURE(status)) { @@ -149,16 +148,17 @@ UnicodeString &ScientificNumberFormatter::SuperscriptStyle::format( break; case UNUM_EXPONENT_SIGN_FIELD: { + using namespace icu::numparse::impl; int32_t beginIndex = fp.getBeginIndex(); int32_t endIndex = fp.getEndIndex(); UChar32 aChar = original.char32At(beginIndex); - if (staticSets.fMinusSigns->contains(aChar)) { + if (unisets::get(unisets::MINUS_SIGN)->contains(aChar)) { appendTo.append( original, copyFromOffset, beginIndex - copyFromOffset); appendTo.append(kSuperscriptMinusSign); - } else if (staticSets.fPlusSigns->contains(aChar)) { + } else if (unisets::get(unisets::PLUS_SIGN)->contains(aChar)) { appendTo.append( original, copyFromOffset, @@ -203,7 +203,6 @@ UnicodeString &ScientificNumberFormatter::MarkupStyle::format( const UnicodeString &original, FieldPositionIterator &fpi, const UnicodeString &preExponent, - const DecimalFormatStaticSets & /*unusedDecimalFormatSets*/, UnicodeString &appendTo, UErrorCode &status) const { if (U_FAILURE(status)) { @@ -243,8 +242,7 @@ ScientificNumberFormatter::ScientificNumberFormatter( DecimalFormat *fmtToAdopt, Style *styleToAdopt, UErrorCode &status) : fPreExponent(), fDecimalFormat(fmtToAdopt), - fStyle(styleToAdopt), - fStaticSets(NULL) { + fStyle(styleToAdopt) { if (U_FAILURE(status)) { return; } @@ -258,7 +256,6 @@ ScientificNumberFormatter::ScientificNumberFormatter( return; } getPreExponent(*sym, fPreExponent); - fStaticSets = DecimalFormatStaticSets::getStaticSets(status); } ScientificNumberFormatter::ScientificNumberFormatter( @@ -266,8 +263,7 @@ ScientificNumberFormatter::ScientificNumberFormatter( : UObject(other), fPreExponent(other.fPreExponent), fDecimalFormat(NULL), - fStyle(NULL), - fStaticSets(other.fStaticSets) { + fStyle(NULL) { fDecimalFormat = static_cast( other.fDecimalFormat->clone()); fStyle = other.fStyle->clone(); @@ -292,7 +288,6 @@ UnicodeString &ScientificNumberFormatter::format( original, fpi, fPreExponent, - *fStaticSets, appendTo, status); } diff --git a/deps/icu-small/source/i18n/significantdigitinterval.h b/deps/icu-small/source/i18n/significantdigitinterval.h deleted file mode 100644 index fc23370de5..0000000000 --- a/deps/icu-small/source/i18n/significantdigitinterval.h +++ /dev/null @@ -1,92 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* significantdigitinterval.h -* -* created on: 2015jan6 -* created by: Travis Keep -*/ - -#ifndef __SIGNIFICANTDIGITINTERVAL_H__ -#define __SIGNIFICANTDIGITINTERVAL_H__ - -#include "unicode/uobject.h" -#include "unicode/utypes.h" - -U_NAMESPACE_BEGIN - -/** - * An interval of allowed significant digit counts. - */ -class U_I18N_API SignificantDigitInterval : public UMemory { -public: - - /** - * No limits on significant digits. - */ - SignificantDigitInterval() - : fMax(INT32_MAX), fMin(0) { } - - /** - * Make this instance have no limit on significant digits. - */ - void clear() { - fMin = 0; - fMax = INT32_MAX; - } - - /** - * Returns TRUE if this object is equal to rhs. - */ - UBool equals(const SignificantDigitInterval &rhs) const { - return ((fMax == rhs.fMax) && (fMin == rhs.fMin)); - } - - /** - * Sets maximum significant digits. 0 or negative means no maximum. - */ - void setMax(int32_t count) { - fMax = count <= 0 ? INT32_MAX : count; - } - - /** - * Get maximum significant digits. INT32_MAX means no maximum. - */ - int32_t getMax() const { - return fMax; - } - - /** - * Sets minimum significant digits. 0 or negative means no minimum. - */ - void setMin(int32_t count) { - fMin = count <= 0 ? 0 : count; - } - - /** - * Get maximum significant digits. 0 means no minimum. - */ - int32_t getMin() const { - return fMin; - } - - /** - * Returns TRUE if this instance represents no constraints on significant - * digits. - */ - UBool isNoConstraints() const { - return fMin == 0 && fMax == INT32_MAX; - } - -private: - int32_t fMax; - int32_t fMin; -}; - -U_NAMESPACE_END - -#endif // __SIGNIFICANTDIGITINTERVAL_H__ diff --git a/deps/icu-small/source/i18n/smallintformatter.cpp b/deps/icu-small/source/i18n/smallintformatter.cpp deleted file mode 100644 index 0c56e38bd6..0000000000 --- a/deps/icu-small/source/i18n/smallintformatter.cpp +++ /dev/null @@ -1,2622 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2015, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: smallintformatter.cpp - */ - -#include "unicode/unistr.h" - -#include "smallintformatter.h" - -static const int32_t gMaxFastInt = 4096; - -static const UChar gDigits[] = { - 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x31, - 0x30,0x30,0x30,0x32,0x30,0x30,0x30,0x33, - 0x30,0x30,0x30,0x34,0x30,0x30,0x30,0x35, - 0x30,0x30,0x30,0x36,0x30,0x30,0x30,0x37, - 0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x39, - 0x30,0x30,0x31,0x30,0x30,0x30,0x31,0x31, - 0x30,0x30,0x31,0x32,0x30,0x30,0x31,0x33, - 0x30,0x30,0x31,0x34,0x30,0x30,0x31,0x35, - 0x30,0x30,0x31,0x36,0x30,0x30,0x31,0x37, - 0x30,0x30,0x31,0x38,0x30,0x30,0x31,0x39, - 0x30,0x30,0x32,0x30,0x30,0x30,0x32,0x31, - 0x30,0x30,0x32,0x32,0x30,0x30,0x32,0x33, - 0x30,0x30,0x32,0x34,0x30,0x30,0x32,0x35, - 0x30,0x30,0x32,0x36,0x30,0x30,0x32,0x37, - 0x30,0x30,0x32,0x38,0x30,0x30,0x32,0x39, - 0x30,0x30,0x33,0x30,0x30,0x30,0x33,0x31, - 0x30,0x30,0x33,0x32,0x30,0x30,0x33,0x33, - 0x30,0x30,0x33,0x34,0x30,0x30,0x33,0x35, - 0x30,0x30,0x33,0x36,0x30,0x30,0x33,0x37, - 0x30,0x30,0x33,0x38,0x30,0x30,0x33,0x39, - 0x30,0x30,0x34,0x30,0x30,0x30,0x34,0x31, - 0x30,0x30,0x34,0x32,0x30,0x30,0x34,0x33, - 0x30,0x30,0x34,0x34,0x30,0x30,0x34,0x35, - 0x30,0x30,0x34,0x36,0x30,0x30,0x34,0x37, - 0x30,0x30,0x34,0x38,0x30,0x30,0x34,0x39, - 0x30,0x30,0x35,0x30,0x30,0x30,0x35,0x31, - 0x30,0x30,0x35,0x32,0x30,0x30,0x35,0x33, - 0x30,0x30,0x35,0x34,0x30,0x30,0x35,0x35, - 0x30,0x30,0x35,0x36,0x30,0x30,0x35,0x37, - 0x30,0x30,0x35,0x38,0x30,0x30,0x35,0x39, - 0x30,0x30,0x36,0x30,0x30,0x30,0x36,0x31, - 0x30,0x30,0x36,0x32,0x30,0x30,0x36,0x33, - 0x30,0x30,0x36,0x34,0x30,0x30,0x36,0x35, - 0x30,0x30,0x36,0x36,0x30,0x30,0x36,0x37, - 0x30,0x30,0x36,0x38,0x30,0x30,0x36,0x39, - 0x30,0x30,0x37,0x30,0x30,0x30,0x37,0x31, - 0x30,0x30,0x37,0x32,0x30,0x30,0x37,0x33, - 0x30,0x30,0x37,0x34,0x30,0x30,0x37,0x35, - 0x30,0x30,0x37,0x36,0x30,0x30,0x37,0x37, - 0x30,0x30,0x37,0x38,0x30,0x30,0x37,0x39, - 0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x31, - 0x30,0x30,0x38,0x32,0x30,0x30,0x38,0x33, - 0x30,0x30,0x38,0x34,0x30,0x30,0x38,0x35, - 0x30,0x30,0x38,0x36,0x30,0x30,0x38,0x37, - 0x30,0x30,0x38,0x38,0x30,0x30,0x38,0x39, - 0x30,0x30,0x39,0x30,0x30,0x30,0x39,0x31, - 0x30,0x30,0x39,0x32,0x30,0x30,0x39,0x33, - 0x30,0x30,0x39,0x34,0x30,0x30,0x39,0x35, - 0x30,0x30,0x39,0x36,0x30,0x30,0x39,0x37, - 0x30,0x30,0x39,0x38,0x30,0x30,0x39,0x39, - 0x30,0x31,0x30,0x30,0x30,0x31,0x30,0x31, - 0x30,0x31,0x30,0x32,0x30,0x31,0x30,0x33, - 0x30,0x31,0x30,0x34,0x30,0x31,0x30,0x35, - 0x30,0x31,0x30,0x36,0x30,0x31,0x30,0x37, - 0x30,0x31,0x30,0x38,0x30,0x31,0x30,0x39, - 0x30,0x31,0x31,0x30,0x30,0x31,0x31,0x31, - 0x30,0x31,0x31,0x32,0x30,0x31,0x31,0x33, - 0x30,0x31,0x31,0x34,0x30,0x31,0x31,0x35, - 0x30,0x31,0x31,0x36,0x30,0x31,0x31,0x37, - 0x30,0x31,0x31,0x38,0x30,0x31,0x31,0x39, - 0x30,0x31,0x32,0x30,0x30,0x31,0x32,0x31, - 0x30,0x31,0x32,0x32,0x30,0x31,0x32,0x33, - 0x30,0x31,0x32,0x34,0x30,0x31,0x32,0x35, - 0x30,0x31,0x32,0x36,0x30,0x31,0x32,0x37, - 0x30,0x31,0x32,0x38,0x30,0x31,0x32,0x39, - 0x30,0x31,0x33,0x30,0x30,0x31,0x33,0x31, - 0x30,0x31,0x33,0x32,0x30,0x31,0x33,0x33, - 0x30,0x31,0x33,0x34,0x30,0x31,0x33,0x35, - 0x30,0x31,0x33,0x36,0x30,0x31,0x33,0x37, - 0x30,0x31,0x33,0x38,0x30,0x31,0x33,0x39, - 0x30,0x31,0x34,0x30,0x30,0x31,0x34,0x31, - 0x30,0x31,0x34,0x32,0x30,0x31,0x34,0x33, - 0x30,0x31,0x34,0x34,0x30,0x31,0x34,0x35, - 0x30,0x31,0x34,0x36,0x30,0x31,0x34,0x37, - 0x30,0x31,0x34,0x38,0x30,0x31,0x34,0x39, - 0x30,0x31,0x35,0x30,0x30,0x31,0x35,0x31, - 0x30,0x31,0x35,0x32,0x30,0x31,0x35,0x33, - 0x30,0x31,0x35,0x34,0x30,0x31,0x35,0x35, - 0x30,0x31,0x35,0x36,0x30,0x31,0x35,0x37, - 0x30,0x31,0x35,0x38,0x30,0x31,0x35,0x39, - 0x30,0x31,0x36,0x30,0x30,0x31,0x36,0x31, - 0x30,0x31,0x36,0x32,0x30,0x31,0x36,0x33, - 0x30,0x31,0x36,0x34,0x30,0x31,0x36,0x35, - 0x30,0x31,0x36,0x36,0x30,0x31,0x36,0x37, - 0x30,0x31,0x36,0x38,0x30,0x31,0x36,0x39, - 0x30,0x31,0x37,0x30,0x30,0x31,0x37,0x31, - 0x30,0x31,0x37,0x32,0x30,0x31,0x37,0x33, - 0x30,0x31,0x37,0x34,0x30,0x31,0x37,0x35, - 0x30,0x31,0x37,0x36,0x30,0x31,0x37,0x37, - 0x30,0x31,0x37,0x38,0x30,0x31,0x37,0x39, - 0x30,0x31,0x38,0x30,0x30,0x31,0x38,0x31, - 0x30,0x31,0x38,0x32,0x30,0x31,0x38,0x33, - 0x30,0x31,0x38,0x34,0x30,0x31,0x38,0x35, - 0x30,0x31,0x38,0x36,0x30,0x31,0x38,0x37, - 0x30,0x31,0x38,0x38,0x30,0x31,0x38,0x39, - 0x30,0x31,0x39,0x30,0x30,0x31,0x39,0x31, - 0x30,0x31,0x39,0x32,0x30,0x31,0x39,0x33, - 0x30,0x31,0x39,0x34,0x30,0x31,0x39,0x35, - 0x30,0x31,0x39,0x36,0x30,0x31,0x39,0x37, - 0x30,0x31,0x39,0x38,0x30,0x31,0x39,0x39, - 0x30,0x32,0x30,0x30,0x30,0x32,0x30,0x31, - 0x30,0x32,0x30,0x32,0x30,0x32,0x30,0x33, - 0x30,0x32,0x30,0x34,0x30,0x32,0x30,0x35, - 0x30,0x32,0x30,0x36,0x30,0x32,0x30,0x37, - 0x30,0x32,0x30,0x38,0x30,0x32,0x30,0x39, - 0x30,0x32,0x31,0x30,0x30,0x32,0x31,0x31, - 0x30,0x32,0x31,0x32,0x30,0x32,0x31,0x33, - 0x30,0x32,0x31,0x34,0x30,0x32,0x31,0x35, - 0x30,0x32,0x31,0x36,0x30,0x32,0x31,0x37, - 0x30,0x32,0x31,0x38,0x30,0x32,0x31,0x39, - 0x30,0x32,0x32,0x30,0x30,0x32,0x32,0x31, - 0x30,0x32,0x32,0x32,0x30,0x32,0x32,0x33, - 0x30,0x32,0x32,0x34,0x30,0x32,0x32,0x35, - 0x30,0x32,0x32,0x36,0x30,0x32,0x32,0x37, - 0x30,0x32,0x32,0x38,0x30,0x32,0x32,0x39, - 0x30,0x32,0x33,0x30,0x30,0x32,0x33,0x31, - 0x30,0x32,0x33,0x32,0x30,0x32,0x33,0x33, - 0x30,0x32,0x33,0x34,0x30,0x32,0x33,0x35, - 0x30,0x32,0x33,0x36,0x30,0x32,0x33,0x37, - 0x30,0x32,0x33,0x38,0x30,0x32,0x33,0x39, - 0x30,0x32,0x34,0x30,0x30,0x32,0x34,0x31, - 0x30,0x32,0x34,0x32,0x30,0x32,0x34,0x33, - 0x30,0x32,0x34,0x34,0x30,0x32,0x34,0x35, - 0x30,0x32,0x34,0x36,0x30,0x32,0x34,0x37, - 0x30,0x32,0x34,0x38,0x30,0x32,0x34,0x39, - 0x30,0x32,0x35,0x30,0x30,0x32,0x35,0x31, - 0x30,0x32,0x35,0x32,0x30,0x32,0x35,0x33, - 0x30,0x32,0x35,0x34,0x30,0x32,0x35,0x35, - 0x30,0x32,0x35,0x36,0x30,0x32,0x35,0x37, - 0x30,0x32,0x35,0x38,0x30,0x32,0x35,0x39, - 0x30,0x32,0x36,0x30,0x30,0x32,0x36,0x31, - 0x30,0x32,0x36,0x32,0x30,0x32,0x36,0x33, - 0x30,0x32,0x36,0x34,0x30,0x32,0x36,0x35, - 0x30,0x32,0x36,0x36,0x30,0x32,0x36,0x37, - 0x30,0x32,0x36,0x38,0x30,0x32,0x36,0x39, - 0x30,0x32,0x37,0x30,0x30,0x32,0x37,0x31, - 0x30,0x32,0x37,0x32,0x30,0x32,0x37,0x33, - 0x30,0x32,0x37,0x34,0x30,0x32,0x37,0x35, - 0x30,0x32,0x37,0x36,0x30,0x32,0x37,0x37, - 0x30,0x32,0x37,0x38,0x30,0x32,0x37,0x39, - 0x30,0x32,0x38,0x30,0x30,0x32,0x38,0x31, - 0x30,0x32,0x38,0x32,0x30,0x32,0x38,0x33, - 0x30,0x32,0x38,0x34,0x30,0x32,0x38,0x35, - 0x30,0x32,0x38,0x36,0x30,0x32,0x38,0x37, - 0x30,0x32,0x38,0x38,0x30,0x32,0x38,0x39, - 0x30,0x32,0x39,0x30,0x30,0x32,0x39,0x31, - 0x30,0x32,0x39,0x32,0x30,0x32,0x39,0x33, - 0x30,0x32,0x39,0x34,0x30,0x32,0x39,0x35, - 0x30,0x32,0x39,0x36,0x30,0x32,0x39,0x37, - 0x30,0x32,0x39,0x38,0x30,0x32,0x39,0x39, - 0x30,0x33,0x30,0x30,0x30,0x33,0x30,0x31, - 0x30,0x33,0x30,0x32,0x30,0x33,0x30,0x33, - 0x30,0x33,0x30,0x34,0x30,0x33,0x30,0x35, - 0x30,0x33,0x30,0x36,0x30,0x33,0x30,0x37, - 0x30,0x33,0x30,0x38,0x30,0x33,0x30,0x39, - 0x30,0x33,0x31,0x30,0x30,0x33,0x31,0x31, - 0x30,0x33,0x31,0x32,0x30,0x33,0x31,0x33, - 0x30,0x33,0x31,0x34,0x30,0x33,0x31,0x35, - 0x30,0x33,0x31,0x36,0x30,0x33,0x31,0x37, - 0x30,0x33,0x31,0x38,0x30,0x33,0x31,0x39, - 0x30,0x33,0x32,0x30,0x30,0x33,0x32,0x31, - 0x30,0x33,0x32,0x32,0x30,0x33,0x32,0x33, - 0x30,0x33,0x32,0x34,0x30,0x33,0x32,0x35, - 0x30,0x33,0x32,0x36,0x30,0x33,0x32,0x37, - 0x30,0x33,0x32,0x38,0x30,0x33,0x32,0x39, - 0x30,0x33,0x33,0x30,0x30,0x33,0x33,0x31, - 0x30,0x33,0x33,0x32,0x30,0x33,0x33,0x33, - 0x30,0x33,0x33,0x34,0x30,0x33,0x33,0x35, - 0x30,0x33,0x33,0x36,0x30,0x33,0x33,0x37, - 0x30,0x33,0x33,0x38,0x30,0x33,0x33,0x39, - 0x30,0x33,0x34,0x30,0x30,0x33,0x34,0x31, - 0x30,0x33,0x34,0x32,0x30,0x33,0x34,0x33, - 0x30,0x33,0x34,0x34,0x30,0x33,0x34,0x35, - 0x30,0x33,0x34,0x36,0x30,0x33,0x34,0x37, - 0x30,0x33,0x34,0x38,0x30,0x33,0x34,0x39, - 0x30,0x33,0x35,0x30,0x30,0x33,0x35,0x31, - 0x30,0x33,0x35,0x32,0x30,0x33,0x35,0x33, - 0x30,0x33,0x35,0x34,0x30,0x33,0x35,0x35, - 0x30,0x33,0x35,0x36,0x30,0x33,0x35,0x37, - 0x30,0x33,0x35,0x38,0x30,0x33,0x35,0x39, - 0x30,0x33,0x36,0x30,0x30,0x33,0x36,0x31, - 0x30,0x33,0x36,0x32,0x30,0x33,0x36,0x33, - 0x30,0x33,0x36,0x34,0x30,0x33,0x36,0x35, - 0x30,0x33,0x36,0x36,0x30,0x33,0x36,0x37, - 0x30,0x33,0x36,0x38,0x30,0x33,0x36,0x39, - 0x30,0x33,0x37,0x30,0x30,0x33,0x37,0x31, - 0x30,0x33,0x37,0x32,0x30,0x33,0x37,0x33, - 0x30,0x33,0x37,0x34,0x30,0x33,0x37,0x35, - 0x30,0x33,0x37,0x36,0x30,0x33,0x37,0x37, - 0x30,0x33,0x37,0x38,0x30,0x33,0x37,0x39, - 0x30,0x33,0x38,0x30,0x30,0x33,0x38,0x31, - 0x30,0x33,0x38,0x32,0x30,0x33,0x38,0x33, - 0x30,0x33,0x38,0x34,0x30,0x33,0x38,0x35, - 0x30,0x33,0x38,0x36,0x30,0x33,0x38,0x37, - 0x30,0x33,0x38,0x38,0x30,0x33,0x38,0x39, - 0x30,0x33,0x39,0x30,0x30,0x33,0x39,0x31, - 0x30,0x33,0x39,0x32,0x30,0x33,0x39,0x33, - 0x30,0x33,0x39,0x34,0x30,0x33,0x39,0x35, - 0x30,0x33,0x39,0x36,0x30,0x33,0x39,0x37, - 0x30,0x33,0x39,0x38,0x30,0x33,0x39,0x39, - 0x30,0x34,0x30,0x30,0x30,0x34,0x30,0x31, - 0x30,0x34,0x30,0x32,0x30,0x34,0x30,0x33, - 0x30,0x34,0x30,0x34,0x30,0x34,0x30,0x35, - 0x30,0x34,0x30,0x36,0x30,0x34,0x30,0x37, - 0x30,0x34,0x30,0x38,0x30,0x34,0x30,0x39, - 0x30,0x34,0x31,0x30,0x30,0x34,0x31,0x31, - 0x30,0x34,0x31,0x32,0x30,0x34,0x31,0x33, - 0x30,0x34,0x31,0x34,0x30,0x34,0x31,0x35, - 0x30,0x34,0x31,0x36,0x30,0x34,0x31,0x37, - 0x30,0x34,0x31,0x38,0x30,0x34,0x31,0x39, - 0x30,0x34,0x32,0x30,0x30,0x34,0x32,0x31, - 0x30,0x34,0x32,0x32,0x30,0x34,0x32,0x33, - 0x30,0x34,0x32,0x34,0x30,0x34,0x32,0x35, - 0x30,0x34,0x32,0x36,0x30,0x34,0x32,0x37, - 0x30,0x34,0x32,0x38,0x30,0x34,0x32,0x39, - 0x30,0x34,0x33,0x30,0x30,0x34,0x33,0x31, - 0x30,0x34,0x33,0x32,0x30,0x34,0x33,0x33, - 0x30,0x34,0x33,0x34,0x30,0x34,0x33,0x35, - 0x30,0x34,0x33,0x36,0x30,0x34,0x33,0x37, - 0x30,0x34,0x33,0x38,0x30,0x34,0x33,0x39, - 0x30,0x34,0x34,0x30,0x30,0x34,0x34,0x31, - 0x30,0x34,0x34,0x32,0x30,0x34,0x34,0x33, - 0x30,0x34,0x34,0x34,0x30,0x34,0x34,0x35, - 0x30,0x34,0x34,0x36,0x30,0x34,0x34,0x37, - 0x30,0x34,0x34,0x38,0x30,0x34,0x34,0x39, - 0x30,0x34,0x35,0x30,0x30,0x34,0x35,0x31, - 0x30,0x34,0x35,0x32,0x30,0x34,0x35,0x33, - 0x30,0x34,0x35,0x34,0x30,0x34,0x35,0x35, - 0x30,0x34,0x35,0x36,0x30,0x34,0x35,0x37, - 0x30,0x34,0x35,0x38,0x30,0x34,0x35,0x39, - 0x30,0x34,0x36,0x30,0x30,0x34,0x36,0x31, - 0x30,0x34,0x36,0x32,0x30,0x34,0x36,0x33, - 0x30,0x34,0x36,0x34,0x30,0x34,0x36,0x35, - 0x30,0x34,0x36,0x36,0x30,0x34,0x36,0x37, - 0x30,0x34,0x36,0x38,0x30,0x34,0x36,0x39, - 0x30,0x34,0x37,0x30,0x30,0x34,0x37,0x31, - 0x30,0x34,0x37,0x32,0x30,0x34,0x37,0x33, - 0x30,0x34,0x37,0x34,0x30,0x34,0x37,0x35, - 0x30,0x34,0x37,0x36,0x30,0x34,0x37,0x37, - 0x30,0x34,0x37,0x38,0x30,0x34,0x37,0x39, - 0x30,0x34,0x38,0x30,0x30,0x34,0x38,0x31, - 0x30,0x34,0x38,0x32,0x30,0x34,0x38,0x33, - 0x30,0x34,0x38,0x34,0x30,0x34,0x38,0x35, - 0x30,0x34,0x38,0x36,0x30,0x34,0x38,0x37, - 0x30,0x34,0x38,0x38,0x30,0x34,0x38,0x39, - 0x30,0x34,0x39,0x30,0x30,0x34,0x39,0x31, - 0x30,0x34,0x39,0x32,0x30,0x34,0x39,0x33, - 0x30,0x34,0x39,0x34,0x30,0x34,0x39,0x35, - 0x30,0x34,0x39,0x36,0x30,0x34,0x39,0x37, - 0x30,0x34,0x39,0x38,0x30,0x34,0x39,0x39, - 0x30,0x35,0x30,0x30,0x30,0x35,0x30,0x31, - 0x30,0x35,0x30,0x32,0x30,0x35,0x30,0x33, - 0x30,0x35,0x30,0x34,0x30,0x35,0x30,0x35, - 0x30,0x35,0x30,0x36,0x30,0x35,0x30,0x37, - 0x30,0x35,0x30,0x38,0x30,0x35,0x30,0x39, - 0x30,0x35,0x31,0x30,0x30,0x35,0x31,0x31, - 0x30,0x35,0x31,0x32,0x30,0x35,0x31,0x33, - 0x30,0x35,0x31,0x34,0x30,0x35,0x31,0x35, - 0x30,0x35,0x31,0x36,0x30,0x35,0x31,0x37, - 0x30,0x35,0x31,0x38,0x30,0x35,0x31,0x39, - 0x30,0x35,0x32,0x30,0x30,0x35,0x32,0x31, - 0x30,0x35,0x32,0x32,0x30,0x35,0x32,0x33, - 0x30,0x35,0x32,0x34,0x30,0x35,0x32,0x35, - 0x30,0x35,0x32,0x36,0x30,0x35,0x32,0x37, - 0x30,0x35,0x32,0x38,0x30,0x35,0x32,0x39, - 0x30,0x35,0x33,0x30,0x30,0x35,0x33,0x31, - 0x30,0x35,0x33,0x32,0x30,0x35,0x33,0x33, - 0x30,0x35,0x33,0x34,0x30,0x35,0x33,0x35, - 0x30,0x35,0x33,0x36,0x30,0x35,0x33,0x37, - 0x30,0x35,0x33,0x38,0x30,0x35,0x33,0x39, - 0x30,0x35,0x34,0x30,0x30,0x35,0x34,0x31, - 0x30,0x35,0x34,0x32,0x30,0x35,0x34,0x33, - 0x30,0x35,0x34,0x34,0x30,0x35,0x34,0x35, - 0x30,0x35,0x34,0x36,0x30,0x35,0x34,0x37, - 0x30,0x35,0x34,0x38,0x30,0x35,0x34,0x39, - 0x30,0x35,0x35,0x30,0x30,0x35,0x35,0x31, - 0x30,0x35,0x35,0x32,0x30,0x35,0x35,0x33, - 0x30,0x35,0x35,0x34,0x30,0x35,0x35,0x35, - 0x30,0x35,0x35,0x36,0x30,0x35,0x35,0x37, - 0x30,0x35,0x35,0x38,0x30,0x35,0x35,0x39, - 0x30,0x35,0x36,0x30,0x30,0x35,0x36,0x31, - 0x30,0x35,0x36,0x32,0x30,0x35,0x36,0x33, - 0x30,0x35,0x36,0x34,0x30,0x35,0x36,0x35, - 0x30,0x35,0x36,0x36,0x30,0x35,0x36,0x37, - 0x30,0x35,0x36,0x38,0x30,0x35,0x36,0x39, - 0x30,0x35,0x37,0x30,0x30,0x35,0x37,0x31, - 0x30,0x35,0x37,0x32,0x30,0x35,0x37,0x33, - 0x30,0x35,0x37,0x34,0x30,0x35,0x37,0x35, - 0x30,0x35,0x37,0x36,0x30,0x35,0x37,0x37, - 0x30,0x35,0x37,0x38,0x30,0x35,0x37,0x39, - 0x30,0x35,0x38,0x30,0x30,0x35,0x38,0x31, - 0x30,0x35,0x38,0x32,0x30,0x35,0x38,0x33, - 0x30,0x35,0x38,0x34,0x30,0x35,0x38,0x35, - 0x30,0x35,0x38,0x36,0x30,0x35,0x38,0x37, - 0x30,0x35,0x38,0x38,0x30,0x35,0x38,0x39, - 0x30,0x35,0x39,0x30,0x30,0x35,0x39,0x31, - 0x30,0x35,0x39,0x32,0x30,0x35,0x39,0x33, - 0x30,0x35,0x39,0x34,0x30,0x35,0x39,0x35, - 0x30,0x35,0x39,0x36,0x30,0x35,0x39,0x37, - 0x30,0x35,0x39,0x38,0x30,0x35,0x39,0x39, - 0x30,0x36,0x30,0x30,0x30,0x36,0x30,0x31, - 0x30,0x36,0x30,0x32,0x30,0x36,0x30,0x33, - 0x30,0x36,0x30,0x34,0x30,0x36,0x30,0x35, - 0x30,0x36,0x30,0x36,0x30,0x36,0x30,0x37, - 0x30,0x36,0x30,0x38,0x30,0x36,0x30,0x39, - 0x30,0x36,0x31,0x30,0x30,0x36,0x31,0x31, - 0x30,0x36,0x31,0x32,0x30,0x36,0x31,0x33, - 0x30,0x36,0x31,0x34,0x30,0x36,0x31,0x35, - 0x30,0x36,0x31,0x36,0x30,0x36,0x31,0x37, - 0x30,0x36,0x31,0x38,0x30,0x36,0x31,0x39, - 0x30,0x36,0x32,0x30,0x30,0x36,0x32,0x31, - 0x30,0x36,0x32,0x32,0x30,0x36,0x32,0x33, - 0x30,0x36,0x32,0x34,0x30,0x36,0x32,0x35, - 0x30,0x36,0x32,0x36,0x30,0x36,0x32,0x37, - 0x30,0x36,0x32,0x38,0x30,0x36,0x32,0x39, - 0x30,0x36,0x33,0x30,0x30,0x36,0x33,0x31, - 0x30,0x36,0x33,0x32,0x30,0x36,0x33,0x33, - 0x30,0x36,0x33,0x34,0x30,0x36,0x33,0x35, - 0x30,0x36,0x33,0x36,0x30,0x36,0x33,0x37, - 0x30,0x36,0x33,0x38,0x30,0x36,0x33,0x39, - 0x30,0x36,0x34,0x30,0x30,0x36,0x34,0x31, - 0x30,0x36,0x34,0x32,0x30,0x36,0x34,0x33, - 0x30,0x36,0x34,0x34,0x30,0x36,0x34,0x35, - 0x30,0x36,0x34,0x36,0x30,0x36,0x34,0x37, - 0x30,0x36,0x34,0x38,0x30,0x36,0x34,0x39, - 0x30,0x36,0x35,0x30,0x30,0x36,0x35,0x31, - 0x30,0x36,0x35,0x32,0x30,0x36,0x35,0x33, - 0x30,0x36,0x35,0x34,0x30,0x36,0x35,0x35, - 0x30,0x36,0x35,0x36,0x30,0x36,0x35,0x37, - 0x30,0x36,0x35,0x38,0x30,0x36,0x35,0x39, - 0x30,0x36,0x36,0x30,0x30,0x36,0x36,0x31, - 0x30,0x36,0x36,0x32,0x30,0x36,0x36,0x33, - 0x30,0x36,0x36,0x34,0x30,0x36,0x36,0x35, - 0x30,0x36,0x36,0x36,0x30,0x36,0x36,0x37, - 0x30,0x36,0x36,0x38,0x30,0x36,0x36,0x39, - 0x30,0x36,0x37,0x30,0x30,0x36,0x37,0x31, - 0x30,0x36,0x37,0x32,0x30,0x36,0x37,0x33, - 0x30,0x36,0x37,0x34,0x30,0x36,0x37,0x35, - 0x30,0x36,0x37,0x36,0x30,0x36,0x37,0x37, - 0x30,0x36,0x37,0x38,0x30,0x36,0x37,0x39, - 0x30,0x36,0x38,0x30,0x30,0x36,0x38,0x31, - 0x30,0x36,0x38,0x32,0x30,0x36,0x38,0x33, - 0x30,0x36,0x38,0x34,0x30,0x36,0x38,0x35, - 0x30,0x36,0x38,0x36,0x30,0x36,0x38,0x37, - 0x30,0x36,0x38,0x38,0x30,0x36,0x38,0x39, - 0x30,0x36,0x39,0x30,0x30,0x36,0x39,0x31, - 0x30,0x36,0x39,0x32,0x30,0x36,0x39,0x33, - 0x30,0x36,0x39,0x34,0x30,0x36,0x39,0x35, - 0x30,0x36,0x39,0x36,0x30,0x36,0x39,0x37, - 0x30,0x36,0x39,0x38,0x30,0x36,0x39,0x39, - 0x30,0x37,0x30,0x30,0x30,0x37,0x30,0x31, - 0x30,0x37,0x30,0x32,0x30,0x37,0x30,0x33, - 0x30,0x37,0x30,0x34,0x30,0x37,0x30,0x35, - 0x30,0x37,0x30,0x36,0x30,0x37,0x30,0x37, - 0x30,0x37,0x30,0x38,0x30,0x37,0x30,0x39, - 0x30,0x37,0x31,0x30,0x30,0x37,0x31,0x31, - 0x30,0x37,0x31,0x32,0x30,0x37,0x31,0x33, - 0x30,0x37,0x31,0x34,0x30,0x37,0x31,0x35, - 0x30,0x37,0x31,0x36,0x30,0x37,0x31,0x37, - 0x30,0x37,0x31,0x38,0x30,0x37,0x31,0x39, - 0x30,0x37,0x32,0x30,0x30,0x37,0x32,0x31, - 0x30,0x37,0x32,0x32,0x30,0x37,0x32,0x33, - 0x30,0x37,0x32,0x34,0x30,0x37,0x32,0x35, - 0x30,0x37,0x32,0x36,0x30,0x37,0x32,0x37, - 0x30,0x37,0x32,0x38,0x30,0x37,0x32,0x39, - 0x30,0x37,0x33,0x30,0x30,0x37,0x33,0x31, - 0x30,0x37,0x33,0x32,0x30,0x37,0x33,0x33, - 0x30,0x37,0x33,0x34,0x30,0x37,0x33,0x35, - 0x30,0x37,0x33,0x36,0x30,0x37,0x33,0x37, - 0x30,0x37,0x33,0x38,0x30,0x37,0x33,0x39, - 0x30,0x37,0x34,0x30,0x30,0x37,0x34,0x31, - 0x30,0x37,0x34,0x32,0x30,0x37,0x34,0x33, - 0x30,0x37,0x34,0x34,0x30,0x37,0x34,0x35, - 0x30,0x37,0x34,0x36,0x30,0x37,0x34,0x37, - 0x30,0x37,0x34,0x38,0x30,0x37,0x34,0x39, - 0x30,0x37,0x35,0x30,0x30,0x37,0x35,0x31, - 0x30,0x37,0x35,0x32,0x30,0x37,0x35,0x33, - 0x30,0x37,0x35,0x34,0x30,0x37,0x35,0x35, - 0x30,0x37,0x35,0x36,0x30,0x37,0x35,0x37, - 0x30,0x37,0x35,0x38,0x30,0x37,0x35,0x39, - 0x30,0x37,0x36,0x30,0x30,0x37,0x36,0x31, - 0x30,0x37,0x36,0x32,0x30,0x37,0x36,0x33, - 0x30,0x37,0x36,0x34,0x30,0x37,0x36,0x35, - 0x30,0x37,0x36,0x36,0x30,0x37,0x36,0x37, - 0x30,0x37,0x36,0x38,0x30,0x37,0x36,0x39, - 0x30,0x37,0x37,0x30,0x30,0x37,0x37,0x31, - 0x30,0x37,0x37,0x32,0x30,0x37,0x37,0x33, - 0x30,0x37,0x37,0x34,0x30,0x37,0x37,0x35, - 0x30,0x37,0x37,0x36,0x30,0x37,0x37,0x37, - 0x30,0x37,0x37,0x38,0x30,0x37,0x37,0x39, - 0x30,0x37,0x38,0x30,0x30,0x37,0x38,0x31, - 0x30,0x37,0x38,0x32,0x30,0x37,0x38,0x33, - 0x30,0x37,0x38,0x34,0x30,0x37,0x38,0x35, - 0x30,0x37,0x38,0x36,0x30,0x37,0x38,0x37, - 0x30,0x37,0x38,0x38,0x30,0x37,0x38,0x39, - 0x30,0x37,0x39,0x30,0x30,0x37,0x39,0x31, - 0x30,0x37,0x39,0x32,0x30,0x37,0x39,0x33, - 0x30,0x37,0x39,0x34,0x30,0x37,0x39,0x35, - 0x30,0x37,0x39,0x36,0x30,0x37,0x39,0x37, - 0x30,0x37,0x39,0x38,0x30,0x37,0x39,0x39, - 0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x31, - 0x30,0x38,0x30,0x32,0x30,0x38,0x30,0x33, - 0x30,0x38,0x30,0x34,0x30,0x38,0x30,0x35, - 0x30,0x38,0x30,0x36,0x30,0x38,0x30,0x37, - 0x30,0x38,0x30,0x38,0x30,0x38,0x30,0x39, - 0x30,0x38,0x31,0x30,0x30,0x38,0x31,0x31, - 0x30,0x38,0x31,0x32,0x30,0x38,0x31,0x33, - 0x30,0x38,0x31,0x34,0x30,0x38,0x31,0x35, - 0x30,0x38,0x31,0x36,0x30,0x38,0x31,0x37, - 0x30,0x38,0x31,0x38,0x30,0x38,0x31,0x39, - 0x30,0x38,0x32,0x30,0x30,0x38,0x32,0x31, - 0x30,0x38,0x32,0x32,0x30,0x38,0x32,0x33, - 0x30,0x38,0x32,0x34,0x30,0x38,0x32,0x35, - 0x30,0x38,0x32,0x36,0x30,0x38,0x32,0x37, - 0x30,0x38,0x32,0x38,0x30,0x38,0x32,0x39, - 0x30,0x38,0x33,0x30,0x30,0x38,0x33,0x31, - 0x30,0x38,0x33,0x32,0x30,0x38,0x33,0x33, - 0x30,0x38,0x33,0x34,0x30,0x38,0x33,0x35, - 0x30,0x38,0x33,0x36,0x30,0x38,0x33,0x37, - 0x30,0x38,0x33,0x38,0x30,0x38,0x33,0x39, - 0x30,0x38,0x34,0x30,0x30,0x38,0x34,0x31, - 0x30,0x38,0x34,0x32,0x30,0x38,0x34,0x33, - 0x30,0x38,0x34,0x34,0x30,0x38,0x34,0x35, - 0x30,0x38,0x34,0x36,0x30,0x38,0x34,0x37, - 0x30,0x38,0x34,0x38,0x30,0x38,0x34,0x39, - 0x30,0x38,0x35,0x30,0x30,0x38,0x35,0x31, - 0x30,0x38,0x35,0x32,0x30,0x38,0x35,0x33, - 0x30,0x38,0x35,0x34,0x30,0x38,0x35,0x35, - 0x30,0x38,0x35,0x36,0x30,0x38,0x35,0x37, - 0x30,0x38,0x35,0x38,0x30,0x38,0x35,0x39, - 0x30,0x38,0x36,0x30,0x30,0x38,0x36,0x31, - 0x30,0x38,0x36,0x32,0x30,0x38,0x36,0x33, - 0x30,0x38,0x36,0x34,0x30,0x38,0x36,0x35, - 0x30,0x38,0x36,0x36,0x30,0x38,0x36,0x37, - 0x30,0x38,0x36,0x38,0x30,0x38,0x36,0x39, - 0x30,0x38,0x37,0x30,0x30,0x38,0x37,0x31, - 0x30,0x38,0x37,0x32,0x30,0x38,0x37,0x33, - 0x30,0x38,0x37,0x34,0x30,0x38,0x37,0x35, - 0x30,0x38,0x37,0x36,0x30,0x38,0x37,0x37, - 0x30,0x38,0x37,0x38,0x30,0x38,0x37,0x39, - 0x30,0x38,0x38,0x30,0x30,0x38,0x38,0x31, - 0x30,0x38,0x38,0x32,0x30,0x38,0x38,0x33, - 0x30,0x38,0x38,0x34,0x30,0x38,0x38,0x35, - 0x30,0x38,0x38,0x36,0x30,0x38,0x38,0x37, - 0x30,0x38,0x38,0x38,0x30,0x38,0x38,0x39, - 0x30,0x38,0x39,0x30,0x30,0x38,0x39,0x31, - 0x30,0x38,0x39,0x32,0x30,0x38,0x39,0x33, - 0x30,0x38,0x39,0x34,0x30,0x38,0x39,0x35, - 0x30,0x38,0x39,0x36,0x30,0x38,0x39,0x37, - 0x30,0x38,0x39,0x38,0x30,0x38,0x39,0x39, - 0x30,0x39,0x30,0x30,0x30,0x39,0x30,0x31, - 0x30,0x39,0x30,0x32,0x30,0x39,0x30,0x33, - 0x30,0x39,0x30,0x34,0x30,0x39,0x30,0x35, - 0x30,0x39,0x30,0x36,0x30,0x39,0x30,0x37, - 0x30,0x39,0x30,0x38,0x30,0x39,0x30,0x39, - 0x30,0x39,0x31,0x30,0x30,0x39,0x31,0x31, - 0x30,0x39,0x31,0x32,0x30,0x39,0x31,0x33, - 0x30,0x39,0x31,0x34,0x30,0x39,0x31,0x35, - 0x30,0x39,0x31,0x36,0x30,0x39,0x31,0x37, - 0x30,0x39,0x31,0x38,0x30,0x39,0x31,0x39, - 0x30,0x39,0x32,0x30,0x30,0x39,0x32,0x31, - 0x30,0x39,0x32,0x32,0x30,0x39,0x32,0x33, - 0x30,0x39,0x32,0x34,0x30,0x39,0x32,0x35, - 0x30,0x39,0x32,0x36,0x30,0x39,0x32,0x37, - 0x30,0x39,0x32,0x38,0x30,0x39,0x32,0x39, - 0x30,0x39,0x33,0x30,0x30,0x39,0x33,0x31, - 0x30,0x39,0x33,0x32,0x30,0x39,0x33,0x33, - 0x30,0x39,0x33,0x34,0x30,0x39,0x33,0x35, - 0x30,0x39,0x33,0x36,0x30,0x39,0x33,0x37, - 0x30,0x39,0x33,0x38,0x30,0x39,0x33,0x39, - 0x30,0x39,0x34,0x30,0x30,0x39,0x34,0x31, - 0x30,0x39,0x34,0x32,0x30,0x39,0x34,0x33, - 0x30,0x39,0x34,0x34,0x30,0x39,0x34,0x35, - 0x30,0x39,0x34,0x36,0x30,0x39,0x34,0x37, - 0x30,0x39,0x34,0x38,0x30,0x39,0x34,0x39, - 0x30,0x39,0x35,0x30,0x30,0x39,0x35,0x31, - 0x30,0x39,0x35,0x32,0x30,0x39,0x35,0x33, - 0x30,0x39,0x35,0x34,0x30,0x39,0x35,0x35, - 0x30,0x39,0x35,0x36,0x30,0x39,0x35,0x37, - 0x30,0x39,0x35,0x38,0x30,0x39,0x35,0x39, - 0x30,0x39,0x36,0x30,0x30,0x39,0x36,0x31, - 0x30,0x39,0x36,0x32,0x30,0x39,0x36,0x33, - 0x30,0x39,0x36,0x34,0x30,0x39,0x36,0x35, - 0x30,0x39,0x36,0x36,0x30,0x39,0x36,0x37, - 0x30,0x39,0x36,0x38,0x30,0x39,0x36,0x39, - 0x30,0x39,0x37,0x30,0x30,0x39,0x37,0x31, - 0x30,0x39,0x37,0x32,0x30,0x39,0x37,0x33, - 0x30,0x39,0x37,0x34,0x30,0x39,0x37,0x35, - 0x30,0x39,0x37,0x36,0x30,0x39,0x37,0x37, - 0x30,0x39,0x37,0x38,0x30,0x39,0x37,0x39, - 0x30,0x39,0x38,0x30,0x30,0x39,0x38,0x31, - 0x30,0x39,0x38,0x32,0x30,0x39,0x38,0x33, - 0x30,0x39,0x38,0x34,0x30,0x39,0x38,0x35, - 0x30,0x39,0x38,0x36,0x30,0x39,0x38,0x37, - 0x30,0x39,0x38,0x38,0x30,0x39,0x38,0x39, - 0x30,0x39,0x39,0x30,0x30,0x39,0x39,0x31, - 0x30,0x39,0x39,0x32,0x30,0x39,0x39,0x33, - 0x30,0x39,0x39,0x34,0x30,0x39,0x39,0x35, - 0x30,0x39,0x39,0x36,0x30,0x39,0x39,0x37, - 0x30,0x39,0x39,0x38,0x30,0x39,0x39,0x39, - 0x31,0x30,0x30,0x30,0x31,0x30,0x30,0x31, - 0x31,0x30,0x30,0x32,0x31,0x30,0x30,0x33, - 0x31,0x30,0x30,0x34,0x31,0x30,0x30,0x35, - 0x31,0x30,0x30,0x36,0x31,0x30,0x30,0x37, - 0x31,0x30,0x30,0x38,0x31,0x30,0x30,0x39, - 0x31,0x30,0x31,0x30,0x31,0x30,0x31,0x31, - 0x31,0x30,0x31,0x32,0x31,0x30,0x31,0x33, - 0x31,0x30,0x31,0x34,0x31,0x30,0x31,0x35, - 0x31,0x30,0x31,0x36,0x31,0x30,0x31,0x37, - 0x31,0x30,0x31,0x38,0x31,0x30,0x31,0x39, - 0x31,0x30,0x32,0x30,0x31,0x30,0x32,0x31, - 0x31,0x30,0x32,0x32,0x31,0x30,0x32,0x33, - 0x31,0x30,0x32,0x34,0x31,0x30,0x32,0x35, - 0x31,0x30,0x32,0x36,0x31,0x30,0x32,0x37, - 0x31,0x30,0x32,0x38,0x31,0x30,0x32,0x39, - 0x31,0x30,0x33,0x30,0x31,0x30,0x33,0x31, - 0x31,0x30,0x33,0x32,0x31,0x30,0x33,0x33, - 0x31,0x30,0x33,0x34,0x31,0x30,0x33,0x35, - 0x31,0x30,0x33,0x36,0x31,0x30,0x33,0x37, - 0x31,0x30,0x33,0x38,0x31,0x30,0x33,0x39, - 0x31,0x30,0x34,0x30,0x31,0x30,0x34,0x31, - 0x31,0x30,0x34,0x32,0x31,0x30,0x34,0x33, - 0x31,0x30,0x34,0x34,0x31,0x30,0x34,0x35, - 0x31,0x30,0x34,0x36,0x31,0x30,0x34,0x37, - 0x31,0x30,0x34,0x38,0x31,0x30,0x34,0x39, - 0x31,0x30,0x35,0x30,0x31,0x30,0x35,0x31, - 0x31,0x30,0x35,0x32,0x31,0x30,0x35,0x33, - 0x31,0x30,0x35,0x34,0x31,0x30,0x35,0x35, - 0x31,0x30,0x35,0x36,0x31,0x30,0x35,0x37, - 0x31,0x30,0x35,0x38,0x31,0x30,0x35,0x39, - 0x31,0x30,0x36,0x30,0x31,0x30,0x36,0x31, - 0x31,0x30,0x36,0x32,0x31,0x30,0x36,0x33, - 0x31,0x30,0x36,0x34,0x31,0x30,0x36,0x35, - 0x31,0x30,0x36,0x36,0x31,0x30,0x36,0x37, - 0x31,0x30,0x36,0x38,0x31,0x30,0x36,0x39, - 0x31,0x30,0x37,0x30,0x31,0x30,0x37,0x31, - 0x31,0x30,0x37,0x32,0x31,0x30,0x37,0x33, - 0x31,0x30,0x37,0x34,0x31,0x30,0x37,0x35, - 0x31,0x30,0x37,0x36,0x31,0x30,0x37,0x37, - 0x31,0x30,0x37,0x38,0x31,0x30,0x37,0x39, - 0x31,0x30,0x38,0x30,0x31,0x30,0x38,0x31, - 0x31,0x30,0x38,0x32,0x31,0x30,0x38,0x33, - 0x31,0x30,0x38,0x34,0x31,0x30,0x38,0x35, - 0x31,0x30,0x38,0x36,0x31,0x30,0x38,0x37, - 0x31,0x30,0x38,0x38,0x31,0x30,0x38,0x39, - 0x31,0x30,0x39,0x30,0x31,0x30,0x39,0x31, - 0x31,0x30,0x39,0x32,0x31,0x30,0x39,0x33, - 0x31,0x30,0x39,0x34,0x31,0x30,0x39,0x35, - 0x31,0x30,0x39,0x36,0x31,0x30,0x39,0x37, - 0x31,0x30,0x39,0x38,0x31,0x30,0x39,0x39, - 0x31,0x31,0x30,0x30,0x31,0x31,0x30,0x31, - 0x31,0x31,0x30,0x32,0x31,0x31,0x30,0x33, - 0x31,0x31,0x30,0x34,0x31,0x31,0x30,0x35, - 0x31,0x31,0x30,0x36,0x31,0x31,0x30,0x37, - 0x31,0x31,0x30,0x38,0x31,0x31,0x30,0x39, - 0x31,0x31,0x31,0x30,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x32,0x31,0x31,0x31,0x33, - 0x31,0x31,0x31,0x34,0x31,0x31,0x31,0x35, - 0x31,0x31,0x31,0x36,0x31,0x31,0x31,0x37, - 0x31,0x31,0x31,0x38,0x31,0x31,0x31,0x39, - 0x31,0x31,0x32,0x30,0x31,0x31,0x32,0x31, - 0x31,0x31,0x32,0x32,0x31,0x31,0x32,0x33, - 0x31,0x31,0x32,0x34,0x31,0x31,0x32,0x35, - 0x31,0x31,0x32,0x36,0x31,0x31,0x32,0x37, - 0x31,0x31,0x32,0x38,0x31,0x31,0x32,0x39, - 0x31,0x31,0x33,0x30,0x31,0x31,0x33,0x31, - 0x31,0x31,0x33,0x32,0x31,0x31,0x33,0x33, - 0x31,0x31,0x33,0x34,0x31,0x31,0x33,0x35, - 0x31,0x31,0x33,0x36,0x31,0x31,0x33,0x37, - 0x31,0x31,0x33,0x38,0x31,0x31,0x33,0x39, - 0x31,0x31,0x34,0x30,0x31,0x31,0x34,0x31, - 0x31,0x31,0x34,0x32,0x31,0x31,0x34,0x33, - 0x31,0x31,0x34,0x34,0x31,0x31,0x34,0x35, - 0x31,0x31,0x34,0x36,0x31,0x31,0x34,0x37, - 0x31,0x31,0x34,0x38,0x31,0x31,0x34,0x39, - 0x31,0x31,0x35,0x30,0x31,0x31,0x35,0x31, - 0x31,0x31,0x35,0x32,0x31,0x31,0x35,0x33, - 0x31,0x31,0x35,0x34,0x31,0x31,0x35,0x35, - 0x31,0x31,0x35,0x36,0x31,0x31,0x35,0x37, - 0x31,0x31,0x35,0x38,0x31,0x31,0x35,0x39, - 0x31,0x31,0x36,0x30,0x31,0x31,0x36,0x31, - 0x31,0x31,0x36,0x32,0x31,0x31,0x36,0x33, - 0x31,0x31,0x36,0x34,0x31,0x31,0x36,0x35, - 0x31,0x31,0x36,0x36,0x31,0x31,0x36,0x37, - 0x31,0x31,0x36,0x38,0x31,0x31,0x36,0x39, - 0x31,0x31,0x37,0x30,0x31,0x31,0x37,0x31, - 0x31,0x31,0x37,0x32,0x31,0x31,0x37,0x33, - 0x31,0x31,0x37,0x34,0x31,0x31,0x37,0x35, - 0x31,0x31,0x37,0x36,0x31,0x31,0x37,0x37, - 0x31,0x31,0x37,0x38,0x31,0x31,0x37,0x39, - 0x31,0x31,0x38,0x30,0x31,0x31,0x38,0x31, - 0x31,0x31,0x38,0x32,0x31,0x31,0x38,0x33, - 0x31,0x31,0x38,0x34,0x31,0x31,0x38,0x35, - 0x31,0x31,0x38,0x36,0x31,0x31,0x38,0x37, - 0x31,0x31,0x38,0x38,0x31,0x31,0x38,0x39, - 0x31,0x31,0x39,0x30,0x31,0x31,0x39,0x31, - 0x31,0x31,0x39,0x32,0x31,0x31,0x39,0x33, - 0x31,0x31,0x39,0x34,0x31,0x31,0x39,0x35, - 0x31,0x31,0x39,0x36,0x31,0x31,0x39,0x37, - 0x31,0x31,0x39,0x38,0x31,0x31,0x39,0x39, - 0x31,0x32,0x30,0x30,0x31,0x32,0x30,0x31, - 0x31,0x32,0x30,0x32,0x31,0x32,0x30,0x33, - 0x31,0x32,0x30,0x34,0x31,0x32,0x30,0x35, - 0x31,0x32,0x30,0x36,0x31,0x32,0x30,0x37, - 0x31,0x32,0x30,0x38,0x31,0x32,0x30,0x39, - 0x31,0x32,0x31,0x30,0x31,0x32,0x31,0x31, - 0x31,0x32,0x31,0x32,0x31,0x32,0x31,0x33, - 0x31,0x32,0x31,0x34,0x31,0x32,0x31,0x35, - 0x31,0x32,0x31,0x36,0x31,0x32,0x31,0x37, - 0x31,0x32,0x31,0x38,0x31,0x32,0x31,0x39, - 0x31,0x32,0x32,0x30,0x31,0x32,0x32,0x31, - 0x31,0x32,0x32,0x32,0x31,0x32,0x32,0x33, - 0x31,0x32,0x32,0x34,0x31,0x32,0x32,0x35, - 0x31,0x32,0x32,0x36,0x31,0x32,0x32,0x37, - 0x31,0x32,0x32,0x38,0x31,0x32,0x32,0x39, - 0x31,0x32,0x33,0x30,0x31,0x32,0x33,0x31, - 0x31,0x32,0x33,0x32,0x31,0x32,0x33,0x33, - 0x31,0x32,0x33,0x34,0x31,0x32,0x33,0x35, - 0x31,0x32,0x33,0x36,0x31,0x32,0x33,0x37, - 0x31,0x32,0x33,0x38,0x31,0x32,0x33,0x39, - 0x31,0x32,0x34,0x30,0x31,0x32,0x34,0x31, - 0x31,0x32,0x34,0x32,0x31,0x32,0x34,0x33, - 0x31,0x32,0x34,0x34,0x31,0x32,0x34,0x35, - 0x31,0x32,0x34,0x36,0x31,0x32,0x34,0x37, - 0x31,0x32,0x34,0x38,0x31,0x32,0x34,0x39, - 0x31,0x32,0x35,0x30,0x31,0x32,0x35,0x31, - 0x31,0x32,0x35,0x32,0x31,0x32,0x35,0x33, - 0x31,0x32,0x35,0x34,0x31,0x32,0x35,0x35, - 0x31,0x32,0x35,0x36,0x31,0x32,0x35,0x37, - 0x31,0x32,0x35,0x38,0x31,0x32,0x35,0x39, - 0x31,0x32,0x36,0x30,0x31,0x32,0x36,0x31, - 0x31,0x32,0x36,0x32,0x31,0x32,0x36,0x33, - 0x31,0x32,0x36,0x34,0x31,0x32,0x36,0x35, - 0x31,0x32,0x36,0x36,0x31,0x32,0x36,0x37, - 0x31,0x32,0x36,0x38,0x31,0x32,0x36,0x39, - 0x31,0x32,0x37,0x30,0x31,0x32,0x37,0x31, - 0x31,0x32,0x37,0x32,0x31,0x32,0x37,0x33, - 0x31,0x32,0x37,0x34,0x31,0x32,0x37,0x35, - 0x31,0x32,0x37,0x36,0x31,0x32,0x37,0x37, - 0x31,0x32,0x37,0x38,0x31,0x32,0x37,0x39, - 0x31,0x32,0x38,0x30,0x31,0x32,0x38,0x31, - 0x31,0x32,0x38,0x32,0x31,0x32,0x38,0x33, - 0x31,0x32,0x38,0x34,0x31,0x32,0x38,0x35, - 0x31,0x32,0x38,0x36,0x31,0x32,0x38,0x37, - 0x31,0x32,0x38,0x38,0x31,0x32,0x38,0x39, - 0x31,0x32,0x39,0x30,0x31,0x32,0x39,0x31, - 0x31,0x32,0x39,0x32,0x31,0x32,0x39,0x33, - 0x31,0x32,0x39,0x34,0x31,0x32,0x39,0x35, - 0x31,0x32,0x39,0x36,0x31,0x32,0x39,0x37, - 0x31,0x32,0x39,0x38,0x31,0x32,0x39,0x39, - 0x31,0x33,0x30,0x30,0x31,0x33,0x30,0x31, - 0x31,0x33,0x30,0x32,0x31,0x33,0x30,0x33, - 0x31,0x33,0x30,0x34,0x31,0x33,0x30,0x35, - 0x31,0x33,0x30,0x36,0x31,0x33,0x30,0x37, - 0x31,0x33,0x30,0x38,0x31,0x33,0x30,0x39, - 0x31,0x33,0x31,0x30,0x31,0x33,0x31,0x31, - 0x31,0x33,0x31,0x32,0x31,0x33,0x31,0x33, - 0x31,0x33,0x31,0x34,0x31,0x33,0x31,0x35, - 0x31,0x33,0x31,0x36,0x31,0x33,0x31,0x37, - 0x31,0x33,0x31,0x38,0x31,0x33,0x31,0x39, - 0x31,0x33,0x32,0x30,0x31,0x33,0x32,0x31, - 0x31,0x33,0x32,0x32,0x31,0x33,0x32,0x33, - 0x31,0x33,0x32,0x34,0x31,0x33,0x32,0x35, - 0x31,0x33,0x32,0x36,0x31,0x33,0x32,0x37, - 0x31,0x33,0x32,0x38,0x31,0x33,0x32,0x39, - 0x31,0x33,0x33,0x30,0x31,0x33,0x33,0x31, - 0x31,0x33,0x33,0x32,0x31,0x33,0x33,0x33, - 0x31,0x33,0x33,0x34,0x31,0x33,0x33,0x35, - 0x31,0x33,0x33,0x36,0x31,0x33,0x33,0x37, - 0x31,0x33,0x33,0x38,0x31,0x33,0x33,0x39, - 0x31,0x33,0x34,0x30,0x31,0x33,0x34,0x31, - 0x31,0x33,0x34,0x32,0x31,0x33,0x34,0x33, - 0x31,0x33,0x34,0x34,0x31,0x33,0x34,0x35, - 0x31,0x33,0x34,0x36,0x31,0x33,0x34,0x37, - 0x31,0x33,0x34,0x38,0x31,0x33,0x34,0x39, - 0x31,0x33,0x35,0x30,0x31,0x33,0x35,0x31, - 0x31,0x33,0x35,0x32,0x31,0x33,0x35,0x33, - 0x31,0x33,0x35,0x34,0x31,0x33,0x35,0x35, - 0x31,0x33,0x35,0x36,0x31,0x33,0x35,0x37, - 0x31,0x33,0x35,0x38,0x31,0x33,0x35,0x39, - 0x31,0x33,0x36,0x30,0x31,0x33,0x36,0x31, - 0x31,0x33,0x36,0x32,0x31,0x33,0x36,0x33, - 0x31,0x33,0x36,0x34,0x31,0x33,0x36,0x35, - 0x31,0x33,0x36,0x36,0x31,0x33,0x36,0x37, - 0x31,0x33,0x36,0x38,0x31,0x33,0x36,0x39, - 0x31,0x33,0x37,0x30,0x31,0x33,0x37,0x31, - 0x31,0x33,0x37,0x32,0x31,0x33,0x37,0x33, - 0x31,0x33,0x37,0x34,0x31,0x33,0x37,0x35, - 0x31,0x33,0x37,0x36,0x31,0x33,0x37,0x37, - 0x31,0x33,0x37,0x38,0x31,0x33,0x37,0x39, - 0x31,0x33,0x38,0x30,0x31,0x33,0x38,0x31, - 0x31,0x33,0x38,0x32,0x31,0x33,0x38,0x33, - 0x31,0x33,0x38,0x34,0x31,0x33,0x38,0x35, - 0x31,0x33,0x38,0x36,0x31,0x33,0x38,0x37, - 0x31,0x33,0x38,0x38,0x31,0x33,0x38,0x39, - 0x31,0x33,0x39,0x30,0x31,0x33,0x39,0x31, - 0x31,0x33,0x39,0x32,0x31,0x33,0x39,0x33, - 0x31,0x33,0x39,0x34,0x31,0x33,0x39,0x35, - 0x31,0x33,0x39,0x36,0x31,0x33,0x39,0x37, - 0x31,0x33,0x39,0x38,0x31,0x33,0x39,0x39, - 0x31,0x34,0x30,0x30,0x31,0x34,0x30,0x31, - 0x31,0x34,0x30,0x32,0x31,0x34,0x30,0x33, - 0x31,0x34,0x30,0x34,0x31,0x34,0x30,0x35, - 0x31,0x34,0x30,0x36,0x31,0x34,0x30,0x37, - 0x31,0x34,0x30,0x38,0x31,0x34,0x30,0x39, - 0x31,0x34,0x31,0x30,0x31,0x34,0x31,0x31, - 0x31,0x34,0x31,0x32,0x31,0x34,0x31,0x33, - 0x31,0x34,0x31,0x34,0x31,0x34,0x31,0x35, - 0x31,0x34,0x31,0x36,0x31,0x34,0x31,0x37, - 0x31,0x34,0x31,0x38,0x31,0x34,0x31,0x39, - 0x31,0x34,0x32,0x30,0x31,0x34,0x32,0x31, - 0x31,0x34,0x32,0x32,0x31,0x34,0x32,0x33, - 0x31,0x34,0x32,0x34,0x31,0x34,0x32,0x35, - 0x31,0x34,0x32,0x36,0x31,0x34,0x32,0x37, - 0x31,0x34,0x32,0x38,0x31,0x34,0x32,0x39, - 0x31,0x34,0x33,0x30,0x31,0x34,0x33,0x31, - 0x31,0x34,0x33,0x32,0x31,0x34,0x33,0x33, - 0x31,0x34,0x33,0x34,0x31,0x34,0x33,0x35, - 0x31,0x34,0x33,0x36,0x31,0x34,0x33,0x37, - 0x31,0x34,0x33,0x38,0x31,0x34,0x33,0x39, - 0x31,0x34,0x34,0x30,0x31,0x34,0x34,0x31, - 0x31,0x34,0x34,0x32,0x31,0x34,0x34,0x33, - 0x31,0x34,0x34,0x34,0x31,0x34,0x34,0x35, - 0x31,0x34,0x34,0x36,0x31,0x34,0x34,0x37, - 0x31,0x34,0x34,0x38,0x31,0x34,0x34,0x39, - 0x31,0x34,0x35,0x30,0x31,0x34,0x35,0x31, - 0x31,0x34,0x35,0x32,0x31,0x34,0x35,0x33, - 0x31,0x34,0x35,0x34,0x31,0x34,0x35,0x35, - 0x31,0x34,0x35,0x36,0x31,0x34,0x35,0x37, - 0x31,0x34,0x35,0x38,0x31,0x34,0x35,0x39, - 0x31,0x34,0x36,0x30,0x31,0x34,0x36,0x31, - 0x31,0x34,0x36,0x32,0x31,0x34,0x36,0x33, - 0x31,0x34,0x36,0x34,0x31,0x34,0x36,0x35, - 0x31,0x34,0x36,0x36,0x31,0x34,0x36,0x37, - 0x31,0x34,0x36,0x38,0x31,0x34,0x36,0x39, - 0x31,0x34,0x37,0x30,0x31,0x34,0x37,0x31, - 0x31,0x34,0x37,0x32,0x31,0x34,0x37,0x33, - 0x31,0x34,0x37,0x34,0x31,0x34,0x37,0x35, - 0x31,0x34,0x37,0x36,0x31,0x34,0x37,0x37, - 0x31,0x34,0x37,0x38,0x31,0x34,0x37,0x39, - 0x31,0x34,0x38,0x30,0x31,0x34,0x38,0x31, - 0x31,0x34,0x38,0x32,0x31,0x34,0x38,0x33, - 0x31,0x34,0x38,0x34,0x31,0x34,0x38,0x35, - 0x31,0x34,0x38,0x36,0x31,0x34,0x38,0x37, - 0x31,0x34,0x38,0x38,0x31,0x34,0x38,0x39, - 0x31,0x34,0x39,0x30,0x31,0x34,0x39,0x31, - 0x31,0x34,0x39,0x32,0x31,0x34,0x39,0x33, - 0x31,0x34,0x39,0x34,0x31,0x34,0x39,0x35, - 0x31,0x34,0x39,0x36,0x31,0x34,0x39,0x37, - 0x31,0x34,0x39,0x38,0x31,0x34,0x39,0x39, - 0x31,0x35,0x30,0x30,0x31,0x35,0x30,0x31, - 0x31,0x35,0x30,0x32,0x31,0x35,0x30,0x33, - 0x31,0x35,0x30,0x34,0x31,0x35,0x30,0x35, - 0x31,0x35,0x30,0x36,0x31,0x35,0x30,0x37, - 0x31,0x35,0x30,0x38,0x31,0x35,0x30,0x39, - 0x31,0x35,0x31,0x30,0x31,0x35,0x31,0x31, - 0x31,0x35,0x31,0x32,0x31,0x35,0x31,0x33, - 0x31,0x35,0x31,0x34,0x31,0x35,0x31,0x35, - 0x31,0x35,0x31,0x36,0x31,0x35,0x31,0x37, - 0x31,0x35,0x31,0x38,0x31,0x35,0x31,0x39, - 0x31,0x35,0x32,0x30,0x31,0x35,0x32,0x31, - 0x31,0x35,0x32,0x32,0x31,0x35,0x32,0x33, - 0x31,0x35,0x32,0x34,0x31,0x35,0x32,0x35, - 0x31,0x35,0x32,0x36,0x31,0x35,0x32,0x37, - 0x31,0x35,0x32,0x38,0x31,0x35,0x32,0x39, - 0x31,0x35,0x33,0x30,0x31,0x35,0x33,0x31, - 0x31,0x35,0x33,0x32,0x31,0x35,0x33,0x33, - 0x31,0x35,0x33,0x34,0x31,0x35,0x33,0x35, - 0x31,0x35,0x33,0x36,0x31,0x35,0x33,0x37, - 0x31,0x35,0x33,0x38,0x31,0x35,0x33,0x39, - 0x31,0x35,0x34,0x30,0x31,0x35,0x34,0x31, - 0x31,0x35,0x34,0x32,0x31,0x35,0x34,0x33, - 0x31,0x35,0x34,0x34,0x31,0x35,0x34,0x35, - 0x31,0x35,0x34,0x36,0x31,0x35,0x34,0x37, - 0x31,0x35,0x34,0x38,0x31,0x35,0x34,0x39, - 0x31,0x35,0x35,0x30,0x31,0x35,0x35,0x31, - 0x31,0x35,0x35,0x32,0x31,0x35,0x35,0x33, - 0x31,0x35,0x35,0x34,0x31,0x35,0x35,0x35, - 0x31,0x35,0x35,0x36,0x31,0x35,0x35,0x37, - 0x31,0x35,0x35,0x38,0x31,0x35,0x35,0x39, - 0x31,0x35,0x36,0x30,0x31,0x35,0x36,0x31, - 0x31,0x35,0x36,0x32,0x31,0x35,0x36,0x33, - 0x31,0x35,0x36,0x34,0x31,0x35,0x36,0x35, - 0x31,0x35,0x36,0x36,0x31,0x35,0x36,0x37, - 0x31,0x35,0x36,0x38,0x31,0x35,0x36,0x39, - 0x31,0x35,0x37,0x30,0x31,0x35,0x37,0x31, - 0x31,0x35,0x37,0x32,0x31,0x35,0x37,0x33, - 0x31,0x35,0x37,0x34,0x31,0x35,0x37,0x35, - 0x31,0x35,0x37,0x36,0x31,0x35,0x37,0x37, - 0x31,0x35,0x37,0x38,0x31,0x35,0x37,0x39, - 0x31,0x35,0x38,0x30,0x31,0x35,0x38,0x31, - 0x31,0x35,0x38,0x32,0x31,0x35,0x38,0x33, - 0x31,0x35,0x38,0x34,0x31,0x35,0x38,0x35, - 0x31,0x35,0x38,0x36,0x31,0x35,0x38,0x37, - 0x31,0x35,0x38,0x38,0x31,0x35,0x38,0x39, - 0x31,0x35,0x39,0x30,0x31,0x35,0x39,0x31, - 0x31,0x35,0x39,0x32,0x31,0x35,0x39,0x33, - 0x31,0x35,0x39,0x34,0x31,0x35,0x39,0x35, - 0x31,0x35,0x39,0x36,0x31,0x35,0x39,0x37, - 0x31,0x35,0x39,0x38,0x31,0x35,0x39,0x39, - 0x31,0x36,0x30,0x30,0x31,0x36,0x30,0x31, - 0x31,0x36,0x30,0x32,0x31,0x36,0x30,0x33, - 0x31,0x36,0x30,0x34,0x31,0x36,0x30,0x35, - 0x31,0x36,0x30,0x36,0x31,0x36,0x30,0x37, - 0x31,0x36,0x30,0x38,0x31,0x36,0x30,0x39, - 0x31,0x36,0x31,0x30,0x31,0x36,0x31,0x31, - 0x31,0x36,0x31,0x32,0x31,0x36,0x31,0x33, - 0x31,0x36,0x31,0x34,0x31,0x36,0x31,0x35, - 0x31,0x36,0x31,0x36,0x31,0x36,0x31,0x37, - 0x31,0x36,0x31,0x38,0x31,0x36,0x31,0x39, - 0x31,0x36,0x32,0x30,0x31,0x36,0x32,0x31, - 0x31,0x36,0x32,0x32,0x31,0x36,0x32,0x33, - 0x31,0x36,0x32,0x34,0x31,0x36,0x32,0x35, - 0x31,0x36,0x32,0x36,0x31,0x36,0x32,0x37, - 0x31,0x36,0x32,0x38,0x31,0x36,0x32,0x39, - 0x31,0x36,0x33,0x30,0x31,0x36,0x33,0x31, - 0x31,0x36,0x33,0x32,0x31,0x36,0x33,0x33, - 0x31,0x36,0x33,0x34,0x31,0x36,0x33,0x35, - 0x31,0x36,0x33,0x36,0x31,0x36,0x33,0x37, - 0x31,0x36,0x33,0x38,0x31,0x36,0x33,0x39, - 0x31,0x36,0x34,0x30,0x31,0x36,0x34,0x31, - 0x31,0x36,0x34,0x32,0x31,0x36,0x34,0x33, - 0x31,0x36,0x34,0x34,0x31,0x36,0x34,0x35, - 0x31,0x36,0x34,0x36,0x31,0x36,0x34,0x37, - 0x31,0x36,0x34,0x38,0x31,0x36,0x34,0x39, - 0x31,0x36,0x35,0x30,0x31,0x36,0x35,0x31, - 0x31,0x36,0x35,0x32,0x31,0x36,0x35,0x33, - 0x31,0x36,0x35,0x34,0x31,0x36,0x35,0x35, - 0x31,0x36,0x35,0x36,0x31,0x36,0x35,0x37, - 0x31,0x36,0x35,0x38,0x31,0x36,0x35,0x39, - 0x31,0x36,0x36,0x30,0x31,0x36,0x36,0x31, - 0x31,0x36,0x36,0x32,0x31,0x36,0x36,0x33, - 0x31,0x36,0x36,0x34,0x31,0x36,0x36,0x35, - 0x31,0x36,0x36,0x36,0x31,0x36,0x36,0x37, - 0x31,0x36,0x36,0x38,0x31,0x36,0x36,0x39, - 0x31,0x36,0x37,0x30,0x31,0x36,0x37,0x31, - 0x31,0x36,0x37,0x32,0x31,0x36,0x37,0x33, - 0x31,0x36,0x37,0x34,0x31,0x36,0x37,0x35, - 0x31,0x36,0x37,0x36,0x31,0x36,0x37,0x37, - 0x31,0x36,0x37,0x38,0x31,0x36,0x37,0x39, - 0x31,0x36,0x38,0x30,0x31,0x36,0x38,0x31, - 0x31,0x36,0x38,0x32,0x31,0x36,0x38,0x33, - 0x31,0x36,0x38,0x34,0x31,0x36,0x38,0x35, - 0x31,0x36,0x38,0x36,0x31,0x36,0x38,0x37, - 0x31,0x36,0x38,0x38,0x31,0x36,0x38,0x39, - 0x31,0x36,0x39,0x30,0x31,0x36,0x39,0x31, - 0x31,0x36,0x39,0x32,0x31,0x36,0x39,0x33, - 0x31,0x36,0x39,0x34,0x31,0x36,0x39,0x35, - 0x31,0x36,0x39,0x36,0x31,0x36,0x39,0x37, - 0x31,0x36,0x39,0x38,0x31,0x36,0x39,0x39, - 0x31,0x37,0x30,0x30,0x31,0x37,0x30,0x31, - 0x31,0x37,0x30,0x32,0x31,0x37,0x30,0x33, - 0x31,0x37,0x30,0x34,0x31,0x37,0x30,0x35, - 0x31,0x37,0x30,0x36,0x31,0x37,0x30,0x37, - 0x31,0x37,0x30,0x38,0x31,0x37,0x30,0x39, - 0x31,0x37,0x31,0x30,0x31,0x37,0x31,0x31, - 0x31,0x37,0x31,0x32,0x31,0x37,0x31,0x33, - 0x31,0x37,0x31,0x34,0x31,0x37,0x31,0x35, - 0x31,0x37,0x31,0x36,0x31,0x37,0x31,0x37, - 0x31,0x37,0x31,0x38,0x31,0x37,0x31,0x39, - 0x31,0x37,0x32,0x30,0x31,0x37,0x32,0x31, - 0x31,0x37,0x32,0x32,0x31,0x37,0x32,0x33, - 0x31,0x37,0x32,0x34,0x31,0x37,0x32,0x35, - 0x31,0x37,0x32,0x36,0x31,0x37,0x32,0x37, - 0x31,0x37,0x32,0x38,0x31,0x37,0x32,0x39, - 0x31,0x37,0x33,0x30,0x31,0x37,0x33,0x31, - 0x31,0x37,0x33,0x32,0x31,0x37,0x33,0x33, - 0x31,0x37,0x33,0x34,0x31,0x37,0x33,0x35, - 0x31,0x37,0x33,0x36,0x31,0x37,0x33,0x37, - 0x31,0x37,0x33,0x38,0x31,0x37,0x33,0x39, - 0x31,0x37,0x34,0x30,0x31,0x37,0x34,0x31, - 0x31,0x37,0x34,0x32,0x31,0x37,0x34,0x33, - 0x31,0x37,0x34,0x34,0x31,0x37,0x34,0x35, - 0x31,0x37,0x34,0x36,0x31,0x37,0x34,0x37, - 0x31,0x37,0x34,0x38,0x31,0x37,0x34,0x39, - 0x31,0x37,0x35,0x30,0x31,0x37,0x35,0x31, - 0x31,0x37,0x35,0x32,0x31,0x37,0x35,0x33, - 0x31,0x37,0x35,0x34,0x31,0x37,0x35,0x35, - 0x31,0x37,0x35,0x36,0x31,0x37,0x35,0x37, - 0x31,0x37,0x35,0x38,0x31,0x37,0x35,0x39, - 0x31,0x37,0x36,0x30,0x31,0x37,0x36,0x31, - 0x31,0x37,0x36,0x32,0x31,0x37,0x36,0x33, - 0x31,0x37,0x36,0x34,0x31,0x37,0x36,0x35, - 0x31,0x37,0x36,0x36,0x31,0x37,0x36,0x37, - 0x31,0x37,0x36,0x38,0x31,0x37,0x36,0x39, - 0x31,0x37,0x37,0x30,0x31,0x37,0x37,0x31, - 0x31,0x37,0x37,0x32,0x31,0x37,0x37,0x33, - 0x31,0x37,0x37,0x34,0x31,0x37,0x37,0x35, - 0x31,0x37,0x37,0x36,0x31,0x37,0x37,0x37, - 0x31,0x37,0x37,0x38,0x31,0x37,0x37,0x39, - 0x31,0x37,0x38,0x30,0x31,0x37,0x38,0x31, - 0x31,0x37,0x38,0x32,0x31,0x37,0x38,0x33, - 0x31,0x37,0x38,0x34,0x31,0x37,0x38,0x35, - 0x31,0x37,0x38,0x36,0x31,0x37,0x38,0x37, - 0x31,0x37,0x38,0x38,0x31,0x37,0x38,0x39, - 0x31,0x37,0x39,0x30,0x31,0x37,0x39,0x31, - 0x31,0x37,0x39,0x32,0x31,0x37,0x39,0x33, - 0x31,0x37,0x39,0x34,0x31,0x37,0x39,0x35, - 0x31,0x37,0x39,0x36,0x31,0x37,0x39,0x37, - 0x31,0x37,0x39,0x38,0x31,0x37,0x39,0x39, - 0x31,0x38,0x30,0x30,0x31,0x38,0x30,0x31, - 0x31,0x38,0x30,0x32,0x31,0x38,0x30,0x33, - 0x31,0x38,0x30,0x34,0x31,0x38,0x30,0x35, - 0x31,0x38,0x30,0x36,0x31,0x38,0x30,0x37, - 0x31,0x38,0x30,0x38,0x31,0x38,0x30,0x39, - 0x31,0x38,0x31,0x30,0x31,0x38,0x31,0x31, - 0x31,0x38,0x31,0x32,0x31,0x38,0x31,0x33, - 0x31,0x38,0x31,0x34,0x31,0x38,0x31,0x35, - 0x31,0x38,0x31,0x36,0x31,0x38,0x31,0x37, - 0x31,0x38,0x31,0x38,0x31,0x38,0x31,0x39, - 0x31,0x38,0x32,0x30,0x31,0x38,0x32,0x31, - 0x31,0x38,0x32,0x32,0x31,0x38,0x32,0x33, - 0x31,0x38,0x32,0x34,0x31,0x38,0x32,0x35, - 0x31,0x38,0x32,0x36,0x31,0x38,0x32,0x37, - 0x31,0x38,0x32,0x38,0x31,0x38,0x32,0x39, - 0x31,0x38,0x33,0x30,0x31,0x38,0x33,0x31, - 0x31,0x38,0x33,0x32,0x31,0x38,0x33,0x33, - 0x31,0x38,0x33,0x34,0x31,0x38,0x33,0x35, - 0x31,0x38,0x33,0x36,0x31,0x38,0x33,0x37, - 0x31,0x38,0x33,0x38,0x31,0x38,0x33,0x39, - 0x31,0x38,0x34,0x30,0x31,0x38,0x34,0x31, - 0x31,0x38,0x34,0x32,0x31,0x38,0x34,0x33, - 0x31,0x38,0x34,0x34,0x31,0x38,0x34,0x35, - 0x31,0x38,0x34,0x36,0x31,0x38,0x34,0x37, - 0x31,0x38,0x34,0x38,0x31,0x38,0x34,0x39, - 0x31,0x38,0x35,0x30,0x31,0x38,0x35,0x31, - 0x31,0x38,0x35,0x32,0x31,0x38,0x35,0x33, - 0x31,0x38,0x35,0x34,0x31,0x38,0x35,0x35, - 0x31,0x38,0x35,0x36,0x31,0x38,0x35,0x37, - 0x31,0x38,0x35,0x38,0x31,0x38,0x35,0x39, - 0x31,0x38,0x36,0x30,0x31,0x38,0x36,0x31, - 0x31,0x38,0x36,0x32,0x31,0x38,0x36,0x33, - 0x31,0x38,0x36,0x34,0x31,0x38,0x36,0x35, - 0x31,0x38,0x36,0x36,0x31,0x38,0x36,0x37, - 0x31,0x38,0x36,0x38,0x31,0x38,0x36,0x39, - 0x31,0x38,0x37,0x30,0x31,0x38,0x37,0x31, - 0x31,0x38,0x37,0x32,0x31,0x38,0x37,0x33, - 0x31,0x38,0x37,0x34,0x31,0x38,0x37,0x35, - 0x31,0x38,0x37,0x36,0x31,0x38,0x37,0x37, - 0x31,0x38,0x37,0x38,0x31,0x38,0x37,0x39, - 0x31,0x38,0x38,0x30,0x31,0x38,0x38,0x31, - 0x31,0x38,0x38,0x32,0x31,0x38,0x38,0x33, - 0x31,0x38,0x38,0x34,0x31,0x38,0x38,0x35, - 0x31,0x38,0x38,0x36,0x31,0x38,0x38,0x37, - 0x31,0x38,0x38,0x38,0x31,0x38,0x38,0x39, - 0x31,0x38,0x39,0x30,0x31,0x38,0x39,0x31, - 0x31,0x38,0x39,0x32,0x31,0x38,0x39,0x33, - 0x31,0x38,0x39,0x34,0x31,0x38,0x39,0x35, - 0x31,0x38,0x39,0x36,0x31,0x38,0x39,0x37, - 0x31,0x38,0x39,0x38,0x31,0x38,0x39,0x39, - 0x31,0x39,0x30,0x30,0x31,0x39,0x30,0x31, - 0x31,0x39,0x30,0x32,0x31,0x39,0x30,0x33, - 0x31,0x39,0x30,0x34,0x31,0x39,0x30,0x35, - 0x31,0x39,0x30,0x36,0x31,0x39,0x30,0x37, - 0x31,0x39,0x30,0x38,0x31,0x39,0x30,0x39, - 0x31,0x39,0x31,0x30,0x31,0x39,0x31,0x31, - 0x31,0x39,0x31,0x32,0x31,0x39,0x31,0x33, - 0x31,0x39,0x31,0x34,0x31,0x39,0x31,0x35, - 0x31,0x39,0x31,0x36,0x31,0x39,0x31,0x37, - 0x31,0x39,0x31,0x38,0x31,0x39,0x31,0x39, - 0x31,0x39,0x32,0x30,0x31,0x39,0x32,0x31, - 0x31,0x39,0x32,0x32,0x31,0x39,0x32,0x33, - 0x31,0x39,0x32,0x34,0x31,0x39,0x32,0x35, - 0x31,0x39,0x32,0x36,0x31,0x39,0x32,0x37, - 0x31,0x39,0x32,0x38,0x31,0x39,0x32,0x39, - 0x31,0x39,0x33,0x30,0x31,0x39,0x33,0x31, - 0x31,0x39,0x33,0x32,0x31,0x39,0x33,0x33, - 0x31,0x39,0x33,0x34,0x31,0x39,0x33,0x35, - 0x31,0x39,0x33,0x36,0x31,0x39,0x33,0x37, - 0x31,0x39,0x33,0x38,0x31,0x39,0x33,0x39, - 0x31,0x39,0x34,0x30,0x31,0x39,0x34,0x31, - 0x31,0x39,0x34,0x32,0x31,0x39,0x34,0x33, - 0x31,0x39,0x34,0x34,0x31,0x39,0x34,0x35, - 0x31,0x39,0x34,0x36,0x31,0x39,0x34,0x37, - 0x31,0x39,0x34,0x38,0x31,0x39,0x34,0x39, - 0x31,0x39,0x35,0x30,0x31,0x39,0x35,0x31, - 0x31,0x39,0x35,0x32,0x31,0x39,0x35,0x33, - 0x31,0x39,0x35,0x34,0x31,0x39,0x35,0x35, - 0x31,0x39,0x35,0x36,0x31,0x39,0x35,0x37, - 0x31,0x39,0x35,0x38,0x31,0x39,0x35,0x39, - 0x31,0x39,0x36,0x30,0x31,0x39,0x36,0x31, - 0x31,0x39,0x36,0x32,0x31,0x39,0x36,0x33, - 0x31,0x39,0x36,0x34,0x31,0x39,0x36,0x35, - 0x31,0x39,0x36,0x36,0x31,0x39,0x36,0x37, - 0x31,0x39,0x36,0x38,0x31,0x39,0x36,0x39, - 0x31,0x39,0x37,0x30,0x31,0x39,0x37,0x31, - 0x31,0x39,0x37,0x32,0x31,0x39,0x37,0x33, - 0x31,0x39,0x37,0x34,0x31,0x39,0x37,0x35, - 0x31,0x39,0x37,0x36,0x31,0x39,0x37,0x37, - 0x31,0x39,0x37,0x38,0x31,0x39,0x37,0x39, - 0x31,0x39,0x38,0x30,0x31,0x39,0x38,0x31, - 0x31,0x39,0x38,0x32,0x31,0x39,0x38,0x33, - 0x31,0x39,0x38,0x34,0x31,0x39,0x38,0x35, - 0x31,0x39,0x38,0x36,0x31,0x39,0x38,0x37, - 0x31,0x39,0x38,0x38,0x31,0x39,0x38,0x39, - 0x31,0x39,0x39,0x30,0x31,0x39,0x39,0x31, - 0x31,0x39,0x39,0x32,0x31,0x39,0x39,0x33, - 0x31,0x39,0x39,0x34,0x31,0x39,0x39,0x35, - 0x31,0x39,0x39,0x36,0x31,0x39,0x39,0x37, - 0x31,0x39,0x39,0x38,0x31,0x39,0x39,0x39, - 0x32,0x30,0x30,0x30,0x32,0x30,0x30,0x31, - 0x32,0x30,0x30,0x32,0x32,0x30,0x30,0x33, - 0x32,0x30,0x30,0x34,0x32,0x30,0x30,0x35, - 0x32,0x30,0x30,0x36,0x32,0x30,0x30,0x37, - 0x32,0x30,0x30,0x38,0x32,0x30,0x30,0x39, - 0x32,0x30,0x31,0x30,0x32,0x30,0x31,0x31, - 0x32,0x30,0x31,0x32,0x32,0x30,0x31,0x33, - 0x32,0x30,0x31,0x34,0x32,0x30,0x31,0x35, - 0x32,0x30,0x31,0x36,0x32,0x30,0x31,0x37, - 0x32,0x30,0x31,0x38,0x32,0x30,0x31,0x39, - 0x32,0x30,0x32,0x30,0x32,0x30,0x32,0x31, - 0x32,0x30,0x32,0x32,0x32,0x30,0x32,0x33, - 0x32,0x30,0x32,0x34,0x32,0x30,0x32,0x35, - 0x32,0x30,0x32,0x36,0x32,0x30,0x32,0x37, - 0x32,0x30,0x32,0x38,0x32,0x30,0x32,0x39, - 0x32,0x30,0x33,0x30,0x32,0x30,0x33,0x31, - 0x32,0x30,0x33,0x32,0x32,0x30,0x33,0x33, - 0x32,0x30,0x33,0x34,0x32,0x30,0x33,0x35, - 0x32,0x30,0x33,0x36,0x32,0x30,0x33,0x37, - 0x32,0x30,0x33,0x38,0x32,0x30,0x33,0x39, - 0x32,0x30,0x34,0x30,0x32,0x30,0x34,0x31, - 0x32,0x30,0x34,0x32,0x32,0x30,0x34,0x33, - 0x32,0x30,0x34,0x34,0x32,0x30,0x34,0x35, - 0x32,0x30,0x34,0x36,0x32,0x30,0x34,0x37, - 0x32,0x30,0x34,0x38,0x32,0x30,0x34,0x39, - 0x32,0x30,0x35,0x30,0x32,0x30,0x35,0x31, - 0x32,0x30,0x35,0x32,0x32,0x30,0x35,0x33, - 0x32,0x30,0x35,0x34,0x32,0x30,0x35,0x35, - 0x32,0x30,0x35,0x36,0x32,0x30,0x35,0x37, - 0x32,0x30,0x35,0x38,0x32,0x30,0x35,0x39, - 0x32,0x30,0x36,0x30,0x32,0x30,0x36,0x31, - 0x32,0x30,0x36,0x32,0x32,0x30,0x36,0x33, - 0x32,0x30,0x36,0x34,0x32,0x30,0x36,0x35, - 0x32,0x30,0x36,0x36,0x32,0x30,0x36,0x37, - 0x32,0x30,0x36,0x38,0x32,0x30,0x36,0x39, - 0x32,0x30,0x37,0x30,0x32,0x30,0x37,0x31, - 0x32,0x30,0x37,0x32,0x32,0x30,0x37,0x33, - 0x32,0x30,0x37,0x34,0x32,0x30,0x37,0x35, - 0x32,0x30,0x37,0x36,0x32,0x30,0x37,0x37, - 0x32,0x30,0x37,0x38,0x32,0x30,0x37,0x39, - 0x32,0x30,0x38,0x30,0x32,0x30,0x38,0x31, - 0x32,0x30,0x38,0x32,0x32,0x30,0x38,0x33, - 0x32,0x30,0x38,0x34,0x32,0x30,0x38,0x35, - 0x32,0x30,0x38,0x36,0x32,0x30,0x38,0x37, - 0x32,0x30,0x38,0x38,0x32,0x30,0x38,0x39, - 0x32,0x30,0x39,0x30,0x32,0x30,0x39,0x31, - 0x32,0x30,0x39,0x32,0x32,0x30,0x39,0x33, - 0x32,0x30,0x39,0x34,0x32,0x30,0x39,0x35, - 0x32,0x30,0x39,0x36,0x32,0x30,0x39,0x37, - 0x32,0x30,0x39,0x38,0x32,0x30,0x39,0x39, - 0x32,0x31,0x30,0x30,0x32,0x31,0x30,0x31, - 0x32,0x31,0x30,0x32,0x32,0x31,0x30,0x33, - 0x32,0x31,0x30,0x34,0x32,0x31,0x30,0x35, - 0x32,0x31,0x30,0x36,0x32,0x31,0x30,0x37, - 0x32,0x31,0x30,0x38,0x32,0x31,0x30,0x39, - 0x32,0x31,0x31,0x30,0x32,0x31,0x31,0x31, - 0x32,0x31,0x31,0x32,0x32,0x31,0x31,0x33, - 0x32,0x31,0x31,0x34,0x32,0x31,0x31,0x35, - 0x32,0x31,0x31,0x36,0x32,0x31,0x31,0x37, - 0x32,0x31,0x31,0x38,0x32,0x31,0x31,0x39, - 0x32,0x31,0x32,0x30,0x32,0x31,0x32,0x31, - 0x32,0x31,0x32,0x32,0x32,0x31,0x32,0x33, - 0x32,0x31,0x32,0x34,0x32,0x31,0x32,0x35, - 0x32,0x31,0x32,0x36,0x32,0x31,0x32,0x37, - 0x32,0x31,0x32,0x38,0x32,0x31,0x32,0x39, - 0x32,0x31,0x33,0x30,0x32,0x31,0x33,0x31, - 0x32,0x31,0x33,0x32,0x32,0x31,0x33,0x33, - 0x32,0x31,0x33,0x34,0x32,0x31,0x33,0x35, - 0x32,0x31,0x33,0x36,0x32,0x31,0x33,0x37, - 0x32,0x31,0x33,0x38,0x32,0x31,0x33,0x39, - 0x32,0x31,0x34,0x30,0x32,0x31,0x34,0x31, - 0x32,0x31,0x34,0x32,0x32,0x31,0x34,0x33, - 0x32,0x31,0x34,0x34,0x32,0x31,0x34,0x35, - 0x32,0x31,0x34,0x36,0x32,0x31,0x34,0x37, - 0x32,0x31,0x34,0x38,0x32,0x31,0x34,0x39, - 0x32,0x31,0x35,0x30,0x32,0x31,0x35,0x31, - 0x32,0x31,0x35,0x32,0x32,0x31,0x35,0x33, - 0x32,0x31,0x35,0x34,0x32,0x31,0x35,0x35, - 0x32,0x31,0x35,0x36,0x32,0x31,0x35,0x37, - 0x32,0x31,0x35,0x38,0x32,0x31,0x35,0x39, - 0x32,0x31,0x36,0x30,0x32,0x31,0x36,0x31, - 0x32,0x31,0x36,0x32,0x32,0x31,0x36,0x33, - 0x32,0x31,0x36,0x34,0x32,0x31,0x36,0x35, - 0x32,0x31,0x36,0x36,0x32,0x31,0x36,0x37, - 0x32,0x31,0x36,0x38,0x32,0x31,0x36,0x39, - 0x32,0x31,0x37,0x30,0x32,0x31,0x37,0x31, - 0x32,0x31,0x37,0x32,0x32,0x31,0x37,0x33, - 0x32,0x31,0x37,0x34,0x32,0x31,0x37,0x35, - 0x32,0x31,0x37,0x36,0x32,0x31,0x37,0x37, - 0x32,0x31,0x37,0x38,0x32,0x31,0x37,0x39, - 0x32,0x31,0x38,0x30,0x32,0x31,0x38,0x31, - 0x32,0x31,0x38,0x32,0x32,0x31,0x38,0x33, - 0x32,0x31,0x38,0x34,0x32,0x31,0x38,0x35, - 0x32,0x31,0x38,0x36,0x32,0x31,0x38,0x37, - 0x32,0x31,0x38,0x38,0x32,0x31,0x38,0x39, - 0x32,0x31,0x39,0x30,0x32,0x31,0x39,0x31, - 0x32,0x31,0x39,0x32,0x32,0x31,0x39,0x33, - 0x32,0x31,0x39,0x34,0x32,0x31,0x39,0x35, - 0x32,0x31,0x39,0x36,0x32,0x31,0x39,0x37, - 0x32,0x31,0x39,0x38,0x32,0x31,0x39,0x39, - 0x32,0x32,0x30,0x30,0x32,0x32,0x30,0x31, - 0x32,0x32,0x30,0x32,0x32,0x32,0x30,0x33, - 0x32,0x32,0x30,0x34,0x32,0x32,0x30,0x35, - 0x32,0x32,0x30,0x36,0x32,0x32,0x30,0x37, - 0x32,0x32,0x30,0x38,0x32,0x32,0x30,0x39, - 0x32,0x32,0x31,0x30,0x32,0x32,0x31,0x31, - 0x32,0x32,0x31,0x32,0x32,0x32,0x31,0x33, - 0x32,0x32,0x31,0x34,0x32,0x32,0x31,0x35, - 0x32,0x32,0x31,0x36,0x32,0x32,0x31,0x37, - 0x32,0x32,0x31,0x38,0x32,0x32,0x31,0x39, - 0x32,0x32,0x32,0x30,0x32,0x32,0x32,0x31, - 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x33, - 0x32,0x32,0x32,0x34,0x32,0x32,0x32,0x35, - 0x32,0x32,0x32,0x36,0x32,0x32,0x32,0x37, - 0x32,0x32,0x32,0x38,0x32,0x32,0x32,0x39, - 0x32,0x32,0x33,0x30,0x32,0x32,0x33,0x31, - 0x32,0x32,0x33,0x32,0x32,0x32,0x33,0x33, - 0x32,0x32,0x33,0x34,0x32,0x32,0x33,0x35, - 0x32,0x32,0x33,0x36,0x32,0x32,0x33,0x37, - 0x32,0x32,0x33,0x38,0x32,0x32,0x33,0x39, - 0x32,0x32,0x34,0x30,0x32,0x32,0x34,0x31, - 0x32,0x32,0x34,0x32,0x32,0x32,0x34,0x33, - 0x32,0x32,0x34,0x34,0x32,0x32,0x34,0x35, - 0x32,0x32,0x34,0x36,0x32,0x32,0x34,0x37, - 0x32,0x32,0x34,0x38,0x32,0x32,0x34,0x39, - 0x32,0x32,0x35,0x30,0x32,0x32,0x35,0x31, - 0x32,0x32,0x35,0x32,0x32,0x32,0x35,0x33, - 0x32,0x32,0x35,0x34,0x32,0x32,0x35,0x35, - 0x32,0x32,0x35,0x36,0x32,0x32,0x35,0x37, - 0x32,0x32,0x35,0x38,0x32,0x32,0x35,0x39, - 0x32,0x32,0x36,0x30,0x32,0x32,0x36,0x31, - 0x32,0x32,0x36,0x32,0x32,0x32,0x36,0x33, - 0x32,0x32,0x36,0x34,0x32,0x32,0x36,0x35, - 0x32,0x32,0x36,0x36,0x32,0x32,0x36,0x37, - 0x32,0x32,0x36,0x38,0x32,0x32,0x36,0x39, - 0x32,0x32,0x37,0x30,0x32,0x32,0x37,0x31, - 0x32,0x32,0x37,0x32,0x32,0x32,0x37,0x33, - 0x32,0x32,0x37,0x34,0x32,0x32,0x37,0x35, - 0x32,0x32,0x37,0x36,0x32,0x32,0x37,0x37, - 0x32,0x32,0x37,0x38,0x32,0x32,0x37,0x39, - 0x32,0x32,0x38,0x30,0x32,0x32,0x38,0x31, - 0x32,0x32,0x38,0x32,0x32,0x32,0x38,0x33, - 0x32,0x32,0x38,0x34,0x32,0x32,0x38,0x35, - 0x32,0x32,0x38,0x36,0x32,0x32,0x38,0x37, - 0x32,0x32,0x38,0x38,0x32,0x32,0x38,0x39, - 0x32,0x32,0x39,0x30,0x32,0x32,0x39,0x31, - 0x32,0x32,0x39,0x32,0x32,0x32,0x39,0x33, - 0x32,0x32,0x39,0x34,0x32,0x32,0x39,0x35, - 0x32,0x32,0x39,0x36,0x32,0x32,0x39,0x37, - 0x32,0x32,0x39,0x38,0x32,0x32,0x39,0x39, - 0x32,0x33,0x30,0x30,0x32,0x33,0x30,0x31, - 0x32,0x33,0x30,0x32,0x32,0x33,0x30,0x33, - 0x32,0x33,0x30,0x34,0x32,0x33,0x30,0x35, - 0x32,0x33,0x30,0x36,0x32,0x33,0x30,0x37, - 0x32,0x33,0x30,0x38,0x32,0x33,0x30,0x39, - 0x32,0x33,0x31,0x30,0x32,0x33,0x31,0x31, - 0x32,0x33,0x31,0x32,0x32,0x33,0x31,0x33, - 0x32,0x33,0x31,0x34,0x32,0x33,0x31,0x35, - 0x32,0x33,0x31,0x36,0x32,0x33,0x31,0x37, - 0x32,0x33,0x31,0x38,0x32,0x33,0x31,0x39, - 0x32,0x33,0x32,0x30,0x32,0x33,0x32,0x31, - 0x32,0x33,0x32,0x32,0x32,0x33,0x32,0x33, - 0x32,0x33,0x32,0x34,0x32,0x33,0x32,0x35, - 0x32,0x33,0x32,0x36,0x32,0x33,0x32,0x37, - 0x32,0x33,0x32,0x38,0x32,0x33,0x32,0x39, - 0x32,0x33,0x33,0x30,0x32,0x33,0x33,0x31, - 0x32,0x33,0x33,0x32,0x32,0x33,0x33,0x33, - 0x32,0x33,0x33,0x34,0x32,0x33,0x33,0x35, - 0x32,0x33,0x33,0x36,0x32,0x33,0x33,0x37, - 0x32,0x33,0x33,0x38,0x32,0x33,0x33,0x39, - 0x32,0x33,0x34,0x30,0x32,0x33,0x34,0x31, - 0x32,0x33,0x34,0x32,0x32,0x33,0x34,0x33, - 0x32,0x33,0x34,0x34,0x32,0x33,0x34,0x35, - 0x32,0x33,0x34,0x36,0x32,0x33,0x34,0x37, - 0x32,0x33,0x34,0x38,0x32,0x33,0x34,0x39, - 0x32,0x33,0x35,0x30,0x32,0x33,0x35,0x31, - 0x32,0x33,0x35,0x32,0x32,0x33,0x35,0x33, - 0x32,0x33,0x35,0x34,0x32,0x33,0x35,0x35, - 0x32,0x33,0x35,0x36,0x32,0x33,0x35,0x37, - 0x32,0x33,0x35,0x38,0x32,0x33,0x35,0x39, - 0x32,0x33,0x36,0x30,0x32,0x33,0x36,0x31, - 0x32,0x33,0x36,0x32,0x32,0x33,0x36,0x33, - 0x32,0x33,0x36,0x34,0x32,0x33,0x36,0x35, - 0x32,0x33,0x36,0x36,0x32,0x33,0x36,0x37, - 0x32,0x33,0x36,0x38,0x32,0x33,0x36,0x39, - 0x32,0x33,0x37,0x30,0x32,0x33,0x37,0x31, - 0x32,0x33,0x37,0x32,0x32,0x33,0x37,0x33, - 0x32,0x33,0x37,0x34,0x32,0x33,0x37,0x35, - 0x32,0x33,0x37,0x36,0x32,0x33,0x37,0x37, - 0x32,0x33,0x37,0x38,0x32,0x33,0x37,0x39, - 0x32,0x33,0x38,0x30,0x32,0x33,0x38,0x31, - 0x32,0x33,0x38,0x32,0x32,0x33,0x38,0x33, - 0x32,0x33,0x38,0x34,0x32,0x33,0x38,0x35, - 0x32,0x33,0x38,0x36,0x32,0x33,0x38,0x37, - 0x32,0x33,0x38,0x38,0x32,0x33,0x38,0x39, - 0x32,0x33,0x39,0x30,0x32,0x33,0x39,0x31, - 0x32,0x33,0x39,0x32,0x32,0x33,0x39,0x33, - 0x32,0x33,0x39,0x34,0x32,0x33,0x39,0x35, - 0x32,0x33,0x39,0x36,0x32,0x33,0x39,0x37, - 0x32,0x33,0x39,0x38,0x32,0x33,0x39,0x39, - 0x32,0x34,0x30,0x30,0x32,0x34,0x30,0x31, - 0x32,0x34,0x30,0x32,0x32,0x34,0x30,0x33, - 0x32,0x34,0x30,0x34,0x32,0x34,0x30,0x35, - 0x32,0x34,0x30,0x36,0x32,0x34,0x30,0x37, - 0x32,0x34,0x30,0x38,0x32,0x34,0x30,0x39, - 0x32,0x34,0x31,0x30,0x32,0x34,0x31,0x31, - 0x32,0x34,0x31,0x32,0x32,0x34,0x31,0x33, - 0x32,0x34,0x31,0x34,0x32,0x34,0x31,0x35, - 0x32,0x34,0x31,0x36,0x32,0x34,0x31,0x37, - 0x32,0x34,0x31,0x38,0x32,0x34,0x31,0x39, - 0x32,0x34,0x32,0x30,0x32,0x34,0x32,0x31, - 0x32,0x34,0x32,0x32,0x32,0x34,0x32,0x33, - 0x32,0x34,0x32,0x34,0x32,0x34,0x32,0x35, - 0x32,0x34,0x32,0x36,0x32,0x34,0x32,0x37, - 0x32,0x34,0x32,0x38,0x32,0x34,0x32,0x39, - 0x32,0x34,0x33,0x30,0x32,0x34,0x33,0x31, - 0x32,0x34,0x33,0x32,0x32,0x34,0x33,0x33, - 0x32,0x34,0x33,0x34,0x32,0x34,0x33,0x35, - 0x32,0x34,0x33,0x36,0x32,0x34,0x33,0x37, - 0x32,0x34,0x33,0x38,0x32,0x34,0x33,0x39, - 0x32,0x34,0x34,0x30,0x32,0x34,0x34,0x31, - 0x32,0x34,0x34,0x32,0x32,0x34,0x34,0x33, - 0x32,0x34,0x34,0x34,0x32,0x34,0x34,0x35, - 0x32,0x34,0x34,0x36,0x32,0x34,0x34,0x37, - 0x32,0x34,0x34,0x38,0x32,0x34,0x34,0x39, - 0x32,0x34,0x35,0x30,0x32,0x34,0x35,0x31, - 0x32,0x34,0x35,0x32,0x32,0x34,0x35,0x33, - 0x32,0x34,0x35,0x34,0x32,0x34,0x35,0x35, - 0x32,0x34,0x35,0x36,0x32,0x34,0x35,0x37, - 0x32,0x34,0x35,0x38,0x32,0x34,0x35,0x39, - 0x32,0x34,0x36,0x30,0x32,0x34,0x36,0x31, - 0x32,0x34,0x36,0x32,0x32,0x34,0x36,0x33, - 0x32,0x34,0x36,0x34,0x32,0x34,0x36,0x35, - 0x32,0x34,0x36,0x36,0x32,0x34,0x36,0x37, - 0x32,0x34,0x36,0x38,0x32,0x34,0x36,0x39, - 0x32,0x34,0x37,0x30,0x32,0x34,0x37,0x31, - 0x32,0x34,0x37,0x32,0x32,0x34,0x37,0x33, - 0x32,0x34,0x37,0x34,0x32,0x34,0x37,0x35, - 0x32,0x34,0x37,0x36,0x32,0x34,0x37,0x37, - 0x32,0x34,0x37,0x38,0x32,0x34,0x37,0x39, - 0x32,0x34,0x38,0x30,0x32,0x34,0x38,0x31, - 0x32,0x34,0x38,0x32,0x32,0x34,0x38,0x33, - 0x32,0x34,0x38,0x34,0x32,0x34,0x38,0x35, - 0x32,0x34,0x38,0x36,0x32,0x34,0x38,0x37, - 0x32,0x34,0x38,0x38,0x32,0x34,0x38,0x39, - 0x32,0x34,0x39,0x30,0x32,0x34,0x39,0x31, - 0x32,0x34,0x39,0x32,0x32,0x34,0x39,0x33, - 0x32,0x34,0x39,0x34,0x32,0x34,0x39,0x35, - 0x32,0x34,0x39,0x36,0x32,0x34,0x39,0x37, - 0x32,0x34,0x39,0x38,0x32,0x34,0x39,0x39, - 0x32,0x35,0x30,0x30,0x32,0x35,0x30,0x31, - 0x32,0x35,0x30,0x32,0x32,0x35,0x30,0x33, - 0x32,0x35,0x30,0x34,0x32,0x35,0x30,0x35, - 0x32,0x35,0x30,0x36,0x32,0x35,0x30,0x37, - 0x32,0x35,0x30,0x38,0x32,0x35,0x30,0x39, - 0x32,0x35,0x31,0x30,0x32,0x35,0x31,0x31, - 0x32,0x35,0x31,0x32,0x32,0x35,0x31,0x33, - 0x32,0x35,0x31,0x34,0x32,0x35,0x31,0x35, - 0x32,0x35,0x31,0x36,0x32,0x35,0x31,0x37, - 0x32,0x35,0x31,0x38,0x32,0x35,0x31,0x39, - 0x32,0x35,0x32,0x30,0x32,0x35,0x32,0x31, - 0x32,0x35,0x32,0x32,0x32,0x35,0x32,0x33, - 0x32,0x35,0x32,0x34,0x32,0x35,0x32,0x35, - 0x32,0x35,0x32,0x36,0x32,0x35,0x32,0x37, - 0x32,0x35,0x32,0x38,0x32,0x35,0x32,0x39, - 0x32,0x35,0x33,0x30,0x32,0x35,0x33,0x31, - 0x32,0x35,0x33,0x32,0x32,0x35,0x33,0x33, - 0x32,0x35,0x33,0x34,0x32,0x35,0x33,0x35, - 0x32,0x35,0x33,0x36,0x32,0x35,0x33,0x37, - 0x32,0x35,0x33,0x38,0x32,0x35,0x33,0x39, - 0x32,0x35,0x34,0x30,0x32,0x35,0x34,0x31, - 0x32,0x35,0x34,0x32,0x32,0x35,0x34,0x33, - 0x32,0x35,0x34,0x34,0x32,0x35,0x34,0x35, - 0x32,0x35,0x34,0x36,0x32,0x35,0x34,0x37, - 0x32,0x35,0x34,0x38,0x32,0x35,0x34,0x39, - 0x32,0x35,0x35,0x30,0x32,0x35,0x35,0x31, - 0x32,0x35,0x35,0x32,0x32,0x35,0x35,0x33, - 0x32,0x35,0x35,0x34,0x32,0x35,0x35,0x35, - 0x32,0x35,0x35,0x36,0x32,0x35,0x35,0x37, - 0x32,0x35,0x35,0x38,0x32,0x35,0x35,0x39, - 0x32,0x35,0x36,0x30,0x32,0x35,0x36,0x31, - 0x32,0x35,0x36,0x32,0x32,0x35,0x36,0x33, - 0x32,0x35,0x36,0x34,0x32,0x35,0x36,0x35, - 0x32,0x35,0x36,0x36,0x32,0x35,0x36,0x37, - 0x32,0x35,0x36,0x38,0x32,0x35,0x36,0x39, - 0x32,0x35,0x37,0x30,0x32,0x35,0x37,0x31, - 0x32,0x35,0x37,0x32,0x32,0x35,0x37,0x33, - 0x32,0x35,0x37,0x34,0x32,0x35,0x37,0x35, - 0x32,0x35,0x37,0x36,0x32,0x35,0x37,0x37, - 0x32,0x35,0x37,0x38,0x32,0x35,0x37,0x39, - 0x32,0x35,0x38,0x30,0x32,0x35,0x38,0x31, - 0x32,0x35,0x38,0x32,0x32,0x35,0x38,0x33, - 0x32,0x35,0x38,0x34,0x32,0x35,0x38,0x35, - 0x32,0x35,0x38,0x36,0x32,0x35,0x38,0x37, - 0x32,0x35,0x38,0x38,0x32,0x35,0x38,0x39, - 0x32,0x35,0x39,0x30,0x32,0x35,0x39,0x31, - 0x32,0x35,0x39,0x32,0x32,0x35,0x39,0x33, - 0x32,0x35,0x39,0x34,0x32,0x35,0x39,0x35, - 0x32,0x35,0x39,0x36,0x32,0x35,0x39,0x37, - 0x32,0x35,0x39,0x38,0x32,0x35,0x39,0x39, - 0x32,0x36,0x30,0x30,0x32,0x36,0x30,0x31, - 0x32,0x36,0x30,0x32,0x32,0x36,0x30,0x33, - 0x32,0x36,0x30,0x34,0x32,0x36,0x30,0x35, - 0x32,0x36,0x30,0x36,0x32,0x36,0x30,0x37, - 0x32,0x36,0x30,0x38,0x32,0x36,0x30,0x39, - 0x32,0x36,0x31,0x30,0x32,0x36,0x31,0x31, - 0x32,0x36,0x31,0x32,0x32,0x36,0x31,0x33, - 0x32,0x36,0x31,0x34,0x32,0x36,0x31,0x35, - 0x32,0x36,0x31,0x36,0x32,0x36,0x31,0x37, - 0x32,0x36,0x31,0x38,0x32,0x36,0x31,0x39, - 0x32,0x36,0x32,0x30,0x32,0x36,0x32,0x31, - 0x32,0x36,0x32,0x32,0x32,0x36,0x32,0x33, - 0x32,0x36,0x32,0x34,0x32,0x36,0x32,0x35, - 0x32,0x36,0x32,0x36,0x32,0x36,0x32,0x37, - 0x32,0x36,0x32,0x38,0x32,0x36,0x32,0x39, - 0x32,0x36,0x33,0x30,0x32,0x36,0x33,0x31, - 0x32,0x36,0x33,0x32,0x32,0x36,0x33,0x33, - 0x32,0x36,0x33,0x34,0x32,0x36,0x33,0x35, - 0x32,0x36,0x33,0x36,0x32,0x36,0x33,0x37, - 0x32,0x36,0x33,0x38,0x32,0x36,0x33,0x39, - 0x32,0x36,0x34,0x30,0x32,0x36,0x34,0x31, - 0x32,0x36,0x34,0x32,0x32,0x36,0x34,0x33, - 0x32,0x36,0x34,0x34,0x32,0x36,0x34,0x35, - 0x32,0x36,0x34,0x36,0x32,0x36,0x34,0x37, - 0x32,0x36,0x34,0x38,0x32,0x36,0x34,0x39, - 0x32,0x36,0x35,0x30,0x32,0x36,0x35,0x31, - 0x32,0x36,0x35,0x32,0x32,0x36,0x35,0x33, - 0x32,0x36,0x35,0x34,0x32,0x36,0x35,0x35, - 0x32,0x36,0x35,0x36,0x32,0x36,0x35,0x37, - 0x32,0x36,0x35,0x38,0x32,0x36,0x35,0x39, - 0x32,0x36,0x36,0x30,0x32,0x36,0x36,0x31, - 0x32,0x36,0x36,0x32,0x32,0x36,0x36,0x33, - 0x32,0x36,0x36,0x34,0x32,0x36,0x36,0x35, - 0x32,0x36,0x36,0x36,0x32,0x36,0x36,0x37, - 0x32,0x36,0x36,0x38,0x32,0x36,0x36,0x39, - 0x32,0x36,0x37,0x30,0x32,0x36,0x37,0x31, - 0x32,0x36,0x37,0x32,0x32,0x36,0x37,0x33, - 0x32,0x36,0x37,0x34,0x32,0x36,0x37,0x35, - 0x32,0x36,0x37,0x36,0x32,0x36,0x37,0x37, - 0x32,0x36,0x37,0x38,0x32,0x36,0x37,0x39, - 0x32,0x36,0x38,0x30,0x32,0x36,0x38,0x31, - 0x32,0x36,0x38,0x32,0x32,0x36,0x38,0x33, - 0x32,0x36,0x38,0x34,0x32,0x36,0x38,0x35, - 0x32,0x36,0x38,0x36,0x32,0x36,0x38,0x37, - 0x32,0x36,0x38,0x38,0x32,0x36,0x38,0x39, - 0x32,0x36,0x39,0x30,0x32,0x36,0x39,0x31, - 0x32,0x36,0x39,0x32,0x32,0x36,0x39,0x33, - 0x32,0x36,0x39,0x34,0x32,0x36,0x39,0x35, - 0x32,0x36,0x39,0x36,0x32,0x36,0x39,0x37, - 0x32,0x36,0x39,0x38,0x32,0x36,0x39,0x39, - 0x32,0x37,0x30,0x30,0x32,0x37,0x30,0x31, - 0x32,0x37,0x30,0x32,0x32,0x37,0x30,0x33, - 0x32,0x37,0x30,0x34,0x32,0x37,0x30,0x35, - 0x32,0x37,0x30,0x36,0x32,0x37,0x30,0x37, - 0x32,0x37,0x30,0x38,0x32,0x37,0x30,0x39, - 0x32,0x37,0x31,0x30,0x32,0x37,0x31,0x31, - 0x32,0x37,0x31,0x32,0x32,0x37,0x31,0x33, - 0x32,0x37,0x31,0x34,0x32,0x37,0x31,0x35, - 0x32,0x37,0x31,0x36,0x32,0x37,0x31,0x37, - 0x32,0x37,0x31,0x38,0x32,0x37,0x31,0x39, - 0x32,0x37,0x32,0x30,0x32,0x37,0x32,0x31, - 0x32,0x37,0x32,0x32,0x32,0x37,0x32,0x33, - 0x32,0x37,0x32,0x34,0x32,0x37,0x32,0x35, - 0x32,0x37,0x32,0x36,0x32,0x37,0x32,0x37, - 0x32,0x37,0x32,0x38,0x32,0x37,0x32,0x39, - 0x32,0x37,0x33,0x30,0x32,0x37,0x33,0x31, - 0x32,0x37,0x33,0x32,0x32,0x37,0x33,0x33, - 0x32,0x37,0x33,0x34,0x32,0x37,0x33,0x35, - 0x32,0x37,0x33,0x36,0x32,0x37,0x33,0x37, - 0x32,0x37,0x33,0x38,0x32,0x37,0x33,0x39, - 0x32,0x37,0x34,0x30,0x32,0x37,0x34,0x31, - 0x32,0x37,0x34,0x32,0x32,0x37,0x34,0x33, - 0x32,0x37,0x34,0x34,0x32,0x37,0x34,0x35, - 0x32,0x37,0x34,0x36,0x32,0x37,0x34,0x37, - 0x32,0x37,0x34,0x38,0x32,0x37,0x34,0x39, - 0x32,0x37,0x35,0x30,0x32,0x37,0x35,0x31, - 0x32,0x37,0x35,0x32,0x32,0x37,0x35,0x33, - 0x32,0x37,0x35,0x34,0x32,0x37,0x35,0x35, - 0x32,0x37,0x35,0x36,0x32,0x37,0x35,0x37, - 0x32,0x37,0x35,0x38,0x32,0x37,0x35,0x39, - 0x32,0x37,0x36,0x30,0x32,0x37,0x36,0x31, - 0x32,0x37,0x36,0x32,0x32,0x37,0x36,0x33, - 0x32,0x37,0x36,0x34,0x32,0x37,0x36,0x35, - 0x32,0x37,0x36,0x36,0x32,0x37,0x36,0x37, - 0x32,0x37,0x36,0x38,0x32,0x37,0x36,0x39, - 0x32,0x37,0x37,0x30,0x32,0x37,0x37,0x31, - 0x32,0x37,0x37,0x32,0x32,0x37,0x37,0x33, - 0x32,0x37,0x37,0x34,0x32,0x37,0x37,0x35, - 0x32,0x37,0x37,0x36,0x32,0x37,0x37,0x37, - 0x32,0x37,0x37,0x38,0x32,0x37,0x37,0x39, - 0x32,0x37,0x38,0x30,0x32,0x37,0x38,0x31, - 0x32,0x37,0x38,0x32,0x32,0x37,0x38,0x33, - 0x32,0x37,0x38,0x34,0x32,0x37,0x38,0x35, - 0x32,0x37,0x38,0x36,0x32,0x37,0x38,0x37, - 0x32,0x37,0x38,0x38,0x32,0x37,0x38,0x39, - 0x32,0x37,0x39,0x30,0x32,0x37,0x39,0x31, - 0x32,0x37,0x39,0x32,0x32,0x37,0x39,0x33, - 0x32,0x37,0x39,0x34,0x32,0x37,0x39,0x35, - 0x32,0x37,0x39,0x36,0x32,0x37,0x39,0x37, - 0x32,0x37,0x39,0x38,0x32,0x37,0x39,0x39, - 0x32,0x38,0x30,0x30,0x32,0x38,0x30,0x31, - 0x32,0x38,0x30,0x32,0x32,0x38,0x30,0x33, - 0x32,0x38,0x30,0x34,0x32,0x38,0x30,0x35, - 0x32,0x38,0x30,0x36,0x32,0x38,0x30,0x37, - 0x32,0x38,0x30,0x38,0x32,0x38,0x30,0x39, - 0x32,0x38,0x31,0x30,0x32,0x38,0x31,0x31, - 0x32,0x38,0x31,0x32,0x32,0x38,0x31,0x33, - 0x32,0x38,0x31,0x34,0x32,0x38,0x31,0x35, - 0x32,0x38,0x31,0x36,0x32,0x38,0x31,0x37, - 0x32,0x38,0x31,0x38,0x32,0x38,0x31,0x39, - 0x32,0x38,0x32,0x30,0x32,0x38,0x32,0x31, - 0x32,0x38,0x32,0x32,0x32,0x38,0x32,0x33, - 0x32,0x38,0x32,0x34,0x32,0x38,0x32,0x35, - 0x32,0x38,0x32,0x36,0x32,0x38,0x32,0x37, - 0x32,0x38,0x32,0x38,0x32,0x38,0x32,0x39, - 0x32,0x38,0x33,0x30,0x32,0x38,0x33,0x31, - 0x32,0x38,0x33,0x32,0x32,0x38,0x33,0x33, - 0x32,0x38,0x33,0x34,0x32,0x38,0x33,0x35, - 0x32,0x38,0x33,0x36,0x32,0x38,0x33,0x37, - 0x32,0x38,0x33,0x38,0x32,0x38,0x33,0x39, - 0x32,0x38,0x34,0x30,0x32,0x38,0x34,0x31, - 0x32,0x38,0x34,0x32,0x32,0x38,0x34,0x33, - 0x32,0x38,0x34,0x34,0x32,0x38,0x34,0x35, - 0x32,0x38,0x34,0x36,0x32,0x38,0x34,0x37, - 0x32,0x38,0x34,0x38,0x32,0x38,0x34,0x39, - 0x32,0x38,0x35,0x30,0x32,0x38,0x35,0x31, - 0x32,0x38,0x35,0x32,0x32,0x38,0x35,0x33, - 0x32,0x38,0x35,0x34,0x32,0x38,0x35,0x35, - 0x32,0x38,0x35,0x36,0x32,0x38,0x35,0x37, - 0x32,0x38,0x35,0x38,0x32,0x38,0x35,0x39, - 0x32,0x38,0x36,0x30,0x32,0x38,0x36,0x31, - 0x32,0x38,0x36,0x32,0x32,0x38,0x36,0x33, - 0x32,0x38,0x36,0x34,0x32,0x38,0x36,0x35, - 0x32,0x38,0x36,0x36,0x32,0x38,0x36,0x37, - 0x32,0x38,0x36,0x38,0x32,0x38,0x36,0x39, - 0x32,0x38,0x37,0x30,0x32,0x38,0x37,0x31, - 0x32,0x38,0x37,0x32,0x32,0x38,0x37,0x33, - 0x32,0x38,0x37,0x34,0x32,0x38,0x37,0x35, - 0x32,0x38,0x37,0x36,0x32,0x38,0x37,0x37, - 0x32,0x38,0x37,0x38,0x32,0x38,0x37,0x39, - 0x32,0x38,0x38,0x30,0x32,0x38,0x38,0x31, - 0x32,0x38,0x38,0x32,0x32,0x38,0x38,0x33, - 0x32,0x38,0x38,0x34,0x32,0x38,0x38,0x35, - 0x32,0x38,0x38,0x36,0x32,0x38,0x38,0x37, - 0x32,0x38,0x38,0x38,0x32,0x38,0x38,0x39, - 0x32,0x38,0x39,0x30,0x32,0x38,0x39,0x31, - 0x32,0x38,0x39,0x32,0x32,0x38,0x39,0x33, - 0x32,0x38,0x39,0x34,0x32,0x38,0x39,0x35, - 0x32,0x38,0x39,0x36,0x32,0x38,0x39,0x37, - 0x32,0x38,0x39,0x38,0x32,0x38,0x39,0x39, - 0x32,0x39,0x30,0x30,0x32,0x39,0x30,0x31, - 0x32,0x39,0x30,0x32,0x32,0x39,0x30,0x33, - 0x32,0x39,0x30,0x34,0x32,0x39,0x30,0x35, - 0x32,0x39,0x30,0x36,0x32,0x39,0x30,0x37, - 0x32,0x39,0x30,0x38,0x32,0x39,0x30,0x39, - 0x32,0x39,0x31,0x30,0x32,0x39,0x31,0x31, - 0x32,0x39,0x31,0x32,0x32,0x39,0x31,0x33, - 0x32,0x39,0x31,0x34,0x32,0x39,0x31,0x35, - 0x32,0x39,0x31,0x36,0x32,0x39,0x31,0x37, - 0x32,0x39,0x31,0x38,0x32,0x39,0x31,0x39, - 0x32,0x39,0x32,0x30,0x32,0x39,0x32,0x31, - 0x32,0x39,0x32,0x32,0x32,0x39,0x32,0x33, - 0x32,0x39,0x32,0x34,0x32,0x39,0x32,0x35, - 0x32,0x39,0x32,0x36,0x32,0x39,0x32,0x37, - 0x32,0x39,0x32,0x38,0x32,0x39,0x32,0x39, - 0x32,0x39,0x33,0x30,0x32,0x39,0x33,0x31, - 0x32,0x39,0x33,0x32,0x32,0x39,0x33,0x33, - 0x32,0x39,0x33,0x34,0x32,0x39,0x33,0x35, - 0x32,0x39,0x33,0x36,0x32,0x39,0x33,0x37, - 0x32,0x39,0x33,0x38,0x32,0x39,0x33,0x39, - 0x32,0x39,0x34,0x30,0x32,0x39,0x34,0x31, - 0x32,0x39,0x34,0x32,0x32,0x39,0x34,0x33, - 0x32,0x39,0x34,0x34,0x32,0x39,0x34,0x35, - 0x32,0x39,0x34,0x36,0x32,0x39,0x34,0x37, - 0x32,0x39,0x34,0x38,0x32,0x39,0x34,0x39, - 0x32,0x39,0x35,0x30,0x32,0x39,0x35,0x31, - 0x32,0x39,0x35,0x32,0x32,0x39,0x35,0x33, - 0x32,0x39,0x35,0x34,0x32,0x39,0x35,0x35, - 0x32,0x39,0x35,0x36,0x32,0x39,0x35,0x37, - 0x32,0x39,0x35,0x38,0x32,0x39,0x35,0x39, - 0x32,0x39,0x36,0x30,0x32,0x39,0x36,0x31, - 0x32,0x39,0x36,0x32,0x32,0x39,0x36,0x33, - 0x32,0x39,0x36,0x34,0x32,0x39,0x36,0x35, - 0x32,0x39,0x36,0x36,0x32,0x39,0x36,0x37, - 0x32,0x39,0x36,0x38,0x32,0x39,0x36,0x39, - 0x32,0x39,0x37,0x30,0x32,0x39,0x37,0x31, - 0x32,0x39,0x37,0x32,0x32,0x39,0x37,0x33, - 0x32,0x39,0x37,0x34,0x32,0x39,0x37,0x35, - 0x32,0x39,0x37,0x36,0x32,0x39,0x37,0x37, - 0x32,0x39,0x37,0x38,0x32,0x39,0x37,0x39, - 0x32,0x39,0x38,0x30,0x32,0x39,0x38,0x31, - 0x32,0x39,0x38,0x32,0x32,0x39,0x38,0x33, - 0x32,0x39,0x38,0x34,0x32,0x39,0x38,0x35, - 0x32,0x39,0x38,0x36,0x32,0x39,0x38,0x37, - 0x32,0x39,0x38,0x38,0x32,0x39,0x38,0x39, - 0x32,0x39,0x39,0x30,0x32,0x39,0x39,0x31, - 0x32,0x39,0x39,0x32,0x32,0x39,0x39,0x33, - 0x32,0x39,0x39,0x34,0x32,0x39,0x39,0x35, - 0x32,0x39,0x39,0x36,0x32,0x39,0x39,0x37, - 0x32,0x39,0x39,0x38,0x32,0x39,0x39,0x39, - 0x33,0x30,0x30,0x30,0x33,0x30,0x30,0x31, - 0x33,0x30,0x30,0x32,0x33,0x30,0x30,0x33, - 0x33,0x30,0x30,0x34,0x33,0x30,0x30,0x35, - 0x33,0x30,0x30,0x36,0x33,0x30,0x30,0x37, - 0x33,0x30,0x30,0x38,0x33,0x30,0x30,0x39, - 0x33,0x30,0x31,0x30,0x33,0x30,0x31,0x31, - 0x33,0x30,0x31,0x32,0x33,0x30,0x31,0x33, - 0x33,0x30,0x31,0x34,0x33,0x30,0x31,0x35, - 0x33,0x30,0x31,0x36,0x33,0x30,0x31,0x37, - 0x33,0x30,0x31,0x38,0x33,0x30,0x31,0x39, - 0x33,0x30,0x32,0x30,0x33,0x30,0x32,0x31, - 0x33,0x30,0x32,0x32,0x33,0x30,0x32,0x33, - 0x33,0x30,0x32,0x34,0x33,0x30,0x32,0x35, - 0x33,0x30,0x32,0x36,0x33,0x30,0x32,0x37, - 0x33,0x30,0x32,0x38,0x33,0x30,0x32,0x39, - 0x33,0x30,0x33,0x30,0x33,0x30,0x33,0x31, - 0x33,0x30,0x33,0x32,0x33,0x30,0x33,0x33, - 0x33,0x30,0x33,0x34,0x33,0x30,0x33,0x35, - 0x33,0x30,0x33,0x36,0x33,0x30,0x33,0x37, - 0x33,0x30,0x33,0x38,0x33,0x30,0x33,0x39, - 0x33,0x30,0x34,0x30,0x33,0x30,0x34,0x31, - 0x33,0x30,0x34,0x32,0x33,0x30,0x34,0x33, - 0x33,0x30,0x34,0x34,0x33,0x30,0x34,0x35, - 0x33,0x30,0x34,0x36,0x33,0x30,0x34,0x37, - 0x33,0x30,0x34,0x38,0x33,0x30,0x34,0x39, - 0x33,0x30,0x35,0x30,0x33,0x30,0x35,0x31, - 0x33,0x30,0x35,0x32,0x33,0x30,0x35,0x33, - 0x33,0x30,0x35,0x34,0x33,0x30,0x35,0x35, - 0x33,0x30,0x35,0x36,0x33,0x30,0x35,0x37, - 0x33,0x30,0x35,0x38,0x33,0x30,0x35,0x39, - 0x33,0x30,0x36,0x30,0x33,0x30,0x36,0x31, - 0x33,0x30,0x36,0x32,0x33,0x30,0x36,0x33, - 0x33,0x30,0x36,0x34,0x33,0x30,0x36,0x35, - 0x33,0x30,0x36,0x36,0x33,0x30,0x36,0x37, - 0x33,0x30,0x36,0x38,0x33,0x30,0x36,0x39, - 0x33,0x30,0x37,0x30,0x33,0x30,0x37,0x31, - 0x33,0x30,0x37,0x32,0x33,0x30,0x37,0x33, - 0x33,0x30,0x37,0x34,0x33,0x30,0x37,0x35, - 0x33,0x30,0x37,0x36,0x33,0x30,0x37,0x37, - 0x33,0x30,0x37,0x38,0x33,0x30,0x37,0x39, - 0x33,0x30,0x38,0x30,0x33,0x30,0x38,0x31, - 0x33,0x30,0x38,0x32,0x33,0x30,0x38,0x33, - 0x33,0x30,0x38,0x34,0x33,0x30,0x38,0x35, - 0x33,0x30,0x38,0x36,0x33,0x30,0x38,0x37, - 0x33,0x30,0x38,0x38,0x33,0x30,0x38,0x39, - 0x33,0x30,0x39,0x30,0x33,0x30,0x39,0x31, - 0x33,0x30,0x39,0x32,0x33,0x30,0x39,0x33, - 0x33,0x30,0x39,0x34,0x33,0x30,0x39,0x35, - 0x33,0x30,0x39,0x36,0x33,0x30,0x39,0x37, - 0x33,0x30,0x39,0x38,0x33,0x30,0x39,0x39, - 0x33,0x31,0x30,0x30,0x33,0x31,0x30,0x31, - 0x33,0x31,0x30,0x32,0x33,0x31,0x30,0x33, - 0x33,0x31,0x30,0x34,0x33,0x31,0x30,0x35, - 0x33,0x31,0x30,0x36,0x33,0x31,0x30,0x37, - 0x33,0x31,0x30,0x38,0x33,0x31,0x30,0x39, - 0x33,0x31,0x31,0x30,0x33,0x31,0x31,0x31, - 0x33,0x31,0x31,0x32,0x33,0x31,0x31,0x33, - 0x33,0x31,0x31,0x34,0x33,0x31,0x31,0x35, - 0x33,0x31,0x31,0x36,0x33,0x31,0x31,0x37, - 0x33,0x31,0x31,0x38,0x33,0x31,0x31,0x39, - 0x33,0x31,0x32,0x30,0x33,0x31,0x32,0x31, - 0x33,0x31,0x32,0x32,0x33,0x31,0x32,0x33, - 0x33,0x31,0x32,0x34,0x33,0x31,0x32,0x35, - 0x33,0x31,0x32,0x36,0x33,0x31,0x32,0x37, - 0x33,0x31,0x32,0x38,0x33,0x31,0x32,0x39, - 0x33,0x31,0x33,0x30,0x33,0x31,0x33,0x31, - 0x33,0x31,0x33,0x32,0x33,0x31,0x33,0x33, - 0x33,0x31,0x33,0x34,0x33,0x31,0x33,0x35, - 0x33,0x31,0x33,0x36,0x33,0x31,0x33,0x37, - 0x33,0x31,0x33,0x38,0x33,0x31,0x33,0x39, - 0x33,0x31,0x34,0x30,0x33,0x31,0x34,0x31, - 0x33,0x31,0x34,0x32,0x33,0x31,0x34,0x33, - 0x33,0x31,0x34,0x34,0x33,0x31,0x34,0x35, - 0x33,0x31,0x34,0x36,0x33,0x31,0x34,0x37, - 0x33,0x31,0x34,0x38,0x33,0x31,0x34,0x39, - 0x33,0x31,0x35,0x30,0x33,0x31,0x35,0x31, - 0x33,0x31,0x35,0x32,0x33,0x31,0x35,0x33, - 0x33,0x31,0x35,0x34,0x33,0x31,0x35,0x35, - 0x33,0x31,0x35,0x36,0x33,0x31,0x35,0x37, - 0x33,0x31,0x35,0x38,0x33,0x31,0x35,0x39, - 0x33,0x31,0x36,0x30,0x33,0x31,0x36,0x31, - 0x33,0x31,0x36,0x32,0x33,0x31,0x36,0x33, - 0x33,0x31,0x36,0x34,0x33,0x31,0x36,0x35, - 0x33,0x31,0x36,0x36,0x33,0x31,0x36,0x37, - 0x33,0x31,0x36,0x38,0x33,0x31,0x36,0x39, - 0x33,0x31,0x37,0x30,0x33,0x31,0x37,0x31, - 0x33,0x31,0x37,0x32,0x33,0x31,0x37,0x33, - 0x33,0x31,0x37,0x34,0x33,0x31,0x37,0x35, - 0x33,0x31,0x37,0x36,0x33,0x31,0x37,0x37, - 0x33,0x31,0x37,0x38,0x33,0x31,0x37,0x39, - 0x33,0x31,0x38,0x30,0x33,0x31,0x38,0x31, - 0x33,0x31,0x38,0x32,0x33,0x31,0x38,0x33, - 0x33,0x31,0x38,0x34,0x33,0x31,0x38,0x35, - 0x33,0x31,0x38,0x36,0x33,0x31,0x38,0x37, - 0x33,0x31,0x38,0x38,0x33,0x31,0x38,0x39, - 0x33,0x31,0x39,0x30,0x33,0x31,0x39,0x31, - 0x33,0x31,0x39,0x32,0x33,0x31,0x39,0x33, - 0x33,0x31,0x39,0x34,0x33,0x31,0x39,0x35, - 0x33,0x31,0x39,0x36,0x33,0x31,0x39,0x37, - 0x33,0x31,0x39,0x38,0x33,0x31,0x39,0x39, - 0x33,0x32,0x30,0x30,0x33,0x32,0x30,0x31, - 0x33,0x32,0x30,0x32,0x33,0x32,0x30,0x33, - 0x33,0x32,0x30,0x34,0x33,0x32,0x30,0x35, - 0x33,0x32,0x30,0x36,0x33,0x32,0x30,0x37, - 0x33,0x32,0x30,0x38,0x33,0x32,0x30,0x39, - 0x33,0x32,0x31,0x30,0x33,0x32,0x31,0x31, - 0x33,0x32,0x31,0x32,0x33,0x32,0x31,0x33, - 0x33,0x32,0x31,0x34,0x33,0x32,0x31,0x35, - 0x33,0x32,0x31,0x36,0x33,0x32,0x31,0x37, - 0x33,0x32,0x31,0x38,0x33,0x32,0x31,0x39, - 0x33,0x32,0x32,0x30,0x33,0x32,0x32,0x31, - 0x33,0x32,0x32,0x32,0x33,0x32,0x32,0x33, - 0x33,0x32,0x32,0x34,0x33,0x32,0x32,0x35, - 0x33,0x32,0x32,0x36,0x33,0x32,0x32,0x37, - 0x33,0x32,0x32,0x38,0x33,0x32,0x32,0x39, - 0x33,0x32,0x33,0x30,0x33,0x32,0x33,0x31, - 0x33,0x32,0x33,0x32,0x33,0x32,0x33,0x33, - 0x33,0x32,0x33,0x34,0x33,0x32,0x33,0x35, - 0x33,0x32,0x33,0x36,0x33,0x32,0x33,0x37, - 0x33,0x32,0x33,0x38,0x33,0x32,0x33,0x39, - 0x33,0x32,0x34,0x30,0x33,0x32,0x34,0x31, - 0x33,0x32,0x34,0x32,0x33,0x32,0x34,0x33, - 0x33,0x32,0x34,0x34,0x33,0x32,0x34,0x35, - 0x33,0x32,0x34,0x36,0x33,0x32,0x34,0x37, - 0x33,0x32,0x34,0x38,0x33,0x32,0x34,0x39, - 0x33,0x32,0x35,0x30,0x33,0x32,0x35,0x31, - 0x33,0x32,0x35,0x32,0x33,0x32,0x35,0x33, - 0x33,0x32,0x35,0x34,0x33,0x32,0x35,0x35, - 0x33,0x32,0x35,0x36,0x33,0x32,0x35,0x37, - 0x33,0x32,0x35,0x38,0x33,0x32,0x35,0x39, - 0x33,0x32,0x36,0x30,0x33,0x32,0x36,0x31, - 0x33,0x32,0x36,0x32,0x33,0x32,0x36,0x33, - 0x33,0x32,0x36,0x34,0x33,0x32,0x36,0x35, - 0x33,0x32,0x36,0x36,0x33,0x32,0x36,0x37, - 0x33,0x32,0x36,0x38,0x33,0x32,0x36,0x39, - 0x33,0x32,0x37,0x30,0x33,0x32,0x37,0x31, - 0x33,0x32,0x37,0x32,0x33,0x32,0x37,0x33, - 0x33,0x32,0x37,0x34,0x33,0x32,0x37,0x35, - 0x33,0x32,0x37,0x36,0x33,0x32,0x37,0x37, - 0x33,0x32,0x37,0x38,0x33,0x32,0x37,0x39, - 0x33,0x32,0x38,0x30,0x33,0x32,0x38,0x31, - 0x33,0x32,0x38,0x32,0x33,0x32,0x38,0x33, - 0x33,0x32,0x38,0x34,0x33,0x32,0x38,0x35, - 0x33,0x32,0x38,0x36,0x33,0x32,0x38,0x37, - 0x33,0x32,0x38,0x38,0x33,0x32,0x38,0x39, - 0x33,0x32,0x39,0x30,0x33,0x32,0x39,0x31, - 0x33,0x32,0x39,0x32,0x33,0x32,0x39,0x33, - 0x33,0x32,0x39,0x34,0x33,0x32,0x39,0x35, - 0x33,0x32,0x39,0x36,0x33,0x32,0x39,0x37, - 0x33,0x32,0x39,0x38,0x33,0x32,0x39,0x39, - 0x33,0x33,0x30,0x30,0x33,0x33,0x30,0x31, - 0x33,0x33,0x30,0x32,0x33,0x33,0x30,0x33, - 0x33,0x33,0x30,0x34,0x33,0x33,0x30,0x35, - 0x33,0x33,0x30,0x36,0x33,0x33,0x30,0x37, - 0x33,0x33,0x30,0x38,0x33,0x33,0x30,0x39, - 0x33,0x33,0x31,0x30,0x33,0x33,0x31,0x31, - 0x33,0x33,0x31,0x32,0x33,0x33,0x31,0x33, - 0x33,0x33,0x31,0x34,0x33,0x33,0x31,0x35, - 0x33,0x33,0x31,0x36,0x33,0x33,0x31,0x37, - 0x33,0x33,0x31,0x38,0x33,0x33,0x31,0x39, - 0x33,0x33,0x32,0x30,0x33,0x33,0x32,0x31, - 0x33,0x33,0x32,0x32,0x33,0x33,0x32,0x33, - 0x33,0x33,0x32,0x34,0x33,0x33,0x32,0x35, - 0x33,0x33,0x32,0x36,0x33,0x33,0x32,0x37, - 0x33,0x33,0x32,0x38,0x33,0x33,0x32,0x39, - 0x33,0x33,0x33,0x30,0x33,0x33,0x33,0x31, - 0x33,0x33,0x33,0x32,0x33,0x33,0x33,0x33, - 0x33,0x33,0x33,0x34,0x33,0x33,0x33,0x35, - 0x33,0x33,0x33,0x36,0x33,0x33,0x33,0x37, - 0x33,0x33,0x33,0x38,0x33,0x33,0x33,0x39, - 0x33,0x33,0x34,0x30,0x33,0x33,0x34,0x31, - 0x33,0x33,0x34,0x32,0x33,0x33,0x34,0x33, - 0x33,0x33,0x34,0x34,0x33,0x33,0x34,0x35, - 0x33,0x33,0x34,0x36,0x33,0x33,0x34,0x37, - 0x33,0x33,0x34,0x38,0x33,0x33,0x34,0x39, - 0x33,0x33,0x35,0x30,0x33,0x33,0x35,0x31, - 0x33,0x33,0x35,0x32,0x33,0x33,0x35,0x33, - 0x33,0x33,0x35,0x34,0x33,0x33,0x35,0x35, - 0x33,0x33,0x35,0x36,0x33,0x33,0x35,0x37, - 0x33,0x33,0x35,0x38,0x33,0x33,0x35,0x39, - 0x33,0x33,0x36,0x30,0x33,0x33,0x36,0x31, - 0x33,0x33,0x36,0x32,0x33,0x33,0x36,0x33, - 0x33,0x33,0x36,0x34,0x33,0x33,0x36,0x35, - 0x33,0x33,0x36,0x36,0x33,0x33,0x36,0x37, - 0x33,0x33,0x36,0x38,0x33,0x33,0x36,0x39, - 0x33,0x33,0x37,0x30,0x33,0x33,0x37,0x31, - 0x33,0x33,0x37,0x32,0x33,0x33,0x37,0x33, - 0x33,0x33,0x37,0x34,0x33,0x33,0x37,0x35, - 0x33,0x33,0x37,0x36,0x33,0x33,0x37,0x37, - 0x33,0x33,0x37,0x38,0x33,0x33,0x37,0x39, - 0x33,0x33,0x38,0x30,0x33,0x33,0x38,0x31, - 0x33,0x33,0x38,0x32,0x33,0x33,0x38,0x33, - 0x33,0x33,0x38,0x34,0x33,0x33,0x38,0x35, - 0x33,0x33,0x38,0x36,0x33,0x33,0x38,0x37, - 0x33,0x33,0x38,0x38,0x33,0x33,0x38,0x39, - 0x33,0x33,0x39,0x30,0x33,0x33,0x39,0x31, - 0x33,0x33,0x39,0x32,0x33,0x33,0x39,0x33, - 0x33,0x33,0x39,0x34,0x33,0x33,0x39,0x35, - 0x33,0x33,0x39,0x36,0x33,0x33,0x39,0x37, - 0x33,0x33,0x39,0x38,0x33,0x33,0x39,0x39, - 0x33,0x34,0x30,0x30,0x33,0x34,0x30,0x31, - 0x33,0x34,0x30,0x32,0x33,0x34,0x30,0x33, - 0x33,0x34,0x30,0x34,0x33,0x34,0x30,0x35, - 0x33,0x34,0x30,0x36,0x33,0x34,0x30,0x37, - 0x33,0x34,0x30,0x38,0x33,0x34,0x30,0x39, - 0x33,0x34,0x31,0x30,0x33,0x34,0x31,0x31, - 0x33,0x34,0x31,0x32,0x33,0x34,0x31,0x33, - 0x33,0x34,0x31,0x34,0x33,0x34,0x31,0x35, - 0x33,0x34,0x31,0x36,0x33,0x34,0x31,0x37, - 0x33,0x34,0x31,0x38,0x33,0x34,0x31,0x39, - 0x33,0x34,0x32,0x30,0x33,0x34,0x32,0x31, - 0x33,0x34,0x32,0x32,0x33,0x34,0x32,0x33, - 0x33,0x34,0x32,0x34,0x33,0x34,0x32,0x35, - 0x33,0x34,0x32,0x36,0x33,0x34,0x32,0x37, - 0x33,0x34,0x32,0x38,0x33,0x34,0x32,0x39, - 0x33,0x34,0x33,0x30,0x33,0x34,0x33,0x31, - 0x33,0x34,0x33,0x32,0x33,0x34,0x33,0x33, - 0x33,0x34,0x33,0x34,0x33,0x34,0x33,0x35, - 0x33,0x34,0x33,0x36,0x33,0x34,0x33,0x37, - 0x33,0x34,0x33,0x38,0x33,0x34,0x33,0x39, - 0x33,0x34,0x34,0x30,0x33,0x34,0x34,0x31, - 0x33,0x34,0x34,0x32,0x33,0x34,0x34,0x33, - 0x33,0x34,0x34,0x34,0x33,0x34,0x34,0x35, - 0x33,0x34,0x34,0x36,0x33,0x34,0x34,0x37, - 0x33,0x34,0x34,0x38,0x33,0x34,0x34,0x39, - 0x33,0x34,0x35,0x30,0x33,0x34,0x35,0x31, - 0x33,0x34,0x35,0x32,0x33,0x34,0x35,0x33, - 0x33,0x34,0x35,0x34,0x33,0x34,0x35,0x35, - 0x33,0x34,0x35,0x36,0x33,0x34,0x35,0x37, - 0x33,0x34,0x35,0x38,0x33,0x34,0x35,0x39, - 0x33,0x34,0x36,0x30,0x33,0x34,0x36,0x31, - 0x33,0x34,0x36,0x32,0x33,0x34,0x36,0x33, - 0x33,0x34,0x36,0x34,0x33,0x34,0x36,0x35, - 0x33,0x34,0x36,0x36,0x33,0x34,0x36,0x37, - 0x33,0x34,0x36,0x38,0x33,0x34,0x36,0x39, - 0x33,0x34,0x37,0x30,0x33,0x34,0x37,0x31, - 0x33,0x34,0x37,0x32,0x33,0x34,0x37,0x33, - 0x33,0x34,0x37,0x34,0x33,0x34,0x37,0x35, - 0x33,0x34,0x37,0x36,0x33,0x34,0x37,0x37, - 0x33,0x34,0x37,0x38,0x33,0x34,0x37,0x39, - 0x33,0x34,0x38,0x30,0x33,0x34,0x38,0x31, - 0x33,0x34,0x38,0x32,0x33,0x34,0x38,0x33, - 0x33,0x34,0x38,0x34,0x33,0x34,0x38,0x35, - 0x33,0x34,0x38,0x36,0x33,0x34,0x38,0x37, - 0x33,0x34,0x38,0x38,0x33,0x34,0x38,0x39, - 0x33,0x34,0x39,0x30,0x33,0x34,0x39,0x31, - 0x33,0x34,0x39,0x32,0x33,0x34,0x39,0x33, - 0x33,0x34,0x39,0x34,0x33,0x34,0x39,0x35, - 0x33,0x34,0x39,0x36,0x33,0x34,0x39,0x37, - 0x33,0x34,0x39,0x38,0x33,0x34,0x39,0x39, - 0x33,0x35,0x30,0x30,0x33,0x35,0x30,0x31, - 0x33,0x35,0x30,0x32,0x33,0x35,0x30,0x33, - 0x33,0x35,0x30,0x34,0x33,0x35,0x30,0x35, - 0x33,0x35,0x30,0x36,0x33,0x35,0x30,0x37, - 0x33,0x35,0x30,0x38,0x33,0x35,0x30,0x39, - 0x33,0x35,0x31,0x30,0x33,0x35,0x31,0x31, - 0x33,0x35,0x31,0x32,0x33,0x35,0x31,0x33, - 0x33,0x35,0x31,0x34,0x33,0x35,0x31,0x35, - 0x33,0x35,0x31,0x36,0x33,0x35,0x31,0x37, - 0x33,0x35,0x31,0x38,0x33,0x35,0x31,0x39, - 0x33,0x35,0x32,0x30,0x33,0x35,0x32,0x31, - 0x33,0x35,0x32,0x32,0x33,0x35,0x32,0x33, - 0x33,0x35,0x32,0x34,0x33,0x35,0x32,0x35, - 0x33,0x35,0x32,0x36,0x33,0x35,0x32,0x37, - 0x33,0x35,0x32,0x38,0x33,0x35,0x32,0x39, - 0x33,0x35,0x33,0x30,0x33,0x35,0x33,0x31, - 0x33,0x35,0x33,0x32,0x33,0x35,0x33,0x33, - 0x33,0x35,0x33,0x34,0x33,0x35,0x33,0x35, - 0x33,0x35,0x33,0x36,0x33,0x35,0x33,0x37, - 0x33,0x35,0x33,0x38,0x33,0x35,0x33,0x39, - 0x33,0x35,0x34,0x30,0x33,0x35,0x34,0x31, - 0x33,0x35,0x34,0x32,0x33,0x35,0x34,0x33, - 0x33,0x35,0x34,0x34,0x33,0x35,0x34,0x35, - 0x33,0x35,0x34,0x36,0x33,0x35,0x34,0x37, - 0x33,0x35,0x34,0x38,0x33,0x35,0x34,0x39, - 0x33,0x35,0x35,0x30,0x33,0x35,0x35,0x31, - 0x33,0x35,0x35,0x32,0x33,0x35,0x35,0x33, - 0x33,0x35,0x35,0x34,0x33,0x35,0x35,0x35, - 0x33,0x35,0x35,0x36,0x33,0x35,0x35,0x37, - 0x33,0x35,0x35,0x38,0x33,0x35,0x35,0x39, - 0x33,0x35,0x36,0x30,0x33,0x35,0x36,0x31, - 0x33,0x35,0x36,0x32,0x33,0x35,0x36,0x33, - 0x33,0x35,0x36,0x34,0x33,0x35,0x36,0x35, - 0x33,0x35,0x36,0x36,0x33,0x35,0x36,0x37, - 0x33,0x35,0x36,0x38,0x33,0x35,0x36,0x39, - 0x33,0x35,0x37,0x30,0x33,0x35,0x37,0x31, - 0x33,0x35,0x37,0x32,0x33,0x35,0x37,0x33, - 0x33,0x35,0x37,0x34,0x33,0x35,0x37,0x35, - 0x33,0x35,0x37,0x36,0x33,0x35,0x37,0x37, - 0x33,0x35,0x37,0x38,0x33,0x35,0x37,0x39, - 0x33,0x35,0x38,0x30,0x33,0x35,0x38,0x31, - 0x33,0x35,0x38,0x32,0x33,0x35,0x38,0x33, - 0x33,0x35,0x38,0x34,0x33,0x35,0x38,0x35, - 0x33,0x35,0x38,0x36,0x33,0x35,0x38,0x37, - 0x33,0x35,0x38,0x38,0x33,0x35,0x38,0x39, - 0x33,0x35,0x39,0x30,0x33,0x35,0x39,0x31, - 0x33,0x35,0x39,0x32,0x33,0x35,0x39,0x33, - 0x33,0x35,0x39,0x34,0x33,0x35,0x39,0x35, - 0x33,0x35,0x39,0x36,0x33,0x35,0x39,0x37, - 0x33,0x35,0x39,0x38,0x33,0x35,0x39,0x39, - 0x33,0x36,0x30,0x30,0x33,0x36,0x30,0x31, - 0x33,0x36,0x30,0x32,0x33,0x36,0x30,0x33, - 0x33,0x36,0x30,0x34,0x33,0x36,0x30,0x35, - 0x33,0x36,0x30,0x36,0x33,0x36,0x30,0x37, - 0x33,0x36,0x30,0x38,0x33,0x36,0x30,0x39, - 0x33,0x36,0x31,0x30,0x33,0x36,0x31,0x31, - 0x33,0x36,0x31,0x32,0x33,0x36,0x31,0x33, - 0x33,0x36,0x31,0x34,0x33,0x36,0x31,0x35, - 0x33,0x36,0x31,0x36,0x33,0x36,0x31,0x37, - 0x33,0x36,0x31,0x38,0x33,0x36,0x31,0x39, - 0x33,0x36,0x32,0x30,0x33,0x36,0x32,0x31, - 0x33,0x36,0x32,0x32,0x33,0x36,0x32,0x33, - 0x33,0x36,0x32,0x34,0x33,0x36,0x32,0x35, - 0x33,0x36,0x32,0x36,0x33,0x36,0x32,0x37, - 0x33,0x36,0x32,0x38,0x33,0x36,0x32,0x39, - 0x33,0x36,0x33,0x30,0x33,0x36,0x33,0x31, - 0x33,0x36,0x33,0x32,0x33,0x36,0x33,0x33, - 0x33,0x36,0x33,0x34,0x33,0x36,0x33,0x35, - 0x33,0x36,0x33,0x36,0x33,0x36,0x33,0x37, - 0x33,0x36,0x33,0x38,0x33,0x36,0x33,0x39, - 0x33,0x36,0x34,0x30,0x33,0x36,0x34,0x31, - 0x33,0x36,0x34,0x32,0x33,0x36,0x34,0x33, - 0x33,0x36,0x34,0x34,0x33,0x36,0x34,0x35, - 0x33,0x36,0x34,0x36,0x33,0x36,0x34,0x37, - 0x33,0x36,0x34,0x38,0x33,0x36,0x34,0x39, - 0x33,0x36,0x35,0x30,0x33,0x36,0x35,0x31, - 0x33,0x36,0x35,0x32,0x33,0x36,0x35,0x33, - 0x33,0x36,0x35,0x34,0x33,0x36,0x35,0x35, - 0x33,0x36,0x35,0x36,0x33,0x36,0x35,0x37, - 0x33,0x36,0x35,0x38,0x33,0x36,0x35,0x39, - 0x33,0x36,0x36,0x30,0x33,0x36,0x36,0x31, - 0x33,0x36,0x36,0x32,0x33,0x36,0x36,0x33, - 0x33,0x36,0x36,0x34,0x33,0x36,0x36,0x35, - 0x33,0x36,0x36,0x36,0x33,0x36,0x36,0x37, - 0x33,0x36,0x36,0x38,0x33,0x36,0x36,0x39, - 0x33,0x36,0x37,0x30,0x33,0x36,0x37,0x31, - 0x33,0x36,0x37,0x32,0x33,0x36,0x37,0x33, - 0x33,0x36,0x37,0x34,0x33,0x36,0x37,0x35, - 0x33,0x36,0x37,0x36,0x33,0x36,0x37,0x37, - 0x33,0x36,0x37,0x38,0x33,0x36,0x37,0x39, - 0x33,0x36,0x38,0x30,0x33,0x36,0x38,0x31, - 0x33,0x36,0x38,0x32,0x33,0x36,0x38,0x33, - 0x33,0x36,0x38,0x34,0x33,0x36,0x38,0x35, - 0x33,0x36,0x38,0x36,0x33,0x36,0x38,0x37, - 0x33,0x36,0x38,0x38,0x33,0x36,0x38,0x39, - 0x33,0x36,0x39,0x30,0x33,0x36,0x39,0x31, - 0x33,0x36,0x39,0x32,0x33,0x36,0x39,0x33, - 0x33,0x36,0x39,0x34,0x33,0x36,0x39,0x35, - 0x33,0x36,0x39,0x36,0x33,0x36,0x39,0x37, - 0x33,0x36,0x39,0x38,0x33,0x36,0x39,0x39, - 0x33,0x37,0x30,0x30,0x33,0x37,0x30,0x31, - 0x33,0x37,0x30,0x32,0x33,0x37,0x30,0x33, - 0x33,0x37,0x30,0x34,0x33,0x37,0x30,0x35, - 0x33,0x37,0x30,0x36,0x33,0x37,0x30,0x37, - 0x33,0x37,0x30,0x38,0x33,0x37,0x30,0x39, - 0x33,0x37,0x31,0x30,0x33,0x37,0x31,0x31, - 0x33,0x37,0x31,0x32,0x33,0x37,0x31,0x33, - 0x33,0x37,0x31,0x34,0x33,0x37,0x31,0x35, - 0x33,0x37,0x31,0x36,0x33,0x37,0x31,0x37, - 0x33,0x37,0x31,0x38,0x33,0x37,0x31,0x39, - 0x33,0x37,0x32,0x30,0x33,0x37,0x32,0x31, - 0x33,0x37,0x32,0x32,0x33,0x37,0x32,0x33, - 0x33,0x37,0x32,0x34,0x33,0x37,0x32,0x35, - 0x33,0x37,0x32,0x36,0x33,0x37,0x32,0x37, - 0x33,0x37,0x32,0x38,0x33,0x37,0x32,0x39, - 0x33,0x37,0x33,0x30,0x33,0x37,0x33,0x31, - 0x33,0x37,0x33,0x32,0x33,0x37,0x33,0x33, - 0x33,0x37,0x33,0x34,0x33,0x37,0x33,0x35, - 0x33,0x37,0x33,0x36,0x33,0x37,0x33,0x37, - 0x33,0x37,0x33,0x38,0x33,0x37,0x33,0x39, - 0x33,0x37,0x34,0x30,0x33,0x37,0x34,0x31, - 0x33,0x37,0x34,0x32,0x33,0x37,0x34,0x33, - 0x33,0x37,0x34,0x34,0x33,0x37,0x34,0x35, - 0x33,0x37,0x34,0x36,0x33,0x37,0x34,0x37, - 0x33,0x37,0x34,0x38,0x33,0x37,0x34,0x39, - 0x33,0x37,0x35,0x30,0x33,0x37,0x35,0x31, - 0x33,0x37,0x35,0x32,0x33,0x37,0x35,0x33, - 0x33,0x37,0x35,0x34,0x33,0x37,0x35,0x35, - 0x33,0x37,0x35,0x36,0x33,0x37,0x35,0x37, - 0x33,0x37,0x35,0x38,0x33,0x37,0x35,0x39, - 0x33,0x37,0x36,0x30,0x33,0x37,0x36,0x31, - 0x33,0x37,0x36,0x32,0x33,0x37,0x36,0x33, - 0x33,0x37,0x36,0x34,0x33,0x37,0x36,0x35, - 0x33,0x37,0x36,0x36,0x33,0x37,0x36,0x37, - 0x33,0x37,0x36,0x38,0x33,0x37,0x36,0x39, - 0x33,0x37,0x37,0x30,0x33,0x37,0x37,0x31, - 0x33,0x37,0x37,0x32,0x33,0x37,0x37,0x33, - 0x33,0x37,0x37,0x34,0x33,0x37,0x37,0x35, - 0x33,0x37,0x37,0x36,0x33,0x37,0x37,0x37, - 0x33,0x37,0x37,0x38,0x33,0x37,0x37,0x39, - 0x33,0x37,0x38,0x30,0x33,0x37,0x38,0x31, - 0x33,0x37,0x38,0x32,0x33,0x37,0x38,0x33, - 0x33,0x37,0x38,0x34,0x33,0x37,0x38,0x35, - 0x33,0x37,0x38,0x36,0x33,0x37,0x38,0x37, - 0x33,0x37,0x38,0x38,0x33,0x37,0x38,0x39, - 0x33,0x37,0x39,0x30,0x33,0x37,0x39,0x31, - 0x33,0x37,0x39,0x32,0x33,0x37,0x39,0x33, - 0x33,0x37,0x39,0x34,0x33,0x37,0x39,0x35, - 0x33,0x37,0x39,0x36,0x33,0x37,0x39,0x37, - 0x33,0x37,0x39,0x38,0x33,0x37,0x39,0x39, - 0x33,0x38,0x30,0x30,0x33,0x38,0x30,0x31, - 0x33,0x38,0x30,0x32,0x33,0x38,0x30,0x33, - 0x33,0x38,0x30,0x34,0x33,0x38,0x30,0x35, - 0x33,0x38,0x30,0x36,0x33,0x38,0x30,0x37, - 0x33,0x38,0x30,0x38,0x33,0x38,0x30,0x39, - 0x33,0x38,0x31,0x30,0x33,0x38,0x31,0x31, - 0x33,0x38,0x31,0x32,0x33,0x38,0x31,0x33, - 0x33,0x38,0x31,0x34,0x33,0x38,0x31,0x35, - 0x33,0x38,0x31,0x36,0x33,0x38,0x31,0x37, - 0x33,0x38,0x31,0x38,0x33,0x38,0x31,0x39, - 0x33,0x38,0x32,0x30,0x33,0x38,0x32,0x31, - 0x33,0x38,0x32,0x32,0x33,0x38,0x32,0x33, - 0x33,0x38,0x32,0x34,0x33,0x38,0x32,0x35, - 0x33,0x38,0x32,0x36,0x33,0x38,0x32,0x37, - 0x33,0x38,0x32,0x38,0x33,0x38,0x32,0x39, - 0x33,0x38,0x33,0x30,0x33,0x38,0x33,0x31, - 0x33,0x38,0x33,0x32,0x33,0x38,0x33,0x33, - 0x33,0x38,0x33,0x34,0x33,0x38,0x33,0x35, - 0x33,0x38,0x33,0x36,0x33,0x38,0x33,0x37, - 0x33,0x38,0x33,0x38,0x33,0x38,0x33,0x39, - 0x33,0x38,0x34,0x30,0x33,0x38,0x34,0x31, - 0x33,0x38,0x34,0x32,0x33,0x38,0x34,0x33, - 0x33,0x38,0x34,0x34,0x33,0x38,0x34,0x35, - 0x33,0x38,0x34,0x36,0x33,0x38,0x34,0x37, - 0x33,0x38,0x34,0x38,0x33,0x38,0x34,0x39, - 0x33,0x38,0x35,0x30,0x33,0x38,0x35,0x31, - 0x33,0x38,0x35,0x32,0x33,0x38,0x35,0x33, - 0x33,0x38,0x35,0x34,0x33,0x38,0x35,0x35, - 0x33,0x38,0x35,0x36,0x33,0x38,0x35,0x37, - 0x33,0x38,0x35,0x38,0x33,0x38,0x35,0x39, - 0x33,0x38,0x36,0x30,0x33,0x38,0x36,0x31, - 0x33,0x38,0x36,0x32,0x33,0x38,0x36,0x33, - 0x33,0x38,0x36,0x34,0x33,0x38,0x36,0x35, - 0x33,0x38,0x36,0x36,0x33,0x38,0x36,0x37, - 0x33,0x38,0x36,0x38,0x33,0x38,0x36,0x39, - 0x33,0x38,0x37,0x30,0x33,0x38,0x37,0x31, - 0x33,0x38,0x37,0x32,0x33,0x38,0x37,0x33, - 0x33,0x38,0x37,0x34,0x33,0x38,0x37,0x35, - 0x33,0x38,0x37,0x36,0x33,0x38,0x37,0x37, - 0x33,0x38,0x37,0x38,0x33,0x38,0x37,0x39, - 0x33,0x38,0x38,0x30,0x33,0x38,0x38,0x31, - 0x33,0x38,0x38,0x32,0x33,0x38,0x38,0x33, - 0x33,0x38,0x38,0x34,0x33,0x38,0x38,0x35, - 0x33,0x38,0x38,0x36,0x33,0x38,0x38,0x37, - 0x33,0x38,0x38,0x38,0x33,0x38,0x38,0x39, - 0x33,0x38,0x39,0x30,0x33,0x38,0x39,0x31, - 0x33,0x38,0x39,0x32,0x33,0x38,0x39,0x33, - 0x33,0x38,0x39,0x34,0x33,0x38,0x39,0x35, - 0x33,0x38,0x39,0x36,0x33,0x38,0x39,0x37, - 0x33,0x38,0x39,0x38,0x33,0x38,0x39,0x39, - 0x33,0x39,0x30,0x30,0x33,0x39,0x30,0x31, - 0x33,0x39,0x30,0x32,0x33,0x39,0x30,0x33, - 0x33,0x39,0x30,0x34,0x33,0x39,0x30,0x35, - 0x33,0x39,0x30,0x36,0x33,0x39,0x30,0x37, - 0x33,0x39,0x30,0x38,0x33,0x39,0x30,0x39, - 0x33,0x39,0x31,0x30,0x33,0x39,0x31,0x31, - 0x33,0x39,0x31,0x32,0x33,0x39,0x31,0x33, - 0x33,0x39,0x31,0x34,0x33,0x39,0x31,0x35, - 0x33,0x39,0x31,0x36,0x33,0x39,0x31,0x37, - 0x33,0x39,0x31,0x38,0x33,0x39,0x31,0x39, - 0x33,0x39,0x32,0x30,0x33,0x39,0x32,0x31, - 0x33,0x39,0x32,0x32,0x33,0x39,0x32,0x33, - 0x33,0x39,0x32,0x34,0x33,0x39,0x32,0x35, - 0x33,0x39,0x32,0x36,0x33,0x39,0x32,0x37, - 0x33,0x39,0x32,0x38,0x33,0x39,0x32,0x39, - 0x33,0x39,0x33,0x30,0x33,0x39,0x33,0x31, - 0x33,0x39,0x33,0x32,0x33,0x39,0x33,0x33, - 0x33,0x39,0x33,0x34,0x33,0x39,0x33,0x35, - 0x33,0x39,0x33,0x36,0x33,0x39,0x33,0x37, - 0x33,0x39,0x33,0x38,0x33,0x39,0x33,0x39, - 0x33,0x39,0x34,0x30,0x33,0x39,0x34,0x31, - 0x33,0x39,0x34,0x32,0x33,0x39,0x34,0x33, - 0x33,0x39,0x34,0x34,0x33,0x39,0x34,0x35, - 0x33,0x39,0x34,0x36,0x33,0x39,0x34,0x37, - 0x33,0x39,0x34,0x38,0x33,0x39,0x34,0x39, - 0x33,0x39,0x35,0x30,0x33,0x39,0x35,0x31, - 0x33,0x39,0x35,0x32,0x33,0x39,0x35,0x33, - 0x33,0x39,0x35,0x34,0x33,0x39,0x35,0x35, - 0x33,0x39,0x35,0x36,0x33,0x39,0x35,0x37, - 0x33,0x39,0x35,0x38,0x33,0x39,0x35,0x39, - 0x33,0x39,0x36,0x30,0x33,0x39,0x36,0x31, - 0x33,0x39,0x36,0x32,0x33,0x39,0x36,0x33, - 0x33,0x39,0x36,0x34,0x33,0x39,0x36,0x35, - 0x33,0x39,0x36,0x36,0x33,0x39,0x36,0x37, - 0x33,0x39,0x36,0x38,0x33,0x39,0x36,0x39, - 0x33,0x39,0x37,0x30,0x33,0x39,0x37,0x31, - 0x33,0x39,0x37,0x32,0x33,0x39,0x37,0x33, - 0x33,0x39,0x37,0x34,0x33,0x39,0x37,0x35, - 0x33,0x39,0x37,0x36,0x33,0x39,0x37,0x37, - 0x33,0x39,0x37,0x38,0x33,0x39,0x37,0x39, - 0x33,0x39,0x38,0x30,0x33,0x39,0x38,0x31, - 0x33,0x39,0x38,0x32,0x33,0x39,0x38,0x33, - 0x33,0x39,0x38,0x34,0x33,0x39,0x38,0x35, - 0x33,0x39,0x38,0x36,0x33,0x39,0x38,0x37, - 0x33,0x39,0x38,0x38,0x33,0x39,0x38,0x39, - 0x33,0x39,0x39,0x30,0x33,0x39,0x39,0x31, - 0x33,0x39,0x39,0x32,0x33,0x39,0x39,0x33, - 0x33,0x39,0x39,0x34,0x33,0x39,0x39,0x35, - 0x33,0x39,0x39,0x36,0x33,0x39,0x39,0x37, - 0x33,0x39,0x39,0x38,0x33,0x39,0x39,0x39, - 0x34,0x30,0x30,0x30,0x34,0x30,0x30,0x31, - 0x34,0x30,0x30,0x32,0x34,0x30,0x30,0x33, - 0x34,0x30,0x30,0x34,0x34,0x30,0x30,0x35, - 0x34,0x30,0x30,0x36,0x34,0x30,0x30,0x37, - 0x34,0x30,0x30,0x38,0x34,0x30,0x30,0x39, - 0x34,0x30,0x31,0x30,0x34,0x30,0x31,0x31, - 0x34,0x30,0x31,0x32,0x34,0x30,0x31,0x33, - 0x34,0x30,0x31,0x34,0x34,0x30,0x31,0x35, - 0x34,0x30,0x31,0x36,0x34,0x30,0x31,0x37, - 0x34,0x30,0x31,0x38,0x34,0x30,0x31,0x39, - 0x34,0x30,0x32,0x30,0x34,0x30,0x32,0x31, - 0x34,0x30,0x32,0x32,0x34,0x30,0x32,0x33, - 0x34,0x30,0x32,0x34,0x34,0x30,0x32,0x35, - 0x34,0x30,0x32,0x36,0x34,0x30,0x32,0x37, - 0x34,0x30,0x32,0x38,0x34,0x30,0x32,0x39, - 0x34,0x30,0x33,0x30,0x34,0x30,0x33,0x31, - 0x34,0x30,0x33,0x32,0x34,0x30,0x33,0x33, - 0x34,0x30,0x33,0x34,0x34,0x30,0x33,0x35, - 0x34,0x30,0x33,0x36,0x34,0x30,0x33,0x37, - 0x34,0x30,0x33,0x38,0x34,0x30,0x33,0x39, - 0x34,0x30,0x34,0x30,0x34,0x30,0x34,0x31, - 0x34,0x30,0x34,0x32,0x34,0x30,0x34,0x33, - 0x34,0x30,0x34,0x34,0x34,0x30,0x34,0x35, - 0x34,0x30,0x34,0x36,0x34,0x30,0x34,0x37, - 0x34,0x30,0x34,0x38,0x34,0x30,0x34,0x39, - 0x34,0x30,0x35,0x30,0x34,0x30,0x35,0x31, - 0x34,0x30,0x35,0x32,0x34,0x30,0x35,0x33, - 0x34,0x30,0x35,0x34,0x34,0x30,0x35,0x35, - 0x34,0x30,0x35,0x36,0x34,0x30,0x35,0x37, - 0x34,0x30,0x35,0x38,0x34,0x30,0x35,0x39, - 0x34,0x30,0x36,0x30,0x34,0x30,0x36,0x31, - 0x34,0x30,0x36,0x32,0x34,0x30,0x36,0x33, - 0x34,0x30,0x36,0x34,0x34,0x30,0x36,0x35, - 0x34,0x30,0x36,0x36,0x34,0x30,0x36,0x37, - 0x34,0x30,0x36,0x38,0x34,0x30,0x36,0x39, - 0x34,0x30,0x37,0x30,0x34,0x30,0x37,0x31, - 0x34,0x30,0x37,0x32,0x34,0x30,0x37,0x33, - 0x34,0x30,0x37,0x34,0x34,0x30,0x37,0x35, - 0x34,0x30,0x37,0x36,0x34,0x30,0x37,0x37, - 0x34,0x30,0x37,0x38,0x34,0x30,0x37,0x39, - 0x34,0x30,0x38,0x30,0x34,0x30,0x38,0x31, - 0x34,0x30,0x38,0x32,0x34,0x30,0x38,0x33, - 0x34,0x30,0x38,0x34,0x34,0x30,0x38,0x35, - 0x34,0x30,0x38,0x36,0x34,0x30,0x38,0x37, - 0x34,0x30,0x38,0x38,0x34,0x30,0x38,0x39, - 0x34,0x30,0x39,0x30,0x34,0x30,0x39,0x31, - 0x34,0x30,0x39,0x32,0x34,0x30,0x39,0x33, - 0x34,0x30,0x39,0x34,0x34,0x30,0x39,0x35}; - - static const int32_t gDigitCount[] = { - 1,1,1,1,1,1,1,1, - 1,1,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2, - 2,2,2,2,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4}; - -U_NAMESPACE_BEGIN - - -IntDigitCountRange::IntDigitCountRange(int32_t min, int32_t max) { - fMin = min < 0 ? 0 : min; - fMax = max < fMin ? fMin : max; -} - -int32_t -IntDigitCountRange::pin(int32_t digitCount) const { - return digitCount < fMin ? fMin : (digitCount < fMax ? digitCount : fMax); -} - -int32_t -SmallIntFormatter::estimateDigitCount( - int32_t positiveValue, const IntDigitCountRange &range) { - if (positiveValue >= gMaxFastInt) { - return range.getMax(); - } - return range.pin(gDigitCount[positiveValue]); -} - -UBool -SmallIntFormatter::canFormat( - int32_t positiveValue, const IntDigitCountRange &range) { - return (positiveValue < gMaxFastInt && range.getMin() <= 4); -} - -UnicodeString & -SmallIntFormatter::format( - int32_t smallPositiveValue, - const IntDigitCountRange &range, - UnicodeString &appendTo) { - int32_t digits = range.pin(gDigitCount[smallPositiveValue]); - - // Always emit at least '0' - if (digits == 0) { - return appendTo.append((UChar) 0x30); - } - return appendTo.append(gDigits, ((smallPositiveValue + 1) << 2) - digits, digits); -} - -U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/smallintformatter.h b/deps/icu-small/source/i18n/smallintformatter.h deleted file mode 100644 index 3373a9c35f..0000000000 --- a/deps/icu-small/source/i18n/smallintformatter.h +++ /dev/null @@ -1,90 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* smallintformatter.h -* -* created on: 2015jan06 -* created by: Travis Keep -*/ - -#ifndef __SMALLINTFORMATTER_H__ -#define __SMALLINTFORMATTER_H__ - -#include "unicode/uobject.h" -#include "unicode/utypes.h" - -U_NAMESPACE_BEGIN - -class UnicodeString; - -/** - * A representation an acceptable range of digit counts for integers. - */ -class U_I18N_API IntDigitCountRange : public UMemory { -public: - /** - * No constraints: 0 up to INT32_MAX - */ - IntDigitCountRange() : fMin(0), fMax(INT32_MAX) { } - IntDigitCountRange(int32_t min, int32_t max); - int32_t pin(int32_t digitCount) const; - int32_t getMax() const { return fMax; } - int32_t getMin() const { return fMin; } -private: - int32_t fMin; - int32_t fMax; -}; - - -/** - * A formatter for small, positive integers. - */ -class U_I18N_API SmallIntFormatter : public UMemory { -public: - /** - * Estimates the actual digit count needed to format positiveValue - * using the given range of digit counts. - * Returns a value that is at least the actual digit count needed. - * - * @param positiveValue the value to format - * @param range the acceptable range of digit counts. - */ - static int32_t estimateDigitCount( - int32_t positiveValue, const IntDigitCountRange &range); - - /** - * Returns TRUE if this class can format positiveValue using - * the given range of digit counts. - * - * @param positiveValue the value to format - * @param range the acceptable range of digit counts. - */ - static UBool canFormat( - int32_t positiveValue, const IntDigitCountRange &range); - - /** - * Formats positiveValue using the given range of digit counts. - * Always uses standard digits '0' through '9'. Formatted value is - * left padded with '0' as necessary to achieve minimum digit count. - * Does not produce any grouping separators or trailing decimal point. - * Calling format to format a value with a particular digit count range - * when canFormat indicates that the same value and digit count range - * cannot be formatted results in undefined behavior. - * - * @param positiveValue the value to format - * @param range the acceptable range of digit counts. - */ - static UnicodeString &format( - int32_t positiveValue, - const IntDigitCountRange &range, - UnicodeString &appendTo); - -}; - -U_NAMESPACE_END - -#endif // __SMALLINTFORMATTER_H__ diff --git a/deps/icu-small/source/i18n/smpdtfmt.cpp b/deps/icu-small/source/i18n/smpdtfmt.cpp index 27fbbd8f7a..b1b90882fc 100644 --- a/deps/icu-small/source/i18n/smpdtfmt.cpp +++ b/deps/icu-small/source/i18n/smpdtfmt.cpp @@ -53,6 +53,7 @@ #include "unicode/vtzone.h" #include "unicode/udisplaycontext.h" #include "unicode/brkiter.h" +#include "unicode/rbnf.h" #include "uresimp.h" #include "olsontz.h" #include "patternprops.h" @@ -72,6 +73,7 @@ #include "cstr.h" #include "dayperiodrules.h" #include "tznames_impl.h" // ZONE_NAME_U16_MAX +#include "number_utypes.h" #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL) #include @@ -312,57 +314,6 @@ const NumberFormat *SimpleDateFormat::getNumberFormatByIndex( return &(**fSharedNumberFormatters[index]); } -class SimpleDateFormatMutableNFNode { - public: - const NumberFormat *key; - NumberFormat *value; - SimpleDateFormatMutableNFNode() - : key(NULL), value(NULL) { } - ~SimpleDateFormatMutableNFNode() { - delete value; - } - private: - SimpleDateFormatMutableNFNode(const SimpleDateFormatMutableNFNode &); - SimpleDateFormatMutableNFNode &operator=(const SimpleDateFormatMutableNFNode &); -}; - -// Single threaded cache of non const NumberFormats. Designed to be stack -// allocated and used for a single format call. -class SimpleDateFormatMutableNFs : public UMemory { - public: - SimpleDateFormatMutableNFs() { - } - - // Returns a non-const clone of nf which can be safely modified. - // Subsequent calls with same nf will return the same non-const clone. - // This object maintains ownership of all returned non-const - // NumberFormat objects. On memory allocation error returns NULL. - // Caller must check for NULL return value. - NumberFormat *get(const NumberFormat *nf) { - if (nf == NULL) { - return NULL; - } - int32_t idx = 0; - while (nodes[idx].value) { - if (nf == nodes[idx].key) { - return nodes[idx].value; - } - ++idx; - } - U_ASSERT(idx < UDAT_FIELD_COUNT); - nodes[idx].key = nf; - nodes[idx].value = (NumberFormat *) nf->clone(); - return nodes[idx].value; - } - private: - // +1 extra for sentinel. If each field had its own NumberFormat, this - // cache would have to allocate UDAT_FIELD_COUNT mutable versions worst - // case. - SimpleDateFormatMutableNFNode nodes[UDAT_FIELD_COUNT + 1]; - SimpleDateFormatMutableNFs(const SimpleDateFormatMutableNFs &); - SimpleDateFormatMutableNFs &operator=(const SimpleDateFormatMutableNFs &); -}; - //---------------------------------------------------------------------- SimpleDateFormat::~SimpleDateFormat() @@ -374,6 +325,7 @@ SimpleDateFormat::~SimpleDateFormat() if (fTimeZoneFormat) { delete fTimeZoneFormat; } + freeFastNumberFormatters(); #if !UCONFIG_NO_BREAK_ITERATION delete fCapitalizationBrkIter; @@ -659,6 +611,10 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other) } } + UErrorCode localStatus = U_ZERO_ERROR; + freeFastNumberFormatters(); + initFastNumberFormatters(localStatus); + return *this; } @@ -908,7 +864,8 @@ SimpleDateFormat::initialize(const Locale& locale, fixNumberFormatForDates(*fNumberFormat); //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse - initNumberFormatters(locale,status); + initNumberFormatters(locale, status); + initFastNumberFormatters(status); } else if (U_SUCCESS(status)) @@ -1023,11 +980,6 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, int32_t fieldNum = 0; UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status); - // Create temporary cache of mutable number format objects. This way - // subFormat won't have to clone the const NumberFormat for each field. - // if several fields share the same NumberFormat, which will almost - // always be the case, this is a big save. - SimpleDateFormatMutableNFs mutableNFs; // loop through the pattern string character by character for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) { UChar ch = fPattern[i]; @@ -1035,7 +987,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, // Use subFormat() to format a repeated pattern character // when a different pattern or non-pattern character is seen if (ch != prevCh && count > 0) { - subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status); + subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status); count = 0; } if (ch == QUOTE) { @@ -1062,7 +1014,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, // Format the last item in the pattern, if any if (count > 0) { - subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status); + subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status); } if (calClone != NULL) { @@ -1257,6 +1209,43 @@ _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeSt } //---------------------------------------------------------------------- + +static number::LocalizedNumberFormatter* +createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt) { + return new number::LocalizedNumberFormatter( + df->toNumberFormatter() + .integerWidth(number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt))); +} + +void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) { + if (U_FAILURE(status)) { + return; + } + auto* df = dynamic_cast(fNumberFormat); + if (df == nullptr) { + return; + } + fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10); + fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10); + fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10); + fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10); + fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2); +} + +void SimpleDateFormat::freeFastNumberFormatters() { + delete fFastNumberFormatters[SMPDTFMT_NF_1x10]; + delete fFastNumberFormatters[SMPDTFMT_NF_2x10]; + delete fFastNumberFormatters[SMPDTFMT_NF_3x10]; + delete fFastNumberFormatters[SMPDTFMT_NF_4x10]; + delete fFastNumberFormatters[SMPDTFMT_NF_2x2]; + fFastNumberFormatters[SMPDTFMT_NF_1x10] = nullptr; + fFastNumberFormatters[SMPDTFMT_NF_2x10] = nullptr; + fFastNumberFormatters[SMPDTFMT_NF_3x10] = nullptr; + fFastNumberFormatters[SMPDTFMT_NF_4x10] = nullptr; + fFastNumberFormatters[SMPDTFMT_NF_2x2] = nullptr; +} + + void SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) { if (U_FAILURE(status)) { @@ -1406,7 +1395,6 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, int32_t fieldNum, FieldPositionHandler& handler, Calendar& cal, - SimpleDateFormatMutableNFs &mutableNFs, UErrorCode& status) const { if (U_FAILURE(status)) { @@ -1419,7 +1407,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch); const int32_t maxIntCount = 10; int32_t beginOffset = appendTo.length(); - NumberFormat *currentNumberFormat; + const NumberFormat *currentNumberFormat; DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther; UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0); @@ -1444,9 +1432,9 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, return; } - currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex)); + currentNumberFormat = getNumberFormatByIndex(patternCharIndex); if (currentNumberFormat == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; + status = U_INTERNAL_PROGRAM_ERROR; return; } UnicodeString hebr("hebr", 4, US_INV); @@ -1566,18 +1554,15 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, case UDAT_FRACTIONAL_SECOND_FIELD: // Fractional seconds left-justify { - currentNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count); - currentNumberFormat->setMaximumIntegerDigits(maxIntCount); + int32_t minDigits = (count > 3) ? 3 : count; if (count == 1) { value /= 100; } else if (count == 2) { value /= 10; } - FieldPosition p(FieldPosition::DONT_CARE); - currentNumberFormat->format(value, appendTo, p); + zeroPaddingNumber(currentNumberFormat, appendTo, value, minDigits, maxIntCount); if (count > 3) { - currentNumberFormat->setMinimumIntegerDigits(count - 3); - currentNumberFormat->format((int32_t)0, appendTo, p); + zeroPaddingNumber(currentNumberFormat, appendTo, 0, count - 3, maxIntCount); } } break; @@ -1695,100 +1680,101 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf)); const TimeZone& tz = cal.getTimeZone(); UDate date = cal.getTime(status); + const TimeZoneFormat *tzfmt = tzFormat(status); if (U_SUCCESS(status)) { if (patternCharIndex == UDAT_TIMEZONE_FIELD) { if (count < 4) { // "z", "zz", "zzz" - tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString); capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort; } else { // "zzzz" or longer - tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString); capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong; } } else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) { if (count < 4) { // "Z" - tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString); } else if (count == 5) { // "ZZZZZ" - tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString); } else { // "ZZ", "ZZZ", "ZZZZ" - tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString); } } else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) { if (count == 1) { // "v" - tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString); capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort; } else if (count == 4) { // "vvvv" - tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString); capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong; } } else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) { if (count == 1) { // "V" - tzFormat()->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString); } else if (count == 2) { // "VV" - tzFormat()->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString); } else if (count == 3) { // "VVV" - tzFormat()->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString); } else if (count == 4) { // "VVVV" - tzFormat()->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString); capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong; } } else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) { if (count == 1) { // "O" - tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString); } else if (count == 4) { // "OOOO" - tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString); } } else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) { if (count == 1) { // "X" - tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString); } else if (count == 2) { // "XX" - tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString); } else if (count == 3) { // "XXX" - tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString); } else if (count == 4) { // "XXXX" - tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString); } else if (count == 5) { // "XXXXX" - tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString); } } else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) { if (count == 1) { // "x" - tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString); } else if (count == 2) { // "xx" - tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString); } else if (count == 3) { // "xxx" - tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString); } else if (count == 4) { // "xxxx" - tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString); } else if (count == 5) { // "xxxxx" - tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString); + tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString); } } else { @@ -1855,7 +1841,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, if (toAppend == NULL || toAppend->isBogus()) { // Reformat with identical arguments except ch, now changed to 'a'. subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum, - handler, cal, mutableNFs, status); + handler, cal, status); } else { appendTo += *toAppend; } @@ -1876,7 +1862,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, // Data doesn't exist for the locale we're looking for. // Falling back to am/pm. subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum, - handler, cal, mutableNFs, status); + handler, cal, status); break; } @@ -1947,7 +1933,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, periodType == DayPeriodRules::DAYPERIOD_PM || toAppend->isBogus()) { subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum, - handler, cal, mutableNFs, status); + handler, cal, status); } else { appendTo += *toAppend; @@ -2004,6 +1990,11 @@ void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) { freeSharedNumberFormatters(fSharedNumberFormatters); fSharedNumberFormatters = NULL; } + + // Also re-compute the fast formatters. + UErrorCode localStatus = U_ZERO_ERROR; + freeFastNumberFormatters(); + initFastNumberFormatters(localStatus); } void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){ @@ -2055,16 +2046,58 @@ SimpleDateFormat::getNumberFormatForField(UChar field) const { //---------------------------------------------------------------------- void SimpleDateFormat::zeroPaddingNumber( - NumberFormat *currentNumberFormat, + const NumberFormat *currentNumberFormat, UnicodeString &appendTo, int32_t value, int32_t minDigits, int32_t maxDigits) const { - if (currentNumberFormat!=NULL) { + const number::LocalizedNumberFormatter* fastFormatter = nullptr; + // NOTE: This uses the heuristic that these five min/max int settings account for the vast majority + // of SimpleDateFormat number formatting cases at the time of writing (ICU 62). + if (currentNumberFormat == fNumberFormat) { + if (maxDigits == 10) { + if (minDigits == 1) { + fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_1x10]; + } else if (minDigits == 2) { + fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x10]; + } else if (minDigits == 3) { + fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_3x10]; + } else if (minDigits == 4) { + fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_4x10]; + } + } else if (maxDigits == 2) { + if (minDigits == 2) { + fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x2]; + } + } + } + if (fastFormatter != nullptr) { + // Can use fast path + number::impl::UFormattedNumberData result; + result.quantity.setToInt(value); + UErrorCode localStatus = U_ZERO_ERROR; + fastFormatter->formatImpl(&result, localStatus); + if (U_FAILURE(localStatus)) { + return; + } + appendTo.append(result.string.toTempUnicodeString()); + return; + } + + // Check for RBNF (no clone necessary) + auto* rbnf = dynamic_cast(currentNumberFormat); + if (rbnf != nullptr) { FieldPosition pos(FieldPosition::DONT_CARE); + rbnf->format(value, appendTo, pos); // 3rd arg is there to speed up processing + return; + } - currentNumberFormat->setMinimumIntegerDigits(minDigits); - currentNumberFormat->setMaximumIntegerDigits(maxDigits); - currentNumberFormat->format(value, appendTo, pos); // 3rd arg is there to speed up processing + // Fall back to slow path (clone and mutate the NumberFormat) + if (currentNumberFormat != nullptr) { + FieldPosition pos(FieldPosition::DONT_CARE); + LocalPointer nf(dynamic_cast(currentNumberFormat->clone())); + nf->setMinimumIntegerDigits(minDigits); + nf->setMaximumIntegerDigits(maxDigits); + nf->format(value, appendTo, pos); // 3rd arg is there to speed up processing } } @@ -2131,7 +2164,6 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& int32_t saveHebrewMonth = -1; int32_t count = 0; UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; - SimpleDateFormatMutableNFs mutableNFs; // For parsing abutting numeric fields. 'abutPat' is the // offset into 'pattern' of the first of 2 or more abutting @@ -2225,7 +2257,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& } pos = subParse(text, pos, ch, count, - TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs); + TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType); // If the parse fails anywhere in the run, back up to the // start of the run and retry. @@ -2240,7 +2272,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& // fields. else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored int32_t s = subParse(text, pos, ch, count, - FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs, &dayPeriodInt); + FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, &dayPeriodInt); if (s == -pos-1) { // era not present, in special cases allow this to continue @@ -2858,7 +2890,7 @@ SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status) */ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count, UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal, - int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs, + int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, int32_t *dayPeriod) const { Formattable number; @@ -2868,7 +2900,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC UErrorCode status = U_ZERO_ERROR; ParsePosition pos(0); UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch); - NumberFormat *currentNumberFormat; + const NumberFormat *currentNumberFormat; UnicodeString temp; UBool gotNumber = FALSE; @@ -2880,7 +2912,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC return -start; } - currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex)); + currentNumberFormat = getNumberFormatByIndex(patternCharIndex); if (currentNumberFormat == NULL) { return -start; } @@ -3393,31 +3425,41 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC case UDAT_TIMEZONE_FIELD: // 'z' { UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG; - TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); - if (tz != NULL) { - cal.adoptTimeZone(tz); - return pos.getIndex(); + const TimeZoneFormat *tzfmt = tzFormat(status); + if (U_SUCCESS(status)) { + TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType); + if (tz != NULL) { + cal.adoptTimeZone(tz); + return pos.getIndex(); + } } - } + return -start; + } break; case UDAT_TIMEZONE_RFC_FIELD: // 'Z' { UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT); - TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); - if (tz != NULL) { - cal.adoptTimeZone(tz); - return pos.getIndex(); + const TimeZoneFormat *tzfmt = tzFormat(status); + if (U_SUCCESS(status)) { + TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType); + if (tz != NULL) { + cal.adoptTimeZone(tz); + return pos.getIndex(); + } } return -start; } case UDAT_TIMEZONE_GENERIC_FIELD: // 'v' { UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG; - TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); - if (tz != NULL) { - cal.adoptTimeZone(tz); - return pos.getIndex(); + const TimeZoneFormat *tzfmt = tzFormat(status); + if (U_SUCCESS(status)) { + TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType); + if (tz != NULL) { + cal.adoptTimeZone(tz); + return pos.getIndex(); + } } return -start; } @@ -3438,20 +3480,26 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC style = UTZFMT_STYLE_GENERIC_LOCATION; break; } - TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); - if (tz != NULL) { - cal.adoptTimeZone(tz); - return pos.getIndex(); + const TimeZoneFormat *tzfmt = tzFormat(status); + if (U_SUCCESS(status)) { + TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType); + if (tz != NULL) { + cal.adoptTimeZone(tz); + return pos.getIndex(); + } } return -start; } case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O' { UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT; - TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); - if (tz != NULL) { - cal.adoptTimeZone(tz); - return pos.getIndex(); + const TimeZoneFormat *tzfmt = tzFormat(status); + if (U_SUCCESS(status)) { + TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType); + if (tz != NULL) { + cal.adoptTimeZone(tz); + return pos.getIndex(); + } } return -start; } @@ -3475,10 +3523,13 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC style = UTZFMT_STYLE_ISO_EXTENDED_FULL; break; } - TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); - if (tz != NULL) { - cal.adoptTimeZone(tz); - return pos.getIndex(); + const TimeZoneFormat *tzfmt = tzFormat(status); + if (U_SUCCESS(status)) { + TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType); + if (tz != NULL) { + cal.adoptTimeZone(tz); + return pos.getIndex(); + } } return -start; } @@ -3502,10 +3553,13 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL; break; } - TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); - if (tz != NULL) { - cal.adoptTimeZone(tz); - return pos.getIndex(); + const TimeZoneFormat *tzfmt = tzFormat(status); + if (U_SUCCESS(status)) { + TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType); + if (tz != NULL) { + cal.adoptTimeZone(tz); + return pos.getIndex(); + } } return -start; } @@ -3539,7 +3593,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC U_ASSERT(dayPeriod != NULL); int32_t ampmStart = subParse(text, start, 0x61, count, obeyCount, allowNegative, ambiguousYear, saveHebrewMonth, cal, - patLoc, numericLeapMonthFormatter, tzTimeType, mutableNFs); + patLoc, numericLeapMonthFormatter, tzTimeType); if (ampmStart > 0) { return ampmStart; @@ -3686,7 +3740,7 @@ void SimpleDateFormat::parseInt(const UnicodeString& text, Formattable& number, ParsePosition& pos, UBool allowNegative, - NumberFormat *fmt) const { + const NumberFormat *fmt) const { parseInt(text, number, -1, pos, allowNegative,fmt); } @@ -3698,18 +3752,21 @@ void SimpleDateFormat::parseInt(const UnicodeString& text, int32_t maxDigits, ParsePosition& pos, UBool allowNegative, - NumberFormat *fmt) const { + const NumberFormat *fmt) const { UnicodeString oldPrefix; - DecimalFormat* df = NULL; - if (!allowNegative && (df = dynamic_cast(fmt)) != NULL) { - df->getNegativePrefix(oldPrefix); + auto* fmtAsDF = dynamic_cast(fmt); + LocalPointer df; + if (!allowNegative && fmtAsDF != nullptr) { + df.adoptInstead(dynamic_cast(fmtAsDF->clone())); + if (df.isNull()) { + // Memory allocation error + return; + } df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1)); + fmt = df.getAlias(); } int32_t oldPos = pos.getIndex(); fmt->parse(text, number, pos); - if (df != NULL) { - df->setNegativePrefix(oldPrefix); - } if (maxDigits > 0) { // adjust the result to fit into @@ -3856,7 +3913,13 @@ SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols //---------------------------------------------------------------------- const TimeZoneFormat* SimpleDateFormat::getTimeZoneFormat(void) const { - return (const TimeZoneFormat*)tzFormat(); + // TimeZoneFormat initialization might fail when out of memory. + // If we always initialize TimeZoneFormat instance, we can return + // such status there. For now, this implementation lazily instantiates + // a TimeZoneFormat for performance optimization reasons, but cannot + // propagate such error (probably just out of memory case) to the caller. + UErrorCode status = U_ZERO_ERROR; + return (const TimeZoneFormat*)tzFormat(status); } //---------------------------------------------------------------------- @@ -4123,12 +4186,11 @@ SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const // Lazy TimeZoneFormat instantiation, semantically const. TimeZoneFormat * -SimpleDateFormat::tzFormat() const { +SimpleDateFormat::tzFormat(UErrorCode &status) const { if (fTimeZoneFormat == NULL) { umtx_lock(&LOCK); { if (fTimeZoneFormat == NULL) { - UErrorCode status = U_ZERO_ERROR; TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status); if (U_FAILURE(status)) { return NULL; diff --git a/deps/icu-small/source/i18n/timezone.cpp b/deps/icu-small/source/i18n/timezone.cpp index e662bf7674..f7f45c7d3e 100644 --- a/deps/icu-small/source/i18n/timezone.cpp +++ b/deps/icu-small/source/i18n/timezone.cpp @@ -739,8 +739,7 @@ private: len = mapLen; } - UBool getID(int32_t i) { - UErrorCode ec = U_ZERO_ERROR; + UBool getID(int32_t i, UErrorCode& ec) { int32_t idLen = 0; const UChar* id = NULL; UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec); @@ -930,7 +929,7 @@ public: virtual const UnicodeString* snext(UErrorCode& status) { if (U_SUCCESS(status) && map != NULL && pos < len) { - getID(map[pos]); + getID(map[pos], status); ++pos; return &unistr; } diff --git a/deps/icu-small/source/i18n/ucln_in.h b/deps/icu-small/source/i18n/ucln_in.h index 40a5c36d87..318eafc143 100644 --- a/deps/icu-small/source/i18n/ucln_in.h +++ b/deps/icu-small/source/i18n/ucln_in.h @@ -26,6 +26,7 @@ as the functions are suppose to be called. It's usually best to have child dependencies called first. */ typedef enum ECleanupI18NType { UCLN_I18N_START = -1, + UCLN_I18N_NUMBER_SKELETONS, UCLN_I18N_CURRENCY_SPACING, UCLN_I18N_SPOOF, UCLN_I18N_SPOOFDATA, diff --git a/deps/icu-small/source/i18n/unicode/compactdecimalformat.h b/deps/icu-small/source/i18n/unicode/compactdecimalformat.h index d682d2d0e7..7dc92f6100 100644 --- a/deps/icu-small/source/i18n/unicode/compactdecimalformat.h +++ b/deps/icu-small/source/i18n/unicode/compactdecimalformat.h @@ -84,7 +84,7 @@ public: * Destructor. * @stable ICU 51 */ - virtual ~CompactDecimalFormat(); + ~CompactDecimalFormat() U_OVERRIDE; /** * Assignment operator. @@ -101,245 +101,21 @@ public: * @return a polymorphic copy of this CompactDecimalFormat. * @stable ICU 51 */ - virtual Format* clone() const; - - /** - * Return TRUE if the given Format objects are semantically equal. - * Objects of different subclasses are considered unequal. - * - * @param other the object to be compared with. - * @return TRUE if the given Format objects are semantically equal. - * @stable ICU 51 - */ - virtual UBool operator==(const Format& other) const; - + Format* clone() const U_OVERRIDE; using DecimalFormat::format; /** - * Format a double or long number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @stable ICU 51 - */ - virtual UnicodeString& format(double number, - UnicodeString& appendTo, - FieldPosition& pos) const; - - /** - * Format a double or long number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @param status - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(double number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const; - - /** - * Format a double or long number using base-10 representation. - * Currently sets status to U_UNSUPPORTED_ERROR. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * Can be NULL. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(double number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a long number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @stable ICU 56 - */ - virtual UnicodeString& format(int32_t number, - UnicodeString& appendTo, - FieldPosition& pos) const; - - /** - * Format a long number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(int32_t number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const; - - /** - * Format a long number using base-10 representation. - * Currently sets status to U_UNSUPPORTED_ERROR - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * Can be NULL. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(int32_t number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format an int64 number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. + * CompactDecimalFormat does not support parsing. This implementation + * does nothing. + * @param text Unused. + * @param result Does not change. + * @param parsePosition Does not change. + * @see Formattable * @stable ICU 51 */ - virtual UnicodeString& format(int64_t number, - UnicodeString& appendTo, - FieldPosition& pos) const; - - /** - * Format an int64 number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(int64_t number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const; - - /** - * Format an int64 number using base-10 representation. - * Currently sets status to U_UNSUPPORTED_ERROR - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * Can be NULL. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(int64_t number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a decimal number. Currently sets status to U_UNSUPPORTED_ERROR - * The syntax of the unformatted number is a "numeric string" - * as defined in the Decimal Arithmetic Specification, available at - * http://speleotrove.com/decimal - * - * @param number The unformatted number, as a string. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * Can be NULL. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(StringPiece number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a decimal number. Currently sets status to U_UNSUPPORTED_ERROR - * The number is a DigitList wrapper onto a floating point decimal number. - * The default implementation in NumberFormat converts the decimal number - * to a double and formats that. - * - * @param number The number, a DigitList format Decimal Floating Point. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(const DigitList &number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a decimal number. Currently sets status to U_UNSUPPORTED_ERROR. - * The number is a DigitList wrapper onto a floating point decimal number. - * The default implementation in NumberFormat converts the decimal number - * to a double and formats that. - * - * @param number The number, a DigitList format Decimal Floating Point. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(const DigitList &number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode& status) const; - - /** - * CompactDecimalFormat does not support parsing. This implementation - * does nothing. - * @param text Unused. - * @param result Does not change. - * @param parsePosition Does not change. - * @see Formattable - * @stable ICU 51 - */ - virtual void parse(const UnicodeString& text, - Formattable& result, - ParsePosition& parsePosition) const; + void parse(const UnicodeString& text, Formattable& result, + ParsePosition& parsePosition) const U_OVERRIDE; /** * CompactDecimalFormat does not support parsing. This implementation @@ -350,10 +126,9 @@ public: * @param status Always set to U_UNSUPPORTED_ERROR. * @stable ICU 51 */ - virtual void parse(const UnicodeString& text, - Formattable& result, - UErrorCode& status) const; + void parse(const UnicodeString& text, Formattable& result, UErrorCode& status) const U_OVERRIDE; +#ifndef U_HIDE_INTERNAL_API /** * Parses text from the given string as a currency amount. Unlike * the parse() method, this method will attempt to parse a generic @@ -374,8 +149,8 @@ public: * the parsed currency; if parse fails, this is NULL. * @internal */ - virtual CurrencyAmount* parseCurrency(const UnicodeString& text, - ParsePosition& pos) const; + CurrencyAmount* parseCurrency(const UnicodeString& text, ParsePosition& pos) const U_OVERRIDE; +#endif /* U_HIDE_INTERNAL_API */ /** * Return the class ID for this class. This is useful only for @@ -401,18 +176,10 @@ public: * other classes have different class IDs. * @stable ICU 51 */ - virtual UClassID getDynamicClassID() const; - -private: - - const UHashtable* _unitsByVariant; - const double* _divisors; - PluralRules* _pluralRules; - - // Default constructor not implemented. - CompactDecimalFormat(const DecimalFormat &, const UHashtable* unitsByVariant, const double* divisors, PluralRules* pluralRules); + UClassID getDynamicClassID() const U_OVERRIDE; - UBool eqHelper(const CompactDecimalFormat& that) const; + private: + CompactDecimalFormat(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status); }; U_NAMESPACE_END diff --git a/deps/icu-small/source/i18n/unicode/currunit.h b/deps/icu-small/source/i18n/unicode/currunit.h index e7e0dc72da..d5bc4aa6d6 100644 --- a/deps/icu-small/source/i18n/unicode/currunit.h +++ b/deps/icu-small/source/i18n/unicode/currunit.h @@ -44,8 +44,9 @@ class U_I18N_API CurrencyUnit: public MeasureUnit { /** * Construct an object with the given ISO currency code. - * @param isoCode the 3-letter ISO 4217 currency code; must not be - * NULL and must have length 3 + * @param isoCode the 3-letter ISO 4217 currency code; must have + * length 3 and need not be NUL-terminated. If NULL, the currency + * is initialized to the unknown currency XXX. * @param ec input-output error code. If the isoCode is invalid, * then this will be set to a failing value. * @stable ICU 3.0 diff --git a/deps/icu-small/source/i18n/unicode/dcfmtsym.h b/deps/icu-small/source/i18n/unicode/dcfmtsym.h index e58befa31b..2f824cec30 100644 --- a/deps/icu-small/source/i18n/unicode/dcfmtsym.h +++ b/deps/icu-small/source/i18n/unicode/dcfmtsym.h @@ -406,9 +406,12 @@ public: * returning a const reference to one of the symbol strings. * The returned reference becomes invalid when the symbol is changed * or when the DecimalFormatSymbols are destroyed. - * ### TODO markus 2002oct11: Consider proposing getConstSymbol() to be really public. * Note: moved #ifndef U_HIDE_INTERNAL_API after this, since this is needed for inline in DecimalFormat * + * This is not currently stable API, but if you think it should be stable, + * post a comment on the following ticket and the ICU team will take a look: + * http://bugs.icu-project.org/trac/ticket/13580 + * * @param symbol Constant to indicate a number format symbol. * @return the format symbol by the param 'symbol' * @internal @@ -422,6 +425,10 @@ public: * to accessing the symbol from getConstSymbol with the corresponding * key, such as kZeroDigitSymbol or kOneDigitSymbol. * + * This is not currently stable API, but if you think it should be stable, + * post a comment on the following ticket and the ICU team will take a look: + * http://bugs.icu-project.org/trac/ticket/13580 + * * @param digit The digit, an integer between 0 and 9 inclusive. * If outside the range 0 to 9, the zero digit is returned. * @return the format symbol for the given digit. diff --git a/deps/icu-small/source/i18n/unicode/decimfmt.h b/deps/icu-small/source/i18n/unicode/decimfmt.h index b062208d9b..3747f510f7 100644 --- a/deps/icu-small/source/i18n/unicode/decimfmt.h +++ b/deps/icu-small/source/i18n/unicode/decimfmt.h @@ -43,28 +43,25 @@ #include "unicode/curramt.h" #include "unicode/enumset.h" -#ifndef U_HIDE_INTERNAL_API -/** - * \def UNUM_DECIMALFORMAT_INTERNAL_SIZE - * @internal - */ -#if UCONFIG_FORMAT_FASTPATHS_49 -#define UNUM_DECIMALFORMAT_INTERNAL_SIZE 16 -#endif -#endif /* U_HIDE_INTERNAL_API */ - U_NAMESPACE_BEGIN -class DigitList; class CurrencyPluralInfo; -class Hashtable; -class UnicodeSet; -class FieldPositionHandler; -class DecimalFormatStaticSets; -class FixedDecimal; -class DecimalFormatImpl; -class PluralRules; -class VisibleDigitsWithExponent; +class CompactDecimalFormat; + +namespace number { +class LocalizedNumberFormatter; +class FormattedNumber; +namespace impl { +class DecimalQuantity; +struct DecimalFormatFields; +} +} + +namespace numparse { +namespace impl { +class NumberParserImpl; +} +} // explicit template instantiation. see digitlst.h // (When building DLLs for Windows this is required.) @@ -672,17 +669,14 @@ template class U_I18N_API EnumSet "123", and "123" -> 1.23 * @stable ICU 2.0 @@ -1362,12 +1320,52 @@ public: * (For Arabic, use arabic percent symbol). * For a permill, set the suffixes to have "\\u2031" and the multiplier to be 1000. * + * This method only supports integer multipliers. To multiply by a non-integer, pair this + * method with setMultiplierScale(). + * * @param newValue the new value of the multiplier for use in percent, permill, etc. * Examples: with 100, 1.23 -> "123", and "123" -> 1.23 * @stable ICU 2.0 */ virtual void setMultiplier(int32_t newValue); +#ifndef U_HIDE_DRAFT_API + /** + * Gets the power of ten by which number should be multiplied before formatting, which + * can be combined with setMultiplier() to multiply by any arbitrary decimal value. + * + * A multiplier scale of 2 corresponds to multiplication by 100, and a multiplier scale + * of -2 corresponds to multiplication by 0.01. + * + * This method is analogous to UNUM_SCALE in getAttribute. + * + * @return the current value of the power-of-ten multiplier. + * @draft ICU 62 + */ + int32_t getMultiplierScale(void) const; +#endif /* U_HIDE_DRAFT_API */ + + /** + * Sets a power of ten by which number should be multiplied before formatting, which + * can be combined with setMultiplier() to multiply by any arbitrary decimal value. + * + * A multiplier scale of 2 corresponds to multiplication by 100, and a multiplier scale + * of -2 corresponds to multiplication by 0.01. + * + * For example, to multiply numbers by 0.5 before formatting, you can do: + * + *

+     * df.setMultiplier(5);
+     * df.setMultiplierScale(-1);
+     * 
+ * + * This method is analogous to UNUM_SCALE in setAttribute. + * + * @param newValue the new value of the power-of-ten multiplier. + * @draft ICU 62 + */ + virtual void setMultiplierScale(int32_t newValue); + /** * Get the rounding increment. * @return A positive rounding increment, or 0.0 if a custom rounding @@ -1400,7 +1398,7 @@ public: * @see #setRoundingMode * @stable ICU 2.0 */ - virtual ERoundingMode getRoundingMode(void) const; + virtual ERoundingMode getRoundingMode(void) const U_OVERRIDE; /** * Set the rounding mode. @@ -1410,7 +1408,7 @@ public: * @see #getRoundingMode * @stable ICU 2.0 */ - virtual void setRoundingMode(ERoundingMode roundingMode); + virtual void setRoundingMode(ERoundingMode roundingMode) U_OVERRIDE; /** * Get the width to which the output of format() is padded. @@ -1469,7 +1467,7 @@ public: * @see #setPadPosition * @stable ICU 2.0 */ - virtual void setPadCharacter(const UnicodeString &padChar); + virtual void setPadCharacter(const UnicodeString& padChar); /** * Get the position at which padding will take place. This is the location @@ -1676,7 +1674,7 @@ public: #endif /* U_HIDE_INTERNAL_API */ - /* Cannot use #ifndef U_HIDE_INTERNAL_API for the following draft method since it is virtual. */ + /* Cannot use #ifndef U_HIDE_INTERNAL_API for the following draft method since it is virtual. */ /** * Sets the minimum grouping digits. Setting to a value less than or * equal to 1 turns off minimum grouping digits. @@ -1717,7 +1715,7 @@ public: UBool isDecimalPatternMatchRequired(void) const; /** - * Allows you to set the behavior of the pattern decimal mark. + * Allows you to set the parse behavior of the pattern decimal mark. * * if TRUE, the input must have a decimal mark if one was specified in the pattern. When * FALSE the decimal mark may be omitted from the input. @@ -1727,6 +1725,60 @@ public: */ virtual void setDecimalPatternMatchRequired(UBool newValue); + /** + * {@icu} Returns whether to ignore exponents when parsing. + * + * @see #setParseNoExponent + * @internal This API is a technical preview. It may change in an upcoming release. + */ + virtual UBool isParseNoExponent() const; + + /** + * {@icu} Specifies whether to stop parsing when an exponent separator is encountered. For + * example, parses "123E4" to 123 (with parse position 3) instead of 1230000 (with parse position + * 5). + * + * @param value true to prevent exponents from being parsed; false to allow them to be parsed. + * @internal This API is a technical preview. It may change in an upcoming release. + */ + virtual void setParseNoExponent(UBool value); + + /** + * {@icu} Returns whether parsing is sensitive to case (lowercase/uppercase). + * + * @see #setParseCaseSensitive + * @internal This API is a technical preview. It may change in an upcoming release. + */ + virtual UBool isParseCaseSensitive() const; + + /** + * {@icu} Whether to pay attention to case when parsing; default is to ignore case (perform + * case-folding). For example, "A" == "a" in case-insensitive but not case-sensitive mode. + * + * Currency symbols are never case-folded. For example, "us$1.00" will not parse in case-insensitive + * mode, even though "US$1.00" parses. + * + * @internal This API is a technical preview. It may change in an upcoming release. + */ + virtual void setParseCaseSensitive(UBool value); + + /** + * {@icu} Returns whether truncation of high-order integer digits should result in an error. + * By default, setMaximumIntegerDigits truncates high-order digits silently. + * + * @see setFormatFailIfMoreThanMaxDigits + * @internal This API is a technical preview. It may change in an upcoming release. + */ + virtual UBool isFormatFailIfMoreThanMaxDigits() const; + + /** + * {@icu} Sets whether truncation of high-order integer digits should result in an error. + * By default, setMaximumIntegerDigits truncates high-order digits silently. + * + * @internal This API is a technical preview. It may change in an upcoming release. + */ + virtual void setFormatFailIfMoreThanMaxDigits(UBool value); + /** * Synthesizes a pattern string that represents the current state @@ -1781,9 +1833,8 @@ public: * set to a failure result. * @stable ICU 2.0 */ - virtual void applyPattern(const UnicodeString& pattern, - UParseError& parseError, - UErrorCode& status); + virtual void applyPattern(const UnicodeString& pattern, UParseError& parseError, UErrorCode& status); + /** * Sets the pattern. * @param pattern The pattern to be applied. @@ -1792,8 +1843,7 @@ public: * set to a failure result. * @stable ICU 2.0 */ - virtual void applyPattern(const UnicodeString& pattern, - UErrorCode& status); + virtual void applyPattern(const UnicodeString& pattern, UErrorCode& status); /** * Apply the given pattern to this Format object. The pattern @@ -1825,8 +1875,7 @@ public: * set to a failure result. * @stable ICU 2.0 */ - virtual void applyLocalizedPattern(const UnicodeString& pattern, - UParseError& parseError, + virtual void applyLocalizedPattern(const UnicodeString& pattern, UParseError& parseError, UErrorCode& status); /** @@ -1838,8 +1887,7 @@ public: * set to a failure result. * @stable ICU 2.0 */ - virtual void applyLocalizedPattern(const UnicodeString& pattern, - UErrorCode& status); + virtual void applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status); /** @@ -1851,7 +1899,7 @@ public: * @see NumberFormat#setMaximumIntegerDigits * @stable ICU 2.0 */ - virtual void setMaximumIntegerDigits(int32_t newValue); + void setMaximumIntegerDigits(int32_t newValue) U_OVERRIDE; /** * Sets the minimum number of digits allowed in the integer portion of a @@ -1862,7 +1910,7 @@ public: * @see NumberFormat#setMinimumIntegerDigits * @stable ICU 2.0 */ - virtual void setMinimumIntegerDigits(int32_t newValue); + void setMinimumIntegerDigits(int32_t newValue) U_OVERRIDE; /** * Sets the maximum number of digits allowed in the fraction portion of a @@ -1873,7 +1921,7 @@ public: * @see NumberFormat#setMaximumFractionDigits * @stable ICU 2.0 */ - virtual void setMaximumFractionDigits(int32_t newValue); + void setMaximumFractionDigits(int32_t newValue) U_OVERRIDE; /** * Sets the minimum number of digits allowed in the fraction portion of a @@ -1884,7 +1932,7 @@ public: * @see NumberFormat#setMinimumFractionDigits * @stable ICU 2.0 */ - virtual void setMinimumFractionDigits(int32_t newValue); + void setMinimumFractionDigits(int32_t newValue) U_OVERRIDE; /** * Returns the minimum number of significant digits that will be @@ -1947,7 +1995,6 @@ public: */ void setSignificantDigitsUsed(UBool useSignificantDigits); - public: /** * Sets the currency used to display currency * amounts. This takes effect immediately, if this format is a @@ -1960,7 +2007,7 @@ public: * @param ec input-output error code * @stable ICU 3.0 */ - virtual void setCurrency(const char16_t* theCurrency, UErrorCode& ec); + void setCurrency(const char16_t* theCurrency, UErrorCode& ec) U_OVERRIDE; /** * Sets the currency used to display currency amounts. See @@ -1984,78 +2031,53 @@ public: */ UCurrencyUsage getCurrencyUsage() const; - -#ifndef U_HIDE_DEPRECATED_API - /** - * The resource tags we use to retrieve decimal format data from - * locale resource bundles. - * @deprecated ICU 3.4. This string has no public purpose. Please don't use it. - */ - static const char fgNumberPatterns[]; -#endif // U_HIDE_DEPRECATED_API - #ifndef U_HIDE_INTERNAL_API - /** - * Get a FixedDecimal corresponding to a double as it would be - * formatted by this DecimalFormat. - * Internal, not intended for public use. - * @internal - */ - FixedDecimal getFixedDecimal(double number, UErrorCode &status) const; - - /** - * Get a FixedDecimal corresponding to a formattable as it would be - * formatted by this DecimalFormat. - * Internal, not intended for public use. - * @internal - */ - FixedDecimal getFixedDecimal(const Formattable &number, UErrorCode &status) const; /** - * Get a FixedDecimal corresponding to a DigitList as it would be - * formatted by this DecimalFormat. Note: the DigitList may be modified. + * Format a number and save it into the given DecimalQuantity. * Internal, not intended for public use. * @internal */ - FixedDecimal getFixedDecimal(DigitList &number, UErrorCode &status) const; + void formatToDecimalQuantity(double number, number::impl::DecimalQuantity& output, + UErrorCode& status) const; /** - * Get a VisibleDigitsWithExponent corresponding to a double - * as it would be formatted by this DecimalFormat. + * Get a DecimalQuantity corresponding to a formattable as it would be + * formatted by this DecimalFormat. * Internal, not intended for public use. * @internal */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - double number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; + void formatToDecimalQuantity(const Formattable& number, number::impl::DecimalQuantity& output, + UErrorCode& status) const; - /** - * Get a VisibleDigitsWithExponent corresponding to a formattable - * as it would be formatted by this DecimalFormat. - * Internal, not intended for public use. - * @internal - */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - const Formattable &number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; +#endif +#ifndef U_HIDE_DRAFT_API /** - * Get a VisibleDigitsWithExponent corresponding to a DigitList - * as it would be formatted by this DecimalFormat. - * Note: the DigitList may be modified. - * Internal, not intended for public use. - * @internal + * Converts this DecimalFormat to a NumberFormatter. Starting in ICU 60, + * NumberFormatter is the recommended way to format numbers. + * + * NOTE: The returned LocalizedNumberFormatter is owned by this DecimalFormat. + * If a non-const method is called on the DecimalFormat, or if the DecimalFormat + * is deleted, the object becomes invalid. If you plan to keep the return value + * beyond the lifetime of the DecimalFormat, copy it to a local variable: + * + *
+     * LocalizedNumberFormatter f = df->toNumberFormatter();
+     * 
+ * + * It is, however, safe to use the return value for chaining: + * + *
+     * FormattedNumber result = df->toNumberFormatter().formatDouble(123, status);
+     * 
+ * + * @param output The variable into which to store the LocalizedNumberFormatter. + * @return The output variable, for chaining. + * @draft ICU 62 */ - VisibleDigitsWithExponent &initVisibleDigitsWithExponent( - DigitList &number, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - -#endif /* U_HIDE_INTERNAL_API */ - -public: + const number::LocalizedNumberFormatter& toNumberFormatter() const; +#endif /* U_HIDE_DRAFT_API */ /** * Return the class ID for this class. This is useful only for @@ -2081,217 +2103,57 @@ public: * other classes have different class IDs. * @stable ICU 2.0 */ - virtual UClassID getDynamicClassID(void) const; - -private: - - DecimalFormat(); // default constructor not implemented - - /** - * Initialize all fields of a new DecimalFormatter to a safe default value. - * Common code for use by constructors. - */ - void init(); - - /** - * Do real work of constructing a new DecimalFormat. - */ - void construct(UErrorCode& status, - UParseError& parseErr, - const UnicodeString* pattern = 0, - DecimalFormatSymbols* symbolsToAdopt = 0 - ); - - void handleCurrencySignInPattern(UErrorCode& status); - - void parse(const UnicodeString& text, - Formattable& result, - ParsePosition& pos, - char16_t* currency) const; - - enum { - fgStatusInfinite, - fgStatusLength // Leave last in list. - } StatusFlags; - - UBool subparse(const UnicodeString& text, - const UnicodeString* negPrefix, - const UnicodeString* negSuffix, - const UnicodeString* posPrefix, - const UnicodeString* posSuffix, - UBool complexCurrencyParsing, - int8_t type, - ParsePosition& parsePosition, - DigitList& digits, UBool* status, - char16_t* currency) const; - - // Mixed style parsing for currency. - // It parses against the current currency pattern - // using complex affix comparison - // parses against the currency plural patterns using complex affix comparison, - // and parses against the current pattern using simple affix comparison. - UBool parseForCurrency(const UnicodeString& text, - ParsePosition& parsePosition, - DigitList& digits, - UBool* status, - char16_t* currency) const; - - int32_t skipPadding(const UnicodeString& text, int32_t position) const; - - int32_t compareAffix(const UnicodeString& input, - int32_t pos, - UBool isNegative, - UBool isPrefix, - const UnicodeString* affixPat, - UBool complexCurrencyParsing, - int8_t type, - char16_t* currency) const; - - static UnicodeString& trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix); - - UBool equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const; - - int32_t compareSimpleAffix(const UnicodeString& affix, - const UnicodeString& input, - int32_t pos, - UBool lenient) const; - - static int32_t skipPatternWhiteSpace(const UnicodeString& text, int32_t pos); - - static int32_t skipUWhiteSpace(const UnicodeString& text, int32_t pos); - - static int32_t skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos); - - static int32_t skipBidiMarks(const UnicodeString& text, int32_t pos); - - int32_t compareComplexAffix(const UnicodeString& affixPat, - const UnicodeString& input, - int32_t pos, - int8_t type, - char16_t* currency) const; - - static int32_t match(const UnicodeString& text, int32_t pos, UChar32 ch); + UClassID getDynamicClassID(void) const U_OVERRIDE; - static int32_t match(const UnicodeString& text, int32_t pos, const UnicodeString& str); + private: - static UBool matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol, - UnicodeSet *sset, UChar32 schar); + /** Rebuilds the formatter object from the property bag. */ + void touch(UErrorCode& status); - static UBool matchDecimal(UChar32 symbolChar, - UBool sawDecimal, UChar32 sawDecimalChar, - const UnicodeSet *sset, UChar32 schar); - - static UBool matchGrouping(UChar32 groupingChar, - UBool sawGrouping, UChar32 sawGroupingChar, - const UnicodeSet *sset, - UChar32 decimalChar, const UnicodeSet *decimalSet, - UChar32 schar); - - // set up currency affix patterns for mix parsing. - // The patterns saved here are the affix patterns of default currency - // pattern and the unique affix patterns of the plural currency patterns. - // Those patterns are used by parseForCurrency(). - void setupCurrencyAffixPatterns(UErrorCode& status); - - // get the currency rounding with respect to currency usage - double getCurrencyRounding(const char16_t* currency, - UErrorCode* ec) const; - - // get the currency fraction with respect to currency usage - int getCurrencyFractionDigits(const char16_t* currency, - UErrorCode* ec) const; - - // hashtable operations - Hashtable* initHashForAffixPattern(UErrorCode& status); - - void deleteHashForAffixPattern(); - - void copyHashForAffixPattern(const Hashtable* source, - Hashtable* target, UErrorCode& status); - - DecimalFormatImpl *fImpl; + /** Rebuilds the formatter object, hiding the error code. */ + void touchNoError(); /** - * Constants. + * Updates the property bag with settings from the given pattern. + * + * @param pattern The pattern string to parse. + * @param ignoreRounding Whether to leave out rounding information (minFrac, maxFrac, and rounding + * increment) when parsing the pattern. This may be desirable if a custom rounding mode, such + * as CurrencyUsage, is to be used instead. One of {@link + * PatternStringParser#IGNORE_ROUNDING_ALWAYS}, {@link PatternStringParser#IGNORE_ROUNDING_IF_CURRENCY}, + * or {@link PatternStringParser#IGNORE_ROUNDING_NEVER}. + * @see PatternAndPropertyUtils#parseToExistingProperties */ + void setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding, + UErrorCode& status); + const numparse::impl::NumberParserImpl* getParser(UErrorCode& status) const; - EnumSet - fBoolFlags; + const numparse::impl::NumberParserImpl* getCurrencyParser(UErrorCode& status) const; + static void fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition, + int32_t offset, UErrorCode& status); - // style is only valid when decimal formatter is constructed by - // DecimalFormat(pattern, decimalFormatSymbol, style) - int fStyle; + static void fieldPositionIteratorHelper(const number::FormattedNumber& formatted, + FieldPositionIterator* fpi, int32_t offset, UErrorCode& status); + void setupFastFormat(); - // Affix pattern set for currency. - // It is a set of AffixPatternsForCurrency, - // each element of the set saves the negative prefix pattern, - // negative suffix pattern, positive prefix pattern, - // and positive suffix pattern of a pattern. - // It is used for currency mixed style parsing. - // It is actually is a set. - // The set contains the default currency pattern from the locale, - // and the currency plural patterns. - // Since it is a set, it does not contain duplicated items. - // For example, if 2 currency plural patterns are the same, only one pattern - // is included in the set. When parsing, we do not check whether the plural - // count match or not. - Hashtable* fAffixPatternsForCurrency; + bool fastFormatDouble(double input, UnicodeString& output) const; - // Information needed for DecimalFormat to format/parse currency plural. - CurrencyPluralInfo* fCurrencyPluralInfo; + bool fastFormatInt64(int64_t input, UnicodeString& output) const; -#if UCONFIG_HAVE_PARSEALLINPUT - UNumberFormatAttributeValue fParseAllInput; -#endif + void doFastFormatInt32(int32_t input, bool isNegative, UnicodeString& output) const; - // Decimal Format Static Sets singleton. - const DecimalFormatStaticSets *fStaticSets; + //=====================================================================================// + // INSTANCE FIELDS // + //=====================================================================================// -protected: + // Only one instance field: keep all fields inside of an implementation class defined in number_mapper.h + number::impl::DecimalFormatFields* fields; -#ifndef U_HIDE_INTERNAL_API - /** - * Rounds a value according to the rules of this object. - * @internal - */ - DigitList& _round(const DigitList& number, DigitList& adjustedNum, UBool& isNegative, UErrorCode& status) const; -#endif /* U_HIDE_INTERNAL_API */ - - /** - * Returns the currency in effect for this formatter. Subclasses - * should override this method as needed. Unlike getCurrency(), - * this method should never return "". - * @result output parameter for null-terminated result, which must - * have a capacity of at least 4 - * @internal - */ - virtual void getEffectiveCurrency(char16_t* result, UErrorCode& ec) const; - - /** number of integer digits - * @stable ICU 2.4 - */ - static const int32_t kDoubleIntegerDigits; - /** number of fraction digits - * @stable ICU 2.4 - */ - static const int32_t kDoubleFractionDigits; - - /** - * When someone turns on scientific mode, we assume that more than this - * number of digits is due to flipping from some other mode that didn't - * restrict the maximum, and so we force 1 integer digit. We don't bother - * to track and see if someone is using exponential notation with more than - * this number, it wouldn't make sense anyway, and this is just to make sure - * that someone turning on scientific mode with default settings doesn't - * end up with lots of zeroes. - * @stable ICU 2.8 - */ - static const int32_t kMaxScientificIntegerDigits; + // Allow child class CompactDecimalFormat to access fProperties: + friend class CompactDecimalFormat; }; diff --git a/deps/icu-small/source/i18n/unicode/fmtable.h b/deps/icu-small/source/i18n/unicode/fmtable.h index 766a71969d..2359b61d46 100644 --- a/deps/icu-small/source/i18n/unicode/fmtable.h +++ b/deps/icu-small/source/i18n/unicode/fmtable.h @@ -33,17 +33,11 @@ U_NAMESPACE_BEGIN class CharString; -class DigitList; - -/** - * \def UNUM_INTERNAL_STACKARRAY_SIZE - * @internal - */ -#if U_PLATFORM == U_PF_OS400 -#define UNUM_INTERNAL_STACKARRAY_SIZE 144 -#else -#define UNUM_INTERNAL_STACKARRAY_SIZE 128 -#endif +namespace number { +namespace impl { +class DecimalQuantity; +} +} /** * Formattable objects can be passed to the Format class or @@ -649,24 +643,25 @@ public: * Internal function, do not use. * TODO: figure out how to make this be non-public. * NumberFormat::format(Formattable, ... - * needs to get at the DigitList, if it exists, for + * needs to get at the DecimalQuantity, if it exists, for * big decimal formatting. * @internal */ - DigitList *getDigitList() const { return fDecimalNum;} + number::impl::DecimalQuantity *getDecimalQuantity() const { return fDecimalQuantity;} /** - * @internal + * Export the value of this Formattable to a DecimalQuantity. + * @internal */ - DigitList *getInternalDigitList(); + void populateDecimalQuantity(number::impl::DecimalQuantity& output, UErrorCode& status) const; /** - * Adopt, and set value from, a DigitList + * Adopt, and set value from, a DecimalQuantity * Internal Function, do not use. - * @param dl the Digit List to be adopted + * @param dl the DecimalQuantity to be adopted * @internal */ - void adoptDigitList(DigitList *dl); + void adoptDecimalQuantity(number::impl::DecimalQuantity *dq); /** * Internal function to return the CharString pointer. @@ -706,9 +701,7 @@ private: CharString *fDecimalStr; - DigitList *fDecimalNum; - - char fStackData[UNUM_INTERNAL_STACKARRAY_SIZE]; // must be big enough for DigitList + number::impl::DecimalQuantity *fDecimalQuantity; Type fType; UnicodeString fBogus; // Bogus string when it's needed. diff --git a/deps/icu-small/source/i18n/unicode/fpositer.h b/deps/icu-small/source/i18n/unicode/fpositer.h index 8e9d69c547..81091f0ffa 100644 --- a/deps/icu-small/source/i18n/unicode/fpositer.h +++ b/deps/icu-small/source/i18n/unicode/fpositer.h @@ -47,13 +47,6 @@ U_NAMESPACE_BEGIN class UVector32; -// Forward declaration for number formatting: -namespace number { -namespace impl { -class NumberStringBuilder; -} -} - /** * FieldPositionIterator returns the field ids and their start/limit positions generated * by a call to Format::format. See Format, NumberFormat, DecimalFormat. @@ -114,7 +107,6 @@ private: void setData(UVector32 *adopt, UErrorCode& status); friend class FieldPositionIteratorHandler; - friend class number::impl::NumberStringBuilder; UVector32 *data; int32_t pos; diff --git a/deps/icu-small/source/i18n/unicode/measunit.h b/deps/icu-small/source/i18n/unicode/measunit.h index f7ddb4e20c..f552253544 100644 --- a/deps/icu-small/source/i18n/unicode/measunit.h +++ b/deps/icu-small/source/i18n/unicode/measunit.h @@ -400,14 +400,6 @@ class U_I18N_API MeasureUnit: public UObject { */ static MeasureUnit *createMilePerGallonImperial(UErrorCode &status); - /* - * The following were draft ICU 58, but have been withdrawn: - * static MeasureUnit *createEast(UErrorCode &status); - * static MeasureUnit *createNorth(UErrorCode &status); - * static MeasureUnit *createSouth(UErrorCode &status); - * static MeasureUnit *createWest(UErrorCode &status); - */ - /** * Returns unit of digital: bit. * Caller owns returned value and must free it. diff --git a/deps/icu-small/source/i18n/unicode/nounit.h b/deps/icu-small/source/i18n/unicode/nounit.h index 290e77e880..288f268d66 100644 --- a/deps/icu-small/source/i18n/unicode/nounit.h +++ b/deps/icu-small/source/i18n/unicode/nounit.h @@ -61,6 +61,12 @@ public: */ NoUnit(const NoUnit& other); + /** + * Destructor. + * @draft ICU 60 + */ + virtual ~NoUnit(); + /** * Return a polymorphic clone of this object. The result will * have the same class as returned by getDynamicClassID(). @@ -86,12 +92,6 @@ public: */ static UClassID U_EXPORT2 getStaticClassID(); - /** - * Destructor. - * @draft ICU 60 - */ - virtual ~NoUnit(); - private: /** * Constructor diff --git a/deps/icu-small/source/i18n/unicode/numberformatter.h b/deps/icu-small/source/i18n/unicode/numberformatter.h index 3fbb33ccee..3ab08319f7 100644 --- a/deps/icu-small/source/i18n/unicode/numberformatter.h +++ b/deps/icu-small/source/i18n/unicode/numberformatter.h @@ -17,6 +17,8 @@ #include "unicode/plurrule.h" #include "unicode/ucurr.h" #include "unicode/unum.h" +#include "unicode/unumberformatter.h" +#include "unicode/uobject.h" #ifndef U_HIDE_DRAFT_API @@ -31,11 +33,11 @@ * // Most basic usage: * NumberFormatter::withLocale(...).format(123).toString(); // 1,234 in en-US * - * // Custom notation, unit, and rounding strategy: + * // Custom notation, unit, and rounding precision: * NumberFormatter::with() * .notation(Notation::compactShort()) * .unit(CurrencyUnit("EUR", status)) - * .rounding(Rounder::maxDigits(2)) + * .precision(Precision::maxDigits(2)) * .locale(...) * .format(1234) * .toString(); // €1.2K in en-US @@ -43,7 +45,7 @@ * // Create a formatter in a singleton for use later: * static const LocalizedNumberFormatter formatter = NumberFormatter::withLocale(...) * .unit(NoUnit::percent()) - * .rounding(Rounder::fixedFraction(3)); + * .precision(Precision::fixedFraction(3)); * formatter.format(5.9831).toString(); // 5.983% in en-US * * // Create a "template" in a singleton but without setting a locale until the call site: @@ -63,7 +65,7 @@ * *
  * UnlocalizedNumberFormatter formatter = UnlocalizedNumberFormatter::with().notation(Notation::scientific());
- * formatter.rounding(Rounder.maxFraction(2)); // does nothing!
+ * formatter.precision(Precision.maxFraction(2)); // does nothing!
  * formatter.locale(Locale.getEnglish()).format(9.8765).toString(); // prints "9.8765E0", not "9.88E0"
  * 
* @@ -74,321 +76,23 @@ * @author Shane Carr */ -/** - * An enum declaring how to render units, including currencies. Example outputs when formatting 123 USD and 123 - * meters in en-CA: - * - *

- *

    - *
  • NARROW*: "$123.00" and "123 m" - *
  • SHORT: "US$ 123.00" and "123 m" - *
  • FULL_NAME: "123.00 US dollars" and "123 meters" - *
  • ISO_CODE: "USD 123.00" and undefined behavior - *
  • HIDDEN: "123.00" and "123" - *
- * - *

- * This enum is similar to {@link com.ibm.icu.text.MeasureFormat.FormatWidth}. - * - * @draft ICU 60 - */ -typedef enum UNumberUnitWidth { - /** - * Print an abbreviated version of the unit name. Similar to SHORT, but always use the shortest available - * abbreviation or symbol. This option can be used when the context hints at the identity of the unit. For more - * information on the difference between NARROW and SHORT, see SHORT. - * - *

- * In CLDR, this option corresponds to the "Narrow" format for measure units and the "¤¤¤¤¤" placeholder for - * currencies. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_NARROW, - - /** - * Print an abbreviated version of the unit name. Similar to NARROW, but use a slightly wider abbreviation or - * symbol when there may be ambiguity. This is the default behavior. - * - *

- * For example, in es-US, the SHORT form for Fahrenheit is "{0} °F", but the NARROW form is "{0}°", - * since Fahrenheit is the customary unit for temperature in that locale. - * - *

- * In CLDR, this option corresponds to the "Short" format for measure units and the "¤" placeholder for - * currencies. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_SHORT, - - /** - * Print the full name of the unit, without any abbreviations. - * - *

- * In CLDR, this option corresponds to the default format for measure units and the "¤¤¤" placeholder for - * currencies. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_FULL_NAME, - - /** - * Use the three-digit ISO XXX code in place of the symbol for displaying currencies. The behavior of this - * option is currently undefined for use with measure units. - * - *

- * In CLDR, this option corresponds to the "¤¤" placeholder for currencies. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_ISO_CODE, - - /** - * Format the number according to the specified unit, but do not display the unit. For currencies, apply - * monetary symbols and formats as with SHORT, but omit the currency symbol. For measure units, the behavior is - * equivalent to not specifying the unit at all. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_HIDDEN - -#ifndef U_HIDE_INTERNAL_API - , - /** - * One more than the highest UNumberUnitWidth value. - * - * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. - */ - UNUM_UNIT_WIDTH_COUNT -#endif // U_HIDE_INTERNAL_API -} UNumberUnitWidth; - -/** - * An enum declaring the strategy for when and how to display grouping separators (i.e., the - * separator, often a comma or period, after every 2-3 powers of ten). The choices are several - * pre-built strategies for different use cases that employ locale data whenever possible. Example - * outputs for 1234 and 1234567 in en-IN: - * - *

    - *
  • OFF: 1234 and 12345 - *
  • MIN2: 1234 and 12,34,567 - *
  • AUTO: 1,234 and 12,34,567 - *
  • ON_ALIGNED: 1,234 and 12,34,567 - *
  • THOUSANDS: 1,234 and 1,234,567 - *
- * - *

- * The default is AUTO, which displays grouping separators unless the locale data says that grouping - * is not customary. To force grouping for all numbers greater than 1000 consistently across locales, - * use ON_ALIGNED. On the other hand, to display grouping less frequently than the default, use MIN2 - * or OFF. See the docs of each option for details. - * - *

- * Note: This enum specifies the strategy for grouping sizes. To set which character to use as the - * grouping separator, use the "symbols" setter. - * - * @draft ICU 61 - */ -typedef enum UGroupingStrategy { - /** - * Do not display grouping separators in any locale. - * - * @draft ICU 61 - */ - UNUM_GROUPING_OFF, - - /** - * Display grouping using locale defaults, except do not show grouping on values smaller than - * 10000 (such that there is a minimum of two digits before the first separator). - * - *

- * Note that locales may restrict grouping separators to be displayed only on 1 million or - * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency). - * - *

- * Locale data is used to determine whether to separate larger numbers into groups of 2 - * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). - * - * @draft ICU 61 - */ - UNUM_GROUPING_MIN2, - - /** - * Display grouping using the default strategy for all locales. This is the default behavior. - * - *

- * Note that locales may restrict grouping separators to be displayed only on 1 million or - * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency). - * - *

- * Locale data is used to determine whether to separate larger numbers into groups of 2 - * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). - * - * @draft ICU 61 - */ - UNUM_GROUPING_AUTO, - - /** - * Always display the grouping separator on values of at least 1000. - * - *

- * This option ignores the locale data that restricts or disables grouping, described in MIN2 and - * AUTO. This option may be useful to normalize the alignment of numbers, such as in a - * spreadsheet. - * - *

- * Locale data is used to determine whether to separate larger numbers into groups of 2 - * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). - * - * @draft ICU 61 - */ - UNUM_GROUPING_ON_ALIGNED, - - /** - * Use the Western defaults: groups of 3 and enabled for all numbers 1000 or greater. Do not use - * locale data for determining the grouping strategy. - * - * @draft ICU 61 - */ - UNUM_GROUPING_THOUSANDS - -} UGroupingStrategy; - -/** - * An enum declaring how to denote positive and negative numbers. Example outputs when formatting - * 123, 0, and -123 in en-US: - * - *

    - *
  • AUTO: "123", "0", and "-123" - *
  • ALWAYS: "+123", "+0", and "-123" - *
  • NEVER: "123", "0", and "123" - *
  • ACCOUNTING: "$123", "$0", and "($123)" - *
  • ACCOUNTING_ALWAYS: "+$123", "+$0", and "($123)" - *
  • EXCEPT_ZERO: "+123", "0", and "-123" - *
  • ACCOUNTING_EXCEPT_ZERO: "+$123", "$0", and "($123)" - *
- * - *

- * The exact format, including the position and the code point of the sign, differ by locale. - * - * @draft ICU 60 - */ -typedef enum UNumberSignDisplay { - /** - * Show the minus sign on negative numbers, and do not show the sign on positive numbers. This is the default - * behavior. - * - * @draft ICU 60 - */ - UNUM_SIGN_AUTO, - - /** - * Show the minus sign on negative numbers and the plus sign on positive numbers, including zero. - * To hide the sign on zero, see {@link UNUM_SIGN_EXCEPT_ZERO}. - * - * @draft ICU 60 - */ - UNUM_SIGN_ALWAYS, - - /** - * Do not show the sign on positive or negative numbers. - * - * @draft ICU 60 - */ - UNUM_SIGN_NEVER, - - /** - * Use the locale-dependent accounting format on negative numbers, and do not show the sign on positive numbers. - * - *

- * The accounting format is defined in CLDR and varies by locale; in many Western locales, the format is a pair - * of parentheses around the number. - * - *

- * Note: Since CLDR defines the accounting format in the monetary context only, this option falls back to the - * AUTO sign display strategy when formatting without a currency unit. This limitation may be lifted in the - * future. - * - * @draft ICU 60 - */ - UNUM_SIGN_ACCOUNTING, - - /** - * Use the locale-dependent accounting format on negative numbers, and show the plus sign on - * positive numbers, including zero. For more information on the accounting format, see the - * ACCOUNTING sign display strategy. To hide the sign on zero, see - * {@link UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO}. - * - * @draft ICU 60 - */ - UNUM_SIGN_ACCOUNTING_ALWAYS, - - /** - * Show the minus sign on negative numbers and the plus sign on positive numbers. Do not show a - * sign on zero. - * - * @draft ICU 61 - */ - UNUM_SIGN_EXCEPT_ZERO, - - /** - * Use the locale-dependent accounting format on negative numbers, and show the plus sign on - * positive numbers. Do not show a sign on zero. For more information on the accounting format, - * see the ACCOUNTING sign display strategy. - * - * @draft ICU 61 - */ - UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO +U_NAMESPACE_BEGIN -#ifndef U_HIDE_INTERNAL_API - , - /** - * One more than the highest UNumberSignDisplay value. - * - * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. - */ - UNUM_SIGN_COUNT -#endif // U_HIDE_INTERNAL_API -} UNumberSignDisplay; +// Forward declarations: +class IFixedDecimal; +class FieldPositionIteratorHandler; -/** - * An enum declaring how to render the decimal separator. - * - *

- *

    - *
  • UNUM_DECIMAL_SEPARATOR_AUTO: "1", "1.1" - *
  • UNUM_DECIMAL_SEPARATOR_ALWAYS: "1.", "1.1" - *
- */ -typedef enum UNumberDecimalSeparatorDisplay { - /** - * Show the decimal separator when there are one or more digits to display after the separator, and do not show - * it otherwise. This is the default behavior. - * - * @draft ICU 60 - */ - UNUM_DECIMAL_SEPARATOR_AUTO, +namespace numparse { +namespace impl { - /** - * Always show the decimal separator, even if there are no digits to display after the separator. - * - * @draft ICU 60 - */ - UNUM_DECIMAL_SEPARATOR_ALWAYS +// Forward declarations: +class NumberParserImpl; +class MultiplierParseHandler; -#ifndef U_HIDE_INTERNAL_API - , - /** - * One more than the highest UNumberDecimalSeparatorDisplay value. - * - * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. - */ - UNUM_DECIMAL_SEPARATOR_COUNT -#endif // U_HIDE_INTERNAL_API -} UNumberDecimalMarkDisplay; +} +} -U_NAMESPACE_BEGIN namespace number { // icu::number +namespace number { // icu::number // Forward declarations: class UnlocalizedNumberFormatter; @@ -396,15 +100,14 @@ class LocalizedNumberFormatter; class FormattedNumber; class Notation; class ScientificNotation; -class Rounder; -class FractionRounder; -class CurrencyRounder; -class IncrementRounder; +class Precision; +class FractionPrecision; +class CurrencyPrecision; +class IncrementPrecision; class IntegerWidth; namespace impl { -#ifndef U_HIDE_INTERNAL_API /** * Datatype for minimum/maximum fraction digits. Must be able to hold kMaxIntFracSig. * @@ -419,24 +122,28 @@ typedef int16_t digits_t; * @internal */ static constexpr int32_t DEFAULT_THRESHOLD = 3; -#endif // U_HIDE_INTERNAL_API // Forward declarations: class Padder; struct MacroProps; struct MicroProps; class DecimalQuantity; -struct NumberFormatterResults; +struct UFormattedNumberData; class NumberFormatterImpl; struct ParsedPatternInfo; class ScientificModifier; class MultiplierProducer; -class MutablePatternModifier; -class LongNameHandler; +class RoundingImpl; class ScientificHandler; -class CompactHandler; class Modifier; class NumberStringBuilder; +class AffixPatternProvider; +class NumberPropertyMapper; +struct DecimalFormatProperties; +class MultiplierFormatHandler; +class CurrencySymbols; +class GeneratorHelpers; +class DecNum; } // namespace impl @@ -530,13 +237,13 @@ class U_I18N_API Notation : public UMemory { * * *

- * When compact notation is specified without an explicit rounding strategy, numbers are rounded off to the closest + * When compact notation is specified without an explicit rounding precision, numbers are rounded off to the closest * integer after scaling the number by the corresponding power of 10, but with a digit shown after the decimal - * separator if there is only one digit before the decimal separator. The default compact notation rounding strategy + * separator if there is only one digit before the decimal separator. The default compact notation rounding precision * is equivalent to: * *

-     * Rounder.integer().withMinDigits(2)
+     * Precision::integer().withMinDigits(2)
      * 
* * @return A CompactNotation for passing to the NumberFormatter notation() setter. @@ -641,6 +348,9 @@ class U_I18N_API Notation : public UMemory { friend class impl::NumberFormatterImpl; friend class impl::ScientificModifier; friend class impl::ScientificHandler; + + // To allow access to the skeleton generation code: + friend class impl::GeneratorHelpers; }; /** @@ -687,21 +397,36 @@ class U_I18N_API ScientificNotation : public Notation { // Inherit constructor using Notation::Notation; + // Raw constructor for NumberPropertyMapper + ScientificNotation(int8_t fEngineeringInterval, bool fRequireMinInt, impl::digits_t fMinExponentDigits, + UNumberSignDisplay fExponentSignDisplay); + friend class Notation; + + // So that NumberPropertyMapper can create instances + friend class impl::NumberPropertyMapper; }; // Reserve extra names in case they are added as classes in the future: -typedef Rounder DigitRounder; +typedef Precision SignificantDigitsPrecision; + +// Typedefs for ICU 60/61 compatibility. +// These will be removed in ICU 64. +// See http://bugs.icu-project.org/trac/ticket/13746 +typedef Precision Rounder; +typedef FractionPrecision FractionRounder; +typedef IncrementPrecision IncrementRounder; +typedef CurrencyPrecision CurrencyRounder; /** - * A class that defines the rounding strategy to be used when formatting numbers in NumberFormatter. + * A class that defines the rounding precision to be used when formatting numbers in NumberFormatter. * *

- * To create a Rounder, use one of the factory methods. + * To create a Precision, use one of the factory methods. * * @draft ICU 60 */ -class U_I18N_API Rounder : public UMemory { +class U_I18N_API Precision : public UMemory { public: /** @@ -717,18 +442,18 @@ class U_I18N_API Rounder : public UMemory { *

* http://www.serpentine.com/blog/2011/06/29/here-be-dragons-advances-in-problems-you-didnt-even-know-you-had/ * - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A Precision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - static Rounder unlimited(); + static Precision unlimited(); /** * Show numbers rounded if necessary to the nearest integer. * - * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A FractionPrecision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - static FractionRounder integer(); + static FractionPrecision integer(); /** * Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator). @@ -754,10 +479,10 @@ class U_I18N_API Rounder : public UMemory { * @param minMaxFractionPlaces * The minimum and maximum number of numerals to display after the decimal separator (rounding if too * long or padding with zeros if too short). - * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A FractionPrecision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - static FractionRounder fixedFraction(int32_t minMaxFractionPlaces); + static FractionPrecision fixedFraction(int32_t minMaxFractionPlaces); /** * Always show at least a certain number of fraction places after the decimal separator, padding with zeros if @@ -769,10 +494,10 @@ class U_I18N_API Rounder : public UMemory { * @param minFractionPlaces * The minimum number of numerals to display after the decimal separator (padding with zeros if * necessary). - * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A FractionPrecision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - static FractionRounder minFraction(int32_t minFractionPlaces); + static FractionPrecision minFraction(int32_t minFractionPlaces); /** * Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator). @@ -781,10 +506,10 @@ class U_I18N_API Rounder : public UMemory { * * @param maxFractionPlaces * The maximum number of numerals to display after the decimal mark (rounding if necessary). - * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A FractionPrecision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - static FractionRounder maxFraction(int32_t maxFractionPlaces); + static FractionPrecision maxFraction(int32_t maxFractionPlaces); /** * Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator); @@ -796,10 +521,10 @@ class U_I18N_API Rounder : public UMemory { * necessary). * @param maxFractionPlaces * The maximum number of numerals to display after the decimal separator (rounding if necessary). - * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A FractionPrecision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - static FractionRounder minMaxFraction(int32_t minFractionPlaces, int32_t maxFractionPlaces); + static FractionPrecision minMaxFraction(int32_t minFractionPlaces, int32_t maxFractionPlaces); /** * Show numbers rounded if necessary to a certain number of significant digits or significant figures. Additionally, @@ -811,10 +536,10 @@ class U_I18N_API Rounder : public UMemory { * @param minMaxSignificantDigits * The minimum and maximum number of significant digits to display (rounding if too long or padding with * zeros if too short). - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. - * @draft ICU 60 + * @return A precision for chaining or passing to the NumberFormatter precision() setter. + * @draft ICU 62 */ - static DigitRounder fixedDigits(int32_t minMaxSignificantDigits); + static SignificantDigitsPrecision fixedSignificantDigits(int32_t minMaxSignificantDigits); /** * Always show at least a certain number of significant digits/figures, padding with zeros if necessary. Do not @@ -825,20 +550,20 @@ class U_I18N_API Rounder : public UMemory { * * @param minSignificantDigits * The minimum number of significant digits to display (padding with zeros if too short). - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. - * @draft ICU 60 + * @return A precision for chaining or passing to the NumberFormatter precision() setter. + * @draft ICU 62 */ - static DigitRounder minDigits(int32_t minSignificantDigits); + static SignificantDigitsPrecision minSignificantDigits(int32_t minSignificantDigits); /** * Show numbers rounded if necessary to a certain number of significant digits/figures. * * @param maxSignificantDigits * The maximum number of significant digits to display (rounding if too long). - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. - * @draft ICU 60 + * @return A precision for chaining or passing to the NumberFormatter precision() setter. + * @draft ICU 62 */ - static DigitRounder maxDigits(int32_t maxSignificantDigits); + static SignificantDigitsPrecision maxSignificantDigits(int32_t maxSignificantDigits); /** * Show numbers rounded if necessary to a certain number of significant digits/figures; in addition, always show at @@ -848,10 +573,36 @@ class U_I18N_API Rounder : public UMemory { * The minimum number of significant digits to display (padding with zeros if necessary). * @param maxSignificantDigits * The maximum number of significant digits to display (rounding if necessary). - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. - * @draft ICU 60 + * @return A precision for chaining or passing to the NumberFormatter precision() setter. + * @draft ICU 62 */ - static DigitRounder minMaxDigits(int32_t minSignificantDigits, int32_t maxSignificantDigits); + static SignificantDigitsPrecision minMaxSignificantDigits(int32_t minSignificantDigits, + int32_t maxSignificantDigits); + +#ifndef U_HIDE_DEPRECATED_API + // Compatiblity methods that will be removed in ICU 64. + // See http://bugs.icu-project.org/trac/ticket/13746 + + /** @deprecated ICU 62 */ + static inline SignificantDigitsPrecision fixedDigits(int32_t a) { + return fixedSignificantDigits(a); + } + + /** @deprecated ICU 62 */ + static inline SignificantDigitsPrecision minDigits(int32_t a) { + return minSignificantDigits(a); + } + + /** @deprecated ICU 62 */ + static inline SignificantDigitsPrecision maxDigits(int32_t a) { + return maxSignificantDigits(a); + } + + /** @deprecated ICU 62 */ + static inline SignificantDigitsPrecision minMaxDigits(int32_t a, int32_t b) { + return minMaxSignificantDigits(a, b); + } +#endif /* U_HIDE_DEPRECATED_API */ /** * Show numbers rounded if necessary to the closest multiple of a certain rounding increment. For example, if the @@ -864,20 +615,21 @@ class U_I18N_API Rounder : public UMemory { * decimal separator (to display 1.2 as "1.00" and 1.3 as "1.50"), you can run: * *

-     * Rounder::increment(0.5).withMinFraction(2)
+     * Precision::increment(0.5).withMinFraction(2)
      * 
* * @param roundingIncrement * The increment to which to round numbers. - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A precision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - static IncrementRounder increment(double roundingIncrement); + static IncrementPrecision increment(double roundingIncrement); /** - * Show numbers rounded and padded according to the rules for the currency unit. The most common rounding settings - * for currencies include Rounder.fixedFraction(2), Rounder.integer(), and - * Rounder.increment(0.05) for cash transactions ("nickel rounding"). + * Show numbers rounded and padded according to the rules for the currency unit. The most common + * rounding precision settings for currencies include Precision::fixedFraction(2), + * Precision::integer(), and Precision::increment(0.05) for cash transactions + * ("nickel rounding"). * *

* The exact rounding details will be resolved at runtime based on the currency unit specified in the @@ -887,24 +639,28 @@ class U_I18N_API Rounder : public UMemory { * @param currencyUsage * Either STANDARD (for digital transactions) or CASH (for transactions where the rounding increment may * be limited by the available denominations of cash or coins). - * @return A CurrencyRounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A CurrencyPrecision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - static CurrencyRounder currency(UCurrencyUsage currencyUsage); + static CurrencyPrecision currency(UCurrencyUsage currencyUsage); +#ifndef U_HIDE_DEPRECATED_API /** * Sets the rounding mode to use when picking the direction to round (up or down). Common values * include HALF_EVEN, HALF_UP, and FLOOR. The default is HALF_EVEN. * * @param roundingMode * The RoundingMode to use. - * @return A Rounder for passing to the NumberFormatter rounding() setter. - * @draft ICU 60 + * @return A Precision for passing to the NumberFormatter precision() setter. + * @deprecated ICU 62 Use the top-level roundingMode() setting instead. + * This method will be removed in ICU 64. + * See http://bugs.icu-project.org/trac/ticket/13746 */ - Rounder withMode(UNumberFormatRoundingMode roundingMode) const; + Precision withMode(UNumberFormatRoundingMode roundingMode) const; +#endif /* U_HIDE_DEPRECATED_API */ private: - enum RounderType { + enum PrecisionType { RND_BOGUS, RND_NONE, RND_FRACTION, @@ -912,11 +668,10 @@ class U_I18N_API Rounder : public UMemory { RND_FRACTION_SIGNIFICANT, RND_INCREMENT, RND_CURRENCY, - RND_PASS_THROUGH, RND_ERROR } fType; - union RounderUnion { + union PrecisionUnion { struct FractionSignificantSettings { // For RND_FRACTION, RND_SIGNIFICANT, and RND_FRACTION_SIGNIFICANT impl::digits_t fMinFrac; @@ -927,24 +682,27 @@ class U_I18N_API Rounder : public UMemory { struct IncrementSettings { double fIncrement; impl::digits_t fMinFrac; + impl::digits_t fMaxFrac; } increment; // For RND_INCREMENT UCurrencyUsage currencyUsage; // For RND_CURRENCY UErrorCode errorCode; // For RND_ERROR } fUnion; - typedef RounderUnion::FractionSignificantSettings FractionSignificantSettings; - typedef RounderUnion::IncrementSettings IncrementSettings; + typedef PrecisionUnion::FractionSignificantSettings FractionSignificantSettings; + typedef PrecisionUnion::IncrementSettings IncrementSettings; + /** The Precision encapsulates the RoundingMode when used within the implementation. */ UNumberFormatRoundingMode fRoundingMode; - Rounder(const RounderType &type, const RounderUnion &union_, UNumberFormatRoundingMode roundingMode) + Precision(const PrecisionType& type, const PrecisionUnion& union_, + UNumberFormatRoundingMode roundingMode) : fType(type), fUnion(union_), fRoundingMode(roundingMode) {} - Rounder(UErrorCode errorCode) : fType(RND_ERROR) { + Precision(UErrorCode errorCode) : fType(RND_ERROR) { fUnion.errorCode = errorCode; } - Rounder() : fType(RND_BOGUS) {} + Precision() : fType(RND_BOGUS) {} bool isBogus() const { return fType == RND_BOGUS; @@ -958,47 +716,21 @@ class U_I18N_API Rounder : public UMemory { return FALSE; } - // On the parent type so that this method can be called internally on Rounder instances. - Rounder withCurrency(const CurrencyUnit ¤cy, UErrorCode &status) const; - - /** NON-CONST: mutates the current instance. */ - void setLocaleData(const CurrencyUnit ¤cy, UErrorCode &status); - - void apply(impl::DecimalQuantity &value, UErrorCode &status) const; - - /** Version of {@link #apply} that obeys minInt constraints. Used for scientific notation compatibility mode. */ - void apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode status); - - /** - * Rounding endpoint used by Engineering and Compact notation. Chooses the most appropriate multiplier (magnitude - * adjustment), applies the adjustment, rounds, and returns the chosen multiplier. - * - *

- * In most cases, this is simple. However, when rounding the number causes it to cross a multiplier boundary, we - * need to re-do the rounding. For example, to display 999,999 in Engineering notation with 2 sigfigs, first you - * guess the multiplier to be -3. However, then you end up getting 1000E3, which is not the correct output. You then - * change your multiplier to be -6, and you get 1.0E6, which is correct. - * - * @param input The quantity to process. - * @param producer Function to call to return a multiplier based on a magnitude. - * @return The number of orders of magnitude the input was adjusted by this method. - */ - int32_t - chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer, - UErrorCode &status); + // On the parent type so that this method can be called internally on Precision instances. + Precision withCurrency(const CurrencyUnit ¤cy, UErrorCode &status) const; - static FractionRounder constructFraction(int32_t minFrac, int32_t maxFrac); + static FractionPrecision constructFraction(int32_t minFrac, int32_t maxFrac); - static Rounder constructSignificant(int32_t minSig, int32_t maxSig); + static Precision constructSignificant(int32_t minSig, int32_t maxSig); - static Rounder - constructFractionSignificant(const FractionRounder &base, int32_t minSig, int32_t maxSig); + static Precision + constructFractionSignificant(const FractionPrecision &base, int32_t minSig, int32_t maxSig); - static IncrementRounder constructIncrement(double increment, int32_t minFrac); + static IncrementPrecision constructIncrement(double increment, int32_t minFrac); - static CurrencyRounder constructCurrency(UCurrencyUsage usage); + static CurrencyPrecision constructCurrency(UCurrencyUsage usage); - static Rounder constructPassThrough(); + static Precision constructPassThrough(); // To allow MacroProps/MicroProps to initialize bogus instances: friend struct impl::MacroProps; @@ -1007,28 +739,31 @@ class U_I18N_API Rounder : public UMemory { // To allow NumberFormatterImpl to access isBogus() and other internal methods: friend class impl::NumberFormatterImpl; - // To give access to apply() and chooseMultiplierAndApply(): - friend class impl::MutablePatternModifier; - friend class impl::LongNameHandler; - friend class impl::ScientificHandler; - friend class impl::CompactHandler; + // To allow NumberPropertyMapper to create instances from DecimalFormatProperties: + friend class impl::NumberPropertyMapper; + + // To allow access to the main implementation class: + friend class impl::RoundingImpl; // To allow child classes to call private methods: - friend class FractionRounder; - friend class CurrencyRounder; - friend class IncrementRounder; + friend class FractionPrecision; + friend class CurrencyPrecision; + friend class IncrementPrecision; + + // To allow access to the skeleton generation code: + friend class impl::GeneratorHelpers; }; /** - * A class that defines a rounding strategy based on a number of fraction places and optionally significant digits to be + * A class that defines a rounding precision based on a number of fraction places and optionally significant digits to be * used when formatting numbers in NumberFormatter. * *

- * To create a FractionRounder, use one of the factory methods on Rounder. + * To create a FractionPrecision, use one of the factory methods on Precision. * * @draft ICU 60 */ -class U_I18N_API FractionRounder : public Rounder { +class U_I18N_API FractionPrecision : public Precision { public: /** * Ensure that no less than this number of significant digits are retained when rounding according to fraction @@ -1043,10 +778,10 @@ class U_I18N_API FractionRounder : public Rounder { * * @param minSignificantDigits * The number of significant figures to guarantee. - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A precision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - Rounder withMinDigits(int32_t minSignificantDigits) const; + Precision withMinDigits(int32_t minSignificantDigits) const; /** * Ensure that no more than this number of significant digits are retained when rounding according to fraction @@ -1062,36 +797,36 @@ class U_I18N_API FractionRounder : public Rounder { * * @param maxSignificantDigits * Round the number to no more than this number of significant figures. - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A precision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - Rounder withMaxDigits(int32_t maxSignificantDigits) const; + Precision withMaxDigits(int32_t maxSignificantDigits) const; private: // Inherit constructor - using Rounder::Rounder; + using Precision::Precision; // To allow parent class to call this class's constructor: - friend class Rounder; + friend class Precision; }; /** - * A class that defines a rounding strategy parameterized by a currency to be used when formatting numbers in + * A class that defines a rounding precision parameterized by a currency to be used when formatting numbers in * NumberFormatter. * *

- * To create a CurrencyRounder, use one of the factory methods on Rounder. + * To create a CurrencyPrecision, use one of the factory methods on Precision. * * @draft ICU 60 */ -class U_I18N_API CurrencyRounder : public Rounder { +class U_I18N_API CurrencyPrecision : public Precision { public: /** - * Associates a currency with this rounding strategy. + * Associates a currency with this rounding precision. * *

* Calling this method is not required, because the currency specified in unit() - * is automatically applied to currency rounding strategies. However, + * is automatically applied to currency rounding precisions. However, * this method enables you to override that automatic association. * *

@@ -1099,30 +834,30 @@ class U_I18N_API CurrencyRounder : public Rounder { * currency format. * * @param currency - * The currency to associate with this rounding strategy. - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. + * The currency to associate with this rounding precision. + * @return A precision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - Rounder withCurrency(const CurrencyUnit ¤cy) const; + Precision withCurrency(const CurrencyUnit ¤cy) const; private: // Inherit constructor - using Rounder::Rounder; + using Precision::Precision; // To allow parent class to call this class's constructor: - friend class Rounder; + friend class Precision; }; /** - * A class that defines a rounding strategy parameterized by a rounding increment to be used when formatting numbers in + * A class that defines a rounding precision parameterized by a rounding increment to be used when formatting numbers in * NumberFormatter. * *

- * To create an IncrementRounder, use one of the factory methods on Rounder. + * To create an IncrementPrecision, use one of the factory methods on Precision. * * @draft ICU 60 */ -class U_I18N_API IncrementRounder : public Rounder { +class U_I18N_API IncrementPrecision : public Precision { public: /** * Specifies the minimum number of fraction digits to render after the decimal separator, padding with zeros if @@ -1136,17 +871,17 @@ class U_I18N_API IncrementRounder : public Rounder { * Note: In ICU4J, this functionality is accomplished via the scale of the BigDecimal rounding increment. * * @param minFrac The minimum number of digits after the decimal separator. - * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. + * @return A precision for chaining or passing to the NumberFormatter precision() setter. * @draft ICU 60 */ - Rounder withMinFraction(int32_t minFrac) const; + Precision withMinFraction(int32_t minFrac) const; private: // Inherit constructor - using Rounder::Rounder; + using Precision::Precision; // To allow parent class to call this class's constructor: - friend class Rounder; + friend class Precision; }; /** @@ -1170,7 +905,6 @@ class U_I18N_API IntegerWidth : public UMemory { * The minimum number of places before the decimal separator. * @return An IntegerWidth for chaining or passing to the NumberFormatter integerWidth() setter. * @draft ICU 60 - * @see NumberFormatter */ static IntegerWidth zeroFillTo(int32_t minInt); @@ -1184,7 +918,6 @@ class U_I18N_API IntegerWidth : public UMemory { * truncation. * @return An IntegerWidth for passing to the NumberFormatter integerWidth() setter. * @draft ICU 60 - * @see NumberFormatter */ IntegerWidth truncateAt(int32_t maxInt); @@ -1193,12 +926,13 @@ class U_I18N_API IntegerWidth : public UMemory { struct { impl::digits_t fMinInt; impl::digits_t fMaxInt; + bool fFormatFailIfMoreThanMaxDigits; } minMaxInt; UErrorCode errorCode; } fUnion; bool fHasError = false; - IntegerWidth(impl::digits_t minInt, impl::digits_t maxInt); + IntegerWidth(impl::digits_t minInt, impl::digits_t maxInt, bool formatFailIfMoreThanMaxDigits); IntegerWidth(UErrorCode errorCode) { // NOLINT fUnion.errorCode = errorCode; @@ -1209,6 +943,11 @@ class U_I18N_API IntegerWidth : public UMemory { fUnion.minMaxInt.fMinInt = -1; } + /** Returns the default instance. */ + static IntegerWidth standard() { + return IntegerWidth::zeroFillTo(1); + } + bool isBogus() const { return !fHasError && fUnion.minMaxInt.fMinInt == -1; } @@ -1223,69 +962,214 @@ class U_I18N_API IntegerWidth : public UMemory { void apply(impl::DecimalQuantity &quantity, UErrorCode &status) const; + bool operator==(const IntegerWidth& other) const; + // To allow MacroProps/MicroProps to initialize empty instances: friend struct impl::MacroProps; friend struct impl::MicroProps; // To allow NumberFormatterImpl to access isBogus() and perform other operations: friend class impl::NumberFormatterImpl; -}; - -namespace impl { - -// Do not enclose entire SymbolsWrapper with #ifndef U_HIDE_INTERNAL_API, needed for a protected field -/** @internal */ -class U_I18N_API SymbolsWrapper : public UMemory { - public: - /** @internal */ - SymbolsWrapper() : fType(SYMPTR_NONE), fPtr{nullptr} {} - /** @internal */ - SymbolsWrapper(const SymbolsWrapper &other); - - /** @internal */ - ~SymbolsWrapper(); + // So that NumberPropertyMapper can create instances + friend class impl::NumberPropertyMapper; - /** @internal */ - SymbolsWrapper &operator=(const SymbolsWrapper &other); + // To allow access to the skeleton generation code: + friend class impl::GeneratorHelpers; +}; -#ifndef U_HIDE_INTERNAL_API +/** + * A class that defines a quantity by which a number should be multiplied when formatting. + * + *

+ * To create a Scale, use one of the factory methods. + * + * @draft ICU 62 + */ +class U_I18N_API Scale : public UMemory { + public: /** - * The provided object is copied, but we do not adopt it. - * @internal + * Do not change the value of numbers when formatting or parsing. + * + * @return A Scale to prevent any multiplication. + * @draft ICU 62 */ - void setTo(const DecimalFormatSymbols &dfs); + static Scale none(); /** - * Adopt the provided object. - * @internal + * Multiply numbers by a power of ten before formatting. Useful for combining with a percent unit: + * + *

+     * NumberFormatter::with().unit(NoUnit::percent()).multiplier(Scale::powerOfTen(2))
+     * 
+ * + * @return A Scale for passing to the setter in NumberFormatter. + * @draft ICU 62 */ - void setTo(const NumberingSystem *ns); + static Scale powerOfTen(int32_t power); /** - * Whether the object is currently holding a DecimalFormatSymbols. - * @internal + * Multiply numbers by an arbitrary value before formatting. Useful for unit conversions. + * + * This method takes a string in a decimal number format with syntax + * as defined in the Decimal Arithmetic Specification, available at + * http://speleotrove.com/decimal + * + * Also see the version of this method that takes a double. + * + * @return A Scale for passing to the setter in NumberFormatter. + * @draft ICU 62 */ - bool isDecimalFormatSymbols() const; + static Scale byDecimal(StringPiece multiplicand); /** - * Whether the object is currently holding a NumberingSystem. - * @internal + * Multiply numbers by an arbitrary value before formatting. Useful for unit conversions. + * + * This method takes a double; also see the version of this method that takes an exact decimal. + * + * @return A Scale for passing to the setter in NumberFormatter. + * @draft ICU 62 */ - bool isNumberingSystem() const; + static Scale byDouble(double multiplicand); /** - * Get the DecimalFormatSymbols pointer. No ownership change. - * @internal + * Multiply a number by both a power of ten and by an arbitrary double value. + * + * @return A Scale for passing to the setter in NumberFormatter. + * @draft ICU 62 */ - const DecimalFormatSymbols *getDecimalFormatSymbols() const; + static Scale byDoubleAndPowerOfTen(double multiplicand, int32_t power); - /** + // We need a custom destructor for the DecNum, which means we need to declare + // the copy/move constructor/assignment quartet. + + /** @draft ICU 62 */ + Scale(const Scale& other); + + /** @draft ICU 62 */ + Scale& operator=(const Scale& other); + + /** @draft ICU 62 */ + Scale(Scale&& src) U_NOEXCEPT; + + /** @draft ICU 62 */ + Scale& operator=(Scale&& src) U_NOEXCEPT; + + /** @draft ICU 62 */ + ~Scale(); + +#ifndef U_HIDE_INTERNAL_API + /** @internal */ + Scale(int32_t magnitude, impl::DecNum* arbitraryToAdopt); +#endif /* U_HIDE_INTERNAL_API */ + + private: + int32_t fMagnitude; + impl::DecNum* fArbitrary; + UErrorCode fError; + + Scale(UErrorCode error) : fMagnitude(0), fArbitrary(nullptr), fError(error) {} + + Scale() : fMagnitude(0), fArbitrary(nullptr), fError(U_ZERO_ERROR) {} + + bool isValid() const { + return fMagnitude != 0 || fArbitrary != nullptr; + } + + UBool copyErrorTo(UErrorCode &status) const { + if (fError != U_ZERO_ERROR) { + status = fError; + return TRUE; + } + return FALSE; + } + + void applyTo(impl::DecimalQuantity& quantity) const; + + void applyReciprocalTo(impl::DecimalQuantity& quantity) const; + + // To allow MacroProps/MicroProps to initialize empty instances: + friend struct impl::MacroProps; + friend struct impl::MicroProps; + + // To allow NumberFormatterImpl to access isBogus() and perform other operations: + friend class impl::NumberFormatterImpl; + + // To allow the helper class MultiplierFormatHandler access to private fields: + friend class impl::MultiplierFormatHandler; + + // To allow access to the skeleton generation code: + friend class impl::GeneratorHelpers; + + // To allow access to parsing code: + friend class ::icu::numparse::impl::NumberParserImpl; + friend class ::icu::numparse::impl::MultiplierParseHandler; +}; + +namespace impl { + +// Do not enclose entire SymbolsWrapper with #ifndef U_HIDE_INTERNAL_API, needed for a protected field +/** @internal */ +class U_I18N_API SymbolsWrapper : public UMemory { + public: + /** @internal */ + SymbolsWrapper() : fType(SYMPTR_NONE), fPtr{nullptr} {} + + /** @internal */ + SymbolsWrapper(const SymbolsWrapper &other); + + /** @internal */ + SymbolsWrapper &operator=(const SymbolsWrapper &other); + + /** @internal */ + SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT; + + /** @internal */ + SymbolsWrapper &operator=(SymbolsWrapper&& src) U_NOEXCEPT; + + /** @internal */ + ~SymbolsWrapper(); + +#ifndef U_HIDE_INTERNAL_API + + /** + * The provided object is copied, but we do not adopt it. + * @internal + */ + void setTo(const DecimalFormatSymbols &dfs); + + /** + * Adopt the provided object. + * @internal + */ + void setTo(const NumberingSystem *ns); + + /** + * Whether the object is currently holding a DecimalFormatSymbols. + * @internal + */ + bool isDecimalFormatSymbols() const; + + /** + * Whether the object is currently holding a NumberingSystem. + * @internal + */ + bool isNumberingSystem() const; + + /** + * Get the DecimalFormatSymbols pointer. No ownership change. + * @internal + */ + const DecimalFormatSymbols *getDecimalFormatSymbols() const; + + /** * Get the NumberingSystem pointer. No ownership change. * @internal */ const NumberingSystem *getNumberingSystem() const; +#endif // U_HIDE_INTERNAL_API + /** @internal */ UBool copyErrorTo(UErrorCode &status) const { if (fType == SYMPTR_DFS && fPtr.dfs == nullptr) { @@ -1297,7 +1181,6 @@ class U_I18N_API SymbolsWrapper : public UMemory { } return FALSE; } -#endif // U_HIDE_INTERNAL_API private: enum SymbolsPointerType { @@ -1311,6 +1194,8 @@ class U_I18N_API SymbolsWrapper : public UMemory { void doCopyFrom(const SymbolsWrapper &other); + void doMoveFrom(SymbolsWrapper&& src); + void doCleanup(); }; @@ -1322,13 +1207,28 @@ class U_I18N_API Grouper : public UMemory { /** @internal */ static Grouper forStrategy(UGroupingStrategy grouping); + /** + * Resolve the values in Properties to a Grouper object. + * @internal + */ + static Grouper forProperties(const DecimalFormatProperties& properties); + // Future: static Grouper forProperties(DecimalFormatProperties& properties); /** @internal */ - Grouper(int16_t grouping1, int16_t grouping2, int16_t minGrouping) - : fGrouping1(grouping1), fGrouping2(grouping2), fMinGrouping(minGrouping) {} + Grouper(int16_t grouping1, int16_t grouping2, int16_t minGrouping, UGroupingStrategy strategy) + : fGrouping1(grouping1), + fGrouping2(grouping2), + fMinGrouping(minGrouping), + fStrategy(strategy) {} #endif // U_HIDE_INTERNAL_API + /** @internal */ + int16_t getPrimary() const; + + /** @internal */ + int16_t getSecondary() const; + private: /** * The grouping sizes, with the following special values: @@ -1342,7 +1242,7 @@ class U_I18N_API Grouper : public UMemory { int16_t fGrouping2; /** - * The minimum gropuing size, with the following special values: + * The minimum grouping size, with the following special values: *
    *
  • -2 = needs locale data *
  • -3 = no less than 2 @@ -1350,6 +1250,12 @@ class U_I18N_API Grouper : public UMemory { */ int16_t fMinGrouping; + /** + * The UGroupingStrategy that was used to create this Grouper, or UNUM_GROUPING_COUNT if this + * was not created from a UGroupingStrategy. + */ + UGroupingStrategy fStrategy; + Grouper() : fGrouping1(-3) {}; bool isBogus() const { @@ -1367,6 +1273,12 @@ class U_I18N_API Grouper : public UMemory { // To allow NumberFormatterImpl to access isBogus() and perform other operations: friend class NumberFormatterImpl; + + // To allow NumberParserImpl to perform setLocaleData(): + friend class ::icu::numparse::impl::NumberParserImpl; + + // To allow access to the skeleton generation code: + friend class impl::GeneratorHelpers; }; // Do not enclose entire Padder with #ifndef U_HIDE_INTERNAL_API, needed for a protected field @@ -1381,6 +1293,9 @@ class U_I18N_API Padder : public UMemory { static Padder codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosition position); #endif // U_HIDE_INTERNAL_API + /** @internal */ + static Padder forProperties(const DecimalFormatProperties& properties); + private: UChar32 fWidth; // -3 = error; -2 = bogus; -1 = no padding union { @@ -1427,6 +1342,9 @@ class U_I18N_API Padder : public UMemory { // To allow NumberFormatterImpl to access isBogus() and perform other operations: friend class impl::NumberFormatterImpl; + + // To allow access to the skeleton generation code: + friend class impl::GeneratorHelpers; }; // Do not enclose entire MacroProps with #ifndef U_HIDE_INTERNAL_API, needed for a protected field @@ -1442,7 +1360,10 @@ struct U_I18N_API MacroProps : public UMemory { MeasureUnit perUnit; // = NoUnit::base(); /** @internal */ - Rounder rounder; // = Rounder(); (bogus) + Precision precision; // = Precision(); (bogus) + + /** @internal */ + UNumberFormatRoundingMode roundingMode = UNUM_ROUND_HALFEVEN; /** @internal */ Grouper grouper; // = Grouper(); (bogus) @@ -1468,20 +1389,33 @@ struct U_I18N_API MacroProps : public UMemory { UNumberDecimalSeparatorDisplay decimal = UNUM_DECIMAL_SEPARATOR_COUNT; /** @internal */ - PluralRules *rules = nullptr; // no ownership + Scale scale; // = Scale(); (benign value) + + /** @internal */ + const AffixPatternProvider* affixProvider = nullptr; // no ownership + + /** @internal */ + const PluralRules* rules = nullptr; // no ownership + + /** @internal */ + const CurrencySymbols* currencySymbols = nullptr; // no ownership /** @internal */ int32_t threshold = DEFAULT_THRESHOLD; + + /** @internal */ Locale locale; + // NOTE: Uses default copy and move constructors. + /** * Check all members for errors. * @internal */ bool copyErrorTo(UErrorCode &status) const { - return notation.copyErrorTo(status) || rounder.copyErrorTo(status) || + return notation.copyErrorTo(status) || precision.copyErrorTo(status) || padder.copyErrorTo(status) || integerWidth.copyErrorTo(status) || - symbols.copyErrorTo(status); + symbols.copyErrorTo(status) || scale.copyErrorTo(status); } }; @@ -1505,7 +1439,7 @@ class U_I18N_API NumberFormatterSettings { * *

    * All notation styles will be properly localized with locale data, and all notation styles are compatible with - * units, rounding strategies, and other number formatter settings. + * units, rounding precisions, and other number formatter settings. * *

    * Pass this method the return value of a {@link Notation} factory method. For example: @@ -1522,7 +1456,18 @@ class U_I18N_API NumberFormatterSettings { * @see Notation * @draft ICU 60 */ - Derived notation(const Notation ¬ation) const; + Derived notation(const Notation ¬ation) const &; + + /** + * Overload of notation() for use on an rvalue reference. + * + * @param notation + * The notation strategy to use. + * @return The fluent chain. + * @see #notation + * @draft ICU 62 + */ + Derived notation(const Notation ¬ation) &&; /** * Specifies the unit (unit of measure, currency, or percent) to associate with rendered numbers. @@ -1534,7 +1479,7 @@ class U_I18N_API NumberFormatterSettings { *

* * All units will be properly localized with locale data, and all units are compatible with notation styles, - * rounding strategies, and other number formatter settings. + * rounding precisions, and other number formatter settings. * * Pass this method any instance of {@link MeasureUnit}. For units of measure (which often involve the * factory methods that return a pointer): @@ -1568,7 +1513,18 @@ class U_I18N_API NumberFormatterSettings { * @see #perUnit * @draft ICU 60 */ - Derived unit(const icu::MeasureUnit &unit) const; + Derived unit(const icu::MeasureUnit &unit) const &; + + /** + * Overload of unit() for use on an rvalue reference. + * + * @param unit + * The unit to render. + * @return The fluent chain. + * @see #unit + * @draft ICU 62 + */ + Derived unit(const icu::MeasureUnit &unit) &&; /** * Like unit(), but takes ownership of a pointer. Convenient for use with the MeasureFormat factory @@ -1585,7 +1541,18 @@ class U_I18N_API NumberFormatterSettings { * @see MeasureUnit * @draft ICU 60 */ - Derived adoptUnit(icu::MeasureUnit *unit) const; + Derived adoptUnit(icu::MeasureUnit *unit) const &; + + /** + * Overload of adoptUnit() for use on an rvalue reference. + * + * @param unit + * The unit to render. + * @return The fluent chain. + * @see #adoptUnit + * @draft ICU 62 + */ + Derived adoptUnit(icu::MeasureUnit *unit) &&; /** * Sets a unit to be used in the denominator. For example, to format "3 m/s", pass METER to the unit and SECOND to @@ -1604,7 +1571,18 @@ class U_I18N_API NumberFormatterSettings { * @see #unit * @draft ICU 61 */ - Derived perUnit(const icu::MeasureUnit &perUnit) const; + Derived perUnit(const icu::MeasureUnit &perUnit) const &; + + /** + * Overload of perUnit() for use on an rvalue reference. + * + * @param perUnit + * The unit to render in the denominator. + * @return The fluent chain. + * @see #perUnit + * @draft ICU 62 + */ + Derived perUnit(const icu::MeasureUnit &perUnit) &&; /** * Like perUnit(), but takes ownership of a pointer. Convenient for use with the MeasureFormat factory @@ -1623,10 +1601,21 @@ class U_I18N_API NumberFormatterSettings { * @see MeasureUnit * @draft ICU 61 */ - Derived adoptPerUnit(icu::MeasureUnit *perUnit) const; + Derived adoptPerUnit(icu::MeasureUnit *perUnit) const &; /** - * Specifies the rounding strategy to use when formatting numbers. + * Overload of adoptPerUnit() for use on an rvalue reference. + * + * @param perUnit + * The unit to render in the denominator. + * @return The fluent chain. + * @see #adoptPerUnit + * @draft ICU 62 + */ + Derived adoptPerUnit(icu::MeasureUnit *perUnit) &&; + + /** + * Specifies the rounding precision to use when formatting numbers. * *
    *
  • Round to 3 decimal places: "3.142" @@ -1636,27 +1625,77 @@ class U_I18N_API NumberFormatterSettings { *
* *

- * Pass this method the return value of one of the factory methods on {@link Rounder}. For example: + * Pass this method the return value of one of the factory methods on {@link Precision}. For example: * *

-     * NumberFormatter::with().rounding(Rounder::fixedFraction(2))
+     * NumberFormatter::with().precision(Precision::fixedFraction(2))
      * 
* *

* In most cases, the default rounding strategy is to round to 6 fraction places; i.e., - * Rounder.maxFraction(6). The exceptions are if compact notation is being used, then the compact + * Precision.maxFraction(6). The exceptions are if compact notation is being used, then the compact * notation rounding strategy is used (see {@link Notation#compactShort} for details), or if the unit is a currency, - * then standard currency rounding is used, which varies from currency to currency (see {@link Rounder#currency} for + * then standard currency rounding is used, which varies from currency to currency (see {@link Precision#currency} for * details). * - * @param rounder - * The rounding strategy to use. + * @param precision + * The rounding precision to use. * @return The fluent chain. - * @see Rounder - * @provisional This API might change or be removed in a future release. - * @draft ICU 60 + * @see Precision + * @draft ICU 62 + */ + Derived precision(const Precision& precision) const &; + + /** + * Overload of precision() for use on an rvalue reference. + * + * @param precision + * The rounding precision to use. + * @return The fluent chain. + * @see #precision + * @draft ICU 62 + */ + Derived precision(const Precision& precision) &&; + +#ifndef U_HIDE_DEPRECATED_API + // Compatibility method that will be removed in ICU 64. + // Use precision() instead. + // See http://bugs.icu-project.org/trac/ticket/13746 + /** @deprecated ICU 62 */ + Derived rounding(const Rounder& rounder) const & { + return precision(rounder); + } +#endif /* U_HIDE_DEPRECATED_API */ + + /** + * Specifies how to determine the direction to round a number when it has more digits than fit in the + * desired precision. When formatting 1.235: + * + *

    + *
  • Ceiling rounding mode with integer precision: "2" + *
  • Half-down rounding mode with 2 fixed fraction digits: "1.23" + *
  • Half-up rounding mode with 2 fixed fraction digits: "1.24" + *
+ * + * The default is HALF_EVEN. For more information on rounding mode, see the ICU userguide here: + * + * http://userguide.icu-project.org/formatparse/numbers/rounding-modes + * + * @param roundingMode The rounding mode to use. + * @return The fluent chain. + * @draft ICU 62 + */ + Derived roundingMode(UNumberFormatRoundingMode roundingMode) const &; + + /** + * Overload of roundingMode() for use on an rvalue reference. + * + * @param roundingMode The rounding mode to use. + * @return The fluent chain. + * @see #roundingMode + * @draft ICU 62 */ - Derived rounding(const Rounder &rounder) const; + Derived roundingMode(UNumberFormatRoundingMode roundingMode) &&; /** * Specifies the grouping strategy to use when formatting numbers. @@ -1685,7 +1724,19 @@ class U_I18N_API NumberFormatterSettings { * @return The fluent chain. * @draft ICU 61 */ - Derived grouping(const UGroupingStrategy &strategy) const; + Derived grouping(UGroupingStrategy strategy) const &; + + /** + * Overload of grouping() for use on an rvalue reference. + * + * @param strategy + * The grouping strategy to use. + * @return The fluent chain. + * @see #grouping + * @provisional This API might change or be removed in a future release. + * @draft ICU 62 + */ + Derived grouping(UGroupingStrategy strategy) &&; /** * Specifies the minimum and maximum number of digits to render before the decimal mark. @@ -1711,7 +1762,18 @@ class U_I18N_API NumberFormatterSettings { * @see IntegerWidth * @draft ICU 60 */ - Derived integerWidth(const IntegerWidth &style) const; + Derived integerWidth(const IntegerWidth &style) const &; + + /** + * Overload of integerWidth() for use on an rvalue reference. + * + * @param style + * The integer width to use. + * @return The fluent chain. + * @see #integerWidth + * @draft ICU 62 + */ + Derived integerWidth(const IntegerWidth &style) &&; /** * Specifies the symbols (decimal separator, grouping separator, percent sign, numerals, etc.) to use when rendering @@ -1741,8 +1803,8 @@ class U_I18N_API NumberFormatterSettings { * after passing it into the fluent chain will not be seen. * *

- * Note: Calling this method will override the NumberingSystem previously specified in - * {@link #symbols(NumberingSystem)}. + * Note: Calling this method will override any previously specified DecimalFormatSymbols + * or NumberingSystem. * *

* The default is to choose the symbols based on the locale specified in the fluent chain. @@ -1753,7 +1815,18 @@ class U_I18N_API NumberFormatterSettings { * @see DecimalFormatSymbols * @draft ICU 60 */ - Derived symbols(const DecimalFormatSymbols &symbols) const; + Derived symbols(const DecimalFormatSymbols &symbols) const &; + + /** + * Overload of symbols() for use on an rvalue reference. + * + * @param symbols + * The DecimalFormatSymbols to use. + * @return The fluent chain. + * @see #symbols + * @draft ICU 62 + */ + Derived symbols(const DecimalFormatSymbols &symbols) &&; /** * Specifies that the given numbering system should be used when fetching symbols. @@ -1773,8 +1846,8 @@ class U_I18N_API NumberFormatterSettings { * * *

- * Note: Calling this method will override the DecimalFormatSymbols previously specified in - * {@link #symbols(DecimalFormatSymbols)}. + * Note: Calling this method will override any previously specified DecimalFormatSymbols + * or NumberingSystem. * *

* The default is to choose the best numbering system for the locale. @@ -1788,7 +1861,18 @@ class U_I18N_API NumberFormatterSettings { * @see NumberingSystem * @draft ICU 60 */ - Derived adoptSymbols(NumberingSystem *symbols) const; + Derived adoptSymbols(NumberingSystem *symbols) const &; + + /** + * Overload of adoptSymbols() for use on an rvalue reference. + * + * @param symbols + * The NumberingSystem to use. + * @return The fluent chain. + * @see #adoptSymbols + * @draft ICU 62 + */ + Derived adoptSymbols(NumberingSystem *symbols) &&; /** * Sets the width of the unit (measure unit or currency). Most common values: @@ -1815,7 +1899,18 @@ class U_I18N_API NumberFormatterSettings { * @see UNumberUnitWidth * @draft ICU 60 */ - Derived unitWidth(const UNumberUnitWidth &width) const; + Derived unitWidth(UNumberUnitWidth width) const &; + + /** + * Overload of unitWidth() for use on an rvalue reference. + * + * @param width + * The width to use when rendering numbers. + * @return The fluent chain. + * @see #unitWidth + * @draft ICU 62 + */ + Derived unitWidth(UNumberUnitWidth width) &&; /** * Sets the plus/minus sign display strategy. Most common values: @@ -1836,14 +1931,24 @@ class U_I18N_API NumberFormatterSettings { *

* The default is AUTO sign display. * - * @param width + * @param style * The sign display strategy to use when rendering numbers. * @return The fluent chain * @see UNumberSignDisplay - * @provisional This API might change or be removed in a future release. * @draft ICU 60 */ - Derived sign(const UNumberSignDisplay &width) const; + Derived sign(UNumberSignDisplay style) const &; + + /** + * Overload of sign() for use on an rvalue reference. + * + * @param style + * The sign display strategy to use when rendering numbers. + * @return The fluent chain. + * @see #sign + * @draft ICU 62 + */ + Derived sign(UNumberSignDisplay style) &&; /** * Sets the decimal separator display strategy. This affects integer numbers with no fraction part. Most common @@ -1864,23 +1969,73 @@ class U_I18N_API NumberFormatterSettings { *

* The default is AUTO decimal separator display. * - * @param width + * @param style * The decimal separator display strategy to use when rendering numbers. * @return The fluent chain * @see UNumberDecimalSeparatorDisplay - * @provisional This API might change or be removed in a future release. * @draft ICU 60 */ - Derived decimal(const UNumberDecimalSeparatorDisplay &width) const; + Derived decimal(UNumberDecimalSeparatorDisplay style) const &; + + /** + * Overload of decimal() for use on an rvalue reference. + * + * @param style + * The decimal separator display strategy to use when rendering numbers. + * @return The fluent chain. + * @see #decimal + * @draft ICU 62 + */ + Derived decimal(UNumberDecimalSeparatorDisplay style) &&; + + /** + * Sets a scale (multiplier) to be used to scale the number by an arbitrary amount before formatting. + * Most common values: + * + *

    + *
  • Multiply by 100: useful for percentages. + *
  • Multiply by an arbitrary value: useful for unit conversions. + *
+ * + *

+ * Pass an element from a {@link Scale} factory method to this setter. For example: + * + *

+     * NumberFormatter::with().scale(Scale::powerOfTen(2))
+     * 
+ * + *

+ * The default is to not apply any multiplier. + * + * @param scale + * The scale to apply when rendering numbers. + * @return The fluent chain + * @draft ICU 62 + */ + Derived scale(const Scale &scale) const &; + + /** + * Overload of scale() for use on an rvalue reference. + * + * @param scale + * The scale to apply when rendering numbers. + * @return The fluent chain. + * @see #scale + * @draft ICU 62 + */ + Derived scale(const Scale &scale) &&; #ifndef U_HIDE_INTERNAL_API /** - * Set the padding strategy. May be added to ICU 61; see #13338. + * Set the padding strategy. May be added in the future; see #13338. * * @internal ICU 60: This API is ICU internal only. */ - Derived padding(const impl::Padder &padder) const; + Derived padding(const impl::Padder &padder) const &; + + /** @internal */ + Derived padding(const impl::Padder &padder) &&; /** * Internal fluent setter to support a custom regulation threshold. A threshold of 1 causes the data structures to @@ -1888,10 +2043,45 @@ class U_I18N_API NumberFormatterSettings { * * @internal ICU 60: This API is ICU internal only. */ - Derived threshold(int32_t threshold) const; + Derived threshold(int32_t threshold) const &; + + /** @internal */ + Derived threshold(int32_t threshold) &&; + + /** + * Internal fluent setter to overwrite the entire macros object. + * + * @internal ICU 60: This API is ICU internal only. + */ + Derived macros(const impl::MacroProps& macros) const &; + + /** @internal */ + Derived macros(const impl::MacroProps& macros) &&; + + /** @internal */ + Derived macros(impl::MacroProps&& macros) const &; + + /** @internal */ + Derived macros(impl::MacroProps&& macros) &&; #endif /* U_HIDE_INTERNAL_API */ + /** + * Creates a skeleton string representation of this number formatter. A skeleton string is a + * locale-agnostic serialized form of a number formatter. + * + * Not all options are capable of being represented in the skeleton string; for example, a + * DecimalFormatSymbols object. If any such option is encountered, the error code is set to + * U_UNSUPPORTED_ERROR. + * + * The returned skeleton is in normalized form, such that two number formatters with equivalent + * behavior should produce the same skeleton. + * + * @return A number skeleton string with behavior corresponding to this number formatter. + * @draft ICU 62 + */ + UnicodeString toSkeleton(UErrorCode& status) const; + /** * Sets the UErrorCode if an error occurred in the fluent chain. * Preserves older error codes in the outErrorCode. @@ -1905,7 +2095,9 @@ class U_I18N_API NumberFormatterSettings { } fMacros.copyErrorTo(outErrorCode); return U_FAILURE(outErrorCode); - } + }; + + // NOTE: Uses default copy and move constructors. protected: impl::MacroProps fMacros; @@ -1944,21 +2136,58 @@ class U_I18N_API UnlocalizedNumberFormatter * @return The fluent chain. * @draft ICU 60 */ - LocalizedNumberFormatter locale(const icu::Locale &locale) const; + LocalizedNumberFormatter locale(const icu::Locale &locale) const &; + + /** + * Overload of locale() for use on an rvalue reference. + * + * @param locale + * The locale to use when loading data for number formatting. + * @return The fluent chain. + * @see #locale + * @draft ICU 62 + */ + LocalizedNumberFormatter locale(const icu::Locale &locale) &&; + + /** + * Default constructor: puts the formatter into a valid but undefined state. + * + * @draft ICU 62 + */ + UnlocalizedNumberFormatter() = default; // Make default copy constructor call the NumberFormatterSettings copy constructor. /** * Returns a copy of this UnlocalizedNumberFormatter. * @draft ICU 60 */ - UnlocalizedNumberFormatter(const UnlocalizedNumberFormatter &other) : UnlocalizedNumberFormatter( - static_cast &>(other)) {} + UnlocalizedNumberFormatter(const UnlocalizedNumberFormatter &other); + + /** + * Move constructor: + * The source UnlocalizedNumberFormatter will be left in a valid but undefined state. + * @draft ICU 62 + */ + UnlocalizedNumberFormatter(UnlocalizedNumberFormatter&& src) U_NOEXCEPT; + + /** + * Copy assignment operator. + * @draft ICU 62 + */ + UnlocalizedNumberFormatter& operator=(const UnlocalizedNumberFormatter& other); + + /** + * Move assignment operator: + * The source UnlocalizedNumberFormatter will be left in a valid but undefined state. + * @draft ICU 62 + */ + UnlocalizedNumberFormatter& operator=(UnlocalizedNumberFormatter&& src) U_NOEXCEPT; private: - UnlocalizedNumberFormatter() = default; + explicit UnlocalizedNumberFormatter(const NumberFormatterSettings& other); explicit UnlocalizedNumberFormatter( - const NumberFormatterSettings &other); + NumberFormatterSettings&& src) U_NOEXCEPT; // To give the fluent setters access to this class's constructor: friend class NumberFormatterSettings; @@ -2016,15 +2245,99 @@ class U_I18N_API LocalizedNumberFormatter * @return A FormattedNumber object; call .toString() to get the string. * @draft ICU 60 */ - FormattedNumber formatDecimal(StringPiece value, UErrorCode &status) const; + FormattedNumber formatDecimal(StringPiece value, UErrorCode& status) const; + +#ifndef U_HIDE_INTERNAL_API + + /** Internal method. + * @internal + */ + FormattedNumber formatDecimalQuantity(const impl::DecimalQuantity& dq, UErrorCode& status) const; + + /** Internal method for DecimalFormat compatibility. + * @internal + */ + void getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result, UErrorCode& status) const; + + /** + * Internal method for testing. + * @internal + */ + const impl::NumberFormatterImpl* getCompiled() const; + + /** + * Internal method for testing. + * @internal + */ + int32_t getCallCount() const; + +#endif + + /** + * Creates a representation of this LocalizedNumberFormat as an icu::Format, enabling the use + * of this number formatter with APIs that need an object of that type, such as MessageFormat. + * + * This API is not intended to be used other than for enabling API compatibility. The formatDouble, + * formatInt, and formatDecimal methods should normally be used when formatting numbers, not the Format + * object returned by this method. + * + * The caller owns the returned object and must delete it when finished. + * + * @return A Format wrapping this LocalizedNumberFormatter. + * @draft ICU 62 + */ + Format* toFormat(UErrorCode& status) const; + + /** + * Default constructor: puts the formatter into a valid but undefined state. + * + * @draft ICU 62 + */ + LocalizedNumberFormatter() = default; // Make default copy constructor call the NumberFormatterSettings copy constructor. /** * Returns a copy of this LocalizedNumberFormatter. * @draft ICU 60 */ - LocalizedNumberFormatter(const LocalizedNumberFormatter &other) : LocalizedNumberFormatter( - static_cast &>(other)) {} + LocalizedNumberFormatter(const LocalizedNumberFormatter &other); + + /** + * Move constructor: + * The source LocalizedNumberFormatter will be left in a valid but undefined state. + * @draft ICU 62 + */ + LocalizedNumberFormatter(LocalizedNumberFormatter&& src) U_NOEXCEPT; + + /** + * Copy assignment operator. + * @draft ICU 62 + */ + LocalizedNumberFormatter& operator=(const LocalizedNumberFormatter& other); + + /** + * Move assignment operator: + * The source LocalizedNumberFormatter will be left in a valid but undefined state. + * @draft ICU 62 + */ + LocalizedNumberFormatter& operator=(LocalizedNumberFormatter&& src) U_NOEXCEPT; + +#ifndef U_HIDE_INTERNAL_API + + /** + * This is the core entrypoint to the number formatting pipeline. It performs self-regulation: a static code path + * for the first few calls, and compiling a more efficient data structure if called repeatedly. + * + *

+ * This function is very hot, being called in every call to the number formatting pipeline. + * + * @param results + * The results object. This method will mutate it to save the results. + * @internal + */ + void formatImpl(impl::UFormattedNumberData *results, UErrorCode &status) const; + +#endif /** * Destruct this LocalizedNumberFormatter, cleaning up any memory it might own. @@ -2033,27 +2346,25 @@ class U_I18N_API LocalizedNumberFormatter ~LocalizedNumberFormatter(); private: + // Note: fCompiled can't be a LocalPointer because impl::NumberFormatterImpl is defined in an internal + // header, and LocalPointer needs the full class definition in order to delete the instance. const impl::NumberFormatterImpl* fCompiled {nullptr}; char fUnsafeCallCount[8] {}; // internally cast to u_atomic_int32_t - LocalizedNumberFormatter() = default; + explicit LocalizedNumberFormatter(const NumberFormatterSettings& other); - explicit LocalizedNumberFormatter(const NumberFormatterSettings &other); + explicit LocalizedNumberFormatter(NumberFormatterSettings&& src) U_NOEXCEPT; LocalizedNumberFormatter(const impl::MacroProps ¯os, const Locale &locale); + LocalizedNumberFormatter(impl::MacroProps &¯os, const Locale &locale); + + void lnfMoveHelper(LocalizedNumberFormatter&& src); + /** - * This is the core entrypoint to the number formatting pipeline. It performs self-regulation: a static code path - * for the first few calls, and compiling a more efficient data structure if called repeatedly. - * - *

- * This function is very hot, being called in every call to the number formatting pipeline. - * - * @param results - * The results object. This method takes ownership. - * @return The formatted number result. + * @return true if the compiled formatter is available. */ - FormattedNumber formatImpl(impl::NumberFormatterResults *results, UErrorCode &status) const; + bool computeCompiled(UErrorCode& status) const; // To give the fluent setters access to this class's constructor: friend class NumberFormatterSettings; @@ -2071,25 +2382,57 @@ class U_I18N_API LocalizedNumberFormatter */ class U_I18N_API FormattedNumber : public UMemory { public: +#ifndef U_HIDE_DEPRECATED_API /** * Returns a UnicodeString representation of the formatted number. * * @return a UnicodeString containing the localized number. - * @draft ICU 60 + * @deprecated ICU 62 Use the version of this method with an error code instead. + * This method was never @stable and will be removed in a future release. + * See http://bugs.icu-project.org/trac/ticket/13746 */ UnicodeString toString() const; +#endif /* U_HIDE_DEPRECATED_API */ + + /** + * Returns a UnicodeString representation of the formatted number. + * + * @param status + * Set if an error occurs while formatting the number to the UnicodeString. + * @return a UnicodeString containing the localized number. + * @draft ICU 62 + */ + UnicodeString toString(UErrorCode& status) const; +#ifndef U_HIDE_DEPRECATED_API /** * Appends the formatted number to an Appendable. * * @param appendable * The Appendable to which to append the formatted number string. * @return The same Appendable, for chaining. - * @draft ICU 60 + * @deprecated ICU 62 Use the version of this method with an error code instead. + * This method was never @stable and will be removed in a future release. + * See http://bugs.icu-project.org/trac/ticket/13746 * @see Appendable */ Appendable &appendTo(Appendable &appendable); +#endif /* U_HIDE_DEPRECATED_API */ + /** + * Appends the formatted number to an Appendable. + * + * @param appendable + * The Appendable to which to append the formatted number string. + * @param status + * Set if an error occurs while formatting the number to the Appendable. + * @return The same Appendable, for chaining. + * @draft ICU 62 + * @see Appendable + */ + Appendable &appendTo(Appendable &appendable, UErrorCode& status); + +#ifndef U_HIDE_DEPRECATED_API /** * Determine the start and end indices of the first occurrence of the given field in the output string. * This allows you to determine the locations of the integer part, fraction part, and sign. @@ -2106,11 +2449,47 @@ class U_I18N_API FormattedNumber : public UMemory { * The FieldPosition to populate with the start and end indices of the desired field. * @param status * Set if an error occurs while populating the FieldPosition. - * @draft ICU 60 + * @deprecated ICU 62 Use {@link #nextFieldPosition} instead. This method will be removed in a future + * release. See http://bugs.icu-project.org/trac/ticket/13746 * @see UNumberFormatFields */ void populateFieldPosition(FieldPosition &fieldPosition, UErrorCode &status); +#endif /* U_HIDE_DEPRECATED_API */ + + /** + * Determines the start and end indices of the next occurrence of the given field in the + * output string. This allows you to determine the locations of, for example, the integer part, + * fraction part, or symbols. + * + * If a field occurs just once, calling this method will find that occurrence and return it. If a + * field occurs multiple times, this method may be called repeatedly with the following pattern: + * + *

+     * FieldPosition fpos(UNUM_GROUPING_SEPARATOR_FIELD);
+     * while (formattedNumber.nextFieldPosition(fpos, status)) {
+     *   // do something with fpos.
+     * }
+     * 
+ * + * This method is useful if you know which field to query. If you want all available field position + * information, use #getAllFieldPositions(). + * + * @param fieldPosition + * Input+output variable. On input, the "field" property determines which field to look + * up, and the "beginIndex" and "endIndex" properties determine where to begin the search. + * On output, the "beginIndex" is set to the beginning of the first occurrence of the + * field with either begin or end indices after the input indices, "endIndex" is set to + * the end of that occurrence of the field (exclusive index). If a field position is not + * found, the method returns FALSE and the FieldPosition may or may not be changed. + * @param status + * Set if an error occurs while populating the FieldPosition. + * @return TRUE if a new occurrence of the field was found; FALSE otherwise. + * @draft ICU 62 + * @see UNumberFormatFields + */ + UBool nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const; +#ifndef U_HIDE_DEPRECATED_API /** * Export the formatted number to a FieldPositionIterator. This allows you to determine which characters in * the output string correspond to which fields, such as the integer part, fraction part, and sign. @@ -2122,10 +2501,67 @@ class U_I18N_API FormattedNumber : public UMemory { * The FieldPositionIterator to populate with all of the fields present in the formatted number. * @param status * Set if an error occurs while populating the FieldPositionIterator. - * @draft ICU 60 + * @deprecated ICU 62 Use {@link #getAllFieldPositions} instead. This method will be removed in a + * future release. See http://bugs.icu-project.org/trac/ticket/13746 * @see UNumberFormatFields */ void populateFieldPositionIterator(FieldPositionIterator &iterator, UErrorCode &status); +#endif /* U_HIDE_DEPRECATED_API */ + + /** + * Export the formatted number to a FieldPositionIterator. This allows you to determine which characters in + * the output string correspond to which fields, such as the integer part, fraction part, and sign. + * + * If information on only one field is needed, use #nextFieldPosition() instead. + * + * @param iterator + * The FieldPositionIterator to populate with all of the fields present in the formatted number. + * @param status + * Set if an error occurs while populating the FieldPositionIterator. + * @draft ICU 62 + * @see UNumberFormatFields + */ + void getAllFieldPositions(FieldPositionIterator &iterator, UErrorCode &status) const; + +#ifndef U_HIDE_INTERNAL_API + + /** + * Gets the raw DecimalQuantity for plural rule selection. + * @internal + */ + void getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const; + + /** + * Populates the mutable builder type FieldPositionIteratorHandler. + * @internal + */ + void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const; + +#endif + + /** + * Copying not supported; use move constructor instead. + */ + FormattedNumber(const FormattedNumber&) = delete; + + /** + * Copying not supported; use move assignment instead. + */ + FormattedNumber& operator=(const FormattedNumber&) = delete; + + /** + * Move constructor: + * Leaves the source FormattedNumber in an undefined state. + * @draft ICU 62 + */ + FormattedNumber(FormattedNumber&& src) U_NOEXCEPT; + + /** + * Move assignment: + * Leaves the source FormattedNumber in an undefined state. + * @draft ICU 62 + */ + FormattedNumber& operator=(FormattedNumber&& src) U_NOEXCEPT; /** * Destruct an instance of FormattedNumber, cleaning up any memory it might own. @@ -2134,13 +2570,17 @@ class U_I18N_API FormattedNumber : public UMemory { ~FormattedNumber(); private: - // Can't use LocalPointer because NumberFormatterResults is forward-declared - const impl::NumberFormatterResults *fResults; + // Can't use LocalPointer because UFormattedNumberData is forward-declared + const impl::UFormattedNumberData *fResults; // Error code for the terminal methods UErrorCode fErrorCode; - explicit FormattedNumber(impl::NumberFormatterResults *results) + /** + * Internal constructor from data type. Adopts the data pointer. + * @internal + */ + explicit FormattedNumber(impl::UFormattedNumberData *results) : fResults(results), fErrorCode(U_ZERO_ERROR) {}; explicit FormattedNumber(UErrorCode errorCode) @@ -2177,9 +2617,21 @@ class U_I18N_API NumberFormatter final { */ static LocalizedNumberFormatter withLocale(const Locale &locale); + /** + * Call this method at the beginning of a NumberFormatter fluent chain to create an instance based + * on a given number skeleton string. + * + * @param skeleton + * The skeleton string off of which to base this NumberFormatter. + * @param status + * Set to U_NUMBER_SKELETON_SYNTAX_ERROR if the skeleton was invalid. + * @return An UnlocalizedNumberFormatter, to be used for chaining. + * @draft ICU 62 + */ + static UnlocalizedNumberFormatter forSkeleton(const UnicodeString& skeleton, UErrorCode& status); + /** * Use factory methods instead of the constructor to create a NumberFormatter. - * @draft ICU 60 */ NumberFormatter() = delete; }; diff --git a/deps/icu-small/source/i18n/unicode/numfmt.h b/deps/icu-small/source/i18n/unicode/numfmt.h index 1332f52566..572e6afc71 100644 --- a/deps/icu-small/source/i18n/unicode/numfmt.h +++ b/deps/icu-small/source/i18n/unicode/numfmt.h @@ -555,16 +555,18 @@ public: UnicodeString& appendTo, FieldPositionIterator* posIter, UErrorCode& status) const; -public: + +// Can't use #ifndef U_HIDE_INTERNAL_API because these are virtual methods + /** * Format a decimal number. - * The number is a DigitList wrapper onto a floating point decimal number. + * The number is a DecimalQuantity wrapper onto a floating point decimal number. * The default implementation in NumberFormat converts the decimal number * to a double and formats that. Subclasses of NumberFormat that want * to specifically handle big decimal numbers must override this method. * class DecimalFormat does so. * - * @param number The number, a DigitList format Decimal Floating Point. + * @param number The number, a DecimalQuantity format Decimal Floating Point. * @param appendTo Output parameter to receive result. * Result is appended to existing contents. * @param posIter On return, can be used to iterate over positions @@ -573,20 +575,20 @@ public: * @return Reference to 'appendTo' parameter. * @internal */ - virtual UnicodeString& format(const DigitList &number, + virtual UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPositionIterator* posIter, UErrorCode& status) const; /** * Format a decimal number. - * The number is a DigitList wrapper onto a floating point decimal number. + * The number is a DecimalQuantity wrapper onto a floating point decimal number. * The default implementation in NumberFormat converts the decimal number * to a double and formats that. Subclasses of NumberFormat that want * to specifically handle big decimal numbers must override this method. * class DecimalFormat does so. * - * @param number The number, a DigitList format Decimal Floating Point. + * @param number The number, a DecimalQuantity format Decimal Floating Point. * @param appendTo Output parameter to receive result. * Result is appended to existing contents. * @param pos On input: an alignment field, if desired. @@ -595,13 +597,11 @@ public: * @return Reference to 'appendTo' parameter. * @internal */ - virtual UnicodeString& format(const DigitList &number, + virtual UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const; -public: - /** * Return a long if possible (e.g. within range LONG_MAX, * LONG_MAX], and with no decimals), otherwise a double. If diff --git a/deps/icu-small/source/i18n/unicode/plurrule.h b/deps/icu-small/source/i18n/unicode/plurrule.h index d372d79c84..03dea3f1b9 100644 --- a/deps/icu-small/source/i18n/unicode/plurrule.h +++ b/deps/icu-small/source/i18n/unicode/plurrule.h @@ -44,7 +44,6 @@ U_NAMESPACE_BEGIN class Hashtable; class IFixedDecimal; -class VisibleDigitsWithExponent; class RuleChain; class PluralRuleParser; class PluralKeywordEnumeration; @@ -348,30 +347,10 @@ public: UnicodeString select(double number) const; #ifndef U_HIDE_INTERNAL_API - /** - * Given a number and a format, returns the keyword of the first applicable - * rule for this PluralRules object. - * Note: This internal preview interface may be removed in the future if - * an architecturally cleaner solution reaches stable status. - * @param obj The numeric object for which the rule should be determined. - * @param fmt The NumberFormat specifying how the number will be formatted - * (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars"). - * @param status Input/output parameter. If at entry this indicates a - * failure status, the method returns immediately; otherwise - * this is set to indicate the outcome of the call. - * @return The keyword of the selected rule. Undefined in the case of an error. - * @internal ICU 59 technology preview, may be removed in the future - */ - UnicodeString select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) const; - /** * @internal */ UnicodeString select(const IFixedDecimal &number) const; - /** - * @internal - */ - UnicodeString select(const VisibleDigitsWithExponent &number) const; #endif /* U_HIDE_INTERNAL_API */ /** diff --git a/deps/icu-small/source/i18n/unicode/rbnf.h b/deps/icu-small/source/i18n/unicode/rbnf.h index d8d33420c2..2d284909f8 100644 --- a/deps/icu-small/source/i18n/unicode/rbnf.h +++ b/deps/icu-small/source/i18n/unicode/rbnf.h @@ -884,7 +884,7 @@ protected: * @return Reference to 'appendTo' parameter. * @internal */ - virtual UnicodeString& format(const DigitList &number, + virtual UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPositionIterator* posIter, UErrorCode& status) const; @@ -906,7 +906,7 @@ protected: * @return Reference to 'appendTo' parameter. * @internal */ - virtual UnicodeString& format(const DigitList &number, + virtual UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const; diff --git a/deps/icu-small/source/i18n/unicode/scientificnumberformatter.h b/deps/icu-small/source/i18n/unicode/scientificnumberformatter.h index 30edee7ecc..6c99a24662 100644 --- a/deps/icu-small/source/i18n/unicode/scientificnumberformatter.h +++ b/deps/icu-small/source/i18n/unicode/scientificnumberformatter.h @@ -24,7 +24,6 @@ U_NAMESPACE_BEGIN class FieldPositionIterator; -class DecimalFormatStaticSets; class DecimalFormatSymbols; class DecimalFormat; class Formattable; @@ -150,7 +149,6 @@ public: const UnicodeString &original, FieldPositionIterator &fpi, const UnicodeString &preExponent, - const DecimalFormatStaticSets &decimalFormatSets, UnicodeString &appendTo, UErrorCode &status) const = 0; private: @@ -165,7 +163,6 @@ public: const UnicodeString &original, FieldPositionIterator &fpi, const UnicodeString &preExponent, - const DecimalFormatStaticSets &decimalFormatSets, UnicodeString &appendTo, UErrorCode &status) const; }; @@ -184,7 +181,6 @@ public: const UnicodeString &original, FieldPositionIterator &fpi, const UnicodeString &preExponent, - const DecimalFormatStaticSets &decimalFormatSets, UnicodeString &appendTo, UErrorCode &status) const; private: @@ -211,7 +207,6 @@ public: UnicodeString fPreExponent; DecimalFormat *fDecimalFormat; Style *fStyle; - const DecimalFormatStaticSets *fStaticSets; }; diff --git a/deps/icu-small/source/i18n/unicode/smpdtfmt.h b/deps/icu-small/source/i18n/unicode/smpdtfmt.h index 9801b29bdb..305412b8d1 100644 --- a/deps/icu-small/source/i18n/unicode/smpdtfmt.h +++ b/deps/icu-small/source/i18n/unicode/smpdtfmt.h @@ -50,6 +50,10 @@ class TimeZoneFormat; class SharedNumberFormat; class SimpleDateFormatMutableNFs; +namespace number { +class LocalizedNumberFormatter; +} + /** * * SimpleDateFormat is a concrete class for formatting and parsing dates in a @@ -1268,7 +1272,6 @@ private: int32_t fieldNum, FieldPositionHandler& handler, Calendar& cal, - SimpleDateFormatMutableNFs &mutableNFs, UErrorCode& status) const; // in case of illegal argument /** @@ -1284,7 +1287,7 @@ private: * @param minDigits Minimum number of digits the result should have * @param maxDigits Maximum number of digits the result should have */ - void zeroPaddingNumber(NumberFormat *currentNumberFormat, + void zeroPaddingNumber(const NumberFormat *currentNumberFormat, UnicodeString &appendTo, int32_t value, int32_t minDigits, @@ -1414,21 +1417,21 @@ private: */ int32_t subParse(const UnicodeString& text, int32_t& start, char16_t ch, int32_t count, UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal, - int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs, + int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, int32_t *dayPeriod=NULL) const; void parseInt(const UnicodeString& text, Formattable& number, ParsePosition& pos, UBool allowNegative, - NumberFormat *fmt) const; + const NumberFormat *fmt) const; void parseInt(const UnicodeString& text, Formattable& number, int32_t maxDigits, ParsePosition& pos, UBool allowNegative, - NumberFormat *fmt) const; + const NumberFormat *fmt) const; int32_t checkIntSuffix(const UnicodeString& text, int32_t start, int32_t patLoc, UBool isNegative) const; @@ -1495,6 +1498,16 @@ private: */ int32_t skipUWhiteSpace(const UnicodeString& text, int32_t pos) const; + /** + * Initialize LocalizedNumberFormatter instances used for speedup. + */ + void initFastNumberFormatters(UErrorCode& status); + + /** + * Delete the LocalizedNumberFormatter instances used for speedup. + */ + void freeFastNumberFormatters(); + /** * Initialize NumberFormat instances used for numbering system overrides. */ @@ -1518,7 +1531,7 @@ private: /** * Lazy TimeZoneFormat instantiation, semantically const */ - TimeZoneFormat *tzFormat() const; + TimeZoneFormat *tzFormat(UErrorCode &status) const; const NumberFormat* getNumberFormatByIndex(UDateFormatField index) const; @@ -1611,6 +1624,20 @@ private: */ const SharedNumberFormat **fSharedNumberFormatters; + enum NumberFormatterKey { + SMPDTFMT_NF_1x10, + SMPDTFMT_NF_2x10, + SMPDTFMT_NF_3x10, + SMPDTFMT_NF_4x10, + SMPDTFMT_NF_2x2, + SMPDTFMT_NF_COUNT + }; + + /** + * Number formatters pre-allocated for fast performance on the most common integer lengths. + */ + const number::LocalizedNumberFormatter* fFastNumberFormatters[SMPDTFMT_NF_COUNT] = {}; + UBool fHaveDefaultCentury; BreakIterator* fCapitalizationBrkIter; diff --git a/deps/icu-small/source/i18n/unicode/timezone.h b/deps/icu-small/source/i18n/unicode/timezone.h index d4cd7cb36d..bbbb6b958e 100644 --- a/deps/icu-small/source/i18n/unicode/timezone.h +++ b/deps/icu-small/source/i18n/unicode/timezone.h @@ -284,6 +284,8 @@ public: * and may return a different TimeZone from the one returned by * TimeZone::createDefault(). * + *

This function is not thread safe.

+ * * @return A new instance of TimeZone detected from the current host system * configuration. * @stable ICU 55 diff --git a/deps/icu-small/source/i18n/unicode/unum.h b/deps/icu-small/source/i18n/unicode/unum.h index 0e7b9fffba..8b76014b16 100644 --- a/deps/icu-small/source/i18n/unicode/unum.h +++ b/deps/icu-small/source/i18n/unicode/unum.h @@ -29,12 +29,13 @@ /** * \file - * \brief C API: NumberFormat + * \brief C API: Compatibility APIs for number formatting. * *

Number Format C API

* - *

IMPORTANT: New users with C++ capabilities are - * strongly encouraged to see if numberformatter.h fits their use case. + *

IMPORTANT: New users with are strongly encouraged to + * see if unumberformatter.h fits their use case. Although not deprecated, + * this header is provided for backwards compatibility only. * * Number Format C API Provides functions for * formatting and parsing a number. Also provides methods for @@ -399,6 +400,10 @@ typedef enum UNumberFormatFields { * number format is opened using the given pattern, which must conform * to the syntax described in DecimalFormat or RuleBasedNumberFormat, * respectively. + * + *

NOTE:: New users with are strongly encouraged to + * use unumf_openWithSkeletonAndLocale instead of unum_open. + * * @param pattern A pattern specifying the format to use. * This parameter is ignored unless the style is * UNUM_PATTERN_DECIMAL or UNUM_PATTERN_RULEBASED. @@ -1013,6 +1018,8 @@ typedef enum UNumberFormatAttribute { *

Example: setting the scale to 3, 123 formats as "123,000" *

Example: setting the scale to -4, 123 formats as "0.0123" * + * This setting is analogous to getMultiplierScale() and setMultiplierScale() in decimfmt.h. + * * @stable ICU 51 */ UNUM_SCALE = 21, #ifndef U_HIDE_INTERNAL_API @@ -1052,7 +1059,7 @@ typedef enum UNumberFormatAttribute { * Default: 0 (unset) * @stable ICU 50 */ - UNUM_PARSE_NO_EXPONENT, + UNUM_PARSE_NO_EXPONENT = 0x1001, /** * if this attribute is set to 1, specifies that, if the pattern contains a @@ -1067,7 +1074,21 @@ typedef enum UNumberFormatAttribute { /* The following cannot be #ifndef U_HIDE_INTERNAL_API, needed in .h file variable declararions */ /** Limit of boolean attributes. * @internal */ - UNUM_LIMIT_BOOLEAN_ATTRIBUTE = 0x1003 + UNUM_LIMIT_BOOLEAN_ATTRIBUTE = 0x1003, + + /** + * Whether parsing is sensitive to case (lowercase/uppercase). + * TODO: Add to the test suite. + * @internal This API is a technical preview. It may change in an upcoming release. + */ + UNUM_PARSE_CASE_SENSITIVE = 0x1004, + + /** + * Formatting: whether to show the plus sign on non-negative numbers. + * TODO: Add to the test suite. + * @internal This API is a technical preview. It may change in an upcoming release. + */ + UNUM_SIGN_ALWAYS_SHOWN = 0x1005, } UNumberFormatAttribute; /** diff --git a/deps/icu-small/source/i18n/unicode/unumberformatter.h b/deps/icu-small/source/i18n/unicode/unumberformatter.h new file mode 100644 index 0000000000..b37f80c503 --- /dev/null +++ b/deps/icu-small/source/i18n/unicode/unumberformatter.h @@ -0,0 +1,666 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __UNUMBERFORMATTER_H__ +#define __UNUMBERFORMATTER_H__ + +#include "unicode/ufieldpositer.h" +#include "unicode/umisc.h" + + +/** + * \file + * \brief C-compatible API for localized number formatting; not recommended for C++. + * + * This is the C-compatible version of the NumberFormatter API introduced in ICU 60. C++ users should + * include unicode/numberformatter.h and use the proper C++ APIs. + * + * The C API accepts a number skeleton string for specifying the settings for formatting, which covers a + * very large subset of all possible number formatting features. For more information on number skeleton + * strings, see unicode/numberformatter.h. + * + * When using UNumberFormatter, which is treated as immutable, the results are exported to a mutable + * UFormattedNumber object, which you subsequently use for populating your string buffer or iterating over + * the fields. + * + * Example code: + *

+ * // Setup:
+ * UErrorCode ec = U_ZERO_ERROR;
+ * UNumberFormatter* uformatter = unumf_openForSkeletonAndLocale(u"precision-integer", -1, "en", &ec);
+ * UFormattedNumber* uresult = unumf_openResult(&ec);
+ * if (U_FAILURE(ec)) { return; }
+ *
+ * // Format a double:
+ * unumf_formatDouble(uformatter, 5142.3, uresult, &ec);
+ * if (U_FAILURE(ec)) { return; }
+ *
+ * // Export the string to a malloc'd buffer:
+ * int32_t len = unumf_resultToString(uresult, NULL, 0, &ec);
+ * // at this point, ec == U_BUFFER_OVERFLOW_ERROR
+ * ec = U_ZERO_ERROR;
+ * UChar* buffer = (UChar*) malloc((len+1)*sizeof(UChar));
+ * unumf_resultToString(uresult, buffer, len+1, &ec);
+ * if (U_FAILURE(ec)) { return; }
+ * // buffer should equal "5,142"
+ *
+ * // Cleanup:
+ * unumf_close(uformatter);
+ * unumf_closeResult(uresult);
+ * free(buffer);
+ * 
+ * + * If you are a C++ user linking against the C libraries, you can use the LocalPointer versions of these + * APIs. The following example uses LocalPointer with the decimal number and field position APIs: + * + *
+ * // Setup:
+ * LocalUNumberFormatterPointer uformatter(unumf_openForSkeletonAndLocale(u"percent", -1, "en", &ec));
+ * LocalUFormattedNumberPointer uresult(unumf_openResult(&ec));
+ * if (U_FAILURE(ec)) { return; }
+ *
+ * // Format a decimal number:
+ * unumf_formatDecimal(uformatter.getAlias(), "9.87E-3", -1, uresult.getAlias(), &ec);
+ * if (U_FAILURE(ec)) { return; }
+ *
+ * // Get the location of the percent sign:
+ * UFieldPosition ufpos = {UNUM_PERCENT_FIELD, 0, 0};
+ * unumf_resultNextFieldPosition(uresult.getAlias(), &ufpos, &ec);
+ * // ufpos should contain beginIndex=7 and endIndex=8 since the string is "0.00987%"
+ *
+ * // No need to do any cleanup since we are using LocalPointer.
+ * 
+ */ + + +#ifndef U_HIDE_DRAFT_API +/** + * An enum declaring how to render units, including currencies. Example outputs when formatting 123 USD and 123 + * meters in en-CA: + * + *

+ *

    + *
  • NARROW*: "$123.00" and "123 m" + *
  • SHORT: "US$ 123.00" and "123 m" + *
  • FULL_NAME: "123.00 US dollars" and "123 meters" + *
  • ISO_CODE: "USD 123.00" and undefined behavior + *
  • HIDDEN: "123.00" and "123" + *
+ * + *

+ * This enum is similar to {@link com.ibm.icu.text.MeasureFormat.FormatWidth}. + * + * @draft ICU 60 + */ +typedef enum UNumberUnitWidth { + /** + * Print an abbreviated version of the unit name. Similar to SHORT, but always use the shortest available + * abbreviation or symbol. This option can be used when the context hints at the identity of the unit. For more + * information on the difference between NARROW and SHORT, see SHORT. + * + *

+ * In CLDR, this option corresponds to the "Narrow" format for measure units and the "¤¤¤¤¤" placeholder for + * currencies. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_NARROW, + + /** + * Print an abbreviated version of the unit name. Similar to NARROW, but use a slightly wider abbreviation or + * symbol when there may be ambiguity. This is the default behavior. + * + *

+ * For example, in es-US, the SHORT form for Fahrenheit is "{0} °F", but the NARROW form is "{0}°", + * since Fahrenheit is the customary unit for temperature in that locale. + * + *

+ * In CLDR, this option corresponds to the "Short" format for measure units and the "¤" placeholder for + * currencies. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_SHORT, + + /** + * Print the full name of the unit, without any abbreviations. + * + *

+ * In CLDR, this option corresponds to the default format for measure units and the "¤¤¤" placeholder for + * currencies. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_FULL_NAME, + + /** + * Use the three-digit ISO XXX code in place of the symbol for displaying currencies. The behavior of this + * option is currently undefined for use with measure units. + * + *

+ * In CLDR, this option corresponds to the "¤¤" placeholder for currencies. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_ISO_CODE, + + /** + * Format the number according to the specified unit, but do not display the unit. For currencies, apply + * monetary symbols and formats as with SHORT, but omit the currency symbol. For measure units, the behavior is + * equivalent to not specifying the unit at all. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_HIDDEN, + + /** + * One more than the highest UNumberUnitWidth value. + * + * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. + */ + UNUM_UNIT_WIDTH_COUNT +} UNumberUnitWidth; +#endif /* U_HIDE_DRAFT_API */ + +#ifndef U_HIDE_DRAFT_API +/** + * An enum declaring the strategy for when and how to display grouping separators (i.e., the + * separator, often a comma or period, after every 2-3 powers of ten). The choices are several + * pre-built strategies for different use cases that employ locale data whenever possible. Example + * outputs for 1234 and 1234567 in en-IN: + * + *

    + *
  • OFF: 1234 and 12345 + *
  • MIN2: 1234 and 12,34,567 + *
  • AUTO: 1,234 and 12,34,567 + *
  • ON_ALIGNED: 1,234 and 12,34,567 + *
  • THOUSANDS: 1,234 and 1,234,567 + *
+ * + *

+ * The default is AUTO, which displays grouping separators unless the locale data says that grouping + * is not customary. To force grouping for all numbers greater than 1000 consistently across locales, + * use ON_ALIGNED. On the other hand, to display grouping less frequently than the default, use MIN2 + * or OFF. See the docs of each option for details. + * + *

+ * Note: This enum specifies the strategy for grouping sizes. To set which character to use as the + * grouping separator, use the "symbols" setter. + * + * @draft ICU 61 -- TODO: This should be renamed to UNumberGroupingStrategy before promoting to stable, + * for consistency with the other enums. + */ +typedef enum UGroupingStrategy { + /** + * Do not display grouping separators in any locale. + * + * @draft ICU 61 + */ + UNUM_GROUPING_OFF, + + /** + * Display grouping using locale defaults, except do not show grouping on values smaller than + * 10000 (such that there is a minimum of two digits before the first separator). + * + *

+ * Note that locales may restrict grouping separators to be displayed only on 1 million or + * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency). + * + *

+ * Locale data is used to determine whether to separate larger numbers into groups of 2 + * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). + * + * @draft ICU 61 + */ + UNUM_GROUPING_MIN2, + + /** + * Display grouping using the default strategy for all locales. This is the default behavior. + * + *

+ * Note that locales may restrict grouping separators to be displayed only on 1 million or + * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency). + * + *

+ * Locale data is used to determine whether to separate larger numbers into groups of 2 + * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). + * + * @draft ICU 61 + */ + UNUM_GROUPING_AUTO, + + /** + * Always display the grouping separator on values of at least 1000. + * + *

+ * This option ignores the locale data that restricts or disables grouping, described in MIN2 and + * AUTO. This option may be useful to normalize the alignment of numbers, such as in a + * spreadsheet. + * + *

+ * Locale data is used to determine whether to separate larger numbers into groups of 2 + * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). + * + * @draft ICU 61 + */ + UNUM_GROUPING_ON_ALIGNED, + + /** + * Use the Western defaults: groups of 3 and enabled for all numbers 1000 or greater. Do not use + * locale data for determining the grouping strategy. + * + * @draft ICU 61 + */ + UNUM_GROUPING_THOUSANDS, + + /** + * One more than the highest UGroupingStrategy value. + * + * @internal ICU 62: The numeric value may change over time; see ICU ticket #12420. + */ + UNUM_GROUPING_COUNT + +} UGroupingStrategy; +#endif /* U_HIDE_DRAFT_API */ + +#ifndef U_HIDE_DRAFT_API +/** + * An enum declaring how to denote positive and negative numbers. Example outputs when formatting + * 123, 0, and -123 in en-US: + * + *

    + *
  • AUTO: "123", "0", and "-123" + *
  • ALWAYS: "+123", "+0", and "-123" + *
  • NEVER: "123", "0", and "123" + *
  • ACCOUNTING: "$123", "$0", and "($123)" + *
  • ACCOUNTING_ALWAYS: "+$123", "+$0", and "($123)" + *
  • EXCEPT_ZERO: "+123", "0", and "-123" + *
  • ACCOUNTING_EXCEPT_ZERO: "+$123", "$0", and "($123)" + *
+ * + *

+ * The exact format, including the position and the code point of the sign, differ by locale. + * + * @draft ICU 60 + */ +typedef enum UNumberSignDisplay { + /** + * Show the minus sign on negative numbers, and do not show the sign on positive numbers. This is the default + * behavior. + * + * @draft ICU 60 + */ + UNUM_SIGN_AUTO, + + /** + * Show the minus sign on negative numbers and the plus sign on positive numbers, including zero. + * To hide the sign on zero, see {@link UNUM_SIGN_EXCEPT_ZERO}. + * + * @draft ICU 60 + */ + UNUM_SIGN_ALWAYS, + + /** + * Do not show the sign on positive or negative numbers. + * + * @draft ICU 60 + */ + UNUM_SIGN_NEVER, + + /** + * Use the locale-dependent accounting format on negative numbers, and do not show the sign on positive numbers. + * + *

+ * The accounting format is defined in CLDR and varies by locale; in many Western locales, the format is a pair + * of parentheses around the number. + * + *

+ * Note: Since CLDR defines the accounting format in the monetary context only, this option falls back to the + * AUTO sign display strategy when formatting without a currency unit. This limitation may be lifted in the + * future. + * + * @draft ICU 60 + */ + UNUM_SIGN_ACCOUNTING, + + /** + * Use the locale-dependent accounting format on negative numbers, and show the plus sign on + * positive numbers, including zero. For more information on the accounting format, see the + * ACCOUNTING sign display strategy. To hide the sign on zero, see + * {@link UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO}. + * + * @draft ICU 60 + */ + UNUM_SIGN_ACCOUNTING_ALWAYS, + + /** + * Show the minus sign on negative numbers and the plus sign on positive numbers. Do not show a + * sign on zero. + * + * @draft ICU 61 + */ + UNUM_SIGN_EXCEPT_ZERO, + + /** + * Use the locale-dependent accounting format on negative numbers, and show the plus sign on + * positive numbers. Do not show a sign on zero. For more information on the accounting format, + * see the ACCOUNTING sign display strategy. + * + * @draft ICU 61 + */ + UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO, + + /** + * One more than the highest UNumberSignDisplay value. + * + * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. + */ + UNUM_SIGN_COUNT +} UNumberSignDisplay; +#endif /* U_HIDE_DRAFT_API */ + +#ifndef U_HIDE_DRAFT_API +/** + * An enum declaring how to render the decimal separator. + * + *

+ *

    + *
  • UNUM_DECIMAL_SEPARATOR_AUTO: "1", "1.1" + *
  • UNUM_DECIMAL_SEPARATOR_ALWAYS: "1.", "1.1" + *
+ */ +typedef enum UNumberDecimalSeparatorDisplay { + /** + * Show the decimal separator when there are one or more digits to display after the separator, and do not show + * it otherwise. This is the default behavior. + * + * @draft ICU 60 + */ + UNUM_DECIMAL_SEPARATOR_AUTO, + + /** + * Always show the decimal separator, even if there are no digits to display after the separator. + * + * @draft ICU 60 + */ + UNUM_DECIMAL_SEPARATOR_ALWAYS, + + /** + * One more than the highest UNumberDecimalSeparatorDisplay value. + * + * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. + */ + UNUM_DECIMAL_SEPARATOR_COUNT +} UNumberDecimalSeparatorDisplay; +#endif /* U_HIDE_DRAFT_API */ + +#ifndef U_HIDE_DRAFT_API +/** + * C-compatible version of icu::number::LocalizedNumberFormatter. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +struct UNumberFormatter; +typedef struct UNumberFormatter UNumberFormatter; + + +/** + * C-compatible version of icu::number::FormattedNumber. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +struct UFormattedNumber; +typedef struct UFormattedNumber UFormattedNumber; + + +/** + * Creates a new UNumberFormatter for the given skeleton string and locale. This is currently the only + * method for creating a new UNumberFormatter. + * + * Objects of type UNumberFormatter returned by this method are threadsafe. + * + * For more details on skeleton strings, see the documentation in numberformatter.h. For more details on + * the usage of this API, see the documentation at the top of unumberformatter.h. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @param skeleton The skeleton string, like u"percent precision-integer" + * @param skeletonLen The number of UChars in the skeleton string, or -1 it it is NUL-terminated. + * @param locale The NUL-terminated locale ID. + * @param ec Set if an error occurs. + * @draft ICU 62 + */ +U_DRAFT UNumberFormatter* U_EXPORT2 +unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale, + UErrorCode* ec); + + +/** + * Creates a new UFormattedNumber for holding the result of a number formatting operation. + * + * Objects of type UFormattedNumber are not guaranteed to be threadsafe. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @param ec Set if an error occurs. + * @draft ICU 62 + */ +U_DRAFT UFormattedNumber* U_EXPORT2 +unumf_openResult(UErrorCode* ec); + + +/** + * Uses a UNumberFormatter to format an integer to a UFormattedNumber. A string, field position, and other + * information can be retrieved from the UFormattedNumber. + * + * The UNumberFormatter can be shared between threads. Each thread should have its own local + * UFormattedNumber, however, for storing the result of the formatting operation. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @param uformatter A formatter object created by unumf_openForSkeletonAndLocale or similar. + * @param value The number to be formatted. + * @param uresult The object that will be mutated to store the result; see unumf_openResult. + * @param ec Set if an error occurs. + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult, + UErrorCode* ec); + + +/** + * Uses a UNumberFormatter to format a double to a UFormattedNumber. A string, field position, and other + * information can be retrieved from the UFormattedNumber. + * + * The UNumberFormatter can be shared between threads. Each thread should have its own local + * UFormattedNumber, however, for storing the result of the formatting operation. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @param uformatter A formatter object created by unumf_openForSkeletonAndLocale or similar. + * @param value The number to be formatted. + * @param uresult The object that will be mutated to store the result; see unumf_openResult. + * @param ec Set if an error occurs. + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult, + UErrorCode* ec); + + +/** + * Uses a UNumberFormatter to format a decimal number to a UFormattedNumber. A string, field position, and + * other information can be retrieved from the UFormattedNumber. + * + * The UNumberFormatter can be shared between threads. Each thread should have its own local + * UFormattedNumber, however, for storing the result of the formatting operation. + * + * The syntax of the unformatted number is a "numeric string" as defined in the Decimal Arithmetic + * Specification, available at http://speleotrove.com/decimal + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @param uformatter A formatter object created by unumf_openForSkeletonAndLocale or similar. + * @param value The numeric string to be formatted. + * @param valueLen The length of the numeric string, or -1 if it is NUL-terminated. + * @param uresult The object that will be mutated to store the result; see unumf_openResult. + * @param ec Set if an error occurs. + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen, + UFormattedNumber* uresult, UErrorCode* ec); + + +/** + * Extracts the result number string out of a UFormattedNumber to a UChar buffer if possible. + * If bufferCapacity is greater than the required length, a terminating NUL is written. + * If bufferCapacity is less than the required length, an error code is set. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @param uresult The object containing the formatted number. + * @param buffer Where to save the string output. + * @param bufferCapacity The number of UChars available in the buffer. + * @param ec Set if an error occurs. + * @return The required length. + * @draft ICU 62 + */ +U_DRAFT int32_t U_EXPORT2 +unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity, + UErrorCode* ec); + + +/** + * Determines the start and end indices of the next occurrence of the given field in the + * output string. This allows you to determine the locations of, for example, the integer part, + * fraction part, or symbols. + * + * If a field occurs just once, calling this method will find that occurrence and return it. If a + * field occurs multiple times, this method may be called repeatedly with the following pattern: + * + *
+ * UFieldPosition ufpos = {UNUM_GROUPING_SEPARATOR_FIELD, 0, 0};
+ * while (unumf_resultNextFieldPosition(uresult, ufpos, &ec)) {
+ *   // do something with ufpos.
+ * }
+ * 
+ * + * This method is useful if you know which field to query. If you want all available field position + * information, use unumf_resultGetAllFieldPositions(). + * + * NOTE: All fields of the UFieldPosition must be initialized before calling this method. + * + * @param fieldPosition + * Input+output variable. On input, the "field" property determines which field to look up, + * and the "endIndex" property determines where to begin the search. On output, the + * "beginIndex" field is set to the beginning of the first occurrence of the field after the + * input "endIndex", and "endIndex" is set to the end of that occurrence of the field + * (exclusive index). If a field position is not found, the FieldPosition is not changed and + * the method returns FALSE. + * @param ec Set if an error occurs. + * @draft ICU 62 + */ +U_DRAFT UBool U_EXPORT2 +unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec); + + +/** + * Populates the given iterator with all fields in the formatted output string. This allows you to + * determine the locations of the integer part, fraction part, and sign. + * + * If you need information on only one field, use unumf_resultNextFieldPosition(). + * + * @param uresult The object containing the formatted number. + * @param fpositer + * A pointer to a UFieldPositionIterator created by {@link #ufieldpositer_open}. Iteration + * information already present in the UFieldPositionIterator is deleted, and the iterator is reset + * to apply to the fields in the formatted string created by this function call. The field values + * and indexes returned by {@link #ufieldpositer_next} represent fields denoted by + * the UNumberFormatFields enum. Fields are not returned in a guaranteed order. Fields cannot + * overlap, but they may nest. For example, 1234 could format as "1,234" which might consist of a + * grouping separator field for ',' and an integer field encompassing the entire string. + * @param ec Set if an error occurs. + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer, + UErrorCode* ec); + + +/** + * Releases the UNumberFormatter created by unumf_openForSkeletonAndLocale(). + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @param uformatter An object created by unumf_openForSkeletonAndLocale(). + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_close(UNumberFormatter* uformatter); + + +/** + * Releases the UFormattedNumber created by unumf_openResult(). + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @param uresult An object created by unumf_openResult(). + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_closeResult(UFormattedNumber* uresult); + + +#if U_SHOW_CPLUSPLUS_API +U_NAMESPACE_BEGIN + +/** + * \class LocalUNumberFormatterPointer + * "Smart pointer" class; closes a UNumberFormatter via unumf_close(). + * For most methods see the LocalPointerBase base class. + * + * Usage: + *
+ * LocalUNumberFormatterPointer uformatter(unumf_openForSkeletonAndLocale(...));
+ * // no need to explicitly call unumf_close()
+ * 
+ * + * @see LocalPointerBase + * @see LocalPointer + * @draft ICU 62 + */ +U_DEFINE_LOCAL_OPEN_POINTER(LocalUNumberFormatterPointer, UNumberFormatter, unumf_close); + +/** + * \class LocalUNumberFormatterPointer + * "Smart pointer" class; closes a UFormattedNumber via unumf_closeResult(). + * For most methods see the LocalPointerBase base class. + * + * Usage: + *
+ * LocalUFormattedNumberPointer uformatter(unumf_openResult(...));
+ * // no need to explicitly call unumf_closeResult()
+ * 
+ * + * @see LocalPointerBase + * @see LocalPointer + * @draft ICU 62 + */ +U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedNumberPointer, UFormattedNumber, unumf_closeResult); + +U_NAMESPACE_END +#endif // U_SHOW_CPLUSPLUS_API + +#endif /* U_HIDE_DRAFT_API */ + +#endif //__UNUMBERFORMATTER_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/unicode/uspoof.h b/deps/icu-small/source/i18n/unicode/uspoof.h index 9fcfcd3ede..781a88247f 100644 --- a/deps/icu-small/source/i18n/unicode/uspoof.h +++ b/deps/icu-small/source/i18n/unicode/uspoof.h @@ -477,7 +477,7 @@ typedef enum USpoofChecks { */ USPOOF_CHAR_LIMIT = 64, - /** + /** * Check that an identifier does not mix numbers from different numbering systems. * For more information, see UTS 39 section 5.3. * @@ -485,6 +485,29 @@ typedef enum USpoofChecks { */ USPOOF_MIXED_NUMBERS = 128, +#ifndef U_HIDE_DRAFT_API + /** + * Check that an identifier does not have a combining character following a character in which that + * combining character would be hidden; for example 'i' followed by a U+0307 combining dot. + * + * More specifically, the following characters are forbidden from preceding a U+0307: + *
    + *
  • Those with the Soft_Dotted Unicode property (which includes 'i' and 'j')
  • + *
  • Latin lowercase letter 'l'
  • + *
  • Dotless 'i' and 'j' ('ı' and 'ȷ', U+0131 and U+0237)
  • + *
  • Any character whose confusable prototype ends with such a character + * (Soft_Dotted, 'l', 'ı', or 'ȷ')
  • + *
+ * In addition, combining characters are allowed between the above characters and U+0307 except those + * with combining class 0 or combining class "Above" (230, same class as U+0307). + * + * This list and the number of combing characters considered by this check may grow over time. + * + * @draft ICU 62 + */ + USPOOF_HIDDEN_OVERLAY = 256, +#endif /* U_HIDE_DRAFT_API */ + /** * Enable all spoof checks. * diff --git a/deps/icu-small/source/i18n/upluralrules.cpp b/deps/icu-small/source/i18n/upluralrules.cpp index 24e74e3ee2..bba6dfe310 100644 --- a/deps/icu-small/source/i18n/upluralrules.cpp +++ b/deps/icu-small/source/i18n/upluralrules.cpp @@ -17,9 +17,44 @@ #include "unicode/unistr.h" #include "unicode/unum.h" #include "unicode/numfmt.h" +#include "number_decimalquantity.h" U_NAMESPACE_USE +namespace { + +/** + * Given a number and a format, returns the keyword of the first applicable + * rule for the PluralRules object. + * @param rules The plural rules. + * @param obj The numeric object for which the rule should be determined. + * @param fmt The NumberFormat specifying how the number will be formatted + * (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars"). + * @param status Input/output parameter. If at entry this indicates a + * failure status, the method returns immediately; otherwise + * this is set to indicate the outcome of the call. + * @return The keyword of the selected rule. Undefined in the case of an error. + */ +UnicodeString select(const PluralRules &rules, const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) { + if (U_SUCCESS(status)) { + const DecimalFormat *decFmt = dynamic_cast(&fmt); + if (decFmt != NULL) { + number::impl::DecimalQuantity dq; + decFmt->formatToDecimalQuantity(obj, dq, status); + if (U_SUCCESS(status)) { + return rules.select(dq); + } + } else { + double number = obj.getDouble(status); + if (U_SUCCESS(status)) { + return rules.select(number); + } + } + } + return UnicodeString(); +} + +} // namespace U_CAPI UPluralRules* U_EXPORT2 uplrules_open(const char *locale, UErrorCode *status) @@ -73,7 +108,7 @@ uplrules_selectWithFormat(const UPluralRules *uplrules, return 0; } Formattable obj(number); - UnicodeString result = plrules->select(obj, *nf, *status); + UnicodeString result = select(*plrules, obj, *nf, *status); return result.extract(keyword, capacity, *status); } diff --git a/deps/icu-small/source/i18n/uspoof.cpp b/deps/icu-small/source/i18n/uspoof.cpp index 019819b11c..710adcd08d 100644 --- a/deps/icu-small/source/i18n/uspoof.cpp +++ b/deps/icu-small/source/i18n/uspoof.cpp @@ -55,75 +55,96 @@ uspoof_cleanup(void) { } static void U_CALLCONV initializeStatics(UErrorCode &status) { - static const char *inclusionPat = - "['\\-.\\:\\u00B7\\u0375\\u058A\\u05F3\\u05F4\\u06FD\\u06FE\\u0F0B\\u200C\\u200D\\u2010\\u" - "2019\\u2027\\u30A0\\u30FB]"; - gInclusionSet = new UnicodeSet(UnicodeString(inclusionPat, -1, US_INV), status); + static const char16_t *inclusionPat = + u"['\\-.\\:\\u00B7\\u0375\\u058A\\u05F3\\u05F4\\u06FD\\u06FE\\u0F0B\\u200C" + u"\\u200D\\u2010\\u2019\\u2027\\u30A0\\u30FB]"; + gInclusionSet = new UnicodeSet(UnicodeString(inclusionPat), status); + if (gInclusionSet == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } gInclusionSet->freeze(); - // Note: data from http://unicode.org/Public/security/9.0.0/IdentifierStatus.txt + // Note: data from IdentifierStatus.txt & IdentifierType.txt // There is tooling to generate this constant in the unicodetools project: // org.unicode.text.tools.RecommendedSetGenerator // It will print the Java and C++ code to the console for easy copy-paste into this file. // Note: concatenated string constants do not work with UNICODE_STRING_SIMPLE on all platforms. - static const char *recommendedPat = - "[0-9A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u0131\\u0134-\\u013E\\u0141-\\u014" - "8\\u014A-\\u017E\\u018F\\u01A0\\u01A1\\u01AF\\u01B0\\u01CD-\\u01DC\\u01DE-\\u01E3\\u01E" - "6-\\u01F0\\u01F4\\u01F5\\u01F8-\\u021B\\u021E\\u021F\\u0226-\\u0233\\u0259\\u02BB\\u02B" - "C\\u02EC\\u0300-\\u0304\\u0306-\\u030C\\u030F-\\u0311\\u0313\\u0314\\u031B\\u0323-\\u03" - "28\\u032D\\u032E\\u0330\\u0331\\u0335\\u0338\\u0339\\u0342\\u0345\\u037B-\\u037D\\u0386" - "\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03CE\\u03FC-\\u045F\\u048A-\\u0529\\u05" - "2E\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0586\\u05B4\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0" - "620-\\u063F\\u0641-\\u0655\\u0660-\\u0669\\u0670-\\u0672\\u0674\\u0679-\\u068D\\u068F-" - "\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE-\\u06FC\\u06FF\\u0750-\\u07B1\\u08A0-\\u08AC\\u08B2" - "\\u08B6-\\u08BD\\u0901-\\u094D\\u094F\\u0950\\u0956\\u0957\\u0960-\\u0963\\u0966-\\u096" - "F\\u0971-\\u0977\\u0979-\\u097F\\u0981-\\u0983\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u0" - "9A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BC-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CE\\u" - "09D7\\u09E0-\\u09E3\\u09E6-\\u09F1\\u0A01-\\u0A03\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-" - "\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A35\\u0A38\\u0A39\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\" - "u0A4B-\\u0A4D\\u0A5C\\u0A66-\\u0A74\\u0A81-\\u0A83\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A9" - "3-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABC-\\u0AC5\\u0AC7-\\u0AC9\\u0" - "ACB-\\u0ACD\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-\\u0AEF\\u0B01-\\u0B03\\u0B05-\\u0B0C\\u0B0F\\" - "u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3C-\\u0B43\\u0B47" - "\\u0B48\\u0B4B-\\u0B4D\\u0B56\\u0B57\\u0B5F-\\u0B61\\u0B66-\\u0B6F\\u0B71\\u0B82\\u0B83" - "\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3" - "\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0B" - "D0\\u0BD7\\u0BE6-\\u0BEF\\u0C01-\\u0C03\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u" - "0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56" - "\\u0C60\\u0C61\\u0C66-\\u0C6F\\u0C80\\u0C82\\u0C83\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92" - "-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0" - "CD5\\u0CD6\\u0CE0-\\u0CE3\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D02\\u0D03\\u0D05-\\u0D0C\\u0" - "D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D-\\u0D43\\u0D46-\\u0D48\\u0D4A-\\u0D4E\\u0D54-\\u0D57" - "\\u0D60\\u0D61\\u0D66-\\u0D6F\\u0D7A-\\u0D7F\\u0D82\\u0D83\\u0D85-\\u0D8E\\u0D91-\\u0D9" - "6\\u0D9A-\\u0DA5\\u0DA7-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0" - "DD4\\u0DD6\\u0DD8-\\u0DDE\\u0DF2\\u0E01-\\u0E32\\u0E34-\\u0E3A\\u0E40-\\u0E4E\\u0E50-\\" - "u0E59\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u" - "0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB2\\u0EB4-\\u0EB9\\u0EBB-\\u0EBD\\" - "u0EC0-\\u0EC4\\u0EC6\\u0EC8-\\u0ECD\\u0ED0-\\u0ED9\\u0EDE\\u0EDF\\u0F00\\u0F20-\\u0F29" - "\\u0F35\\u0F37\\u0F3E-\\u0F42\\u0F44-\\u0F47\\u0F49-\\u0F4C\\u0F4E-\\u0F51\\u0F53-\\u0F" - "56\\u0F58-\\u0F5B\\u0F5D-\\u0F68\\u0F6A-\\u0F6C\\u0F71\\u0F72\\u0F74\\u0F7A-\\u0F80\\u0" - "F82-\\u0F84\\u0F86-\\u0F92\\u0F94-\\u0F97\\u0F99-\\u0F9C\\u0F9E-\\u0FA1\\u0FA3-\\u0FA6" - "\\u0FA8-\\u0FAB\\u0FAD-\\u0FB8\\u0FBA-\\u0FBC\\u0FC6\\u1000-\\u1049\\u1050-\\u109D\\u10" - "C7\\u10CD\\u10D0-\\u10F0\\u10F7-\\u10FA\\u10FD-\\u10FF\\u1200-\\u1248\\u124A-\\u124D\\u" - "1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2" - "-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1" - "315\\u1318-\\u135A\\u135D-\\u135F\\u1380-\\u138F\\u1780-\\u17A2\\u17A5-\\u17A7\\u17A9-" - "\\u17B3\\u17B6-\\u17CA\\u17D2\\u17D7\\u17DC\\u17E0-\\u17E9\\u1C80-\\u1C88\\u1E00-\\u1E9" - "9\\u1E9E\\u1EA0-\\u1EF9\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1" - "F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F70\\u1F72\\u1F74\\u1F76\\u1F78\\u1F7A\\u1F" - "7C\\u1F80-\\u1FB4\\u1FB6-\\u1FBA\\u1FBC\\u1FC2-\\u1FC4\\u1FC6-\\u1FC8\\u1FCA\\u1FCC\\u1" - "FD0-\\u1FD2\\u1FD6-\\u1FDA\\u1FE0-\\u1FE2\\u1FE4-\\u1FEA\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-" - "\\u1FF8\\u1FFA\\u1FFC\\u2D27\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0" - "-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u3" - "005-\\u3007\\u3041-\\u3096\\u3099\\u309A\\u309D\\u309E\\u30A1-\\u30FA\\u30FC-\\u30FE\\u" - "3105-\\u312D\\u31A0-\\u31BA\\u3400-\\u4DB5\\u4E00-\\u9FD5\\uA660\\uA661\\uA674-\\uA67B" - "\\uA67F\\uA69F\\uA717-\\uA71F\\uA788\\uA78D\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7AE" - "\\uA7FA\\uA9E7-\\uA9FE\\uAA60-\\uAA76\\uAA7A-\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB" - "11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAC00-\\uD7A3\\uFA0E\\uFA0F\\uFA11\\uFA13\\uF" - "A14\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29\\U00020000-\\U0002A6D6\\U0002A700-\\U0" - "002B734\\U0002B740-\\U0002B81D\\U0002B820-\\U0002CEA1]"; - - gRecommendedSet = new UnicodeSet(UnicodeString(recommendedPat, -1, US_INV), status); + static const char16_t *recommendedPat = + u"[0-9A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u0131\\u0134-\\u013E" + u"\\u0141-\\u0148\\u014A-\\u017E\\u018F\\u01A0\\u01A1\\u01AF\\u01B0\\u01CD-" + u"\\u01DC\\u01DE-\\u01E3\\u01E6-\\u01F0\\u01F4\\u01F5\\u01F8-\\u021B\\u021E" + u"\\u021F\\u0226-\\u0233\\u0259\\u02BB\\u02BC\\u02EC\\u0300-\\u0304\\u0306-" + u"\\u030C\\u030F-\\u0311\\u0313\\u0314\\u031B\\u0323-\\u0328\\u032D\\u032E" + u"\\u0330\\u0331\\u0335\\u0338\\u0339\\u0342\\u0345\\u037B-\\u037D\\u0386" + u"\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03CE\\u03FC-\\u045F\\u048A-" + u"\\u0529\\u052E\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0586\\u0588\\u05B4" + u"\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u063F\\u0641-\\u0655\\u0660-\\u0669" + u"\\u0670-\\u0672\\u0674\\u0679-\\u068D\\u068F-\\u06D3\\u06D5\\u06E5\\u06E6" + u"\\u06EE-\\u06FC\\u06FF\\u0750-\\u07B1\\u08A0-\\u08AC\\u08B2\\u08B6-\\u08BD" + u"\\u0901-\\u094D\\u094F\\u0950\\u0956\\u0957\\u0960-\\u0963\\u0966-\\u096F" + u"\\u0971-\\u0977\\u0979-\\u097F\\u0981-\\u0983\\u0985-\\u098C\\u098F\\u0990" + u"\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BC-\\u09C4\\u09C7" + u"\\u09C8\\u09CB-\\u09CE\\u09D7\\u09E0-\\u09E3\\u09E6-\\u09F1\\u09FC\\u09FE" + u"\\u0A01-\\u0A03\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30" + u"\\u0A32\\u0A35\\u0A38\\u0A39\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-" + u"\\u0A4D\\u0A5C\\u0A66-\\u0A74\\u0A81-\\u0A83\\u0A85-\\u0A8D\\u0A8F-\\u0A91" + u"\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABC-\\u0AC5" + u"\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-\\u0AEF\\u0AFA-" + u"\\u0AFF\\u0B01-\\u0B03\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-" + u"\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3C-\\u0B43\\u0B47\\u0B48\\u0B4B-" + u"\\u0B4D\\u0B56\\u0B57\\u0B5F-\\u0B61\\u0B66-\\u0B6F\\u0B71\\u0B82\\u0B83" + u"\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E" + u"\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-\\u0BC2\\u0BC6-" + u"\\u0BC8\\u0BCA-\\u0BCD\\u0BD0\\u0BD7\\u0BE6-\\u0BEF\\u0C01-\\u0C0C\\u0C0E-" + u"\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D-\\u0C44\\u0C46-" + u"\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C60\\u0C61\\u0C66-\\u0C6F\\u0C80" + u"\\u0C82\\u0C83\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3" + u"\\u0CB5-\\u0CB9\\u0CBC-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6" + u"\\u0CE0-\\u0CE3\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D00\\u0D02\\u0D03\\u0D05-" + u"\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D43\\u0D46-\\u0D48\\u0D4A-\\u0D4E\\u0D54-" + u"\\u0D57\\u0D60\\u0D61\\u0D66-\\u0D6F\\u0D7A-\\u0D7F\\u0D82\\u0D83\\u0D85-" + u"\\u0D8E\\u0D91-\\u0D96\\u0D9A-\\u0DA5\\u0DA7-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD" + u"\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDE\\u0DF2\\u0E01-" + u"\\u0E32\\u0E34-\\u0E3A\\u0E40-\\u0E4E\\u0E50-\\u0E59\\u0E81\\u0E82\\u0E84" + u"\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3" + u"\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB2\\u0EB4-\\u0EB9\\u0EBB-\\u0EBD" + u"\\u0EC0-\\u0EC4\\u0EC6\\u0EC8-\\u0ECD\\u0ED0-\\u0ED9\\u0EDE\\u0EDF\\u0F00" + u"\\u0F20-\\u0F29\\u0F35\\u0F37\\u0F3E-\\u0F42\\u0F44-\\u0F47\\u0F49-\\u0F4C" + u"\\u0F4E-\\u0F51\\u0F53-\\u0F56\\u0F58-\\u0F5B\\u0F5D-\\u0F68\\u0F6A-\\u0F6C" + u"\\u0F71\\u0F72\\u0F74\\u0F7A-\\u0F80\\u0F82-\\u0F84\\u0F86-\\u0F92\\u0F94-" + u"\\u0F97\\u0F99-\\u0F9C\\u0F9E-\\u0FA1\\u0FA3-\\u0FA6\\u0FA8-\\u0FAB\\u0FAD-" + u"\\u0FB8\\u0FBA-\\u0FBC\\u0FC6\\u1000-\\u1049\\u1050-\\u109D\\u10C7\\u10CD" + u"\\u10D0-\\u10F0\\u10F7-\\u10FA\\u10FD-\\u10FF\\u1200-\\u1248\\u124A-\\u124D" + u"\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-" + u"\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6" + u"\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u135D-\\u135F\\u1380-\\u138F" + u"\\u1780-\\u17A2\\u17A5-\\u17A7\\u17A9-\\u17B3\\u17B6-\\u17CA\\u17D2\\u17D7" + u"\\u17DC\\u17E0-\\u17E9\\u1C80-\\u1C88\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1E00-" + u"\\u1E99\\u1E9E\\u1EA0-\\u1EF9\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45" + u"\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F70\\u1F72" + u"\\u1F74\\u1F76\\u1F78\\u1F7A\\u1F7C\\u1F80-\\u1FB4\\u1FB6-\\u1FBA\\u1FBC" + u"\\u1FC2-\\u1FC4\\u1FC6-\\u1FC8\\u1FCA\\u1FCC\\u1FD0-\\u1FD2\\u1FD6-\\u1FDA" + u"\\u1FE0-\\u1FE2\\u1FE4-\\u1FEA\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FF8\\u1FFA" + u"\\u1FFC\\u2D27\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-" + u"\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-" + u"\\u2DDE\\u3005-\\u3007\\u3041-\\u3096\\u3099\\u309A\\u309D\\u309E\\u30A1-" + u"\\u30FA\\u30FC-\\u30FE\\u3105-\\u312F\\u31A0-\\u31BA\\u3400-\\u4DB5\\u4E00-" + u"\\u9FEF\\uA660\\uA661\\uA674-\\uA67B\\uA67F\\uA69F\\uA717-\\uA71F\\uA788" + u"\\uA78D\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7AE\\uA7AF\\uA7B8\\uA7B9" + u"\\uA7FA\\uA9E7-\\uA9FE\\uAA60-\\uAA76\\uAA7A-\\uAA7F\\uAB01-\\uAB06\\uAB09-" + u"\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAC00-\\uD7A3\\uFA0E" + u"\\uFA0F\\uFA11\\uFA13\\uFA14\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29" + u"\\U0001133B\\U0001B002-\\U0001B11E\\U00020000-\\U0002A6D6\\U0002A700-" + u"\\U0002B734\\U0002B740-\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-" + u"\\U0002EBE0]"; + + gRecommendedSet = new UnicodeSet(UnicodeString(recommendedPat), status); + if (gRecommendedSet == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + delete gInclusionSet; + return; + } gRecommendedSet->freeze(); gNfdNormalizer = Normalizer2::getNFDInstance(status); ucln_i18n_registerCleanup(UCLN_I18N_SPOOF, uspoof_cleanup); @@ -140,12 +161,13 @@ uspoof_open(UErrorCode *status) { return NULL; } SpoofImpl *si = new SpoofImpl(*status); - if (U_SUCCESS(*status) && si == NULL) { + if (si == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; } if (U_FAILURE(*status)) { delete si; - si = NULL; + return NULL; } return si->asUSpoofChecker(); } @@ -157,18 +179,38 @@ uspoof_openFromSerialized(const void *data, int32_t length, int32_t *pActualLeng if (U_FAILURE(*status)) { return NULL; } + + if (data == NULL) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return NULL; + } + umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status); + if (U_FAILURE(*status)) + { + return NULL; + } + SpoofData *sd = new SpoofData(data, length, *status); - SpoofImpl *si = new SpoofImpl(sd, *status); + if (sd == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + if (U_FAILURE(*status)) { delete sd; - delete si; return NULL; } - if (sd == NULL || si == NULL) { + + SpoofImpl *si = new SpoofImpl(sd, *status); + if (si == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; - delete sd; - delete si; + delete sd; // explicit delete as the destructor for si won't be called. + return NULL; + } + + if (U_FAILURE(*status)) { + delete si; // no delete for sd, as the si destructor will delete it. return NULL; } @@ -186,6 +228,10 @@ uspoof_clone(const USpoofChecker *sc, UErrorCode *status) { return NULL; } SpoofImpl *result = new SpoofImpl(*src, *status); // copy constructor + if (result == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } if (U_FAILURE(*status)) { delete result; result = NULL; @@ -524,6 +570,13 @@ int32_t checkImpl(const SpoofImpl* This, const UnicodeString& id, CheckResult* c checkResult->fNumerics = numerics; // UnicodeSet::operator= } + if (0 != (This->fChecks & USPOOF_HIDDEN_OVERLAY)) { + int32_t index = This->findHiddenOverlay(id, *status); + if (index != -1) { + result |= USPOOF_HIDDEN_OVERLAY; + } + } + if (0 != (This->fChecks & USPOOF_CHAR_LIMIT)) { int32_t i; diff --git a/deps/icu-small/source/i18n/uspoof_build.cpp b/deps/icu-small/source/i18n/uspoof_build.cpp index 7d2440e5af..7087c1ce59 100644 --- a/deps/icu-small/source/i18n/uspoof_build.cpp +++ b/deps/icu-small/source/i18n/uspoof_build.cpp @@ -71,8 +71,29 @@ uspoof_openFromSource(const char *confusables, int32_t confusablesLen, // Set up a shell of a spoof detector, with empty data. SpoofData *newSpoofData = new SpoofData(*status); + + if (newSpoofData == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + + if (U_FAILURE(*status)) { + delete newSpoofData; + return NULL; + } SpoofImpl *This = new SpoofImpl(newSpoofData, *status); + if (This == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + delete newSpoofData; // explicit delete as the destructor for SpoofImpl won't be called. + return NULL; + } + + if (U_FAILURE(*status)) { + delete This; // no delete for newSpoofData, as the SpoofImpl destructor will delete it. + return NULL; + } + // Compile the binary data from the source (text) format. ConfusabledataBuilder::buildConfusableData(This, confusables, confusablesLen, errorType, pe, *status); diff --git a/deps/icu-small/source/i18n/uspoof_conf.cpp b/deps/icu-small/source/i18n/uspoof_conf.cpp index 3a061d9dfc..672b3e0a6c 100644 --- a/deps/icu-small/source/i18n/uspoof_conf.cpp +++ b/deps/icu-small/source/i18n/uspoof_conf.cpp @@ -76,6 +76,10 @@ SPUString::~SPUString() { SPUStringPool::SPUStringPool(UErrorCode &status) : fVec(NULL), fHash(NULL) { fVec = new UVector(status); + if (fVec == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } fHash = uhash_open(uhash_hashUnicodeString, // key hash function uhash_compareUnicodeString, // Key Comparator NULL, // Value Comparator @@ -136,6 +140,10 @@ SPUString *SPUStringPool::addString(UnicodeString *src, UErrorCode &status) { delete src; } else { hashedString = new SPUString(src); + if (hashedString == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } uhash_put(fHash, src, hashedString, &status); fVec->addElement(hashedString, status); } @@ -160,11 +168,32 @@ ConfusabledataBuilder::ConfusabledataBuilder(SpoofImpl *spImpl, UErrorCode &stat if (U_FAILURE(status)) { return; } - fTable = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status); - fKeySet = new UnicodeSet(); - fKeyVec = new UVector(status); - fValueVec = new UVector(status); + + fTable = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status); + + fKeySet = new UnicodeSet(); + if (fKeySet == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + + fKeyVec = new UVector(status); + if (fKeyVec == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + + fValueVec = new UVector(status); + if (fValueVec == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + stringPool = new SPUStringPool(status); + if (stringPool == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } } diff --git a/deps/icu-small/source/i18n/uspoof_impl.cpp b/deps/icu-small/source/i18n/uspoof_impl.cpp index 0ca85c00a9..c1034c2e53 100644 --- a/deps/icu-small/source/i18n/uspoof_impl.cpp +++ b/deps/icu-small/source/i18n/uspoof_impl.cpp @@ -377,6 +377,43 @@ URestrictionLevel SpoofImpl::getRestrictionLevel(const UnicodeString& input, UEr return USPOOF_MINIMALLY_RESTRICTIVE; } +int32_t SpoofImpl::findHiddenOverlay(const UnicodeString& input, UErrorCode&) const { + bool sawLeadCharacter = false; + for (int32_t i=0; iconfusableLookup(cp, skelStr); + UChar32 finalCp = skelStr.char32At(skelStr.moveIndex32(skelStr.length(), -1)); + if (finalCp != cp && isIllegalCombiningDotLeadCharacterNoLookup(finalCp)) { + return true; + } + return false; +} + // Convert a text format hex number. Utility function used by builder code. Static. @@ -532,24 +569,25 @@ uspoof_cleanupDefaultData(void) { if (gDefaultSpoofData) { // Will delete, assuming all user-level spoof checkers were closed. gDefaultSpoofData->removeReference(); - gDefaultSpoofData = NULL; + gDefaultSpoofData = nullptr; gSpoofInitDefaultOnce.reset(); } return TRUE; } static void U_CALLCONV uspoof_loadDefaultData(UErrorCode& status) { - UDataMemory *udm = udata_openChoice(NULL, "cfu", "confusables", + UDataMemory *udm = udata_openChoice(nullptr, "cfu", "confusables", spoofDataIsAcceptable, - NULL, // context, would receive dataVersion if supplied. + nullptr, // context, would receive dataVersion if supplied. &status); if (U_FAILURE(status)) { return; } gDefaultSpoofData = new SpoofData(udm, status); if (U_FAILURE(status)) { delete gDefaultSpoofData; + gDefaultSpoofData = nullptr; return; } - if (gDefaultSpoofData == NULL) { + if (gDefaultSpoofData == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } @@ -590,6 +628,10 @@ SpoofData::SpoofData(const void *data, int32_t length, UErrorCode &status) status = U_INVALID_FORMAT_ERROR; return; } + if (data == NULL) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } void *ncData = const_cast(data); fRawData = static_cast(ncData); if (length < fRawData->fLength) { diff --git a/deps/icu-small/source/i18n/uspoof_impl.h b/deps/icu-small/source/i18n/uspoof_impl.h index 1184b8d906..470a31f2c9 100644 --- a/deps/icu-small/source/i18n/uspoof_impl.h +++ b/deps/icu-small/source/i18n/uspoof_impl.h @@ -83,6 +83,9 @@ public: void getNumerics(const UnicodeString& input, UnicodeSet& result, UErrorCode& status) const; URestrictionLevel getRestrictionLevel(const UnicodeString& input, UErrorCode& status) const; + int32_t findHiddenOverlay(const UnicodeString& input, UErrorCode& status) const; + bool isIllegalCombiningDotLeadCharacter(UChar32 cp) const; + /** parse a hex number. Untility used by the builders. */ static UChar32 ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status); diff --git a/deps/icu-small/source/i18n/valueformatter.cpp b/deps/icu-small/source/i18n/valueformatter.cpp deleted file mode 100644 index e769f369d4..0000000000 --- a/deps/icu-small/source/i18n/valueformatter.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines Corporation and -* others. All Rights Reserved. -******************************************************************************* -*/ - -#include "unicode/plurrule.h" -#include "unicode/unistr.h" -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "digitformatter.h" -#include "digitgrouping.h" -#include "digitinterval.h" -#include "digitlst.h" -#include "precision.h" -#include "plurrule_impl.h" -#include "smallintformatter.h" -#include "uassert.h" -#include "valueformatter.h" -#include "visibledigits.h" - -U_NAMESPACE_BEGIN - -ValueFormatter::~ValueFormatter() {} - -VisibleDigitsWithExponent & -ValueFormatter::toVisibleDigitsWithExponent( - int64_t value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - switch (fType) { - case kFixedDecimal: - return fFixedPrecision->initVisibleDigitsWithExponent( - value, digits, status); - break; - case kScientificNotation: - return fScientificPrecision->initVisibleDigitsWithExponent( - value, digits, status); - break; - default: - U_ASSERT(FALSE); - break; - } - return digits; -} - -VisibleDigitsWithExponent & -ValueFormatter::toVisibleDigitsWithExponent( - DigitList &value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const { - switch (fType) { - case kFixedDecimal: - return fFixedPrecision->initVisibleDigitsWithExponent( - value, digits, status); - break; - case kScientificNotation: - return fScientificPrecision->initVisibleDigitsWithExponent( - value, digits, status); - break; - default: - U_ASSERT(FALSE); - break; - } - return digits; -} - -static UBool isNoGrouping( - const DigitGrouping &grouping, - int32_t value, - const FixedPrecision &precision) { - IntDigitCountRange range( - precision.fMin.getIntDigitCount(), - precision.fMax.getIntDigitCount()); - return grouping.isNoGrouping(value, range); -} - -UBool -ValueFormatter::isFastFormattable(int32_t value) const { - switch (fType) { - case kFixedDecimal: - { - if (value == INT32_MIN) { - return FALSE; - } - if (value < 0) { - value = -value; - } - return fFixedPrecision->isFastFormattable() && fFixedOptions->isFastFormattable() && isNoGrouping(*fGrouping, value, *fFixedPrecision); - } - case kScientificNotation: - return FALSE; - default: - U_ASSERT(FALSE); - break; - } - return FALSE; -} - -DigitList & -ValueFormatter::round(DigitList &value, UErrorCode &status) const { - if (value.isNaN() || value.isInfinite()) { - return value; - } - switch (fType) { - case kFixedDecimal: - return fFixedPrecision->round(value, 0, status); - case kScientificNotation: - return fScientificPrecision->round(value, status); - default: - U_ASSERT(FALSE); - break; - } - return value; -} - -UnicodeString & -ValueFormatter::formatInt32( - int32_t value, - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - switch (fType) { - case kFixedDecimal: - { - IntDigitCountRange range( - fFixedPrecision->fMin.getIntDigitCount(), - fFixedPrecision->fMax.getIntDigitCount()); - return fDigitFormatter->formatPositiveInt32( - value, - range, - handler, - appendTo); - } - break; - case kScientificNotation: - default: - U_ASSERT(FALSE); - break; - } - return appendTo; -} - -UnicodeString & -ValueFormatter::format( - const VisibleDigitsWithExponent &value, - FieldPositionHandler &handler, - UnicodeString &appendTo) const { - switch (fType) { - case kFixedDecimal: - return fDigitFormatter->format( - value.getMantissa(), - *fGrouping, - *fFixedOptions, - handler, - appendTo); - break; - case kScientificNotation: - return fDigitFormatter->format( - value, - *fScientificOptions, - handler, - appendTo); - break; - default: - U_ASSERT(FALSE); - break; - } - return appendTo; -} - -int32_t -ValueFormatter::countChar32(const VisibleDigitsWithExponent &value) const { - switch (fType) { - case kFixedDecimal: - return fDigitFormatter->countChar32( - value.getMantissa(), - *fGrouping, - *fFixedOptions); - break; - case kScientificNotation: - return fDigitFormatter->countChar32( - value, - *fScientificOptions); - break; - default: - U_ASSERT(FALSE); - break; - } - return 0; -} - -void -ValueFormatter::prepareFixedDecimalFormatting( - const DigitFormatter &formatter, - const DigitGrouping &grouping, - const FixedPrecision &precision, - const DigitFormatterOptions &options) { - fType = kFixedDecimal; - fDigitFormatter = &formatter; - fGrouping = &grouping; - fFixedPrecision = &precision; - fFixedOptions = &options; -} - -void -ValueFormatter::prepareScientificFormatting( - const DigitFormatter &formatter, - const ScientificPrecision &precision, - const SciFormatterOptions &options) { - fType = kScientificNotation; - fDigitFormatter = &formatter; - fScientificPrecision = &precision; - fScientificOptions = &options; -} - -U_NAMESPACE_END - -#endif /* !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/valueformatter.h b/deps/icu-small/source/i18n/valueformatter.h deleted file mode 100644 index 836a05b17c..0000000000 --- a/deps/icu-small/source/i18n/valueformatter.h +++ /dev/null @@ -1,161 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2015, International Business Machines Corporation and * -* others. All Rights Reserved. * -******************************************************************************* -*/ - -#ifndef VALUEFORMATTER_H -#define VALUEFORMATTER_H - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/uobject.h" -#include "unicode/utypes.h" - - - -U_NAMESPACE_BEGIN - -class UnicodeString; -class DigitList; -class FieldPositionHandler; -class DigitGrouping; -class PluralRules; -class FixedPrecision; -class DigitFormatter; -class DigitFormatterOptions; -class ScientificPrecision; -class SciFormatterOptions; -class FixedDecimal; -class VisibleDigitsWithExponent; - - -/** - * A closure around rounding and formatting a value. As these instances are - * designed to be short lived (they only exist while formatting a value), they - * do not own their own attributes. Rather the caller maintains ownership of - * all attributes. A caller first calls a prepareXXX method on an instance - * to share its data before using that instance. Using an - * instance without first calling a prepareXXX method results in an - * assertion error and a program crash. - */ -class U_I18N_API ValueFormatter : public UObject { -public: - ValueFormatter() : fType(kFormatTypeCount) { - } - - virtual ~ValueFormatter(); - - /** - * This function is here only to support the protected round() method - * in DecimalFormat. It serves no ther purpose than that. - * - * @param value this value is rounded in place. - * @param status any error returned here. - */ - DigitList &round(DigitList &value, UErrorCode &status) const; - - /** - * Returns TRUE if the absolute value of value can be fast formatted - * using ValueFormatter::formatInt32. - */ - UBool isFastFormattable(int32_t value) const; - - /** - * Converts value to a VisibleDigitsWithExponent. - * Result may be fixed point or scientific. - */ - VisibleDigitsWithExponent &toVisibleDigitsWithExponent( - int64_t value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - - /** - * Converts value to a VisibleDigitsWithExponent. - * Result may be fixed point or scientific. - */ - VisibleDigitsWithExponent &toVisibleDigitsWithExponent( - DigitList &value, - VisibleDigitsWithExponent &digits, - UErrorCode &status) const; - - /** - * formats positiveValue and appends to appendTo. Returns appendTo. - * @param positiveValue If negative, no negative sign is formatted. - * @param handler stores the field positions - * @param appendTo formatted value appended here. - */ - UnicodeString &format( - const VisibleDigitsWithExponent &positiveValue, - FieldPositionHandler &handler, - UnicodeString &appendTo) const; - - - /** - * formats positiveValue and appends to appendTo. Returns appendTo. - * value must be positive. Calling formatInt32 to format a value when - * isFastFormattable indicates that the value cannot be fast formatted - * results in undefined behavior. - */ - UnicodeString &formatInt32( - int32_t positiveValue, - FieldPositionHandler &handler, - UnicodeString &appendTo) const; - - /** - * Returns the number of code points needed to format. - * @param positiveValue if negative, the negative sign is not included - * in count. - */ - int32_t countChar32( - const VisibleDigitsWithExponent &positiveValue) const; - - /** - * Prepares this instance for fixed decimal formatting. - */ - void prepareFixedDecimalFormatting( - const DigitFormatter &formatter, - const DigitGrouping &grouping, - const FixedPrecision &precision, - const DigitFormatterOptions &options); - - /** - * Prepares this instance for scientific formatting. - */ - void prepareScientificFormatting( - const DigitFormatter &formatter, - const ScientificPrecision &precision, - const SciFormatterOptions &options); - -private: - ValueFormatter(const ValueFormatter &); - ValueFormatter &operator=(const ValueFormatter &); - enum FormatType { - kFixedDecimal, - kScientificNotation, - kFormatTypeCount - }; - - FormatType fType; - - // for fixed decimal and scientific formatting - const DigitFormatter *fDigitFormatter; - - // for fixed decimal formatting - const FixedPrecision *fFixedPrecision; - const DigitFormatterOptions *fFixedOptions; - const DigitGrouping *fGrouping; - - // for scientific formatting - const ScientificPrecision *fScientificPrecision; - const SciFormatterOptions *fScientificOptions; -}; - -U_NAMESPACE_END - -#endif /* !UCONFIG_NO_FORMATTING */ - -#endif /* VALUEFORMATTER_H */ diff --git a/deps/icu-small/source/i18n/visibledigits.cpp b/deps/icu-small/source/i18n/visibledigits.cpp deleted file mode 100644 index 03cfc68d25..0000000000 --- a/deps/icu-small/source/i18n/visibledigits.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* - * Copyright (C) 2016, International Business Machines - * Corporation and others. All Rights Reserved. - * - * file name: visibledigits.cpp - */ - -#include - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "cstring.h" -#include "decNumber.h" -#include "digitlst.h" -#include "uassert.h" -#include "visibledigits.h" - -static const int32_t kNegative = 1; -static const int32_t kInfinite = 2; -static const int32_t kNaN = 4; - -U_NAMESPACE_BEGIN - -void VisibleDigits::setNegative() { - fFlags |= kNegative; -} - -void VisibleDigits::setNaN() { - fFlags |= kNaN; -} - -void VisibleDigits::setInfinite() { - fFlags |= kInfinite; -} - -void VisibleDigits::clear() { - fInterval.clear(); - fDigits.clear(); - fExponent = 0; - fFlags = 0; - fAbsIntValue = 0LL; - fAbsIntValueSet = FALSE; - fAbsDoubleValue = 0.0; - fAbsDoubleValueSet = FALSE; -} - -UBool VisibleDigits::isNegative() const { - return (fFlags & kNegative); -} - -UBool VisibleDigits::isNaN() const { - return (fFlags & kNaN); -} - -UBool VisibleDigits::isInfinite() const { - return (fFlags & kInfinite); -} - -int32_t VisibleDigits::getDigitByExponent(int32_t digitPos) const { - if (digitPos < fExponent || digitPos >= fExponent + fDigits.length()) { - return 0; - } - const char *ptr = fDigits.data(); - return ptr[digitPos - fExponent]; -} - -UBool VisibleDigits::isOverMaxDigits() const { - return (fExponent + fDigits.length() > fInterval.getMostSignificantExclusive()); -} - -UBool VisibleDigits::isNaNOrInfinity() const { - return (fFlags & (kInfinite | kNaN)) != 0; -} - -double VisibleDigits::computeAbsDoubleValue() const { - // Take care of NaN and infinity - if (isNaN()) { - return uprv_getNaN(); - } - if (isInfinite()) { - return uprv_getInfinity(); - } - - // stack allocate a decNumber to hold MAX_DBL_DIGITS+3 significant digits - struct { - decNumber decNum; - char digits[MAX_DBL_DIGITS+3]; - } decNumberWithStorage; - decNumber *numberPtr = &decNumberWithStorage.decNum; - - int32_t mostSig = fInterval.getMostSignificantExclusive(); - int32_t mostSigNonZero = fExponent + fDigits.length(); - int32_t end = mostSig > mostSigNonZero ? mostSigNonZero : mostSig; - int32_t leastSig = fInterval.getLeastSignificantInclusive(); - int32_t start = leastSig > fExponent ? leastSig : fExponent; - if (end <= start) { - return 0.0; - } - if (start < end - (MAX_DBL_DIGITS+3)) { - start = end - (MAX_DBL_DIGITS+3); - } - uint8_t *pos = numberPtr->lsu; - const char *src = &(fDigits.data()[start - fExponent]); - for (int32_t i = start; i < end; ++i) { - *pos++ = (uint8_t) (*src++); - } - numberPtr->exponent = start; - numberPtr->bits = 0; - numberPtr->digits = end - start; - char str[MAX_DBL_DIGITS+18]; - uprv_decNumberToString(numberPtr, str); - U_ASSERT(uprv_strlen(str) < MAX_DBL_DIGITS+18); - char *unused = NULL; - return DigitList::decimalStrToDouble(str, &unused); -} - -void VisibleDigits::getFixedDecimal( - double &source, int64_t &intValue, int64_t &f, int64_t &t, int32_t &v, UBool &hasIntValue) const { - source = 0.0; - intValue = 0; - f = 0; - t = 0; - v = 0; - hasIntValue = FALSE; - if (isNaNOrInfinity()) { - return; - } - - // source - if (fAbsDoubleValueSet) { - source = fAbsDoubleValue; - } else { - source = computeAbsDoubleValue(); - } - - // visible decimal digits - v = fInterval.getFracDigitCount(); - - // intValue - - // If we initialized from an int64 just use that instead of - // calculating - if (fAbsIntValueSet) { - intValue = fAbsIntValue; - } else { - int32_t startPos = fInterval.getMostSignificantExclusive(); - if (startPos > 18) { - startPos = 18; - } - // process the integer digits - for (int32_t i = startPos - 1; i >= 0; --i) { - intValue = intValue * 10LL + getDigitByExponent(i); - } - if (intValue == 0LL && startPos > 0) { - intValue = 100000000000000000LL; - } - } - - // f (decimal digits) - // skip over any leading 0's in fraction digits. - int32_t idx = -1; - for (; idx >= -v && getDigitByExponent(idx) == 0; --idx) - ; - - // Only process up to first 18 non zero fraction digits for decimalDigits - // since that is all we can fit into an int64. - for (int32_t i = idx; i >= -v && i > idx - 18; --i) { - f = f * 10LL + getDigitByExponent(i); - } - - // If we have no decimal digits, we don't have an integer value - hasIntValue = (f == 0LL); - - // t (decimal digits without trailing zeros) - t = f; - while (t > 0 && t % 10LL == 0) { - t /= 10; - } -} - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/deps/icu-small/source/i18n/visibledigits.h b/deps/icu-small/source/i18n/visibledigits.h deleted file mode 100644 index 03c8013e39..0000000000 --- a/deps/icu-small/source/i18n/visibledigits.h +++ /dev/null @@ -1,162 +0,0 @@ -// © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* * Copyright (C) 2015, International Business Machines -* Corporation and others. All Rights Reserved. -******************************************************************************* -* visibledigits.h -* -* created on: 2015jun20 -* created by: Travis Keep -*/ - -#ifndef __VISIBLEDIGITS_H__ -#define __VISIBLEDIGITS_H__ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/uobject.h" - -#include "charstr.h" -#include "digitinterval.h" - -U_NAMESPACE_BEGIN - -class DigitList; - -/** - * VisibleDigits represents the digits visible for formatting. - * Once initialized using a FixedPrecision instance, VisibleDigits instances - * remain unchanged until they are initialized again. A VisibleDigits with - * a numeric value equal to 3.0 could be "3", "3.0", "3.00" or even "003.0" - * depending on settings of the FixedPrecision instance used to initialize it. - */ -class U_I18N_API VisibleDigits : public UMemory { -public: - VisibleDigits() : fExponent(0), fFlags(0), fAbsIntValue(0), fAbsIntValueSet(FALSE), fAbsDoubleValue(0.0), fAbsDoubleValueSet(FALSE) { } - - UBool isNegative() const; - UBool isNaN() const; - UBool isInfinite() const; - UBool isNaNOrInfinity() const; - - /** - * Gets the digit at particular exponent, if number is 987.6, then - * getDigit(2) == 9 and gitDigit(0) == 7 and gitDigit(-1) == 6. - * If isNaN() or isInfinity() return TRUE, then the result of this - * function is undefined. - */ - int32_t getDigitByExponent(int32_t digitPos) const; - - /** - * Returns the digit interval which indicates the leftmost and rightmost - * position of this instance. - * If isNaN() or isInfinity() return TRUE, then the result of this - * function is undefined. - */ - const DigitInterval &getInterval() const { return fInterval; } - - /** - * Gets the parameters needed to create a FixedDecimal. - */ - void getFixedDecimal(double &source, int64_t &intValue, int64_t &f, int64_t &t, int32_t &v, UBool &hasIntValue) const; - - -private: - /** - * The digits, least significant first. Both the least and most - * significant digit in this list are non-zero; however, digits in the - * middle may be zero. This field contains values between (char) 0, and - * (char) 9 inclusive. - */ - CharString fDigits; - - /** - * The range of displayable digits. This field is needed to account for - * any leading and trailing zeros which are not stored in fDigits. - */ - DigitInterval fInterval; - - /** - * The exponent value of the least significant digit in fDigits. For - * example, fExponent = 2 and fDigits = {7, 8, 5} represents 58700. - */ - int32_t fExponent; - - /** - * Contains flags such as NaN, Inf, and negative. - */ - int32_t fFlags; - - /** - * Contains the absolute value of the digits left of the decimal place - * if fAbsIntValueSet is TRUE - */ - int64_t fAbsIntValue; - - /** - * Indicates whether or not fAbsIntValue is set. - */ - UBool fAbsIntValueSet; - - /** - * Contains the absolute value of the value this instance represents - * if fAbsDoubleValueSet is TRUE - */ - double fAbsDoubleValue; - - /** - * Indicates whether or not fAbsDoubleValue is set. - */ - UBool fAbsDoubleValueSet; - - void setNegative(); - void setNaN(); - void setInfinite(); - void clear(); - double computeAbsDoubleValue() const; - UBool isOverMaxDigits() const; - - VisibleDigits(const VisibleDigits &); - VisibleDigits &operator=(const VisibleDigits &); - - friend class FixedPrecision; - friend class VisibleDigitsWithExponent; -}; - -/** - * A VisibleDigits with a possible exponent. - */ -class U_I18N_API VisibleDigitsWithExponent : public UMemory { -public: - VisibleDigitsWithExponent() : fHasExponent(FALSE) { } - const VisibleDigits &getMantissa() const { return fMantissa; } - const VisibleDigits *getExponent() const { - return fHasExponent ? &fExponent : NULL; - } - void clear() { - fMantissa.clear(); - fExponent.clear(); - fHasExponent = FALSE; - } - UBool isNegative() const { return fMantissa.isNegative(); } - UBool isNaN() const { return fMantissa.isNaN(); } - UBool isInfinite() const { return fMantissa.isInfinite(); } -private: - VisibleDigitsWithExponent(const VisibleDigitsWithExponent &); - VisibleDigitsWithExponent &operator=( - const VisibleDigitsWithExponent &); - VisibleDigits fMantissa; - VisibleDigits fExponent; - UBool fHasExponent; - - friend class ScientificPrecision; - friend class FixedPrecision; -}; - - -U_NAMESPACE_END -#endif /* #if !UCONFIG_NO_FORMATTING */ -#endif // __VISIBLEDIGITS_H__ diff --git a/deps/icu-small/source/i18n/windtfmt.cpp b/deps/icu-small/source/i18n/windtfmt.cpp index e8e32abd3f..983fd46c12 100644 --- a/deps/icu-small/source/i18n/windtfmt.cpp +++ b/deps/icu-small/source/i18n/windtfmt.cpp @@ -385,7 +385,8 @@ UnicodeString Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION *tzi, const for (int z = 0; z < ec; z += 1) { UnicodeString equiv = TimeZone::getEquivalentID(icuid, z); - if (found = uprv_getWindowsTimeZoneInfo(tzi, equiv.getBuffer(), equiv.length())) { + found = uprv_getWindowsTimeZoneInfo(tzi, equiv.getBuffer(), equiv.length()); + if (found) { break; } } diff --git a/deps/icu-small/source/i18n/zonemeta.cpp b/deps/icu-small/source/i18n/zonemeta.cpp index c386b0cae5..02562048a5 100644 --- a/deps/icu-small/source/i18n/zonemeta.cpp +++ b/deps/icu-small/source/i18n/zonemeta.cpp @@ -690,6 +690,7 @@ ZoneMeta::createMetazoneMappings(const UnicodeString &tzid) { mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status); if (U_FAILURE(status)) { delete mzMappings; + mzMappings = NULL; uprv_free(entry); break; } diff --git a/deps/icu-small/source/tools/toolutil/swapimpl.cpp b/deps/icu-small/source/tools/toolutil/swapimpl.cpp index a64a6a1703..f3f333a005 100644 --- a/deps/icu-small/source/tools/toolutil/swapimpl.cpp +++ b/deps/icu-small/source/tools/toolutil/swapimpl.cpp @@ -336,7 +336,7 @@ ucase_swap(const UDataSwapper *ds, ((pInfo->formatVersion[0]==1 && pInfo->formatVersion[2]==UTRIE_SHIFT && pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT) || - pInfo->formatVersion[0]==2 || pInfo->formatVersion[0]==3) + 2<=pInfo->formatVersion[0] || pInfo->formatVersion[0]<=4) )) { udata_printError(ds, "ucase_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as case mapping data\n", pInfo->dataFormat[0], pInfo->dataFormat[1], diff --git a/deps/icu-small/source/tools/toolutil/udbgutil.cpp b/deps/icu-small/source/tools/toolutil/udbgutil.cpp index 446e11aaf9..dcc80ebe06 100644 --- a/deps/icu-small/source/tools/toolutil/udbgutil.cpp +++ b/deps/icu-small/source/tools/toolutil/udbgutil.cpp @@ -554,7 +554,6 @@ static const USystemParams systemParams[] = { #endif { "uconfig.internal_digitlist", paramInteger, "b", 1}, /* always 1 */ { "uconfig.have_parseallinput", paramInteger, "b", UCONFIG_HAVE_PARSEALLINPUT}, - { "uconfig.format_fastpaths_49",paramInteger, "b", UCONFIG_FORMAT_FASTPATHS_49}, }; -- cgit v1.2.3